aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYevgeny Petrilin <yevgenyp@mellanox.co.il>2011-03-22 18:37:47 -0400
committerDavid S. Miller <davem@davemloft.net>2011-03-23 15:24:18 -0400
commit0b7ca5a928e2271bbc225e9e1ac1f22e9fbee54f (patch)
tree8a24efdb4ceb6f28a8d49e942f80d397c06f4a5f
parent908222655b38005483d64385e06341a38647fdf1 (diff)
mlx4: Changing interrupt scheme
Adding a pool of MSI-X vectors and EQs that can be used explicitly by mlx4_core customers (mlx4_ib, mlx4_en). The consumers will assign their own names to the interrupt vectors. Those vectors are not opened at mlx4 device initialization, opened by demand. Changed the max number of possible EQs according to the new scheme, no longer relies on on number of cores. The new functionality is exposed through mlx4_assign_eq() and mlx4_release_eq(). Customers that do not use the new API will get completion vectors as before. Signed-off-by: Markuze Alex <markuze@mellanox.co.il> Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/mlx4/cq.c2
-rw-r--r--drivers/net/mlx4/eq.c107
-rw-r--r--drivers/net/mlx4/main.c20
-rw-r--r--drivers/net/mlx4/mlx4.h6
-rw-r--r--drivers/net/mlx4/profile.c4
-rw-r--r--include/linux/mlx4/device.h8
6 files changed, 134 insertions, 13 deletions
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
index 7cd34e9c7c7e..bd8ef9f2fa71 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/mlx4/cq.c
@@ -198,7 +198,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
198 u64 mtt_addr; 198 u64 mtt_addr;
199 int err; 199 int err;
200 200
201 if (vector >= dev->caps.num_comp_vectors) 201 if (vector > dev->caps.num_comp_vectors + dev->caps.comp_pool)
202 return -EINVAL; 202 return -EINVAL;
203 203
204 cq->vector = vector; 204 cq->vector = vector;
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 552d0fce6f67..506cfd0372ec 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -42,7 +42,7 @@
42#include "fw.h" 42#include "fw.h"
43 43
44enum { 44enum {
45 MLX4_IRQNAME_SIZE = 64 45 MLX4_IRQNAME_SIZE = 32
46}; 46};
47 47
48enum { 48enum {
@@ -317,8 +317,8 @@ static int mlx4_num_eq_uar(struct mlx4_dev *dev)
317 * we need to map, take the difference of highest index and 317 * we need to map, take the difference of highest index and
318 * the lowest index we'll use and add 1. 318 * the lowest index we'll use and add 1.
319 */ 319 */
320 return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs) / 4 - 320 return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs +
321 dev->caps.reserved_eqs / 4 + 1; 321 dev->caps.comp_pool)/4 - dev->caps.reserved_eqs/4 + 1;
322} 322}
323 323
324static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) 324static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)
@@ -496,16 +496,32 @@ static void mlx4_free_eq(struct mlx4_dev *dev,
496static void mlx4_free_irqs(struct mlx4_dev *dev) 496static void mlx4_free_irqs(struct mlx4_dev *dev)
497{ 497{
498 struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; 498 struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table;
499 int i; 499 struct mlx4_priv *priv = mlx4_priv(dev);
500 int i, vec;
500 501
501 if (eq_table->have_irq) 502 if (eq_table->have_irq)
502 free_irq(dev->pdev->irq, dev); 503 free_irq(dev->pdev->irq, dev);
504
503 for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) 505 for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
504 if (eq_table->eq[i].have_irq) { 506 if (eq_table->eq[i].have_irq) {
505 free_irq(eq_table->eq[i].irq, eq_table->eq + i); 507 free_irq(eq_table->eq[i].irq, eq_table->eq + i);
506 eq_table->eq[i].have_irq = 0; 508 eq_table->eq[i].have_irq = 0;
507 } 509 }
508 510
511 for (i = 0; i < dev->caps.comp_pool; i++) {
512 /*
513 * Freeing the assigned irq's
514 * all bits should be 0, but we need to validate
515 */
516 if (priv->msix_ctl.pool_bm & 1ULL << i) {
517 /* NO need protecting*/
518 vec = dev->caps.num_comp_vectors + 1 + i;
519 free_irq(priv->eq_table.eq[vec].irq,
520 &priv->eq_table.eq[vec]);
521 }
522 }
523
524
509 kfree(eq_table->irq_names); 525 kfree(eq_table->irq_names);
510} 526}
511 527
@@ -578,7 +594,8 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
578 (priv->eq_table.inta_pin < 32 ? 4 : 0); 594 (priv->eq_table.inta_pin < 32 ? 4 : 0);
579 595
580 priv->eq_table.irq_names = 596 priv->eq_table.irq_names =
581 kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1), 597 kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1 +
598 dev->caps.comp_pool),
582 GFP_KERNEL); 599 GFP_KERNEL);
583 if (!priv->eq_table.irq_names) { 600 if (!priv->eq_table.irq_names) {
584 err = -ENOMEM; 601 err = -ENOMEM;
@@ -601,6 +618,22 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
601 if (err) 618 if (err)
602 goto err_out_comp; 619 goto err_out_comp;
603 620
621 /*if additional completion vectors poolsize is 0 this loop will not run*/
622 for (i = dev->caps.num_comp_vectors + 1;
623 i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) {
624
625 err = mlx4_create_eq(dev, dev->caps.num_cqs -
626 dev->caps.reserved_cqs +
627 MLX4_NUM_SPARE_EQE,
628 (dev->flags & MLX4_FLAG_MSI_X) ? i : 0,
629 &priv->eq_table.eq[i]);
630 if (err) {
631 --i;
632 goto err_out_unmap;
633 }
634 }
635
636
604 if (dev->flags & MLX4_FLAG_MSI_X) { 637 if (dev->flags & MLX4_FLAG_MSI_X) {
605 const char *eq_name; 638 const char *eq_name;
606 639
@@ -686,7 +719,7 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
686 719
687 mlx4_free_irqs(dev); 720 mlx4_free_irqs(dev);
688 721
689 for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) 722 for (i = 0; i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i)
690 mlx4_free_eq(dev, &priv->eq_table.eq[i]); 723 mlx4_free_eq(dev, &priv->eq_table.eq[i]);
691 724
692 mlx4_unmap_clr_int(dev); 725 mlx4_unmap_clr_int(dev);
@@ -743,3 +776,65 @@ int mlx4_test_interrupts(struct mlx4_dev *dev)
743 return err; 776 return err;
744} 777}
745EXPORT_SYMBOL(mlx4_test_interrupts); 778EXPORT_SYMBOL(mlx4_test_interrupts);
779
780int mlx4_assign_eq(struct mlx4_dev *dev, char* name, int * vector)
781{
782
783 struct mlx4_priv *priv = mlx4_priv(dev);
784 int vec = 0, err = 0, i;
785
786 spin_lock(&priv->msix_ctl.pool_lock);
787 for (i = 0; !vec && i < dev->caps.comp_pool; i++) {
788 if (~priv->msix_ctl.pool_bm & 1ULL << i) {
789 priv->msix_ctl.pool_bm |= 1ULL << i;
790 vec = dev->caps.num_comp_vectors + 1 + i;
791 snprintf(priv->eq_table.irq_names +
792 vec * MLX4_IRQNAME_SIZE,
793 MLX4_IRQNAME_SIZE, "%s", name);
794 err = request_irq(priv->eq_table.eq[vec].irq,
795 mlx4_msi_x_interrupt, 0,
796 &priv->eq_table.irq_names[vec<<5],
797 priv->eq_table.eq + vec);
798 if (err) {
799 /*zero out bit by fliping it*/
800 priv->msix_ctl.pool_bm ^= 1 << i;
801 vec = 0;
802 continue;
803 /*we dont want to break here*/
804 }
805 eq_set_ci(&priv->eq_table.eq[vec], 1);
806 }
807 }
808 spin_unlock(&priv->msix_ctl.pool_lock);
809
810 if (vec) {
811 *vector = vec;
812 } else {
813 *vector = 0;
814 err = (i == dev->caps.comp_pool) ? -ENOSPC : err;
815 }
816 return err;
817}
818EXPORT_SYMBOL(mlx4_assign_eq);
819
820void mlx4_release_eq(struct mlx4_dev *dev, int vec)
821{
822 struct mlx4_priv *priv = mlx4_priv(dev);
823 /*bm index*/
824 int i = vec - dev->caps.num_comp_vectors - 1;
825
826 if (likely(i >= 0)) {
827 /*sanity check , making sure were not trying to free irq's
828 Belonging to a legacy EQ*/
829 spin_lock(&priv->msix_ctl.pool_lock);
830 if (priv->msix_ctl.pool_bm & 1ULL << i) {
831 free_irq(priv->eq_table.eq[vec].irq,
832 &priv->eq_table.eq[vec]);
833 priv->msix_ctl.pool_bm &= ~(1ULL << i);
834 }
835 spin_unlock(&priv->msix_ctl.pool_lock);
836 }
837
838}
839EXPORT_SYMBOL(mlx4_release_eq);
840
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 2765a3ce9c24..517ca34f5b37 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -969,13 +969,15 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
969{ 969{
970 struct mlx4_priv *priv = mlx4_priv(dev); 970 struct mlx4_priv *priv = mlx4_priv(dev);
971 struct msix_entry *entries; 971 struct msix_entry *entries;
972 int nreq; 972 int nreq = min_t(int, dev->caps.num_ports *
973 min_t(int, num_online_cpus() + 1, MAX_MSIX_P_PORT)
974 + MSIX_LEGACY_SZ, MAX_MSIX);
973 int err; 975 int err;
974 int i; 976 int i;
975 977
976 if (msi_x) { 978 if (msi_x) {
977 nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, 979 nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs,
978 num_possible_cpus() + 1); 980 nreq);
979 entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); 981 entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL);
980 if (!entries) 982 if (!entries)
981 goto no_msi; 983 goto no_msi;
@@ -998,7 +1000,15 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
998 goto no_msi; 1000 goto no_msi;
999 } 1001 }
1000 1002
1001 dev->caps.num_comp_vectors = nreq - 1; 1003 if (nreq <
1004 MSIX_LEGACY_SZ + dev->caps.num_ports * MIN_MSIX_P_PORT) {
1005 /*Working in legacy mode , all EQ's shared*/
1006 dev->caps.comp_pool = 0;
1007 dev->caps.num_comp_vectors = nreq - 1;
1008 } else {
1009 dev->caps.comp_pool = nreq - MSIX_LEGACY_SZ;
1010 dev->caps.num_comp_vectors = MSIX_LEGACY_SZ - 1;
1011 }
1002 for (i = 0; i < nreq; ++i) 1012 for (i = 0; i < nreq; ++i)
1003 priv->eq_table.eq[i].irq = entries[i].vector; 1013 priv->eq_table.eq[i].irq = entries[i].vector;
1004 1014
@@ -1010,6 +1020,7 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
1010 1020
1011no_msi: 1021no_msi:
1012 dev->caps.num_comp_vectors = 1; 1022 dev->caps.num_comp_vectors = 1;
1023 dev->caps.comp_pool = 0;
1013 1024
1014 for (i = 0; i < 2; ++i) 1025 for (i = 0; i < 2; ++i)
1015 priv->eq_table.eq[i].irq = dev->pdev->irq; 1026 priv->eq_table.eq[i].irq = dev->pdev->irq;
@@ -1151,6 +1162,9 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
1151 if (err) 1162 if (err)
1152 goto err_close; 1163 goto err_close;
1153 1164
1165 priv->msix_ctl.pool_bm = 0;
1166 spin_lock_init(&priv->msix_ctl.pool_lock);
1167
1154 mlx4_enable_msi_x(dev); 1168 mlx4_enable_msi_x(dev);
1155 1169
1156 err = mlx4_setup_hca(dev); 1170 err = mlx4_setup_hca(dev);
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 0da5bb7285b4..67ee8dacae79 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -282,6 +282,11 @@ struct mlx4_sense {
282 struct delayed_work sense_poll; 282 struct delayed_work sense_poll;
283}; 283};
284 284
285struct mlx4_msix_ctl {
286 u64 pool_bm;
287 spinlock_t pool_lock;
288};
289
285struct mlx4_priv { 290struct mlx4_priv {
286 struct mlx4_dev dev; 291 struct mlx4_dev dev;
287 292
@@ -313,6 +318,7 @@ struct mlx4_priv {
313 struct mlx4_port_info port[MLX4_MAX_PORTS + 1]; 318 struct mlx4_port_info port[MLX4_MAX_PORTS + 1];
314 struct mlx4_sense sense; 319 struct mlx4_sense sense;
315 struct mutex port_mutex; 320 struct mutex port_mutex;
321 struct mlx4_msix_ctl msix_ctl;
316}; 322};
317 323
318static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) 324static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c
index e749f82865fe..b967647d0c76 100644
--- a/drivers/net/mlx4/profile.c
+++ b/drivers/net/mlx4/profile.c
@@ -107,9 +107,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
107 profile[MLX4_RES_AUXC].num = request->num_qp; 107 profile[MLX4_RES_AUXC].num = request->num_qp;
108 profile[MLX4_RES_SRQ].num = request->num_srq; 108 profile[MLX4_RES_SRQ].num = request->num_srq;
109 profile[MLX4_RES_CQ].num = request->num_cq; 109 profile[MLX4_RES_CQ].num = request->num_cq;
110 profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs, 110 profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs, MAX_MSIX);
111 dev_cap->reserved_eqs +
112 num_possible_cpus() + 1);
113 profile[MLX4_RES_DMPT].num = request->num_mpt; 111 profile[MLX4_RES_DMPT].num = request->num_mpt;
114 profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; 112 profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS;
115 profile[MLX4_RES_MTT].num = request->num_mtt; 113 profile[MLX4_RES_MTT].num = request->num_mtt;
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 049214642036..78380823d827 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -39,6 +39,11 @@
39 39
40#include <asm/atomic.h> 40#include <asm/atomic.h>
41 41
42#define MAX_MSIX_P_PORT 17
43#define MAX_MSIX 64
44#define MSIX_LEGACY_SZ 4
45#define MIN_MSIX_P_PORT 5
46
42enum { 47enum {
43 MLX4_FLAG_MSI_X = 1 << 0, 48 MLX4_FLAG_MSI_X = 1 << 0,
44 MLX4_FLAG_OLD_PORT_CMDS = 1 << 1, 49 MLX4_FLAG_OLD_PORT_CMDS = 1 << 1,
@@ -223,6 +228,7 @@ struct mlx4_caps {
223 int num_eqs; 228 int num_eqs;
224 int reserved_eqs; 229 int reserved_eqs;
225 int num_comp_vectors; 230 int num_comp_vectors;
231 int comp_pool;
226 int num_mpts; 232 int num_mpts;
227 int num_mtt_segs; 233 int num_mtt_segs;
228 int mtts_per_seg; 234 int mtts_per_seg;
@@ -526,5 +532,7 @@ void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr,
526int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); 532int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr);
527int mlx4_SYNC_TPT(struct mlx4_dev *dev); 533int mlx4_SYNC_TPT(struct mlx4_dev *dev);
528int mlx4_test_interrupts(struct mlx4_dev *dev); 534int mlx4_test_interrupts(struct mlx4_dev *dev);
535int mlx4_assign_eq(struct mlx4_dev *dev, char* name , int* vector);
536void mlx4_release_eq(struct mlx4_dev *dev, int vec);
529 537
530#endif /* MLX4_DEVICE_H */ 538#endif /* MLX4_DEVICE_H */