]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/infiniband/hw/ehca/ehca_qp.c
IB/ehca: Support small QP queues
[linux-2.6-omap-h63xx.git] / drivers / infiniband / hw / ehca / ehca_qp.c
index 483f0ca1acc41ce7d3c7c4d4154d9a685b1fcefb..b178cba963450cee28a72a01947d90fee63c48ef 100644 (file)
@@ -275,34 +275,39 @@ static inline void queue2resp(struct ipzu_queue_resp *resp,
        resp->toggle_state = queue->toggle_state;
 }
 
-static inline int ll_qp_msg_size(int nr_sge)
-{
-       return 128 << nr_sge;
-}
-
 /*
  * init_qp_queue initializes/constructs r/squeue and registers queue pages.
  */
 static inline int init_qp_queue(struct ehca_shca *shca,
+                               struct ehca_pd *pd,
                                struct ehca_qp *my_qp,
                                struct ipz_queue *queue,
                                int q_type,
                                u64 expected_hret,
-                               int nr_q_pages,
-                               int wqe_size,
-                               int nr_sges)
+                               struct ehca_alloc_queue_parms *parms,
+                               int wqe_size)
 {
-       int ret, cnt, ipz_rc;
+       int ret, cnt, ipz_rc, nr_q_pages;
        void *vpage;
        u64 rpage, h_ret;
        struct ib_device *ib_dev = &shca->ib_device;
        struct ipz_adapter_handle ipz_hca_handle = shca->ipz_hca_handle;
 
-       if (!nr_q_pages)
+       if (!parms->queue_size)
                return 0;
 
-       ipz_rc = ipz_queue_ctor(queue, nr_q_pages, EHCA_PAGESIZE,
-                               wqe_size, nr_sges);
+       if (parms->is_small) {
+               nr_q_pages = 1;
+               ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,
+                                       128 << parms->page_size,
+                                       wqe_size, parms->act_nr_sges, 1);
+       } else {
+               nr_q_pages = parms->queue_size;
+               ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,
+                                       EHCA_PAGESIZE, wqe_size,
+                                       parms->act_nr_sges, 0);
+       }
+
        if (!ipz_rc) {
                ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%x",
                         ipz_rc);
