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