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.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
a405391274
@ -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;
|
||||
if (!i) {
|
||||
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 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 @@ free_irq:
|
||||
}
|
||||
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user