[openib-general] [PATCH] mthca - command interface

Eli Cohen eli at mellanox.co.il
Mon Feb 20 02:53:04 PST 2006


This patch is checks whether the HCA supports posting commands through
doorbells and if they are, will configure the driver accordingly. This
functionality can be controlled by the value of a read/write paramter -
post_cmd2dbell. When 0 commands are posted through HCR - otherwise if
HCA is capable commands go through doorbell. The value of the parameter
works collectively on all available HCAs.
This use of UAR0 to post commands eliminates the need for polling the go
bit prior to posting a new command. Since reading from a PCI device is
much more expensive then issuing a posted write, it is expected that
this command will provide better CPU utilization. We are currently
developing such tests and once we have results I will post them in this
list.

Signed-off-by: Eli Cohen <eli at mellanox.co.il>

Index: source/drivers/infiniband/hw/mthca/mthca_dev.h
===================================================================
--- source.orig/drivers/infiniband/hw/mthca/mthca_dev.h
+++ source/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -117,9 +117,18 @@ enum {
 	MTHCA_OPCODE_INVALID        = 0xff
 };
 
+enum {
+	MTHCA_CMD_USE_EVENTS         = (1 << 0),
+	MTHCA_CMD_CAN_POST_DOORBELLS = (1 << 1),
+	MTHCA_CMD_POST_DOORBELLS     = (1 << 2)
+};
+
+enum {
+	MTHCA_CMD_NUM_DBELL_DWORDS = 8
+};
+
 struct mthca_cmd {
 	struct pci_pool          *pool;
-	int                       use_events;
 	struct mutex              hcr_mutex;
 	struct semaphore 	  poll_sem;
 	struct semaphore 	  event_sem;
@@ -128,6 +137,10 @@ struct mthca_cmd {
 	int                       free_head;
 	struct mthca_cmd_context *context;
 	u16                       token_mask;
+	u32                       flags;
+	void __iomem             *dbell_map;
+	u64                       dbell_base;
+	u16                       dbell_offsets[MTHCA_CMD_NUM_DBELL_DWORDS];
 };
 
 struct mthca_limits {
Index: source/drivers/infiniband/hw/mthca/mthca_cmd.c
===================================================================
--- source.orig/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ source/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -182,25 +182,68 @@ struct mthca_cmd_context {
 	u8                status;
 };
 
+
+static int post_cmd2dbell = 1;
+module_param(post_cmd2dbell, int, 0666);
+MODULE_PARM_DESC(post_cmd2dbell, "post commands through doorbell");
+
 static inline int go_bit(struct mthca_dev *dev)
 {
 	return readl(dev->hcr + HCR_STATUS_OFFSET) &
 		swab32(1 << HCR_GO_BIT);
 }
 
-static int mthca_cmd_post(struct mthca_dev *dev,
-			  u64 in_param,
-			  u64 out_param,
-			  u32 in_modifier,
-			  u8 op_modifier,
-			  u16 op,
-			  u16 token,
-			  int event)
+
+static void mthca_cmd_post_dbell(struct mthca_dev *dev,
+				 u64 in_param,
+				 u64 out_param,
+				 u32 in_modifier,
+				 u8 op_modifier,
+				 u16 op,
+				 u16 token)
 {
-	int err = 0;
+	void __iomem *ptr = dev->cmd.dbell_map;
+	u16 *offs = dev->cmd.dbell_offsets;
 
-	mutex_lock(&dev->cmd.hcr_mutex);
+	__raw_writel((__force u32) cpu_to_be32(in_param >> 32),
+		     ptr + offs[0]);
+	wmb();
+	__raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful),
+		     ptr + offs[1]);
+	wmb();
+	__raw_writel((__force u32) cpu_to_be32(in_modifier),
+		     ptr + offs[2]);
+	wmb();
+	__raw_writel((__force u32) cpu_to_be32(out_param >> 32),
+		     ptr + offs[3]);
+	wmb();
+	__raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful),
+		     ptr + offs[4]);
+	wmb();
+	__raw_writel((__force u32) cpu_to_be32(token << 16),
+		     ptr + offs[5]);
+	wmb();
+	__raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) |
+					       (1 << HCA_E_BIT) |
+					       (op_modifier << HCR_OPMOD_SHIFT) |
+					        op),
+		     ptr + offs[6]);
+	wmb();
+	__raw_writel((__force u32) 0,
+		     ptr + offs[7]);
+	wmb();
+}
 
