1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019-2021 Broadcom
8 #include <rte_common.h>
11 #include <cfa_resource_types.h>
14 #include "tf_common.h"
16 #include "tf_session.h"
17 #include "tf_device.h"
25 * Generic RM Element data type that an RM DB is build upon.
27 struct tf_rm_element {
29 * RM Element configuration type. If Private then the
30 * hcapi_type can be ignored. If Null then the element is not
31 * valid for the device.
33 enum tf_rm_elem_cfg_type cfg_type;
36 * HCAPI RM Type for the element.
41 * HCAPI RM allocated range information for the element.
43 struct tf_rm_alloc_info alloc;
46 * Bit allocator pool for the element. Pool size is controlled
47 * by the struct tf_session_resources at time of session creation.
48 * Null indicates that the element is not used for the device.
50 struct bitalloc *pool;
58 * Number of elements in the DB
63 * Direction this DB controls.
68 * Module type, used for logging purposes.
70 enum tf_device_module_type type;
73 * The DB consists of an array of elements
75 struct tf_rm_element *db;
79 * Adjust an index according to the allocation information.
81 * All resources are controlled in a 0 based pool. Some resources, by
82 * design, are not 0 based, i.e. Full Action Records (SRAM) thus they
83 * need to be adjusted before they are handed out.
86 * Pointer to the DB configuration
89 * Pointer to the allocation values associated with the module
92 * Number of DB configuration elements
95 * Number of HCAPI entries with a reservation value greater than 0
99 * - EOPNOTSUPP - Operation not supported
102 tf_rm_count_hcapi_reservations(enum tf_dir dir,
103 enum tf_device_module_type type,
104 struct tf_rm_element_cfg *cfg,
105 uint16_t *reservations,
107 uint16_t *valid_count)
112 for (i = 0; i < count; i++) {
113 if ((cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI ||
114 cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI_BA) &&
118 /* Only log msg if a type is attempted reserved and
119 * not supported. We ignore EM module as its using a
120 * split configuration array thus it would fail for
121 * this type of check.
123 if (type != TF_DEVICE_MODULE_TYPE_EM &&
124 cfg[i].cfg_type == TF_RM_ELEM_CFG_NULL &&
125 reservations[i] > 0) {
127 "%s, %s, %s allocation of %d not supported\n",
128 tf_device_module_type_2_str(type),
130 tf_device_module_type_subtype_2_str(type, i),
139 * Resource Manager Adjust of base index definitions.
141 enum tf_rm_adjust_type {
142 TF_RM_ADJUST_ADD_BASE, /**< Adds base to the index */
143 TF_RM_ADJUST_RM_BASE /**< Removes base from the index */
147 * Adjust an index according to the allocation information.
149 * All resources are controlled in a 0 based pool. Some resources, by
150 * design, are not 0 based, i.e. Full Action Records (SRAM) thus they
151 * need to be adjusted before they are handed out.
154 * Pointer to the db, used for the lookup
160 * DB index for the element type
170 * - EOPNOTSUPP - Operation not supported
173 tf_rm_adjust_index(struct tf_rm_element *db,
174 enum tf_rm_adjust_type action,
182 base_index = db[db_index].alloc.entry.start;
185 case TF_RM_ADJUST_RM_BASE:
186 *adj_index = index - base_index;
188 case TF_RM_ADJUST_ADD_BASE:
189 *adj_index = index + base_index;
199 * Logs an array of found residual entries to the console.
202 * Receive or transmit direction
205 * Type of Device Module
208 * Number of entries in the residual array
211 * Pointer to an array of residual entries. Array is index same as
212 * the DB in which this function is used. Each entry holds residual
213 * value for that entry.
216 tf_rm_log_residuals(enum tf_dir dir,
217 enum tf_device_module_type type,
223 /* Walk the residual array and log the types that wasn't
224 * cleaned up to the console.
226 for (i = 0; i < count; i++) {
227 if (residuals[i] != 0)
229 "%s, %s was not cleaned up, %d outstanding\n",
231 tf_device_module_type_subtype_2_str(type, i),
237 * Performs a check of the passed in DB for any lingering elements. If
238 * a resource type was found to not have been cleaned up by the caller
239 * then its residual values are recorded, logged and passed back in an
240 * allocate reservation array that the caller can pass to the FW for
244 * Pointer to the db, used for the lookup
247 * Pointer to the reservation size of the generated reservation
251 * Pointer Pointer to a reservation array. The reservation array is
252 * allocated after the residual scan and holds any found residual
253 * entries. Thus it can be smaller than the DB that the check was
254 * performed on. Array must be freed by the caller.
256 * [out] residuals_present
257 * Pointer to a bool flag indicating if residual was present in the
262 * - EOPNOTSUPP - Operation not supported
265 tf_rm_check_residuals(struct tf_rm_new_db *rm_db,
267 struct tf_rm_resc_entry **resv,
268 bool *residuals_present)
275 uint16_t *residuals = NULL;
277 struct tf_rm_get_inuse_count_parms iparms;
278 struct tf_rm_get_alloc_info_parms aparms;
279 struct tf_rm_get_hcapi_parms hparms;
280 struct tf_rm_alloc_info info;
281 struct tfp_calloc_parms cparms;
282 struct tf_rm_resc_entry *local_resv = NULL;
284 /* Create array to hold the entries that have residuals */
285 cparms.nitems = rm_db->num_entries;
286 cparms.size = sizeof(uint16_t);
287 cparms.alignment = 0;
288 rc = tfp_calloc(&cparms);
292 residuals = (uint16_t *)cparms.mem_va;
294 /* Traverse the DB and collect any residual elements */
295 iparms.rm_db = rm_db;
296 iparms.count = &count;
297 for (i = 0, found = 0; i < rm_db->num_entries; i++) {
299 rc = tf_rm_get_inuse_count(&iparms);
300 /* Not a device supported entry, just skip */
304 goto cleanup_residuals;
308 residuals[i] = count;
309 *residuals_present = true;
313 if (*residuals_present) {
314 /* Populate a reduced resv array with only the entries
315 * that have residuals.
317 cparms.nitems = found;
318 cparms.size = sizeof(struct tf_rm_resc_entry);
319 cparms.alignment = 0;
320 rc = tfp_calloc(&cparms);
324 local_resv = (struct tf_rm_resc_entry *)cparms.mem_va;
326 aparms.rm_db = rm_db;
327 hparms.rm_db = rm_db;
328 hparms.hcapi_type = &hcapi_type;
329 for (i = 0, f = 0; i < rm_db->num_entries; i++) {
330 if (residuals[i] == 0)
334 rc = tf_rm_get_info(&aparms);
339 rc = tf_rm_get_hcapi_type(&hparms);
343 local_resv[f].type = hcapi_type;
344 local_resv[f].start = info.entry.start;
345 local_resv[f].stride = info.entry.stride;
351 tf_rm_log_residuals(rm_db->dir,
356 tfp_free((void *)residuals);
362 tfp_free((void *)local_resv);
365 tfp_free((void *)residuals);
371 tf_rm_create_db(struct tf *tfp,
372 struct tf_rm_create_db_parms *parms)
377 struct tf_session *tfs;
378 struct tf_dev_info *dev;
380 struct tfp_calloc_parms cparms;
381 struct tf_rm_resc_req_entry *query;
382 enum tf_rm_resc_resv_strategy resv_strategy;
383 struct tf_rm_resc_req_entry *req;
384 struct tf_rm_resc_entry *resv;
385 struct tf_rm_new_db *rm_db;
386 struct tf_rm_element *db;
388 uint16_t hcapi_items;
390 TF_CHECK_PARMS2(tfp, parms);
392 /* Retrieve the session information */
393 rc = tf_session_get_session_internal(tfp, &tfs);
397 /* Retrieve device information */
398 rc = tf_session_get_device(tfs, &dev);
402 /* Need device max number of elements for the RM QCAPS */
403 rc = dev->ops->tf_dev_get_max_types(tfp, &max_types);
407 cparms.nitems = max_types;
408 cparms.size = sizeof(struct tf_rm_resc_req_entry);
409 cparms.alignment = 0;
410 rc = tfp_calloc(&cparms);
414 query = (struct tf_rm_resc_req_entry *)cparms.mem_va;
416 /* Get Firmware Capabilities */
417 rc = tf_msg_session_resc_qcaps(tfp,
426 /* Process capabilities against DB requirements. However, as a
427 * DB can hold elements that are not HCAPI we can reduce the
428 * req msg content by removing those out of the request yet
429 * the DB holds them all as to give a fast lookup. We can also
430 * remove entries where there are no request for elements.
432 tf_rm_count_hcapi_reservations(parms->dir,
439 /* Handle the case where a DB create request really ends up
440 * being empty. Unsupported (if not rare) case but possible
441 * that no resources are necessary for a 'direction'.
443 if (hcapi_items == 0) {
445 "%s: DB create request for Zero elements, DB Type:%s\n",
446 tf_dir_2_str(parms->dir),
447 tf_device_module_type_2_str(parms->type));
453 /* Alloc request, alignment already set */
454 cparms.nitems = (size_t)hcapi_items;
455 cparms.size = sizeof(struct tf_rm_resc_req_entry);
456 rc = tfp_calloc(&cparms);
459 req = (struct tf_rm_resc_req_entry *)cparms.mem_va;
461 /* Alloc reservation, alignment and nitems already set */
462 cparms.size = sizeof(struct tf_rm_resc_entry);
463 rc = tfp_calloc(&cparms);
466 resv = (struct tf_rm_resc_entry *)cparms.mem_va;
468 /* Build the request */
469 for (i = 0, j = 0; i < parms->num_elements; i++) {
470 /* Skip any non HCAPI cfg elements */
471 if (parms->cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI ||
472 parms->cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI_BA) {
473 /* Only perform reservation for entries that
476 if (parms->alloc_cnt[i] == 0)
479 /* Verify that we can get the full amount
480 * allocated per the qcaps availability.
482 if (parms->alloc_cnt[i] <=
483 query[parms->cfg[i].hcapi_type].max) {
484 req[j].type = parms->cfg[i].hcapi_type;
485 req[j].min = parms->alloc_cnt[i];
486 req[j].max = parms->alloc_cnt[i];
490 "%s: Resource failure, type:%d\n",
491 tf_dir_2_str(parms->dir),
492 parms->cfg[i].hcapi_type);
494 "req:%d, avail:%d\n",
496 query[parms->cfg[i].hcapi_type].max);
502 rc = tf_msg_session_resc_alloc(tfp,
511 /* Build the RM DB per the request */
513 cparms.size = sizeof(struct tf_rm_new_db);
514 rc = tfp_calloc(&cparms);
517 rm_db = (void *)cparms.mem_va;
519 /* Build the DB within RM DB */
520 cparms.nitems = parms->num_elements;
521 cparms.size = sizeof(struct tf_rm_element);
522 rc = tfp_calloc(&cparms);
525 rm_db->db = (struct tf_rm_element *)cparms.mem_va;
528 for (i = 0, j = 0; i < parms->num_elements; i++) {
529 db[i].cfg_type = parms->cfg[i].cfg_type;
530 db[i].hcapi_type = parms->cfg[i].hcapi_type;
532 /* Skip any non HCAPI types as we didn't include them
533 * in the reservation request.
535 if (parms->cfg[i].cfg_type != TF_RM_ELEM_CFG_HCAPI &&
536 parms->cfg[i].cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
539 /* If the element didn't request an allocation no need
540 * to create a pool nor verify if we got a reservation.
542 if (parms->alloc_cnt[i] == 0)
545 /* If the element had requested an allocation and that
546 * allocation was a success (full amount) then
549 if (parms->alloc_cnt[i] == resv[j].stride) {
550 db[i].alloc.entry.start = resv[j].start;
551 db[i].alloc.entry.stride = resv[j].stride;
553 /* Only allocate BA pool if so requested */
554 if (parms->cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI_BA) {
556 pool_size = (BITALLOC_SIZEOF(resv[j].stride) /
557 sizeof(struct bitalloc));
558 /* Alloc request, alignment already set */
559 cparms.nitems = pool_size;
560 cparms.size = sizeof(struct bitalloc);
561 rc = tfp_calloc(&cparms);
564 "%s: Pool alloc failed, type:%d\n",
565 tf_dir_2_str(parms->dir),
569 db[i].pool = (struct bitalloc *)cparms.mem_va;
571 rc = ba_init(db[i].pool, resv[j].stride);
574 "%s: Pool init failed, type:%d\n",
575 tf_dir_2_str(parms->dir),
582 /* Bail out as we want what we requested for
583 * all elements, not any less.
586 "%s: Alloc failed, type:%d\n",
587 tf_dir_2_str(parms->dir),
590 "req:%d, alloc:%d\n",
597 rm_db->num_entries = parms->num_elements;
598 rm_db->dir = parms->dir;
599 rm_db->type = parms->type;
600 *parms->rm_db = (void *)rm_db;
602 tfp_free((void *)req);
603 tfp_free((void *)resv);
608 tfp_free((void *)req);
609 tfp_free((void *)resv);
610 tfp_free((void *)db->pool);
611 tfp_free((void *)db);
612 tfp_free((void *)rm_db);
619 tf_rm_free_db(struct tf *tfp,
620 struct tf_rm_free_db_parms *parms)
624 uint16_t resv_size = 0;
625 struct tf_rm_new_db *rm_db;
626 struct tf_rm_resc_entry *resv;
627 bool residuals_found = false;
629 TF_CHECK_PARMS2(parms, parms->rm_db);
631 /* Device unbind happens when the TF Session is closed and the
632 * session ref count is 0. Device unbind will cleanup each of
633 * its support modules, i.e. Identifier, thus we're ending up
634 * here to close the DB.
636 * On TF Session close it is assumed that the session has already
637 * cleaned up all its resources, individually, while
638 * destroying its flows.
640 * To assist in the 'cleanup checking' the DB is checked for any
641 * remaining elements and logged if found to be the case.
643 * Any such elements will need to be 'cleared' ahead of
644 * returning the resources to the HCAPI RM.
646 * RM will signal FW to flush the DB resources. FW will
647 * perform the invalidation. TF Session close will return the
648 * previous allocated elements to the RM and then close the
649 * HCAPI RM registration. That then saves several 'free' msgs
650 * from being required.
653 rm_db = (struct tf_rm_new_db *)parms->rm_db;
655 /* Check for residuals that the client didn't clean up */
656 rc = tf_rm_check_residuals(rm_db,
663 /* Invalidate any residuals followed by a DB traversal for
666 if (residuals_found) {
667 rc = tf_msg_session_resc_flush(tfp,
671 tfp_free((void *)resv);
672 /* On failure we still have to cleanup so we can only
673 * log that FW failed.
677 "%s: Internal Flush error, module:%s\n",
678 tf_dir_2_str(parms->dir),
679 tf_device_module_type_2_str(rm_db->type));
682 /* No need to check for configuration type, even if we do not
683 * have a BA pool we just delete on a null ptr, no harm
685 for (i = 0; i < rm_db->num_entries; i++)
686 tfp_free((void *)rm_db->db[i].pool);
688 tfp_free((void *)parms->rm_db);
694 tf_rm_allocate(struct tf_rm_allocate_parms *parms)
699 struct tf_rm_new_db *rm_db;
700 enum tf_rm_elem_cfg_type cfg_type;
702 TF_CHECK_PARMS2(parms, parms->rm_db);
704 rm_db = (struct tf_rm_new_db *)parms->rm_db;
707 cfg_type = rm_db->db[parms->db_index].cfg_type;
709 /* Bail out if not controlled by RM */
710 if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
713 /* Bail out if the pool is not valid, should never happen */
714 if (rm_db->db[parms->db_index].pool == NULL) {
717 "%s: Invalid pool for this type:%d, rc:%s\n",
718 tf_dir_2_str(rm_db->dir),
725 * priority 0: allocate from top of the tcam i.e. high
726 * priority !0: allocate index from bottom i.e lowest
729 id = ba_alloc_reverse(rm_db->db[parms->db_index].pool);
731 id = ba_alloc(rm_db->db[parms->db_index].pool);
735 "%s: Allocation failed, rc:%s\n",
736 tf_dir_2_str(rm_db->dir),
741 /* Adjust for any non zero start value */
742 rc = tf_rm_adjust_index(rm_db->db,
743 TF_RM_ADJUST_ADD_BASE,
749 "%s: Alloc adjust of base index failed, rc:%s\n",
750 tf_dir_2_str(rm_db->dir),
755 *parms->index = index;
756 if (parms->base_index)
757 *parms->base_index = id;
763 tf_rm_free(struct tf_rm_free_parms *parms)
767 struct tf_rm_new_db *rm_db;
768 enum tf_rm_elem_cfg_type cfg_type;
770 TF_CHECK_PARMS2(parms, parms->rm_db);
772 rm_db = (struct tf_rm_new_db *)parms->rm_db;
775 cfg_type = rm_db->db[parms->db_index].cfg_type;
777 /* Bail out if not controlled by RM */
778 if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
781 /* Bail out if the pool is not valid, should never happen */
782 if (rm_db->db[parms->db_index].pool == NULL) {
785 "%s: Invalid pool for this type:%d, rc:%s\n",
786 tf_dir_2_str(rm_db->dir),
792 /* Adjust for any non zero start value */
793 rc = tf_rm_adjust_index(rm_db->db,
794 TF_RM_ADJUST_RM_BASE,
801 rc = ba_free(rm_db->db[parms->db_index].pool, adj_index);
802 /* No logging direction matters and that is not available here */
810 tf_rm_is_allocated(struct tf_rm_is_allocated_parms *parms)
814 struct tf_rm_new_db *rm_db;
815 enum tf_rm_elem_cfg_type cfg_type;
817 TF_CHECK_PARMS2(parms, parms->rm_db);
819 rm_db = (struct tf_rm_new_db *)parms->rm_db;
822 cfg_type = rm_db->db[parms->db_index].cfg_type;
824 /* Bail out if not controlled by RM */
825 if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
828 /* Bail out if the pool is not valid, should never happen */
829 if (rm_db->db[parms->db_index].pool == NULL) {
832 "%s: Invalid pool for this type:%d, rc:%s\n",
833 tf_dir_2_str(rm_db->dir),
839 /* Adjust for any non zero start value */
840 rc = tf_rm_adjust_index(rm_db->db,
841 TF_RM_ADJUST_RM_BASE,
848 if (parms->base_index)
849 *parms->base_index = adj_index;
850 *parms->allocated = ba_inuse(rm_db->db[parms->db_index].pool,
857 tf_rm_get_info(struct tf_rm_get_alloc_info_parms *parms)
859 struct tf_rm_new_db *rm_db;
860 enum tf_rm_elem_cfg_type cfg_type;
862 TF_CHECK_PARMS2(parms, parms->rm_db);
864 rm_db = (struct tf_rm_new_db *)parms->rm_db;
867 cfg_type = rm_db->db[parms->db_index].cfg_type;
869 /* Bail out if not controlled by HCAPI */
870 if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
871 cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
875 &rm_db->db[parms->db_index].alloc,
876 sizeof(struct tf_rm_alloc_info));
882 tf_rm_get_hcapi_type(struct tf_rm_get_hcapi_parms *parms)
884 struct tf_rm_new_db *rm_db;
885 enum tf_rm_elem_cfg_type cfg_type;
887 TF_CHECK_PARMS2(parms, parms->rm_db);
889 rm_db = (struct tf_rm_new_db *)parms->rm_db;
892 cfg_type = rm_db->db[parms->db_index].cfg_type;
894 /* Bail out if not controlled by HCAPI */
895 if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
896 cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
899 *parms->hcapi_type = rm_db->db[parms->db_index].hcapi_type;
905 tf_rm_get_inuse_count(struct tf_rm_get_inuse_count_parms *parms)
908 struct tf_rm_new_db *rm_db;
909 enum tf_rm_elem_cfg_type cfg_type;
911 TF_CHECK_PARMS2(parms, parms->rm_db);
913 rm_db = (struct tf_rm_new_db *)parms->rm_db;
916 cfg_type = rm_db->db[parms->db_index].cfg_type;
918 /* Bail out if not controlled by RM */
919 if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
922 /* Bail silently (no logging), if the pool is not valid there
923 * was no elements allocated for it.
925 if (rm_db->db[parms->db_index].pool == NULL) {
930 *parms->count = ba_inuse_count(rm_db->db[parms->db_index].pool);
937 tf_rm_check_indexes_in_range(struct tf_rm_check_indexes_in_range_parms *parms)
939 struct tf_rm_new_db *rm_db;
940 enum tf_rm_elem_cfg_type cfg_type;
945 TF_CHECK_PARMS2(parms, parms->rm_db);
947 rm_db = (struct tf_rm_new_db *)parms->rm_db;
950 cfg_type = rm_db->db[parms->db_index].cfg_type;
952 /* Bail out if not controlled by RM */
953 if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
956 /* Bail out if the pool is not valid, should never happen */
957 if (rm_db->db[parms->db_index].pool == NULL) {
960 "%s: Invalid pool for this type:%d, rc:%s\n",
961 tf_dir_2_str(rm_db->dir),
967 base_index = rm_db->db[parms->db_index].alloc.entry.start;
968 stride = rm_db->db[parms->db_index].alloc.entry.stride;
970 if (parms->starting_index < base_index ||
971 parms->starting_index + parms->num_entries > base_index + stride)