1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019-2021 Broadcom
7 #include "tf_sram_mgr.h"
10 #include "tf_common.h"
14 #if (STATS_CLEAR_ON_READ_SUPPORT == 0)
17 /***************************
18 * Internal Data Structures
19 ***************************/
24 * Contains all the information about a particular 64B SRAM
25 * block and the slices within it.
27 struct tf_sram_block {
30 struct tf_sram_block *prev;
33 struct tf_sram_block *next;
35 /** Bitmap indicating which slices are in use
36 * If a bit is set, it indicates the slice
37 * in the row is in use.
41 /** Block id - this is a 64B offset
49 * List of 64B SRAM blocks used for fixed size slices (8, 16, 32, 64B)
51 struct tf_sram_slice_list {
52 /** Pointer to head of linked list of blocks.
54 struct tf_sram_block *head;
56 /** Pointer to tail of linked list of blocks.
58 struct tf_sram_block *tail;
60 /** Total count of blocks
64 /** First non-full block in the list
66 struct tf_sram_block *first_not_full_block;
68 /** Entry slice size for this list
70 enum tf_sram_slice_size size;
75 * TF SRAM bank info consists of lists of different slice sizes per bank
77 struct tf_sram_bank_info {
78 struct tf_sram_slice_list slice[TF_SRAM_SLICE_SIZE_MAX];
82 * SRAM banks consist of SRAM bank information
85 struct tf_sram_bank_info bank[TF_SRAM_BANK_ID_MAX];
89 * SRAM banks consist of SRAM bank information
92 struct tf_sram_bank dir[TF_DIR_MAX];
95 /**********************
97 **********************/
100 * Get slice size in string format
103 *tf_sram_slice_2_str(enum tf_sram_slice_size slice_size)
105 switch (slice_size) {
106 case TF_SRAM_SLICE_SIZE_8B:
108 case TF_SRAM_SLICE_SIZE_16B:
110 case TF_SRAM_SLICE_SIZE_32B:
112 case TF_SRAM_SLICE_SIZE_64B:
115 return "Invalid slice size";
120 * Get bank in string format
123 *tf_sram_bank_2_str(enum tf_sram_bank_id bank_id)
126 case TF_SRAM_BANK_ID_0:
128 case TF_SRAM_BANK_ID_1:
130 case TF_SRAM_BANK_ID_2:
132 case TF_SRAM_BANK_ID_3:
135 return "Invalid bank_id";
140 * TF SRAM get slice list
143 tf_sram_get_slice_list(struct tf_sram *sram,
144 struct tf_sram_slice_list **slice_list,
145 enum tf_sram_slice_size slice_size,
147 enum tf_sram_bank_id bank_id)
151 TF_CHECK_PARMS2(sram, slice_list);
153 *slice_list = &sram->dir[dir].bank[bank_id].slice[slice_size];
158 uint16_t tf_sram_bank_2_base_offset[TF_SRAM_BANK_ID_MAX] = {
166 * Translate a block id and bank_id to an 8B offset
169 tf_sram_block_id_2_offset(enum tf_sram_bank_id bank_id, uint16_t block_id,
172 *offset = (block_id + tf_sram_bank_2_base_offset[bank_id]) << 3;
176 * Translates an 8B offset and bank_id to a block_id
179 tf_sram_offset_2_block_id(enum tf_sram_bank_id bank_id, uint16_t offset,
180 uint16_t *block_id, uint16_t *slice_offset)
182 *slice_offset = offset & 0x7;
183 *block_id = ((offset & ~0x7) >> 3) -
184 tf_sram_bank_2_base_offset[bank_id];
188 * Find a matching block_id within the slice list
190 static struct tf_sram_block
191 *tf_sram_find_block(uint16_t block_id, struct tf_sram_slice_list *slice_list)
194 struct tf_sram_block *block;
196 cnt = slice_list->cnt;
197 block = slice_list->head;
199 while (cnt > 0 && block) {
200 if (block->block_id == block_id)
209 * Given the current block get the next block within the slice list
211 * List is not changed.
213 static struct tf_sram_block
214 *tf_sram_get_next_block(struct tf_sram_block *block)
216 struct tf_sram_block *nblock;
219 nblock = block->next;
226 * Free an allocated slice from a block and if the block is empty,
227 * return an indication so that the block can be freed.
230 tf_sram_free_slice(enum tf_sram_slice_size slice_size,
231 uint16_t slice_offset, struct tf_sram_block *block,
232 bool *block_is_empty)
236 uint8_t slice_mask = 0;
238 TF_CHECK_PARMS2(block, block_is_empty);
240 switch (slice_size) {
241 case TF_SRAM_SLICE_SIZE_8B:
242 shift = slice_offset >> 0;
244 slice_mask = 1 << shift;
247 case TF_SRAM_SLICE_SIZE_16B:
248 shift = slice_offset >> 1;
250 slice_mask = 1 << shift;
253 case TF_SRAM_SLICE_SIZE_32B:
254 shift = slice_offset >> 2;
256 slice_mask = 1 << shift;
259 case TF_SRAM_SLICE_SIZE_64B:
261 shift = slice_offset >> 0;
263 slice_mask = 1 << shift;
267 if ((block->in_use_mask & slice_mask) == 0) {
269 TFP_DRV_LOG(ERR, "block_id(0x%x) slice(%d) was not allocated\n",
270 block->block_id, slice_offset);
274 block->in_use_mask &= ~slice_mask;
276 if (block->in_use_mask == 0)
277 *block_is_empty = true;
279 *block_is_empty = false;
285 * TF SRAM get next slice
287 * Gets the next slice_offset available in the block
288 * and updates the in_use_mask.
291 tf_sram_get_next_slice_in_block(struct tf_sram_block *block,
292 enum tf_sram_slice_size slice_size,
293 uint16_t *slice_offset,
296 int rc, free_id = -1;
297 uint8_t shift, max_slices, mask, i, full_mask;
299 TF_CHECK_PARMS3(block, slice_offset, block_is_full);
301 switch (slice_size) {
302 case TF_SRAM_SLICE_SIZE_8B:
307 case TF_SRAM_SLICE_SIZE_16B:
312 case TF_SRAM_SLICE_SIZE_32B:
317 case TF_SRAM_SLICE_SIZE_64B:
325 mask = block->in_use_mask;
327 for (i = 0; i < max_slices; i++) {
328 if ((mask & 1) == 0) {
330 block->in_use_mask |= 1 << free_id;
336 if (block->in_use_mask == full_mask)
337 *block_is_full = true;
339 *block_is_full = false;
343 *slice_offset = free_id << shift;
354 * TF SRAM get indication as to whether the slice offset is
355 * allocated in the block.
359 tf_sram_is_slice_allocated_in_block(struct tf_sram_block *block,
360 enum tf_sram_slice_size slice_size,
361 uint16_t slice_offset,
366 uint8_t slice_mask = 0;
368 TF_CHECK_PARMS2(block, is_allocated);
370 *is_allocated = false;
372 switch (slice_size) {
373 case TF_SRAM_SLICE_SIZE_8B:
374 shift = slice_offset >> 0;
376 slice_mask = 1 << shift;
379 case TF_SRAM_SLICE_SIZE_16B:
380 shift = slice_offset >> 1;
382 slice_mask = 1 << shift;
385 case TF_SRAM_SLICE_SIZE_32B:
386 shift = slice_offset >> 2;
388 slice_mask = 1 << shift;
391 case TF_SRAM_SLICE_SIZE_64B:
393 shift = slice_offset >> 0;
395 slice_mask = 1 << shift;
399 if ((block->in_use_mask & slice_mask) == 0) {
400 TFP_DRV_LOG(ERR, "block_id(0x%x) slice(%d) was not allocated\n",
401 block->block_id, slice_offset);
402 *is_allocated = false;
404 *is_allocated = true;
411 * Get the block count
414 tf_sram_get_block_cnt(struct tf_sram_slice_list *slice_list)
416 return slice_list->cnt;
421 * Free a block data structure - does not free to the RM
424 tf_sram_free_block(struct tf_sram_slice_list *slice_list,
425 struct tf_sram_block *block)
427 if (slice_list->head == block && slice_list->tail == block) {
428 slice_list->head = NULL;
429 slice_list->tail = NULL;
430 } else if (slice_list->head == block) {
431 slice_list->head = block->next;
432 slice_list->head->prev = NULL;
433 } else if (slice_list->tail == block) {
434 slice_list->tail = block->prev;
435 slice_list->tail->next = NULL;
437 block->prev->next = block->next;
438 block->next->prev = block->prev;
444 * Free the entire slice_list
447 tf_sram_free_slice_list(struct tf_sram_slice_list *slice_list)
449 uint32_t i, block_cnt;
450 struct tf_sram_block *nblock, *block;
452 block_cnt = tf_sram_get_block_cnt(slice_list);
453 block = slice_list->head;
455 for (i = 0; i < block_cnt; i++) {
456 nblock = block->next;
457 tf_sram_free_block(slice_list, block);
463 * Allocate a single SRAM block from memory and add it to the slice list
465 static struct tf_sram_block
466 *tf_sram_alloc_block(struct tf_sram_slice_list *slice_list,
469 struct tf_sram_block *block;
470 struct tfp_calloc_parms cparms;
474 cparms.size = sizeof(struct tf_sram_block);
475 cparms.alignment = 0;
476 rc = tfp_calloc(&cparms);
480 "Failed to allocate block, rc:%s\n",
484 block = (struct tf_sram_block *)cparms.mem_va;
485 block->block_id = block_id;
487 if (slice_list->head == NULL) {
488 slice_list->head = block;
489 slice_list->tail = block;
493 block->next = slice_list->head;
495 block->next->prev = block;
496 slice_list->head = block->next->prev;
503 * Find the first not full block in the slice list
506 tf_sram_find_first_not_full_block(struct tf_sram_slice_list *slice_list,
507 enum tf_sram_slice_size slice_size,
508 struct tf_sram_block **first_not_full_block)
510 struct tf_sram_block *block = slice_list->head;
511 uint8_t slice_mask, mask;
513 switch (slice_size) {
514 case TF_SRAM_SLICE_SIZE_8B:
518 case TF_SRAM_SLICE_SIZE_16B:
522 case TF_SRAM_SLICE_SIZE_32B:
526 case TF_SRAM_SLICE_SIZE_64B:
532 *first_not_full_block = NULL;
535 mask = block->in_use_mask & slice_mask;
536 if (mask != slice_mask) {
537 *first_not_full_block = block;
544 tf_sram_dump_block(struct tf_sram_block *block)
546 TFP_DRV_LOG(INFO, "block_id(0x%x) in_use_mask(0x%02x)\n",
551 /**********************
553 **********************/
555 tf_sram_mgr_bind(void **sram_handle)
558 struct tf_sram *sram;
559 struct tfp_calloc_parms cparms;
561 TF_CHECK_PARMS1(sram_handle);
564 cparms.size = sizeof(struct tf_sram);
565 cparms.alignment = 0;
566 rc = tfp_calloc(&cparms);
570 "Failed to allocate SRAM mgmt data, rc:%s\n",
574 sram = (struct tf_sram *)cparms.mem_va;
580 tf_sram_mgr_unbind(void *sram_handle)
583 struct tf_sram *sram;
584 enum tf_sram_bank_id bank_id;
585 enum tf_sram_slice_size slice_size;
587 struct tf_sram_slice_list *slice_list;
589 TF_CHECK_PARMS1(sram_handle);
591 sram = (struct tf_sram *)sram_handle;
593 for (dir = 0; dir < TF_DIR_MAX; dir++) {
596 for (bank_id = TF_SRAM_BANK_ID_0;
597 bank_id < TF_SRAM_BANK_ID_MAX;
599 /* For each slice size
601 for (slice_size = TF_SRAM_SLICE_SIZE_8B;
602 slice_size < TF_SRAM_SLICE_SIZE_MAX;
604 rc = tf_sram_get_slice_list(sram, &slice_list,
610 "No SRAM slice list, rc:%s\n",
614 if (tf_sram_get_block_cnt(slice_list))
615 tf_sram_free_slice_list(slice_list);
623 /* Freeing of the RM resources is handled by the table manager */
627 int tf_sram_mgr_alloc(void *sram_handle,
628 struct tf_sram_mgr_alloc_parms *parms)
631 struct tf_sram *sram;
632 struct tf_sram_slice_list *slice_list;
633 uint16_t block_id, slice_offset = 0;
635 struct tf_sram_block *block;
636 struct tf_rm_allocate_parms aparms = { 0 };
638 uint16_t block_offset;
640 TF_CHECK_PARMS3(sram_handle, parms, parms->sram_offset);
642 sram = (struct tf_sram *)sram_handle;
644 /* Check the current slice list
646 rc = tf_sram_get_slice_list(sram, &slice_list, parms->slice_size,
647 parms->dir, parms->bank_id);
651 "No SRAM slice list, rc:%s\n",
656 /* If the list is empty or all entries are full allocate a new block
658 if (!slice_list->first_not_full_block) {
659 /* Allocate and insert a new block
661 aparms.index = &index;
662 aparms.subtype = parms->tbl_type;
663 aparms.rm_db = parms->rm_db;
664 rc = tf_rm_allocate(&aparms);
669 block = tf_sram_alloc_block(slice_list, block_id);
674 (struct tf_sram_block *)(slice_list->first_not_full_block);
676 rc = tf_sram_get_next_slice_in_block(block,
681 /* Find the new first non-full block in the list
683 tf_sram_find_first_not_full_block(slice_list,
685 &slice_list->first_not_full_block);
687 tf_sram_block_id_2_offset(parms->bank_id, block->block_id,
690 *parms->sram_offset = block_offset + slice_offset;
695 tf_sram_mgr_free(void *sram_handle,
696 struct tf_sram_mgr_free_parms *parms)
699 struct tf_sram *sram;
700 struct tf_sram_slice_list *slice_list;
701 uint16_t block_id, slice_offset;
702 struct tf_sram_block *block;
704 struct tf_rm_free_parms fparms = { 0 };
706 TF_CHECK_PARMS2(sram_handle, parms);
708 sram = (struct tf_sram *)sram_handle;
710 /* Check the current slice list
712 rc = tf_sram_get_slice_list(sram, &slice_list, parms->slice_size,
713 parms->dir, parms->bank_id);
717 "No SRAM slice list, rc:%s\n",
722 /* Determine the block id and slice offset from the SRAM offset
724 tf_sram_offset_2_block_id(parms->bank_id, parms->sram_offset, &block_id,
727 /* Search the list of blocks for the matching block id
729 block = tf_sram_find_block(block_id, slice_list);
731 TFP_DRV_LOG(ERR, "block not found 0x%x\n", block_id);
735 /* If found, search for the matching SRAM slice in use.
737 rc = tf_sram_free_slice(parms->slice_size, slice_offset,
738 block, &block_is_empty);
740 TFP_DRV_LOG(ERR, "Error freeing slice (%s)\n", strerror(-rc));
743 #if (STATS_CLEAR_ON_READ_SUPPORT == 0)
744 /* If this is a counter, clear it. In the future we need to switch to
745 * using the special access registers on Thor to automatically clear on
748 /* If this is counter table, clear the entry on free */
749 if (parms->tbl_type == TF_TBL_TYPE_ACT_STATS_64) {
750 uint8_t data[8] = { 0 };
751 uint16_t hcapi_type = 0;
752 struct tf_rm_get_hcapi_parms hparms = { 0 };
754 /* Get the hcapi type */
755 hparms.rm_db = parms->rm_db;
756 hparms.subtype = parms->tbl_type;
757 hparms.hcapi_type = &hcapi_type;
758 rc = tf_rm_get_hcapi_type(&hparms);
761 "%s, Failed type lookup, type:%s, rc:%s\n",
762 tf_dir_2_str(parms->dir),
763 tf_tbl_type_2_str(parms->tbl_type),
769 rc = tf_msg_set_tbl_entry(parms->tfp,
777 "%s, Set failed, type:%s, rc:%s\n",
778 tf_dir_2_str(parms->dir),
779 tf_tbl_type_2_str(parms->tbl_type),
785 /* If the block is empty, free the block to the RM
787 if (block_is_empty) {
788 fparms.rm_db = parms->rm_db;
789 fparms.subtype = parms->tbl_type;
790 fparms.index = block_id;
791 rc = tf_rm_free(&fparms);
794 TFP_DRV_LOG(ERR, "Free block_id(%d) failed error(%s)\n",
795 block_id, strerror(-rc));
797 /* Free local entry regardless
799 tf_sram_free_block(slice_list, block);
801 /* Find the next non-full block in the list
803 tf_sram_find_first_not_full_block(slice_list,
805 &slice_list->first_not_full_block);
812 tf_sram_mgr_dump(void *sram_handle,
813 struct tf_sram_mgr_dump_parms *parms)
816 struct tf_sram *sram;
817 struct tf_sram_slice_list *slice_list;
818 uint32_t block_cnt, i;
819 struct tf_sram_block *block;
821 TF_CHECK_PARMS2(sram_handle, parms);
823 sram = (struct tf_sram *)sram_handle;
825 rc = tf_sram_get_slice_list(sram, &slice_list, parms->slice_size,
826 parms->dir, parms->bank_id);
830 if (slice_list->cnt || slice_list->first_not_full_block) {
831 TFP_DRV_LOG(INFO, "\n********** %s: %s: %s ***********\n",
832 tf_sram_bank_2_str(parms->bank_id),
833 tf_dir_2_str(parms->dir),
834 tf_sram_slice_2_str(parms->slice_size));
836 block_cnt = tf_sram_get_block_cnt(slice_list);
837 TFP_DRV_LOG(INFO, "block_cnt(%d)\n", block_cnt);
838 if (slice_list->first_not_full_block)
839 TFP_DRV_LOG(INFO, "first_not_full_block(0x%x)\n",
840 slice_list->first_not_full_block->block_id);
841 block = slice_list->head;
842 for (i = 0; i < block_cnt; i++) {
843 tf_sram_dump_block(block);
844 block = tf_sram_get_next_block(block);
846 TFP_DRV_LOG(INFO, "*********************************\n");
851 * Validate an SRAM Slice is allocated
853 * Validate whether the SRAM slice is allocated
856 * Pointer to SRAM handle
859 * Pointer to the SRAM alloc parameters
862 * - (0) if successful
863 * - (-EINVAL) on failure
866 int tf_sram_mgr_is_allocated(void *sram_handle,
867 struct tf_sram_mgr_is_allocated_parms *parms)
870 struct tf_sram *sram;
871 struct tf_sram_slice_list *slice_list;
872 uint16_t block_id, slice_offset;
873 struct tf_sram_block *block;
875 TF_CHECK_PARMS3(sram_handle, parms, parms->is_allocated);
877 sram = (struct tf_sram *)sram_handle;
879 /* Check the current slice list
881 rc = tf_sram_get_slice_list(sram, &slice_list, parms->slice_size,
882 parms->dir, parms->bank_id);
886 "No SRAM slice list, rc:%s\n",
891 /* If the list is empty, then it cannot be allocated
893 if (!slice_list->cnt) {
894 TFP_DRV_LOG(ERR, "List is empty for %s:%s:%s\n",
895 tf_dir_2_str(parms->dir),
896 tf_sram_slice_2_str(parms->slice_size),
897 tf_sram_bank_2_str(parms->bank_id));
899 parms->is_allocated = false;
903 /* Determine the block id and slice offset from the SRAM offset
905 tf_sram_offset_2_block_id(parms->bank_id, parms->sram_offset, &block_id,
908 /* Search the list of blocks for the matching block id
910 block = tf_sram_find_block(block_id, slice_list);
912 TFP_DRV_LOG(ERR, "block not found in list 0x%x\n",
914 parms->is_allocated = false;
918 rc = tf_sram_is_slice_allocated_in_block(block,
921 parms->is_allocated);