diff options
author | Eli Cohen <eli@mellanox.co.il> | 2006-02-26 17:36:06 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-03-20 13:08:17 -0500 |
commit | 14abdffcc0a0ca9c5bb3274648d073e09a6fd2ba (patch) | |
tree | fe934450412ed70f627e9d98bb881b03c7b31222 | |
parent | ea88fd16d6e85f4bc71b6053180b64f04be1ff14 (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>
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_cmd.c | 146 | ||||
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_dev.h | 13 |
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 | ||
185 | static int fw_cmd_doorbell = 1; | ||
186 | module_param(fw_cmd_doorbell, int, 0644); | ||
187 | MODULE_PARM_DESC(fw_cmd_doorbell, "post FW commands through doorbell page if nonzero " | ||
188 | "(and supported by FW)"); | ||
189 | |||
185 | static inline int go_bit(struct mthca_dev *dev) | 190 | static 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 | ||
191 | static int mthca_cmd_post(struct mthca_dev *dev, | 196 | static 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 | ||
228 | static 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 | ||
239 | out: | 270 | return 0; |
271 | } | ||
272 | |||
273 | static 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 | ||
720 | static 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 | |||
664 | int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status) | 746 | int 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 | ||
113 | enum { | ||
114 | MTHCA_CMD_USE_EVENTS = 1 << 0, | ||
115 | MTHCA_CMD_POST_DOORBELLS = 1 << 1 | ||
116 | }; | ||
117 | |||
118 | enum { | ||
119 | MTHCA_CMD_NUM_DBELL_DWORDS = 8 | ||
120 | }; | ||
121 | |||
113 | struct mthca_cmd { | 122 | struct 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 | ||
126 | struct mthca_limits { | 137 | struct mthca_limits { |