IB/mlx5: Add memory windows allocation support
authorMatan Barak <matanb@mellanox.com>
Mon, 29 Feb 2016 16:05:30 +0000 (18:05 +0200)
committerDoug Ledford <dledford@redhat.com>
Tue, 1 Mar 2016 16:18:54 +0000 (11:18 -0500)
This patch adds user-space support for memory windows allocation and
deallocation. It also exposes the supported types via
query_device_caps verb.

Signed-off-by: Matan Barak <matanb@mellanox.com>
Reviewed-by: Yishai Hadas <yishaih@mellanox.com>
Tested-by: Max Gurtovoy <maxg@mellanox.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/hw/mlx5/user.h
include/linux/mlx5/mlx5_ifc.h

index 16f7d0b41c04f3ba3ec359d7ab1b762ca08b9b5d..4d9b7cc4ca73a2e8f148a514819f6eecd31b6653 100644 (file)
@@ -487,6 +487,11 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
                props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;
        if (MLX5_CAP_GEN(mdev, xrc))
                props->device_cap_flags |= IB_DEVICE_XRC;
+       if (MLX5_CAP_GEN(mdev, imaicl)) {
+               props->device_cap_flags |= IB_DEVICE_MEM_WINDOW |
+                                          IB_DEVICE_MEM_WINDOW_TYPE_2B;
+               props->max_mw = 1 << MLX5_CAP_GEN(mdev, log_max_mkey);
+       }
        props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
        if (MLX5_CAP_GEN(mdev, sho)) {
                props->device_cap_flags |= IB_DEVICE_SIGNATURE_HANDOVER;
@@ -2306,6 +2311,14 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
 
        mlx5_ib_internal_fill_odp_caps(dev);
 
+       if (MLX5_CAP_GEN(mdev, imaicl)) {
+               dev->ib_dev.alloc_mw            = mlx5_ib_alloc_mw;
+               dev->ib_dev.dealloc_mw          = mlx5_ib_dealloc_mw;
+               dev->ib_dev.uverbs_cmd_mask |=
+                       (1ull << IB_USER_VERBS_CMD_ALLOC_MW)    |
+                       (1ull << IB_USER_VERBS_CMD_DEALLOC_MW);
+       }
+
        if (MLX5_CAP_GEN(mdev, xrc)) {
                dev->ib_dev.alloc_xrcd = mlx5_ib_alloc_xrcd;
                dev->ib_dev.dealloc_xrcd = mlx5_ib_dealloc_xrcd;
index 4167d67179ffc2c00748f4680e23a433d7ae8c25..648d2e2e445ba77871af6c06f00c99fe7f22eee1 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/mlx5/srq.h>
 #include <linux/types.h>
 #include <linux/mlx5/transobj.h>
+#include <rdma/ib_user_verbs.h>
 
 #define mlx5_ib_dbg(dev, format, arg...)                               \
 pr_debug("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__,   \
@@ -461,6 +462,11 @@ struct mlx5_ib_mr {
        int                     access_flags; /* Needed for rereg MR */
 };
 
+struct mlx5_ib_mw {
+       struct ib_mw            ibmw;
+       struct mlx5_core_mkey   mmkey;
+};
+
 struct mlx5_ib_umr_context {
        enum ib_wc_status       status;
        struct completion       done;
@@ -633,6 +639,11 @@ static inline struct mlx5_ib_mr *to_mmr(struct ib_mr *ibmr)
        return container_of(ibmr, struct mlx5_ib_mr, ibmr);
 }
 
+static inline struct mlx5_ib_mw *to_mmw(struct ib_mw *ibmw)
+{
+       return container_of(ibmw, struct mlx5_ib_mw, ibmw);
+}
+
 struct mlx5_ib_ah {
        struct ib_ah            ibah;
        struct mlx5_av          av;
@@ -693,6 +704,9 @@ struct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc);
 struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
                                  u64 virt_addr, int access_flags,
                                  struct ib_udata *udata);
+struct ib_mw *mlx5_ib_alloc_mw(struct ib_pd *pd, enum ib_mw_type type,
+                              struct ib_udata *udata);
+int mlx5_ib_dealloc_mw(struct ib_mw *mw);
 int mlx5_ib_update_mtt(struct mlx5_ib_mr *mr, u64 start_page_index,
                       int npages, int zap);
 int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
index 399e2b5fb5736837fe888b767b6814130609cddc..70a047dde69e10575d61cfc98872544d2b1349f7 100644 (file)
@@ -40,6 +40,7 @@
 #include <rdma/ib_umem_odp.h>
 #include <rdma/ib_verbs.h>
 #include "mlx5_ib.h"
+#include "user.h"
 
 enum {
        MAX_PENDING_REG_MR = 8,
@@ -1620,6 +1621,88 @@ err_free:
        return ERR_PTR(err);
 }
 
+struct ib_mw *mlx5_ib_alloc_mw(struct ib_pd *pd, enum ib_mw_type type,
+                              struct ib_udata *udata)
+{
+       struct mlx5_ib_dev *dev = to_mdev(pd->device);
+       struct mlx5_create_mkey_mbox_in *in = NULL;
+       struct mlx5_ib_mw *mw = NULL;
+       int ndescs;
+       int err;
+       struct mlx5_ib_alloc_mw req = {};
+       struct {
+               __u32   comp_mask;
+               __u32   response_length;
+       } resp = {};
+
+       err = ib_copy_from_udata(&req, udata, min(udata->inlen, sizeof(req)));
+       if (err)
+               return ERR_PTR(err);
+
+       if (req.comp_mask || req.reserved1 || req.reserved2)
+               return ERR_PTR(-EOPNOTSUPP);
+
+       if (udata->inlen > sizeof(req) &&
+           !ib_is_udata_cleared(udata, sizeof(req),
+                                udata->inlen - sizeof(req)))
+               return ERR_PTR(-EOPNOTSUPP);
+
+       ndescs = req.num_klms ? roundup(req.num_klms, 4) : roundup(1, 4);
+
+       mw = kzalloc(sizeof(*mw), GFP_KERNEL);
+       in = kzalloc(sizeof(*in), GFP_KERNEL);
+       if (!mw || !in) {
+               err = -ENOMEM;
+               goto free;
+       }
+
+       in->seg.status = MLX5_MKEY_STATUS_FREE;
+       in->seg.xlt_oct_size = cpu_to_be32(ndescs);
+       in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn);
+       in->seg.flags = MLX5_PERM_UMR_EN | MLX5_ACCESS_MODE_KLM |
+               MLX5_PERM_LOCAL_READ;
+       if (type == IB_MW_TYPE_2)
+               in->seg.flags_pd |= cpu_to_be32(MLX5_MKEY_REMOTE_INVAL);
+       in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
+
+       err = mlx5_core_create_mkey(dev->mdev, &mw->mmkey, in, sizeof(*in),
+                                   NULL, NULL, NULL);
+       if (err)
+               goto free;
+
+       mw->ibmw.rkey = mw->mmkey.key;
+
+       resp.response_length = min(offsetof(typeof(resp), response_length) +
+                                  sizeof(resp.response_length), udata->outlen);
+       if (resp.response_length) {
+               err = ib_copy_to_udata(udata, &resp, resp.response_length);
+               if (err) {
+                       mlx5_core_destroy_mkey(dev->mdev, &mw->mmkey);
+                       goto free;
+               }
+       }
+
+       kfree(in);
+       return &mw->ibmw;
+
+free:
+       kfree(mw);
+       kfree(in);
+       return ERR_PTR(err);
+}
+
+int mlx5_ib_dealloc_mw(struct ib_mw *mw)
+{
+       struct mlx5_ib_mw *mmw = to_mmw(mw);
+       int err;
+
+       err =  mlx5_core_destroy_mkey((to_mdev(mw->device))->mdev,
+                                     &mmw->mmkey);
+       if (!err)
+               kfree(mmw);
+       return err;
+}
+
 int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
                            struct ib_mr_status *mr_status)
 {
index b94a55404a596dab323a843dec9a817fddbaff74..61bc308bb802ce93069601e85507849a8f61e98d 100644 (file)
@@ -152,6 +152,13 @@ struct mlx5_ib_create_qp_resp {
        __u32   uuar_index;
 };
 
+struct mlx5_ib_alloc_mw {
+       __u32   comp_mask;
+       __u8    num_klms;
+       __u8    reserved1;
+       __u16   reserved2;
+};
+
 static inline int get_qp_user_index(struct mlx5_ib_ucontext *ucontext,
                                    struct mlx5_ib_create_qp *ucmd,
                                    int inlen,
index 72bba5261766be76c3ba40ae0b44b14f7a691163..3044cfa683f14bef095ad60ceb3a6c3bcdd7aff0 100644 (file)
@@ -769,7 +769,9 @@ struct mlx5_ifc_cmd_hca_cap_bits {
        u8         cd[0x1];
        u8         reserved_at_22c[0x1];
        u8         apm[0x1];
-       u8         reserved_at_22e[0x7];
+       u8         reserved_at_22e[0x2];
+       u8         imaicl[0x1];
+       u8         reserved_at_231[0x4];
        u8         qkv[0x1];
        u8         pkv[0x1];
        u8         set_deth_sqpn[0x1];