IB/mlx5: Changes in memory region creation to support on-demand paging
[deliverable/linux.git] / drivers / infiniband / hw / mlx5 / mr.c
index 8ee7cb46e0590668bd79277bc672a9d41f90f02d..49fc3ca735a4de957ac173ce653367522d5f83cd 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/export.h>
 #include <linux/delay.h>
 #include <rdma/ib_umem.h>
+#include <rdma/ib_verbs.h>
 #include "mlx5_ib.h"
 
 enum {
@@ -47,13 +48,6 @@ enum {
        MLX5_UMR_ALIGN  = 2048
 };
 
-static __be64 *mr_align(__be64 *ptr, int align)
-{
-       unsigned long mask = align - 1;
-
-       return (__be64 *)(((unsigned long)ptr + mask) & ~mask);
-}
-
 static int order2idx(struct mlx5_ib_dev *dev, int order)
 {
        struct mlx5_mr_cache *cache = &dev->cache;
@@ -146,7 +140,7 @@ static int add_keys(struct mlx5_ib_dev *dev, int c, int num)
                mr->order = ent->order;
                mr->umred = 1;
                mr->dev = dev;
-               in->seg.status = 1 << 6;
+               in->seg.status = MLX5_MKEY_STATUS_FREE;
                in->seg.xlt_oct_size = cpu_to_be32((npages + 1) / 2);
                in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
                in->seg.flags = MLX5_ACCESS_MODE_MTT | MLX5_PERM_UMR_EN;
@@ -159,6 +153,9 @@ static int add_keys(struct mlx5_ib_dev *dev, int c, int num)
                                            sizeof(*in), reg_mr_callback,
                                            mr, &mr->out);
                if (err) {
+                       spin_lock_irq(&ent->lock);
+                       ent->pending--;
+                       spin_unlock_irq(&ent->lock);
                        mlx5_ib_warn(dev, "create mkey failed %d\n", err);
                        kfree(mr);
                        break;
@@ -665,7 +662,7 @@ static int get_octo_len(u64 addr, u64 len, int page_size)
 
 static int use_umr(int order)
 {
-       return order <= 17;
+       return order <= MLX5_MAX_UMR_SHIFT;
 }
 
 static void prep_umr_reg_wqe(struct ib_pd *pd, struct ib_send_wr *wr,
@@ -675,6 +672,7 @@ static void prep_umr_reg_wqe(struct ib_pd *pd, struct ib_send_wr *wr,
 {
        struct mlx5_ib_dev *dev = to_mdev(pd->device);
        struct ib_mr *mr = dev->umrc.mr;
+       struct mlx5_umr_wr *umrwr = (struct mlx5_umr_wr *)&wr->wr.fast_reg;
 
        sg->addr = dma;
        sg->length = ALIGN(sizeof(u64) * n, 64);
@@ -689,21 +687,24 @@ static void prep_umr_reg_wqe(struct ib_pd *pd, struct ib_send_wr *wr,
                wr->num_sge = 0;
 
        wr->opcode = MLX5_IB_WR_UMR;
-       wr->wr.fast_reg.page_list_len = n;
-       wr->wr.fast_reg.page_shift = page_shift;
-       wr->wr.fast_reg.rkey = key;
-       wr->wr.fast_reg.iova_start = virt_addr;
-       wr->wr.fast_reg.length = len;
-       wr->wr.fast_reg.access_flags = access_flags;
-       wr->wr.fast_reg.page_list = (struct ib_fast_reg_page_list *)pd;
+
+       umrwr->npages = n;
+       umrwr->page_shift = page_shift;
+       umrwr->mkey = key;
+       umrwr->target.virt_addr = virt_addr;
+       umrwr->length = len;
+       umrwr->access_flags = access_flags;
+       umrwr->pd = pd;
 }
 
 static void prep_umr_unreg_wqe(struct mlx5_ib_dev *dev,
                               struct ib_send_wr *wr, u32 key)
 {
-       wr->send_flags = MLX5_IB_SEND_UMR_UNREG;
+       struct mlx5_umr_wr *umrwr = (struct mlx5_umr_wr *)&wr->wr.fast_reg;
+
+       wr->send_flags = MLX5_IB_SEND_UMR_UNREG | MLX5_IB_SEND_UMR_FAIL_IF_FREE;
        wr->opcode = MLX5_IB_WR_UMR;
-       wr->wr.fast_reg.rkey = key;
+       umrwr->mkey = key;
 }
 
 void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context)
@@ -739,7 +740,10 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
        struct ib_send_wr wr, *bad;
        struct mlx5_ib_mr *mr;
        struct ib_sge sg;
-       int size = sizeof(u64) * npages;
+       int size;
+       __be64 *mr_pas;
+       __be64 *pas;
+       dma_addr_t dma;
        int err = 0;
        int i;
 
@@ -758,25 +762,31 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
        if (!mr)
                return ERR_PTR(-EAGAIN);
 
-       mr->pas = kmalloc(size + MLX5_UMR_ALIGN - 1, GFP_KERNEL);
-       if (!mr->pas) {
+       /* UMR copies MTTs in units of MLX5_UMR_MTT_ALIGNMENT bytes.
+        * To avoid copying garbage after the pas array, we allocate
+        * a little more. */
+       size = ALIGN(sizeof(u64) * npages, MLX5_UMR_MTT_ALIGNMENT);
+       mr_pas = kmalloc(size + MLX5_UMR_ALIGN - 1, GFP_KERNEL);
+       if (!mr_pas) {
                err = -ENOMEM;
                goto free_mr;
        }
 
-       mlx5_ib_populate_pas(dev, umem, page_shift,
-                            mr_align(mr->pas, MLX5_UMR_ALIGN), 1);
+       pas = PTR_ALIGN(mr_pas, MLX5_UMR_ALIGN);
+       mlx5_ib_populate_pas(dev, umem, page_shift, pas, MLX5_IB_MTT_PRESENT);
+       /* Clear padding after the actual pages. */
+       memset(pas + npages, 0, size - npages * sizeof(u64));
 
-       mr->dma = dma_map_single(ddev, mr_align(mr->pas, MLX5_UMR_ALIGN), size,
-                                DMA_TO_DEVICE);
-       if (dma_mapping_error(ddev, mr->dma)) {
+       dma = dma_map_single(ddev, pas, size, DMA_TO_DEVICE);
+       if (dma_mapping_error(ddev, dma)) {
                err = -ENOMEM;
                goto free_pas;
        }
 
        memset(&wr, 0, sizeof(wr));
        wr.wr_id = (u64)(unsigned long)&umr_context;
-       prep_umr_reg_wqe(pd, &wr, &sg, mr->dma, npages, mr->mmr.key, page_shift, virt_addr, len, access_flags);
+       prep_umr_reg_wqe(pd, &wr, &sg, dma, npages, mr->mmr.key, page_shift,
+                        virt_addr, len, access_flags);
 
        mlx5_ib_init_umr_context(&umr_context);
        down(&umrc->sem);
@@ -798,10 +808,10 @@ static struct mlx5_ib_mr *reg_umr(struct ib_pd *pd, struct ib_umem *umem,
 
 unmap_dma:
        up(&umrc->sem);
-       dma_unmap_single(ddev, mr->dma, size, DMA_TO_DEVICE);
+       dma_unmap_single(ddev, dma, size, DMA_TO_DEVICE);
 
 free_pas:
-       kfree(mr->pas);
+       kfree(mr_pas);
 
 free_mr:
        if (err) {
@@ -822,6 +832,8 @@ static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr,
        struct mlx5_ib_mr *mr;
        int inlen;
        int err;
+       bool pg_cap = !!(dev->mdev->caps.gen.flags &
+                        MLX5_DEV_CAP_FLAG_ON_DMND_PG);
 
        mr = kzalloc(sizeof(*mr), GFP_KERNEL);
        if (!mr)
@@ -833,8 +845,12 @@ static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr,
                err = -ENOMEM;
                goto err_1;
        }
-       mlx5_ib_populate_pas(dev, umem, page_shift, in->pas, 0);
+       mlx5_ib_populate_pas(dev, umem, page_shift, in->pas,
+                            pg_cap ? MLX5_IB_MTT_PRESENT : 0);
 
+       /* The MLX5_MKEY_INBOX_PG_ACCESS bit allows setting the access flags
+        * in the page list submitted with the command. */
+       in->flags = pg_cap ? cpu_to_be32(MLX5_MKEY_INBOX_PG_ACCESS) : 0;
        in->seg.flags = convert_access(access_flags) |
                MLX5_ACCESS_MODE_MTT;
        in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn);
@@ -853,14 +869,14 @@ static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr,
                goto err_2;
        }
        mr->umem = umem;
-       mlx5_vfree(in);
+       kvfree(in);
 
        mlx5_ib_dbg(dev, "mkey = 0x%x\n", mr->mmr.key);
 
        return mr;
 
 err_2:
-       mlx5_vfree(in);
+       kvfree(in);
 
 err_1:
        kfree(mr);
@@ -1025,7 +1041,7 @@ struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd,
                goto err_free;
        }
 
-       in->seg.status = 1 << 6; /* free */
+       in->seg.status = MLX5_MKEY_STATUS_FREE;
        in->seg.xlt_oct_size = cpu_to_be32(ndescs);
        in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
        in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn);
@@ -1140,7 +1156,7 @@ struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd,
                goto err_free;
        }
 
-       in->seg.status = 1 << 6; /* free */
+       in->seg.status = MLX5_MKEY_STATUS_FREE;
        in->seg.xlt_oct_size = cpu_to_be32((max_page_list_len + 1) / 2);
        in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
        in->seg.flags = MLX5_PERM_UMR_EN | MLX5_ACCESS_MODE_MTT;
This page took 0.044213 seconds and 5 git commands to generate.