net/mlx4_en: Don't use irq_affinity_notifier to track changes in IRQ affinity map
IRQ affinity notifier can only have a single notifier - cpu_rmap
notifier. Can't use it to track changes in IRQ affinity map.
Detect IRQ affinity changes by comparing CPU to current IRQ affinity map
during NAPI poll thread.
CC: Thomas Gleixner <tglx@linutronix.de>
CC: Ben Hutchings <ben@decadent.org.uk>
Fixes: 2eacc23
("net/mlx4_core: Enforce irq affinity changes immediatly")
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1b037474d0
commit
35f6f45368
@ -294,8 +294,6 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
|
|||||||
init_completion(&cq->free);
|
init_completion(&cq->free);
|
||||||
|
|
||||||
cq->irq = priv->eq_table.eq[cq->vector].irq;
|
cq->irq = priv->eq_table.eq[cq->vector].irq;
|
||||||
cq->irq_affinity_change = false;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_radix:
|
err_radix:
|
||||||
|
@ -128,6 +128,10 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
|
|||||||
mlx4_warn(mdev, "Failed assigning an EQ to %s, falling back to legacy EQ's\n",
|
mlx4_warn(mdev, "Failed assigning an EQ to %s, falling back to legacy EQ's\n",
|
||||||
name);
|
name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cq->irq_desc =
|
||||||
|
irq_to_desc(mlx4_eq_get_irq(mdev->dev,
|
||||||
|
cq->vector));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cq->vector = (cq->ring + 1 + priv->port) %
|
cq->vector = (cq->ring + 1 + priv->port) %
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include <linux/if_ether.h>
|
#include <linux/if_ether.h>
|
||||||
#include <linux/if_vlan.h>
|
#include <linux/if_vlan.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
|
||||||
#include "mlx4_en.h"
|
#include "mlx4_en.h"
|
||||||
|
|
||||||
@ -896,16 +897,25 @@ int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget)
|
|||||||
|
|
||||||
/* If we used up all the quota - we're probably not done yet... */
|
/* If we used up all the quota - we're probably not done yet... */
|
||||||
if (done == budget) {
|
if (done == budget) {
|
||||||
|
int cpu_curr;
|
||||||
|
const struct cpumask *aff;
|
||||||
|
|
||||||
INC_PERF_COUNTER(priv->pstats.napi_quota);
|
INC_PERF_COUNTER(priv->pstats.napi_quota);
|
||||||
if (unlikely(cq->mcq.irq_affinity_change)) {
|
|
||||||
cq->mcq.irq_affinity_change = false;
|
cpu_curr = smp_processor_id();
|
||||||
|
aff = irq_desc_get_irq_data(cq->irq_desc)->affinity;
|
||||||
|
|
||||||
|
if (unlikely(!cpumask_test_cpu(cpu_curr, aff))) {
|
||||||
|
/* Current cpu is not according to smp_irq_affinity -
|
||||||
|
* probably affinity changed. need to stop this NAPI
|
||||||
|
* poll, and restart it on the right CPU
|
||||||
|
*/
|
||||||
napi_complete(napi);
|
napi_complete(napi);
|
||||||
mlx4_en_arm_cq(priv, cq);
|
mlx4_en_arm_cq(priv, cq);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Done for now */
|
/* Done for now */
|
||||||
cq->mcq.irq_affinity_change = false;
|
|
||||||
napi_complete(napi);
|
napi_complete(napi);
|
||||||
mlx4_en_arm_cq(priv, cq);
|
mlx4_en_arm_cq(priv, cq);
|
||||||
}
|
}
|
||||||
|
@ -474,15 +474,9 @@ int mlx4_en_poll_tx_cq(struct napi_struct *napi, int budget)
|
|||||||
/* If we used up all the quota - we're probably not done yet... */
|
/* If we used up all the quota - we're probably not done yet... */
|
||||||
if (done < budget) {
|
if (done < budget) {
|
||||||
/* Done for now */
|
/* Done for now */
|
||||||
cq->mcq.irq_affinity_change = false;
|
|
||||||
napi_complete(napi);
|
napi_complete(napi);
|
||||||
mlx4_en_arm_cq(priv, cq);
|
mlx4_en_arm_cq(priv, cq);
|
||||||
return done;
|
return done;
|
||||||
} else if (unlikely(cq->mcq.irq_affinity_change)) {
|
|
||||||
cq->mcq.irq_affinity_change = false;
|
|
||||||
napi_complete(napi);
|
|
||||||
mlx4_en_arm_cq(priv, cq);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return budget;
|
return budget;
|
||||||
}
|
}
|
||||||
|
@ -53,11 +53,6 @@ enum {
|
|||||||
MLX4_EQ_ENTRY_SIZE = 0x20
|
MLX4_EQ_ENTRY_SIZE = 0x20
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mlx4_irq_notify {
|
|
||||||
void *arg;
|
|
||||||
struct irq_affinity_notify notify;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MLX4_EQ_STATUS_OK ( 0 << 28)
|
#define MLX4_EQ_STATUS_OK ( 0 << 28)
|
||||||
#define MLX4_EQ_STATUS_WRITE_FAIL (10 << 28)
|
#define MLX4_EQ_STATUS_WRITE_FAIL (10 << 28)
|
||||||
#define MLX4_EQ_OWNER_SW ( 0 << 24)
|
#define MLX4_EQ_OWNER_SW ( 0 << 24)
|
||||||
@ -1088,57 +1083,6 @@ static void mlx4_unmap_clr_int(struct mlx4_dev *dev)
|
|||||||
iounmap(priv->clr_base);
|
iounmap(priv->clr_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mlx4_irq_notifier_notify(struct irq_affinity_notify *notify,
|
|
||||||
const cpumask_t *mask)
|
|
||||||
{
|
|
||||||
struct mlx4_irq_notify *n = container_of(notify,
|
|
||||||
struct mlx4_irq_notify,
|
|
||||||
notify);
|
|
||||||
struct mlx4_priv *priv = (struct mlx4_priv *)n->arg;
|
|
||||||
struct radix_tree_iter iter;
|
|
||||||
void **slot;
|
|
||||||
|
|
||||||
radix_tree_for_each_slot(slot, &priv->cq_table.tree, &iter, 0) {
|
|
||||||
struct mlx4_cq *cq = (struct mlx4_cq *)(*slot);
|
|
||||||
|
|
||||||
if (cq->irq == notify->irq)
|
|
||||||
cq->irq_affinity_change = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mlx4_release_irq_notifier(struct kref *ref)
|
|
||||||
{
|
|
||||||
struct mlx4_irq_notify *n = container_of(ref, struct mlx4_irq_notify,
|
|
||||||
notify.kref);
|
|
||||||
kfree(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mlx4_assign_irq_notifier(struct mlx4_priv *priv,
|
|
||||||
struct mlx4_dev *dev, int irq)
|
|
||||||
{
|
|
||||||
struct mlx4_irq_notify *irq_notifier = NULL;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
irq_notifier = kzalloc(sizeof(*irq_notifier), GFP_KERNEL);
|
|
||||||
if (!irq_notifier) {
|
|
||||||
mlx4_warn(dev, "Failed to allocate irq notifier. irq %d\n",
|
|
||||||
irq);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
irq_notifier->notify.irq = irq;
|
|
||||||
irq_notifier->notify.notify = mlx4_irq_notifier_notify;
|
|
||||||
irq_notifier->notify.release = mlx4_release_irq_notifier;
|
|
||||||
irq_notifier->arg = priv;
|
|
||||||
err = irq_set_affinity_notifier(irq, &irq_notifier->notify);
|
|
||||||
if (err) {
|
|
||||||
kfree(irq_notifier);
|
|
||||||
irq_notifier = NULL;
|
|
||||||
mlx4_warn(dev, "Failed to set irq notifier. irq %d\n", irq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int mlx4_alloc_eq_table(struct mlx4_dev *dev)
|
int mlx4_alloc_eq_table(struct mlx4_dev *dev)
|
||||||
{
|
{
|
||||||
struct mlx4_priv *priv = mlx4_priv(dev);
|
struct mlx4_priv *priv = mlx4_priv(dev);
|
||||||
@ -1409,8 +1353,6 @@ int mlx4_assign_eq(struct mlx4_dev *dev, char *name, struct cpu_rmap *rmap,
|
|||||||
continue;
|
continue;
|
||||||
/*we dont want to break here*/
|
/*we dont want to break here*/
|
||||||
}
|
}
|
||||||
mlx4_assign_irq_notifier(priv, dev,
|
|
||||||
priv->eq_table.eq[vec].irq);
|
|
||||||
|
|
||||||
eq_set_ci(&priv->eq_table.eq[vec], 1);
|
eq_set_ci(&priv->eq_table.eq[vec], 1);
|
||||||
}
|
}
|
||||||
@ -1427,6 +1369,14 @@ int mlx4_assign_eq(struct mlx4_dev *dev, char *name, struct cpu_rmap *rmap,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mlx4_assign_eq);
|
EXPORT_SYMBOL(mlx4_assign_eq);
|
||||||
|
|
||||||
|
int mlx4_eq_get_irq(struct mlx4_dev *dev, int vec)
|
||||||
|
{
|
||||||
|
struct mlx4_priv *priv = mlx4_priv(dev);
|
||||||
|
|
||||||
|
return priv->eq_table.eq[vec].irq;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(mlx4_eq_get_irq);
|
||||||
|
|
||||||
void mlx4_release_eq(struct mlx4_dev *dev, int vec)
|
void mlx4_release_eq(struct mlx4_dev *dev, int vec)
|
||||||
{
|
{
|
||||||
struct mlx4_priv *priv = mlx4_priv(dev);
|
struct mlx4_priv *priv = mlx4_priv(dev);
|
||||||
@ -1438,9 +1388,6 @@ void mlx4_release_eq(struct mlx4_dev *dev, int vec)
|
|||||||
Belonging to a legacy EQ*/
|
Belonging to a legacy EQ*/
|
||||||
mutex_lock(&priv->msix_ctl.pool_lock);
|
mutex_lock(&priv->msix_ctl.pool_lock);
|
||||||
if (priv->msix_ctl.pool_bm & 1ULL << i) {
|
if (priv->msix_ctl.pool_bm & 1ULL << i) {
|
||||||
irq_set_affinity_notifier(
|
|
||||||
priv->eq_table.eq[vec].irq,
|
|
||||||
NULL);
|
|
||||||
free_irq(priv->eq_table.eq[vec].irq,
|
free_irq(priv->eq_table.eq[vec].irq,
|
||||||
&priv->eq_table.eq[vec]);
|
&priv->eq_table.eq[vec]);
|
||||||
priv->msix_ctl.pool_bm &= ~(1ULL << i);
|
priv->msix_ctl.pool_bm &= ~(1ULL << i);
|
||||||
|
@ -343,6 +343,7 @@ struct mlx4_en_cq {
|
|||||||
#define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD)
|
#define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD)
|
||||||
spinlock_t poll_lock; /* protects from LLS/napi conflicts */
|
spinlock_t poll_lock; /* protects from LLS/napi conflicts */
|
||||||
#endif /* CONFIG_NET_RX_BUSY_POLL */
|
#endif /* CONFIG_NET_RX_BUSY_POLL */
|
||||||
|
struct irq_desc *irq_desc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mlx4_en_port_profile {
|
struct mlx4_en_port_profile {
|
||||||
|
@ -578,8 +578,6 @@ struct mlx4_cq {
|
|||||||
u32 cons_index;
|
u32 cons_index;
|
||||||
|
|
||||||
u16 irq;
|
u16 irq;
|
||||||
bool irq_affinity_change;
|
|
||||||
|
|
||||||
__be32 *set_ci_db;
|
__be32 *set_ci_db;
|
||||||
__be32 *arm_db;
|
__be32 *arm_db;
|
||||||
int arm_sn;
|
int arm_sn;
|
||||||
@ -1167,6 +1165,8 @@ int mlx4_assign_eq(struct mlx4_dev *dev, char *name, struct cpu_rmap *rmap,
|
|||||||
int *vector);
|
int *vector);
|
||||||
void mlx4_release_eq(struct mlx4_dev *dev, int vec);
|
void mlx4_release_eq(struct mlx4_dev *dev, int vec);
|
||||||
|
|
||||||
|
int mlx4_eq_get_irq(struct mlx4_dev *dev, int vec);
|
||||||
|
|
||||||
int mlx4_get_phys_port_id(struct mlx4_dev *dev);
|
int mlx4_get_phys_port_id(struct mlx4_dev *dev);
|
||||||
int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port);
|
int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port);
|
||||||
int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port);
|
int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port);
|
||||||
|
Loading…
Reference in New Issue
Block a user