drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c
Extension
.c
Size
6246 bytes
Lines
205
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!pool->irqs_per_cpu[cpu]) {
			best_cpu = cpu;
			break;
		}
		if (best_cpu < 0)
			best_cpu = cpu;
		if (pool->irqs_per_cpu[cpu] < pool->irqs_per_cpu[best_cpu])
			best_cpu = cpu;
	}
	if (best_cpu == -1) {
		/* There isn't online CPUs in req_mask */
		mlx5_core_err(pool->dev, "NO online CPUs in req_mask (%*pbl)\n",
			      cpumask_pr_args(req_mask));
		best_cpu = cpumask_first(cpu_online_mask);
	}
	pool->irqs_per_cpu[best_cpu]++;
	return best_cpu;
}

/* Creating an IRQ from irq_pool */
static struct mlx5_irq *
irq_pool_request_irq(struct mlx5_irq_pool *pool, struct irq_affinity_desc *af_desc)
{
	struct irq_affinity_desc *auto_desc;
	struct mlx5_irq *irq;
	u32 irq_index;
	int err;

	auto_desc = kvzalloc_obj(*auto_desc);
	if (!auto_desc)
		return ERR_PTR(-ENOMEM);

	err = xa_alloc(&pool->irqs, &irq_index, NULL, pool->xa_num_irqs, GFP_KERNEL);
	if (err) {
		kvfree(auto_desc);
		return ERR_PTR(err);
	}

	if (pool->irqs_per_cpu) {
		if (cpumask_weight(&af_desc->mask) > 1)
			/* if req_mask contain more then one CPU, set the least loadad CPU
			 * of req_mask
			 */
			cpumask_set_cpu(cpu_get_least_loaded(pool, &af_desc->mask),
					&auto_desc->mask);
		else
			cpu_get(pool, cpumask_first(&af_desc->mask));
	}

	irq = mlx5_irq_alloc(pool, irq_index,
			     cpumask_empty(&auto_desc->mask) ? af_desc : auto_desc,
			     NULL);
	if (IS_ERR(irq))
		xa_erase(&pool->irqs, irq_index);

	kvfree(auto_desc);

	return irq;
}

/* Looking for the IRQ with the smallest refcount that fits req_mask.
 * If pool is sf_comp_pool, then we are looking for an IRQ with any of the
 * requested CPUs in req_mask.
 * for example: req_mask = 0xf, irq0_mask = 0x10, irq1_mask = 0x1. irq0_mask
 * isn't subset of req_mask, so we will skip it. irq1_mask is subset of req_mask,
 * we don't skip it.
 * If pool is sf_ctrl_pool, then all IRQs have the same mask, so any IRQ will
 * fit. And since mask is subset of itself, we will pass the first if bellow.
 */
static struct mlx5_irq *
irq_pool_find_least_loaded(struct mlx5_irq_pool *pool, const struct cpumask *req_mask)
{
	int start = pool->xa_num_irqs.min;
	int end = pool->xa_num_irqs.max;
	struct mlx5_irq *irq = NULL;
	struct mlx5_irq *iter;
	int irq_refcount = 0;
	unsigned long index;

	lockdep_assert_held(&pool->lock);
	xa_for_each_range(&pool->irqs, index, iter, start, end) {
		int iter_refcount = mlx5_irq_read_locked(iter);
		const struct cpumask *iter_mask;

		iter_mask = irq_get_effective_affinity_mask(mlx5_irq_get_irq(iter));
		if (!iter_mask)
			continue;
		if (!cpumask_subset(iter_mask, req_mask))
			/* skip IRQs with a mask which is not subset of req_mask */
			continue;

Annotation

Implementation Notes