+
+static int mthca_cmd_post_hcr(struct mthca_dev *dev,
+			      u64 in_param,
+			      u64 out_param,
+			      u32 in_modifier,
+			      u8 op_modifier,
+			      u16 op,
+			      u16 token,
+			      int event)
+{
 	if (event) {
 		unsigned long end = jiffies + GO_BIT_TIMEOUT;
 
@@ -210,10 +253,8 @@ static int mthca_cmd_post(struct mthca_d
 		}
 	}
 
-	if (go_bit(dev)) {
-		err = -EAGAIN;
-		goto out;
-	}
+	if (go_bit(dev))
+		return -EAGAIN;
 
 	/*
 	 * We use writel (instead of something like memcpy_toio)
@@ -236,7 +277,29 @@ static int mthca_cmd_post(struct mthca_d
 					       (op_modifier << HCR_OPMOD_SHIFT) |
 					       op),                       dev->hcr + 6 * 4);
 
-out:
+	return 0;
+}
+
+static int mthca_cmd_post(struct mthca_dev *dev,
+			  u64 in_param,
+			  u64 out_param,
+			  u32 in_modifier,
+			  u8 op_modifier,
+			  u16 op,
+			  u16 token,
+			  int event)
+{
+	int err = 0;
+
+	mutex_lock(&dev->cmd.hcr_mutex);
+
+	if (event && dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS && post_cmd2dbell)
+		mthca_cmd_post_dbell(dev, in_param, out_param, in_modifier,
+					   op_modifier, op, token);
+	else
+		err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier,
+					 op_modifier, op, token, event);
+
 	mutex_unlock(&dev->cmd.hcr_mutex);
 	return err;
 }
@@ -386,7 +449,7 @@ static int mthca_cmd_box(struct mthca_de
 			 unsigned long timeout,
 			 u8 *status)
 {
-	if (dev->cmd.use_events)
+	if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
 		return mthca_cmd_wait(dev, in_param, &out_param, 0,
 				      in_modifier, op_modifier, op,
 				      timeout, status);
@@ -423,7 +486,7 @@ static int mthca_cmd_imm(struct mthca_de
 			 unsigned long timeout,
 			 u8 *status)
 {
-	if (dev->cmd.use_events)
+	if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
 		return mthca_cmd_wait(dev, in_param, out_param, 1,
 				      in_modifier, op_modifier, op,
 				      timeout, status);
@@ -437,7 +500,7 @@ int mthca_cmd_init(struct mthca_dev *dev
 {
 	mutex_init(&dev->cmd.hcr_mutex);
 	sema_init(&dev->cmd.poll_sem, 1);
-	dev->cmd.use_events = 0;
+	dev->cmd.flags &= ~MTHCA_CMD_USE_EVENTS;
 
 	dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
 			   MTHCA_HCR_SIZE);
@@ -461,6 +524,8 @@ void mthca_cmd_cleanup(struct mthca_dev 
 {
 	pci_pool_destroy(dev->cmd.pool);
 	iounmap(dev->hcr);
+	if (dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS)
+		iounmap(dev->cmd.dbell_map);
 }
 
 /*
@@ -498,12 +563,47 @@ int mthca_cmd_use_events(struct mthca_de
 		; /* nothing */
 	--dev->cmd.token_mask;
 
-	dev->cmd.use_events = 1;
+	dev->cmd.flags |= MTHCA_CMD_USE_EVENTS;
+
+
 	down(&dev->cmd.poll_sem);
 
 	return 0;
 }
 
+
+/*
+ *  attempt to post commands through doorbells
+ */
+int mthca_use_cmd_doorbells(struct mthca_dev *dev)
+{
+	int i;
+	u16 max_off = 0;
+	unsigned long pg1, pg2;
+
+	if (!dev->cmd.flags & MTHCA_CMD_CAN_POST_DOORBELLS)
+		return -ENODEV;
+
+	for (i=0; i<8; ++i)
+		if (dev->cmd.dbell_offsets[i] > max_off)
+			max_off = dev->cmd.dbell_offsets[i];
+
+	pg1 = dev->cmd.dbell_base & PAGE_MASK;
+	pg2 = (dev->cmd.dbell_base + max_off) & PAGE_MASK;
+
+	if (pg1 != pg2)
+		return -ENOMEM;
+
+	dev->cmd.dbell_map = ioremap(dev->cmd.dbell_base, max_off + sizeof(u32));
+	if (!dev->cmd.dbell_map)
+		return -ENOMEM;
+
+	dev->cmd.flags |= MTHCA_CMD_POST_DOORBELLS;
+	mthca_dbg(dev, "posting commands through doorbell\n");
+
+	return 0;
+}
+
 /*
  * Switch back to polling (used when shutting down the device)
  */
