1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019-2020 Broadcom
3 * All rights reserved.
4 */
5
6 #include <string.h>
7
8 #include <rte_common.h>
9
10 #include <cfa_resource_types.h>
11
12 #include "tf_rm.h"
13 #include "tf_common.h"
14 #include "tf_util.h"
15 #include "tf_session.h"
16 #include "tf_device.h"
17 #include "tfp.h"
18 #include "tf_msg.h"
19
20 /* Logging defines */
21 #define TF_RM_DEBUG 0
22
23 /**
24 * Generic RM Element data type that an RM DB is build upon.
25 */
26 struct tf_rm_element {
27 /**
28 * RM Element configuration type. If Private then the
29 * hcapi_type can be ignored. If Null then the element is not
30 * valid for the device.
31 */
32 enum tf_rm_elem_cfg_type cfg_type;
33
34 /**
35 * HCAPI RM Type for the element.
36 */
37 uint16_t hcapi_type;
38
39 /**
40 * HCAPI RM allocated range information for the element.
41 */
42 struct tf_rm_alloc_info alloc;
43
44 /**
45 * Bit allocator pool for the element. Pool size is controlled
46 * by the struct tf_session_resources at time of session creation.
47 * Null indicates that the element is not used for the device.
48 */
49 struct bitalloc *pool;
50 };
51
52 /**
53 * TF RM DB definition
54 */
55 struct tf_rm_new_db {
56 /**
57 * Number of elements in the DB
58 */
59 uint16_t num_entries;
60
61 /**
62 * Direction this DB controls.
63 */
64 enum tf_dir dir;
65
66 /**
67 * Module type, used for logging purposes.
68 */
69 enum tf_device_module_type type;
70
71 /**
72 * The DB consists of an array of elements
73 */
74 struct tf_rm_element *db;
75 };
76
77 /**
78 * Adjust an index according to the allocation information.
79 *
80 * All resources are controlled in a 0 based pool. Some resources, by
81 * design, are not 0 based, i.e. Full Action Records (SRAM) thus they
82 * need to be adjusted before they are handed out.
83 *
84 * [in] cfg
85 * Pointer to the DB configuration
86 *
87 * [in] reservations
88 * Pointer to the allocation values associated with the module
89 *
90 * [in] count
91 * Number of DB configuration elements
92 *
93 * [out] valid_count
94 * Number of HCAPI entries with a reservation value greater than 0
95 *
96 * Returns:
97 * 0 - Success
98 * - EOPNOTSUPP - Operation not supported
99 */
100 static void
tf_rm_count_hcapi_reservations(enum tf_dir dir,enum tf_device_module_type type,struct tf_rm_element_cfg * cfg,uint16_t * reservations,uint16_t count,uint16_t * valid_count)101 tf_rm_count_hcapi_reservations(enum tf_dir dir,
102 enum tf_device_module_type type,
103 struct tf_rm_element_cfg *cfg,
104 uint16_t *reservations,
105 uint16_t count,
106 uint16_t *valid_count)
107 {
108 int i;
109 uint16_t cnt = 0;
110
111 for (i = 0; i < count; i++) {
112 if ((cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI ||
113 cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI_BA) &&
114 reservations[i] > 0)
115 cnt++;
116
117 /* Only log msg if a type is attempted reserved and
118 * not supported. We ignore EM module as its using a
119 * split configuration array thus it would fail for
120 * this type of check.
121 */
122 if (type != TF_DEVICE_MODULE_TYPE_EM &&
123 cfg[i].cfg_type == TF_RM_ELEM_CFG_NULL &&
124 reservations[i] > 0) {
125 TFP_DRV_LOG(ERR,
126 "%s, %s, %s allocation of %d not supported\n",
127 tf_device_module_type_2_str(type),
128 tf_dir_2_str(dir),
129 tf_device_module_type_subtype_2_str(type, i),
130 reservations[i]);
131 }
132 }
133
134 *valid_count = cnt;
135 }
136
137 /**
138 * Resource Manager Adjust of base index definitions.
139 */
140 enum tf_rm_adjust_type {
141 TF_RM_ADJUST_ADD_BASE, /**< Adds base to the index */
142 TF_RM_ADJUST_RM_BASE /**< Removes base from the index */
143 };
144
145 /**
146 * Adjust an index according to the allocation information.
147 *
148 * All resources are controlled in a 0 based pool. Some resources, by
149 * design, are not 0 based, i.e. Full Action Records (SRAM) thus they
150 * need to be adjusted before they are handed out.
151 *
152 * [in] db
153 * Pointer to the db, used for the lookup
154 *
155 * [in] action
156 * Adjust action
157 *
158 * [in] db_index
159 * DB index for the element type
160 *
161 * [in] index
162 * Index to convert
163 *
164 * [out] adj_index
165 * Adjusted index
166 *
167 * Returns:
168 * 0 - Success
169 * - EOPNOTSUPP - Operation not supported
170 */
171 static int
tf_rm_adjust_index(struct tf_rm_element * db,enum tf_rm_adjust_type action,uint32_t db_index,uint32_t index,uint32_t * adj_index)172 tf_rm_adjust_index(struct tf_rm_element *db,
173 enum tf_rm_adjust_type action,
174 uint32_t db_index,
175 uint32_t index,
176 uint32_t *adj_index)
177 {
178 int rc = 0;
179 uint32_t base_index;
180
181 base_index = db[db_index].alloc.entry.start;
182
183 switch (action) {
184 case TF_RM_ADJUST_RM_BASE:
185 *adj_index = index - base_index;
186 break;
187 case TF_RM_ADJUST_ADD_BASE:
188 *adj_index = index + base_index;
189 break;
190 default:
191 return -EOPNOTSUPP;
192 }
193
194 return rc;
195 }
196
197 /**
198 * Logs an array of found residual entries to the console.
199 *
200 * [in] dir
201 * Receive or transmit direction
202 *
203 * [in] type
204 * Type of Device Module
205 *
206 * [in] count
207 * Number of entries in the residual array
208 *
209 * [in] residuals
210 * Pointer to an array of residual entries. Array is index same as
211 * the DB in which this function is used. Each entry holds residual
212 * value for that entry.
213 */
214 static void
tf_rm_log_residuals(enum tf_dir dir,enum tf_device_module_type type,uint16_t count,uint16_t * residuals)215 tf_rm_log_residuals(enum tf_dir dir,
216 enum tf_device_module_type type,
217 uint16_t count,
218 uint16_t *residuals)
219 {
220 int i;
221
222 /* Walk the residual array and log the types that wasn't
223 * cleaned up to the console.
224 */
225 for (i = 0; i < count; i++) {
226 if (residuals[i] != 0)
227 TFP_DRV_LOG(ERR,
228 "%s, %s was not cleaned up, %d outstanding\n",
229 tf_dir_2_str(dir),
230 tf_device_module_type_subtype_2_str(type, i),
231 residuals[i]);
232 }
233 }
234
235 /**
236 * Performs a check of the passed in DB for any lingering elements. If
237 * a resource type was found to not have been cleaned up by the caller
238 * then its residual values are recorded, logged and passed back in an
239 * allocate reservation array that the caller can pass to the FW for
240 * cleanup.
241 *
242 * [in] db
243 * Pointer to the db, used for the lookup
244 *
245 * [out] resv_size
246 * Pointer to the reservation size of the generated reservation
247 * array.
248 *
249 * [in/out] resv
250 * Pointer Pointer to a reservation array. The reservation array is
251 * allocated after the residual scan and holds any found residual
252 * entries. Thus it can be smaller than the DB that the check was
253 * performed on. Array must be freed by the caller.
254 *
255 * [out] residuals_present
256 * Pointer to a bool flag indicating if residual was present in the
257 * DB
258 *
259 * Returns:
260 * 0 - Success
261 * - EOPNOTSUPP - Operation not supported
262 */
263 static int
tf_rm_check_residuals(struct tf_rm_new_db * rm_db,uint16_t * resv_size,struct tf_rm_resc_entry ** resv,bool * residuals_present)264 tf_rm_check_residuals(struct tf_rm_new_db *rm_db,
265 uint16_t *resv_size,
266 struct tf_rm_resc_entry **resv,
267 bool *residuals_present)
268 {
269 int rc;
270 int i;
271 int f;
272 uint16_t count;
273 uint16_t found;
274 uint16_t *residuals = NULL;
275 uint16_t hcapi_type;
276 struct tf_rm_get_inuse_count_parms iparms;
277 struct tf_rm_get_alloc_info_parms aparms;
278 struct tf_rm_get_hcapi_parms hparms;
279 struct tf_rm_alloc_info info;
280 struct tfp_calloc_parms cparms;
281 struct tf_rm_resc_entry *local_resv = NULL;
282
283 /* Create array to hold the entries that have residuals */
284 cparms.nitems = rm_db->num_entries;
285 cparms.size = sizeof(uint16_t);
286 cparms.alignment = 0;
287 rc = tfp_calloc(&cparms);
288 if (rc)
289 return rc;
290
291 residuals = (uint16_t *)cparms.mem_va;
292
293 /* Traverse the DB and collect any residual elements */
294 iparms.rm_db = rm_db;
295 iparms.count = &count;
296 for (i = 0, found = 0; i < rm_db->num_entries; i++) {
297 iparms.db_index = i;
298 rc = tf_rm_get_inuse_count(&iparms);
299 /* Not a device supported entry, just skip */
300 if (rc == -ENOTSUP)
301 continue;
302 if (rc)
303 goto cleanup_residuals;
304
305 if (count) {
306 found++;
307 residuals[i] = count;
308 *residuals_present = true;
309 }
310 }
311
312 if (*residuals_present) {
313 /* Populate a reduced resv array with only the entries
314 * that have residuals.
315 */
316 cparms.nitems = found;
317 cparms.size = sizeof(struct tf_rm_resc_entry);
318 cparms.alignment = 0;
319 rc = tfp_calloc(&cparms);
320 if (rc)
321 return rc;
322
323 local_resv = (struct tf_rm_resc_entry *)cparms.mem_va;
324
325 aparms.rm_db = rm_db;
326 hparms.rm_db = rm_db;
327 hparms.hcapi_type = &hcapi_type;
328 for (i = 0, f = 0; i < rm_db->num_entries; i++) {
329 if (residuals[i] == 0)
330 continue;
331 aparms.db_index = i;
332 aparms.info = &info;
333 rc = tf_rm_get_info(&aparms);
334 if (rc)
335 goto cleanup_all;
336
337 hparms.db_index = i;
338 rc = tf_rm_get_hcapi_type(&hparms);
339 if (rc)
340 goto cleanup_all;
341
342 local_resv[f].type = hcapi_type;
343 local_resv[f].start = info.entry.start;
344 local_resv[f].stride = info.entry.stride;
345 f++;
346 }
347 *resv_size = found;
348 }
349
350 tf_rm_log_residuals(rm_db->dir,
351 rm_db->type,
352 rm_db->num_entries,
353 residuals);
354
355 tfp_free((void *)residuals);
356 *resv = local_resv;
357
358 return 0;
359
360 cleanup_all:
361 tfp_free((void *)local_resv);
362 *resv = NULL;
363 cleanup_residuals:
364 tfp_free((void *)residuals);
365
366 return rc;
367 }
368
369 int
tf_rm_create_db(struct tf * tfp,struct tf_rm_create_db_parms * parms)370 tf_rm_create_db(struct tf *tfp,
371 struct tf_rm_create_db_parms *parms)
372 {
373 int rc;
374 int i;
375 int j;
376 struct tf_session *tfs;
377 struct tf_dev_info *dev;
378 uint16_t max_types;
379 struct tfp_calloc_parms cparms;
380 struct tf_rm_resc_req_entry *query;
381 enum tf_rm_resc_resv_strategy resv_strategy;
382 struct tf_rm_resc_req_entry *req;
383 struct tf_rm_resc_entry *resv;
384 struct tf_rm_new_db *rm_db;
385 struct tf_rm_element *db;
386 uint32_t pool_size;
387 uint16_t hcapi_items;
388
389 TF_CHECK_PARMS2(tfp, parms);
390
391 /* Retrieve the session information */
392 rc = tf_session_get_session_internal(tfp, &tfs);
393 if (rc)
394 return rc;
395
396 /* Retrieve device information */
397 rc = tf_session_get_device(tfs, &dev);
398 if (rc)
399 return rc;
400
401 /* Need device max number of elements for the RM QCAPS */
402 rc = dev->ops->tf_dev_get_max_types(tfp, &max_types);
403 if (rc)
404 return rc;
405
406 cparms.nitems = max_types;
407 cparms.size = sizeof(struct tf_rm_resc_req_entry);
408 cparms.alignment = 0;
409 rc = tfp_calloc(&cparms);
410 if (rc)
411 return rc;
412
413 query = (struct tf_rm_resc_req_entry *)cparms.mem_va;
414
415 /* Get Firmware Capabilities */
416 rc = tf_msg_session_resc_qcaps(tfp,
417 parms->dir,
418 max_types,
419 query,
420 &resv_strategy);
421 if (rc)
422 return rc;
423
424 /* Process capabilities against DB requirements. However, as a
425 * DB can hold elements that are not HCAPI we can reduce the
426 * req msg content by removing those out of the request yet
427 * the DB holds them all as to give a fast lookup. We can also
428 * remove entries where there are no request for elements.
429 */
430 tf_rm_count_hcapi_reservations(parms->dir,
431 parms->type,
432 parms->cfg,
433 parms->alloc_cnt,
434 parms->num_elements,
435 &hcapi_items);
436
437 /* Handle the case where a DB create request really ends up
438 * being empty. Unsupported (if not rare) case but possible
439 * that no resources are necessary for a 'direction'.
440 */
441 if (hcapi_items == 0) {
442 TFP_DRV_LOG(ERR,
443 "%s: DB create request for Zero elements, DB Type:%s\n",
444 tf_dir_2_str(parms->dir),
445 tf_device_module_type_2_str(parms->type));
446
447 parms->rm_db = NULL;
448 return -ENOMEM;
449 }
450
451 /* Alloc request, alignment already set */
452 cparms.nitems = (size_t)hcapi_items;
453 cparms.size = sizeof(struct tf_rm_resc_req_entry);
454 rc = tfp_calloc(&cparms);
455 if (rc)
456 return rc;
457 req = (struct tf_rm_resc_req_entry *)cparms.mem_va;
458
459 /* Alloc reservation, alignment and nitems already set */
460 cparms.size = sizeof(struct tf_rm_resc_entry);
461 rc = tfp_calloc(&cparms);
462 if (rc)
463 return rc;
464 resv = (struct tf_rm_resc_entry *)cparms.mem_va;
465
466 /* Build the request */
467 for (i = 0, j = 0; i < parms->num_elements; i++) {
468 /* Skip any non HCAPI cfg elements */
469 if (parms->cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI ||
470 parms->cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI_BA) {
471 /* Only perform reservation for entries that
472 * has been requested
473 */
474 if (parms->alloc_cnt[i] == 0)
475 continue;
476
477 /* Verify that we can get the full amount
478 * allocated per the qcaps availability.
479 */
480 if (parms->alloc_cnt[i] <=
481 query[parms->cfg[i].hcapi_type].max) {
482 req[j].type = parms->cfg[i].hcapi_type;
483 req[j].min = parms->alloc_cnt[i];
484 req[j].max = parms->alloc_cnt[i];
485 j++;
486 } else {
487 TFP_DRV_LOG(ERR,
488 "%s: Resource failure, type:%d\n",
489 tf_dir_2_str(parms->dir),
490 parms->cfg[i].hcapi_type);
491 TFP_DRV_LOG(ERR,
492 "req:%d, avail:%d\n",
493 parms->alloc_cnt[i],
494 query[parms->cfg[i].hcapi_type].max);
495 return -EINVAL;
496 }
497 }
498 }
499
500 rc = tf_msg_session_resc_alloc(tfp,
501 parms->dir,
502 hcapi_items,
503 req,
504 resv);
505 if (rc)
506 return rc;
507
508 /* Build the RM DB per the request */
509 cparms.nitems = 1;
510 cparms.size = sizeof(struct tf_rm_new_db);
511 rc = tfp_calloc(&cparms);
512 if (rc)
513 return rc;
514 rm_db = (void *)cparms.mem_va;
515
516 /* Build the DB within RM DB */
517 cparms.nitems = parms->num_elements;
518 cparms.size = sizeof(struct tf_rm_element);
519 rc = tfp_calloc(&cparms);
520 if (rc)
521 return rc;
522 rm_db->db = (struct tf_rm_element *)cparms.mem_va;
523
524 db = rm_db->db;
525 for (i = 0, j = 0; i < parms->num_elements; i++) {
526 db[i].cfg_type = parms->cfg[i].cfg_type;
527 db[i].hcapi_type = parms->cfg[i].hcapi_type;
528
529 /* Skip any non HCAPI types as we didn't include them
530 * in the reservation request.
531 */
532 if (parms->cfg[i].cfg_type != TF_RM_ELEM_CFG_HCAPI &&
533 parms->cfg[i].cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
534 continue;
535
536 /* If the element didn't request an allocation no need
537 * to create a pool nor verify if we got a reservation.
538 */
539 if (parms->alloc_cnt[i] == 0)
540 continue;
541
542 /* If the element had requested an allocation and that
543 * allocation was a success (full amount) then
544 * allocate the pool.
545 */
546 if (parms->alloc_cnt[i] == resv[j].stride) {
547 db[i].alloc.entry.start = resv[j].start;
548 db[i].alloc.entry.stride = resv[j].stride;
549
550 /* Only allocate BA pool if so requested */
551 if (parms->cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI_BA) {
552 /* Create pool */
553 pool_size = (BITALLOC_SIZEOF(resv[j].stride) /
554 sizeof(struct bitalloc));
555 /* Alloc request, alignment already set */
556 cparms.nitems = pool_size;
557 cparms.size = sizeof(struct bitalloc);
558 rc = tfp_calloc(&cparms);
559 if (rc) {
560 TFP_DRV_LOG(ERR,
561 "%s: Pool alloc failed, type:%d\n",
562 tf_dir_2_str(parms->dir),
563 db[i].cfg_type);
564 goto fail;
565 }
566 db[i].pool = (struct bitalloc *)cparms.mem_va;
567
568 rc = ba_init(db[i].pool, resv[j].stride);
569 if (rc) {
570 TFP_DRV_LOG(ERR,
571 "%s: Pool init failed, type:%d\n",
572 tf_dir_2_str(parms->dir),
573 db[i].cfg_type);
574 goto fail;
575 }
576 }
577 j++;
578 } else {
579 /* Bail out as we want what we requested for
580 * all elements, not any less.
581 */
582 TFP_DRV_LOG(ERR,
583 "%s: Alloc failed, type:%d\n",
584 tf_dir_2_str(parms->dir),
585 db[i].cfg_type);
586 TFP_DRV_LOG(ERR,
587 "req:%d, alloc:%d\n",
588 parms->alloc_cnt[i],
589 resv[j].stride);
590 goto fail;
591 }
592 }
593
594 rm_db->num_entries = parms->num_elements;
595 rm_db->dir = parms->dir;
596 rm_db->type = parms->type;
597 *parms->rm_db = (void *)rm_db;
598
599 #if (TF_RM_DEBUG == 1)
600 printf("%s: type:%d num_entries:%d\n",
601 tf_dir_2_str(parms->dir),
602 parms->type,
603 i);
604 #endif /* (TF_RM_DEBUG == 1) */
605
606 tfp_free((void *)req);
607 tfp_free((void *)resv);
608
609 return 0;
610
611 fail:
612 tfp_free((void *)req);
613 tfp_free((void *)resv);
614 tfp_free((void *)db->pool);
615 tfp_free((void *)db);
616 tfp_free((void *)rm_db);
617 parms->rm_db = NULL;
618
619 return -EINVAL;
620 }
621
622 int
tf_rm_free_db(struct tf * tfp,struct tf_rm_free_db_parms * parms)623 tf_rm_free_db(struct tf *tfp,
624 struct tf_rm_free_db_parms *parms)
625 {
626 int rc;
627 int i;
628 uint16_t resv_size = 0;
629 struct tf_rm_new_db *rm_db;
630 struct tf_rm_resc_entry *resv;
631 bool residuals_found = false;
632
633 TF_CHECK_PARMS2(parms, parms->rm_db);
634
635 /* Device unbind happens when the TF Session is closed and the
636 * session ref count is 0. Device unbind will cleanup each of
637 * its support modules, i.e. Identifier, thus we're ending up
638 * here to close the DB.
639 *
640 * On TF Session close it is assumed that the session has already
641 * cleaned up all its resources, individually, while
642 * destroying its flows.
643 *
644 * To assist in the 'cleanup checking' the DB is checked for any
645 * remaining elements and logged if found to be the case.
646 *
647 * Any such elements will need to be 'cleared' ahead of
648 * returning the resources to the HCAPI RM.
649 *
650 * RM will signal FW to flush the DB resources. FW will
651 * perform the invalidation. TF Session close will return the
652 * previous allocated elements to the RM and then close the
653 * HCAPI RM registration. That then saves several 'free' msgs
654 * from being required.
655 */
656
657 rm_db = (struct tf_rm_new_db *)parms->rm_db;
658
659 /* Check for residuals that the client didn't clean up */
660 rc = tf_rm_check_residuals(rm_db,
661 &resv_size,
662 &resv,
663 &residuals_found);
664 if (rc)
665 return rc;
666
667 /* Invalidate any residuals followed by a DB traversal for
668 * pool cleanup.
669 */
670 if (residuals_found) {
671 rc = tf_msg_session_resc_flush(tfp,
672 parms->dir,
673 resv_size,
674 resv);
675 tfp_free((void *)resv);
676 /* On failure we still have to cleanup so we can only
677 * log that FW failed.
678 */
679 if (rc)
680 TFP_DRV_LOG(ERR,
681 "%s: Internal Flush error, module:%s\n",
682 tf_dir_2_str(parms->dir),
683 tf_device_module_type_2_str(rm_db->type));
684 }
685
686 /* No need to check for configuration type, even if we do not
687 * have a BA pool we just delete on a null ptr, no harm
688 */
689 for (i = 0; i < rm_db->num_entries; i++)
690 tfp_free((void *)rm_db->db[i].pool);
691
692 tfp_free((void *)parms->rm_db);
693
694 return rc;
695 }
696
697 int
tf_rm_allocate(struct tf_rm_allocate_parms * parms)698 tf_rm_allocate(struct tf_rm_allocate_parms *parms)
699 {
700 int rc;
701 int id;
702 uint32_t index;
703 struct tf_rm_new_db *rm_db;
704 enum tf_rm_elem_cfg_type cfg_type;
705
706 TF_CHECK_PARMS2(parms, parms->rm_db);
707
708 rm_db = (struct tf_rm_new_db *)parms->rm_db;
709 if (!rm_db->db)
710 return -EINVAL;
711 cfg_type = rm_db->db[parms->db_index].cfg_type;
712
713 /* Bail out if not controlled by RM */
714 if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
715 return -ENOTSUP;
716
717 /* Bail out if the pool is not valid, should never happen */
718 if (rm_db->db[parms->db_index].pool == NULL) {
719 rc = -ENOTSUP;
720 TFP_DRV_LOG(ERR,
721 "%s: Invalid pool for this type:%d, rc:%s\n",
722 tf_dir_2_str(rm_db->dir),
723 parms->db_index,
724 strerror(-rc));
725 return rc;
726 }
727
728 /*
729 * priority 0: allocate from top of the tcam i.e. high
730 * priority !0: allocate index from bottom i.e lowest
731 */
732 if (parms->priority)
733 id = ba_alloc_reverse(rm_db->db[parms->db_index].pool);
734 else
735 id = ba_alloc(rm_db->db[parms->db_index].pool);
736 if (id == BA_FAIL) {
737 rc = -ENOMEM;
738 TFP_DRV_LOG(ERR,
739 "%s: Allocation failed, rc:%s\n",
740 tf_dir_2_str(rm_db->dir),
741 strerror(-rc));
742 return rc;
743 }
744
745 /* Adjust for any non zero start value */
746 rc = tf_rm_adjust_index(rm_db->db,
747 TF_RM_ADJUST_ADD_BASE,
748 parms->db_index,
749 id,
750 &index);
751 if (rc) {
752 TFP_DRV_LOG(ERR,
753 "%s: Alloc adjust of base index failed, rc:%s\n",
754 tf_dir_2_str(rm_db->dir),
755 strerror(-rc));
756 return -EINVAL;
757 }
758
759 *parms->index = index;
760 if (parms->base_index)
761 *parms->base_index = id;
762
763 return rc;
764 }
765
766 int
tf_rm_free(struct tf_rm_free_parms * parms)767 tf_rm_free(struct tf_rm_free_parms *parms)
768 {
769 int rc;
770 uint32_t adj_index;
771 struct tf_rm_new_db *rm_db;
772 enum tf_rm_elem_cfg_type cfg_type;
773
774 TF_CHECK_PARMS2(parms, parms->rm_db);
775
776 rm_db = (struct tf_rm_new_db *)parms->rm_db;
777 if (!rm_db->db)
778 return -EINVAL;
779 cfg_type = rm_db->db[parms->db_index].cfg_type;
780
781 /* Bail out if not controlled by RM */
782 if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
783 return -ENOTSUP;
784
785 /* Bail out if the pool is not valid, should never happen */
786 if (rm_db->db[parms->db_index].pool == NULL) {
787 rc = -ENOTSUP;
788 TFP_DRV_LOG(ERR,
789 "%s: Invalid pool for this type:%d, rc:%s\n",
790 tf_dir_2_str(rm_db->dir),
791 parms->db_index,
792 strerror(-rc));
793 return rc;
794 }
795
796 /* Adjust for any non zero start value */
797 rc = tf_rm_adjust_index(rm_db->db,
798 TF_RM_ADJUST_RM_BASE,
799 parms->db_index,
800 parms->index,
801 &adj_index);
802 if (rc)
803 return rc;
804
805 rc = ba_free(rm_db->db[parms->db_index].pool, adj_index);
806 /* No logging direction matters and that is not available here */
807 if (rc)
808 return rc;
809
810 return rc;
811 }
812
813 int
tf_rm_is_allocated(struct tf_rm_is_allocated_parms * parms)814 tf_rm_is_allocated(struct tf_rm_is_allocated_parms *parms)
815 {
816 int rc;
817 uint32_t adj_index;
818 struct tf_rm_new_db *rm_db;
819 enum tf_rm_elem_cfg_type cfg_type;
820
821 TF_CHECK_PARMS2(parms, parms->rm_db);
822
823 rm_db = (struct tf_rm_new_db *)parms->rm_db;
824 if (!rm_db->db)
825 return -EINVAL;
826 cfg_type = rm_db->db[parms->db_index].cfg_type;
827
828 /* Bail out if not controlled by RM */
829 if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
830 return -ENOTSUP;
831
832 /* Bail out if the pool is not valid, should never happen */
833 if (rm_db->db[parms->db_index].pool == NULL) {
834 rc = -ENOTSUP;
835 TFP_DRV_LOG(ERR,
836 "%s: Invalid pool for this type:%d, rc:%s\n",
837 tf_dir_2_str(rm_db->dir),
838 parms->db_index,
839 strerror(-rc));
840 return rc;
841 }
842
843 /* Adjust for any non zero start value */
844 rc = tf_rm_adjust_index(rm_db->db,
845 TF_RM_ADJUST_RM_BASE,
846 parms->db_index,
847 parms->index,
848 &adj_index);
849 if (rc)
850 return rc;
851
852 if (parms->base_index)
853 *parms->base_index = adj_index;
854 *parms->allocated = ba_inuse(rm_db->db[parms->db_index].pool,
855 adj_index);
856
857 return rc;
858 }
859
860 int
tf_rm_get_info(struct tf_rm_get_alloc_info_parms * parms)861 tf_rm_get_info(struct tf_rm_get_alloc_info_parms *parms)
862 {
863 struct tf_rm_new_db *rm_db;
864 enum tf_rm_elem_cfg_type cfg_type;
865
866 TF_CHECK_PARMS2(parms, parms->rm_db);
867
868 rm_db = (struct tf_rm_new_db *)parms->rm_db;
869 if (!rm_db->db)
870 return -EINVAL;
871 cfg_type = rm_db->db[parms->db_index].cfg_type;
872
873 /* Bail out if not controlled by HCAPI */
874 if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
875 cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
876 return -ENOTSUP;
877
878 memcpy(parms->info,
879 &rm_db->db[parms->db_index].alloc,
880 sizeof(struct tf_rm_alloc_info));
881
882 return 0;
883 }
884
885 int
tf_rm_get_hcapi_type(struct tf_rm_get_hcapi_parms * parms)886 tf_rm_get_hcapi_type(struct tf_rm_get_hcapi_parms *parms)
887 {
888 struct tf_rm_new_db *rm_db;
889 enum tf_rm_elem_cfg_type cfg_type;
890
891 TF_CHECK_PARMS2(parms, parms->rm_db);
892
893 rm_db = (struct tf_rm_new_db *)parms->rm_db;
894 if (!rm_db->db)
895 return -EINVAL;
896 cfg_type = rm_db->db[parms->db_index].cfg_type;
897
898 /* Bail out if not controlled by HCAPI */
899 if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
900 cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
901 return -ENOTSUP;
902
903 *parms->hcapi_type = rm_db->db[parms->db_index].hcapi_type;
904
905 return 0;
906 }
907
908 int
tf_rm_get_inuse_count(struct tf_rm_get_inuse_count_parms * parms)909 tf_rm_get_inuse_count(struct tf_rm_get_inuse_count_parms *parms)
910 {
911 int rc = 0;
912 struct tf_rm_new_db *rm_db;
913 enum tf_rm_elem_cfg_type cfg_type;
914
915 TF_CHECK_PARMS2(parms, parms->rm_db);
916
917 rm_db = (struct tf_rm_new_db *)parms->rm_db;
918 if (!rm_db->db)
919 return -EINVAL;
920 cfg_type = rm_db->db[parms->db_index].cfg_type;
921
922 /* Bail out if not controlled by RM */
923 if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
924 return -ENOTSUP;
925
926 /* Bail silently (no logging), if the pool is not valid there
927 * was no elements allocated for it.
928 */
929 if (rm_db->db[parms->db_index].pool == NULL) {
930 *parms->count = 0;
931 return 0;
932 }
933
934 *parms->count = ba_inuse_count(rm_db->db[parms->db_index].pool);
935
936 return rc;
937
938 }
939
940 int
tf_rm_check_indexes_in_range(struct tf_rm_check_indexes_in_range_parms * parms)941 tf_rm_check_indexes_in_range(struct tf_rm_check_indexes_in_range_parms *parms)
942 {
943 struct tf_rm_new_db *rm_db;
944 enum tf_rm_elem_cfg_type cfg_type;
945 uint32_t base_index;
946 uint32_t stride;
947 int rc = 0;
948
949 TF_CHECK_PARMS2(parms, parms->rm_db);
950
951 rm_db = (struct tf_rm_new_db *)parms->rm_db;
952 if (!rm_db->db)
953 return -EINVAL;
954 cfg_type = rm_db->db[parms->db_index].cfg_type;
955
956 /* Bail out if not controlled by RM */
957 if (cfg_type != TF_RM_ELEM_CFG_HCAPI_BA)
958 return -ENOTSUP;
959
960 /* Bail out if the pool is not valid, should never happen */
961 if (rm_db->db[parms->db_index].pool == NULL) {
962 rc = -ENOTSUP;
963 TFP_DRV_LOG(ERR,
964 "%s: Invalid pool for this type:%d, rc:%s\n",
965 tf_dir_2_str(rm_db->dir),
966 parms->db_index,
967 strerror(-rc));
968 return rc;
969 }
970
971 base_index = rm_db->db[parms->db_index].alloc.entry.start;
972 stride = rm_db->db[parms->db_index].alloc.entry.stride;
973
974 if (parms->starting_index < base_index ||
975 parms->starting_index + parms->num_entries > base_index + stride)
976 return -EINVAL;
977
978 return rc;
979 }
980