dm.c (6316B)
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 10struct 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 17struct 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 NULL; 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 58err_modify_hdr: 59 kfree(dm->steering_sw_icm_alloc_blocks); 60 61err_steering: 62 kfree(dm); 63 64 return ERR_PTR(-ENOMEM); 65} 66 67void 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 92int mlx5_dm_sw_icm_alloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type, 93 u64 length, u32 log_alignment, u16 uid, 94 phys_addr_t *addr, u32 *obj_id) 95{ 96 u32 num_blocks = DIV_ROUND_UP_ULL(length, MLX5_SW_ICM_BLOCK_SIZE(dev)); 97 u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {}; 98 u32 in[MLX5_ST_SZ_DW(create_sw_icm_in)] = {}; 99 struct mlx5_dm *dm = dev->dm; 100 unsigned long *block_map; 101 u64 icm_start_addr; 102 u32 log_icm_size; 103 u64 align_mask; 104 u32 max_blocks; 105 u64 block_idx; 106 void *sw_icm; 107 int ret; 108 109 if (!dev->dm) 110 return -EOPNOTSUPP; 111 112 if (!length || (length & (length - 1)) || 113 length & (MLX5_SW_ICM_BLOCK_SIZE(dev) - 1)) 114 return -EINVAL; 115 116 MLX5_SET(general_obj_in_cmd_hdr, in, opcode, 117 MLX5_CMD_OP_CREATE_GENERAL_OBJECT); 118 MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM); 119 MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid); 120 121 switch (type) { 122 case MLX5_SW_ICM_TYPE_STEERING: 123 icm_start_addr = MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address); 124 log_icm_size = MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size); 125 block_map = dm->steering_sw_icm_alloc_blocks; 126 break; 127 case MLX5_SW_ICM_TYPE_HEADER_MODIFY: 128 icm_start_addr = MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address); 129 log_icm_size = MLX5_CAP_DEV_MEM(dev, 130 log_header_modify_sw_icm_size); 131 block_map = dm->header_modify_sw_icm_alloc_blocks; 132 break; 133 default: 134 return -EINVAL; 135 } 136 137 if (!block_map) 138 return -EOPNOTSUPP; 139 140 max_blocks = BIT(log_icm_size - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev)); 141 142 if (log_alignment < MLX5_LOG_SW_ICM_BLOCK_SIZE(dev)) 143 log_alignment = MLX5_LOG_SW_ICM_BLOCK_SIZE(dev); 144 align_mask = BIT(log_alignment - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev)) - 1; 145 146 spin_lock(&dm->lock); 147 block_idx = bitmap_find_next_zero_area(block_map, max_blocks, 0, 148 num_blocks, align_mask); 149 150 if (block_idx < max_blocks) 151 bitmap_set(block_map, 152 block_idx, num_blocks); 153 154 spin_unlock(&dm->lock); 155 156 if (block_idx >= max_blocks) 157 return -ENOMEM; 158 159 sw_icm = MLX5_ADDR_OF(create_sw_icm_in, in, sw_icm); 160 icm_start_addr += block_idx << MLX5_LOG_SW_ICM_BLOCK_SIZE(dev); 161 MLX5_SET64(sw_icm, sw_icm, sw_icm_start_addr, 162 icm_start_addr); 163 MLX5_SET(sw_icm, sw_icm, log_sw_icm_size, ilog2(length)); 164 165 ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 166 if (ret) { 167 spin_lock(&dm->lock); 168 bitmap_clear(block_map, 169 block_idx, num_blocks); 170 spin_unlock(&dm->lock); 171 172 return ret; 173 } 174 175 *addr = icm_start_addr; 176 *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); 177 178 return 0; 179} 180EXPORT_SYMBOL_GPL(mlx5_dm_sw_icm_alloc); 181 182int mlx5_dm_sw_icm_dealloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type, 183 u64 length, u16 uid, phys_addr_t addr, u32 obj_id) 184{ 185 u32 num_blocks = DIV_ROUND_UP_ULL(length, MLX5_SW_ICM_BLOCK_SIZE(dev)); 186 u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {}; 187 u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; 188 struct mlx5_dm *dm = dev->dm; 189 unsigned long *block_map; 190 u64 icm_start_addr; 191 u64 start_idx; 192 int err; 193 194 if (!dev->dm) 195 return -EOPNOTSUPP; 196 197 switch (type) { 198 case MLX5_SW_ICM_TYPE_STEERING: 199 icm_start_addr = MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address); 200 block_map = dm->steering_sw_icm_alloc_blocks; 201 break; 202 case MLX5_SW_ICM_TYPE_HEADER_MODIFY: 203 icm_start_addr = MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address); 204 block_map = dm->header_modify_sw_icm_alloc_blocks; 205 break; 206 default: 207 return -EINVAL; 208 } 209 210 MLX5_SET(general_obj_in_cmd_hdr, in, opcode, 211 MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); 212 MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM); 213 MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id); 214 MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid); 215 216 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 217 if (err) 218 return err; 219 220 start_idx = (addr - icm_start_addr) >> MLX5_LOG_SW_ICM_BLOCK_SIZE(dev); 221 spin_lock(&dm->lock); 222 bitmap_clear(block_map, 223 start_idx, num_blocks); 224 spin_unlock(&dm->lock); 225 226 return 0; 227} 228EXPORT_SYMBOL_GPL(mlx5_dm_sw_icm_dealloc);