Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2021 Marvell.
3 : : */
4 : :
5 : : #include "cnxk_mempool.h"
6 : :
7 : : #define BATCH_ALLOC_SZ ROC_CN10K_NPA_BATCH_ALLOC_MAX_PTRS
8 : : #define BATCH_OP_DATA_TABLE_MZ_NAME "batch_op_data_table_mz"
9 : : #define BATCH_ALLOC_WAIT_US 5
10 : : #define BATCH_ALLOC_RETRIES 4
11 : :
12 : : enum batch_op_status {
13 : : BATCH_ALLOC_OP_NOT_ISSUED = 0,
14 : : BATCH_ALLOC_OP_ISSUED = 1,
15 : : BATCH_ALLOC_OP_DONE
16 : : };
17 : :
18 : : struct batch_op_mem {
19 : : unsigned int sz;
20 : : enum batch_op_status status;
21 : : alignas(ROC_ALIGN) uint64_t objs[BATCH_ALLOC_SZ];
22 : : };
23 : :
24 : : struct batch_op_data {
25 : : uint64_t lmt_addr;
26 : : uint32_t max_async_batch;
27 : : alignas(ROC_ALIGN) struct batch_op_mem mem[RTE_MAX_LCORE];
28 : : };
29 : :
30 : : static struct batch_op_data **batch_op_data_tbl;
31 : :
32 : : static int
33 : 0 : batch_op_data_table_create(void)
34 : : {
35 : : const struct rte_memzone *mz;
36 : :
37 : : /* If table is already set, nothing to do */
38 [ # # ]: 0 : if (batch_op_data_tbl)
39 : : return 0;
40 : :
41 : 0 : mz = rte_memzone_lookup(BATCH_OP_DATA_TABLE_MZ_NAME);
42 [ # # ]: 0 : if (mz == NULL) {
43 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
44 : : unsigned int maxpools, sz;
45 : :
46 : 0 : maxpools = roc_idev_npa_maxpools_get();
47 : 0 : sz = maxpools * sizeof(struct batch_op_data *);
48 : :
49 : 0 : mz = rte_memzone_reserve_aligned(
50 : : BATCH_OP_DATA_TABLE_MZ_NAME, sz, SOCKET_ID_ANY,
51 : : 0, ROC_ALIGN);
52 : : }
53 [ # # ]: 0 : if (mz == NULL) {
54 : 0 : plt_err("Failed to reserve batch op data table");
55 : 0 : return -ENOMEM;
56 : : }
57 : : }
58 : 0 : batch_op_data_tbl = mz->addr;
59 : : rte_wmb();
60 : 0 : return 0;
61 : : }
62 : :
63 : : static inline struct batch_op_data *
64 : : batch_op_data_get(uint64_t pool_id)
65 : : {
66 : : uint64_t aura = roc_npa_aura_handle_to_aura(pool_id);
67 : :
68 [ # # ]: 0 : return batch_op_data_tbl[aura];
69 : : }
70 : :
71 : : static inline void
72 : : batch_op_data_set(uint64_t pool_id, struct batch_op_data *op_data)
73 : : {
74 : : uint64_t aura = roc_npa_aura_handle_to_aura(pool_id);
75 : :
76 : 0 : batch_op_data_tbl[aura] = op_data;
77 : : }
78 : :
79 : : int
80 : 0 : batch_op_init(struct rte_mempool *mp)
81 : : {
82 : : struct batch_op_data *op_data;
83 : : int i;
84 : :
85 : : op_data = batch_op_data_get(mp->pool_id);
86 : : /* The data should not have been allocated previously */
87 : : RTE_ASSERT(op_data == NULL);
88 : :
89 : 0 : op_data = rte_zmalloc(NULL, sizeof(struct batch_op_data), ROC_ALIGN);
90 [ # # ]: 0 : if (op_data == NULL)
91 : : return -ENOMEM;
92 : :
93 [ # # ]: 0 : for (i = 0; i < RTE_MAX_LCORE; i++) {
94 : 0 : op_data->mem[i].sz = 0;
95 : 0 : op_data->mem[i].status = BATCH_ALLOC_OP_NOT_ISSUED;
96 : : }
97 : :
98 : 0 : op_data->lmt_addr = roc_idev_lmt_base_addr_get();
99 : 0 : op_data->max_async_batch =
100 : 0 : RTE_MIN((unsigned int)BATCH_ALLOC_SZ,
101 : : RTE_ALIGN_CEIL(mp->cache_size, ROC_ALIGN / 8));
102 : :
103 : 0 : batch_op_data_set(mp->pool_id, op_data);
104 : : rte_wmb();
105 : :
106 : 0 : return 0;
107 : : }
108 : :
109 : : void
110 : 0 : batch_op_fini(struct rte_mempool *mp)
111 : : {
112 : : struct batch_op_data *op_data;
113 : : int i;
114 : :
115 [ # # ]: 0 : op_data = batch_op_data_get(mp->pool_id);
116 [ # # ]: 0 : if (!op_data) {
117 : : /* Batch op data can be uninitialized in case of empty
118 : : * mempools.
119 : : */
120 : : return;
121 : : }
122 : :
123 : : /* If max_async_batch == 0, then batch mem will be empty */
124 [ # # ]: 0 : if (op_data->max_async_batch == 0)
125 : 0 : goto free_op_data;
126 : :
127 : : rte_wmb();
128 [ # # ]: 0 : for (i = 0; i < RTE_MAX_LCORE; i++) {
129 : : struct batch_op_mem *mem = &op_data->mem[i];
130 : :
131 [ # # ]: 0 : if (mem->status == BATCH_ALLOC_OP_ISSUED) {
132 : 0 : mem->sz = roc_npa_aura_batch_alloc_extract(
133 : 0 : mem->objs, mem->objs, op_data->max_async_batch);
134 : 0 : mem->status = BATCH_ALLOC_OP_DONE;
135 : : }
136 [ # # ]: 0 : if (mem->status == BATCH_ALLOC_OP_DONE) {
137 : 0 : roc_npa_aura_op_bulk_free(mp->pool_id, mem->objs,
138 : : mem->sz, 1);
139 : 0 : mem->status = BATCH_ALLOC_OP_NOT_ISSUED;
140 : : }
141 : : }
142 : :
143 : 0 : free_op_data:
144 : 0 : rte_free(op_data);
145 : 0 : batch_op_data_set(mp->pool_id, NULL);
146 : : rte_wmb();
147 : : }
148 : :
149 : : int __rte_hot
150 : 0 : cn10k_mempool_enq(struct rte_mempool *mp, void *const *obj_table,
151 : : unsigned int n)
152 : : {
153 : : const uint64_t *ptr = (const uint64_t *)obj_table;
154 : : uint64_t lmt_addr = 0, lmt_id = 0;
155 : : struct batch_op_data *op_data;
156 : :
157 : : /* Ensure mbuf init changes are written before the free pointers are
158 : : * enqueued to the stack.
159 : : */
160 : 0 : rte_io_wmb();
161 : :
162 : : /* For non-EAL threads, rte_lcore_id() will not be valid. Hence
163 : : * fallback to bulk alloc
164 : : */
165 [ # # ]: 0 : if (unlikely(rte_lcore_id() == LCORE_ID_ANY))
166 : 0 : return cnxk_mempool_enq(mp, obj_table, n);
167 : :
168 [ # # ]: 0 : if (n == 1) {
169 : 0 : roc_npa_aura_op_free(mp->pool_id, 1, ptr[0]);
170 : 0 : return 0;
171 : : }
172 : :
173 : 0 : op_data = batch_op_data_get(mp->pool_id);
174 : 0 : lmt_addr = op_data->lmt_addr;
175 : : ROC_LMT_BASE_ID_GET(lmt_addr, lmt_id);
176 : 0 : roc_npa_aura_op_batch_free(mp->pool_id, ptr, n, 1, lmt_addr, lmt_id);
177 : :
178 : 0 : return 0;
179 : : }
180 : :
181 : : unsigned int
182 : 0 : cn10k_mempool_get_count(const struct rte_mempool *mp)
183 : : {
184 : : struct batch_op_data *op_data;
185 : : unsigned int count = 0;
186 : : int i;
187 : :
188 [ # # ]: 0 : op_data = batch_op_data_get(mp->pool_id);
189 : : /* If max_async_batch == 0, then batch alloc mem will be empty */
190 [ # # ]: 0 : if (op_data->max_async_batch == 0)
191 : 0 : goto npa_pool_count;
192 : :
193 : : rte_wmb();
194 [ # # ]: 0 : for (i = 0; i < RTE_MAX_LCORE; i++) {
195 : : struct batch_op_mem *mem = &op_data->mem[i];
196 : :
197 [ # # ]: 0 : if (mem->status == BATCH_ALLOC_OP_ISSUED)
198 : 0 : count += roc_npa_aura_batch_alloc_count(
199 [ # # ]: 0 : mem->objs, op_data->max_async_batch,
200 : : BATCH_ALLOC_WAIT_US);
201 : :
202 [ # # ]: 0 : if (mem->status == BATCH_ALLOC_OP_DONE)
203 : 0 : count += mem->sz;
204 : : }
205 : :
206 : 0 : npa_pool_count:
207 : 0 : count += cnxk_mempool_get_count(mp);
208 : :
209 : 0 : return count;
210 : : }
211 : :
212 : : static inline unsigned int __rte_hot
213 : : mempool_deq(struct rte_mempool *mp, void **obj_table, unsigned int n)
214 : : {
215 [ # # # # ]: 0 : return cnxk_mempool_deq(mp, obj_table, n) ? 0 : n;
216 : : }
217 : :
218 : : static inline unsigned int __rte_hot
219 : 0 : mempool_deq_batch_async(struct rte_mempool *mp, void **obj_table, unsigned int n)
220 : : {
221 : : struct batch_op_data *op_data;
222 : : struct batch_op_mem *mem;
223 : : unsigned int count = 0;
224 : : int tid, rc, retry;
225 : : bool loop = true;
226 : :
227 [ # # ]: 0 : op_data = batch_op_data_get(mp->pool_id);
228 : 0 : tid = rte_lcore_id();
229 : : mem = &op_data->mem[tid];
230 : :
231 : : /* Issue batch alloc */
232 [ # # ]: 0 : if (mem->status == BATCH_ALLOC_OP_NOT_ISSUED) {
233 [ # # ]: 0 : rc = roc_npa_aura_batch_alloc_issue(
234 : : mp->pool_id, mem->objs, op_data->max_async_batch, 0, 1);
235 : : /* If issue fails, try falling back to default alloc */
236 [ # # ]: 0 : if (unlikely(rc))
237 : 0 : return mempool_deq(mp, obj_table, n);
238 : 0 : mem->status = BATCH_ALLOC_OP_ISSUED;
239 : : }
240 : :
241 : : retry = BATCH_ALLOC_RETRIES;
242 [ # # ]: 0 : while (loop) {
243 : : unsigned int cur_sz;
244 : :
245 [ # # ]: 0 : if (mem->status == BATCH_ALLOC_OP_ISSUED) {
246 : 0 : mem->sz = roc_npa_aura_batch_alloc_extract(
247 : 0 : mem->objs, mem->objs, op_data->max_async_batch);
248 : :
249 : : /* If partial alloc reduce the retry count */
250 : 0 : retry -= (mem->sz != op_data->max_async_batch);
251 : : /* Break the loop if retry count exhausted */
252 : 0 : loop = !!retry;
253 : 0 : mem->status = BATCH_ALLOC_OP_DONE;
254 : : }
255 : :
256 : 0 : cur_sz = n - count;
257 : 0 : if (cur_sz > mem->sz)
258 : : cur_sz = mem->sz;
259 : :
260 : : /* Dequeue the pointers */
261 [ # # ]: 0 : memcpy(&obj_table[count], &mem->objs[mem->sz - cur_sz],
262 : : cur_sz * sizeof(uintptr_t));
263 : 0 : mem->sz -= cur_sz;
264 : 0 : count += cur_sz;
265 : :
266 : : /* Break loop if the required pointers has been dequeued */
267 : 0 : loop &= (count != n);
268 : :
269 : : /* Issue next batch alloc if pointers are exhausted */
270 [ # # ]: 0 : if (mem->sz == 0) {
271 [ # # ]: 0 : rc = roc_npa_aura_batch_alloc_issue(
272 : : mp->pool_id, mem->objs,
273 : : op_data->max_async_batch, 0, 1);
274 : : /* Break loop if issue failed and set status */
275 : 0 : loop &= !rc;
276 : 0 : mem->status = !rc;
277 : : }
278 : : }
279 : :
280 : : return count;
281 : : }
282 : :
283 : : static inline unsigned int __rte_hot
284 : 0 : mempool_deq_batch_sync(struct rte_mempool *mp, void **obj_table, unsigned int n)
285 : : {
286 : : struct batch_op_data *op_data;
287 : : struct batch_op_mem *mem;
288 : : unsigned int count = 0;
289 : : int tid, retry, rc;
290 : :
291 : 0 : op_data = batch_op_data_get(mp->pool_id);
292 : 0 : tid = rte_lcore_id();
293 : : mem = &op_data->mem[tid];
294 : :
295 : : retry = BATCH_ALLOC_RETRIES;
296 [ # # ]: 0 : while (count != n && retry) {
297 : : unsigned int cur_sz, batch_sz;
298 : :
299 : 0 : cur_sz = n - count;
300 : 0 : batch_sz = RTE_MIN(BATCH_ALLOC_SZ, (int)cur_sz);
301 : :
302 : : /* Issue batch alloc */
303 [ # # ]: 0 : rc = roc_npa_aura_batch_alloc_issue(mp->pool_id, mem->objs,
304 : : batch_sz, 0, 1);
305 : :
306 : : /* If issue fails, try falling back to default alloc */
307 [ # # ]: 0 : if (unlikely(rc))
308 : 0 : return count +
309 : 0 : mempool_deq(mp, obj_table + count, n - count);
310 : :
311 : 0 : cur_sz = roc_npa_aura_batch_alloc_extract(mem->objs, mem->objs,
312 : : batch_sz);
313 : :
314 : : /* Dequeue the pointers */
315 : 0 : memcpy(&obj_table[count], mem->objs,
316 : : cur_sz * sizeof(uintptr_t));
317 : 0 : count += cur_sz;
318 : :
319 : : /* If partial alloc reduce the retry count */
320 : 0 : retry -= (batch_sz != cur_sz);
321 : : }
322 : :
323 : : return count;
324 : : }
325 : :
326 : : int __rte_hot
327 [ # # ]: 0 : cn10k_mempool_deq(struct rte_mempool *mp, void **obj_table, unsigned int n)
328 : : {
329 : : struct batch_op_data *op_data;
330 : : unsigned int count = 0;
331 : :
332 : : /* For non-EAL threads, rte_lcore_id() will not be valid. Hence
333 : : * fallback to bulk alloc
334 : : */
335 [ # # ]: 0 : if (unlikely(rte_lcore_id() == LCORE_ID_ANY))
336 : 0 : return cnxk_mempool_deq(mp, obj_table, n);
337 : :
338 [ # # ]: 0 : op_data = batch_op_data_get(mp->pool_id);
339 [ # # ]: 0 : if (op_data->max_async_batch)
340 : 0 : count = mempool_deq_batch_async(mp, obj_table, n);
341 : : else
342 : 0 : count = mempool_deq_batch_sync(mp, obj_table, n);
343 : :
344 [ # # ]: 0 : if (unlikely(count != n)) {
345 : : /* No partial alloc allowed. Free up allocated pointers */
346 : 0 : cn10k_mempool_enq(mp, obj_table, count);
347 : 0 : return -ENOENT;
348 : : }
349 : :
350 : : return 0;
351 : : }
352 : :
353 : : int
354 : 0 : cn10k_mempool_alloc(struct rte_mempool *mp)
355 : : {
356 : : uint32_t block_size;
357 : : size_t padding;
358 : : int rc;
359 : :
360 : 0 : block_size = mp->elt_size + mp->header_size + mp->trailer_size;
361 : : /* Align header size to ROC_ALIGN */
362 [ # # ]: 0 : if (mp->header_size % ROC_ALIGN != 0) {
363 : 0 : padding = RTE_ALIGN_CEIL(mp->header_size, ROC_ALIGN) -
364 : : mp->header_size;
365 : 0 : mp->header_size += padding;
366 : 0 : block_size += padding;
367 : : }
368 : :
369 : : /* Align block size to ROC_ALIGN */
370 [ # # ]: 0 : if (block_size % ROC_ALIGN != 0) {
371 : 0 : padding = RTE_ALIGN_CEIL(block_size, ROC_ALIGN) - block_size;
372 : 0 : mp->trailer_size += padding;
373 : : block_size += padding;
374 : : }
375 : :
376 : 0 : rc = cnxk_mempool_alloc(mp, 0);
377 [ # # ]: 0 : if (rc)
378 : : return rc;
379 : :
380 : 0 : rc = batch_op_init(mp);
381 [ # # ]: 0 : if (rc) {
382 : 0 : plt_err("Failed to init batch alloc mem rc=%d", rc);
383 : 0 : goto error;
384 : : }
385 : :
386 : : return 0;
387 : : error:
388 : 0 : cnxk_mempool_free(mp);
389 : 0 : return rc;
390 : : }
391 : :
392 : : void
393 : 0 : cn10k_mempool_free(struct rte_mempool *mp)
394 : : {
395 : 0 : batch_op_fini(mp);
396 : 0 : cnxk_mempool_free(mp);
397 : 0 : }
398 : :
399 : : int
400 : 0 : cn10k_mempool_plt_init(void)
401 : : {
402 : 0 : return batch_op_data_table_create();
403 : : }
404 : :
405 : : static struct rte_mempool_ops cn10k_mempool_ops = {
406 : : .name = "cn10k_mempool_ops",
407 : : .alloc = cn10k_mempool_alloc,
408 : : .free = cn10k_mempool_free,
409 : : .enqueue = cn10k_mempool_enq,
410 : : .dequeue = cn10k_mempool_deq,
411 : : .get_count = cn10k_mempool_get_count,
412 : : .calc_mem_size = cnxk_mempool_calc_mem_size,
413 : : .populate = cnxk_mempool_populate,
414 : : };
415 : :
416 : 276 : RTE_MEMPOOL_REGISTER_OPS(cn10k_mempool_ops);
|