xref: /linux/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c (revision 9c736ace0666efe68efd53fcdfa2c6653c3e0e72)
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
3 
4 #include "internal.h"
5 #include "buddy.h"
6 
hws_pool_free_one_resource(struct mlx5hws_pool_resource * resource)7 static void hws_pool_free_one_resource(struct mlx5hws_pool_resource *resource)
8 {
9 	switch (resource->pool->type) {
10 	case MLX5HWS_POOL_TYPE_STE:
11 		mlx5hws_cmd_ste_destroy(resource->pool->ctx->mdev, resource->base_id);
12 		break;
13 	case MLX5HWS_POOL_TYPE_STC:
14 		mlx5hws_cmd_stc_destroy(resource->pool->ctx->mdev, resource->base_id);
15 		break;
16 	default:
17 		break;
18 	}
19 
20 	kfree(resource);
21 }
22 
hws_pool_resource_free(struct mlx5hws_pool * pool)23 static void hws_pool_resource_free(struct mlx5hws_pool *pool)
24 {
25 	hws_pool_free_one_resource(pool->resource);
26 	pool->resource = NULL;
27 
28 	if (pool->tbl_type == MLX5HWS_TABLE_TYPE_FDB) {
29 		hws_pool_free_one_resource(pool->mirror_resource);
30 		pool->mirror_resource = NULL;
31 	}
32 }
33 
34 static struct mlx5hws_pool_resource *
hws_pool_create_one_resource(struct mlx5hws_pool * pool,u32 log_range,u32 fw_ft_type)35 hws_pool_create_one_resource(struct mlx5hws_pool *pool, u32 log_range,
36 			     u32 fw_ft_type)
37 {
38 	struct mlx5hws_cmd_ste_create_attr ste_attr;
39 	struct mlx5hws_cmd_stc_create_attr stc_attr;
40 	struct mlx5hws_pool_resource *resource;
41 	u32 obj_id = 0;
42 	int ret;
43 
44 	resource = kzalloc(sizeof(*resource), GFP_KERNEL);
45 	if (!resource)
46 		return NULL;
47 
48 	switch (pool->type) {
49 	case MLX5HWS_POOL_TYPE_STE:
50 		ste_attr.log_obj_range = log_range;
51 		ste_attr.table_type = fw_ft_type;
52 		ret = mlx5hws_cmd_ste_create(pool->ctx->mdev, &ste_attr, &obj_id);
53 		break;
54 	case MLX5HWS_POOL_TYPE_STC:
55 		stc_attr.log_obj_range = log_range;
56 		stc_attr.table_type = fw_ft_type;
57 		ret = mlx5hws_cmd_stc_create(pool->ctx->mdev, &stc_attr, &obj_id);
58 		break;
59 	default:
60 		ret = -EINVAL;
61 	}
62 
63 	if (ret)
64 		goto free_resource;
65 
66 	resource->pool = pool;
67 	resource->range = 1 << log_range;
68 	resource->base_id = obj_id;
69 
70 	return resource;
71 
72 free_resource:
73 	kfree(resource);
74 	return NULL;
75 }
76 
hws_pool_resource_alloc(struct mlx5hws_pool * pool)77 static int hws_pool_resource_alloc(struct mlx5hws_pool *pool)
78 {
79 	struct mlx5hws_pool_resource *resource;
80 	u32 fw_ft_type, opt_log_range;
81 
82 	fw_ft_type = mlx5hws_table_get_res_fw_ft_type(pool->tbl_type, false);
83 	opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_MIRROR ?
84 				0 : pool->alloc_log_sz;
85 	resource = hws_pool_create_one_resource(pool, opt_log_range, fw_ft_type);
86 	if (!resource) {
87 		mlx5hws_err(pool->ctx, "Failed to allocate resource\n");
88 		return -EINVAL;
89 	}
90 
91 	pool->resource = resource;
92 
93 	if (pool->tbl_type == MLX5HWS_TABLE_TYPE_FDB) {
94 		struct mlx5hws_pool_resource *mirror_resource;
95 
96 		fw_ft_type = mlx5hws_table_get_res_fw_ft_type(pool->tbl_type, true);
97 		opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_ORIG ?
98 					0 : pool->alloc_log_sz;
99 		mirror_resource = hws_pool_create_one_resource(pool, opt_log_range, fw_ft_type);
100 		if (!mirror_resource) {
101 			mlx5hws_err(pool->ctx, "Failed to allocate mirrored resource\n");
102 			hws_pool_free_one_resource(resource);
103 			pool->resource = NULL;
104 			return -EINVAL;
105 		}
106 		pool->mirror_resource = mirror_resource;
107 	}
108 
109 	return 0;
110 }
111 
hws_pool_buddy_init(struct mlx5hws_pool * pool)112 static int hws_pool_buddy_init(struct mlx5hws_pool *pool)
113 {
114 	struct mlx5hws_buddy_mem *buddy;
115 
116 	buddy = mlx5hws_buddy_create(pool->alloc_log_sz);
117 	if (!buddy) {
118 		mlx5hws_err(pool->ctx, "Failed to create buddy order: %zu\n",
119 			    pool->alloc_log_sz);
120 		return -ENOMEM;
121 	}
122 
123 	if (hws_pool_resource_alloc(pool) != 0) {
124 		mlx5hws_err(pool->ctx, "Failed to create resource type: %d size %zu\n",
125 			    pool->type, pool->alloc_log_sz);
126 		mlx5hws_buddy_cleanup(buddy);
127 		kfree(buddy);
128 		return -ENOMEM;
129 	}
130 
131 	pool->db.buddy = buddy;
132 
133 	return 0;
134 }
135 
hws_pool_buddy_db_get_chunk(struct mlx5hws_pool * pool,struct mlx5hws_pool_chunk * chunk)136 static int hws_pool_buddy_db_get_chunk(struct mlx5hws_pool *pool,
137 				       struct mlx5hws_pool_chunk *chunk)
138 {
139 	struct mlx5hws_buddy_mem *buddy = pool->db.buddy;
140 
141 	if (!buddy) {
142 		mlx5hws_err(pool->ctx, "Bad buddy state\n");
143 		return -EINVAL;
144 	}
145 
146 	chunk->offset = mlx5hws_buddy_alloc_mem(buddy, chunk->order);
147 	if (chunk->offset >= 0)
148 		return 0;
149 
150 	return -ENOMEM;
151 }
152 
hws_pool_buddy_db_put_chunk(struct mlx5hws_pool * pool,struct mlx5hws_pool_chunk * chunk)153 static void hws_pool_buddy_db_put_chunk(struct mlx5hws_pool *pool,
154 					struct mlx5hws_pool_chunk *chunk)
155 {
156 	struct mlx5hws_buddy_mem *buddy;
157 
158 	buddy = pool->db.buddy;
159 	if (!buddy) {
160 		mlx5hws_err(pool->ctx, "Bad buddy state\n");
161 		return;
162 	}
163 
164 	mlx5hws_buddy_free_mem(buddy, chunk->offset, chunk->order);
165 }
166 
hws_pool_buddy_db_uninit(struct mlx5hws_pool * pool)167 static void hws_pool_buddy_db_uninit(struct mlx5hws_pool *pool)
168 {
169 	struct mlx5hws_buddy_mem *buddy;
170 
171 	buddy = pool->db.buddy;
172 	if (buddy) {
173 		mlx5hws_buddy_cleanup(buddy);
174 		kfree(buddy);
175 		pool->db.buddy = NULL;
176 	}
177 }
178 
hws_pool_buddy_db_init(struct mlx5hws_pool * pool)179 static int hws_pool_buddy_db_init(struct mlx5hws_pool *pool)
180 {
181 	int ret;
182 
183 	ret = hws_pool_buddy_init(pool);
184 	if (ret)
185 		return ret;
186 
187 	pool->p_db_uninit = &hws_pool_buddy_db_uninit;
188 	pool->p_get_chunk = &hws_pool_buddy_db_get_chunk;
189 	pool->p_put_chunk = &hws_pool_buddy_db_put_chunk;
190 
191 	return 0;
192 }
193 
hws_pool_create_and_init_bitmap(u32 log_range)194 static unsigned long *hws_pool_create_and_init_bitmap(u32 log_range)
195 {
196 	unsigned long *bitmap;
197 
198 	bitmap = bitmap_zalloc(1 << log_range, GFP_KERNEL);
199 	if (!bitmap)
200 		return NULL;
201 
202 	bitmap_fill(bitmap, 1 << log_range);
203 
204 	return bitmap;
205 }
206 
hws_pool_bitmap_init(struct mlx5hws_pool * pool)207 static int hws_pool_bitmap_init(struct mlx5hws_pool *pool)
208 {
209 	unsigned long *bitmap;
210 
211 	bitmap = hws_pool_create_and_init_bitmap(pool->alloc_log_sz);
212 	if (!bitmap) {
213 		mlx5hws_err(pool->ctx, "Failed to create bitmap order: %zu\n",
214 			    pool->alloc_log_sz);
215 		return -ENOMEM;
216 	}
217 
218 	if (hws_pool_resource_alloc(pool) != 0) {
219 		mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %zu\n",
220 			    pool->type, pool->alloc_log_sz);
221 		bitmap_free(bitmap);
222 		return -ENOMEM;
223 	}
224 
225 	pool->db.bitmap = bitmap;
226 
227 	return 0;
228 }
229 
hws_pool_bitmap_db_get_chunk(struct mlx5hws_pool * pool,struct mlx5hws_pool_chunk * chunk)230 static int hws_pool_bitmap_db_get_chunk(struct mlx5hws_pool *pool,
231 					struct mlx5hws_pool_chunk *chunk)
232 {
233 	unsigned long *bitmap, size;
234 
235 	if (chunk->order != 0) {
236 		mlx5hws_err(pool->ctx, "Pool only supports order 0 allocs\n");
237 		return -EINVAL;
238 	}
239 
240 	bitmap = pool->db.bitmap;
241 	if (!bitmap) {
242 		mlx5hws_err(pool->ctx, "Bad bitmap state\n");
243 		return -EINVAL;
244 	}
245 
246 	size = 1 << pool->alloc_log_sz;
247 
248 	chunk->offset = find_first_bit(bitmap, size);
249 	if (chunk->offset >= size)
250 		return -ENOMEM;
251 
252 	bitmap_clear(bitmap, chunk->offset, 1);
253 
254 	return 0;
255 }
256 
hws_pool_bitmap_db_put_chunk(struct mlx5hws_pool * pool,struct mlx5hws_pool_chunk * chunk)257 static void hws_pool_bitmap_db_put_chunk(struct mlx5hws_pool *pool,
258 					 struct mlx5hws_pool_chunk *chunk)
259 {
260 	unsigned long *bitmap;
261 
262 	bitmap = pool->db.bitmap;
263 	if (!bitmap) {
264 		mlx5hws_err(pool->ctx, "Bad bitmap state\n");
265 		return;
266 	}
267 
268 	bitmap_set(bitmap, chunk->offset, 1);
269 }
270 
hws_pool_bitmap_db_uninit(struct mlx5hws_pool * pool)271 static void hws_pool_bitmap_db_uninit(struct mlx5hws_pool *pool)
272 {
273 	unsigned long *bitmap;
274 
275 	bitmap = pool->db.bitmap;
276 	if (bitmap) {
277 		bitmap_free(bitmap);
278 		pool->db.bitmap = NULL;
279 	}
280 }
281 
hws_pool_bitmap_db_init(struct mlx5hws_pool * pool)282 static int hws_pool_bitmap_db_init(struct mlx5hws_pool *pool)
283 {
284 	int ret;
285 
286 	ret = hws_pool_bitmap_init(pool);
287 	if (ret)
288 		return ret;
289 
290 	pool->p_db_uninit = &hws_pool_bitmap_db_uninit;
291 	pool->p_get_chunk = &hws_pool_bitmap_db_get_chunk;
292 	pool->p_put_chunk = &hws_pool_bitmap_db_put_chunk;
293 
294 	return 0;
295 }
296 
hws_pool_db_init(struct mlx5hws_pool * pool,enum mlx5hws_db_type db_type)297 static int hws_pool_db_init(struct mlx5hws_pool *pool,
298 			    enum mlx5hws_db_type db_type)
299 {
300 	int ret;
301 
302 	if (db_type == MLX5HWS_POOL_DB_TYPE_BITMAP)
303 		ret = hws_pool_bitmap_db_init(pool);
304 	else
305 		ret = hws_pool_buddy_db_init(pool);
306 
307 	if (ret) {
308 		mlx5hws_err(pool->ctx, "Failed to init pool type: %d (ret: %d)\n",
309 			    db_type, ret);
310 		return ret;
311 	}
312 
313 	return 0;
314 }
315 
hws_pool_db_unint(struct mlx5hws_pool * pool)316 static void hws_pool_db_unint(struct mlx5hws_pool *pool)
317 {
318 	pool->p_db_uninit(pool);
319 }
320 
mlx5hws_pool_chunk_alloc(struct mlx5hws_pool * pool,struct mlx5hws_pool_chunk * chunk)321 int mlx5hws_pool_chunk_alloc(struct mlx5hws_pool *pool,
322 			     struct mlx5hws_pool_chunk *chunk)
323 {
324 	int ret;
325 
326 	mutex_lock(&pool->lock);
327 	ret = pool->p_get_chunk(pool, chunk);
328 	if (ret == 0)
329 		pool->available_elems -= 1 << chunk->order;
330 	mutex_unlock(&pool->lock);
331 
332 	return ret;
333 }
334 
mlx5hws_pool_chunk_free(struct mlx5hws_pool * pool,struct mlx5hws_pool_chunk * chunk)335 void mlx5hws_pool_chunk_free(struct mlx5hws_pool *pool,
336 			     struct mlx5hws_pool_chunk *chunk)
337 {
338 	mutex_lock(&pool->lock);
339 	pool->p_put_chunk(pool, chunk);
340 	pool->available_elems += 1 << chunk->order;
341 	mutex_unlock(&pool->lock);
342 }
343 
344 struct mlx5hws_pool *
mlx5hws_pool_create(struct mlx5hws_context * ctx,struct mlx5hws_pool_attr * pool_attr)345 mlx5hws_pool_create(struct mlx5hws_context *ctx, struct mlx5hws_pool_attr *pool_attr)
346 {
347 	enum mlx5hws_db_type res_db_type;
348 	struct mlx5hws_pool *pool;
349 
350 	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
351 	if (!pool)
352 		return NULL;
353 
354 	pool->ctx = ctx;
355 	pool->type = pool_attr->pool_type;
356 	pool->alloc_log_sz = pool_attr->alloc_log_sz;
357 	pool->flags = pool_attr->flags;
358 	pool->tbl_type = pool_attr->table_type;
359 	pool->opt_type = pool_attr->opt_type;
360 
361 	if (pool->flags & MLX5HWS_POOL_FLAG_BUDDY)
362 		res_db_type = MLX5HWS_POOL_DB_TYPE_BUDDY;
363 	else
364 		res_db_type = MLX5HWS_POOL_DB_TYPE_BITMAP;
365 
366 	pool->alloc_log_sz = pool_attr->alloc_log_sz;
367 	pool->available_elems = 1 << pool_attr->alloc_log_sz;
368 
369 	if (hws_pool_db_init(pool, res_db_type))
370 		goto free_pool;
371 
372 	mutex_init(&pool->lock);
373 
374 	return pool;
375 
376 free_pool:
377 	kfree(pool);
378 	return NULL;
379 }
380 
mlx5hws_pool_destroy(struct mlx5hws_pool * pool)381 void mlx5hws_pool_destroy(struct mlx5hws_pool *pool)
382 {
383 	mutex_destroy(&pool->lock);
384 
385 	if (pool->available_elems != 1 << pool->alloc_log_sz)
386 		mlx5hws_err(pool->ctx, "Attempting to destroy non-empty pool\n");
387 
388 	if (pool->resource)
389 		hws_pool_resource_free(pool);
390 
391 	hws_pool_db_unint(pool);
392 
393 	kfree(pool);
394 }
395