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 = 1;
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_get_tcam_slice_info == NULL) {
67 "Operation not supported, rc:%s\n",
72 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
73 TF_TCAM_TBL_TYPE_WC_TCAM,
79 tcam_cnt = parms->resources->tcam_cnt;
80 if ((tcam_cnt[TF_DIR_RX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % num_slices) ||
81 (tcam_cnt[TF_DIR_TX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % num_slices)) {
83 "Requested num of WC TCAM entries has to be multiple %d\n",
88 memset(&db_cfg, 0, sizeof(db_cfg));
90 cparms.size = sizeof(struct tcam_rm_db);
92 if (tfp_calloc(&cparms) != 0) {
93 TFP_DRV_LOG(ERR, "tcam_rm_db alloc error %s\n",
98 tcam_db = cparms.mem_va;
99 for (i = 0; i < TF_DIR_MAX; i++)
100 tcam_db->tcam_db[i] = NULL;
101 tf_session_set_db(tfp, TF_MODULE_TYPE_TCAM, tcam_db);
103 db_cfg.module = TF_MODULE_TYPE_TCAM;
104 db_cfg.num_elements = parms->num_elements;
105 db_cfg.cfg = parms->cfg;
107 for (d = 0; d < TF_DIR_MAX; d++) {
109 db_cfg.alloc_cnt = parms->resources->tcam_cnt[d].cnt;
110 db_cfg.rm_db = (void *)&tcam_db->tcam_db[d];
111 if (tf_session_is_shared_session(tfs) &&
112 (!tf_session_is_shared_session_creator(tfs)))
113 db_rc[d] = tf_rm_create_db_no_reservation(tfp, &db_cfg);
115 db_rc[d] = tf_rm_create_db(tfp, &db_cfg);
119 if (db_rc[TF_DIR_RX] && db_rc[TF_DIR_TX]) {
120 TFP_DRV_LOG(ERR, "No TCAM DB created\n");
121 return db_rc[TF_DIR_RX];
124 /* check if reserved resource for WC is multiple of num_slices */
125 for (d = 0; d < TF_DIR_MAX; d++) {
126 if (!tcam_db->tcam_db[d])
129 memset(&info, 0, sizeof(info));
130 ainfo.rm_db = tcam_db->tcam_db[d];
131 ainfo.subtype = TF_TCAM_TBL_TYPE_WC_TCAM;
133 rc = tf_rm_get_info(&ainfo);
137 if (info.entry.start % num_slices != 0 ||
138 info.entry.stride % num_slices != 0) {
140 "%s: TCAM reserved resource is not multiple of %d\n",
148 /* Initialize the TCAM manager. */
149 if (parms->shadow_copy) {
150 for (d = 0; d < TF_DIR_MAX; d++) {
151 memset(&shadow_cfg, 0, sizeof(shadow_cfg));
152 memset(&shadow_cdb, 0, sizeof(shadow_cdb));
153 /* Get the base addresses of the tcams for tcam mgr */
154 for (i = 0; i < TF_TCAM_TBL_TYPE_MAX; i++) {
155 memset(&info, 0, sizeof(info));
157 if (!parms->resources->tcam_cnt[d].cnt[i])
159 ainfo.rm_db = tcam_db->tcam_db[d];
162 rc = tf_rm_get_info(&ainfo);
166 shadow_cfg.base_addr[i] = info.entry.start;
169 /* Create the shadow db */
170 shadow_cfg.alloc_cnt =
171 parms->resources->tcam_cnt[d].cnt;
172 shadow_cfg.num_entries = parms->num_elements;
174 shadow_cdb.shadow_db = &shadow_tcam_db[d];
175 shadow_cdb.cfg = &shadow_cfg;
176 rc = tf_shadow_tcam_create_db(&shadow_cdb);
179 "TCAM MGR DB creation failed "
188 "TCAM - initialized\n");
192 for (i = 0; i < TF_DIR_MAX; i++) {
193 memset(&fparms, 0, sizeof(fparms));
195 fparms.rm_db = tcam_db->tcam_db[i];
196 /* Ignoring return here since we are in the error case */
197 (void)tf_rm_free_db(tfp, &fparms);
199 if (parms->shadow_copy) {
200 fshadow.shadow_db = shadow_tcam_db[i];
201 tf_shadow_tcam_free_db(&fshadow);
202 shadow_tcam_db[i] = NULL;
205 tcam_db->tcam_db[i] = NULL;
206 tf_session_set_db(tfp, TF_MODULE_TYPE_TCAM, NULL);
215 tf_tcam_unbind(struct tf *tfp)
219 struct tf_rm_free_db_parms fparms;
220 struct tcam_rm_db *tcam_db;
221 void *tcam_db_ptr = NULL;
222 struct tf_shadow_tcam_free_db_parms fshadow;
223 TF_CHECK_PARMS1(tfp);
225 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
229 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
231 for (i = 0; i < TF_DIR_MAX; i++) {
232 if (tcam_db->tcam_db[i] == NULL)
234 memset(&fparms, 0, sizeof(fparms));
236 fparms.rm_db = tcam_db->tcam_db[i];
237 rc = tf_rm_free_db(tfp, &fparms);
241 tcam_db->tcam_db[i] = NULL;
244 memset(&fshadow, 0, sizeof(fshadow));
246 fshadow.shadow_db = shadow_tcam_db[i];
247 tf_shadow_tcam_free_db(&fshadow);
248 shadow_tcam_db[i] = NULL;
258 tf_tcam_alloc(struct tf *tfp,
259 struct tf_tcam_alloc_parms *parms)
262 struct tf_session *tfs;
263 struct tf_dev_info *dev;
264 struct tf_rm_allocate_parms aparms;
265 uint16_t num_slices = 1;
267 struct tcam_rm_db *tcam_db;
268 void *tcam_db_ptr = NULL;
270 TF_CHECK_PARMS2(tfp, parms);
272 /* Retrieve the session information */
273 rc = tf_session_get_session_internal(tfp, &tfs);
277 /* Retrieve the device information */
278 rc = tf_session_get_device(tfs, &dev);
282 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
285 "%s: Operation not supported, rc:%s\n",
286 tf_dir_2_str(parms->dir),
291 /* Need to retrieve number of slices based on the key_size */
292 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
299 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
302 "Failed to get tcam_db from session, rc:%s\n",
306 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
309 * For WC TCAM, number of slices could be 4, 2, 1 based on
310 * the key_size. For other TCAM, it is always 1
312 for (i = 0; i < num_slices; i++) {
313 memset(&aparms, 0, sizeof(aparms));
314 aparms.rm_db = tcam_db->tcam_db[parms->dir];
315 aparms.subtype = parms->type;
316 aparms.priority = parms->priority;
317 aparms.index = &index;
318 rc = tf_rm_allocate(&aparms);
321 "%s: Failed tcam, type:%d\n",
322 tf_dir_2_str(parms->dir),
327 /* return the start index of each row */
336 tf_tcam_free(struct tf *tfp,
337 struct tf_tcam_free_parms *parms)
340 struct tf_session *tfs;
341 struct tf_dev_info *dev;
342 struct tf_rm_is_allocated_parms aparms;
343 struct tf_rm_free_parms fparms;
344 struct tf_rm_get_hcapi_parms hparms;
345 uint16_t num_slices = 1;
347 struct tf_shadow_tcam_remove_parms shparms;
349 struct tcam_rm_db *tcam_db;
350 void *tcam_db_ptr = NULL;
352 TF_CHECK_PARMS2(tfp, parms);
354 /* Retrieve the session information */
355 rc = tf_session_get_session_internal(tfp, &tfs);
359 /* Retrieve the device information */
360 rc = tf_session_get_device(tfs, &dev);
364 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
367 "%s: Operation not supported, rc:%s\n",
368 tf_dir_2_str(parms->dir),
373 /* Need to retrieve row size etc */
374 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
381 if (parms->idx % num_slices) {
383 "%s: TCAM reserved resource is not multiple of %d\n",
384 tf_dir_2_str(parms->dir),
389 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
392 "Failed to get em_ext_db from session, rc:%s\n",
396 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
398 /* Check if element is in use */
399 memset(&aparms, 0, sizeof(aparms));
400 aparms.rm_db = tcam_db->tcam_db[parms->dir];
401 aparms.subtype = parms->type;
402 aparms.index = parms->idx;
403 aparms.allocated = &allocated;
404 rc = tf_rm_is_allocated(&aparms);
408 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
410 "%s: Entry already free, type:%d, index:%d\n",
411 tf_dir_2_str(parms->dir),
418 * The Shadow mgmt, if enabled, determines if the entry needs
422 shparms.shadow_db = shadow_tcam_db[parms->dir];
423 shparms.fparms = parms;
424 rc = tf_shadow_tcam_remove(&shparms);
427 * Should not get here, log it and let the entry be
430 TFP_DRV_LOG(ERR, "%s: Shadow free fail, "
431 "type:%d index:%d deleting the entry.\n",
432 tf_dir_2_str(parms->dir),
437 * If the entry still has references, just return the
438 * ref count to the caller. No need to remove entry
441 if (parms->ref_cnt >= 1)
446 for (i = 0; i < num_slices; i++) {
447 /* Free requested element */
448 memset(&fparms, 0, sizeof(fparms));
449 fparms.rm_db = tcam_db->tcam_db[parms->dir];
450 fparms.subtype = parms->type;
451 fparms.index = parms->idx + i;
452 rc = tf_rm_free(&fparms);
455 "%s: Free failed, type:%d, index:%d\n",
456 tf_dir_2_str(parms->dir),
463 /* Convert TF type to HCAPI RM type */
464 memset(&hparms, 0, sizeof(hparms));
466 hparms.rm_db = tcam_db->tcam_db[parms->dir];
467 hparms.subtype = parms->type;
468 hparms.hcapi_type = &parms->hcapi_type;
470 rc = tf_rm_get_hcapi_type(&hparms);
474 rc = tf_msg_tcam_entry_free(tfp, dev, parms);
478 "%s: %s: Entry %d free failed, rc:%s\n",
479 tf_dir_2_str(parms->dir),
480 tf_tcam_tbl_2_str(parms->type),
490 tf_tcam_alloc_search(struct tf *tfp,
491 struct tf_tcam_alloc_search_parms *parms)
493 struct tf_shadow_tcam_search_parms sparms;
494 struct tf_shadow_tcam_bind_index_parms bparms;
495 struct tf_tcam_free_parms fparms;
496 struct tf_tcam_alloc_parms aparms;
497 uint16_t num_slice_per_row = 1;
498 struct tf_session *tfs;
499 struct tf_dev_info *dev;
502 TF_CHECK_PARMS2(tfp, parms);
504 if (!shadow_init || !shadow_tcam_db[parms->dir]) {
505 TFP_DRV_LOG(ERR, "%s: TCAM Shadow not initialized for %s\n",
506 tf_dir_2_str(parms->dir),
507 tf_tcam_tbl_2_str(parms->type));
511 /* Retrieve the session information */
512 rc = tf_session_get_session_internal(tfp, &tfs);
516 /* Retrieve the device information */
517 rc = tf_session_get_device(tfs, &dev);
521 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
524 "%s: Operation not supported, rc:%s\n",
525 tf_dir_2_str(parms->dir),
530 /* Need to retrieve row size etc */
531 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
539 * Prep the shadow search, reusing the parms from original search
540 * instead of copying them. Shadow will update output in there.
542 memset(&sparms, 0, sizeof(sparms));
543 sparms.sparms = parms;
544 sparms.shadow_db = shadow_tcam_db[parms->dir];
546 rc = tf_shadow_tcam_search(&sparms);
551 * The app didn't request us to alloc the entry, so return now.
552 * The hit should have been updated in the original search parm.
554 if (!parms->alloc || parms->search_status != MISS)
557 /* Caller desires an allocate on miss */
558 if (dev->ops->tf_dev_alloc_tcam == NULL) {
561 "%s: Operation not supported, rc:%s\n",
562 tf_dir_2_str(parms->dir),
566 memset(&aparms, 0, sizeof(aparms));
567 aparms.dir = parms->dir;
568 aparms.type = parms->type;
569 aparms.key_size = parms->key_size;
570 aparms.priority = parms->priority;
571 rc = dev->ops->tf_dev_alloc_tcam(tfp, &aparms);
575 /* Successful allocation, attempt to add it to the shadow */
576 memset(&bparms, 0, sizeof(bparms));
577 bparms.dir = parms->dir;
578 bparms.shadow_db = shadow_tcam_db[parms->dir];
579 bparms.type = parms->type;
580 bparms.key = parms->key;
581 bparms.mask = parms->mask;
582 bparms.key_size = parms->key_size;
583 bparms.idx = aparms.idx;
584 bparms.hb_handle = sparms.hb_handle;
585 rc = tf_shadow_tcam_bind_index(&bparms);
587 /* Error binding entry, need to free the allocated idx */
588 if (dev->ops->tf_dev_free_tcam == NULL) {
591 "%s: Operation not supported, rc:%s\n",
592 tf_dir_2_str(parms->dir),
597 fparms.dir = parms->dir;
598 fparms.type = parms->type;
599 fparms.idx = aparms.idx;
600 rc = dev->ops->tf_dev_free_tcam(tfp, &fparms);
605 /* Add the allocated index to output and done */
606 parms->idx = aparms.idx;
612 tf_tcam_set(struct tf *tfp __rte_unused,
613 struct tf_tcam_set_parms *parms __rte_unused)
616 struct tf_session *tfs;
617 struct tf_dev_info *dev;
618 struct tf_rm_is_allocated_parms aparms;
619 struct tf_rm_get_hcapi_parms hparms;
620 struct tf_shadow_tcam_insert_parms iparms;
621 uint16_t num_slice_per_row = 1;
623 struct tcam_rm_db *tcam_db;
624 void *tcam_db_ptr = NULL;
626 TF_CHECK_PARMS2(tfp, parms);
628 /* Retrieve the session information */
629 rc = tf_session_get_session_internal(tfp, &tfs);
633 /* Retrieve the device information */
634 rc = tf_session_get_device(tfs, &dev);
638 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
641 "%s: Operation not supported, rc:%s\n",
642 tf_dir_2_str(parms->dir),
647 /* Need to retrieve row size etc */
648 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
655 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
658 "Failed to get em_ext_db from session, rc:%s\n",
662 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
664 /* Check if element is in use */
665 memset(&aparms, 0, sizeof(aparms));
667 aparms.rm_db = tcam_db->tcam_db[parms->dir];
668 aparms.subtype = parms->type;
669 aparms.index = parms->idx;
670 aparms.allocated = &allocated;
671 rc = tf_rm_is_allocated(&aparms);
675 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
677 "%s: Entry is not allocated, type:%d, index:%d\n",
678 tf_dir_2_str(parms->dir),
684 /* Convert TF type to HCAPI RM type */
685 memset(&hparms, 0, sizeof(hparms));
687 hparms.rm_db = tcam_db->tcam_db[parms->dir];
688 hparms.subtype = parms->type;
689 hparms.hcapi_type = &parms->hcapi_type;
691 rc = tf_rm_get_hcapi_type(&hparms);
695 rc = tf_msg_tcam_entry_set(tfp, dev, parms);
699 "%s: %s: Entry %d set failed, rc:%s",
700 tf_dir_2_str(parms->dir),
701 tf_tcam_tbl_2_str(parms->type),
707 /* Successfully added to hw, now for shadow if enabled. */
708 if (!shadow_init || !shadow_tcam_db[parms->dir])
711 iparms.shadow_db = shadow_tcam_db[parms->dir];
712 iparms.sparms = parms;
713 rc = tf_shadow_tcam_insert(&iparms);
716 "%s: %s: Entry %d set failed, rc:%s",
717 tf_dir_2_str(parms->dir),
718 tf_tcam_tbl_2_str(parms->type),
728 tf_tcam_get(struct tf *tfp __rte_unused,
729 struct tf_tcam_get_parms *parms)
732 struct tf_session *tfs;
733 struct tf_dev_info *dev;
734 struct tf_rm_is_allocated_parms aparms;
735 struct tf_rm_get_hcapi_parms hparms;
737 struct tcam_rm_db *tcam_db;
738 void *tcam_db_ptr = NULL;
740 TF_CHECK_PARMS2(tfp, parms);
742 /* Retrieve the session information */
743 rc = tf_session_get_session_internal(tfp, &tfs);
747 /* Retrieve the device information */
748 rc = tf_session_get_device(tfs, &dev);
752 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
755 "Failed to get em_ext_db from session, rc:%s\n",
759 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
761 /* Check if element is in use */
762 memset(&aparms, 0, sizeof(aparms));
764 aparms.rm_db = tcam_db->tcam_db[parms->dir];
765 aparms.subtype = parms->type;
766 aparms.index = parms->idx;
767 aparms.allocated = &allocated;
768 rc = tf_rm_is_allocated(&aparms);
772 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
774 "%s: Entry is not allocated, type:%d, index:%d\n",
775 tf_dir_2_str(parms->dir),
781 /* Convert TF type to HCAPI RM type */
782 memset(&hparms, 0, sizeof(hparms));
784 hparms.rm_db = tcam_db->tcam_db[parms->dir];
785 hparms.subtype = parms->type;
786 hparms.hcapi_type = &parms->hcapi_type;
788 rc = tf_rm_get_hcapi_type(&hparms);
792 rc = tf_msg_tcam_entry_get(tfp, dev, parms);
796 "%s: %s: Entry %d set failed, rc:%s",
797 tf_dir_2_str(parms->dir),
798 tf_tcam_tbl_2_str(parms->type),
808 tf_tcam_get_resc_info(struct tf *tfp,
809 struct tf_tcam_resource_info *tcam)
813 struct tf_resource_info *dinfo;
814 struct tf_rm_get_alloc_info_parms ainfo;
815 void *tcam_db_ptr = NULL;
816 struct tcam_rm_db *tcam_db;
818 TF_CHECK_PARMS2(tfp, tcam);
820 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
823 "No resource allocated for tcam from session\n");
826 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
828 /* check if reserved resource for WC is multiple of num_slices */
829 for (d = 0; d < TF_DIR_MAX; d++) {
830 ainfo.rm_db = tcam_db->tcam_db[d];
831 dinfo = tcam[d].info;
833 ainfo.info = (struct tf_rm_alloc_info *)dinfo;
835 rc = tf_rm_get_all_info(&ainfo, TF_TCAM_TBL_TYPE_MAX);
836 if (rc && rc != -ENOTSUP)