Commit a4053912 authored by Paolo Abeni's avatar Paolo Abeni

Merge branch 'net-mana-assigning-irq-affinity-on-ht-cores'

Souradeep Chakrabarti says:

====================
net: mana: Assigning IRQ affinity on HT cores

This patch set introduces a new helper function irq_setup(),
to optimize IRQ distribution for MANA network devices.
The patch set makes the driver working 15% faster than
with cpumask_local_spread().
====================

Link: https://lore.kernel.org/r/1706509267-17754-1-git-send-email-schakrabarti@linux.microsoft.comSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 3723b56d 8afefc36
...@@ -1249,15 +1249,47 @@ void mana_gd_free_res_map(struct gdma_resource *r) ...@@ -1249,15 +1249,47 @@ void mana_gd_free_res_map(struct gdma_resource *r)
r->size = 0; r->size = 0;
} }
static int irq_setup(unsigned int *irqs, unsigned int len, int node)
{
const struct cpumask *next, *prev = cpu_none_mask;
cpumask_var_t cpus __free(free_cpumask_var);
int cpu, weight;
if (!alloc_cpumask_var(&cpus, GFP_KERNEL))
return -ENOMEM;
rcu_read_lock();
for_each_numa_hop_mask(next, node) {
weight = cpumask_weight_andnot(next, prev);
while (weight > 0) {
cpumask_andnot(cpus, next, prev);
for_each_cpu(cpu, cpus) {
if (len-- == 0)
goto done;
irq_set_affinity_and_hint(*irqs++, topology_sibling_cpumask(cpu));
cpumask_andnot(cpus, cpus, topology_sibling_cpumask(cpu));
--weight;
}
}
prev = next;
}
done:
rcu_read_unlock();
return 0;
}
static int mana_gd_setup_irqs(struct pci_dev *pdev) static int mana_gd_setup_irqs(struct pci_dev *pdev)
{ {
unsigned int max_queues_per_port = num_online_cpus();
struct gdma_context *gc = pci_get_drvdata(pdev); struct gdma_context *gc = pci_get_drvdata(pdev);
unsigned int max_queues_per_port;
struct gdma_irq_context *gic; struct gdma_irq_context *gic;
unsigned int max_irqs, cpu; unsigned int max_irqs, cpu;
int nvec, irq; int start_irq_index = 1;
int nvec, *irqs, irq;
int err, i = 0, j; int err, i = 0, j;
cpus_read_lock();
max_queues_per_port = num_online_cpus();
if (max_queues_per_port > MANA_MAX_NUM_QUEUES) if (max_queues_per_port > MANA_MAX_NUM_QUEUES)
max_queues_per_port = MANA_MAX_NUM_QUEUES; max_queues_per_port = MANA_MAX_NUM_QUEUES;
...@@ -1265,8 +1297,18 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) ...@@ -1265,8 +1297,18 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
max_irqs = max_queues_per_port + 1; max_irqs = max_queues_per_port + 1;
nvec = pci_alloc_irq_vectors(pdev, 2, max_irqs, PCI_IRQ_MSIX); nvec = pci_alloc_irq_vectors(pdev, 2, max_irqs, PCI_IRQ_MSIX);
if (nvec < 0) if (nvec < 0) {
cpus_read_unlock();
return nvec; return nvec;
}
if (nvec <= num_online_cpus())
start_irq_index = 0;
irqs = kmalloc_array((nvec - start_irq_index), sizeof(int), GFP_KERNEL);
if (!irqs) {
err = -ENOMEM;
goto free_irq_vector;
}
gc->irq_contexts = kcalloc(nvec, sizeof(struct gdma_irq_context), gc->irq_contexts = kcalloc(nvec, sizeof(struct gdma_irq_context),
GFP_KERNEL); GFP_KERNEL);
...@@ -1294,17 +1336,41 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) ...@@ -1294,17 +1336,41 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
goto free_irq; goto free_irq;
} }
err = request_irq(irq, mana_gd_intr, 0, gic->name, gic); if (!i) {
if (err) err = request_irq(irq, mana_gd_intr, 0, gic->name, gic);
goto free_irq; if (err)
goto free_irq;
cpu = cpumask_local_spread(i, gc->numa_node);
irq_set_affinity_and_hint(irq, cpumask_of(cpu)); /* If number of IRQ is one extra than number of online CPUs,
* then we need to assign IRQ0 (hwc irq) and IRQ1 to
* same CPU.
* Else we will use different CPUs for IRQ0 and IRQ1.
* Also we are using cpumask_local_spread instead of
* cpumask_first for the node, because the node can be
* mem only.
*/
if (start_irq_index) {
cpu = cpumask_local_spread(i, gc->numa_node);
irq_set_affinity_and_hint(irq, cpumask_of(cpu));
} else {
irqs[start_irq_index] = irq;
}
} else {
irqs[i - start_irq_index] = irq;
err = request_irq(irqs[i - start_irq_index], mana_gd_intr, 0,
gic->name, gic);
if (err)
goto free_irq;
}
} }
err = irq_setup(irqs, (nvec - start_irq_index), gc->numa_node);
if (err)
goto free_irq;
gc->max_num_msix = nvec; gc->max_num_msix = nvec;
gc->num_msix_usable = nvec; gc->num_msix_usable = nvec;
cpus_read_unlock();
return 0; return 0;
free_irq: free_irq:
...@@ -1317,8 +1383,10 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) ...@@ -1317,8 +1383,10 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
} }
kfree(gc->irq_contexts); kfree(gc->irq_contexts);
kfree(irqs);
gc->irq_contexts = NULL; gc->irq_contexts = NULL;
free_irq_vector: free_irq_vector:
cpus_read_unlock();
pci_free_irq_vectors(pdev); pci_free_irq_vectors(pdev);
return err; return err;
} }
......
...@@ -54,6 +54,7 @@ struct device; ...@@ -54,6 +54,7 @@ struct device;
* bitmap_full(src, nbits) Are all bits set in *src? * bitmap_full(src, nbits) Are all bits set in *src?
* bitmap_weight(src, nbits) Hamming Weight: number set bits * bitmap_weight(src, nbits) Hamming Weight: number set bits
* bitmap_weight_and(src1, src2, nbits) Hamming Weight of and'ed bitmap * bitmap_weight_and(src1, src2, nbits) Hamming Weight of and'ed bitmap
* bitmap_weight_andnot(src1, src2, nbits) Hamming Weight of andnot'ed bitmap
* bitmap_set(dst, pos, nbits) Set specified bit area * bitmap_set(dst, pos, nbits) Set specified bit area
* bitmap_clear(dst, pos, nbits) Clear specified bit area * bitmap_clear(dst, pos, nbits) Clear specified bit area
* bitmap_find_next_zero_area(buf, len, pos, n, mask) Find bit free area * bitmap_find_next_zero_area(buf, len, pos, n, mask) Find bit free area
...@@ -169,6 +170,8 @@ bool __bitmap_subset(const unsigned long *bitmap1, ...@@ -169,6 +170,8 @@ bool __bitmap_subset(const unsigned long *bitmap1,
unsigned int __bitmap_weight(const unsigned long *bitmap, unsigned int nbits); unsigned int __bitmap_weight(const unsigned long *bitmap, unsigned int nbits);
unsigned int __bitmap_weight_and(const unsigned long *bitmap1, unsigned int __bitmap_weight_and(const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int nbits); const unsigned long *bitmap2, unsigned int nbits);
unsigned int __bitmap_weight_andnot(const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int nbits);
void __bitmap_set(unsigned long *map, unsigned int start, int len); void __bitmap_set(unsigned long *map, unsigned int start, int len);
void __bitmap_clear(unsigned long *map, unsigned int start, int len); void __bitmap_clear(unsigned long *map, unsigned int start, int len);
...@@ -425,6 +428,15 @@ unsigned long bitmap_weight_and(const unsigned long *src1, ...@@ -425,6 +428,15 @@ unsigned long bitmap_weight_and(const unsigned long *src1,
return __bitmap_weight_and(src1, src2, nbits); return __bitmap_weight_and(src1, src2, nbits);
} }
static __always_inline
unsigned long bitmap_weight_andnot(const unsigned long *src1,
const unsigned long *src2, unsigned int nbits)
{
if (small_const_nbits(nbits))
return hweight_long(*src1 & ~(*src2) & BITMAP_LAST_WORD_MASK(nbits));
return __bitmap_weight_andnot(src1, src2, nbits);
}
static __always_inline void bitmap_set(unsigned long *map, unsigned int start, static __always_inline void bitmap_set(unsigned long *map, unsigned int start,
unsigned int nbits) unsigned int nbits)
{ {
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* set of CPUs in a system, one bit position per CPU number. In general, * set of CPUs in a system, one bit position per CPU number. In general,
* only nr_cpu_ids (<= NR_CPUS) bits are valid. * only nr_cpu_ids (<= NR_CPUS) bits are valid.
*/ */
#include <linux/cleanup.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/threads.h> #include <linux/threads.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
...@@ -719,6 +720,19 @@ static inline unsigned int cpumask_weight_and(const struct cpumask *srcp1, ...@@ -719,6 +720,19 @@ static inline unsigned int cpumask_weight_and(const struct cpumask *srcp1,
return bitmap_weight_and(cpumask_bits(srcp1), cpumask_bits(srcp2), small_cpumask_bits); return bitmap_weight_and(cpumask_bits(srcp1), cpumask_bits(srcp2), small_cpumask_bits);
} }
/**
* cpumask_weight_andnot - Count of bits in (*srcp1 & ~*srcp2)
* @srcp1: the cpumask to count bits (< nr_cpu_ids) in.
* @srcp2: the cpumask to count bits (< nr_cpu_ids) in.
*
* Return: count of bits set in both *srcp1 and *srcp2
*/
static inline unsigned int cpumask_weight_andnot(const struct cpumask *srcp1,
const struct cpumask *srcp2)
{
return bitmap_weight_andnot(cpumask_bits(srcp1), cpumask_bits(srcp2), small_cpumask_bits);
}
/** /**
* cpumask_shift_right - *dstp = *srcp >> n * cpumask_shift_right - *dstp = *srcp >> n
* @dstp: the cpumask result * @dstp: the cpumask result
...@@ -977,6 +991,8 @@ static inline bool cpumask_available(cpumask_var_t mask) ...@@ -977,6 +991,8 @@ static inline bool cpumask_available(cpumask_var_t mask)
} }
#endif /* CONFIG_CPUMASK_OFFSTACK */ #endif /* CONFIG_CPUMASK_OFFSTACK */
DEFINE_FREE(free_cpumask_var, struct cpumask *, if (_T) free_cpumask_var(_T));
/* It's common to want to use cpu_all_mask in struct member initializers, /* It's common to want to use cpu_all_mask in struct member initializers,
* so it has to refer to an address rather than a pointer. */ * so it has to refer to an address rather than a pointer. */
extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS); extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS);
......
...@@ -348,6 +348,13 @@ unsigned int __bitmap_weight_and(const unsigned long *bitmap1, ...@@ -348,6 +348,13 @@ unsigned int __bitmap_weight_and(const unsigned long *bitmap1,
} }
EXPORT_SYMBOL(__bitmap_weight_and); EXPORT_SYMBOL(__bitmap_weight_and);
unsigned int __bitmap_weight_andnot(const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int bits)
{
return BITMAP_WEIGHT(bitmap1[idx] & ~bitmap2[idx], bits);
}
EXPORT_SYMBOL(__bitmap_weight_andnot);
void __bitmap_set(unsigned long *map, unsigned int start, int len) void __bitmap_set(unsigned long *map, unsigned int start, int len)
{ {
unsigned long *p = map + BIT_WORD(start); unsigned long *p = map + BIT_WORD(start);
......
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