Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
0002 // Copyright (c) 2019 Mellanox Technologies
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     /* protect access to icm bitmask */
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);