@@ -323,7 +328,7 @@ static inline int init_qp_queue(struct ehca_shca *shca,
                h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
                                                 my_qp->ipz_qp_handle,
                                                 NULL, 0, q_type,
-                                                rpage, 1,
+                                                rpage, parms->is_small ? 0 : 1,
                                                 my_qp->galpas.kernel);
                if (cnt == (nr_q_pages - 1)) {  /* last page! */
                        if (h_ret != expected_hret) {
@@ -354,10 +359,45 @@ static inline int init_qp_queue(struct ehca_shca *shca,
        return 0;
 
 init_qp_queue1:
-       ipz_queue_dtor(queue);
+       ipz_queue_dtor(pd, queue);
        return ret;
 }
 
+static inline int ehca_calc_wqe_size(int act_nr_sge, int is_llqp)
+{
+       if (is_llqp)
+               return 128 << act_nr_sge;
+       else
+               return offsetof(struct ehca_wqe,
+                               u.nud.sg_list[act_nr_sge]);
+}
+
+static void ehca_determine_small_queue(struct ehca_alloc_queue_parms *queue,
+                                      int req_nr_sge, int is_llqp)
+{
+       u32 wqe_size, q_size;
+       int act_nr_sge = req_nr_sge;
+
+       if (!is_llqp)
+               /* round up #SGEs so WQE size is a power of 2 */
+               for (act_nr_sge = 4; act_nr_sge <= 252;
+                    act_nr_sge = 4 + 2 * act_nr_sge)
+                       if (act_nr_sge >= req_nr_sge)
+                               break;
+
+       wqe_size = ehca_calc_wqe_size(act_nr_sge, is_llqp);
+       q_size = wqe_size * (queue->max_wr + 1);
+
+       if (q_size <= 512)
+               queue->page_size = 2;
+       else if (q_size <= 1024)
+               queue->page_size = 3;
+       else
+               queue->page_size = 0;
+
+       queue->is_small = (queue->page_size != 0);
+}
+
 /*
  * Create an ib_qp struct that is either a QP or an SRQ, depending on
  * the value of the is_srq parameter. If init_attr and srq_init_attr share
@@ -553,10 +593,20 @@ static struct ehca_qp *internal_create_qp(
        if (my_qp->recv_cq)
                parms.recv_cq_handle = my_qp->recv_cq->ipz_cq_handle;
 
-       parms.max_send_wr = init_attr->cap.max_send_wr;
-       parms.max_recv_wr = init_attr->cap.max_recv_wr;
-       parms.max_send_sge = max_send_sge;
-       parms.max_recv_sge = max_recv_sge;
+       parms.squeue.max_wr = init_attr->cap.max_send_wr;
+       parms.rqueue.max_wr = init_attr->cap.max_recv_wr;
+       parms.squeue.max_sge = max_send_sge;
+       parms.rqueue.max_sge = max_recv_sge;
+
+       if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)
+           && !(context && udata)) { /* no small QP support in userspace ATM */
+               ehca_determine_small_queue(
+                       &parms.squeue, max_send_sge, is_llqp);
+               ehca_determine_small_queue(
+                       &parms.rqueue, max_recv_sge, is_llqp);
+               parms.qp_storage =
+                       (parms.squeue.is_small || parms.rqueue.is_small);
+       }
 
        h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms);
        if (h_ret != H_SUCCESS) {
@@ -570,50 +620,33 @@ static struct ehca_qp *internal_create_qp(
        my_qp->ipz_qp_handle = parms.qp_handle;
        my_qp->galpas = parms.galpas;
 
+       swqe_size = ehca_calc_wqe_size(parms.squeue.act_nr_sges, is_llqp);
+       rwqe_size = ehca_calc_wqe_size(parms.rqueue.act_nr_sges, is_llqp);
+
        switch (qp_type) {
        case IB_QPT_RC:
-               if (!is_llqp) {
-                       swqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
-                                            (parms.act_nr_send_sges)]);
-                       rwqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
-                                            (parms.act_nr_recv_sges)]);
-               } else { /* for LLQP we need to use msg size, not wqe size */
-                       swqe_size = ll_qp_msg_size(max_send_sge);
-                       rwqe_size = ll_qp_msg_size(max_recv_sge);
-                       parms.act_nr_send_sges = 1;
-                       parms.act_nr_recv_sges = 1;
+               if (is_llqp) {
+                       parms.squeue.act_nr_sges = 1;
+                       parms.rqueue.act_nr_sges = 1;
                }
                break;
-       case IB_QPT_UC:
-               swqe_size = offsetof(struct ehca_wqe,
-                                    u.nud.sg_list[parms.act_nr_send_sges]);
-               rwqe_size = offsetof(struct ehca_wqe,
-                                    u.nud.sg_list[parms.act_nr_recv_sges]);
-               break;
-
        case IB_QPT_UD:
        case IB_QPT_GSI:
        case IB_QPT_SMI:
+               /* UD circumvention */
                if (is_llqp) {
-                       swqe_size = ll_qp_msg_size(parms.act_nr_send_sges);
-                       rwqe_size = ll_qp_msg_size(parms.act_nr_recv_sges);
-                       parms.act_nr_send_sges = 1;
-                       parms.act_nr_recv_sges = 1;
+                       parms.squeue.act_nr_sges = 1;
+                       parms.rqueue.act_nr_sges = 1;
                } else {
-                       /* UD circumvention */
-                       parms.act_nr_send_sges -= 2;
-                       parms.act_nr_recv_sges -= 2;
-                       swqe_size = offsetof(struct ehca_wqe, u.ud_av.sg_list[
-                                                    parms.act_nr_send_sges]);
-                       rwqe_size = offsetof(struct ehca_wqe, u.ud_av.sg_list[
-                                                    parms.act_nr_recv_sges]);
+                       parms.squeue.act_nr_sges -= 2;
+                       parms.rqueue.act_nr_sges -= 2;
                }
 
                if (IB_QPT_GSI == qp_type || IB_QPT_SMI == qp_type) {
-                       parms.act_nr_send_wqes = init_attr->cap.max_send_wr;
-                       parms.act_nr_recv_wqes = init_attr->cap.max_recv_wr;
-                       parms.act_nr_send_sges = init_attr->cap.max_send_sge;
-                       parms.act_nr_recv_sges = init_attr->cap.max_recv_sge;
+                       parms.squeue.act_nr_wqes = init_attr->cap.max_send_wr;
+                       parms.rqueue.act_nr_wqes = init_attr->cap.max_recv_wr;
+                       parms.squeue.act_nr_sges = init_attr->cap.max_send_sge;
+                       parms.rqueue.act_nr_sges = init_attr->cap.max_recv_sge;
                        ib_qp_num = (qp_type == IB_QPT_SMI) ? 0 : 1;
                }
 
@@ -626,10 +659,9 @@ static struct ehca_qp *internal_create_qp(
        /* initialize r/squeue and register queue pages */
        if (HAS_SQ(my_qp)) {
                ret = init_qp_queue(
-                       shca, my_qp, &my_qp->ipz_squeue, 0,
+                       shca, my_pd, my_qp, &my_qp->ipz_squeue, 0,
                        HAS_RQ(my_qp) ? H_PAGE_REGISTERED : H_SUCCESS,
-                       parms.nr_sq_pages, swqe_size,
-                       parms.act_nr_send_sges);
+                       &parms.squeue, swqe_size);
                if (ret) {
                        ehca_err(pd->device, "Couldn't initialize squeue "
                                 "and pages  ret=%x", ret);
@@ -639,9 +671,8 @@ static struct ehca_qp *internal_create_qp(
 
        if (HAS_RQ(my_qp)) {
                ret = init_qp_queue(
-                       shca, my_qp, &my_qp->ipz_rqueue, 1,
-                       H_SUCCESS, parms.nr_rq_pages, rwqe_size,
-                       parms.act_nr_recv_sges);
+                       shca, my_pd, my_qp, &my_qp->ipz_rqueue, 1,
+                       H_SUCCESS, &parms.rqueue, rwqe_size);
                if (ret) {
                        ehca_err(pd->device, "Couldn't initialize rqueue "
                                 "and pages ret=%x", ret);
@@ -671,10 +702,10 @@ static struct ehca_qp *internal_create_qp(
        }
 
        init_attr->cap.max_inline_data = 0; /* not supported yet */
-       init_attr->cap.max_recv_sge = parms.act_nr_recv_sges;
-       init_attr->cap.max_recv_wr = parms.act_nr_recv_wqes;
-       init_attr->cap.max_send_sge = parms.act_nr_send_sges;
-       init_attr->cap.max_send_wr = parms.act_nr_send_wqes;
+       init_attr->cap.max_recv_sge = parms.rqueue.act_nr_sges;
+       init_attr->cap.max_recv_wr = parms.rqueue.act_nr_wqes;
+       init_attr->cap.max_send_sge = parms.squeue.act_nr_sges;
+       init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes;
        my_qp->init_attr = *init_attr;
 
        /* NOTE: define_apq0() not supported yet */
@@ -708,6 +739,8 @@ static struct ehca_qp *internal_create_qp(
                resp.ext_type = my_qp->ext_type;
                resp.qkey = my_qp->qkey;
                resp.real_qp_num = my_qp->real_qp_num;
+               resp.ipz_rqueue.offset = my_qp->ipz_rqueue.offset;
+               resp.ipz_squeue.offset = my_qp->ipz_squeue.offset;
                if (HAS_SQ(my_qp))
                        queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue);
                if (HAS_RQ(my_qp))
@@ -724,11 +757,11 @@ static struct ehca_qp *internal_create_qp(
 
 create_qp_exit4:
        if (HAS_RQ(my_qp))
-               ipz_queue_dtor(&my_qp->ipz_rqueue);
+               ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
 
 create_qp_exit3:
        if (HAS_SQ(my_qp))
-               ipz_queue_dtor(&my_qp->ipz_squeue);
+               ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
 
 create_qp_exit2:
        hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
@@ -1735,9 +1768,9 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
        }
 
        if (HAS_RQ(my_qp))
-               ipz_queue_dtor(&my_qp->ipz_rqueue);
+               ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
        if (HAS_SQ(my_qp))
-               ipz_queue_dtor(&my_qp->ipz_squeue);
+               ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
        kmem_cache_free(qp_cache, my_qp);
        return 0;
 }