0001
0002
0003
0004 #include <linux/mlx5/driver.h>
0005 #include <linux/mlx5/device.h>
0006
0007 #include "mlx5_core.h"
0008 #include "lib/mlx5.h"
0009
0010 struct mlx5_dm {
0011
0012 spinlock_t lock;
0013 unsigned long *steering_sw_icm_alloc_blocks;
0014 unsigned long *header_modify_sw_icm_alloc_blocks;
0015 unsigned long *header_modify_pattern_sw_icm_alloc_blocks;
0016 };
0017
0018 struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
0019 {
0020 u64 header_modify_pattern_icm_blocks = 0;
0021 u64 header_modify_icm_blocks = 0;
0022 u64 steering_icm_blocks = 0;
0023 struct mlx5_dm *dm;
0024 bool support_v2;
0025
0026 if (!(MLX5_CAP_GEN_64(dev, general_obj_types) & MLX5_GENERAL_OBJ_TYPES_CAP_SW_ICM))
0027 return NULL;
0028
0029 dm = kzalloc(sizeof(*dm), GFP_KERNEL);
0030 if (!dm)
0031 return ERR_PTR(-ENOMEM);
0032
0033 spin_lock_init(&dm->lock);
0034
0035 if (MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address)) {
0036 steering_icm_blocks =
0037 BIT(MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size) -
0038 MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
0039
0040 dm->steering_sw_icm_alloc_blocks =
0041 bitmap_zalloc(steering_icm_blocks, GFP_KERNEL);
0042 if (!dm->steering_sw_icm_alloc_blocks)
0043 goto err_steering;
0044 }
0045
0046 if (MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address)) {
0047 header_modify_icm_blocks =
0048 BIT(MLX5_CAP_DEV_MEM(dev, log_header_modify_sw_icm_size) -
0049 MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
0050
0051 dm->header_modify_sw_icm_alloc_blocks =
0052 bitmap_zalloc(header_modify_icm_blocks, GFP_KERNEL);
0053 if (!dm->header_modify_sw_icm_alloc_blocks)
0054 goto err_modify_hdr;
0055 }
0056
0057 support_v2 = MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner_v2) &&
0058 MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner_v2) &&
0059 MLX5_CAP64_DEV_MEM(dev, header_modify_pattern_sw_icm_start_address);
0060
0061 if (support_v2) {
0062 header_modify_pattern_icm_blocks =
0063 BIT(MLX5_CAP_DEV_MEM(dev, log_header_modify_pattern_sw_icm_size) -
0064 MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
0065
0066 dm->header_modify_pattern_sw_icm_alloc_blocks =
0067 bitmap_zalloc(header_modify_pattern_icm_blocks, GFP_KERNEL);
0068 if (!dm->header_modify_pattern_sw_icm_alloc_blocks)
0069 goto err_pattern;
0070 }
0071
0072 return dm;
0073
0074 err_pattern:
0075 bitmap_free(dm->header_modify_sw_icm_alloc_blocks);
0076
0077 err_modify_hdr:
0078 bitmap_free(dm->steering_sw_icm_alloc_blocks);
0079
0080 err_steering:
0081 kfree(dm);
0082
0083 return ERR_PTR(-ENOMEM);
0084 }
0085
0086 void mlx5_dm_cleanup(struct mlx5_core_dev *dev)
0087 {
0088 struct mlx5_dm *dm = dev->dm;
0089
0090 if (!dev->dm)
0091 return;
0092
0093 if (dm->steering_sw_icm_alloc_blocks) {
0094 WARN_ON(!bitmap_empty(dm->steering_sw_icm_alloc_blocks,
0095 BIT(MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size) -
0096 MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
0097 bitmap_free(dm->steering_sw_icm_alloc_blocks);
0098 }
0099
0100 if (dm->header_modify_sw_icm_alloc_blocks) {
0101 WARN_ON(!bitmap_empty(dm->header_modify_sw_icm_alloc_blocks,
0102 BIT(MLX5_CAP_DEV_MEM(dev,
0103 log_header_modify_sw_icm_size) -
0104 MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
0105 bitmap_free(dm->header_modify_sw_icm_alloc_blocks);
0106 }
0107
0108 if (dm->header_modify_pattern_sw_icm_alloc_blocks) {
0109 WARN_ON(!bitmap_empty(dm->header_modify_pattern_sw_icm_alloc_blocks,
0110 BIT(MLX5_CAP_DEV_MEM(dev,
0111 log_header_modify_pattern_sw_icm_size) -
0112 MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
0113 bitmap_free(dm->header_modify_pattern_sw_icm_alloc_blocks);
0114 }
0115
0116 kfree(dm);
0117 }
0118
0119 int mlx5_dm_sw_icm_alloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
0120 u64 length, u32 log_alignment, u16 uid,
0121 phys_addr_t *addr, u32 *obj_id)
0122 {
0123 u32 num_blocks = DIV_ROUND_UP_ULL(length, MLX5_SW_ICM_BLOCK_SIZE(dev));
0124 u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
0125 u32 in[MLX5_ST_SZ_DW(create_sw_icm_in)] = {};
0126 struct mlx5_dm *dm = dev->dm;
0127 unsigned long *block_map;
0128 u64 icm_start_addr;
0129 u32 log_icm_size;
0130 u64 align_mask;
0131 u32 max_blocks;
0132 u64 block_idx;
0133 void *sw_icm;
0134 int ret;
0135
0136 if (!dev->dm)
0137 return -EOPNOTSUPP;
0138
0139 if (!length || (length & (length - 1)) ||
0140 length & (MLX5_SW_ICM_BLOCK_SIZE(dev) - 1))
0141 return -EINVAL;
0142
0143 MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
0144 MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
0145 MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM);
0146 MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid);
0147
0148 switch (type) {
0149 case MLX5_SW_ICM_TYPE_STEERING:
0150 icm_start_addr = MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address);
0151 log_icm_size = MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size);
0152 block_map = dm->steering_sw_icm_alloc_blocks;
0153 break;
0154 case MLX5_SW_ICM_TYPE_HEADER_MODIFY:
0155 icm_start_addr = MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address);
0156 log_icm_size = MLX5_CAP_DEV_MEM(dev,
0157 log_header_modify_sw_icm_size);
0158 block_map = dm->header_modify_sw_icm_alloc_blocks;
0159 break;
0160 case MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN:
0161 icm_start_addr = MLX5_CAP64_DEV_MEM(dev,
0162 header_modify_pattern_sw_icm_start_address);
0163 log_icm_size = MLX5_CAP_DEV_MEM(dev,
0164 log_header_modify_pattern_sw_icm_size);
0165 block_map = dm->header_modify_pattern_sw_icm_alloc_blocks;
0166 break;
0167 default:
0168 return -EINVAL;
0169 }
0170
0171 if (!block_map)
0172 return -EOPNOTSUPP;
0173
0174 max_blocks = BIT(log_icm_size - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
0175
0176 if (log_alignment < MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))
0177 log_alignment = MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
0178 align_mask = BIT(log_alignment - MLX5_LOG_SW_ICM_BLOCK_SIZE(dev)) - 1;
0179
0180 spin_lock(&dm->lock);
0181 block_idx = bitmap_find_next_zero_area(block_map, max_blocks, 0,
0182 num_blocks, align_mask);
0183
0184 if (block_idx < max_blocks)
0185 bitmap_set(block_map,
0186 block_idx, num_blocks);
0187
0188 spin_unlock(&dm->lock);
0189
0190 if (block_idx >= max_blocks)
0191 return -ENOMEM;
0192
0193 sw_icm = MLX5_ADDR_OF(create_sw_icm_in, in, sw_icm);
0194 icm_start_addr += block_idx << MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
0195 MLX5_SET64(sw_icm, sw_icm, sw_icm_start_addr,
0196 icm_start_addr);
0197 MLX5_SET(sw_icm, sw_icm, log_sw_icm_size, ilog2(length));
0198
0199 ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
0200 if (ret) {
0201 spin_lock(&dm->lock);
0202 bitmap_clear(block_map,
0203 block_idx, num_blocks);
0204 spin_unlock(&dm->lock);
0205
0206 return ret;
0207 }
0208
0209 *addr = icm_start_addr;
0210 *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
0211
0212 return 0;
0213 }
0214 EXPORT_SYMBOL_GPL(mlx5_dm_sw_icm_alloc);
0215
0216 int mlx5_dm_sw_icm_dealloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
0217 u64 length, u16 uid, phys_addr_t addr, u32 obj_id)
0218 {
0219 u32 num_blocks = DIV_ROUND_UP_ULL(length, MLX5_SW_ICM_BLOCK_SIZE(dev));
0220 u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
0221 u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
0222 struct mlx5_dm *dm = dev->dm;
0223 unsigned long *block_map;
0224 u64 icm_start_addr;
0225 u64 start_idx;
0226 int err;
0227
0228 if (!dev->dm)
0229 return -EOPNOTSUPP;
0230
0231 switch (type) {
0232 case MLX5_SW_ICM_TYPE_STEERING:
0233 icm_start_addr = MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address);
0234 block_map = dm->steering_sw_icm_alloc_blocks;
0235 break;
0236 case MLX5_SW_ICM_TYPE_HEADER_MODIFY:
0237 icm_start_addr = MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address);
0238 block_map = dm->header_modify_sw_icm_alloc_blocks;
0239 break;
0240 case MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN:
0241 icm_start_addr = MLX5_CAP64_DEV_MEM(dev,
0242 header_modify_pattern_sw_icm_start_address);
0243 block_map = dm->header_modify_pattern_sw_icm_alloc_blocks;
0244 break;
0245 default:
0246 return -EINVAL;
0247 }
0248
0249 MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
0250 MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
0251 MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_SW_ICM);
0252 MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id);
0253 MLX5_SET(general_obj_in_cmd_hdr, in, uid, uid);
0254
0255 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
0256 if (err)
0257 return err;
0258
0259 start_idx = (addr - icm_start_addr) >> MLX5_LOG_SW_ICM_BLOCK_SIZE(dev);
0260 spin_lock(&dm->lock);
0261 bitmap_clear(block_map,
0262 start_idx, num_blocks);
0263 spin_unlock(&dm->lock);
0264
0265 return 0;
0266 }
0267 EXPORT_SYMBOL_GPL(mlx5_dm_sw_icm_dealloc);