aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c')
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c75
1 files changed, 49 insertions, 26 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
index 3465b363fc2f..c79a10b3454d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
@@ -18,7 +18,7 @@
#define MLX5_SFS_PER_CTRL_IRQ 64
#define MLX5_IRQ_CTRL_SF_MAX 8
-/* min num of vectores for SFs to be enabled */
+/* min num of vectors for SFs to be enabled */
#define MLX5_IRQ_VEC_COMP_BASE_SF 2
#define MLX5_EQ_SHARE_IRQ_MAX_COMP (8)
@@ -28,13 +28,13 @@
#define MLX5_EQ_REFS_PER_IRQ (2)
struct mlx5_irq {
- u32 index;
struct atomic_notifier_head nh;
cpumask_var_t mask;
char name[MLX5_MAX_IRQ_NAME];
- struct kref kref;
- int irqn;
struct mlx5_irq_pool *pool;
+ int refcount;
+ u32 index;
+ int irqn;
};
struct mlx5_irq_pool {
@@ -138,9 +138,8 @@ out:
return ret;
}
-static void irq_release(struct kref *kref)
+static void irq_release(struct mlx5_irq *irq)
{
- struct mlx5_irq *irq = container_of(kref, struct mlx5_irq, kref);
struct mlx5_irq_pool *pool = irq->pool;
xa_erase(&pool->irqs, irq->index);
@@ -159,10 +158,31 @@ static void irq_put(struct mlx5_irq *irq)
struct mlx5_irq_pool *pool = irq->pool;
mutex_lock(&pool->lock);
- kref_put(&irq->kref, irq_release);
+ irq->refcount--;
+ if (!irq->refcount)
+ irq_release(irq);
mutex_unlock(&pool->lock);
}
+static int irq_get_locked(struct mlx5_irq *irq)
+{
+ lockdep_assert_held(&irq->pool->lock);
+ if (WARN_ON_ONCE(!irq->refcount))
+ return 0;
+ irq->refcount++;
+ return 1;
+}
+
+static int irq_get(struct mlx5_irq *irq)
+{
+ int err;
+
+ mutex_lock(&irq->pool->lock);
+ err = irq_get_locked(irq);
+ mutex_unlock(&irq->pool->lock);
+ return err;
+}
+
static irqreturn_t irq_int_handler(int irq, void *nh)
{
atomic_notifier_call_chain(nh, 0, NULL);
@@ -215,7 +235,7 @@ static struct mlx5_irq *irq_request(struct mlx5_irq_pool *pool, int i)
goto err_cpumask;
}
irq->pool = pool;
- kref_init(&irq->kref);
+ irq->refcount = 1;
irq->index = i;
err = xa_err(xa_store(&pool->irqs, irq->index, irq, GFP_KERNEL));
if (err) {
@@ -235,18 +255,18 @@ err_req_irq:
int mlx5_irq_attach_nb(struct mlx5_irq *irq, struct notifier_block *nb)
{
- int err;
+ int ret;
- err = kref_get_unless_zero(&irq->kref);
- if (WARN_ON_ONCE(!err))
+ ret = irq_get(irq);
+ if (!ret)
/* Something very bad happens here, we are enabling EQ
* on non-existing IRQ.
*/
return -ENOENT;
- err = atomic_notifier_chain_register(&irq->nh, nb);
- if (err)
+ ret = atomic_notifier_chain_register(&irq->nh, nb);
+ if (ret)
irq_put(irq);
- return err;
+ return ret;
}
int mlx5_irq_detach_nb(struct mlx5_irq *irq, struct notifier_block *nb)
@@ -304,10 +324,9 @@ static struct mlx5_irq *irq_pool_find_least_loaded(struct mlx5_irq_pool *pool,
xa_for_each_range(&pool->irqs, index, iter, start, end) {
if (!cpumask_equal(iter->mask, affinity))
continue;
- if (kref_read(&iter->kref) < pool->min_threshold)
+ if (iter->refcount < pool->min_threshold)
return iter;
- if (!irq || kref_read(&iter->kref) <
- kref_read(&irq->kref))
+ if (!irq || iter->refcount < irq->refcount)
irq = iter;
}
return irq;
@@ -322,7 +341,7 @@ static struct mlx5_irq *irq_pool_request_affinity(struct mlx5_irq_pool *pool,
mutex_lock(&pool->lock);
least_loaded_irq = irq_pool_find_least_loaded(pool, affinity);
if (least_loaded_irq &&
- kref_read(&least_loaded_irq->kref) < pool->min_threshold)
+ least_loaded_irq->refcount < pool->min_threshold)
goto out;
new_irq = irq_pool_create_irq(pool, affinity);
if (IS_ERR(new_irq)) {
@@ -340,11 +359,11 @@ static struct mlx5_irq *irq_pool_request_affinity(struct mlx5_irq_pool *pool,
least_loaded_irq = new_irq;
goto unlock;
out:
- kref_get(&least_loaded_irq->kref);
- if (kref_read(&least_loaded_irq->kref) > pool->max_threshold)
+ irq_get_locked(least_loaded_irq);
+ if (least_loaded_irq->refcount > pool->max_threshold)
mlx5_core_dbg(pool->dev, "IRQ %u overloaded, pool_name: %s, %u EQs on this irq\n",
least_loaded_irq->irqn, pool->name,
- kref_read(&least_loaded_irq->kref) / MLX5_EQ_REFS_PER_IRQ);
+ least_loaded_irq->refcount / MLX5_EQ_REFS_PER_IRQ);
unlock:
mutex_unlock(&pool->lock);
return least_loaded_irq;
@@ -360,7 +379,7 @@ irq_pool_request_vector(struct mlx5_irq_pool *pool, int vecidx,
mutex_lock(&pool->lock);
irq = xa_load(&pool->irqs, vecidx);
if (irq) {
- kref_get(&irq->kref);
+ irq_get_locked(irq);
goto unlock;
}
irq = irq_request(pool, vecidx);
@@ -427,7 +446,7 @@ out:
return irq;
mlx5_core_dbg(dev, "irq %u mapped to cpu %*pbl, %u EQs on this irq\n",
irq->irqn, cpumask_pr_args(affinity),
- kref_read(&irq->kref) / MLX5_EQ_REFS_PER_IRQ);
+ irq->refcount / MLX5_EQ_REFS_PER_IRQ);
return irq;
}
@@ -459,8 +478,12 @@ static void irq_pool_free(struct mlx5_irq_pool *pool)
struct mlx5_irq *irq;
unsigned long index;
+ /* There are cases in which we are destrying the irq_table before
+ * freeing all the IRQs, fast teardown for example. Hence, free the irqs
+ * which might not have been freed.
+ */
xa_for_each(&pool->irqs, index, irq)
- irq_release(&irq->kref);
+ irq_release(irq);
xa_destroy(&pool->irqs);
mutex_destroy(&pool->lock);
kvfree(pool);
@@ -483,7 +506,7 @@ static int irq_pools_init(struct mlx5_core_dev *dev, int sf_vec, int pf_vec)
if (!mlx5_sf_max_functions(dev))
return 0;
if (sf_vec < MLX5_IRQ_VEC_COMP_BASE_SF) {
- mlx5_core_err(dev, "Not enough IRQs for SFs. SF may run at lower performance\n");
+ mlx5_core_dbg(dev, "Not enught IRQs for SFs. SF may run at lower performance\n");
return 0;
}
@@ -601,7 +624,7 @@ void mlx5_irq_table_destroy(struct mlx5_core_dev *dev)
return;
/* There are cases where IRQs still will be in used when we reaching
- * to here. Hence, making sure all the irqs are realeased.
+ * to here. Hence, making sure all the irqs are released.
*/
irq_pools_destroy(table);
pci_free_irq_vectors(dev->pdev);