Merge branch 'cpufreq/arm/linux-next' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / infiniband / hw / mlx5 / devx.c
index 07b8350..c869b2a 100644 (file)
@@ -630,9 +630,8 @@ static bool devx_is_valid_obj_id(struct uverbs_attr_bundle *attrs,
        case UVERBS_OBJECT_QP:
        {
                struct mlx5_ib_qp *qp = to_mqp(uobj->object);
-               enum ib_qp_type qp_type = qp->ibqp.qp_type;
 
-               if (qp_type == IB_QPT_RAW_PACKET ||
+               if (qp->type == IB_QPT_RAW_PACKET ||
                    (qp->flags & IB_QP_CREATE_SOURCE_QPN)) {
                        struct mlx5_ib_raw_packet_qp *raw_packet_qp =
                                                         &qp->raw_packet_qp;
@@ -649,10 +648,9 @@ static bool devx_is_valid_obj_id(struct uverbs_attr_bundle *attrs,
                                               sq->tisn) == obj_id);
                }
 
-               if (qp_type == MLX5_IB_QPT_DCT)
+               if (qp->type == MLX5_IB_QPT_DCT)
                        return get_enc_obj_id(MLX5_CMD_OP_CREATE_DCT,
                                              qp->dct.mdct.mqp.qpn) == obj_id;
-
                return get_enc_obj_id(MLX5_CMD_OP_CREATE_QP,
                                      qp->ibqp.qp_num) == obj_id;
        }
@@ -977,7 +975,6 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_QUERY_EQN)(
        struct mlx5_ib_dev *dev;
        int user_vector;
        int dev_eqn;
-       unsigned int irqn;
        int err;
 
        if (uverbs_copy_from(&user_vector, attrs,
@@ -989,7 +986,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_QUERY_EQN)(
                return PTR_ERR(c);
        dev = to_mdev(c->ibucontext.device);
 
-       err = mlx5_vector2eqn(dev->mdev, user_vector, &dev_eqn, &irqn);
+       err = mlx5_vector2eqn(dev->mdev, user_vector, &dev_eqn);
        if (err < 0)
                return err;
 
@@ -2185,27 +2182,69 @@ static int devx_umem_get(struct mlx5_ib_dev *dev, struct ib_ucontext *ucontext,
        return 0;
 }
 
+static unsigned int devx_umem_find_best_pgsize(struct ib_umem *umem,
+                                              unsigned long pgsz_bitmap)
+{
+       unsigned long page_size;
+
+       /* Don't bother checking larger page sizes as offset must be zero and
+        * total DEVX umem length must be equal to total umem length.
+        */
+       pgsz_bitmap &= GENMASK_ULL(max_t(u64, order_base_2(umem->length),
+                                        PAGE_SHIFT),
+                                  MLX5_ADAPTER_PAGE_SHIFT);
+       if (!pgsz_bitmap)
+               return 0;
+
+       page_size = ib_umem_find_best_pgoff(umem, pgsz_bitmap, U64_MAX);
+       if (!page_size)
+               return 0;
+
+       /* If the page_size is less than the CPU page size then we can use the
+        * offset and create a umem which is a subset of the page list.
+        * For larger page sizes we can't be sure the DMA  list reflects the
+        * VA so we must ensure that the umem extent is exactly equal to the
+        * page list. Reduce the page size until one of these cases is true.
+        */
+       while ((ib_umem_dma_offset(umem, page_size) != 0 ||
+               (umem->length % page_size) != 0) &&
+               page_size > PAGE_SIZE)
+               page_size /= 2;
+
+       return page_size;
+}
+
 static int devx_umem_reg_cmd_alloc(struct mlx5_ib_dev *dev,
                                   struct uverbs_attr_bundle *attrs,
                                   struct devx_umem *obj,
                                   struct devx_umem_reg_cmd *cmd)
 {
+       unsigned long pgsz_bitmap;
        unsigned int page_size;
        __be64 *mtt;
        void *umem;
+       int ret;
 
        /*
-        * We don't know what the user intends to use this umem for, but the HW
-        * restrictions must be met. MR, doorbell records, QP, WQ and CQ all
-        * have different requirements. Since we have no idea how to sort this
-        * out, only support PAGE_SIZE with the expectation that userspace will
-        * provide the necessary alignments inside the known PAGE_SIZE and that
-        * FW will check everything.
+        * If the user does not pass in pgsz_bitmap then the user promises not
+        * to use umem_offset!=0 in any commands that allocate on top of the
+        * umem.
+        *
+        * If the user wants to use a umem_offset then it must pass in
+        * pgsz_bitmap which guides the maximum page size and thus maximum
+        * object alignment inside the umem. See the PRM.
+        *
+        * Users are not allowed to use IOVA here, mkeys are not supported on
+        * umem.
         */
-       page_size = ib_umem_find_best_pgoff(
-               obj->umem, PAGE_SIZE,
-               __mlx5_page_offset_to_bitmask(__mlx5_bit_sz(umem, page_offset),
-                                             0));
+       ret = uverbs_get_const_default(&pgsz_bitmap, attrs,
+                       MLX5_IB_ATTR_DEVX_UMEM_REG_PGSZ_BITMAP,
+                       GENMASK_ULL(63,
+                                   min(PAGE_SHIFT, MLX5_ADAPTER_PAGE_SHIFT)));
+       if (ret)
+               return ret;
+
+       page_size = devx_umem_find_best_pgsize(obj->umem, pgsz_bitmap);
        if (!page_size)
                return -EINVAL;
 
@@ -2791,6 +2830,8 @@ DECLARE_UVERBS_NAMED_METHOD(
                           UA_MANDATORY),
        UVERBS_ATTR_FLAGS_IN(MLX5_IB_ATTR_DEVX_UMEM_REG_ACCESS,
                             enum ib_access_flags),
+       UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_DEVX_UMEM_REG_PGSZ_BITMAP,
+                            u64),
        UVERBS_ATTR_PTR_OUT(MLX5_IB_ATTR_DEVX_UMEM_REG_OUT_ID,
                            UVERBS_ATTR_TYPE(u32),
                            UA_MANDATORY));