Merge tag 'rdma-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[firefly-linux-kernel-4.4.55.git] / drivers / infiniband / hw / cxgb4 / qp.c
index 70b1808a08f4d12bf9d1668cb5bae06d1cd2e202..232040447e8a23803cc73e64c203734d36492c2e 100644 (file)
@@ -42,10 +42,21 @@ static int ocqp_support = 1;
 module_param(ocqp_support, int, 0644);
 MODULE_PARM_DESC(ocqp_support, "Support on-chip SQs (default=1)");
 
-int db_fc_threshold = 2000;
+int db_fc_threshold = 1000;
 module_param(db_fc_threshold, int, 0644);
-MODULE_PARM_DESC(db_fc_threshold, "QP count/threshold that triggers automatic "
-                "db flow control mode (default = 2000)");
+MODULE_PARM_DESC(db_fc_threshold,
+                "QP count/threshold that triggers"
+                " automatic db flow control mode (default = 1000)");
+
+int db_coalescing_threshold;
+module_param(db_coalescing_threshold, int, 0644);
+MODULE_PARM_DESC(db_coalescing_threshold,
+                "QP count/threshold that triggers"
+                " disabling db coalescing (default = 0)");
+
+static int max_fr_immd = T4_MAX_FR_IMMD;
+module_param(max_fr_immd, int, 0644);
+MODULE_PARM_DESC(max_fr_immd, "fastreg threshold for using DSGL instead of immedate");
 
 static void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state)
 {
@@ -76,7 +87,7 @@ static void dealloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
 
 static int alloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
 {
-       if (!ocqp_support || !t4_ocqp_supported())
+       if (!ocqp_support || !ocqp_supported(&rdev->lldi))
                return -ENOSYS;
        sq->dma_addr = c4iw_ocqp_pool_alloc(rdev, sq->memsize);
        if (!sq->dma_addr)
@@ -100,6 +111,16 @@ static int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
        return 0;
 }
 
+static int alloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq, int user)
+{
+       int ret = -ENOSYS;
+       if (user)
+               ret = alloc_oc_sq(rdev, sq);
+       if (ret)
+               ret = alloc_host_sq(rdev, sq);
+       return ret;
+}
+
 static int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
                      struct c4iw_dev_ucontext *uctx)
 {
@@ -129,7 +150,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
        int wr_len;
        struct c4iw_wr_wait wr_wait;
        struct sk_buff *skb;
-       int ret;
+       int ret = 0;
        int eqsize;
 
        wq->sq.qid = c4iw_get_qpid(rdev, uctx);
@@ -168,18 +189,9 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
                goto free_sw_rq;
        }
 
-       if (user) {
-               ret = alloc_oc_sq(rdev, &wq->sq);
-               if (ret)
-                       goto free_hwaddr;
-
-               ret = alloc_host_sq(rdev, &wq->sq);
-               if (ret)
-                       goto free_sq;
-       } else
-               ret = alloc_host_sq(rdev, &wq->sq);
-               if (ret)
-                       goto free_hwaddr;
+       ret = alloc_sq(rdev, &wq->sq, user);
+       if (ret)
+               goto free_hwaddr;
        memset(wq->sq.queue, 0, wq->sq.memsize);
        dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr);
 
@@ -534,7 +546,7 @@ static int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe,
 }
 
 static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe,
