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 return -ENOMEM;
128 }
129
130 pool->db.buddy = buddy;
131
132 return 0;
133 }
134
hws_pool_buddy_db_get_chunk(struct mlx5hws_pool * pool,struct mlx5hws_pool_chunk * chunk)135 static int hws_pool_buddy_db_get_chunk(struct mlx5hws_pool *pool,
136 struct mlx5hws_pool_chunk *chunk)
137 {
138 struct mlx5hws_buddy_mem *buddy = pool->db.buddy;
139
140 if (!buddy) {
141 mlx5hws_err(pool->ctx, "Bad buddy state\n");
142 return -EINVAL;
143 }
144
145 chunk->offset = mlx5hws_buddy_alloc_mem(buddy, chunk->order);
146 if (chunk->offset >= 0)
147 return 0;
148
149 return -ENOMEM;
150 }
151
hws_pool_buddy_db_put_chunk(struct mlx5hws_pool * pool,struct mlx5hws_pool_chunk * chunk)152 static void hws_pool_buddy_db_put_chunk(struct mlx5hws_pool *pool,
153 struct mlx5hws_pool_chunk *chunk)
154 {
155 struct mlx5hws_buddy_mem *buddy;
156
157 buddy = pool->db.buddy;
158 if (!buddy) {
159 mlx5hws_err(pool->ctx, "Bad buddy state\n");
160 return;
161 }
162
163 mlx5hws_buddy_free_mem(buddy, chunk->offset, chunk->order);
164 }
165
hws_pool_buddy_db_uninit(struct mlx5hws_pool * pool)166 static void hws_pool_buddy_db_uninit(struct mlx5hws_pool *pool)
167 {
168 struct mlx5hws_buddy_mem *buddy;
169
170 buddy = pool->db.buddy;
171 if (buddy) {
172 mlx5hws_buddy_cleanup(buddy);
173 kfree(buddy);
174 pool->db.buddy = NULL;
175 }
176 }
177
hws_pool_buddy_db_init(struct mlx5hws_pool * pool)178 static int hws_pool_buddy_db_init(struct mlx5hws_pool *pool)
179 {
180 int ret;
181
182 ret = hws_pool_buddy_init(pool);
183 if (ret)
184 return ret;
185
186 pool->p_db_uninit = &hws_pool_buddy_db_uninit;
187 pool->p_get_chunk = &hws_pool_buddy_db_get_chunk;
188 pool->p_put_chunk = &hws_pool_buddy_db_put_chunk;
189
190 return 0;
191 }
192
hws_pool_create_and_init_bitmap(u32 log_range)193 static unsigned long *hws_pool_create_and_init_bitmap(u32 log_range)
194 {
195 unsigned long *bitmap;
196
197 bitmap = bitmap_zalloc(1 << log_range, GFP_KERNEL);
198 if (!bitmap)
199 return NULL;
200
201 bitmap_fill(bitmap, 1 << log_range);
202
203 return bitmap;
204 }
205
hws_pool_bitmap_init(struct mlx5hws_pool * pool)206 static int hws_pool_bitmap_init(struct mlx5hws_pool *pool)
207 {
208 unsigned long *bitmap;
209
210 bitmap = hws_pool_create_and_init_bitmap(pool->alloc_log_sz);
211 if (!bitmap) {
212 mlx5hws_err(pool->ctx, "Failed to create bitmap order: %zu\n",
213 pool->alloc_log_sz);
214 return -ENOMEM;
215 }
216
217 if (hws_pool_resource_alloc(pool) != 0) {
218 mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %zu\n",
219 pool->type, pool->alloc_log_sz);
220 bitmap_free(bitmap);
221 return -ENOMEM;
222 }
223
224 pool->db.bitmap = bitmap;
225
226 return 0;
227 }
228
hws_pool_bitmap_db_get_chunk(struct mlx5hws_pool * pool,struct mlx5hws_pool_chunk * chunk)229 static int hws_pool_bitmap_db_get_chunk(struct mlx5hws_pool *pool,
230 struct mlx5hws_pool_chunk *chunk)
231 {
232 unsigned long *bitmap, size;
233
234 if (chunk->order != 0) {
235 mlx5hws_err(pool->ctx, "Pool only supports order 0 allocs\n");
236 return -EINVAL;
237 }
238
239 bitmap = pool->db.bitmap;
240 if (!bitmap) {
241 mlx5hws_err(pool->ctx, "Bad bitmap state\n");
242 return -EINVAL;
243 }
244
245 size = 1 << pool->alloc_log_sz;
246
247 chunk->offset = find_first_bit(bitmap, size);
248 if (chunk->offset >= size)
249 return -ENOMEM;
250
251 bitmap_clear(bitmap, chunk->offset, 1);
252
253 return 0;
254 }
255
hws_pool_bitmap_db_put_chunk(struct mlx5hws_pool * pool,struct mlx5hws_pool_chunk * chunk)256 static void hws_pool_bitmap_db_put_chunk(struct mlx5hws_pool *pool,
257 struct mlx5hws_pool_chunk *chunk)
258 {
259 unsigned long *bitmap;
260
261 bitmap = pool->db.bitmap;
262 if (!bitmap) {
263 mlx5hws_err(pool->ctx, "Bad bitmap state\n");
264 return;
265 }
266
267 bitmap_set(bitmap, chunk->offset, 1);
268 }
269
hws_pool_bitmap_db_uninit(struct mlx5hws_pool * pool)270 static void hws_pool_bitmap_db_uninit(struct mlx5hws_pool *pool)
271 {
272 unsigned long *bitmap;
273
274 bitmap = pool->db.bitmap;
275 if (bitmap) {
276 bitmap_free(bitmap);
277 pool->db.bitmap = NULL;
278 }
279 }
280
hws_pool_bitmap_db_init(struct mlx5hws_pool * pool)281 static int hws_pool_bitmap_db_init(struct mlx5hws_pool *pool)
282 {
283 int ret;
284
285 ret = hws_pool_bitmap_init(pool);
286 if (ret)
287 return ret;
288
289 pool->p_db_uninit = &hws_pool_bitmap_db_uninit;
290 pool->p_get_chunk = &hws_pool_bitmap_db_get_chunk;
291 pool->p_put_chunk = &hws_pool_bitmap_db_put_chunk;
292
293 return 0;
294 }
295
hws_pool_db_init(struct mlx5hws_pool * pool,enum mlx5hws_db_type db_type)296 static int hws_pool_db_init(struct mlx5hws_pool *pool,
297 enum mlx5hws_db_type db_type)
298 {
299 int ret;
300
301 if (db_type == MLX5HWS_POOL_DB_TYPE_BITMAP)
302 ret = hws_pool_bitmap_db_init(pool);
303 else
304 ret = hws_pool_buddy_db_init(pool);
305
306 if (ret) {
307 mlx5hws_err(pool->ctx, "Failed to init pool type: %d (ret: %d)\n",
308 db_type, ret);
309 return ret;
310 }
311
312 return 0;
313 }
314
hws_pool_db_unint(struct mlx5hws_pool * pool)315 static void hws_pool_db_unint(struct mlx5hws_pool *pool)
316 {
317 pool->p_db_uninit(pool);
318 }
319
mlx5hws_pool_chunk_alloc(struct mlx5hws_pool * pool,struct mlx5hws_pool_chunk * chunk)320 int mlx5hws_pool_chunk_alloc(struct mlx5hws_pool *pool,
321 struct mlx5hws_pool_chunk *chunk)
322 {
323 int ret;
324
325 mutex_lock(&pool->lock);
326 ret = pool->p_get_chunk(pool, chunk);
327 if (ret == 0)
328 pool->available_elems -= 1 << chunk->order;
329 mutex_unlock(&pool->lock);
330
331 return ret;
332 }
333
mlx5hws_pool_chunk_free(struct mlx5hws_pool * pool,struct mlx5hws_pool_chunk * chunk)334 void mlx5hws_pool_chunk_free(struct mlx5hws_pool *pool,
335 struct mlx5hws_pool_chunk *chunk)
336 {
337 mutex_lock(&pool->lock);
338 pool->p_put_chunk(pool, chunk);
339 pool->available_elems += 1 << chunk->order;
340 mutex_unlock(&pool->lock);
341 }
342
343 struct mlx5hws_pool *
mlx5hws_pool_create(struct mlx5hws_context * ctx,struct mlx5hws_pool_attr * pool_attr)344 mlx5hws_pool_create(struct mlx5hws_context *ctx, struct mlx5hws_pool_attr *pool_attr)
345 {
346 enum mlx5hws_db_type res_db_type;
347 struct mlx5hws_pool *pool;
348
349 pool = kzalloc(sizeof(*pool), GFP_KERNEL);
350 if (!pool)
351 return NULL;
352
353 pool->ctx = ctx;
354 pool->type = pool_attr->pool_type;
355 pool->alloc_log_sz = pool_attr->alloc_log_sz;
356 pool->flags = pool_attr->flags;
357 pool->tbl_type = pool_attr->table_type;
358 pool->opt_type = pool_attr->opt_type;
359
360 if (pool->flags & MLX5HWS_POOL_FLAG_BUDDY)
361 res_db_type = MLX5HWS_POOL_DB_TYPE_BUDDY;
362 else
363 res_db_type = MLX5HWS_POOL_DB_TYPE_BITMAP;
364
365 pool->alloc_log_sz = pool_attr->alloc_log_sz;
366 pool->available_elems = 1 << pool_attr->alloc_log_sz;
367
368 if (hws_pool_db_init(pool, res_db_type))
369 goto free_pool;
370
371 mutex_init(&pool->lock);
372
373 return pool;
374
375 free_pool:
376 kfree(pool);
377 return NULL;
378 }
379
mlx5hws_pool_destroy(struct mlx5hws_pool * pool)380 void mlx5hws_pool_destroy(struct mlx5hws_pool *pool)
381 {
382 mutex_destroy(&pool->lock);
383
384 if (pool->available_elems != 1 << pool->alloc_log_sz)
385 mlx5hws_err(pool->ctx, "Attempting to destroy non-empty pool\n");
386
387 if (pool->resource)
388 hws_pool_resource_free(pool);
389
390 hws_pool_db_unint(pool);
391
392 kfree(pool);
393 }
394