IB/mlx5: Extend UAR stuff to support dynamic allocation
[linux-2.6-block.git] / drivers / infiniband / hw / mlx5 / main.c
index fb38da571f402ba61d16ac7d069481bcf39febcc..b894bc5be384a6777eda8207cd6fa2640aa6e66c 100644 (file)
@@ -1240,9 +1240,18 @@ static void print_lib_caps(struct mlx5_ib_dev *dev, u64 caps)
                    caps & MLX5_LIB_CAP_4K_UAR ? "y" : "n");
 }
 
+static u16 calc_dynamic_bfregs(int uars_per_sys_page)
+{
+       /* Large page with non 4k uar support might limit the dynamic size */
+       if (uars_per_sys_page == 1  && PAGE_SIZE > 4096)
+               return MLX5_MIN_DYN_BFREGS;
+
+       return MLX5_MAX_DYN_BFREGS;
+}
+
 static int calc_total_bfregs(struct mlx5_ib_dev *dev, bool lib_uar_4k,
                             struct mlx5_ib_alloc_ucontext_req_v2 *req,
-                            u32 *num_sys_pages)
+                            struct mlx5_bfreg_info *bfregi)
 {
        int uars_per_sys_page;
        int bfregs_per_sys_page;
@@ -1259,16 +1268,21 @@ static int calc_total_bfregs(struct mlx5_ib_dev *dev, bool lib_uar_4k,
 
        uars_per_sys_page = get_uars_per_sys_page(dev, lib_uar_4k);
        bfregs_per_sys_page = uars_per_sys_page * MLX5_NON_FP_BFREGS_PER_UAR;
+       /* This holds the required static allocation asked by the user */
        req->total_num_bfregs = ALIGN(req->total_num_bfregs, bfregs_per_sys_page);
-       *num_sys_pages = req->total_num_bfregs / bfregs_per_sys_page;
-
        if (req->num_low_latency_bfregs > req->total_num_bfregs - 1)
                return -EINVAL;
 
-       mlx5_ib_dbg(dev, "uar_4k: fw support %s, lib support %s, user requested %d bfregs, allocated %d, using %d sys pages\n",
+       bfregi->num_static_sys_pages = req->total_num_bfregs / bfregs_per_sys_page;
+       bfregi->num_dyn_bfregs = ALIGN(calc_dynamic_bfregs(uars_per_sys_page), bfregs_per_sys_page);
+       bfregi->total_num_bfregs = req->total_num_bfregs + bfregi->num_dyn_bfregs;
+       bfregi->num_sys_pages = bfregi->total_num_bfregs / bfregs_per_sys_page;
+
+       mlx5_ib_dbg(dev, "uar_4k: fw support %s, lib support %s, user requested %d bfregs, allocated %d, total bfregs %d, using %d sys pages\n",
                    MLX5_CAP_GEN(dev->mdev, uar_4k) ? "yes" : "no",
                    lib_uar_4k ? "yes" : "no", ref_bfregs,
-                   req->total_num_bfregs, *num_sys_pages);
+                   req->total_num_bfregs, bfregi->total_num_bfregs,
+                   bfregi->num_sys_pages);
 
        return 0;
 }
@@ -1280,7 +1294,7 @@ static int allocate_uars(struct mlx5_ib_dev *dev, struct mlx5_ib_ucontext *conte
        int i;
 
        bfregi = &context->bfregi;
-       for (i = 0; i < bfregi->num_sys_pages; i++) {
+       for (i = 0; i < bfregi->num_static_sys_pages; i++) {
                err = mlx5_cmd_alloc_uar(dev->mdev, &bfregi->sys_pages[i]);
                if (err)
                        goto error;
@@ -1304,7 +1318,7 @@ static int deallocate_uars(struct mlx5_ib_dev *dev, struct mlx5_ib_ucontext *con
        int i;
 
        bfregi = &context->bfregi;
-       for (i = 0; i < bfregi->num_sys_pages; i++) {
+       for (i = 0; i < bfregi->num_static_sys_pages; i++) {
                err = mlx5_cmd_free_uar(dev->mdev, bfregi->sys_pages[i]);
                if (err) {
                        mlx5_ib_warn(dev, "failed to free uar %d\n", i);
@@ -1419,13 +1433,13 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
        bfregi = &context->bfregi;
 
        /* updates req->total_num_bfregs */
-       err = calc_total_bfregs(dev, lib_uar_4k, &req, &bfregi->num_sys_pages);
+       err = calc_total_bfregs(dev, lib_uar_4k, &req, bfregi);
        if (err)
                goto out_ctx;
 
        mutex_init(&bfregi->lock);
        bfregi->lib_uar_4k = lib_uar_4k;
-       bfregi->count = kcalloc(req.total_num_bfregs, sizeof(*bfregi->count),
+       bfregi->count = kcalloc(bfregi->total_num_bfregs, sizeof(*bfregi->count),
                                GFP_KERNEL);
        if (!bfregi->count) {
                err = -ENOMEM;
@@ -1509,6 +1523,11 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
        if (field_avail(typeof(resp), num_uars_per_page, udata->outlen))
                resp.response_length += sizeof(resp.num_uars_per_page);
 
+       if (field_avail(typeof(resp), num_dyn_bfregs, udata->outlen)) {
+               resp.num_dyn_bfregs = bfregi->num_dyn_bfregs;
+               resp.response_length += sizeof(resp.num_dyn_bfregs);
+       }
+
        err = ib_copy_to_udata(udata, &resp, resp.response_length);
        if (err)
                goto out_td;