1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019-2021 Broadcom
7 #include <rte_common.h>
10 #include "tf_common.h"
13 #include "tf_device.h"
15 #include "tf_session.h"
17 #include "tf_shadow_tcam.h"
24 static void *shadow_tcam_db[TF_DIR_MAX];
27 * Shadow init flag, set on bind and cleared on unbind
29 static uint8_t shadow_init;
32 tf_tcam_bind(struct tf *tfp,
33 struct tf_tcam_cfg_parms *parms)
36 int db_rc[TF_DIR_MAX] = { 0 };
38 struct tf_rm_alloc_info info;
39 struct tf_rm_free_db_parms fparms;
40 struct tf_rm_create_db_parms db_cfg;
41 struct tf_tcam_resources *tcam_cnt;
42 struct tf_rm_get_alloc_info_parms ainfo;
43 struct tf_shadow_tcam_free_db_parms fshadow;
44 struct tf_shadow_tcam_cfg_parms shadow_cfg;
45 struct tf_shadow_tcam_create_db_parms shadow_cdb;
46 uint16_t num_slices = parms->wc_num_slices;
47 struct tf_session *tfs;
48 struct tf_dev_info *dev;
49 struct tcam_rm_db *tcam_db;
50 struct tfp_calloc_parms cparms;
52 TF_CHECK_PARMS2(tfp, parms);
54 /* Retrieve the session information */
55 rc = tf_session_get_session_internal(tfp, &tfs);
59 /* Retrieve the device information */
60 rc = tf_session_get_device(tfs, &dev);
64 if (dev->ops->tf_dev_set_tcam_slice_info == NULL) {
67 "Operation not supported, rc:%s\n",
72 rc = dev->ops->tf_dev_set_tcam_slice_info(tfp,
77 tcam_cnt = parms->resources->tcam_cnt;
78 if ((tcam_cnt[TF_DIR_RX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % num_slices) ||
79 (tcam_cnt[TF_DIR_TX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % num_slices)) {
81 "Requested num of WC TCAM entries has to be multiple %d\n",
86 memset(&db_cfg, 0, sizeof(db_cfg));
88 cparms.size = sizeof(struct tcam_rm_db);
90 if (tfp_calloc(&cparms) != 0) {
91 TFP_DRV_LOG(ERR, "tcam_rm_db alloc error %s\n",
96 tcam_db = cparms.mem_va;
97 for (i = 0; i < TF_DIR_MAX; i++)
98 tcam_db->tcam_db[i] = NULL;
99 tf_session_set_db(tfp, TF_MODULE_TYPE_TCAM, tcam_db);
101 db_cfg.module = TF_MODULE_TYPE_TCAM;
102 db_cfg.num_elements = parms->num_elements;
103 db_cfg.cfg = parms->cfg;
105 for (d = 0; d < TF_DIR_MAX; d++) {
107 db_cfg.alloc_cnt = parms->resources->tcam_cnt[d].cnt;
108 db_cfg.rm_db = (void *)&tcam_db->tcam_db[d];
109 if (tf_session_is_shared_session(tfs) &&
110 (!tf_session_is_shared_session_creator(tfs)))
111 db_rc[d] = tf_rm_create_db_no_reservation(tfp, &db_cfg);
113 db_rc[d] = tf_rm_create_db(tfp, &db_cfg);
117 if (db_rc[TF_DIR_RX] && db_rc[TF_DIR_TX]) {
118 TFP_DRV_LOG(ERR, "No TCAM DB created\n");
119 return db_rc[TF_DIR_RX];
122 /* check if reserved resource for WC is multiple of num_slices */
123 for (d = 0; d < TF_DIR_MAX; d++) {
124 if (!tcam_db->tcam_db[d])
127 memset(&info, 0, sizeof(info));
128 ainfo.rm_db = tcam_db->tcam_db[d];
129 ainfo.subtype = TF_TCAM_TBL_TYPE_WC_TCAM;
131 rc = tf_rm_get_info(&ainfo);
135 if (info.entry.start % num_slices != 0 ||
136 info.entry.stride % num_slices != 0) {
138 "%s: TCAM reserved resource is not multiple of %d\n",
146 /* Initialize the TCAM manager. */
147 if (parms->shadow_copy) {
148 for (d = 0; d < TF_DIR_MAX; d++) {
149 memset(&shadow_cfg, 0, sizeof(shadow_cfg));
150 memset(&shadow_cdb, 0, sizeof(shadow_cdb));
151 /* Get the base addresses of the tcams for tcam mgr */
152 for (i = 0; i < TF_TCAM_TBL_TYPE_MAX; i++) {
153 memset(&info, 0, sizeof(info));
155 if (!parms->resources->tcam_cnt[d].cnt[i])
157 ainfo.rm_db = tcam_db->tcam_db[d];
160 rc = tf_rm_get_info(&ainfo);
164 shadow_cfg.base_addr[i] = info.entry.start;
167 /* Create the shadow db */
168 shadow_cfg.alloc_cnt =
169 parms->resources->tcam_cnt[d].cnt;
170 shadow_cfg.num_entries = parms->num_elements;
172 shadow_cdb.shadow_db = &shadow_tcam_db[d];
173 shadow_cdb.cfg = &shadow_cfg;
174 rc = tf_shadow_tcam_create_db(&shadow_cdb);
177 "TCAM MGR DB creation failed "
186 "TCAM - initialized\n");
190 for (i = 0; i < TF_DIR_MAX; i++) {
191 memset(&fparms, 0, sizeof(fparms));
193 fparms.rm_db = tcam_db->tcam_db[i];
194 /* Ignoring return here since we are in the error case */
195 (void)tf_rm_free_db(tfp, &fparms);
197 if (parms->shadow_copy) {
198 fshadow.shadow_db = shadow_tcam_db[i];
199 tf_shadow_tcam_free_db(&fshadow);
200 shadow_tcam_db[i] = NULL;
203 tcam_db->tcam_db[i] = NULL;
204 tf_session_set_db(tfp, TF_MODULE_TYPE_TCAM, NULL);
213 tf_tcam_unbind(struct tf *tfp)
217 struct tf_rm_free_db_parms fparms;
218 struct tcam_rm_db *tcam_db;
219 void *tcam_db_ptr = NULL;
220 struct tf_shadow_tcam_free_db_parms fshadow;
221 TF_CHECK_PARMS1(tfp);
223 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
227 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
229 for (i = 0; i < TF_DIR_MAX; i++) {
230 if (tcam_db->tcam_db[i] == NULL)
232 memset(&fparms, 0, sizeof(fparms));
234 fparms.rm_db = tcam_db->tcam_db[i];
235 rc = tf_rm_free_db(tfp, &fparms);
239 tcam_db->tcam_db[i] = NULL;
242 memset(&fshadow, 0, sizeof(fshadow));
244 fshadow.shadow_db = shadow_tcam_db[i];
245 tf_shadow_tcam_free_db(&fshadow);
246 shadow_tcam_db[i] = NULL;
256 tf_tcam_alloc(struct tf *tfp,
257 struct tf_tcam_alloc_parms *parms)
260 struct tf_session *tfs;
261 struct tf_dev_info *dev;
262 struct tf_rm_allocate_parms aparms;
263 uint16_t num_slices = 1;
265 struct tcam_rm_db *tcam_db;
266 void *tcam_db_ptr = NULL;
268 TF_CHECK_PARMS2(tfp, parms);
270 /* Retrieve the session information */
271 rc = tf_session_get_session_internal(tfp, &tfs);
275 /* Retrieve the device information */
276 rc = tf_session_get_device(tfs, &dev);
280 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
283 "%s: Operation not supported, rc:%s\n",
284 tf_dir_2_str(parms->dir),
289 /* Need to retrieve number of slices based on the key_size */
290 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
297 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
300 "Failed to get tcam_db from session, rc:%s\n",
304 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
307 * For WC TCAM, number of slices could be 4, 2, 1 based on
308 * the key_size. For other TCAM, it is always 1
310 for (i = 0; i < num_slices; i++) {
311 memset(&aparms, 0, sizeof(aparms));
312 aparms.rm_db = tcam_db->tcam_db[parms->dir];
313 aparms.subtype = parms->type;
314 aparms.priority = parms->priority;
315 aparms.index = &index;
316 rc = tf_rm_allocate(&aparms);
319 "%s: Failed tcam, type:%d\n",
320 tf_dir_2_str(parms->dir),
325 /* return the start index of each row */
326 if (parms->priority == 0) {
338 tf_tcam_free(struct tf *tfp,
339 struct tf_tcam_free_parms *parms)
342 struct tf_session *tfs;
343 struct tf_dev_info *dev;
344 struct tf_rm_is_allocated_parms aparms;
345 struct tf_rm_free_parms fparms;
346 struct tf_rm_get_hcapi_parms hparms;
347 uint16_t num_slices = 1;
349 struct tf_shadow_tcam_remove_parms shparms;
351 struct tcam_rm_db *tcam_db;
352 void *tcam_db_ptr = NULL;
354 TF_CHECK_PARMS2(tfp, parms);
356 /* Retrieve the session information */
357 rc = tf_session_get_session_internal(tfp, &tfs);
361 /* Retrieve the device information */
362 rc = tf_session_get_device(tfs, &dev);
366 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
369 "%s: Operation not supported, rc:%s\n",
370 tf_dir_2_str(parms->dir),
375 /* Need to retrieve row size etc */
376 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
383 if (parms->idx % num_slices) {
385 "%s: TCAM reserved resource is not multiple of %d\n",
386 tf_dir_2_str(parms->dir),
391 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
394 "Failed to get em_ext_db from session, rc:%s\n",
398 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
400 /* Check if element is in use */
401 memset(&aparms, 0, sizeof(aparms));
402 aparms.rm_db = tcam_db->tcam_db[parms->dir];
403 aparms.subtype = parms->type;
404 aparms.index = parms->idx;
405 aparms.allocated = &allocated;
406 rc = tf_rm_is_allocated(&aparms);
410 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
412 "%s: Entry already free, type:%d, index:%d\n",
413 tf_dir_2_str(parms->dir),
420 * The Shadow mgmt, if enabled, determines if the entry needs
424 shparms.shadow_db = shadow_tcam_db[parms->dir];
425 shparms.fparms = parms;
426 rc = tf_shadow_tcam_remove(&shparms);
429 * Should not get here, log it and let the entry be
432 TFP_DRV_LOG(ERR, "%s: Shadow free fail, "
433 "type:%d index:%d deleting the entry.\n",
434 tf_dir_2_str(parms->dir),
439 * If the entry still has references, just return the
440 * ref count to the caller. No need to remove entry
443 if (parms->ref_cnt >= 1)
448 for (i = 0; i < num_slices; i++) {
449 /* Free requested element */
450 memset(&fparms, 0, sizeof(fparms));
451 fparms.rm_db = tcam_db->tcam_db[parms->dir];
452 fparms.subtype = parms->type;
453 fparms.index = parms->idx + i;
454 rc = tf_rm_free(&fparms);
457 "%s: Free failed, type:%d, index:%d\n",
458 tf_dir_2_str(parms->dir),
465 /* Convert TF type to HCAPI RM type */
466 memset(&hparms, 0, sizeof(hparms));
468 hparms.rm_db = tcam_db->tcam_db[parms->dir];
469 hparms.subtype = parms->type;
470 hparms.hcapi_type = &parms->hcapi_type;
472 rc = tf_rm_get_hcapi_type(&hparms);
476 rc = tf_msg_tcam_entry_free(tfp, dev, parms);
480 "%s: %s: Entry %d free failed, rc:%s\n",
481 tf_dir_2_str(parms->dir),
482 tf_tcam_tbl_2_str(parms->type),
492 tf_tcam_alloc_search(struct tf *tfp,
493 struct tf_tcam_alloc_search_parms *parms)
495 struct tf_shadow_tcam_search_parms sparms;
496 struct tf_shadow_tcam_bind_index_parms bparms;
497 struct tf_tcam_free_parms fparms;
498 struct tf_tcam_alloc_parms aparms;
499 uint16_t num_slice_per_row = 1;
500 struct tf_session *tfs;
501 struct tf_dev_info *dev;
504 TF_CHECK_PARMS2(tfp, parms);
506 if (!shadow_init || !shadow_tcam_db[parms->dir]) {
507 TFP_DRV_LOG(ERR, "%s: TCAM Shadow not initialized for %s\n",
508 tf_dir_2_str(parms->dir),
509 tf_tcam_tbl_2_str(parms->type));
513 /* Retrieve the session information */
514 rc = tf_session_get_session_internal(tfp, &tfs);
518 /* Retrieve the device information */
519 rc = tf_session_get_device(tfs, &dev);
523 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
526 "%s: Operation not supported, rc:%s\n",
527 tf_dir_2_str(parms->dir),
532 /* Need to retrieve row size etc */
533 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
541 * Prep the shadow search, reusing the parms from original search
542 * instead of copying them. Shadow will update output in there.
544 memset(&sparms, 0, sizeof(sparms));
545 sparms.sparms = parms;
546 sparms.shadow_db = shadow_tcam_db[parms->dir];
548 rc = tf_shadow_tcam_search(&sparms);
553 * The app didn't request us to alloc the entry, so return now.
554 * The hit should have been updated in the original search parm.
556 if (!parms->alloc || parms->search_status != MISS)
559 /* Caller desires an allocate on miss */
560 if (dev->ops->tf_dev_alloc_tcam == NULL) {
563 "%s: Operation not supported, rc:%s\n",
564 tf_dir_2_str(parms->dir),
568 memset(&aparms, 0, sizeof(aparms));
569 aparms.dir = parms->dir;
570 aparms.type = parms->type;
571 aparms.key_size = parms->key_size;
572 aparms.priority = parms->priority;
573 rc = dev->ops->tf_dev_alloc_tcam(tfp, &aparms);
577 /* Successful allocation, attempt to add it to the shadow */
578 memset(&bparms, 0, sizeof(bparms));
579 bparms.dir = parms->dir;
580 bparms.shadow_db = shadow_tcam_db[parms->dir];
581 bparms.type = parms->type;
582 bparms.key = parms->key;
583 bparms.mask = parms->mask;
584 bparms.key_size = parms->key_size;
585 bparms.idx = aparms.idx;
586 bparms.hb_handle = sparms.hb_handle;
587 rc = tf_shadow_tcam_bind_index(&bparms);
589 /* Error binding entry, need to free the allocated idx */
590 if (dev->ops->tf_dev_free_tcam == NULL) {
593 "%s: Operation not supported, rc:%s\n",
594 tf_dir_2_str(parms->dir),
599 fparms.dir = parms->dir;
600 fparms.type = parms->type;
601 fparms.idx = aparms.idx;
602 rc = dev->ops->tf_dev_free_tcam(tfp, &fparms);
607 /* Add the allocated index to output and done */
608 parms->idx = aparms.idx;
614 tf_tcam_set(struct tf *tfp __rte_unused,
615 struct tf_tcam_set_parms *parms __rte_unused)
618 struct tf_session *tfs;
619 struct tf_dev_info *dev;
620 struct tf_rm_is_allocated_parms aparms;
621 struct tf_rm_get_hcapi_parms hparms;
622 struct tf_shadow_tcam_insert_parms iparms;
623 uint16_t num_slice_per_row = 1;
625 struct tcam_rm_db *tcam_db;
626 void *tcam_db_ptr = NULL;
628 TF_CHECK_PARMS2(tfp, parms);
630 /* Retrieve the session information */
631 rc = tf_session_get_session_internal(tfp, &tfs);
635 /* Retrieve the device information */
636 rc = tf_session_get_device(tfs, &dev);
640 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
643 "%s: Operation not supported, rc:%s\n",
644 tf_dir_2_str(parms->dir),
649 /* Need to retrieve row size etc */
650 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
657 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
660 "Failed to get em_ext_db from session, rc:%s\n",
664 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
666 /* Check if element is in use */
667 memset(&aparms, 0, sizeof(aparms));
669 aparms.rm_db = tcam_db->tcam_db[parms->dir];
670 aparms.subtype = parms->type;
671 aparms.index = parms->idx;
672 aparms.allocated = &allocated;
673 rc = tf_rm_is_allocated(&aparms);
677 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
679 "%s: Entry is not allocated, type:%d, index:%d\n",
680 tf_dir_2_str(parms->dir),
686 /* Convert TF type to HCAPI RM type */
687 memset(&hparms, 0, sizeof(hparms));
689 hparms.rm_db = tcam_db->tcam_db[parms->dir];
690 hparms.subtype = parms->type;
691 hparms.hcapi_type = &parms->hcapi_type;
693 rc = tf_rm_get_hcapi_type(&hparms);
697 rc = tf_msg_tcam_entry_set(tfp, dev, parms);
701 "%s: %s: Entry %d set failed, rc:%s",
702 tf_dir_2_str(parms->dir),
703 tf_tcam_tbl_2_str(parms->type),
709 /* Successfully added to hw, now for shadow if enabled. */
710 if (!shadow_init || !shadow_tcam_db[parms->dir])
713 iparms.shadow_db = shadow_tcam_db[parms->dir];
714 iparms.sparms = parms;
715 rc = tf_shadow_tcam_insert(&iparms);
718 "%s: %s: Entry %d set failed, rc:%s",
719 tf_dir_2_str(parms->dir),
720 tf_tcam_tbl_2_str(parms->type),
730 tf_tcam_get(struct tf *tfp __rte_unused,
731 struct tf_tcam_get_parms *parms)
734 struct tf_session *tfs;
735 struct tf_dev_info *dev;
736 struct tf_rm_is_allocated_parms aparms;
737 struct tf_rm_get_hcapi_parms hparms;
739 struct tcam_rm_db *tcam_db;
740 void *tcam_db_ptr = NULL;
742 TF_CHECK_PARMS2(tfp, parms);
744 /* Retrieve the session information */
745 rc = tf_session_get_session_internal(tfp, &tfs);
749 /* Retrieve the device information */
750 rc = tf_session_get_device(tfs, &dev);
754 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
757 "Failed to get em_ext_db from session, rc:%s\n",
761 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
763 /* Check if element is in use */
764 memset(&aparms, 0, sizeof(aparms));
766 aparms.rm_db = tcam_db->tcam_db[parms->dir];
767 aparms.subtype = parms->type;
768 aparms.index = parms->idx;
769 aparms.allocated = &allocated;
770 rc = tf_rm_is_allocated(&aparms);
774 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
776 "%s: Entry is not allocated, type:%d, index:%d\n",
777 tf_dir_2_str(parms->dir),
783 /* Convert TF type to HCAPI RM type */
784 memset(&hparms, 0, sizeof(hparms));
786 hparms.rm_db = tcam_db->tcam_db[parms->dir];
787 hparms.subtype = parms->type;
788 hparms.hcapi_type = &parms->hcapi_type;
790 rc = tf_rm_get_hcapi_type(&hparms);
794 rc = tf_msg_tcam_entry_get(tfp, dev, parms);
798 "%s: %s: Entry %d set failed, rc:%s",
799 tf_dir_2_str(parms->dir),
800 tf_tcam_tbl_2_str(parms->type),
810 tf_tcam_get_resc_info(struct tf *tfp,
811 struct tf_tcam_resource_info *tcam)
815 struct tf_resource_info *dinfo;
816 struct tf_rm_get_alloc_info_parms ainfo;
817 void *tcam_db_ptr = NULL;
818 struct tcam_rm_db *tcam_db;
820 TF_CHECK_PARMS2(tfp, tcam);
822 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
824 return 0; /* db doesn't exist */
826 return rc; /* error getting db */
828 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
830 /* check if reserved resource for WC is multiple of num_slices */
831 for (d = 0; d < TF_DIR_MAX; d++) {
832 ainfo.rm_db = tcam_db->tcam_db[d];
837 dinfo = tcam[d].info;
839 ainfo.info = (struct tf_rm_alloc_info *)dinfo;
841 rc = tf_rm_get_all_info(&ainfo, TF_TCAM_TBL_TYPE_MAX);
842 if (rc && rc != -ENOTSUP)