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