IB/mlx5: Add support for QP with a given source QPN
authorYishai Hadas <yishaih@mellanox.com>
Thu, 8 Jun 2017 13:15:08 +0000 (16:15 +0300)
committerDoug Ledford <dledford@redhat.com>
Mon, 24 Jul 2017 14:40:46 +0000 (10:40 -0400)
Allow user space applications to accelerate send and receive
traffic which is typically handled by IPoIB ULP by creating
a UD QP with a given source QPN of the IPoIB UD QP.

UD QP with a given source QPN should basically be similar to
RAW QP from point of view of its created resources.

However,
- Its TIS should point to the source QPN.
- Modify can be done only on its state as the transport attributes
  are managed by its source QP.

This patch manages below:
- Creating/destroying/modifying UD QP with a given source QPN.

Signed-off-by: Yishai Hadas <yishaih@mellanox.com>
Reviewed-by: Maor Gottlieb <maorg@mellanox.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/hw/mlx5/qp.c

index 0316147..7ac9910 100644 (file)
@@ -383,6 +383,7 @@ struct mlx5_ib_qp {
        struct list_head        cq_recv_list;
        struct list_head        cq_send_list;
        u32                     rate_limit;
+       u32                     underlay_qpn;
 };
 
 struct mlx5_ib_cq_buf {
@@ -404,6 +405,7 @@ enum mlx5_ib_qp_flags {
        MLX5_IB_QP_CAP_SCATTER_FCS              = 1 << 7,
        MLX5_IB_QP_RSS                          = 1 << 8,
        MLX5_IB_QP_CVLAN_STRIPPING              = 1 << 9,
+       MLX5_IB_QP_UNDERLAY                     = 1 << 10,
 };
 
 struct mlx5_umr_wr {
index c5d8ec8..5c7ce9b 100644 (file)
@@ -34,6 +34,7 @@
 #include <rdma/ib_umem.h>
 #include <rdma/ib_cache.h>
 #include <rdma/ib_user_verbs.h>
+#include <linux/mlx5/fs.h>
 #include "mlx5_ib.h"
 
 /* not supported currently */
@@ -453,7 +454,8 @@ static int set_user_buf_size(struct mlx5_ib_dev *dev,
                return -EINVAL;
        }
 
-       if (attr->qp_type == IB_QPT_RAW_PACKET) {
+       if (attr->qp_type == IB_QPT_RAW_PACKET ||
+           qp->flags & MLX5_IB_QP_UNDERLAY) {
                base->ubuffer.buf_size = qp->rq.wqe_cnt << qp->rq.wqe_shift;
                qp->raw_packet_qp.sq.ubuffer.buf_size = qp->sq.wqe_cnt << 6;
        } else {
@@ -1025,12 +1027,16 @@ static int is_connected(enum ib_qp_type qp_type)
 }
 
 static int create_raw_packet_qp_tis(struct mlx5_ib_dev *dev,
+                                   struct mlx5_ib_qp *qp,
                                    struct mlx5_ib_sq *sq, u32 tdn)
 {
        u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {0};
        void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
 
        MLX5_SET(tisc, tisc, transport_domain, tdn);
+       if (qp->flags & MLX5_IB_QP_UNDERLAY)
+               MLX5_SET(tisc, tisc, underlay_qpn, qp->underlay_qpn);
+
        return mlx5_core_create_tis(dev->mdev, in, sizeof(in), &sq->tisn);
 }
 
@@ -1233,7 +1239,7 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
        u32 tdn = mucontext->tdn;
 
        if (qp->sq.wqe_cnt) {
-               err = create_raw_packet_qp_tis(dev, sq, tdn);
+               err = create_raw_packet_qp_tis(dev, qp, sq, tdn);
                if (err)
                        return err;
 
@@ -1506,10 +1512,6 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
        u32 *in;
        int err;
 
-       base = init_attr->qp_type == IB_QPT_RAW_PACKET ?
-              &qp->raw_packet_qp.rq.base :
-              &qp->trans_qp.base;
-
        mutex_init(&qp->mutex);
        spin_lock_init(&qp->sq.lock);
        spin_lock_init(&qp->rq.lock);
@@ -1591,10 +1593,28 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
 
                qp->wq_sig = !!(ucmd.flags & MLX5_QP_FLAG_SIGNATURE);
                qp->scat_cqe = !!(ucmd.flags & MLX5_QP_FLAG_SCATTER_CQE);
+
+               if (init_attr->create_flags & IB_QP_CREATE_SOURCE_QPN) {
+                       if (init_attr->qp_type != IB_QPT_UD ||
+                           (MLX5_CAP_GEN(dev->mdev, port_type) !=
+                            MLX5_CAP_PORT_TYPE_IB) ||
+                           !mlx5_get_flow_namespace(dev->mdev, MLX5_FLOW_NAMESPACE_BYPASS)) {
+                               mlx5_ib_dbg(dev, "Source QP option isn't supported\n");
+                               return -EOPNOTSUPP;
+                       }
+
+                       qp->flags |= MLX5_IB_QP_UNDERLAY;
+                       qp->underlay_qpn = init_attr->source_qpn;
+               }
        } else {
                qp->wq_sig = !!wq_signature;
        }
 
+       base = (init_attr->qp_type == IB_QPT_RAW_PACKET ||
+               qp->flags & MLX5_IB_QP_UNDERLAY) ?
+              &qp->raw_packet_qp.rq.base :
+              &qp->trans_qp.base;
+
        qp->has_rq = qp_has_rq(init_attr);
        err = set_rq_size(dev, &init_attr->cap, qp->has_rq,
                          qp, (pd && pd->uobject) ? &ucmd : NULL);
@@ -1745,7 +1765,8 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
                qp->flags |= MLX5_IB_QP_LSO;
        }
 
-       if (init_attr->qp_type == IB_QPT_RAW_PACKET) {
+       if (init_attr->qp_type == IB_QPT_RAW_PACKET ||
+           qp->flags & MLX5_IB_QP_UNDERLAY) {
                qp->raw_packet_qp.sq.ubuffer.buf_addr = ucmd.sq_buf_addr;
                raw_packet_qp_copy_info(qp, &qp->raw_packet_qp);
                err = create_raw_packet_qp(dev, qp, in, pd);
@@ -1897,7 +1918,7 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
 static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
 {
        struct mlx5_ib_cq *send_cq, *recv_cq;
-       struct mlx5_ib_qp_base *base = &qp->trans_qp.base;
+       struct mlx5_ib_qp_base *base;
        unsigned long flags;
        int err;
 
@@ -1906,12 +1927,14 @@ static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
                return;
        }
 
-       base = qp->ibqp.qp_type == IB_QPT_RAW_PACKET ?
+       base = (qp->ibqp.qp_type == IB_QPT_RAW_PACKET ||
+               qp->flags & MLX5_IB_QP_UNDERLAY) ?
               &qp->raw_packet_qp.rq.base :
               &qp->trans_qp.base;
 
        if (qp->state != IB_QPS_RESET) {
-               if (qp->ibqp.qp_type != IB_QPT_RAW_PACKET) {
+               if (qp->ibqp.qp_type != IB_QPT_RAW_PACKET &&
+                   !(qp->flags & MLX5_IB_QP_UNDERLAY)) {
                        err = mlx5_core_qp_modify(dev->mdev,
                                                  MLX5_CMD_OP_2RST_QP, 0,
                                                  NULL, &base->mqp);
@@ -1950,7 +1973,8 @@ static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
        mlx5_ib_unlock_cqs(send_cq, recv_cq);
        spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
 
-       if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) {
+       if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET ||
+           qp->flags & MLX5_IB_QP_UNDERLAY) {
                destroy_raw_packet_qp(dev, qp);
        } else {
                err = mlx5_core_destroy_qp(dev->mdev, &base->mqp);
@@ -2706,7 +2730,8 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
 
        if (is_sqp(ibqp->qp_type)) {
                context->mtu_msgmax = (IB_MTU_256 << 5) | 8;
-       } else if (ibqp->qp_type == IB_QPT_UD ||
+       } else if ((ibqp->qp_type == IB_QPT_UD &&
+                   !(qp->flags & MLX5_IB_QP_UNDERLAY)) ||
                   ibqp->qp_type == MLX5_IB_QPT_REG_UMR) {
                context->mtu_msgmax = (IB_MTU_4096 << 5) | 12;
        } else if (attr_mask & IB_QP_PATH_MTU) {
@@ -2803,6 +2828,11 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
        if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
                u8 port_num = (attr_mask & IB_QP_PORT ? attr->port_num :
                               qp->port) - 1;
+
+               /* Underlay port should be used - index 0 function per port */
+               if (qp->flags & MLX5_IB_QP_UNDERLAY)
+                       port_num = 0;
+
                mibport = &dev->port[port_num];
                context->qp_counter_set_usr_page |=
                        cpu_to_be32((u32)(mibport->cnts.set_id) << 24);
@@ -2828,7 +2858,8 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
        optpar = ib_mask_to_mlx5_opt(attr_mask);
        optpar &= opt_mask[mlx5_cur][mlx5_new][mlx5_st];
 
-       if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) {
+       if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET ||
+           qp->flags & MLX5_IB_QP_UNDERLAY) {
                struct mlx5_modify_raw_qp_param raw_qp_param = {};
 
                raw_qp_param.operation = op;
@@ -2917,7 +2948,13 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                ll = dev->ib_dev.get_link_layer(&dev->ib_dev, port);
        }
 
-       if (qp_type != MLX5_IB_QPT_REG_UMR &&
+       if (qp->flags & MLX5_IB_QP_UNDERLAY) {
+               if (attr_mask & ~(IB_QP_STATE | IB_QP_CUR_STATE)) {
+                       mlx5_ib_dbg(dev, "invalid attr_mask 0x%x when underlay QP is used\n",
+                                   attr_mask);
+                       goto out;
+               }
+       } else if (qp_type != MLX5_IB_QPT_REG_UMR &&
            !ib_modify_qp_is_ok(cur_state, new_state, qp_type, attr_mask, ll)) {
                mlx5_ib_dbg(dev, "invalid QP state transition from %d to %d, qp_type %d, attr_mask 0x%x\n",
                            cur_state, new_state, ibqp->qp_type, attr_mask);
@@ -4481,9 +4518,14 @@ int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
                return mlx5_ib_gsi_query_qp(ibqp, qp_attr, qp_attr_mask,
                                            qp_init_attr);
 
+       /* Not all of output fields are applicable, make sure to zero them */
+       memset(qp_init_attr, 0, sizeof(*qp_init_attr));
+       memset(qp_attr, 0, sizeof(*qp_attr));
+
        mutex_lock(&qp->mutex);
 
-       if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) {
+       if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET ||
+           qp->flags & MLX5_IB_QP_UNDERLAY) {
                err = query_raw_packet_qp_state(dev, qp, &raw_packet_qp_state);
                if (err)
                        goto out;