aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw
diff options
context:
space:
mode:
authorVipul Pandya <vipul@chelsio.com>2013-03-14 01:09:01 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-14 11:35:59 -0400
commit42b6a949903d28f59c95f4c71080aa8b41e3d1d1 (patch)
treed91e9304efb9504fb03256bb5e0fb78f76da7c3d /drivers/infiniband/hw
parent80ccdd60512fc19fa87bf02876c59aeeb82fe4bc (diff)
RDMA/cxgb4: Use DSGLs for fastreg and adapter memory writes for T5.
It enables direct DMA by HW to memory region PBL arrays and fast register PBL arrays from host memory, vs the T4 way of passing these arrays in the WR itself. The result is lower latency for memory registration, and larger PBL array support for fast register operations. This patch also updates ULP_TX_MEM_WRITE command fields for T5. Ordering bit of ULP_TX_MEM_WRITE is at bit position 22 in T5 and at 23 in T4. Signed-off-by: Vipul Pandya <vipul@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/infiniband/hw')
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h2
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c138
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c76
-rw-r--r--drivers/infiniband/hw/cxgb4/t4.h2
4 files changed, 182 insertions, 36 deletions
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index 4dbe96a06a84..08e406ca815b 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -369,7 +369,6 @@ struct c4iw_fr_page_list {
369 DEFINE_DMA_UNMAP_ADDR(mapping); 369 DEFINE_DMA_UNMAP_ADDR(mapping);
370 dma_addr_t dma_addr; 370 dma_addr_t dma_addr;
371 struct c4iw_dev *dev; 371 struct c4iw_dev *dev;
372 int size;
373}; 372};
374 373
375static inline struct c4iw_fr_page_list *to_c4iw_fr_page_list( 374static inline struct c4iw_fr_page_list *to_c4iw_fr_page_list(
@@ -940,6 +939,7 @@ extern c4iw_handler_func c4iw_handlers[NUM_CPL_CMDS];
940extern int c4iw_max_read_depth; 939extern int c4iw_max_read_depth;
941extern int db_fc_threshold; 940extern int db_fc_threshold;
942extern int db_coalescing_threshold; 941extern int db_coalescing_threshold;
942extern int use_dsgl;
943 943
944 944
945#endif 945#endif
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index 903a92d6f91d..33db9ee307dc 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -30,16 +30,76 @@
30 * SOFTWARE. 30 * SOFTWARE.
31 */ 31 */
32 32
33#include <linux/module.h>
34#include <linux/moduleparam.h>
33#include <rdma/ib_umem.h> 35#include <rdma/ib_umem.h>
34#include <linux/atomic.h> 36#include <linux/atomic.h>
35 37
36#include "iw_cxgb4.h" 38#include "iw_cxgb4.h"
37 39
40int use_dsgl = 1;
41module_param(use_dsgl, int, 0644);
42MODULE_PARM_DESC(use_dsgl, "Use DSGL for PBL/FastReg (default=1)");
43
38#define T4_ULPTX_MIN_IO 32 44#define T4_ULPTX_MIN_IO 32
39#define C4IW_MAX_INLINE_SIZE 96 45#define C4IW_MAX_INLINE_SIZE 96
46#define T4_ULPTX_MAX_DMA 1024
47#define C4IW_INLINE_THRESHOLD 128
40 48
41static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len, 49static int inline_threshold = C4IW_INLINE_THRESHOLD;
42 void *data) 50module_param(inline_threshold, int, 0644);
51MODULE_PARM_DESC(inline_threshold, "inline vs dsgl threshold (default=128)");
52
53static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr,
54 u32 len, void *data, int wait)
55{
56 struct sk_buff *skb;
57 struct ulp_mem_io *req;
58 struct ulptx_sgl *sgl;
59 u8 wr_len;
60 int ret = 0;
61 struct c4iw_wr_wait wr_wait;
62
63 addr &= 0x7FFFFFF;
64
65 if (wait)
66 c4iw_init_wr_wait(&wr_wait);
67 wr_len = roundup(sizeof(*req) + sizeof(*sgl), 16);
68
69 skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
70 if (!skb)
71 return -ENOMEM;
72 set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
73
74 req = (struct ulp_mem_io *)__skb_put(skb, wr_len);
75 memset(req, 0, wr_len);
76 INIT_ULPTX_WR(req, wr_len, 0, 0);
77 req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR) |
78 (wait ? FW_WR_COMPL(1) : 0));
79 req->wr.wr_lo = wait ? (__force __be64)&wr_wait : 0;
80 req->wr.wr_mid = cpu_to_be32(FW_WR_LEN16(DIV_ROUND_UP(wr_len, 16)));
81 req->cmd = cpu_to_be32(ULPTX_CMD(ULP_TX_MEM_WRITE));
82 req->cmd |= cpu_to_be32(V_T5_ULP_MEMIO_ORDER(1));
83 req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN(len>>5));
84 req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr), 16));
85 req->lock_addr = cpu_to_be32(ULP_MEMIO_ADDR(addr));
86
87 sgl = (struct ulptx_sgl *)(req + 1);
88 sgl->cmd_nsge = cpu_to_be32(ULPTX_CMD(ULP_TX_SC_DSGL) |
89 ULPTX_NSGE(1));
90 sgl->len0 = cpu_to_be32(len);
91 sgl->addr0 = cpu_to_be64(virt_to_phys(data));
92
93 ret = c4iw_ofld_send(rdev, skb);
94 if (ret)
95 return ret;
96 if (wait)
97 ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
98 return ret;
99}
100
101static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
102 void *data)
43{ 103{
44 struct sk_buff *skb; 104 struct sk_buff *skb;
45 struct ulp_mem_io *req; 105 struct ulp_mem_io *req;
@@ -47,6 +107,12 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
47 u8 wr_len, *to_dp, *from_dp; 107 u8 wr_len, *to_dp, *from_dp;
48 int copy_len, num_wqe, i, ret = 0; 108 int copy_len, num_wqe, i, ret = 0;
49 struct c4iw_wr_wait wr_wait; 109 struct c4iw_wr_wait wr_wait;
110 __be32 cmd = cpu_to_be32(ULPTX_CMD(ULP_TX_MEM_WRITE));
111
112 if (is_t4(rdev->lldi.adapter_type))
113 cmd |= cpu_to_be32(ULP_MEMIO_ORDER(1));
114 else
115 cmd |= cpu_to_be32(V_T5_ULP_MEMIO_IMM(1));
50 116
51 addr &= 0x7FFFFFF; 117 addr &= 0x7FFFFFF;
52 PDBG("%s addr 0x%x len %u\n", __func__, addr, len); 118 PDBG("%s addr 0x%x len %u\n", __func__, addr, len);
@@ -77,7 +143,7 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
77 req->wr.wr_mid = cpu_to_be32( 143 req->wr.wr_mid = cpu_to_be32(
78 FW_WR_LEN16(DIV_ROUND_UP(wr_len, 16))); 144 FW_WR_LEN16(DIV_ROUND_UP(wr_len, 16)));
79 145
80 req->cmd = cpu_to_be32(ULPTX_CMD(ULP_TX_MEM_WRITE) | (1<<23)); 146 req->cmd = cmd;
81 req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN( 147 req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN(
82 DIV_ROUND_UP(copy_len, T4_ULPTX_MIN_IO))); 148 DIV_ROUND_UP(copy_len, T4_ULPTX_MIN_IO)));
83 req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr), 149 req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr),
@@ -107,6 +173,50 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
107 return ret; 173 return ret;
108} 174}
109 175
176int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len, void *data)
177{
178 u32 remain = len;
179 u32 dmalen;
180 int ret = 0;
181
182 while (remain > inline_threshold) {
183 if (remain < T4_ULPTX_MAX_DMA) {
184 if (remain & ~T4_ULPTX_MIN_IO)
185 dmalen = remain & ~(T4_ULPTX_MIN_IO-1);
186 else
187 dmalen = remain;
188 } else
189 dmalen = T4_ULPTX_MAX_DMA;
190 remain -= dmalen;
191 ret = _c4iw_write_mem_dma_aligned(rdev, addr, dmalen, data,
192 !remain);
193 if (ret)
194 goto out;
195 addr += dmalen >> 5;
196 data += dmalen;
197 }
198 if (remain)
199 ret = _c4iw_write_mem_inline(rdev, addr, remain, data);
200out:
201 return ret;
202}
203
204/*
205 * write len bytes of data into addr (32B aligned address)
206 * If data is NULL, clear len byte of memory to zero.
207 */
208static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
209 void *data)
210{
211 if (is_t5(rdev->lldi.adapter_type) && use_dsgl) {
212 if (len > inline_threshold)
213 return _c4iw_write_mem_dma(rdev, addr, len, data);
214 else
215 return _c4iw_write_mem_inline(rdev, addr, len, data);
216 } else
217 return _c4iw_write_mem_inline(rdev, addr, len, data);
218}
219
110/* 220/*
111 * Build and write a TPT entry. 221 * Build and write a TPT entry.
112 * IN: stag key, pdid, perm, bind_enabled, zbva, to, len, page_size, 222 * IN: stag key, pdid, perm, bind_enabled, zbva, to, len, page_size,
@@ -760,19 +870,23 @@ struct ib_fast_reg_page_list *c4iw_alloc_fastreg_pbl(struct ib_device *device,
760 struct c4iw_fr_page_list *c4pl; 870 struct c4iw_fr_page_list *c4pl;
761 struct c4iw_dev *dev = to_c4iw_dev(device); 871 struct c4iw_dev *dev = to_c4iw_dev(device);
762 dma_addr_t dma_addr; 872 dma_addr_t dma_addr;
763 int size = sizeof *c4pl + page_list_len * sizeof(u64); 873 int pll_len = roundup(page_list_len * sizeof(u64), 32);
764 874
765 c4pl = dma_alloc_coherent(&dev->rdev.lldi.pdev->dev, size, 875 c4pl = kmalloc(sizeof(*c4pl), GFP_KERNEL);
766 &dma_addr, GFP_KERNEL);
767 if (!c4pl) 876 if (!c4pl)
768 return ERR_PTR(-ENOMEM); 877 return ERR_PTR(-ENOMEM);
769 878
879 c4pl->ibpl.page_list = dma_alloc_coherent(&dev->rdev.lldi.pdev->dev,
880 pll_len, &dma_addr,
881 GFP_KERNEL);
882 if (!c4pl->ibpl.page_list) {
883 kfree(c4pl);
884 return ERR_PTR(-ENOMEM);
885 }
770 dma_unmap_addr_set(c4pl, mapping, dma_addr); 886 dma_unmap_addr_set(c4pl, mapping, dma_addr);
771 c4pl->dma_addr = dma_addr; 887 c4pl->dma_addr = dma_addr;
772 c4pl->dev = dev; 888 c4pl->dev = dev;
773 c4pl->size = size; 889 c4pl->ibpl.max_page_list_len = pll_len;
774 c4pl->ibpl.page_list = (u64 *)(c4pl + 1);
775 c4pl->ibpl.max_page_list_len = page_list_len;
776 890
777 return &c4pl->ibpl; 891 return &c4pl->ibpl;
778} 892}
@@ -781,8 +895,10 @@ void c4iw_free_fastreg_pbl(struct ib_fast_reg_page_list *ibpl)
781{ 895{
782 struct c4iw_fr_page_list *c4pl = to_c4iw_fr_page_list(ibpl); 896 struct c4iw_fr_page_list *c4pl = to_c4iw_fr_page_list(ibpl);
783 897
784 dma_free_coherent(&c4pl->dev->rdev.lldi.pdev->dev, c4pl->size, 898 dma_free_coherent(&c4pl->dev->rdev.lldi.pdev->dev,
785 c4pl, dma_unmap_addr(c4pl, mapping)); 899 c4pl->ibpl.max_page_list_len,
900 c4pl->ibpl.page_list, dma_unmap_addr(c4pl, mapping));
901 kfree(c4pl);
786} 902}
787 903
788int c4iw_dereg_mr(struct ib_mr *ib_mr) 904int c4iw_dereg_mr(struct ib_mr *ib_mr)
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index 28592d45809b..90833d701631 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -54,6 +54,10 @@ MODULE_PARM_DESC(db_coalescing_threshold,
54 "QP count/threshold that triggers" 54 "QP count/threshold that triggers"
55 " disabling db coalescing (default = 0)"); 55 " disabling db coalescing (default = 0)");
56 56
57static int max_fr_immd = T4_MAX_FR_IMMD;
58module_param(max_fr_immd, int, 0644);
59MODULE_PARM_DESC(max_fr_immd, "fastreg threshold for using DSGL instead of immedate");
60
57static void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state) 61static void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state)
58{ 62{
59 unsigned long flag; 63 unsigned long flag;
@@ -539,7 +543,7 @@ static int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe,
539} 543}
540 544
541static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe, 545static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe,
542 struct ib_send_wr *wr, u8 *len16) 546 struct ib_send_wr *wr, u8 *len16, u8 t5dev)
543{ 547{
544 548
545 struct fw_ri_immd *imdp; 549 struct fw_ri_immd *imdp;
@@ -561,28 +565,51 @@ static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe,
561 wqe->fr.va_hi = cpu_to_be32(wr->wr.fast_reg.iova_start >> 32); 565 wqe->fr.va_hi = cpu_to_be32(wr->wr.fast_reg.iova_start >> 32);
562 wqe->fr.va_lo_fbo = cpu_to_be32(wr->wr.fast_reg.iova_start & 566 wqe->fr.va_lo_fbo = cpu_to_be32(wr->wr.fast_reg.iova_start &
563 0xffffffff); 567 0xffffffff);
564 WARN_ON(pbllen > T4_MAX_FR_IMMD); 568
565 imdp = (struct fw_ri_immd *)(&wqe->fr + 1); 569 if (t5dev && use_dsgl && (pbllen > max_fr_immd)) {
566 imdp->op = FW_RI_DATA_IMMD; 570 struct c4iw_fr_page_list *c4pl =
567 imdp->r1 = 0; 571 to_c4iw_fr_page_list(wr->wr.fast_reg.page_list);
568 imdp->r2 = 0; 572 struct fw_ri_dsgl *sglp;
569 imdp->immdlen = cpu_to_be32(pbllen); 573
570 p = (__be64 *)(imdp + 1); 574 for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
571 rem = pbllen; 575 wr->wr.fast_reg.page_list->page_list[i] = (__force u64)
572 for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) { 576 cpu_to_be64((u64)
573 *p = cpu_to_be64((u64)wr->wr.fast_reg.page_list->page_list[i]); 577 wr->wr.fast_reg.page_list->page_list[i]);
574 rem -= sizeof *p; 578 }
575 if (++p == (__be64 *)&sq->queue[sq->size]) 579
576 p = (__be64 *)sq->queue; 580 sglp = (struct fw_ri_dsgl *)(&wqe->fr + 1);
577 } 581 sglp->op = FW_RI_DATA_DSGL;
578 BUG_ON(rem < 0); 582 sglp->r1 = 0;
579 while (rem) { 583 sglp->nsge = cpu_to_be16(1);
580 *p = 0; 584 sglp->addr0 = cpu_to_be64(c4pl->dma_addr);
581 rem -= sizeof *p; 585 sglp->len0 = cpu_to_be32(pbllen);
582 if (++p == (__be64 *)&sq->queue[sq->size]) 586
583 p = (__be64 *)sq->queue; 587 *len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*sglp), 16);
588 } else {
589 imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
590 imdp->op = FW_RI_DATA_IMMD;
591 imdp->r1 = 0;
592 imdp->r2 = 0;
593 imdp->immdlen = cpu_to_be32(pbllen);
594 p = (__be64 *)(imdp + 1);
595 rem = pbllen;
596 for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
597 *p = cpu_to_be64(
598 (u64)wr->wr.fast_reg.page_list->page_list[i]);
599 rem -= sizeof(*p);
600 if (++p == (__be64 *)&sq->queue[sq->size])
601 p = (__be64 *)sq->queue;
602 }
603 BUG_ON(rem < 0);
604 while (rem) {
605 *p = 0;
606 rem -= sizeof(*p);
607 if (++p == (__be64 *)&sq->queue[sq->size])
608 p = (__be64 *)sq->queue;
609 }
610 *len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*imdp)
611 + pbllen, 16);
584 } 612 }
585 *len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *imdp + pbllen, 16);
586 return 0; 613 return 0;
587} 614}
588 615
@@ -683,7 +710,10 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
683 case IB_WR_FAST_REG_MR: 710 case IB_WR_FAST_REG_MR:
684 fw_opcode = FW_RI_FR_NSMR_WR; 711 fw_opcode = FW_RI_FR_NSMR_WR;
685 swsqe->opcode = FW_RI_FAST_REGISTER; 712 swsqe->opcode = FW_RI_FAST_REGISTER;
686 err = build_fastreg(&qhp->wq.sq, wqe, wr, &len16); 713 err = build_fastreg(&qhp->wq.sq, wqe, wr, &len16,
714 is_t5(
715 qhp->rhp->rdev.lldi.adapter_type) ?
716 1 : 0);
687 break; 717 break;
688 case IB_WR_LOCAL_INV: 718 case IB_WR_LOCAL_INV:
689 if (wr->send_flags & IB_SEND_FENCE) 719 if (wr->send_flags & IB_SEND_FENCE)
diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
index 689edc96155d..ebcb03bd1b72 100644
--- a/drivers/infiniband/hw/cxgb4/t4.h
+++ b/drivers/infiniband/hw/cxgb4/t4.h
@@ -84,7 +84,7 @@ struct t4_status_page {
84 sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge)) 84 sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
85#define T4_MAX_FR_IMMD ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_fr_nsmr_wr) - \ 85#define T4_MAX_FR_IMMD ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_fr_nsmr_wr) - \
86 sizeof(struct fw_ri_immd)) & ~31UL) 86 sizeof(struct fw_ri_immd)) & ~31UL)
87#define T4_MAX_FR_DEPTH (T4_MAX_FR_IMMD / sizeof(u64)) 87#define T4_MAX_FR_DEPTH (1024 / sizeof(u64))
88 88
89#define T4_RQ_NUM_SLOTS 2 89#define T4_RQ_NUM_SLOTS 2
90#define T4_RQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_RQ_NUM_SLOTS) 90#define T4_RQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_RQ_NUM_SLOTS)