net/bnxt: refactor host session failure cleanup
[dpdk.git] / drivers / net / bnxt / tf_core / tf_rm.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
8 #include <rte_common.h>
9 #include <rte_debug.h>
10
11 #include <cfa_resource_types.h>
12
13 #include "tf_rm.h"
14 #include "tf_common.h"
15 #include "tf_util.h"
16 #include "tf_session.h"
17 #include "tf_device.h"
18 #include "tfp.h"
19 #include "tf_msg.h"
20
21 /**
22  * Generic RM Element data type that an RM DB is build upon.
23  */
24 struct tf_rm_element {
25         /**
26          * RM Element configuration type. If Private then the
27          * hcapi_type can be ignored. If Null then the element is not
28          * valid for the device.
29          */
30         enum tf_rm_elem_cfg_type cfg_type;
31
32         /**
33          * HCAPI RM Type for the element.
34          */
35         uint16_t hcapi_type;
36
37         /**
38          * HCAPI RM allocated range information for the element.
39          */
40         struct tf_rm_alloc_info alloc;
41
42         /**
43          * If cfg_type == HCAPI_BA_CHILD, this field indicates
44          * the parent module subtype for look up into the parent pool.
45          * An example subtype is TF_TBL_TYPE_FULL_ACT_RECORD which is a
46          * module subtype of TF_MODULE_TYPE_TABLE.
47          */
48         uint16_t parent_subtype;
49
50         /**
51          * Bit allocator pool for the element. Pool size is controlled
52          * by the struct tf_session_resources at time of session creation.
53          * Null indicates that the pool is not used for the element.
54          */
55         struct bitalloc *pool;
56 };
57
58 /**
59  * TF RM DB definition
60  */
61 struct tf_rm_new_db {
62         /**
63          * Number of elements in the DB
64          */
65         uint16_t num_entries;
66
67         /**
68          * Direction this DB controls.
69          */
70         enum tf_dir dir;
71
72         /**
73          * Module type, used for logging purposes.
74          */
75         enum tf_module_type module;
76
77         /**
78          * The DB consists of an array of elements
79          */
80         struct tf_rm_element *db;
81 };
82
83 /**
84  * Adjust an index according to the allocation information.
85  *
86  * All resources are controlled in a 0 based pool. Some resources, by
87  * design, are not 0 based, i.e. Full Action Records (SRAM) thus they
88  * need to be adjusted before they are handed out.
89  *
90  * [in] cfg
91  *   Pointer to the DB configuration
92  *
93  * [in] reservations
94  *   Pointer to the allocation values associated with the module
95  *
96  * [in] count
97  *   Number of DB configuration elements
98  *
99  * [out] valid_count
100  *   Number of HCAPI entries with a reservation value greater than 0
101  *
102  * Returns:
103  *     0          - Success
104  *   - EOPNOTSUPP - Operation not supported
105  */
106 static void
107 tf_rm_count_hcapi_reservations(enum tf_dir dir,
108                                enum tf_module_type module,
109                                struct tf_rm_element_cfg *cfg,
110                                uint16_t *reservations,
111                                uint16_t count,
112                                uint16_t *valid_count)
113 {
114         int i;
115         uint16_t cnt = 0;
116
117         for (i = 0; i < count; i++) {
118                 if (cfg[i].cfg_type != TF_RM_ELEM_CFG_NULL &&
119                     reservations[i] > 0)
120                         cnt++;
121
122                 /* Only log msg if a type is attempted reserved and
123                  * not supported. We ignore EM module as its using a
124                  * split configuration array thus it would fail for
125                  * this type of check.
126                  */
127                 if (module != TF_MODULE_TYPE_EM &&
128                     cfg[i].cfg_type == TF_RM_ELEM_CFG_NULL &&
129                     reservations[i] > 0) {
130                         TFP_DRV_LOG(ERR,
131                                 "%s, %s, %s allocation of %d not supported\n",
132                                 tf_module_2_str(module),
133                                 tf_dir_2_str(dir),
134                                 tf_module_subtype_2_str(module, i),
135                                 reservations[i]);
136                 }
137         }
138
139         *valid_count = cnt;
140 }
141
142 /**
143  * Resource Manager Adjust of base index definitions.
144  */
145 enum tf_rm_adjust_type {
146         TF_RM_ADJUST_ADD_BASE, /**< Adds base to the index */
147         TF_RM_ADJUST_RM_BASE   /**< Removes base from the index */
148 };
149
150 /**
151  * Adjust an index according to the allocation information.
152  *
153  * All resources are controlled in a 0 based pool. Some resources, by
154  * design, are not 0 based, i.e. Full Action Records (SRAM) thus they
155  * need to be adjusted before they are handed out.
156  *
157  * [in] db
158  *   Pointer to the db, used for the lookup
159  *
160  * [in] action
161  *   Adjust action
162  *
163  * [in] subtype
164  *   TF module subtype used as an index into the database.
165  *   An example subtype is TF_TBL_TYPE_FULL_ACT_RECORD which is a
166  *   module subtype of TF_MODULE_TYPE_TABLE.
167  *
168  * [in] index
169  *   Index to convert
170  *
171  * [out] adj_index
172  *   Adjusted index
173  *
174  * Returns:
175  *     0          - Success
176  *   - EOPNOTSUPP - Operation not supported
177  */
178 static int
179 tf_rm_adjust_index(struct tf_rm_element *db,
180                    enum tf_rm_adjust_type action,
181                    uint32_t subtype,
182                    uint32_t index,
183                    uint32_t *adj_index)
184 {
185         int rc = 0;
186         uint32_t base_index;
187
188         base_index = db[subtype].alloc.entry.start;
189
190         switch (action) {
191         case TF_RM_ADJUST_RM_BASE:
192                 *adj_index = index - base_index;
193                 break;
194         case TF_RM_ADJUST_ADD_BASE:
195                 *adj_index = index + base_index;
196                 break;
197         default:
198                 return -EOPNOTSUPP;
199         }
200
201         return rc;
202 }
203
204 /**
205  * Performs a check of the passed in DB for any lingering elements. If
206  * a resource type was found to not have been cleaned up by the caller
207  * then its residual values are recorded, logged and passed back in an
208  * allocate reservation array that the caller can pass to the FW for
209  * cleanup.
210  *
211  * [in] db
212  *   Pointer to the db, used for the lookup
213  *
214  * [out] resv_size
215  *   Pointer to the reservation size of the generated reservation
216  *   array.
217  *
218  * [in/out] resv
219  *   Pointer Pointer to a reservation array. The reservation array is
220  *   allocated after the residual scan and holds any found residual
221  *   entries. Thus it can be smaller than the DB that the check was
222  *   performed on. Array must be freed by the caller.
223  *
224  * [out] residuals_present
225  *   Pointer to a bool flag indicating if residual was present in the
226  *   DB
227  *
228  * Returns:
229  *     0          - Success
230  *   - EOPNOTSUPP - Operation not supported
231  */
232 static int
233 tf_rm_check_residuals(struct tf_rm_new_db *rm_db,
234                       uint16_t *resv_size,
235                       struct tf_rm_resc_entry **resv,
236                       bool *residuals_present)
237 {
238         int rc;
239         int i;
240         int f;
241         uint16_t count;
242         uint16_t found;
243         uint16_t *residuals = NULL;
244         uint16_t hcapi_type;
245         struct tf_rm_get_inuse_count_parms iparms;
246         struct tf_rm_get_alloc_info_parms aparms;
247         struct tf_rm_get_hcapi_parms hparms;
248         struct tf_rm_alloc_info info;
249         struct tfp_calloc_parms cparms;
250         struct tf_rm_resc_entry *local_resv = NULL;
251
252         /* Create array to hold the entries that have residuals */
253         cparms.nitems = rm_db->num_entries;
254         cparms.size = sizeof(uint16_t);
255         cparms.alignment = 0;
256         rc = tfp_calloc(&cparms);
257         if (rc)
258                 return rc;
259
260         residuals = (uint16_t *)cparms.mem_va;
261
262         /* Traverse the DB and collect any residual elements */
263         iparms.rm_db = rm_db;
264         iparms.count = &count;
265         for (i = 0, found = 0; i < rm_db->num_entries; i++) {
266                 iparms.subtype = i;
267                 rc = tf_rm_get_inuse_count(&iparms);
268                 /* Not a device supported entry, just skip */
269                 if (rc == -ENOTSUP)
270                         continue;
271                 if (rc)
272                         goto cleanup_residuals;
273
274                 if (count) {
275                         found++;
276                         residuals[i] = count;
277                         *residuals_present = true;
278                 }
279         }
280
281         if (*residuals_present) {
282                 /* Populate a reduced resv array with only the entries
283                  * that have residuals.
284                  */
285                 cparms.nitems = found;
286                 cparms.size = sizeof(struct tf_rm_resc_entry);
287                 cparms.alignment = 0;
288                 rc = tfp_calloc(&cparms);
289                 if (rc)
290                         return rc;
291
292                 local_resv = (struct tf_rm_resc_entry *)cparms.mem_va;
293
294                 aparms.rm_db = rm_db;
295                 hparms.rm_db = rm_db;
296                 hparms.hcapi_type = &hcapi_type;
297                 for (i = 0, f = 0; i < rm_db->num_entries; i++) {
298                         if (residuals[i] == 0)
299                                 continue;
300                         aparms.subtype = i;
301                         aparms.info = &info;
302                         rc = tf_rm_get_info(&aparms);
303                         if (rc)
304                                 goto cleanup_all;
305
306                         hparms.subtype = i;
307                         rc = tf_rm_get_hcapi_type(&hparms);
308                         if (rc)
309                                 goto cleanup_all;
310
311                         local_resv[f].type = hcapi_type;
312                         local_resv[f].start = info.entry.start;
313                         local_resv[f].stride = info.entry.stride;
314                         f++;
315                 }
316                 *resv_size = found;
317         }
318
319         tfp_free((void *)residuals);
320         *resv = local_resv;
321
322         return 0;
323
324  cleanup_all:
325         tfp_free((void *)local_resv);
326         *resv = NULL;
327  cleanup_residuals:
328         tfp_free((void *)residuals);
329
330         return rc;
331 }
332
333 /**
334  * Some resources do not have a 1:1 mapping between the Truflow type and the cfa
335  * resource type (HCAPI RM).  These resources have multiple Truflow types which
336  * map to a single HCAPI RM type.  In order to support this, one Truflow type
337  * sharing the HCAPI resources is designated the parent.  All other Truflow
338  * types associated with that HCAPI RM type are designated the children.
339  *
340  * This function updates the resource counts of any HCAPI_BA_PARENT with the
341  * counts of the HCAPI_BA_CHILDREN.  These are read from the alloc_cnt and
342  * written back to the req_cnt.
343  *
344  * [in] cfg
345  *   Pointer to an array of module specific Truflow type indexed RM cfg items
346  *
347  * [in] alloc_cnt
348  *   Pointer to the tf_open_session() configured array of module specific
349  *   Truflow type indexed requested counts.
350  *
351  * [in/out] req_cnt
352  *   Pointer to the location to put the updated resource counts.
353  *
354  * Returns:
355  *     0          - Success
356  *     -          - Failure if negative
357  */
358 static int
359 tf_rm_update_parent_reservations(struct tf_rm_element_cfg *cfg,
360                                  uint16_t *alloc_cnt,
361                                  uint16_t num_elements,
362                                  uint16_t *req_cnt)
363 {
364         int parent, child;
365
366         /* Search through all the elements */
367         for (parent = 0; parent < num_elements; parent++) {
368                 uint16_t combined_cnt = 0;
369
370                 /* If I am a parent */
371                 if (cfg[parent].cfg_type == TF_RM_ELEM_CFG_HCAPI_BA_PARENT) {
372                         /* start with my own count */
373                         RTE_ASSERT(cfg[parent].slices);
374                         combined_cnt =
375                                 alloc_cnt[parent] / cfg[parent].slices;
376
377                         if (alloc_cnt[parent] % cfg[parent].slices)
378                                 combined_cnt++;
379
380                         /* Search again through all the elements */
381                         for (child = 0; child < num_elements; child++) {
382                                 /* If this is one of my children */
383                                 if (cfg[child].cfg_type ==
384                                     TF_RM_ELEM_CFG_HCAPI_BA_CHILD &&
385                                     cfg[child].parent_subtype == parent) {
386                                         uint16_t cnt = 0;
387                                         RTE_ASSERT(cfg[child].slices);
388
389                                         /* Increment the parents combined count
390                                          * with each child's count adjusted for
391                                          * number of slices per RM allocated item.
392                                          */
393                                         cnt =
394                                          alloc_cnt[child] / cfg[child].slices;
395
396                                         if (alloc_cnt[child] % cfg[child].slices)
397                                                 cnt++;
398
399                                         combined_cnt += cnt;
400                                         /* Clear the requested child count */
401                                         req_cnt[child] = 0;
402                                 }
403                         }
404                         /* Save the parent count to be requested */
405                         req_cnt[parent] = combined_cnt;
406                 }
407         }
408         return 0;
409 }
410
411 int
412 tf_rm_create_db(struct tf *tfp,
413                 struct tf_rm_create_db_parms *parms)
414 {
415         int rc;
416         struct tf_session *tfs;
417         struct tf_dev_info *dev;
418         int i, j;
419         uint16_t max_types, hcapi_items, *req_cnt;
420         struct tfp_calloc_parms cparms;
421         struct tf_rm_resc_req_entry *query;
422         enum tf_rm_resc_resv_strategy resv_strategy;
423         struct tf_rm_resc_req_entry *req;
424         struct tf_rm_resc_entry *resv;
425         struct tf_rm_new_db *rm_db;
426         struct tf_rm_element *db;
427         uint32_t pool_size;
428
429         TF_CHECK_PARMS2(tfp, parms);
430
431         /* Retrieve the session information */
432         rc = tf_session_get_session_internal(tfp, &tfs);
433         if (rc)
434                 return rc;
435
436         /* Retrieve device information */
437         rc = tf_session_get_device(tfs, &dev);
438         if (rc)
439                 return rc;
440
441         /* Need device max number of elements for the RM QCAPS */
442         rc = dev->ops->tf_dev_get_max_types(tfp, &max_types);
443
444
445         /* Allocate memory for RM QCAPS request */
446         cparms.nitems = max_types;
447         cparms.size = sizeof(struct tf_rm_resc_req_entry);
448         cparms.alignment = 0;
449         rc = tfp_calloc(&cparms);
450         if (rc)
451                 return rc;
452
453         query = (struct tf_rm_resc_req_entry *)cparms.mem_va;
454
455         /* Get Firmware Capabilities */
456         rc = tf_msg_session_resc_qcaps(tfp,
457                                        dev,
458                                        parms->dir,
459                                        max_types,
460                                        query,
461                                        &resv_strategy);
462         if (rc)
463                 return rc;
464
465         /* Copy requested counts (alloc_cnt) from tf_open_session() to local
466          * copy (req_cnt) so that it can be updated if required.
467          */
468
469         cparms.nitems = parms->num_elements;
470         cparms.size = sizeof(uint16_t);
471         rc = tfp_calloc(&cparms);
472         if (rc)
473                 return rc;
474
475         req_cnt = (uint16_t *)cparms.mem_va;
476
477         tfp_memcpy(req_cnt, parms->alloc_cnt,
478                    parms->num_elements * sizeof(uint16_t));
479
480         /* Update the req_cnt based upon the element configuration
481          */
482         tf_rm_update_parent_reservations(parms->cfg,
483                                          parms->alloc_cnt,
484                                          parms->num_elements,
485                                          req_cnt);
486
487         /* Process capabilities against DB requirements. However, as a
488          * DB can hold elements that are not HCAPI we can reduce the
489          * req msg content by removing those out of the request yet
490          * the DB holds them all as to give a fast lookup. We can also
491          * remove entries where there are no request for elements.
492          */
493         tf_rm_count_hcapi_reservations(parms->dir,
494                                        parms->module,
495                                        parms->cfg,
496                                        req_cnt,
497                                        parms->num_elements,
498                                        &hcapi_items);
499
500         if (hcapi_items == 0) {
501                 parms->rm_db = NULL;
502                 return -ENOMEM;
503         }
504
505         /* Alloc request, alignment already set */
506         cparms.nitems = (size_t)hcapi_items;
507         cparms.size = sizeof(struct tf_rm_resc_req_entry);
508         rc = tfp_calloc(&cparms);
509         if (rc)
510                 return rc;
511         req = (struct tf_rm_resc_req_entry *)cparms.mem_va;
512
513         /* Alloc reservation, alignment and nitems already set */
514         cparms.size = sizeof(struct tf_rm_resc_entry);
515         rc = tfp_calloc(&cparms);
516         if (rc)
517                 return rc;
518         resv = (struct tf_rm_resc_entry *)cparms.mem_va;
519
520         /* Build the request */
521         for (i = 0, j = 0; i < parms->num_elements; i++) {
522                 struct tf_rm_element_cfg *cfg = &parms->cfg[i];
523                 uint16_t hcapi_type = cfg->hcapi_type;
524
525                 /* Only perform reservation for requested entries
526                  */
527                 if (req_cnt[i] == 0)
528                         continue;
529
530                 /* Skip any children in the request */
531                 if (cfg->cfg_type == TF_RM_ELEM_CFG_HCAPI ||
532                     cfg->cfg_type == TF_RM_ELEM_CFG_HCAPI_BA ||
533                     cfg->cfg_type == TF_RM_ELEM_CFG_HCAPI_BA_PARENT) {
534
535                         /* Verify that we can get the full amount per qcaps.
536                          */
537                         if (req_cnt[i] <= query[hcapi_type].max) {
538                                 req[j].type = hcapi_type;
539                                 req[j].min = req_cnt[i];
540                                 req[j].max = req_cnt[i];
541                                 j++;
542                         } else {
543                                 const char *type_str;
544
545                                 dev->ops->tf_dev_get_resource_str(tfp,
546                                                               hcapi_type,
547                                                               &type_str);
548                                 TFP_DRV_LOG(ERR,
549                                             "Failure, %s:%d:%s req:%d avail:%d\n",
550                                             tf_dir_2_str(parms->dir),
551                                             hcapi_type, type_str,
552                                             req_cnt[i],
553                                             query[hcapi_type].max);
554                                 return -EINVAL;
555                         }
556                 }
557         }
558
559         /* Allocate all resources for the module type
560          */
561         rc = tf_msg_session_resc_alloc(tfp,
562                                        dev,
563                                        parms->dir,
564                                        hcapi_items,
565                                        req,
566                                        resv);
567         if (rc)
568                 return rc;
569
570         /* Build the RM DB per the request */
571         cparms.nitems = 1;
572         cparms.size = sizeof(struct tf_rm_new_db);
573         rc = tfp_calloc(&cparms);
574         if (rc)
575                 return rc;
576         rm_db = (void *)cparms.mem_va;
577
578         /* Build the DB within RM DB */
579         cparms.nitems = parms->num_elements;
580         cparms.size = sizeof(struct tf_rm_element);
581         rc = tfp_calloc(&cparms);
582         if (rc)
583                 return rc;
584         rm_db->db = (struct tf_rm_element *)cparms.mem_va;
585
586         db = rm_db->db;
587         for (i = 0, j = 0; i < parms->num_elements; i++) {
588                 struct tf_rm_element_cfg *cfg = &parms->cfg[i];
589                 const char *type_str;
590
591                 dev->ops->tf_dev_get_resource_str(tfp,
592                                                   cfg->hcapi_type,
593                                                   &type_str);
594
595                 db[i].cfg_type = cfg->cfg_type;
596                 db[i].hcapi_type = cfg->hcapi_type;
597
598                 /* Save the parent subtype for later use to find the pool
599                  */
600                 if (cfg->cfg_type == TF_RM_ELEM_CFG_HCAPI_BA_CHILD)
601                         db[i].parent_subtype = cfg->parent_subtype;
602
603                 /* If the element didn't request an allocation no need
604                  * to create a pool nor verify if we got a reservation.
605                  */
606                 if (req_cnt[i] == 0)
607                         continue;
608
609                 /* Skip any children or invalid
610                  */
611                 if (cfg->cfg_type != TF_RM_ELEM_CFG_HCAPI &&
612                     cfg->cfg_type != TF_RM_ELEM_CFG_HCAPI_BA &&
613                     cfg->cfg_type != TF_RM_ELEM_CFG_HCAPI_BA_PARENT)
614                         continue;
615
616                 /* If the element had requested an allocation and that
617                  * allocation was a success (full amount) then
618                  * allocate the pool.
619                  */
620                 if (req_cnt[i] == resv[j].stride) {
621                         db[i].alloc.entry.start = resv[j].start;
622                         db[i].alloc.entry.stride = resv[j].stride;
623
624                         /* Only allocate BA pool if a BA type not a child */
625                         if (cfg->cfg_type == TF_RM_ELEM_CFG_HCAPI_BA ||
626                             cfg->cfg_type == TF_RM_ELEM_CFG_HCAPI_BA_PARENT) {
627                                 if (cfg->divider) {
628                                         resv[j].stride =
629                                                 resv[j].stride / cfg->divider;
630                                         if (resv[j].stride <= 0) {
631                                                 TFP_DRV_LOG(ERR,
632                                                      "%s:Divide fails:%d:%s\n",
633                                                      tf_dir_2_str(parms->dir),
634                                                      cfg->hcapi_type, type_str);
635                                                 goto fail;
636                                         }
637                                 }
638                                 /* Create pool */
639                                 pool_size = (BITALLOC_SIZEOF(resv[j].stride) /
640                                              sizeof(struct bitalloc));
641                                 /* Alloc request, alignment already set */
642                                 cparms.nitems = pool_size;
643                                 cparms.size = sizeof(struct bitalloc);
644                                 rc = tfp_calloc(&cparms);
645                                 if (rc) {
646                                         TFP_DRV_LOG(ERR,
647                                          "%s: Pool alloc failed, type:%d:%s\n",
648                                          tf_dir_2_str(parms->dir),
649                                          cfg->hcapi_type, type_str);
650                                         goto fail;
651                                 }
652                                 db[i].pool = (struct bitalloc *)cparms.mem_va;
653
654                                 rc = ba_init(db[i].pool,
655                                              resv[j].stride,
656                                              !tf_session_is_shared_session(tfs));
657                                 if (rc) {
658                                         TFP_DRV_LOG(ERR,
659                                           "%s: Pool init failed, type:%d:%s\n",
660                                           tf_dir_2_str(parms->dir),
661                                           cfg->hcapi_type, type_str);
662                                         goto fail;
663                                 }
664                         }
665                         j++;
666                 } else {
667                         /* Bail out as we want what we requested for
668                          * all elements, not any less.
669                          */
670                         TFP_DRV_LOG(ERR,
671                                     "%s: Alloc failed %d:%s req:%d, alloc:%d\n",
672                                     tf_dir_2_str(parms->dir), cfg->hcapi_type,
673                                     type_str, req_cnt[i], resv[j].stride);
674                         goto fail;
675                 }
676         }
677
678         rm_db->num_entries = parms->num_elements;
679         rm_db->dir = parms->dir;
680         rm_db->module = parms->module;
681         *parms->rm_db = (void *)rm_db;
682
683         tfp_free((void *)req);
684         tfp_free((void *)resv);
685         tfp_free((void *)req_cnt);
686         return 0;
687
688  fail:
689         tfp_free((void *)req);
690         tfp_free((void *)resv);
691         tfp_free((void *)db->pool);
692         tfp_free((void *)db);
693         tfp_free((void *)rm_db);
694         tfp_free((void *)req_cnt);
695         parms->rm_db = NULL;
696
697         return -EINVAL;
698 }
699
700 int
701 tf_rm_create_db_no_reservation(struct tf *tfp,
702                                struct tf_rm_create_db_parms *parms)
703 {
704         int rc;
705         struct tf_session *tfs;
706         struct tf_dev_info *dev;
707         int i, j;
708         uint16_t hcapi_items, *req_cnt;
709         struct tfp_calloc_parms cparms;
710         struct tf_rm_resc_req_entry *req;
711         struct tf_rm_resc_entry *resv;
712         struct tf_rm_new_db *rm_db;
713         struct tf_rm_element *db;
714         uint32_t pool_size;
715
716         TF_CHECK_PARMS2(tfp, parms);
717
718         /* Retrieve the session information */
719         rc = tf_session_get_session_internal(tfp, &tfs);
720         if (rc)
721                 return rc;
722
723         /* Retrieve device information */
724         rc = tf_session_get_device(tfs, &dev);
725         if (rc)
726                 return rc;
727
728         /* Copy requested counts (alloc_cnt) from tf_open_session() to local
729          * copy (req_cnt) so that it can be updated if required.
730          */
731
732         cparms.nitems = parms->num_elements;
733         cparms.size = sizeof(uint16_t);
734         cparms.alignment = 0;
735         rc = tfp_calloc(&cparms);
736         if (rc)
737                 return rc;
738
739         req_cnt = (uint16_t *)cparms.mem_va;
740
741         tfp_memcpy(req_cnt, parms->alloc_cnt,
742                    parms->num_elements * sizeof(uint16_t));
743
744         /* Process capabilities against DB requirements. However, as a
745          * DB can hold elements that are not HCAPI we can reduce the
746          * req msg content by removing those out of the request yet
747          * the DB holds them all as to give a fast lookup. We can also
748          * remove entries where there are no request for elements.
749          */
750         tf_rm_count_hcapi_reservations(parms->dir,
751                                        parms->module,
752                                        parms->cfg,
753                                        req_cnt,
754                                        parms->num_elements,
755                                        &hcapi_items);
756
757         if (hcapi_items == 0) {
758                 TFP_DRV_LOG(ERR,
759                         "%s: module:%s Empty RM DB create request\n",
760                         tf_dir_2_str(parms->dir),
761                         tf_module_2_str(parms->module));
762
763                 parms->rm_db = NULL;
764                 return -ENOMEM;
765         }
766
767         /* Alloc request, alignment already set */
768         cparms.nitems = (size_t)hcapi_items;
769         cparms.size = sizeof(struct tf_rm_resc_req_entry);
770         rc = tfp_calloc(&cparms);
771         if (rc)
772                 return rc;
773         req = (struct tf_rm_resc_req_entry *)cparms.mem_va;
774
775         /* Alloc reservation, alignment and nitems already set */
776         cparms.size = sizeof(struct tf_rm_resc_entry);
777         rc = tfp_calloc(&cparms);
778         if (rc)
779                 return rc;
780         resv = (struct tf_rm_resc_entry *)cparms.mem_va;
781
782         /* Build the request */
783         for (i = 0, j = 0; i < parms->num_elements; i++) {
784                 struct tf_rm_element_cfg *cfg = &parms->cfg[i];
785                 uint16_t hcapi_type = cfg->hcapi_type;
786
787                 /* Only perform reservation for requested entries
788                  */
789                 if (req_cnt[i] == 0)
790                         continue;
791
792                 /* Skip any children in the request */
793                 if (cfg->cfg_type == TF_RM_ELEM_CFG_HCAPI ||
794                     cfg->cfg_type == TF_RM_ELEM_CFG_HCAPI_BA ||
795                     cfg->cfg_type == TF_RM_ELEM_CFG_HCAPI_BA_PARENT) {
796                         req[j].type = hcapi_type;
797                         req[j].min = req_cnt[i];
798                         req[j].max = req_cnt[i];
799                         j++;
800                 }
801         }
802
803         /* Get all resources info for the module type
804          */
805         rc = tf_msg_session_resc_info(tfp,
806                                       dev,
807                                       parms->dir,
808                                       hcapi_items,
809                                       req,
810                                       resv);
811         if (rc)
812                 return rc;
813
814         /* Build the RM DB per the request */
815         cparms.nitems = 1;
816         cparms.size = sizeof(struct tf_rm_new_db);
817         rc = tfp_calloc(&cparms);
818         if (rc)
819                 return rc;
820         rm_db = (void *)cparms.mem_va;
821
822         /* Build the DB within RM DB */
823         cparms.nitems = parms->num_elements;
824         cparms.size = sizeof(struct tf_rm_element);
825         rc = tfp_calloc(&cparms);
826         if (rc)
827                 return rc;
828         rm_db->db = (struct tf_rm_element *)cparms.mem_va;
829
830         db = rm_db->db;
831         for (i = 0, j = 0; i < parms->num_elements; i++) {
832                 struct tf_rm_element_cfg *cfg = &parms->cfg[i];
833                 const char *type_str;
834
835                 dev->ops->tf_dev_get_resource_str(tfp,
836                                                   cfg->hcapi_type,
837                                                   &type_str);
838
839                 db[i].cfg_type = cfg->cfg_type;
840                 db[i].hcapi_type = cfg->hcapi_type;
841
842                 /* Save the parent subtype for later use to find the pool
843                  */
844                 if (cfg->cfg_type == TF_RM_ELEM_CFG_HCAPI_BA_CHILD)
845                         db[i].parent_subtype = cfg->parent_subtype;
846
847                 /* If the element didn't request an allocation no need
848                  * to create a pool nor verify if we got a reservation.
849                  */
850                 if (req_cnt[i] == 0)
851                         continue;
852
853                 /* Skip any children or invalid
854                  */
855                 if (cfg->cfg_type != TF_RM_ELEM_CFG_HCAPI &&
856                     cfg->cfg_type != TF_RM_ELEM_CFG_HCAPI_BA &&
857                     cfg->cfg_type != TF_RM_ELEM_CFG_HCAPI_BA_PARENT)
858                         continue;
859
860                 /* If the element had requested an allocation and that
861                  * allocation was a success (full amount) then
862                  * allocate the pool.
863                  */
864                 if (req_cnt[i] == resv[j].stride) {
865                         db[i].alloc.entry.start = resv[j].start;
866                         db[i].alloc.entry.stride = resv[j].stride;
867
868                         /* Only allocate BA pool if a BA type not a child */
869                         if (cfg->cfg_type == TF_RM_ELEM_CFG_HCAPI_BA ||
870                             cfg->cfg_type == TF_RM_ELEM_CFG_HCAPI_BA_PARENT) {
871                                 if (cfg->divider) {
872                                         resv[j].stride =
873                                                 resv[j].stride / cfg->divider;
874                                         if (resv[j].stride <= 0) {
875                                                 TFP_DRV_LOG(ERR,
876                                                      "%s:Divide fails:%d:%s\n",
877                                                      tf_dir_2_str(parms->dir),
878                                                      cfg->hcapi_type, type_str);
879                                                 goto fail;
880                                         }
881                                 }
882                                 /* Create pool */
883                                 pool_size = (BITALLOC_SIZEOF(resv[j].stride) /
884                                              sizeof(struct bitalloc));
885                                 /* Alloc request, alignment already set */
886                                 cparms.nitems = pool_size;
887                                 cparms.size = sizeof(struct bitalloc);
888                                 rc = tfp_calloc(&cparms);
889                                 if (rc) {
890                                         TFP_DRV_LOG(ERR,
891                                          "%s: Pool alloc failed, type:%d:%s\n",
892                                          tf_dir_2_str(parms->dir),
893                                          cfg->hcapi_type, type_str);
894                                         goto fail;
895                                 }
896                                 db[i].pool = (struct bitalloc *)cparms.mem_va;
897
898                                 rc = ba_init(db[i].pool,
899                                              resv[j].stride,
900                                              !tf_session_is_shared_session(tfs));
901                                 if (rc) {
902                                         TFP_DRV_LOG(ERR,
903                                           "%s: Pool init failed, type:%d:%s\n",
904                                           tf_dir_2_str(parms->dir),
905                                           cfg->hcapi_type, type_str);
906                                         goto fail;
907                                 }
908                         }
909                         j++;
910                 } else {
911                         /* Bail out as we want what we requested for
912                          * all elements, not any less.
913                          */
914                         TFP_DRV_LOG(ERR,
915                                     "%s: Alloc failed %d:%s req:%d, alloc:%d\n",
916                                     tf_dir_2_str(parms->dir), cfg->hcapi_type,
917                                     type_str, req_cnt[i], resv[j].stride);
918                         goto fail;
919                 }
920         }
921
922         rm_db->num_entries = parms->num_elements;
923         rm_db->dir = parms->dir;
924         rm_db->module = parms->module;
925         *parms->rm_db = (void *)rm_db;
926
927         tfp_free((void *)req);
928         tfp_free((void *)resv);
929         tfp_free((void *)req_cnt);
930         return 0;
931
932  fail:
933         tfp_free((void *)req);
934         tfp_free((void *)resv);
935         tfp_free((void *)db->pool);
936         tfp_free((void *)db);
937         tfp_free((void *)rm_db);
938         tfp_free((void *)req_cnt);
939         parms->rm_db = NULL;
940
941         return -EINVAL;
942 }
943 int
944 tf_rm_free_db(struct tf *tfp,
945               struct tf_rm_free_db_parms *parms)
946 {
947         int rc;
948         int i;
949         uint16_t resv_size = 0;
950         struct tf_rm_new_db *rm_db;
951         struct tf_rm_resc_entry *resv;
952         bool residuals_found = false;
953
954         TF_CHECK_PARMS2(parms, parms->rm_db);
955
956         /* Device unbind happens when the TF Session is closed and the
957          * session ref count is 0. Device unbind will cleanup each of
958          * its support modules, i.e. Identifier, thus we're ending up
959          * here to close the DB.
960          *
961          * On TF Session close it is assumed that the session has already
962          * cleaned up all its resources, individually, while
963          * destroying its flows.
964          *
965          * To assist in the 'cleanup checking' the DB is checked for any
966          * remaining elements and logged if found to be the case.
967          *
968          * Any such elements will need to be 'cleared' ahead of
969          * returning the resources to the HCAPI RM.
970          *
971          * RM will signal FW to flush the DB resources. FW will
972          * perform the invalidation. TF Session close will return the
973          * previous allocated elements to the RM and then close the
974          * HCAPI RM registration. That then saves several 'free' msgs
975          * from being required.
976          */
977
978         rm_db = (struct tf_rm_new_db *)parms->rm_db;
979
980         /* Check for residuals that the client didn't clean up */
981         rc = tf_rm_check_residuals(rm_db,
982                                    &resv_size,
983                                    &resv,
984                                    &residuals_found);
985         if (rc)
986                 return rc;
987
988         /* Invalidate any residuals followed by a DB traversal for
989          * pool cleanup.
990          */
991         if (residuals_found) {
992                 rc = tf_msg_session_resc_flush(tfp,
993                                                parms->dir,
994                                                resv_size,
995                                                resv);
996                 tfp_free((void *)resv);
997                 /* On failure we still have to cleanup so we can only
998                  * log that FW failed.
999                  */
1000                 if (rc)
1001                         TFP_DRV_LOG(ERR,
1002                                     "%s: Internal Flush error, module:%s\n",
1003                                     tf_dir_2_str(parms->dir),
1004                                     tf_module_2_str(rm_db->module));
1005         }
1006
1007         /* No need to check for configuration type, even if we do not
1008          * have a BA pool we just delete on a null ptr, no harm
1009          */
1010         for (i = 0; i < rm_db->num_entries; i++)
1011                 tfp_free((void *)rm_db->db[i].pool);
1012
1013         tfp_free((void *)parms->rm_db);
1014
1015         return rc;
1016 }
1017 /**
1018  * Get the bit allocator pool associated with the subtype and the db
1019  *
1020  * [in] rm_db
1021  *   Pointer to the DB
1022  *
1023  * [in] subtype
1024  *   Module subtype used to index into the module specific database.
1025  *   An example subtype is TF_TBL_TYPE_FULL_ACT_RECORD which is a
1026  *   module subtype of TF_MODULE_TYPE_TABLE.
1027  *
1028  * [in/out] pool
1029  *   Pointer to the bit allocator pool used
1030  *
1031  * [in/out] new_subtype
1032  *   Pointer to the subtype of the actual pool used
1033  * Returns:
1034  *     0          - Success
1035  *   - ENOTSUP    - Operation not supported
1036  */
1037 static int
1038 tf_rm_get_pool(struct tf_rm_new_db *rm_db,
1039                uint16_t subtype,
1040                struct bitalloc **pool,
1041                uint16_t *new_subtype)
1042 {
1043         int rc = 0;
1044         uint16_t tmp_subtype = subtype;
1045
1046         /* If we are a child, get the parent table index */
1047         if (rm_db->db[subtype].cfg_type == TF_RM_ELEM_CFG_HCAPI_BA_CHILD)
1048                 tmp_subtype = rm_db->db[subtype].parent_subtype;
1049
1050         *pool = rm_db->db[tmp_subtype].pool;
1051
1052         /* Bail out if the pool is not valid, should never happen */
1053         if (rm_db->db[tmp_subtype].pool == NULL) {
1054                 rc = -ENOTSUP;
1055                 TFP_DRV_LOG(ERR,
1056                             "%s: Invalid pool for this type:%d, rc:%s\n",
1057                             tf_dir_2_str(rm_db->dir),
1058                             tmp_subtype,
1059                             strerror(-rc));
1060                 return rc;
1061         }
1062         *new_subtype = tmp_subtype;
1063         return rc;
1064 }
1065
1066 int
1067 tf_rm_allocate(struct tf_rm_allocate_parms *parms)
1068 {
1069         int rc;
1070         int id;
1071         uint32_t index;
1072         struct tf_rm_new_db *rm_db;
1073         enum tf_rm_elem_cfg_type cfg_type;
1074         struct bitalloc *pool;
1075         uint16_t subtype;
1076
1077         TF_CHECK_PARMS2(parms, parms->rm_db);
1078
1079         rm_db = (struct tf_rm_new_db *)parms->rm_db;
1080         TF_CHECK_PARMS1(rm_db->db);
1081
1082         cfg_type = rm_db->db[parms->subtype].cfg_type;
1083
1084         /* Bail out if not controlled by RM */
1085         if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA &&
1086             cfg_type != TF_RM_ELEM_CFG_HCAPI_BA_PARENT &&
1087             cfg_type != TF_RM_ELEM_CFG_HCAPI_BA_CHILD)
1088                 return -ENOTSUP;
1089
1090         rc = tf_rm_get_pool(rm_db, parms->subtype, &pool, &subtype);
1091         if (rc)
1092                 return rc;
1093         /*
1094          * priority  0: allocate from top of the tcam i.e. high
1095          * priority !0: allocate index from bottom i.e lowest
1096          */
1097         if (parms->priority)
1098                 id = ba_alloc_reverse(pool);
1099         else
1100                 id = ba_alloc(pool);
1101         if (id == BA_FAIL) {
1102                 rc = -ENOMEM;
1103                 TFP_DRV_LOG(ERR,
1104                             "%s: Allocation failed, rc:%s\n",
1105                             tf_dir_2_str(rm_db->dir),
1106                             strerror(-rc));
1107                 return rc;
1108         }
1109
1110         /* Adjust for any non zero start value */
1111         rc = tf_rm_adjust_index(rm_db->db,
1112                                 TF_RM_ADJUST_ADD_BASE,
1113                                 subtype,
1114                                 id,
1115                                 &index);
1116         if (rc) {
1117                 TFP_DRV_LOG(ERR,
1118                             "%s: Alloc adjust of base index failed, rc:%s\n",
1119                             tf_dir_2_str(rm_db->dir),
1120                             strerror(-rc));
1121                 return -EINVAL;
1122         }
1123
1124         *parms->index = index;
1125         if (parms->base_index)
1126                 *parms->base_index = id;
1127
1128         return rc;
1129 }
1130
1131 int
1132 tf_rm_free(struct tf_rm_free_parms *parms)
1133 {
1134         int rc;
1135         uint32_t adj_index;
1136         struct tf_rm_new_db *rm_db;
1137         enum tf_rm_elem_cfg_type cfg_type;
1138         struct bitalloc *pool;
1139         uint16_t subtype;
1140
1141         TF_CHECK_PARMS2(parms, parms->rm_db);
1142         rm_db = (struct tf_rm_new_db *)parms->rm_db;
1143         TF_CHECK_PARMS1(rm_db->db);
1144
1145         cfg_type = rm_db->db[parms->subtype].cfg_type;
1146
1147         /* Bail out if not controlled by RM */
1148         if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA &&
1149             cfg_type != TF_RM_ELEM_CFG_HCAPI_BA_PARENT &&
1150             cfg_type != TF_RM_ELEM_CFG_HCAPI_BA_CHILD)
1151                 return -ENOTSUP;
1152
1153         rc = tf_rm_get_pool(rm_db, parms->subtype, &pool, &subtype);
1154         if (rc)
1155                 return rc;
1156
1157         /* Adjust for any non zero start value */
1158         rc = tf_rm_adjust_index(rm_db->db,
1159                                 TF_RM_ADJUST_RM_BASE,
1160                                 subtype,
1161                                 parms->index,
1162                                 &adj_index);
1163         if (rc)
1164                 return rc;
1165
1166         rc = ba_free(pool, adj_index);
1167         /* No logging direction matters and that is not available here */
1168         if (rc)
1169                 return rc;
1170
1171         return rc;
1172 }
1173
1174 int
1175 tf_rm_is_allocated(struct tf_rm_is_allocated_parms *parms)
1176 {
1177         int rc;
1178         uint32_t adj_index;
1179         struct tf_rm_new_db *rm_db;
1180         enum tf_rm_elem_cfg_type cfg_type;
1181         struct bitalloc *pool;
1182         uint16_t subtype;
1183
1184         TF_CHECK_PARMS2(parms, parms->rm_db);
1185         rm_db = (struct tf_rm_new_db *)parms->rm_db;
1186         TF_CHECK_PARMS1(rm_db->db);
1187
1188         cfg_type = rm_db->db[parms->subtype].cfg_type;
1189
1190
1191         /* Bail out if not controlled by RM */
1192         if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA &&
1193             cfg_type != TF_RM_ELEM_CFG_HCAPI_BA_PARENT &&
1194             cfg_type != TF_RM_ELEM_CFG_HCAPI_BA_CHILD)
1195                 return -ENOTSUP;
1196
1197         rc = tf_rm_get_pool(rm_db, parms->subtype, &pool, &subtype);
1198         if (rc)
1199                 return rc;
1200
1201         /* Adjust for any non zero start value */
1202         rc = tf_rm_adjust_index(rm_db->db,
1203                                 TF_RM_ADJUST_RM_BASE,
1204                                 subtype,
1205                                 parms->index,
1206                                 &adj_index);
1207         if (rc)
1208                 return rc;
1209
1210         if (parms->base_index)
1211                 *parms->base_index = adj_index;
1212         *parms->allocated = ba_inuse(pool, adj_index);
1213
1214         return rc;
1215 }
1216
1217 int
1218 tf_rm_get_info(struct tf_rm_get_alloc_info_parms *parms)
1219 {
1220         struct tf_rm_new_db *rm_db;
1221         enum tf_rm_elem_cfg_type cfg_type;
1222
1223         TF_CHECK_PARMS2(parms, parms->rm_db);
1224         rm_db = (struct tf_rm_new_db *)parms->rm_db;
1225         TF_CHECK_PARMS1(rm_db->db);
1226
1227         cfg_type = rm_db->db[parms->subtype].cfg_type;
1228
1229         /* Bail out if not controlled by HCAPI */
1230         if (cfg_type == TF_RM_ELEM_CFG_NULL)
1231                 return -ENOTSUP;
1232
1233         memcpy(parms->info,
1234                &rm_db->db[parms->subtype].alloc,
1235                sizeof(struct tf_rm_alloc_info));
1236
1237         return 0;
1238 }
1239
1240 int
1241 tf_rm_get_all_info(struct tf_rm_get_alloc_info_parms *parms, int size)
1242 {
1243         struct tf_rm_new_db *rm_db;
1244         enum tf_rm_elem_cfg_type cfg_type;
1245         struct tf_rm_alloc_info *info = parms->info;
1246         int i;
1247
1248         TF_CHECK_PARMS1(parms);
1249
1250         /* No rm info available for this module type
1251          */
1252         if (!parms->rm_db)
1253                 return -ENOMEM;
1254
1255         rm_db = (struct tf_rm_new_db *)parms->rm_db;
1256         TF_CHECK_PARMS1(rm_db->db);
1257
1258         for (i = 0; i < size; i++) {
1259                 cfg_type = rm_db->db[i].cfg_type;
1260
1261                 /* Bail out if not controlled by HCAPI */
1262                 if (cfg_type == TF_RM_ELEM_CFG_NULL) {
1263                         info++;
1264                         continue;
1265                 }
1266
1267                 memcpy(info,
1268                        &rm_db->db[i].alloc,
1269                        sizeof(struct tf_rm_alloc_info));
1270                 info++;
1271         }
1272
1273         return 0;
1274 }
1275
1276 int
1277 tf_rm_get_hcapi_type(struct tf_rm_get_hcapi_parms *parms)
1278 {
1279         struct tf_rm_new_db *rm_db;
1280         enum tf_rm_elem_cfg_type cfg_type;
1281
1282         TF_CHECK_PARMS2(parms, parms->rm_db);
1283         rm_db = (struct tf_rm_new_db *)parms->rm_db;
1284         TF_CHECK_PARMS1(rm_db->db);
1285
1286         cfg_type = rm_db->db[parms->subtype].cfg_type;
1287
1288         /* Bail out if not controlled by HCAPI */
1289         if (cfg_type == TF_RM_ELEM_CFG_NULL)
1290                 return -ENOTSUP;
1291
1292         *parms->hcapi_type = rm_db->db[parms->subtype].hcapi_type;
1293
1294         return 0;
1295 }
1296
1297 int
1298 tf_rm_get_inuse_count(struct tf_rm_get_inuse_count_parms *parms)
1299 {
1300         int rc = 0;
1301         struct tf_rm_new_db *rm_db;
1302         enum tf_rm_elem_cfg_type cfg_type;
1303
1304         TF_CHECK_PARMS2(parms, parms->rm_db);
1305         rm_db = (struct tf_rm_new_db *)parms->rm_db;
1306         TF_CHECK_PARMS1(rm_db->db);
1307
1308         cfg_type = rm_db->db[parms->subtype].cfg_type;
1309
1310         /* Bail out if not a BA pool */
1311         if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA &&
1312             cfg_type != TF_RM_ELEM_CFG_HCAPI_BA_PARENT &&
1313             cfg_type != TF_RM_ELEM_CFG_HCAPI_BA_CHILD)
1314                 return -ENOTSUP;
1315
1316         /* Bail silently (no logging), if the pool is not valid there
1317          * was no elements allocated for it.
1318          */
1319         if (rm_db->db[parms->subtype].pool == NULL) {
1320                 *parms->count = 0;
1321                 return 0;
1322         }
1323
1324         *parms->count = ba_inuse_count(rm_db->db[parms->subtype].pool);
1325
1326         return rc;
1327 }
1328 /* Only used for table bulk get at this time
1329  */
1330 int
1331 tf_rm_check_indexes_in_range(struct tf_rm_check_indexes_in_range_parms *parms)
1332 {
1333         struct tf_rm_new_db *rm_db;
1334         enum tf_rm_elem_cfg_type cfg_type;
1335         uint32_t base_index;
1336         uint32_t stride;
1337         int rc = 0;
1338         struct bitalloc *pool;
1339         uint16_t subtype;
1340
1341         TF_CHECK_PARMS2(parms, parms->rm_db);
1342         rm_db = (struct tf_rm_new_db *)parms->rm_db;
1343         TF_CHECK_PARMS1(rm_db->db);
1344
1345         cfg_type = rm_db->db[parms->subtype].cfg_type;
1346
1347         /* Bail out if not a BA pool */
1348         if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA &&
1349             cfg_type != TF_RM_ELEM_CFG_HCAPI_BA_PARENT &&
1350             cfg_type != TF_RM_ELEM_CFG_HCAPI_BA_CHILD)
1351                 return -ENOTSUP;
1352
1353         rc = tf_rm_get_pool(rm_db, parms->subtype, &pool, &subtype);
1354         if (rc)
1355                 return rc;
1356
1357         base_index = rm_db->db[subtype].alloc.entry.start;
1358         stride = rm_db->db[subtype].alloc.entry.stride;
1359
1360         if (parms->starting_index < base_index ||
1361             parms->starting_index + parms->num_entries > base_index + stride)
1362                 return -EINVAL;
1363
1364         return rc;
1365 }