net/mlx5: Add interface to get reference to a UAR
authorEli Cohen <eli@mellanox.com>
Tue, 3 Jan 2017 21:55:24 +0000 (23:55 +0200)
committerSaeed Mahameed <saeedm@mellanox.com>
Mon, 9 Jan 2017 18:24:55 +0000 (20:24 +0200)
A reference to a UAR is required to generate CQ or EQ doorbells. Since
CQ or EQ doorbells can all be generated using the same UAR area without
any effect on performance, we are just getting a reference to any
available UAR, If one is not available we allocate it but we don't waste
the blue flame registers it can provide and we will use them for
subsequent allocations.
We get a reference to such UAR and put in mlx5_priv so any kernel
consumer can make use of it.

Signed-off-by: Eli Cohen <eli@mellanox.com>
Reviewed-by: Matan Barak <matanb@mellanox.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/eq.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/uar.c
include/linux/mlx5/driver.h

index 11a8d638bcd0ba1b8c8f4e0c7b9961fb604eb39f..5130d65dd41a8b5a786a7fc5e168a91c7b08796e 100644 (file)
@@ -512,7 +512,7 @@ static void init_eq_buf(struct mlx5_eq *eq)
 
 int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
                       int nent, u64 mask, const char *name,
-                      struct mlx5_uar *uar, enum mlx5_eq_type type)
+                      enum mlx5_eq_type type)
 {
        u32 out[MLX5_ST_SZ_DW(create_eq_out)] = {0};
        struct mlx5_priv *priv = &dev->priv;
@@ -556,7 +556,7 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
 
        eqc = MLX5_ADDR_OF(create_eq_in, in, eq_context_entry);
        MLX5_SET(eqc, eqc, log_eq_size, ilog2(eq->nent));
-       MLX5_SET(eqc, eqc, uar_page, uar->index);
+       MLX5_SET(eqc, eqc, uar_page, priv->uar->index);
        MLX5_SET(eqc, eqc, intr, vecidx);
        MLX5_SET(eqc, eqc, log_page_size,
                 eq->buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT);
@@ -571,7 +571,7 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
        eq->eqn = MLX5_GET(create_eq_out, out, eq_number);
        eq->irqn = priv->msix_arr[vecidx].vector;
        eq->dev = dev;
-       eq->doorbell = uar->map + MLX5_EQ_DOORBEL_OFFSET;
+       eq->doorbell = priv->uar->map + MLX5_EQ_DOORBEL_OFFSET;
        err = request_irq(eq->irqn, handler, 0,
                          priv->irq_info[vecidx].name, eq);
        if (err)
@@ -686,8 +686,7 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev)
 
        err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD,
                                 MLX5_NUM_CMD_EQE, 1ull << MLX5_EVENT_TYPE_CMD,
-                                "mlx5_cmd_eq", &dev->priv.bfregi.uars[0],
-                                MLX5_EQ_TYPE_ASYNC);
+                                "mlx5_cmd_eq", MLX5_EQ_TYPE_ASYNC);
        if (err) {
                mlx5_core_warn(dev, "failed to create cmd EQ %d\n", err);
                return err;
@@ -697,8 +696,7 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev)
 
        err = mlx5_create_map_eq(dev, &table->async_eq, MLX5_EQ_VEC_ASYNC,
                                 MLX5_NUM_ASYNC_EQE, async_event_mask,
-                                "mlx5_async_eq", &dev->priv.bfregi.uars[0],
-                                MLX5_EQ_TYPE_ASYNC);
+                                "mlx5_async_eq", MLX5_EQ_TYPE_ASYNC);
        if (err) {
                mlx5_core_warn(dev, "failed to create async EQ %d\n", err);
                goto err1;
@@ -708,7 +706,6 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev)
                                 MLX5_EQ_VEC_PAGES,
                                 /* TODO: sriov max_vf + */ 1,
                                 1 << MLX5_EVENT_TYPE_PAGE_REQUEST, "mlx5_pages_eq",
-                                &dev->priv.bfregi.uars[0],
                                 MLX5_EQ_TYPE_ASYNC);
        if (err) {
                mlx5_core_warn(dev, "failed to create pages EQ %d\n", err);
@@ -722,7 +719,6 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev)
                                         MLX5_NUM_ASYNC_EQE,
                                         1 << MLX5_EVENT_TYPE_PAGE_FAULT,
                                         "mlx5_page_fault_eq",
