[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