@@ -511,7 +611,7 @@ void mthca_cmd_use_polling(struct mthca_
 {
 	int i;
 
-	dev->cmd.use_events = 0;
+	dev->cmd.flags &= ~MTHCA_CMD_USE_EVENTS;
 
 	for (i = 0; i < dev->cmd.max_cmds; ++i)
 		down(&dev->cmd.event_sem);
@@ -665,8 +765,10 @@ int mthca_QUERY_FW(struct mthca_dev *dev
 {
 	struct mthca_mailbox *mailbox;
 	u32 *outbox;
+	u32 tmp;
 	int err = 0;
 	u8 lg;
+	int i;
 
 #define QUERY_FW_OUT_SIZE             0x100
 #define QUERY_FW_VER_OFFSET            0x00
@@ -674,6 +776,11 @@ int mthca_QUERY_FW(struct mthca_dev *dev
 #define QUERY_FW_ERR_START_OFFSET      0x30
 #define QUERY_FW_ERR_SIZE_OFFSET       0x38
 
+
+#define QUERY_FW_CMD_DB_EN_OFFSET      0x10
+#define QUERY_FW_CMD_DB_OFFSET         0x50
+#define QUERY_FW_CMD_DB_BASE           0x60
+
 #define QUERY_FW_START_OFFSET          0x20
 #define QUERY_FW_END_OFFSET            0x28
 
@@ -706,6 +813,15 @@ int mthca_QUERY_FW(struct mthca_dev *dev
 	dev->cmd.max_cmds = 1 << lg;
 	MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET);
 	MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET);
+	MTHCA_GET(tmp, outbox, QUERY_FW_CMD_DB_EN_OFFSET);
+	if (tmp & 0x1) {
+		mthca_dbg(dev, "FW supports commands through doorbells\n");
+		dev->cmd.flags |= MTHCA_CMD_CAN_POST_DOORBELLS;
+	}
+	MTHCA_GET(dev->cmd.dbell_base, outbox, QUERY_FW_CMD_DB_BASE);
+	for (i=0; i<MTHCA_CMD_NUM_DBELL_DWORDS; ++i)
+		MTHCA_GET(dev->cmd.dbell_offsets[i], outbox,
+			QUERY_FW_CMD_DB_OFFSET + (i << 1));
 
 	mthca_dbg(dev, "FW version %012llx, max commands %d\n",
 		  (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
@@ -1659,7 +1775,6 @@ int mthca_MODIFY_QP(struct mthca_dev *de
 		if (0) {
 			int i;
 			mthca_dbg(dev, "Dumping QP context:\n");
-			printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
 			for (i = 0; i < 0x100 / 4; ++i) {
 				if (i % 8 == 0)
 					printk("  [%02x] ", i * 4);
Index: source/drivers/infiniband/hw/mthca/mthca_cmd.h
===================================================================
--- source.orig/drivers/infiniband/hw/mthca/mthca_cmd.h
+++ source/drivers/infiniband/hw/mthca/mthca_cmd.h
@@ -244,6 +244,7 @@ struct mthca_set_ib_param {
 int mthca_cmd_init(struct mthca_dev *dev);
 void mthca_cmd_cleanup(struct mthca_dev *dev);
 int mthca_cmd_use_events(struct mthca_dev *dev);
+int mthca_use_cmd_doorbells(struct mthca_dev *dev);
 void mthca_cmd_use_polling(struct mthca_dev *dev);
 void mthca_cmd_event(struct mthca_dev *dev, u16 token,
 		     u8  status, u64 out_param);
Index: source/drivers/infiniband/hw/mthca/mthca_main.c
===================================================================
--- source.orig/drivers/infiniband/hw/mthca/mthca_main.c
+++ source/drivers/infiniband/hw/mthca/mthca_main.c
@@ -69,6 +69,8 @@ MODULE_PARM_DESC(msi, "attempt to use MS
 
 #endif /* CONFIG_PCI_MSI */
 
+
+
 static const char mthca_version[] __devinitdata =
 	DRV_NAME ": Mellanox InfiniBand HCA driver v"
 	DRV_VERSION " (" DRV_RELDATE ")\n";
@@ -754,6 +756,11 @@ static int __devinit mthca_setup_hca(str
 		goto err_eq_table_free;
 	}
 
+	err = mthca_use_cmd_doorbells(dev);
+	if (err)
+		mthca_dbg(dev, "not using commands through doorbells\n");
+
+
 	err = mthca_NOP(dev, &status);
 	if (err || status) {
 		mthca_err(dev, "NOP command failed to generate interrupt (IRQ %d), aborting.\n",




More information about the general mailing list