-                        struct ib_send_wr *wr, u8 *len16)
+                        struct ib_send_wr *wr, u8 *len16, u8 t5dev)
 {
 
        struct fw_ri_immd *imdp;
@@ -556,28 +568,51 @@ static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe,
        wqe->fr.va_hi = cpu_to_be32(wr->wr.fast_reg.iova_start >> 32);
        wqe->fr.va_lo_fbo = cpu_to_be32(wr->wr.fast_reg.iova_start &
                                        0xffffffff);
-       WARN_ON(pbllen > T4_MAX_FR_IMMD);
-       imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
-       imdp->op = FW_RI_DATA_IMMD;
-       imdp->r1 = 0;
-       imdp->r2 = 0;
-       imdp->immdlen = cpu_to_be32(pbllen);
-       p = (__be64 *)(imdp + 1);
-       rem = pbllen;
-       for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
-               *p = cpu_to_be64((u64)wr->wr.fast_reg.page_list->page_list[i]);
-               rem -= sizeof *p;
-               if (++p == (__be64 *)&sq->queue[sq->size])
-                       p = (__be64 *)sq->queue;
-       }
-       BUG_ON(rem < 0);
-       while (rem) {
-               *p = 0;
-               rem -= sizeof *p;
-               if (++p == (__be64 *)&sq->queue[sq->size])
-                       p = (__be64 *)sq->queue;
+
+       if (t5dev && use_dsgl && (pbllen > max_fr_immd)) {
+               struct c4iw_fr_page_list *c4pl =
+                       to_c4iw_fr_page_list(wr->wr.fast_reg.page_list);
+               struct fw_ri_dsgl *sglp;
+
+               for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
+                       wr->wr.fast_reg.page_list->page_list[i] = (__force u64)
+                               cpu_to_be64((u64)
+                               wr->wr.fast_reg.page_list->page_list[i]);
+               }
+
+               sglp = (struct fw_ri_dsgl *)(&wqe->fr + 1);
+               sglp->op = FW_RI_DATA_DSGL;
+               sglp->r1 = 0;
+               sglp->nsge = cpu_to_be16(1);
+               sglp->addr0 = cpu_to_be64(c4pl->dma_addr);
+               sglp->len0 = cpu_to_be32(pbllen);
+
+               *len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*sglp), 16);
+       } else {
+               imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
+               imdp->op = FW_RI_DATA_IMMD;
+               imdp->r1 = 0;
+               imdp->r2 = 0;
+               imdp->immdlen = cpu_to_be32(pbllen);
+               p = (__be64 *)(imdp + 1);
+               rem = pbllen;
+               for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
+                       *p = cpu_to_be64(
+                               (u64)wr->wr.fast_reg.page_list->page_list[i]);
+                       rem -= sizeof(*p);
+                       if (++p == (__be64 *)&sq->queue[sq->size])
+                               p = (__be64 *)sq->queue;
+               }
+               BUG_ON(rem < 0);
+               while (rem) {
+                       *p = 0;
+                       rem -= sizeof(*p);
+                       if (++p == (__be64 *)&sq->queue[sq->size])
+                               p = (__be64 *)sq->queue;
+               }
+               *len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*imdp)
+                                     + pbllen, 16);
        }
-       *len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *imdp + pbllen, 16);
        return 0;
 }
 
@@ -678,7 +713,10 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                case IB_WR_FAST_REG_MR:
                        fw_opcode = FW_RI_FR_NSMR_WR;
                        swsqe->opcode = FW_RI_FAST_REGISTER;
-                       err = build_fastreg(&qhp->wq.sq, wqe, wr, &len16);
+                       err = build_fastreg(&qhp->wq.sq, wqe, wr, &len16,
+                                           is_t5(
+                                           qhp->rhp->rdev.lldi.adapter_type) ?
+                                           1 : 0);
                        break;
                case IB_WR_LOCAL_INV:
                        if (wr->send_flags & IB_SEND_FENCE)
@@ -1450,6 +1488,9 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
                rhp->db_state = NORMAL;
                idr_for_each(&rhp->qpidr, enable_qp_db, NULL);
        }
+       if (db_coalescing_threshold >= 0)
+               if (rhp->qpcnt <= db_coalescing_threshold)
+                       cxgb4_enable_db_coalescing(rhp->rdev.lldi.ports[0]);
        spin_unlock_irq(&rhp->lock);
        atomic_dec(&qhp->refcnt);
        wait_event(qhp->wait, !atomic_read(&qhp->refcnt));
@@ -1561,11 +1602,15 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
        spin_lock_irq(&rhp->lock);
        if (rhp->db_state != NORMAL)
                t4_disable_wq_db(&qhp->wq);
-       if (++rhp->qpcnt > db_fc_threshold && rhp->db_state == NORMAL) {
+       rhp->qpcnt++;
+       if (rhp->qpcnt > db_fc_threshold && rhp->db_state == NORMAL) {
                rhp->rdev.stats.db_state_transitions++;
                rhp->db_state = FLOW_CONTROL;
                idr_for_each(&rhp->qpidr, disable_qp_db, NULL);
        }
+       if (db_coalescing_threshold >= 0)
+               if (rhp->qpcnt > db_coalescing_threshold)
+                       cxgb4_disable_db_coalescing(rhp->rdev.lldi.ports[0]);
        ret = insert_handle_nolock(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
        spin_unlock_irq(&rhp->lock);
        if (ret)