aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorEli Cohen <eli@mellanox.co.il>2006-02-26 17:36:06 -0500
committerRoland Dreier <rolandd@cisco.com>2006-03-20 13:08:17 -0500
commit14abdffcc0a0ca9c5bb3274648d073e09a6fd2ba (patch)
treefe934450412ed70f627e9d98bb881b03c7b31222 /drivers/infiniband
parentea88fd16d6e85f4bc71b6053180b64f04be1ff14 (diff)
IB/mthca: Write FW commands through doorbell page
This patch is checks whether the HCA supports posting FW commands through a doorbell page (user access region 0, or "UAR0"). If this is supported, the driver maps UAR0 and uses it for FW commands. This can be controlled by the value of a writable module parameter fw_cmd_doorbell. When the parameter is 0, the commands are posted through HCR using the old method; otherwise if HCA is capable commands go through UAR0. 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 issuing FW commands this way will provide better CPU utilization. Signed-off-by: Eli Cohen <eli@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c146
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h13
2 files changed, 136 insertions, 23 deletions
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index 890c060ff4d1..d1e7ecb5f233 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -182,25 +182,58 @@ struct mthca_cmd_context {
182 u8 status; 182 u8 status;
183}; 183};
184 184
185static int fw_cmd_doorbell = 1;
186module_param(fw_cmd_doorbell, int, 0644);
187MODULE_PARM_DESC(fw_cmd_doorbell, "post FW commands through doorbell page if nonzero "
188 "(and supported by FW)");
189
185static inline int go_bit(struct mthca_dev *dev) 190static inline int go_bit(struct mthca_dev *dev)
186{ 191{
187 return readl(dev->hcr + HCR_STATUS_OFFSET) & 192 return readl(dev->hcr + HCR_STATUS_OFFSET) &
188 swab32(1 << HCR_GO_BIT); 193 swab32(1 << HCR_GO_BIT);
189} 194}
190 195
191static int mthca_cmd_post(struct mthca_dev *dev, 196static void mthca_cmd_post_dbell(struct mthca_dev *dev,
192 u64 in_param, 197 u64 in_param,
193 u64 out_param, 198 u64 out_param,
194 u32 in_modifier, 199 u32 in_modifier,
195 u8 op_modifier, 200 u8 op_modifier,
196 u16 op, 201 u16 op,
197 u16 token, 202 u16 token)
198 int event)
199{ 203{
200 int err = 0; 204 void __iomem *ptr = dev->cmd.dbell_map;
205 u16 *offs = dev->cmd.dbell_offsets;
201 206
202 mutex_lock(&dev->cmd.hcr_mutex); 207 __raw_writel((__force u32) cpu_to_be32(in_param >> 32), ptr + offs[0]);
208 wmb();
209 __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), ptr + offs[1]);
210 wmb();
211 __raw_writel((__force u32) cpu_to_be32(in_modifier), ptr + offs[2]);
212 wmb();
213 __raw_writel((__force u32) cpu_to_be32(out_param >> 32), ptr + offs[3]);
214 wmb();
215 __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), ptr + offs[4]);
216 wmb();
217 __raw_writel((__force u32) cpu_to_be32(token << 16), ptr + offs[5]);
218 wmb();
219 __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) |
220 (1 << HCA_E_BIT) |
221 (op_modifier << HCR_OPMOD_SHIFT) |
222 op), ptr + offs[6]);
223 wmb();
224 __raw_writel((__force u32) 0, ptr + offs[7]);
225 wmb();
226}
203 227
228static int mthca_cmd_post_hcr(struct mthca_dev *dev,
229 u64 in_param,
230 u64 out_param,
231 u32 in_modifier,
232 u8 op_modifier,
233 u16 op,
234 u16 token,
235 int event)
236{
204 if (event) { 237 if (event) {
205 unsigned long end = jiffies + GO_BIT_TIMEOUT; 238 unsigned long end = jiffies + GO_BIT_TIMEOUT;
206 239
@@ -210,10 +243,8 @@ static int mthca_cmd_post(struct mthca_dev *dev,
210 } 243 }
211 } 244 }
212 245
213 if (go_bit(dev)) { 246 if (go_bit(dev))
214 err = -EAGAIN; 247 return -EAGAIN;
215 goto out;
216 }
217 248
218 /* 249 /*
219 * We use writel (instead of something like memcpy_toio) 250 * We use writel (instead of something like memcpy_toio)
@@ -236,7 +267,29 @@ static int mthca_cmd_post(struct mthca_dev *dev,
236 (op_modifier << HCR_OPMOD_SHIFT) | 267 (op_modifier << HCR_OPMOD_SHIFT) |
237 op), dev->hcr + 6 * 4); 268 op), dev->hcr + 6 * 4);
238 269
239out: 270 return 0;
271}
272
273static int mthca_cmd_post(struct mthca_dev *dev,
274 u64 in_param,
275 u64 out_param,
276 u32 in_modifier,
277 u8 op_modifier,
278 u16 op,
279 u16 token,
280 int event)
281{
282 int err = 0;
283
284 mutex_lock(&dev->cmd.hcr_mutex);
285
286 if (event && dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS && fw_cmd_doorbell)
287 mthca_cmd_post_dbell(dev, in_param, out_param, in_modifier,
288 op_modifier, op, token);
289 else
290 err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier,
291 op_modifier, op, token, event);
292
240 mutex_unlock(&dev->cmd.hcr_mutex); 293 mutex_unlock(&dev->cmd.hcr_mutex);
241 return err; 294 return err;
242} 295}
@@ -386,7 +439,7 @@ static int mthca_cmd_box(struct mthca_dev *dev,
386 unsigned long timeout, 439 unsigned long timeout,
387 u8 *status) 440 u8 *status)
388{ 441{
389 if (dev->cmd.use_events) 442 if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
390 return mthca_cmd_wait(dev, in_param, &out_param, 0, 443 return mthca_cmd_wait(dev, in_param, &out_param, 0,
391 in_modifier, op_modifier, op, 444 in_modifier, op_modifier, op,
392 timeout, status); 445 timeout, status);
@@ -423,7 +476,7 @@ static int mthca_cmd_imm(struct mthca_dev *dev,
423 unsigned long timeout, 476 unsigned long timeout,
424 u8 *status) 477 u8 *status)
425{ 478{
426 if (dev->cmd.use_events) 479 if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
427 return mthca_cmd_wait(dev, in_param, out_param, 1, 480 return mthca_cmd_wait(dev, in_param, out_param, 1,
428 in_modifier, op_modifier, op, 481 in_modifier, op_modifier, op,
429 timeout, status); 482 timeout, status);
@@ -437,7 +490,7 @@ int mthca_cmd_init(struct mthca_dev *dev)
437{ 490{
438 mutex_init(&dev->cmd.hcr_mutex); 491 mutex_init(&dev->cmd.hcr_mutex);
439 sema_init(&dev->cmd.poll_sem, 1); 492 sema_init(&dev->cmd.poll_sem, 1);
440 dev->cmd.use_events = 0; 493 dev->cmd.flags = 0;
441 494
442 dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE, 495 dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
443 MTHCA_HCR_SIZE); 496 MTHCA_HCR_SIZE);
@@ -461,6 +514,8 @@ void mthca_cmd_cleanup(struct mthca_dev *dev)
461{ 514{
462 pci_pool_destroy(dev->cmd.pool); 515 pci_pool_destroy(dev->cmd.pool);
463 iounmap(dev->hcr); 516 iounmap(dev->hcr);
517 if (dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS)
518 iounmap(dev->cmd.dbell_map);
464} 519}
465 520
466/* 521/*
@@ -498,7 +553,8 @@ int mthca_cmd_use_events(struct mthca_dev *dev)
498 ; /* nothing */ 553 ; /* nothing */
499 --dev->cmd.token_mask; 554 --dev->cmd.token_mask;
500 555
501 dev->cmd.use_events = 1; 556 dev->cmd.flags |= MTHCA_CMD_USE_EVENTS;
557
502 down(&dev->cmd.poll_sem); 558 down(&dev->cmd.poll_sem);
503 559
504 return 0; 560 return 0;
@@ -511,7 +567,7 @@ void mthca_cmd_use_polling(struct mthca_dev *dev)
511{ 567{
512 int i; 568 int i;
513 569
514 dev->cmd.use_events = 0; 570 dev->cmd.flags &= ~MTHCA_CMD_USE_EVENTS;
515 571
516 for (i = 0; i < dev->cmd.max_cmds; ++i) 572 for (i = 0; i < dev->cmd.max_cmds; ++i)
517 down(&dev->cmd.event_sem); 573 down(&dev->cmd.event_sem);
@@ -661,12 +717,41 @@ int mthca_RUN_FW(struct mthca_dev *dev, u8 *status)
661 return mthca_cmd(dev, 0, 0, 0, CMD_RUN_FW, CMD_TIME_CLASS_A, status); 717 return mthca_cmd(dev, 0, 0, 0, CMD_RUN_FW, CMD_TIME_CLASS_A, status);
662} 718}
663 719
720static void mthca_setup_cmd_doorbells(struct mthca_dev *dev, u64 base)
721{
722 unsigned long addr;
723 u16 max_off = 0;
724 int i;
725
726 for (i = 0; i < 8; ++i)
727 max_off = max(max_off, dev->cmd.dbell_offsets[i]);
728
729 if ((base & PAGE_MASK) != ((base + max_off) & PAGE_MASK)) {
730 mthca_warn(dev, "Firmware doorbell region at 0x%016llx, "
731 "length 0x%x crosses a page boundary\n",
732 (unsigned long long) base, max_off);
733 return;
734 }
735
736 addr = pci_resource_start(dev->pdev, 2) +
737 ((pci_resource_len(dev->pdev, 2) - 1) & base);
738 dev->cmd.dbell_map = ioremap(addr, max_off + sizeof(u32));
739 if (!dev->cmd.dbell_map)
740 return;
741
742 dev->cmd.flags |= MTHCA_CMD_POST_DOORBELLS;
743 mthca_dbg(dev, "Mapped doorbell page for posting FW commands\n");
744}
745
664int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status) 746int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
665{ 747{
666 struct mthca_mailbox *mailbox; 748 struct mthca_mailbox *mailbox;
667 u32 *outbox; 749 u32 *outbox;
750 u64 base;
751 u32 tmp;
668 int err = 0; 752 int err = 0;
669 u8 lg; 753 u8 lg;
754 int i;
670 755
671#define QUERY_FW_OUT_SIZE 0x100 756#define QUERY_FW_OUT_SIZE 0x100
672#define QUERY_FW_VER_OFFSET 0x00 757#define QUERY_FW_VER_OFFSET 0x00
@@ -674,6 +759,10 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
674#define QUERY_FW_ERR_START_OFFSET 0x30 759#define QUERY_FW_ERR_START_OFFSET 0x30
675#define QUERY_FW_ERR_SIZE_OFFSET 0x38 760#define QUERY_FW_ERR_SIZE_OFFSET 0x38
676 761
762#define QUERY_FW_CMD_DB_EN_OFFSET 0x10
763#define QUERY_FW_CMD_DB_OFFSET 0x50
764#define QUERY_FW_CMD_DB_BASE 0x60
765
677#define QUERY_FW_START_OFFSET 0x20 766#define QUERY_FW_START_OFFSET 0x20
678#define QUERY_FW_END_OFFSET 0x28 767#define QUERY_FW_END_OFFSET 0x28
679 768
@@ -702,16 +791,29 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
702 ((dev->fw_ver & 0xffff0000ull) >> 16) | 791 ((dev->fw_ver & 0xffff0000ull) >> 16) |
703 ((dev->fw_ver & 0x0000ffffull) << 16); 792 ((dev->fw_ver & 0x0000ffffull) << 16);
704 793
794 mthca_dbg(dev, "FW version %012llx, max commands %d\n",
795 (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
796
705 MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET); 797 MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
706 dev->cmd.max_cmds = 1 << lg; 798 dev->cmd.max_cmds = 1 << lg;
707 MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET); 799 MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET);
708 MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET); 800 MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET);
709 801
710 mthca_dbg(dev, "FW version %012llx, max commands %d\n",
711 (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
712 mthca_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x\n", 802 mthca_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x\n",
713 (unsigned long long) dev->catas_err.addr, dev->catas_err.size); 803 (unsigned long long) dev->catas_err.addr, dev->catas_err.size);
714 804
805 MTHCA_GET(tmp, outbox, QUERY_FW_CMD_DB_EN_OFFSET);
806 if (tmp & 0x1) {
807 mthca_dbg(dev, "FW supports commands through doorbells\n");
808
809 MTHCA_GET(base, outbox, QUERY_FW_CMD_DB_BASE);
810 for (i = 0; i < MTHCA_CMD_NUM_DBELL_DWORDS; ++i)
811 MTHCA_GET(dev->cmd.dbell_offsets[i], outbox,
812 QUERY_FW_CMD_DB_OFFSET + (i << 1));
813
814 mthca_setup_cmd_doorbells(dev, base);
815 }
816
715 if (mthca_is_memfree(dev)) { 817 if (mthca_is_memfree(dev)) {
716 MTHCA_GET(dev->fw.arbel.fw_pages, outbox, QUERY_FW_SIZE_OFFSET); 818 MTHCA_GET(dev->fw.arbel.fw_pages, outbox, QUERY_FW_SIZE_OFFSET);
717 MTHCA_GET(dev->fw.arbel.clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET); 819 MTHCA_GET(dev->fw.arbel.clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET);
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index 7f0dc221fa47..b2aea80a683f 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -110,9 +110,17 @@ enum {
110 MTHCA_OPCODE_INVALID = 0xff 110 MTHCA_OPCODE_INVALID = 0xff
111}; 111};
112 112
113enum {
114 MTHCA_CMD_USE_EVENTS = 1 << 0,
115 MTHCA_CMD_POST_DOORBELLS = 1 << 1
116};
117
118enum {
119 MTHCA_CMD_NUM_DBELL_DWORDS = 8
120};
121
113struct mthca_cmd { 122struct mthca_cmd {
114 struct pci_pool *pool; 123 struct pci_pool *pool;
115 int use_events;
116 struct mutex hcr_mutex; 124 struct mutex hcr_mutex;
117 struct semaphore poll_sem; 125 struct semaphore poll_sem;
118 struct semaphore event_sem; 126 struct semaphore event_sem;
@@ -121,6 +129,9 @@ struct mthca_cmd {
121 int free_head; 129 int free_head;
122 struct mthca_cmd_context *context; 130 struct mthca_cmd_context *context;
123 u16 token_mask; 131 u16 token_mask;
132 u32 flags;
133 void __iomem *dbell_map;
134 u16 dbell_offsets[MTHCA_CMD_NUM_DBELL_DWORDS];
124}; 135};
125 136
126struct mthca_limits { 137struct mthca_limits {