-                                        &dev->priv.bfregi.uars[0],
                                         MLX5_EQ_TYPE_PF);
                if (err) {
                        mlx5_core_warn(dev, "failed to create page fault EQ %d\n",
index 634e96a025169aee13e4326eabf0c92e177edac1..2882d0483ed87b74cad22fb097d0ed2ff6742229 100644 (file)
@@ -753,8 +753,7 @@ static int alloc_comp_eqs(struct mlx5_core_dev *dev)
                snprintf(name, MLX5_MAX_IRQ_NAME, "mlx5_comp%d", i);
                err = mlx5_create_map_eq(dev, eq,
                                         i + MLX5_EQ_VEC_COMP_BASE, nent, 0,
-                                        name, &dev->priv.bfregi.uars[0],
-                                        MLX5_EQ_TYPE_COMP);
+                                        name, MLX5_EQ_TYPE_COMP);
                if (err) {
                        kfree(eq);
                        goto clean;
@@ -1094,12 +1093,18 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
                goto err_cleanup_once;
        }
 
-       err = mlx5_alloc_bfregs(dev, &priv->bfregi);
-       if (err) {
+       dev->priv.uar = mlx5_get_uars_page(dev);
+       if (!dev->priv.uar) {
                dev_err(&pdev->dev, "Failed allocating uar, aborting\n");
                goto err_disable_msix;
        }
 
+       err = mlx5_alloc_bfregs(dev, &priv->bfregi);
+       if (err) {
+               dev_err(&pdev->dev, "Failed allocating uuars, aborting\n");
+               goto err_uar_cleanup;
+       }
+
        err = mlx5_start_eqs(dev);
        if (err) {
                dev_err(&pdev->dev, "Failed to start pages and async EQs\n");
@@ -1172,6 +1177,9 @@ err_stop_eqs:
 err_free_uar:
        mlx5_free_bfregs(dev, &priv->bfregi);
 
+err_uar_cleanup:
+       mlx5_put_uars_page(dev, priv->uar);
+
 err_disable_msix:
        mlx5_disable_msix(dev);
 
@@ -1231,6 +1239,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
        free_comp_eqs(dev);
        mlx5_stop_eqs(dev);
        mlx5_free_bfregs(dev, &priv->bfregi);
+       mlx5_put_uars_page(dev, priv->uar);
        mlx5_disable_msix(dev);
        if (cleanup)
                mlx5_cleanup_once(dev);
@@ -1305,6 +1314,11 @@ static int init_one(struct pci_dev *pdev,
                goto clean_dev;
        }
 #endif
+       mutex_init(&priv->bfregs.reg_head.lock);
+       mutex_init(&priv->bfregs.wc_head.lock);
+       INIT_LIST_HEAD(&priv->bfregs.reg_head.list);
+       INIT_LIST_HEAD(&priv->bfregs.wc_head.list);
+
        err = mlx5_pci_init(dev, priv);
        if (err) {
                dev_err(&pdev->dev, "mlx5_pci_init failed with error code %d\n", err);
index 6a081a8787a7322c2e3013f9c1d82924b8c10dd3..fcc0270ea72f804826230940aa243f633ccbb6a6 100644 (file)
@@ -332,6 +332,38 @@ error1:
        return ERR_PTR(err);
 }
 
+struct mlx5_uars_page *mlx5_get_uars_page(struct mlx5_core_dev *mdev)
+{
+       struct mlx5_uars_page *ret;
+
+       mutex_lock(&mdev->priv.bfregs.reg_head.lock);
+       if (list_empty(&mdev->priv.bfregs.reg_head.list)) {
+               ret = alloc_uars_page(mdev, false);
+               if (IS_ERR(ret)) {
+                       ret = NULL;
+                       goto out;
+               }
+               list_add(&ret->list, &mdev->priv.bfregs.reg_head.list);
+       } else {
+               ret = list_first_entry(&mdev->priv.bfregs.reg_head.list,
+                                      struct mlx5_uars_page, list);
+               kref_get(&ret->ref_count);
+       }
+out:
+       mutex_unlock(&mdev->priv.bfregs.reg_head.lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(mlx5_get_uars_page);
+
+void mlx5_put_uars_page(struct mlx5_core_dev *mdev, struct mlx5_uars_page *up)
+{
+       mutex_lock(&mdev->priv.bfregs.reg_head.lock);
+       kref_put(&up->ref_count, up_rel_func);
+       mutex_unlock(&mdev->priv.bfregs.reg_head.lock);
+}
+EXPORT_SYMBOL(mlx5_put_uars_page);
+
 static unsigned long map_offset(struct mlx5_core_dev *mdev, int dbi)
 {
        /* return the offset in bytes from the start of the page to the
index 969aa1fe17e2395b9a8d4cef5052884a4ac11b32..9a3a0954855b87af505b8de0e0aa729036d34c4f 100644 (file)
@@ -679,6 +679,7 @@ struct mlx5_priv {
        struct srcu_struct      pfault_srcu;
 #endif
        struct mlx5_bfreg_data          bfregs;
+       struct mlx5_uars_page          *uar;
 };
 
 enum mlx5_device_state {
@@ -1007,7 +1008,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec);
 void mlx5_cq_event(struct mlx5_core_dev *dev, u32 cqn, int event_type);
 int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx,
                       int nent, u64 mask, const char *name,
-                      struct mlx5_uar *uar, enum mlx5_eq_type type);
+                      enum mlx5_eq_type type);
 int mlx5_destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq);
 int mlx5_start_eqs(struct mlx5_core_dev *dev);
 int mlx5_stop_eqs(struct mlx5_core_dev *dev);
@@ -1118,6 +1119,8 @@ int mlx5_cmd_create_vport_lag(struct mlx5_core_dev *dev);
 int mlx5_cmd_destroy_vport_lag(struct mlx5_core_dev *dev);
 bool mlx5_lag_is_active(struct mlx5_core_dev *dev);
 struct net_device *mlx5_lag_get_roce_netdev(struct mlx5_core_dev *dev);
+struct mlx5_uars_page *mlx5_get_uars_page(struct mlx5_core_dev *mdev);
+void mlx5_put_uars_page(struct mlx5_core_dev *mdev, struct mlx5_uars_page *up);
 
 struct mlx5_profile {
        u64     mask;