diff options
author | Amir Vadai <amirv@mellanox.com> | 2014-06-29 04:54:55 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-02 21:29:23 -0400 |
commit | 35f6f45368632f21bd27559c44dbb1cab51d8947 (patch) | |
tree | 0d1401763591079cb2d2300a0313f5c205593677 | |
parent | 1b037474d0c0b5ceb65bc809e3d8ac4497ee041b (diff) |
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>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/cq.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_cq.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_rx.c | 16 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_tx.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/eq.c | 69 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 | ||||
-rw-r--r-- | include/linux/mlx4/device.h | 4 |
7 files changed, 28 insertions, 74 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c index 80f725228f5b..56022d647837 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c | |||
@@ -294,8 +294,6 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, | |||
294 | init_completion(&cq->free); | 294 | init_completion(&cq->free); |
295 | 295 | ||
296 | cq->irq = priv->eq_table.eq[cq->vector].irq; | 296 | cq->irq = priv->eq_table.eq[cq->vector].irq; |
297 | cq->irq_affinity_change = false; | ||
298 | |||
299 | return 0; | 297 | return 0; |
300 | 298 | ||
301 | err_radix: | 299 | err_radix: |
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c index 4b2130760eed..1213cc71348c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c | |||
@@ -128,6 +128,10 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, | |||
128 | mlx4_warn(mdev, "Failed assigning an EQ to %s, falling back to legacy EQ's\n", | 128 | mlx4_warn(mdev, "Failed assigning an EQ to %s, falling back to legacy EQ's\n", |
129 | name); | 129 | name); |
130 | } | 130 | } |
131 | |||
132 | cq->irq_desc = | ||
133 | irq_to_desc(mlx4_eq_get_irq(mdev->dev, | ||
134 | cq->vector)); | ||
131 | } | 135 | } |
132 | } else { | 136 | } else { |
133 | cq->vector = (cq->ring + 1 + priv->port) % | 137 | cq->vector = (cq->ring + 1 + priv->port) % |
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index d2d415732d99..96724170308a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/if_ether.h> | 40 | #include <linux/if_ether.h> |
41 | #include <linux/if_vlan.h> | 41 | #include <linux/if_vlan.h> |
42 | #include <linux/vmalloc.h> | 42 | #include <linux/vmalloc.h> |
43 | #include <linux/irq.h> | ||
43 | 44 | ||
44 | #include "mlx4_en.h" | 45 | #include "mlx4_en.h" |
45 | 46 | ||
@@ -896,16 +897,25 @@ int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget) | |||
896 | 897 | ||
897 | /* If we used up all the quota - we're probably not done yet... */ | 898 | /* If we used up all the quota - we're probably not done yet... */ |
898 | if (done == budget) { | 899 | if (done == budget) { |
900 | int cpu_curr; | ||
901 | const struct cpumask *aff; | ||
902 | |||
899 | INC_PERF_COUNTER(priv->pstats.napi_quota); | 903 | INC_PERF_COUNTER(priv->pstats.napi_quota); |
900 | if (unlikely(cq->mcq.irq_affinity_change)) { | 904 | |
901 | cq->mcq.irq_affinity_change = false; | 905 | cpu_curr = smp_processor_id(); |
906 | aff = irq_desc_get_irq_data(cq->irq_desc)->affinity; | ||
907 | |||
908 | if (unlikely(!cpumask_test_cpu(cpu_curr, aff))) { | ||
909 | /* Current cpu is not according to smp_irq_affinity - | ||
910 | * probably affinity changed. need to stop this NAPI | ||
911 | * poll, and restart it on the right CPU | ||
912 | */ | ||
902 | napi_complete(napi); | 913 | napi_complete(napi); |
903 | mlx4_en_arm_cq(priv, cq); | 914 | mlx4_en_arm_cq(priv, cq); |
904 | return 0; | 915 | return 0; |
905 | } | 916 | } |
906 | } else { | 917 | } else { |
907 | /* Done for now */ | 918 | /* Done for now */ |
908 | cq->mcq.irq_affinity_change = false; | ||
909 | napi_complete(napi); | 919 | napi_complete(napi); |
910 | mlx4_en_arm_cq(priv, cq); | 920 | mlx4_en_arm_cq(priv, cq); |
911 | } | 921 | } |
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 8be7483f8236..ac3dead3792c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c | |||
@@ -474,15 +474,9 @@ int mlx4_en_poll_tx_cq(struct napi_struct *napi, int budget) | |||
474 | /* If we used up all the quota - we're probably not done yet... */ | 474 | /* If we used up all the quota - we're probably not done yet... */ |
475 | if (done < budget) { | 475 | if (done < budget) { |
476 | /* Done for now */ | 476 | /* Done for now */ |
477 | cq->mcq.irq_affinity_change = false; | ||
478 | napi_complete(napi); | 477 | napi_complete(napi); |
479 | mlx4_en_arm_cq(priv, cq); | 478 | mlx4_en_arm_cq(priv, cq); |
480 | return done; | 479 | return done; |
481 | } else if (unlikely(cq->mcq.irq_affinity_change)) { | ||
482 | cq->mcq.irq_affinity_change = false; | ||
483 | napi_complete(napi); | ||
484 | mlx4_en_arm_cq(priv, cq); | ||
485 | return 0; | ||
486 | } | 480 | } |
487 | return budget; | 481 | return budget; |
488 | } | 482 | } |
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index d954ec1eac17..2a004b347e1d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c | |||
@@ -53,11 +53,6 @@ enum { | |||
53 | MLX4_EQ_ENTRY_SIZE = 0x20 | 53 | MLX4_EQ_ENTRY_SIZE = 0x20 |
54 | }; | 54 | }; |
55 | 55 | ||
56 | struct mlx4_irq_notify { | ||
57 | void *arg; | ||
58 | struct irq_affinity_notify notify; | ||
59 | }; | ||
60 | |||
61 | #define MLX4_EQ_STATUS_OK ( 0 << 28) | 56 | #define MLX4_EQ_STATUS_OK ( 0 << 28) |
62 | #define MLX4_EQ_STATUS_WRITE_FAIL (10 << 28) | 57 | #define MLX4_EQ_STATUS_WRITE_FAIL (10 << 28) |
63 | #define MLX4_EQ_OWNER_SW ( 0 << 24) | 58 | #define MLX4_EQ_OWNER_SW ( 0 << 24) |
@@ -1088,57 +1083,6 @@ static void mlx4_unmap_clr_int(struct mlx4_dev *dev) | |||
1088 | iounmap(priv->clr_base); | 1083 | iounmap(priv->clr_base); |
1089 | } | 1084 | } |
1090 | 1085 | ||
1091 | static void mlx4_irq_notifier_notify(struct irq_affinity_notify *notify, | ||
1092 | const cpumask_t *mask) | ||
1093 | { | ||
1094 | struct mlx4_irq_notify *n = container_of(notify, | ||
1095 | struct mlx4_irq_notify, | ||
1096 | notify); | ||
1097 | struct mlx4_priv *priv = (struct mlx4_priv *)n->arg; | ||
1098 | struct radix_tree_iter iter; | ||
1099 | void **slot; | ||
1100 | |||
1101 | radix_tree_for_each_slot(slot, &priv->cq_table.tree, &iter, 0) { | ||
1102 | struct mlx4_cq *cq = (struct mlx4_cq *)(*slot); | ||
1103 | |||
1104 | if (cq->irq == notify->irq) | ||
1105 | cq->irq_affinity_change = true; | ||
1106 | } | ||
1107 | } | ||
1108 | |||
1109 | static void mlx4_release_irq_notifier(struct kref *ref) | ||
1110 | { | ||
1111 | struct mlx4_irq_notify *n = container_of(ref, struct mlx4_irq_notify, | ||
1112 | notify.kref); | ||
1113 | kfree(n); | ||
1114 | } | ||
1115 | |||
1116 | static void mlx4_assign_irq_notifier(struct mlx4_priv *priv, | ||
1117 | struct mlx4_dev *dev, int irq) | ||
1118 | { | ||
1119 | struct mlx4_irq_notify *irq_notifier = NULL; | ||
1120 | int err = 0; | ||
1121 | |||
1122 | irq_notifier = kzalloc(sizeof(*irq_notifier), GFP_KERNEL); | ||
1123 | if (!irq_notifier) { | ||
1124 | mlx4_warn(dev, "Failed to allocate irq notifier. irq %d\n", | ||
1125 | irq); | ||
1126 | return; | ||
1127 | } | ||
1128 | |||
1129 | irq_notifier->notify.irq = irq; | ||
1130 | irq_notifier->notify.notify = mlx4_irq_notifier_notify; | ||
1131 | irq_notifier->notify.release = mlx4_release_irq_notifier; | ||
1132 | irq_notifier->arg = priv; | ||
1133 | err = irq_set_affinity_notifier(irq, &irq_notifier->notify); | ||
1134 | if (err) { | ||
1135 | kfree(irq_notifier); | ||
1136 | irq_notifier = NULL; | ||
1137 | mlx4_warn(dev, "Failed to set irq notifier. irq %d\n", irq); | ||
1138 | } | ||
1139 | } | ||
1140 | |||
1141 | |||
1142 | int mlx4_alloc_eq_table(struct mlx4_dev *dev) | 1086 | int mlx4_alloc_eq_table(struct mlx4_dev *dev) |
1143 | { | 1087 | { |
1144 | struct mlx4_priv *priv = mlx4_priv(dev); | 1088 | 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, | |||
1409 | continue; | 1353 | continue; |
1410 | /*we dont want to break here*/ | 1354 | /*we dont want to break here*/ |
1411 | } | 1355 | } |
1412 | mlx4_assign_irq_notifier(priv, dev, | ||
1413 | priv->eq_table.eq[vec].irq); | ||
1414 | 1356 | ||
1415 | eq_set_ci(&priv->eq_table.eq[vec], 1); | 1357 | eq_set_ci(&priv->eq_table.eq[vec], 1); |
1416 | } | 1358 | } |
@@ -1427,6 +1369,14 @@ int mlx4_assign_eq(struct mlx4_dev *dev, char *name, struct cpu_rmap *rmap, | |||
1427 | } | 1369 | } |
1428 | EXPORT_SYMBOL(mlx4_assign_eq); | 1370 | EXPORT_SYMBOL(mlx4_assign_eq); |
1429 | 1371 | ||
1372 | int mlx4_eq_get_irq(struct mlx4_dev *dev, int vec) | ||
1373 | { | ||
1374 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
1375 | |||
1376 | return priv->eq_table.eq[vec].irq; | ||
1377 | } | ||
1378 | EXPORT_SYMBOL(mlx4_eq_get_irq); | ||
1379 | |||
1430 | void mlx4_release_eq(struct mlx4_dev *dev, int vec) | 1380 | void mlx4_release_eq(struct mlx4_dev *dev, int vec) |
1431 | { | 1381 | { |
1432 | struct mlx4_priv *priv = mlx4_priv(dev); | 1382 | struct mlx4_priv *priv = mlx4_priv(dev); |
@@ -1438,9 +1388,6 @@ void mlx4_release_eq(struct mlx4_dev *dev, int vec) | |||
1438 | Belonging to a legacy EQ*/ | 1388 | Belonging to a legacy EQ*/ |
1439 | mutex_lock(&priv->msix_ctl.pool_lock); | 1389 | mutex_lock(&priv->msix_ctl.pool_lock); |
1440 | if (priv->msix_ctl.pool_bm & 1ULL << i) { | 1390 | if (priv->msix_ctl.pool_bm & 1ULL << i) { |
1441 | irq_set_affinity_notifier( | ||
1442 | priv->eq_table.eq[vec].irq, | ||
1443 | NULL); | ||
1444 | free_irq(priv->eq_table.eq[vec].irq, | 1391 | free_irq(priv->eq_table.eq[vec].irq, |
1445 | &priv->eq_table.eq[vec]); | 1392 | &priv->eq_table.eq[vec]); |
1446 | priv->msix_ctl.pool_bm &= ~(1ULL << i); | 1393 | priv->msix_ctl.pool_bm &= ~(1ULL << i); |
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 0e15295bedd6..624e1939e9ee 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | |||
@@ -343,6 +343,7 @@ struct mlx4_en_cq { | |||
343 | #define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD) | 343 | #define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD) |
344 | spinlock_t poll_lock; /* protects from LLS/napi conflicts */ | 344 | spinlock_t poll_lock; /* protects from LLS/napi conflicts */ |
345 | #endif /* CONFIG_NET_RX_BUSY_POLL */ | 345 | #endif /* CONFIG_NET_RX_BUSY_POLL */ |
346 | struct irq_desc *irq_desc; | ||
346 | }; | 347 | }; |
347 | 348 | ||
348 | struct mlx4_en_port_profile { | 349 | struct mlx4_en_port_profile { |
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index b12f4bbd064c..35b51e7af886 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h | |||
@@ -578,8 +578,6 @@ struct mlx4_cq { | |||
578 | u32 cons_index; | 578 | u32 cons_index; |
579 | 579 | ||
580 | u16 irq; | 580 | u16 irq; |
581 | bool irq_affinity_change; | ||
582 | |||
583 | __be32 *set_ci_db; | 581 | __be32 *set_ci_db; |
584 | __be32 *arm_db; | 582 | __be32 *arm_db; |
585 | int arm_sn; | 583 | int arm_sn; |
@@ -1167,6 +1165,8 @@ int mlx4_assign_eq(struct mlx4_dev *dev, char *name, struct cpu_rmap *rmap, | |||
1167 | int *vector); | 1165 | int *vector); |
1168 | void mlx4_release_eq(struct mlx4_dev *dev, int vec); | 1166 | void mlx4_release_eq(struct mlx4_dev *dev, int vec); |
1169 | 1167 | ||
1168 | int mlx4_eq_get_irq(struct mlx4_dev *dev, int vec); | ||
1169 | |||
1170 | int mlx4_get_phys_port_id(struct mlx4_dev *dev); | 1170 | int mlx4_get_phys_port_id(struct mlx4_dev *dev); |
1171 | int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port); | 1171 | int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port); |
1172 | int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port); | 1172 | int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port); |