[openib-general] PATCH] mthca - command interface - revised
Eli Cohen
eli at mellanox.co.il
Wed Feb 15 05:31:33 PST 2006
Roland,
this patch is modified according to your comments. It also adds a kernel
configuration option which selects whether to use posting commands
through doorbells. The option is off by default.
Signed-off-by: Eli Cohen <eli at mellanox.co.il>
Index: linux-2.6.14.2/drivers/infiniband/hw/mthca/mthca_dev.h
===================================================================
--- linux-2.6.14.2.orig/drivers/infiniband/hw/mthca/mthca_dev.h
+++ linux-2.6.14.2/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: linux-2.6.14.2/drivers/infiniband/hw/mthca/mthca_cmd.c
===================================================================
--- linux-2.6.14.2.orig/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ linux-2.6.14.2/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -188,19 +188,57 @@ static inline int go_bit(struct mthca_de
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;
+
+ __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();
+}
- mutex_lock(&dev->cmd.hcr_mutex);
+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 +248,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 +272,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 (dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS && event)
+ 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 +444,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 +481,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 +495,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 +519,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 +558,49 @@ 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;
}
+
+#ifdef CONFIG_INFINIBAND_MTHCA_CMD_UAR
+/*
+ * 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;
+}
+#endif
+
/*
* Switch back to polling (used when shutting down the device)
*/
@@ -511,7 +608,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 +762,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 +773,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 +810,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 +1772,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: linux-2.6.14.2/drivers/infiniband/hw/mthca/mthca_cmd.h
===================================================================
--- linux-2.6.14.2.orig/drivers/infiniband/hw/mthca/mthca_cmd.h
+++ linux-2.6.14.2/drivers/infiniband/hw/mthca/mthca_cmd.h
@@ -244,6 +244,14 @@ 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);
+#if defined(CONFIG_INFINIBAND_MTHCA_CMD_UAR)
+int mthca_use_cmd_doorbells(struct mthca_dev *dev);
+#else
+static inline int mthca_use_cmd_doorbells(struct mthca_dev *dev)
+{
+ return -ENOSYS;
+}
+#endif
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: linux-2.6.14.2/drivers/infiniband/hw/mthca/mthca_main.c
===================================================================
--- linux-2.6.14.2.orig/drivers/infiniband/hw/mthca/mthca_main.c
+++ linux-2.6.14.2/drivers/infiniband/hw/mthca/mthca_main.c
@@ -754,6 +754,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",
Index: linux-2.6.14.2/drivers/infiniband/hw/mthca/Kconfig
===================================================================
--- linux-2.6.14.2.orig/drivers/infiniband/hw/mthca/Kconfig
+++ linux-2.6.14.2/drivers/infiniband/hw/mthca/Kconfig
@@ -14,3 +14,12 @@ config INFINIBAND_MTHCA_DEBUG
This option causes the mthca driver produce a bunch of debug
messages. Select this is you are developing the driver or
trying to diagnose a problem.
+
+config INFINIBAND_MTHCA_CMD_UAR
+ bool "Post commands through uar0"
+ depends on INFINIBAND_MTHCA
+ default n
+ ---help---
+ This option will check if the device supports issuing commands
+ by writing to the UAR area. This can result in better CPU
+ utilization.
More information about the general
mailing list