root/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlx5_dm_create
  2. mlx5_dm_cleanup
  3. mlx5_dm_sw_icm_alloc
  4. mlx5_dm_sw_icm_dealloc

   1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
   2 // Copyright (c) 2019 Mellanox Technologies
   3 
   4 #include <linux/mlx5/driver.h>
   5 #include <linux/mlx5/device.h>
   6 
   7 #include "mlx5_core.h"
   8 #include "lib/mlx5.h"
   9 
  10 struct mlx5_dm {
  11         /* protect access to icm bitmask */
  12         spinlock_t lock;
  13         unsigned long *steering_sw_icm_alloc_blocks;
  14         unsigned long *header_modify_sw_icm_alloc_blocks;
  15 };
  16 
  17 struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
  18 {
  19         u64 header_modify_icm_blocks = 0;
  20         u64 steering_icm_blocks = 0;
  21         struct mlx5_dm *dm;
  22 
  23         if (!(MLX5_CAP_GEN_64(dev, general_obj_types) & MLX5_GENERAL_OBJ_TYPES_CAP_SW_ICM))
  24                 return 0;
  25 
  26         dm = kzalloc(sizeof(*dm), GFP_KERNEL);
  27         if (!dm)
  28                 return ERR_PTR(-ENOMEM);
  29 
  30         spin_lock_init(&dm->lock);
  31 
  32         if (MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address)) {
  33                 steering_icm_blocks =
  34                         BIT(MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size) -
  35                             MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
  36 
  37                 dm->steering_sw_icm_alloc_blocks =
  38                         kcalloc(BITS_TO_LONGS(steering_icm_blocks),
  39                                 sizeof(unsigned long), GFP_KERNEL);
  40                 if (!dm->steering_sw_icm_alloc_blocks)
  41                         goto err_steering;
  42         }
  43 
  44         if (MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address)) {
  45                 header_modify_icm_blocks =
  46                         BIT(MLX5_CAP_DEV_MEM(dev, log_header_modify_sw_icm_size) -
  47                             MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
  48 
  49                 dm->header_modify_sw_icm_alloc_blocks =
  50                         kcalloc(BITS_TO_LONGS(header_modify_icm_blocks),
  51                                 sizeof(unsigned long), GFP_KERNEL);
  52                 if (!dm->header_modify_sw_icm_alloc_blocks)
  53                         goto err_modify_hdr;
  54         }
  55 
  56         return dm;
  57 
  58 err_modify_hdr:
  59         kfree(dm->steering_sw_icm_alloc_blocks);
  60 
  61 err_steering:
  62         kfree(dm);
  63 
  64         return ERR_PTR(-ENOMEM);
  65 }
  66 
  67 void mlx5_dm_cleanup(struct mlx5_core_dev *dev)
  68 {
  69         struct mlx5_dm *dm = dev->dm;
  70 
  71         if (!dev->dm)
  72                 return;
  73 
  74         if (dm->steering_sw_icm_alloc_blocks) {
  75                 WARN_ON(!bitmap_empty(dm->steering_sw_icm_alloc_blocks,
  76                                       BIT(MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size) -
  77                                           MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
  78                 kfree(dm->steering_sw_icm_alloc_blocks);
  79         }
  80 
  81         if (dm->header_modify_sw_icm_alloc_blocks) {
  82                 WARN_ON(!bitmap_empty(dm->header_modify_sw_icm_alloc_blocks,
  83                                       BIT(MLX5_CAP_DEV_MEM(dev,
  84                                                            log_header_modify_sw_icm_size) -
  85                                       MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
  86                 kfree(dm->header_modify_sw_icm_alloc_blocks);
  87         }
  88 
  89         kfree(dm);
  90 }
  91 
  92 int mlx5_dm_sw_icm_alloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
  93                          u64 length, u16 uid, phys_addr_t *addr, u32 *obj_id)
  94 {
  95         u32 num_blocks = DIV_ROUND_UP_ULL(length, MLX5_SW_ICM_BLOCK_SIZE(dev));
  96         u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
  97         u32 in[MLX5_ST_SZ_DW(create_sw_icm_in)] = {};
  98         struct mlx5_dm *dm = dev->dm;
  99         unsigned long *block_map;
 100         u64 icm_start_addr;
 101         u32 log_icm_size;
 102         u32 max_blocks;
 103         u64 block_idx;
 104         void *sw_icm;
 105         int ret;
 106 
 107         if (!dev->dm)
 108                 return -EOPNOTSUPP;
 109 
 110         if (!length || (length & (length - 1)) ||
 111             length & (MLX5_SW_ICM_BLOCK_SIZE(dev) - 1))
 112                 return -EINVAL;
 113 
 114         MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
 115                  MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
 116         MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM);
 117         MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid);
 118 
 119         switch (type) {
 120         case MLX5_SW_ICM_TYPE_STEERING:
 121                 icm_start_addr = MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address);
 122                 log_icm_size = MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size);
 123                 block_map = dm->steering_sw_icm_alloc_blocks;
 124                 break;
 125         case MLX5_SW_ICM_TYPE_HEADER_MODIFY:
 126                 icm_start_addr = MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address);
 127                 log_icm_size = MLX5_CAP_DEV_MEM(dev,
 128                                                 log_header_modify_sw_icm_size);
 129                 block_map = dm->header_modify_sw_icm_alloc_blocks;
 130                 break;
 131         default:
 132                 return -EINVAL;
 133         }
 134 
 135         if (!block_map)
 136                 return -EOPNOTSUPP;
 137 
 138         max_blocks = BIT(log_icm_size - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
 139         spin_lock(&dm->lock);
 140         block_idx = bitmap_find_next_zero_area(block_map,
 141                                                max_blocks,
 142                                                0,
 143                                                num_blocks, 0);
 144 
 145         if (block_idx < max_blocks)
 146                 bitmap_set(block_map,
 147                            block_idx, num_blocks);
 148 
 149         spin_unlock(&dm->lock);
 150 
 151         if (block_idx >= max_blocks)
 152                 return -ENOMEM;
 153 
 154         sw_icm = MLX5_ADDR_OF(create_sw_icm_in, in, sw_icm);
 155         icm_start_addr += block_idx << MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
 156         MLX5_SET64(sw_icm, sw_icm, sw_icm_start_addr,
 157                    icm_start_addr);
 158         MLX5_SET(sw_icm, sw_icm, log_sw_icm_size, ilog2(length));
 159 
 160         ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
 161         if (ret) {
 162                 spin_lock(&dm->lock);
 163                 bitmap_clear(block_map,
 164                              block_idx, num_blocks);
 165                 spin_unlock(&dm->lock);
 166 
 167                 return ret;
 168         }
 169 
 170         *addr = icm_start_addr;
 171         *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
 172 
 173         return 0;
 174 }
 175 EXPORT_SYMBOL_GPL(mlx5_dm_sw_icm_alloc);
 176 
 177 int mlx5_dm_sw_icm_dealloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
 178                            u64 length, u16 uid, phys_addr_t addr, u32 obj_id)
 179 {
 180         u32 num_blocks = DIV_ROUND_UP_ULL(length, MLX5_SW_ICM_BLOCK_SIZE(dev));
 181         u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
 182         u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
 183         struct mlx5_dm *dm = dev->dm;
 184         unsigned long *block_map;
 185         u64 icm_start_addr;
 186         u64 start_idx;
 187         int err;
 188 
 189         if (!dev->dm)
 190                 return -EOPNOTSUPP;
 191 
 192         switch (type) {
 193         case MLX5_SW_ICM_TYPE_STEERING:
 194                 icm_start_addr = MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address);
 195                 block_map = dm->steering_sw_icm_alloc_blocks;
 196                 break;
 197         case MLX5_SW_ICM_TYPE_HEADER_MODIFY:
 198                 icm_start_addr = MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address);
 199                 block_map = dm->header_modify_sw_icm_alloc_blocks;
 200                 break;
 201         default:
 202                 return -EINVAL;
 203         }
 204 
 205         MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
 206                  MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
 207         MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM);
 208         MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id);
 209         MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid);
 210 
 211         err =  mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
 212         if (err)
 213                 return err;
 214 
 215         start_idx = (addr - icm_start_addr) >> MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
 216         spin_lock(&dm->lock);
 217         bitmap_clear(block_map,
 218                      start_idx, num_blocks);
 219         spin_unlock(&dm->lock);
 220 
 221         return 0;
 222 }
 223 EXPORT_SYMBOL_GPL(mlx5_dm_sw_icm_dealloc);

/* [<][>][^][v][top][bottom][index][help] */