IB/mlx4: Add support for XRC QPs
authorSean Hefty <sean.hefty@intel.com>
Thu, 2 Jun 2011 18:32:15 +0000 (11:32 -0700)
committerRoland Dreier <roland@purestorage.com>
Thu, 13 Oct 2011 16:44:18 +0000 (09:44 -0700)
Support the creation of XRC INI and TGT QPs.  To handle the case where
a CQ or PD is not provided, we allocate them internally with the xrcd.

Signed-off-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/mlx4_ib.h
drivers/infiniband/hw/mlx4/qp.c
drivers/net/mlx4/qp.c
include/linux/mlx4/qp.h

index 42a538e5df368b4369146d5abfe8a703b4c52439..aec76ad7787235eb689395d869b3919d00b7df3e 100644 (file)
@@ -128,6 +128,8 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
            (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_REMOTE_INV) &&
            (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_FAST_REG_WR))
                props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
+       if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC)
+               props->device_cap_flags |= IB_DEVICE_XRC;
 
        props->vendor_id           = be32_to_cpup((__be32 *) (out_mad->data + 36)) &
                0xffffff;
index ce150b0e2cc85c4310661f1fe29b86d08fd1e556..ed80345c99ae159a458ed952514620bb35aca968 100644 (file)
@@ -145,6 +145,7 @@ struct mlx4_ib_qp {
        struct mlx4_mtt         mtt;
        int                     buf_size;
        struct mutex            mutex;
+       u16                     xrcdn;
        u32                     flags;
        u8                      port;
        u8                      alt_port;
index 3a91d9d8dc518fc278b819e594978477aaeeff56..1bbe64103674fe66527e3b2a34b99791b64a395e 100644 (file)
@@ -302,15 +302,14 @@ static int send_wqe_overhead(enum ib_qp_type type, u32 flags)
 }
 
 static int set_rq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
