[ofa-general] [PATCH 2 of 3] IB/mthca: support multiple completion vectors

Michael S. Tsirkin mst at dev.mellanox.co.il
Thu May 3 03:49:24 PDT 2007


Support 2 completion vectors in mthca on SMP if MSI-X is enabled

Signed-off-by: Michael S. Tsirkin <mst at dev.mellanox.co.il>

---

I don't know how many vectors make sense, so I decided to be
conservative here, since each EQ consumes a lot of memory by default.

Index: linux-2.6/drivers/infiniband/hw/mthca/mthca_cq.c
===================================================================
--- linux-2.6.orig/drivers/infiniband/hw/mthca/mthca_cq.c
+++ linux-2.6/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -779,7 +779,7 @@ int mthca_arbel_arm_cq(struct ib_cq *ibc
 	return 0;
 }
 
-int mthca_init_cq(struct mthca_dev *dev, int nent,
+int mthca_init_cq(struct mthca_dev *dev, int nent, int comp_vector,
 		  struct mthca_ucontext *ctx, u32 pdn,
 		  struct mthca_cq *cq)
 {
@@ -790,6 +790,7 @@ int mthca_init_cq(struct mthca_dev *dev,
 
 	cq->ibcq.cqe  = nent - 1;
 	cq->is_kernel = !ctx;
+	cq->eq = MTHCA_EQ_COMP + comp_vector;
 
 	cq->cqn = mthca_alloc(&dev->cq_table.alloc);
 	if (cq->cqn == -1)
@@ -844,7 +845,7 @@ int mthca_init_cq(struct mthca_dev *dev,
 	else
 		cq_context->logsize_usrpage |= cpu_to_be32(dev->driver_uar.index);
 	cq_context->error_eqn       = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn);
-	cq_context->comp_eqn        = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn);
+	cq_context->comp_eqn        = cpu_to_be32(dev->eq_table.eq[cq->eq].eqn);
 	cq_context->pd              = cpu_to_be32(pdn);
 	cq_context->lkey            = cpu_to_be32(cq->buf.mr.ibmr.lkey);
 	cq_context->cqn             = cpu_to_be32(cq->cqn);
@@ -954,7 +955,7 @@ void mthca_free_cq(struct mthca_dev *dev
 	spin_unlock_irq(&dev->cq_table.lock);
 
 	if (dev->mthca_flags & MTHCA_FLAG_MSI_X)
-		synchronize_irq(dev->eq_table.eq[MTHCA_EQ_COMP].msi_x_vector);
+		synchronize_irq(dev->eq_table.eq[cq->eq].msi_x_vector);
 	else
 		synchronize_irq(dev->pdev->irq);
 
Index: linux-2.6/drivers/infiniband/hw/mthca/mthca_dev.h
===================================================================
--- linux-2.6.orig/drivers/infiniband/hw/mthca/mthca_dev.h
+++ linux-2.6/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -96,7 +96,9 @@ enum {
 	MTHCA_EQ_CMD,
 	MTHCA_EQ_ASYNC,
 	MTHCA_EQ_COMP,
-	MTHCA_NUM_EQ
+	MTHCA_NUM_EQ,
+	MTHCA_COMP_VECTORS = 2,
+	MTHCA_MAX_EQS = MTHCA_NUM_EQ + MTHCA_COMP_VECTORS - 1
 };
 
 enum {
@@ -230,7 +232,7 @@ struct mthca_eq_table {
 	void __iomem      *clr_int;
 	u32                clr_mask;
 	u32                arm_mask;
-	struct mthca_eq    eq[MTHCA_NUM_EQ];
+	struct mthca_eq    eq[MTHCA_MAX_EQS];
 	u64                icm_virt;
 	struct page       *icm_page;
 	dma_addr_t         icm_dma;
@@ -497,7 +499,7 @@ int mthca_poll_cq(struct ib_cq *ibcq, in
 		  struct ib_wc *entry);
 int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
 int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
-int mthca_init_cq(struct mthca_dev *dev, int nent,
+int mthca_init_cq(struct mthca_dev *dev, int nent, int comp_vector,
 		  struct mthca_ucontext *ctx, u32 pdn,
 		  struct mthca_cq *cq);
 void mthca_free_cq(struct mthca_dev *dev,
Index: linux-2.6/drivers/infiniband/hw/mthca/mthca_eq.c
===================================================================
--- linux-2.6.orig/drivers/infiniband/hw/mthca/mthca_eq.c
+++ linux-2.6/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -161,6 +161,11 @@ struct mthca_eqe {
 	u8 owner;
 } __attribute__((packed));
 
+static inline int mthca_num_eq(struct mthca_dev *dev)
+{
+	return dev->ib_dev.num_comp_vectors + MTHCA_NUM_EQ - 1;
+}
+
 #define  MTHCA_EQ_ENTRY_OWNER_SW      (0 << 7)
 #define  MTHCA_EQ_ENTRY_OWNER_HW      (1 << 7)
 
@@ -579,8 +584,7 @@ static int mthca_create_eq(struct mthca_
 
 	dev->eq_table.arm_mask |= eq->eqn_mask;
 
-	mthca_dbg(dev, "Allocated EQ %d with %d entries\n",
-		  eq->eqn, eq->nent);
+	mthca_dbg(dev, "Allocated EQ %d with %d entries\n", eq->eqn, eq->nent);
 
 	return err;
 
@@ -657,7 +661,7 @@ static void mthca_free_irqs(struct mthca
 
 	if (dev->eq_table.have_irq)
 		free_irq(dev->pdev->irq, dev);
-	for (i = 0; i < MTHCA_NUM_EQ; ++i)
+	for (i = 0; i < mthca_num_eq(dev); ++i)
 		if (dev->eq_table.eq[i].have_irq)
 			free_irq(dev->eq_table.eq[i].msi_x_vector,
 				 dev->eq_table.eq + i);
@@ -824,12 +828,37 @@ void mthca_unmap_eq_icm(struct mthca_dev
 	__free_page(dev->eq_table.icm_page);
 }
 
+static inline const char *eq_name(int i)
+{
+	switch (i) {
+	case MTHCA_EQ_ASYNC:
+		return DRV_NAME " (async)";
+	case MTHCA_EQ_CMD:
+		return DRV_NAME " (cmd)";
+	default:
+		return DRV_NAME " (comp)";
+	}
+}
+
+static inline int eq_size(struct mthca_dev *dev, int i)
+{
+	switch (i) {
+	case MTHCA_EQ_ASYNC:
+		return MTHCA_NUM_ASYNC_EQE;
+	case MTHCA_EQ_CMD:
+		return MTHCA_NUM_CMD_EQE;
+	default:
+		return dev->limits.num_cqs;
+	}
+}
+
+
 int mthca_init_eq_table(struct mthca_dev *dev)
 {
 	int err;
 	u8 status;
 	u8 intr;
-	int i;
+	int i, eqn;
 
 	err = mthca_alloc_init(&dev->eq_table.alloc,
 			       dev->limits.num_eqs,
@@ -857,39 +886,29 @@ int mthca_init_eq_table(struct mthca_dev
 	intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ?
 		128 : dev->eq_table.inta_pin;
 
-	err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE,
-			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr,
-			      &dev->eq_table.eq[MTHCA_EQ_COMP]);
-	if (err)
-		goto err_out_unmap;
-
-	err = mthca_create_eq(dev, MTHCA_NUM_ASYNC_EQE + MTHCA_NUM_SPARE_EQE,
-			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 129 : intr,
-			      &dev->eq_table.eq[MTHCA_EQ_ASYNC]);
-	if (err)
-		goto err_out_comp;
-
-	err = mthca_create_eq(dev, MTHCA_NUM_CMD_EQE + MTHCA_NUM_SPARE_EQE,
-			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 130 : intr,
-			      &dev->eq_table.eq[MTHCA_EQ_CMD]);
-	if (err)
-		goto err_out_async;
+	for (eqn = 0; eqn < mthca_num_eq(dev); ++eqn) {
+		err = mthca_create_eq(dev, eq_size(dev, eqn) + MTHCA_NUM_SPARE_EQE,
+				      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ?
+				      128 + eqn : intr,
+				      &dev->eq_table.eq[eqn]);
+		if (err)
+			goto err_out_eq;
+	}
 
 	if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {
-		static const char *eq_name[] = {
-			[MTHCA_EQ_COMP]  = DRV_NAME " (comp)",
-			[MTHCA_EQ_ASYNC] = DRV_NAME " (async)",
-			[MTHCA_EQ_CMD]   = DRV_NAME " (cmd)"
-		};
-
-		for (i = 0; i < MTHCA_NUM_EQ; ++i) {
+		for (i = 0; i < mthca_num_eq(dev); ++i) {
 			err = request_irq(dev->eq_table.eq[i].msi_x_vector,
 					  mthca_is_memfree(dev) ?
 					  mthca_arbel_msi_x_interrupt :
 					  mthca_tavor_msi_x_interrupt,
-					  0, eq_name[i], dev->eq_table.eq + i);
-			if (err)
-				goto err_out_cmd;
+					  0, eq_name(i), dev->eq_table.eq + i);
+			if (err) {
+				mthca_err(dev, "Failed to request IRQ %d for EQ %d (%d),"
+					 " aborting.\n",
+					 dev->eq_table.eq[i].msi_x_vector,
+					 dev->eq_table.eq[i].eqn, i);
+				goto err_out_irq;
+			}
 			dev->eq_table.eq[i].have_irq = 1;
 		}
 	} else {
@@ -898,8 +917,11 @@ int mthca_init_eq_table(struct mthca_dev
 				  mthca_arbel_interrupt :
 				  mthca_tavor_interrupt,
 				  IRQF_SHARED, DRV_NAME, dev);
-		if (err)
-			goto err_out_cmd;
+		if (err) {
+			mthca_err(dev, "Failed to request IRQ %d, aborting.\n",
+				  dev->pdev->irq);
+			goto err_out_eq;
+		}
 		dev->eq_table.have_irq = 1;
 	}
 
@@ -921,7 +943,7 @@ int mthca_init_eq_table(struct mthca_dev
 		mthca_warn(dev, "MAP_EQ for cmd EQ %d returned status 0x%02x\n",
 			   dev->eq_table.eq[MTHCA_EQ_CMD].eqn, status);
 
-	for (i = 0; i < MTHCA_NUM_EQ; ++i)
+	for (i = 0; i < mthca_num_eq(dev); ++i)
 		if (mthca_is_memfree(dev))
 			arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask);
 		else
@@ -929,17 +951,13 @@ int mthca_init_eq_table(struct mthca_dev
 
 	return 0;
 
-err_out_cmd:
+err_out_irq:
 	mthca_free_irqs(dev);
-	mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_CMD]);
 
-err_out_async:
-	mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_ASYNC]);
-
-err_out_comp:
-	mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_COMP]);
+err_out_eq:
+	for (i = 0; i < eqn; ++i)
+		mthca_free_eq(dev, &dev->eq_table.eq[i]);
 
-err_out_unmap:
 	mthca_unmap_eq_regs(dev);
 
 err_out_free:
@@ -959,7 +977,7 @@ void mthca_cleanup_eq_table(struct mthca
 	mthca_MAP_EQ(dev, MTHCA_CMD_EVENT_MASK,
 		     1, dev->eq_table.eq[MTHCA_EQ_CMD].eqn, &status);
 
-	for (i = 0; i < MTHCA_NUM_EQ; ++i)
+	for (i = 0; i < mthca_num_eq(dev); ++i)
 		mthca_free_eq(dev, &dev->eq_table.eq[i]);
 
 	mthca_unmap_eq_regs(dev);
Index: linux-2.6/drivers/infiniband/hw/mthca/mthca_main.c
===================================================================
--- linux-2.6.orig/drivers/infiniband/hw/mthca/mthca_main.c
+++ linux-2.6/drivers/infiniband/hw/mthca/mthca_main.c
@@ -39,6 +39,7 @@
 #include <linux/errno.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
+#include <linux/cpumask.h>
 
 #include "mthca_dev.h"
 #include "mthca_config_reg.h"
@@ -976,24 +977,35 @@ static void mthca_release_regions(struct
 
 static int mthca_enable_msi_x(struct mthca_dev *mdev)
 {
-	struct msix_entry entries[3];
-	int err;
+	struct msix_entry entries[MTHCA_MAX_EQS];
+	int i, err, num;
 
-	entries[0].entry = 0;
-	entries[1].entry = 1;
-	entries[2].entry = 2;
-
-	err = pci_enable_msix(mdev->pdev, entries, ARRAY_SIZE(entries));
-	if (err) {
-		if (err > 0)
-			mthca_info(mdev, "Only %d MSI-X vectors available, "
-				   "not using MSI-X\n", err);
-		return err;
+	num = min(mdev->limits.num_eqs - mdev->limits.reserved_eqs, MTHCA_MAX_EQS);
+	num = min(num_possible_cpus(), num);
+
+	for (i = 0; i < num; ++i)
+		entries[i].entry = i;
+
+	for (;;) {
+		err = pci_enable_msix(mdev->pdev, entries, num);
+		if (!err)
+			break;
+		else if (err < 0)
+			return err;
+
+		if (err < MTHCA_NUM_EQ) {
+			mthca_info(mdev, "Only %d MSI-X vectors available. "
+				   "Not using MSI-X\n", err);
+			pci_disable_msix(mdev->pdev);
+			return err;
+		}
+
+		num = err;
 	}
 
-	mdev->eq_table.eq[MTHCA_EQ_COMP ].msi_x_vector = entries[0].vector;
-	mdev->eq_table.eq[MTHCA_EQ_ASYNC].msi_x_vector = entries[1].vector;
-	mdev->eq_table.eq[MTHCA_EQ_CMD  ].msi_x_vector = entries[2].vector;
+	mdev->ib_dev.num_comp_vectors = num - MTHCA_NUM_EQ + 1;
+	for (i = 0; i < num; ++i)
+		mdev->eq_table.eq[i].msi_x_vector = entries[i].vector;
 
 	return 0;
 }
@@ -1115,12 +1127,6 @@ static int __mthca_init_one(struct pci_d
 		goto err_free_dev;
 	}
 
-	if (msi_x && !mthca_enable_msi_x(mdev))
-		mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
-	if (msi && !(mdev->mthca_flags & MTHCA_FLAG_MSI_X) &&
-	    !pci_enable_msi(pdev))
-		mdev->mthca_flags |= MTHCA_FLAG_MSI;
-
 	if (mthca_cmd_init(mdev)) {
 		mthca_err(mdev, "Failed to init command interface, aborting.\n");
 		goto err_free_dev;
@@ -1144,6 +1150,12 @@ static int __mthca_init_one(struct pci_d
 		mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n");
 	}
 
+	if (msi_x && !mthca_enable_msi_x(mdev))
+		mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
+	if (msi && !(mdev->mthca_flags & MTHCA_FLAG_MSI_X) &&
+	    !pci_enable_msi(pdev))
+		mdev->mthca_flags |= MTHCA_FLAG_MSI;
+
 	err = mthca_setup_hca(mdev);
 	if (err)
 		goto err_close;
@@ -1180,17 +1192,17 @@ err_cleanup:
 	mthca_cleanup_uar_table(mdev);
 
 err_close:
+	if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
+		pci_disable_msix(pdev);
+	if (mdev->mthca_flags & MTHCA_FLAG_MSI)
+		pci_disable_msi(pdev);
+
 	mthca_close_hca(mdev);
 
 err_cmd:
 	mthca_cmd_cleanup(mdev);
 
 err_free_dev:
-	if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
-		pci_disable_msix(pdev);
-	if (mdev->mthca_flags & MTHCA_FLAG_MSI)
-		pci_disable_msi(pdev);
-
 	ib_dealloc_device(&mdev->ib_dev);
 
 err_free_res:
@@ -1231,14 +1243,15 @@ static void __mthca_remove_one(struct pc
 		iounmap(mdev->kar);
 		mthca_uar_free(mdev, &mdev->driver_uar);
 		mthca_cleanup_uar_table(mdev);
-		mthca_close_hca(mdev);
-		mthca_cmd_cleanup(mdev);
 
 		if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
 			pci_disable_msix(pdev);
 		if (mdev->mthca_flags & MTHCA_FLAG_MSI)
 			pci_disable_msi(pdev);
 
+		mthca_close_hca(mdev);
+		mthca_cmd_cleanup(mdev);
+
 		ib_dealloc_device(&mdev->ib_dev);
 		mthca_release_regions(pdev, mdev->mthca_flags &
 				      MTHCA_FLAG_DDR_HIDDEN);
Index: linux-2.6/drivers/infiniband/hw/mthca/mthca_provider.c
===================================================================
--- linux-2.6.orig/drivers/infiniband/hw/mthca/mthca_provider.c
+++ linux-2.6/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -707,7 +707,7 @@ static struct ib_cq *mthca_create_cq(str
 	for (nent = 1; nent <= entries; nent <<= 1)
 		; /* nothing */
 
-	err = mthca_init_cq(to_mdev(ibdev), nent,
+	err = mthca_init_cq(to_mdev(ibdev), nent, comp_vector,
 			    context ? to_mucontext(context) : NULL,
 			    context ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num,
 			    cq);
Index: linux-2.6/drivers/infiniband/hw/mthca/mthca_provider.h
===================================================================
--- linux-2.6.orig/drivers/infiniband/hw/mthca/mthca_provider.h
+++ linux-2.6/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -202,6 +202,7 @@ struct mthca_cq {
 	spinlock_t		lock;
 	int			refcount;
 	int			cqn;
+	int			eq;
 	u32			cons_index;
 	struct mthca_cq_buf	buf;
 	struct mthca_cq_resize *resize_buf;

-- 
MST



More information about the general mailing list