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)
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)
{
unsigned int max_queues_per_port = num_online_cpus();
struct gdma_context *gc = pci_get_drvdata(pdev);
unsigned int max_queues_per_port;
struct gdma_irq_context *gic;
unsigned int max_irqs, cpu;
int nvec, irq;
int start_irq_index = 1;
int nvec, *irqs, irq;
int err, i = 0, j;
cpus_read_lock();
max_queues_per_port = num_online_cpus();
if (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)
max_irqs = max_queues_per_port + 1;
nvec = pci_alloc_irq_vectors(pdev, 2, max_irqs, PCI_IRQ_MSIX);
if (nvec < 0)
if (nvec < 0) {
cpus_read_unlock();
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),
GFP_KERNEL);
......@@ -1294,17 +1336,41 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
goto free_irq;
}
err = request_irq(irq, mana_gd_intr, 0, gic->name, gic);
if (err)
goto free_irq;
cpu = cpumask_local_spread(i, gc->numa_node);
irq_set_affinity_and_hint(irq, cpumask_of(cpu));
if (!i) {
err = request_irq(irq, mana_gd_intr, 0, gic->name, gic);
if (err)
goto free_irq;
/* 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->num_msix_usable = nvec;
cpus_read_unlock();
return 0;
free_irq:
......@@ -1317,8 +1383,10 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
}
kfree(gc->irq_contexts);
kfree(irqs);
gc->irq_contexts = NULL;
free_irq_vector:
cpus_read_unlock();
pci_free_irq_vectors(pdev);
return err;
}
......
......@@ -54,6 +54,7 @@ struct device;
* bitmap_full(src, nbits) Are all bits set in *src?
* bitmap_weight(src, nbits) Hamming Weight: number set bits
* 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_clear(dst, pos, nbits) Clear specified bit 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,
unsigned int __bitmap_weight(const unsigned long *bitmap, unsigned int nbits);
unsigned int __bitmap_weight_and(const unsigned long *bitmap1,
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_clear(unsigned long *map, unsigned int start, int len);
......@@ -425,6 +428,15 @@ unsigned long bitmap_weight_and(const unsigned long *src1,
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,
unsigned int nbits)
{
......
......@@ -7,6 +7,7 @@
* set of CPUs in a system, one bit position per CPU number. In general,
* only nr_cpu_ids (<= NR_CPUS) bits are valid.
*/
#include <linux/cleanup.h>
#include <linux/kernel.h>
#include <linux/threads.h>
#include <linux/bitmap.h>
......@@ -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);
}
/**
* 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
* @dstp: the cpumask result
......@@ -977,6 +991,8 @@ static inline bool cpumask_available(cpumask_var_t mask)
}
#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,
* so it has to refer to an address rather than a pointer. */
extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS);
......
......@@ -348,6 +348,13 @@ unsigned int __bitmap_weight_and(const unsigned long *bitmap1,
}
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)
{
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