-                      int is_user, int has_srq, struct mlx4_ib_qp *qp)
+                      int is_user, int has_rq, struct mlx4_ib_qp *qp)
 {
        /* Sanity check RQ size before proceeding */
        if (cap->max_recv_wr  > dev->dev->caps.max_wqes  ||
            cap->max_recv_sge > dev->dev->caps.max_rq_sg)
                return -EINVAL;
 
-       if (has_srq) {
-               /* QPs attached to an SRQ should have no RQ */
+       if (!has_rq) {
                if (cap->max_recv_wr)
                        return -EINVAL;
 
@@ -463,6 +462,14 @@ static int set_user_sq_size(struct mlx4_ib_dev *dev,
        return 0;
 }
 
+static int qp_has_rq(struct ib_qp_init_attr *attr)
+{
+       if (attr->qp_type == IB_QPT_XRC_INI || attr->qp_type == IB_QPT_XRC_TGT)
+               return 0;
+
+       return !attr->srq;
+}
+
 static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                            struct ib_qp_init_attr *init_attr,
                            struct ib_udata *udata, int sqpn, struct mlx4_ib_qp *qp)
@@ -479,7 +486,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
        if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
                qp->sq_signal_bits = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE);
 
-       err = set_rq_size(dev, &init_attr->cap, !!pd->uobject, !!init_attr->srq, qp);
+       err = set_rq_size(dev, &init_attr->cap, !!pd->uobject, qp_has_rq(init_attr), qp);
        if (err)
                goto err;
 
@@ -513,7 +520,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                if (err)
                        goto err_mtt;
 
-               if (!init_attr->srq) {
+               if (qp_has_rq(init_attr)) {
                        err = mlx4_ib_db_map_user(to_mucontext(pd->uobject->context),
                                                  ucmd.db_addr, &qp->db);
                        if (err)
@@ -532,7 +539,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                if (err)
                        goto err;
 
-               if (!init_attr->srq) {
+               if (qp_has_rq(init_attr)) {
                        err = mlx4_db_alloc(dev->dev, &qp->db, 0);
                        if (err)
                                goto err;
@@ -575,6 +582,9 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
        if (err)
                goto err_qpn;
 
+       if (init_attr->qp_type == IB_QPT_XRC_TGT)
+               qp->mqp.qpn |= (1 << 23);
+
        /*
         * Hardware wants QPN written in big-endian order (after
         * shifting) for send doorbell.  Precompute this value to save
@@ -592,9 +602,8 @@ err_qpn:
 
 err_wrid:
        if (pd->uobject) {
-               if (!init_attr->srq)
-                       mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context),
-                                             &qp->db);
+               if (qp_has_rq(init_attr))
+                       mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &qp->db);
        } else {
                kfree(qp->sq.wrid);
                kfree(qp->rq.wrid);
@@ -610,7 +619,7 @@ err_buf:
                mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf);
 
 err_db:
-       if (!pd->uobject && !init_attr->srq)
+       if (!pd->uobject && qp_has_rq(init_attr))
                mlx4_db_free(dev->dev, &qp->db);
 
 err:
@@ -671,6 +680,33 @@ static void del_gid_entries(struct mlx4_ib_qp *qp)
        }
 }
 
+static struct mlx4_ib_pd *get_pd(struct mlx4_ib_qp *qp)
+{
+       if (qp->ibqp.qp_type == IB_QPT_XRC_TGT)
+               return to_mpd(to_mxrcd(qp->ibqp.xrcd)->pd);
+       else
+               return to_mpd(qp->ibqp.pd);
+}
+
+static void get_cqs(struct mlx4_ib_qp *qp,
+                   struct mlx4_ib_cq **send_cq, struct mlx4_ib_cq **recv_cq)
+{
+       switch (qp->ibqp.qp_type) {
+       case IB_QPT_XRC_TGT:
+               *send_cq = to_mcq(to_mxrcd(qp->ibqp.xrcd)->cq);
+               *recv_cq = *send_cq;
+               break;
+       case IB_QPT_XRC_INI:
+               *send_cq = to_mcq(qp->ibqp.send_cq);
+               *recv_cq = *send_cq;
+               break;
+       default:
+               *send_cq = to_mcq(qp->ibqp.send_cq);
+               *recv_cq = to_mcq(qp->ibqp.recv_cq);
+               break;
+       }
+}
+
 static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
                              int is_user)
 {
@@ -682,8 +718,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
                        printk(KERN_WARNING "mlx4_ib: modify QP %06x to RESET failed.\n",
                               qp->mqp.qpn);
 
-       send_cq = to_mcq(qp->ibqp.send_cq);
-       recv_cq = to_mcq(qp->ibqp.recv_cq);
+       get_cqs(qp, &send_cq, &recv_cq);
 
        mlx4_ib_lock_cqs(send_cq, recv_cq);
 
@@ -706,7 +741,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
        mlx4_mtt_cleanup(dev->dev, &qp->mtt);
 
        if (is_user) {
-               if (!qp->ibqp.srq)
+               if (qp->rq.wqe_cnt)
                        mlx4_ib_db_unmap_user(to_mucontext(qp->ibqp.uobject->context),
                                              &qp->db);
                ib_umem_release(qp->umem);
@@ -714,7 +749,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
                kfree(qp->sq.wrid);
                kfree(qp->rq.wrid);
                mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf);
-               if (!qp->ibqp.srq)
+               if (qp->rq.wqe_cnt)
                        mlx4_db_free(dev->dev, &qp->db);
        }
 
@@ -725,10 +760,10 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
                                struct ib_qp_init_attr *init_attr,
                                struct ib_udata *udata)
 {
-       struct mlx4_ib_dev *dev = to_mdev(pd->device);
        struct mlx4_ib_sqp *sqp;
        struct mlx4_ib_qp *qp;
        int err;
+       u16 xrcdn = 0;
 
        /*
         * We only support LSO and multicast loopback blocking, and
@@ -739,10 +774,20 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
                return ERR_PTR(-EINVAL);
 
        if (init_attr->create_flags &&
-           (pd->uobject || init_attr->qp_type != IB_QPT_UD))
+           (udata || init_attr->qp_type != IB_QPT_UD))
                return ERR_PTR(-EINVAL);
 
        switch (init_attr->qp_type) {
+       case IB_QPT_XRC_TGT:
+               pd = to_mxrcd(init_attr->xrcd)->pd;
+               xrcdn = to_mxrcd(init_attr->xrcd)->xrcdn;
+               init_attr->send_cq = to_mxrcd(init_attr->xrcd)->cq;
+               /* fall through */
+       case IB_QPT_XRC_INI:
+               if (!(to_mdev(pd->device)->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC))
+                       return ERR_PTR(-ENOSYS);
+               init_attr->recv_cq = init_attr->send_cq;
+               /* fall through */
        case IB_QPT_RC:
        case IB_QPT_UC:
        case IB_QPT_UD:
@@ -751,13 +796,14 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
                if (!qp)
                        return ERR_PTR(-ENOMEM);
 
-               err = create_qp_common(dev, pd, init_attr, udata, 0, qp);
+               err = create_qp_common(to_mdev(pd->device), pd, init_attr, udata, 0, qp);
                if (err) {
                        kfree(qp);
                        return ERR_PTR(err);
                }
 
                qp->ibqp.qp_num = qp->mqp.qpn;
+               qp->xrcdn = xrcdn;
 
                break;
        }
@@ -765,7 +811,7 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
        case IB_QPT_GSI:
        {
                /* Userspace is not allowed to create special QPs: */
-               if (pd->uobject)
+               if (udata)
                        return ERR_PTR(-EINVAL);
 
                sqp = kzalloc(sizeof *sqp, GFP_KERNEL);
@@ -774,8 +820,8 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
 
                qp = &sqp->qp;
 
-               err = create_qp_common(dev, pd, init_attr, udata,
-                                      dev->dev->caps.sqp_start +
+               err = create_qp_common(to_mdev(pd->device), pd, init_attr, udata,
+                                      to_mdev(pd->device)->dev->caps.sqp_start +
                                       (init_attr->qp_type == IB_QPT_SMI ? 0 : 2) +
                                       init_attr->port_num - 1,
                                       qp);
@@ -801,11 +847,13 @@ int mlx4_ib_destroy_qp(struct ib_qp *qp)
 {
        struct mlx4_ib_dev *dev = to_mdev(qp->device);
        struct mlx4_ib_qp *mqp = to_mqp(qp);
+       struct mlx4_ib_pd *pd;
 
        if (is_qp0(dev, mqp))
                mlx4_CLOSE_PORT(dev->dev, mqp->port);
 
-       destroy_qp_common(dev, mqp, !!qp->pd->uobject);
+       pd = get_pd(mqp);
+       destroy_qp_common(dev, mqp, !!pd->ibpd.uobject);
 
        if (is_sqp(dev, mqp))
                kfree(to_msqp(mqp));
@@ -821,6 +869,8 @@ static int to_mlx4_st(enum ib_qp_type type)
        case IB_QPT_RC:         return MLX4_QP_ST_RC;
        case IB_QPT_UC:         return MLX4_QP_ST_UC;
        case IB_QPT_UD:         return MLX4_QP_ST_UD;
+       case IB_QPT_XRC_INI:
+       case IB_QPT_XRC_TGT:    return MLX4_QP_ST_XRC;
        case IB_QPT_SMI:
        case IB_QPT_GSI:        return MLX4_QP_ST_MLX;
        default:                return -1;
@@ -959,6 +1009,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
 {
        struct mlx4_ib_dev *dev = to_mdev(ibqp->device);
        struct mlx4_ib_qp *qp = to_mqp(ibqp);
+       struct mlx4_ib_pd *pd;
+       struct mlx4_ib_cq *send_cq, *recv_cq;
        struct mlx4_qp_context *context;
        enum mlx4_qp_optpar optpar = 0;
        int sqd_event;
@@ -1014,8 +1066,10 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                context->sq_size_stride = ilog2(qp->sq.wqe_cnt) << 3;
        context->sq_size_stride |= qp->sq.wqe_shift - 4;
 
-       if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
+       if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
                context->sq_size_stride |= !!qp->sq_no_prefetch << 7;
+               context->xrcd = cpu_to_be32((u32) qp->xrcdn);
+       }
 
        if (qp->ibqp.uobject)
                context->usr_page = cpu_to_be32(to_mucontext(ibqp->uobject->context)->uar.index);
@@ -1079,8 +1133,12 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                optpar |= MLX4_QP_OPTPAR_ALT_ADDR_PATH;
        }
 
-       context->pd         = cpu_to_be32(to_mpd(ibqp->pd)->pdn);
-       context->params1    = cpu_to_be32(MLX4_IB_ACK_REQ_FREQ << 28);
+       pd = get_pd(qp);
+       get_cqs(qp, &send_cq, &recv_cq);
+       context->pd       = cpu_to_be32(pd->pdn);
+       context->cqn_send = cpu_to_be32(send_cq->mcq.cqn);
+       context->cqn_recv = cpu_to_be32(recv_cq->mcq.cqn);
+       context->params1  = cpu_to_be32(MLX4_IB_ACK_REQ_FREQ << 28);
 
        /* Set "fast registration enabled" for all kernel QPs */
        if (!qp->ibqp.uobject)
@@ -1106,8 +1164,6 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
        if (attr_mask & IB_QP_SQ_PSN)
                context->next_send_psn = cpu_to_be32(attr->sq_psn);
 
-       context->cqn_send = cpu_to_be32(to_mcq(ibqp->send_cq)->mcq.cqn);
-
        if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
                if (attr->max_dest_rd_atomic)
                        context->params2 |=
@@ -1130,8 +1186,6 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
        if (attr_mask & IB_QP_RQ_PSN)
                context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn);
 
-       context->cqn_recv = cpu_to_be32(to_mcq(ibqp->recv_cq)->mcq.cqn);
-
        if (attr_mask & IB_QP_QKEY) {
                context->qkey = cpu_to_be32(attr->qkey);
                optpar |= MLX4_QP_OPTPAR_Q_KEY;
@@ -1140,7 +1194,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
        if (ibqp->srq)
                context->srqn = cpu_to_be32(1 << 24 | to_msrq(ibqp->srq)->msrq.srqn);
 
-       if (!ibqp->srq && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
+       if (qp->rq.wqe_cnt && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
                context->db_rec_addr = cpu_to_be64(qp->db.dma);
 
        if (cur_state == IB_QPS_INIT &&
@@ -1225,17 +1279,17 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
         * entries and reinitialize the QP.
         */
        if (new_state == IB_QPS_RESET && !ibqp->uobject) {
-               mlx4_ib_cq_clean(to_mcq(ibqp->recv_cq), qp->mqp.qpn,
+               mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn,
                                 ibqp->srq ? to_msrq(ibqp->srq): NULL);
-               if (ibqp->send_cq != ibqp->recv_cq)
-                       mlx4_ib_cq_clean(to_mcq(ibqp->send_cq), qp->mqp.qpn, NULL);
+               if (send_cq != recv_cq)
+                       mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
 
                qp->rq.head = 0;
                qp->rq.tail = 0;
                qp->sq.head = 0;
                qp->sq.tail = 0;
                qp->sq_next_wqe = 0;
-               if (!ibqp->srq)
+               if (qp->rq.wqe_cnt)
                        *qp->db.db  = 0;
        }
 
index ec9350e5f21ab7072dc00a062b28cb9781af2d7b..51c53898c35f89f3529e866fea994e001a828a85 100644 (file)
@@ -280,6 +280,9 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
         * We reserve 2 extra QPs per port for the special QPs.  The
         * block of special QPs must be aligned to a multiple of 8, so
         * round up.
+        *
+        * We also reserve the MSB of the 24-bit QP number to indicate
+        * that a QP is an XRC QP.
         */
        dev->caps.sqp_start =
                ALIGN(dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 8);
index 4001c8249dbb7f74668fe5e5d935cfeb51ad1cc0..48cc4cb9785856b5469e322250672b3e9a1a2449 100644 (file)
@@ -75,6 +75,7 @@ enum {
        MLX4_QP_ST_UC                           = 0x1,
        MLX4_QP_ST_RD                           = 0x2,
        MLX4_QP_ST_UD                           = 0x3,
+       MLX4_QP_ST_XRC                          = 0x6,
        MLX4_QP_ST_MLX                          = 0x7
 };
 
@@ -137,7 +138,7 @@ struct mlx4_qp_context {
        __be32                  ssn;
        __be32                  params2;
        __be32                  rnr_nextrecvpsn;
-       __be32                  srcd;
+       __be32                  xrcd;
        __be32                  cqn_recv;
        __be64                  db_rec_addr;
        __be32                  qkey;