net/bnxt: modify resource reservation strategy
[dpdk.git] / drivers / net / bnxt / tf_core / tf_em_internal.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2021 Broadcom
3  * All rights reserved.
4  */
5
6 #include <string.h>
7 #include <rte_common.h>
8 #include <rte_errno.h>
9 #include <rte_log.h>
10
11 #include "tf_core.h"
12 #include "tf_util.h"
13 #include "tf_common.h"
14 #include "tf_em.h"
15 #include "tf_msg.h"
16 #include "tfp.h"
17 #include "tf_ext_flow_handle.h"
18 #include "bnxt.h"
19
20 #define TF_EM_DB_EM_REC 0
21
22 /**
23  * EM Pool
24  */
25 #if (TF_EM_ALLOC == 1)
26 #include "dpool.h"
27 #else
28
29 /**
30  * Create EM Tbl pool of memory indexes.
31  *
32  * [in] dir
33  *   direction
34  * [in] num_entries
35  *   number of entries to write
36  * [in] start
37  *   starting offset
38  *
39  * Return:
40  *  0       - Success, entry allocated - no search support
41  *  -ENOMEM -EINVAL -EOPNOTSUPP
42  *          - Failure, entry not allocated, out of resources
43  */
44 static int
45 tf_create_em_pool(struct tf_session *tfs,
46                   enum tf_dir dir,
47                   uint32_t num_entries,
48                   uint32_t start)
49 {
50         struct tfp_calloc_parms parms;
51         uint32_t i, j;
52         int rc = 0;
53         struct stack *pool;
54
55         /*
56          * Allocate stack pool
57          */
58         parms.nitems = 1;
59         parms.size = sizeof(struct stack);
60         parms.alignment = 0;
61
62         rc = tfp_calloc(&parms);
63
64         if (rc) {
65                 TFP_DRV_LOG(ERR,
66                             "%s, EM stack allocation failure %s\n",
67                             tf_dir_2_str(dir),
68                             strerror(-rc));
69                 return rc;
70         }
71
72         pool = (struct stack *)parms.mem_va;
73         tfs->em_pool[dir] = (void *)pool;
74
75         /* Assumes that num_entries has been checked before we get here */
76         parms.nitems = num_entries / TF_SESSION_EM_ENTRY_SIZE;
77         parms.size = sizeof(uint32_t);
78         parms.alignment = 0;
79
80         rc = tfp_calloc(&parms);
81
82         if (rc) {
83                 TFP_DRV_LOG(ERR,
84                             "%s, EM pool allocation failure %s\n",
85                             tf_dir_2_str(dir),
86                             strerror(-rc));
87                 return rc;
88         }
89
90         /* Create empty stack
91          */
92         rc = stack_init(num_entries / TF_SESSION_EM_ENTRY_SIZE,
93                         (uint32_t *)parms.mem_va,
94                         pool);
95
96         if (rc) {
97                 TFP_DRV_LOG(ERR,
98                             "%s, EM pool stack init failure %s\n",
99                             tf_dir_2_str(dir),
100                             strerror(-rc));
101                 goto cleanup;
102         }
103
104         /* Fill pool with indexes
105          */
106         j = start + num_entries - TF_SESSION_EM_ENTRY_SIZE;
107
108         for (i = 0; i < (num_entries / TF_SESSION_EM_ENTRY_SIZE); i++) {
109                 rc = stack_push(pool, j);
110                 if (rc) {
111                         TFP_DRV_LOG(ERR,
112                                     "%s, EM pool stack push failure %s\n",
113                                     tf_dir_2_str(dir),
114                                     strerror(-rc));
115                         goto cleanup;
116                 }
117
118                 j -= TF_SESSION_EM_ENTRY_SIZE;
119         }
120
121         if (!stack_is_full(pool)) {
122                 rc = -EINVAL;
123                 TFP_DRV_LOG(ERR,
124                             "%s, EM pool stack failure %s\n",
125                             tf_dir_2_str(dir),
126                             strerror(-rc));
127                 goto cleanup;
128         }
129
130         return 0;
131 cleanup:
132         tfp_free((void *)parms.mem_va);
133         tfp_free((void *)tfs->em_pool[dir]);
134         tfs->em_pool[dir] = NULL;
135         return rc;
136 }
137
138 /**
139  * Create EM Tbl pool of memory indexes.
140  *
141  * [in] dir
142  *   direction
143  *
144  * Return:
145  */
146 static void
147 tf_free_em_pool(struct tf_session *tfs,
148                 enum tf_dir dir)
149 {
150         struct stack *pool = (struct stack *)tfs->em_pool[dir];
151         uint32_t *ptr;
152
153         if (pool != NULL) {
154                 ptr = stack_items(pool);
155
156                 if (ptr != NULL)
157                         tfp_free(ptr);
158
159                 tfp_free(pool);
160                 tfs->em_pool[dir] = NULL;
161         }
162 }
163 #endif /* TF_EM_ALLOC != 1 */
164
165 /**
166  * Insert EM internal entry API
167  *
168  *  returns:
169  *     0 - Success
170  */
171 int
172 tf_em_insert_int_entry(struct tf *tfp,
173                        struct tf_insert_em_entry_parms *parms)
174 {
175         int rc;
176         uint32_t gfid;
177         uint16_t rptr_index = 0;
178         uint8_t rptr_entry = 0;
179         uint8_t num_of_entries = 0;
180         struct tf_session *tfs;
181 #if (TF_EM_ALLOC == 1)
182         struct dpool *pool;
183 #else
184         struct stack *pool;
185 #endif
186         uint32_t index;
187
188         /* Retrieve the session information */
189         rc = tf_session_get_session(tfp, &tfs);
190         if (rc) {
191                 TFP_DRV_LOG(ERR,
192                             "%s: Failed to lookup session, rc:%s\n",
193                             tf_dir_2_str(parms->dir),
194                             strerror(-rc));
195                 return rc;
196         }
197
198 #if (TF_EM_ALLOC == 1)
199         pool = (struct dpool *)tfs->em_pool[parms->dir];
200         index = dpool_alloc(pool, TF_SESSION_EM_ENTRY_SIZE, 0);
201         if (index == DP_INVALID_INDEX) {
202                 PMD_DRV_LOG(ERR,
203                             "%s, EM entry index allocation failed\n",
204                             tf_dir_2_str(parms->dir));
205                 return -1;
206         }
207 #else
208         pool = (struct stack *)tfs->em_pool[parms->dir];
209         rc = stack_pop(pool, &index);
210         if (rc) {
211                 PMD_DRV_LOG(ERR,
212                             "%s, EM entry index allocation failed\n",
213                             tf_dir_2_str(parms->dir));
214                 return rc;
215         }
216 #endif
217
218
219         rptr_index = index;
220         rc = tf_msg_insert_em_internal_entry(tfp,
221                                              parms,
222                                              &rptr_index,
223                                              &rptr_entry,
224                                              &num_of_entries);
225         if (rc) {
226                 /* Free the allocated index before returning */
227 #if (TF_EM_ALLOC == 1)
228                 dpool_free(pool, index);
229 #else
230                 stack_push(pool, index);
231 #endif
232                 return -1;
233         }
234         TF_SET_GFID(gfid,
235                     ((rptr_index << TF_EM_INTERNAL_INDEX_SHIFT) |
236                      rptr_entry),
237                     0); /* N/A for internal table */
238
239         TF_SET_FLOW_ID(parms->flow_id,
240                        gfid,
241                        TF_GFID_TABLE_INTERNAL,
242                        parms->dir);
243
244         TF_SET_FIELDS_IN_FLOW_HANDLE(parms->flow_handle,
245                                      (uint32_t)num_of_entries,
246                                      0,
247                                      TF_FLAGS_FLOW_HANDLE_INTERNAL,
248                                      rptr_index,
249                                      rptr_entry,
250                                      0);
251         return 0;
252 }
253
254
255 /** Delete EM internal entry API
256  *
257  * returns:
258  * 0
259  * -EINVAL
260  */
261 int
262 tf_em_delete_int_entry(struct tf *tfp,
263                        struct tf_delete_em_entry_parms *parms)
264 {
265         int rc = 0;
266         struct tf_session *tfs;
267 #if (TF_EM_ALLOC == 1)
268         struct dpool *pool;
269 #else
270         struct stack *pool;
271 #endif
272         /* Retrieve the session information */
273         rc = tf_session_get_session(tfp, &tfs);
274         if (rc) {
275                 TFP_DRV_LOG(ERR,
276                             "%s: Failed to lookup session, rc:%s\n",
277                             tf_dir_2_str(parms->dir),
278                             strerror(-rc));
279                 return rc;
280         }
281
282         rc = tf_msg_delete_em_entry(tfp, parms);
283
284         /* Return resource to pool */
285         if (rc == 0) {
286 #if (TF_EM_ALLOC == 1)
287                 pool = (struct dpool *)tfs->em_pool[parms->dir];
288                 dpool_free(pool, parms->index);
289 #else
290                 pool = (struct stack *)tfs->em_pool[parms->dir];
291                 stack_push(pool, parms->index);
292 #endif
293         }
294
295         return rc;
296 }
297
298 #if (TF_EM_ALLOC == 1)
299 static int
300 tf_em_move_callback(void *user_data,
301                     uint64_t entry_data,
302                     uint32_t new_index)
303 {
304         int rc;
305         struct tf *tfp = (struct tf *)user_data;
306         struct tf_move_em_entry_parms parms;
307         struct tf_dev_info     *dev;
308         struct tf_session      *tfs;
309
310         memset(&parms, 0, sizeof(parms));
311
312         parms.tbl_scope_id = 0;
313         parms.flow_handle  = entry_data;
314         parms.new_index    = new_index;
315         TF_GET_DIR_FROM_FLOW_ID(entry_data, parms.dir);
316         parms.mem          = TF_MEM_INTERNAL;
317
318         /* Retrieve the session information */
319         rc = tf_session_get_session(tfp, &tfs);
320         if (rc) {
321                 TFP_DRV_LOG(ERR,
322                             "%s: Failed to lookup session, rc:%s\n",
323                             tf_dir_2_str(parms.dir),
324                             strerror(-rc));
325                 return rc;
326         }
327
328         /* Retrieve the device information */
329         rc = tf_session_get_device(tfs, &dev);
330         if (rc) {
331                 TFP_DRV_LOG(ERR,
332                             "%s: Failed to lookup device, rc:%s\n",
333                             tf_dir_2_str(parms.dir),
334                             strerror(-rc));
335                 return rc;
336         }
337
338         if (dev->ops->tf_dev_move_int_em_entry != NULL)
339                 rc = dev->ops->tf_dev_move_int_em_entry(tfp, &parms);
340         else
341                 rc = -EOPNOTSUPP;
342
343         return rc;
344 }
345 #endif
346
347 int
348 tf_em_int_bind(struct tf *tfp,
349                struct tf_em_cfg_parms *parms)
350 {
351         int rc;
352         int db_rc[TF_DIR_MAX] = { 0 };
353         int i;
354         struct tf_rm_create_db_parms db_cfg = { 0 };
355         struct tf_rm_get_alloc_info_parms iparms;
356         struct tf_rm_alloc_info info;
357         struct em_rm_db *em_db;
358         struct tfp_calloc_parms cparms;
359         struct tf_session *tfs;
360
361         TF_CHECK_PARMS2(tfp, parms);
362
363         /* Retrieve the session information */
364         rc = tf_session_get_session_internal(tfp, &tfs);
365         if (rc)
366                 return rc;
367
368         memset(&db_cfg, 0, sizeof(db_cfg));
369         cparms.nitems = 1;
370         cparms.size = sizeof(struct em_rm_db);
371         cparms.alignment = 0;
372         if (tfp_calloc(&cparms) != 0) {
373                 TFP_DRV_LOG(ERR, "em_rm_db alloc error %s\n",
374                             strerror(ENOMEM));
375                 return -ENOMEM;
376         }
377
378         em_db = cparms.mem_va;
379         for (i = 0; i < TF_DIR_MAX; i++)
380                 em_db->em_db[i] = NULL;
381         tf_session_set_db(tfp, TF_MODULE_TYPE_EM, em_db);
382
383         db_cfg.module = TF_MODULE_TYPE_EM;
384         db_cfg.num_elements = parms->num_elements;
385         db_cfg.cfg = parms->cfg;
386
387         for (i = 0; i < TF_DIR_MAX; i++) {
388                 db_cfg.dir = i;
389                 db_cfg.alloc_cnt = parms->resources->em_cnt[i].cnt;
390
391                 /* Check if we got any request to support EEM, if so
392                  * we build an EM Int DB holding Table Scopes.
393                  */
394                 if (db_cfg.alloc_cnt[TF_EM_TBL_TYPE_EM_RECORD] == 0)
395                         continue;
396
397                 if (db_cfg.alloc_cnt[TF_EM_TBL_TYPE_EM_RECORD] %
398                     TF_SESSION_EM_ENTRY_SIZE != 0) {
399                         rc = -ENOMEM;
400                         TFP_DRV_LOG(ERR,
401                                     "%s, EM Allocation must be in blocks of %d, failure %s\n",
402                                     tf_dir_2_str(i),
403                                     TF_SESSION_EM_ENTRY_SIZE,
404                                     strerror(-rc));
405
406                         return rc;
407                 }
408
409                 db_cfg.rm_db = (void *)&em_db->em_db[i];
410                 if (tf_session_is_shared_session(tfs) &&
411                         (!tf_session_is_shared_session_creator(tfs)))
412                         db_rc[i] = tf_rm_create_db_no_reservation(tfp, &db_cfg);
413                 else
414                         db_rc[i] = tf_rm_create_db(tfp, &db_cfg);
415                 if (db_rc[i]) {
416                         TFP_DRV_LOG(ERR,
417                                     "%s: EM Int DB creation failed\n",
418                                     tf_dir_2_str(i));
419
420                 }
421         }
422
423         /* No db created */
424         if (db_rc[TF_DIR_RX] && db_rc[TF_DIR_TX])
425                 return db_rc[TF_DIR_RX];
426
427
428         if (!tf_session_is_shared_session(tfs)) {
429                 for (i = 0; i < TF_DIR_MAX; i++) {
430                         iparms.rm_db = em_db->em_db[i];
431                         iparms.subtype = TF_EM_DB_EM_REC;
432                         iparms.info = &info;
433
434                         rc = tf_rm_get_info(&iparms);
435                         if (rc) {
436                                 TFP_DRV_LOG(ERR,
437                                             "%s: EM DB get info failed\n",
438                                             tf_dir_2_str(i));
439                                 return rc;
440                         }
441 #if (TF_EM_ALLOC == 1)
442                         /*
443                          * Allocate stack pool
444                          */
445                         cparms.nitems = 1;
446                         cparms.size = sizeof(struct dpool);
447                         cparms.alignment = 0;
448
449                         rc = tfp_calloc(&cparms);
450
451                         if (rc) {
452                                 TFP_DRV_LOG(ERR,
453                                          "%s, EM stack allocation failure %s\n",
454                                          tf_dir_2_str(i),
455                                          strerror(-rc));
456                                 return rc;
457                         }
458
459                         tfs->em_pool[i] = (struct dpool *)cparms.mem_va;
460
461                         rc = dpool_init(tfs->em_pool[i],
462                                         iparms.info->entry.start,
463                                         iparms.info->entry.stride,
464                                         7,
465                                         (void *)tfp,
466                                         tf_em_move_callback);
467 #else
468                         rc = tf_create_em_pool(tfs,
469                                        i,
470                                        iparms.info->entry.stride,
471                                        iparms.info->entry.start);
472 #endif
473                         /* Logging handled in tf_create_em_pool */
474                         if (rc)
475                                 return rc;
476                 }
477
478                 if (rc) {
479                         TFP_DRV_LOG(ERR,
480                                     "%s: EM pool init failed\n",
481                                     tf_dir_2_str(i));
482                         return rc;
483                 }
484         }
485
486         return 0;
487 }
488
489 int
490 tf_em_int_unbind(struct tf *tfp)
491 {
492         int rc;
493         int i;
494         struct tf_rm_free_db_parms fparms = { 0 };
495         struct em_rm_db *em_db;
496         void *em_db_ptr = NULL;
497         struct tf_session *tfs;
498
499         TF_CHECK_PARMS1(tfp);
500
501         /* Retrieve the session information */
502         rc = tf_session_get_session_internal(tfp, &tfs);
503         if (rc)
504                 return rc;
505
506         if (!tf_session_is_shared_session(tfs)) {
507                 for (i = 0; i < TF_DIR_MAX; i++)
508 #if (TF_EM_ALLOC == 1)
509                         dpool_free_all(tfs->em_pool[i]);
510 #else
511                 tf_free_em_pool(tfs, i);
512 #endif
513         }
514
515         rc = tf_session_get_db(tfp, TF_MODULE_TYPE_EM, &em_db_ptr);
516         if (rc) {
517                 TFP_DRV_LOG(INFO,
518                             "Em_db is not initialized, rc:%s\n",
519                             strerror(-rc));
520                 return 0;
521         }
522         em_db = (struct em_rm_db *)em_db_ptr;
523
524         for (i = 0; i < TF_DIR_MAX; i++) {
525                 if (em_db->em_db[i] == NULL)
526                         continue;
527                 fparms.dir = i;
528                 fparms.rm_db = em_db->em_db[i];
529                 rc = tf_rm_free_db(tfp, &fparms);
530                 if (rc)
531                         return rc;
532
533                 em_db->em_db[i] = NULL;
534         }
535
536         return 0;
537 }
538
539 int
540 tf_em_get_resc_info(struct tf *tfp,
541                     struct tf_em_resource_info *em)
542 {
543         int rc;
544         int d;
545         struct tf_resource_info *dinfo;
546         struct tf_rm_get_alloc_info_parms ainfo;
547         void *em_db_ptr = NULL;
548         struct em_rm_db *em_db;
549
550         TF_CHECK_PARMS2(tfp, em);
551
552         rc = tf_session_get_db(tfp, TF_MODULE_TYPE_EM, &em_db_ptr);
553         if (rc) {
554                 TFP_DRV_LOG(INFO,
555                             "No resource allocated for em from session\n");
556                 return 0;
557         }
558         em_db = (struct em_rm_db *)em_db_ptr;
559
560         /* check if reserved resource for WC is multiple of num_slices */
561         for (d = 0; d < TF_DIR_MAX; d++) {
562                 ainfo.rm_db = em_db->em_db[d];
563                 dinfo = em[d].info;
564
565                 ainfo.info = (struct tf_rm_alloc_info *)dinfo;
566                 ainfo.subtype = 0;
567                 rc = tf_rm_get_all_info(&ainfo, TF_EM_TBL_TYPE_MAX);
568                 if (rc && rc != -ENOTSUP)
569                         return rc;
570         }
571
572         return 0;
573 }