1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2019 Mellanox Technologies
4 #include <linux/mlx5/driver.h>
5 #include <linux/mlx5/device.h>
11 /* protect access to icm bitmask */
13 unsigned long *steering_sw_icm_alloc_blocks;
14 unsigned long *header_modify_sw_icm_alloc_blocks;
17 struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
19 u64 header_modify_icm_blocks = 0;
20 u64 steering_icm_blocks = 0;
23 if (!(MLX5_CAP_GEN_64(dev, general_obj_types) & MLX5_GENERAL_OBJ_TYPES_CAP_SW_ICM))
26 dm = kzalloc(sizeof(*dm), GFP_KERNEL);
28 return ERR_PTR(-ENOMEM);
30 spin_lock_init(&dm->lock);
32 if (MLX5_CAP64_DEV_MEM(dev, steering_sw_icm_start_address)) {
34 BIT(MLX5_CAP_DEV_MEM(dev, log_steering_sw_icm_size) -
35 MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
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)
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));
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)
59 kfree(dm->steering_sw_icm_alloc_blocks);
64 return ERR_PTR(-ENOMEM);
67 void mlx5_dm_cleanup(struct mlx5_core_dev *dev)
69 struct mlx5_dm *dm = dev->dm;
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);
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);
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)
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;
110 if (!length || (length & (length - 1)) ||
111 length & (MLX5_SW_ICM_BLOCK_SIZE(dev) - 1))
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);
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;
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;
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,
145 if (block_idx < max_blocks)
146 bitmap_set(block_map,
147 block_idx, num_blocks);
149 spin_unlock(&dm->lock);
151 if (block_idx >= max_blocks)
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,
158 MLX5_SET(sw_icm, sw_icm, log_sw_icm_size, ilog2(length));
160 ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
162 spin_lock(&dm->lock);
163 bitmap_clear(block_map,
164 block_idx, num_blocks);
165 spin_unlock(&dm->lock);
170 *addr = icm_start_addr;
171 *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
175 EXPORT_SYMBOL_GPL(mlx5_dm_sw_icm_alloc);
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)
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;
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;
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;
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);
211 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
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);
223 EXPORT_SYMBOL_GPL(mlx5_dm_sw_icm_dealloc);