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);
118 "%s: TCAM DB creation failed\n",
124 if (db_rc[TF_DIR_RX] && db_rc[TF_DIR_TX])
125 return db_rc[TF_DIR_RX];
127 /* check if reserved resource for WC is multiple of num_slices */
128 for (d = 0; d < TF_DIR_MAX; 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);
228 "Tcam_db is not initialized, rc:%s\n",
232 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
234 for (i = 0; i < TF_DIR_MAX; i++) {
235 if (tcam_db->tcam_db[i] == NULL)
237 memset(&fparms, 0, sizeof(fparms));
239 fparms.rm_db = tcam_db->tcam_db[i];
240 rc = tf_rm_free_db(tfp, &fparms);
244 tcam_db->tcam_db[i] = NULL;
247 memset(&fshadow, 0, sizeof(fshadow));
249 fshadow.shadow_db = shadow_tcam_db[i];
250 tf_shadow_tcam_free_db(&fshadow);
251 shadow_tcam_db[i] = NULL;
261 tf_tcam_alloc(struct tf *tfp,
262 struct tf_tcam_alloc_parms *parms)
265 struct tf_session *tfs;
266 struct tf_dev_info *dev;
267 struct tf_rm_allocate_parms aparms;
268 uint16_t num_slices = 1;
270 struct tcam_rm_db *tcam_db;
271 void *tcam_db_ptr = NULL;
273 TF_CHECK_PARMS2(tfp, parms);
275 /* Retrieve the session information */
276 rc = tf_session_get_session_internal(tfp, &tfs);
280 /* Retrieve the device information */
281 rc = tf_session_get_device(tfs, &dev);
285 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
288 "%s: Operation not supported, rc:%s\n",
289 tf_dir_2_str(parms->dir),
294 /* Need to retrieve number of slices based on the key_size */
295 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
302 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
305 "Failed to get em_ext_db from session, rc:%s\n",
309 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
312 * For WC TCAM, number of slices could be 4, 2, 1 based on
313 * the key_size. For other TCAM, it is always 1
315 for (i = 0; i < num_slices; i++) {
316 memset(&aparms, 0, sizeof(aparms));
317 aparms.rm_db = tcam_db->tcam_db[parms->dir];
318 aparms.subtype = parms->type;
319 aparms.priority = parms->priority;
320 aparms.index = &index;
321 rc = tf_rm_allocate(&aparms);
324 "%s: Failed tcam, type:%d\n",
325 tf_dir_2_str(parms->dir),
330 /* return the start index of each row */
339 tf_tcam_free(struct tf *tfp,
340 struct tf_tcam_free_parms *parms)
343 struct tf_session *tfs;
344 struct tf_dev_info *dev;
345 struct tf_rm_is_allocated_parms aparms;
346 struct tf_rm_free_parms fparms;
347 struct tf_rm_get_hcapi_parms hparms;
348 uint16_t num_slices = 1;
350 struct tf_shadow_tcam_remove_parms shparms;
352 struct tcam_rm_db *tcam_db;
353 void *tcam_db_ptr = NULL;
355 TF_CHECK_PARMS2(tfp, parms);
357 /* Retrieve the session information */
358 rc = tf_session_get_session_internal(tfp, &tfs);
362 /* Retrieve the device information */
363 rc = tf_session_get_device(tfs, &dev);
367 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
370 "%s: Operation not supported, rc:%s\n",
371 tf_dir_2_str(parms->dir),
376 /* Need to retrieve row size etc */
377 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
384 if (parms->idx % num_slices) {
386 "%s: TCAM reserved resource is not multiple of %d\n",
387 tf_dir_2_str(parms->dir),
392 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
395 "Failed to get em_ext_db from session, rc:%s\n",
399 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
401 /* Check if element is in use */
402 memset(&aparms, 0, sizeof(aparms));
403 aparms.rm_db = tcam_db->tcam_db[parms->dir];
404 aparms.subtype = parms->type;
405 aparms.index = parms->idx;
406 aparms.allocated = &allocated;
407 rc = tf_rm_is_allocated(&aparms);
411 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
413 "%s: Entry already free, type:%d, index:%d\n",
414 tf_dir_2_str(parms->dir),
421 * The Shadow mgmt, if enabled, determines if the entry needs
425 shparms.shadow_db = shadow_tcam_db[parms->dir];
426 shparms.fparms = parms;
427 rc = tf_shadow_tcam_remove(&shparms);
430 * Should not get here, log it and let the entry be
433 TFP_DRV_LOG(ERR, "%s: Shadow free fail, "
434 "type:%d index:%d deleting the entry.\n",
435 tf_dir_2_str(parms->dir),
440 * If the entry still has references, just return the
441 * ref count to the caller. No need to remove entry
444 if (parms->ref_cnt >= 1)
449 for (i = 0; i < num_slices; i++) {
450 /* Free requested element */
451 memset(&fparms, 0, sizeof(fparms));
452 fparms.rm_db = tcam_db->tcam_db[parms->dir];
453 fparms.subtype = parms->type;
454 fparms.index = parms->idx + i;
455 rc = tf_rm_free(&fparms);
458 "%s: Free failed, type:%d, index:%d\n",
459 tf_dir_2_str(parms->dir),
466 /* Convert TF type to HCAPI RM type */
467 memset(&hparms, 0, sizeof(hparms));
469 hparms.rm_db = tcam_db->tcam_db[parms->dir];
470 hparms.subtype = parms->type;
471 hparms.hcapi_type = &parms->hcapi_type;
473 rc = tf_rm_get_hcapi_type(&hparms);
477 rc = tf_msg_tcam_entry_free(tfp, dev, parms);
481 "%s: %s: Entry %d free failed, rc:%s\n",
482 tf_dir_2_str(parms->dir),
483 tf_tcam_tbl_2_str(parms->type),
493 tf_tcam_alloc_search(struct tf *tfp,
494 struct tf_tcam_alloc_search_parms *parms)
496 struct tf_shadow_tcam_search_parms sparms;
497 struct tf_shadow_tcam_bind_index_parms bparms;
498 struct tf_tcam_free_parms fparms;
499 struct tf_tcam_alloc_parms aparms;
500 uint16_t num_slice_per_row = 1;
501 struct tf_session *tfs;
502 struct tf_dev_info *dev;
505 TF_CHECK_PARMS2(tfp, parms);
507 if (!shadow_init || !shadow_tcam_db[parms->dir]) {
508 TFP_DRV_LOG(ERR, "%s: TCAM Shadow not initialized for %s\n",
509 tf_dir_2_str(parms->dir),
510 tf_tcam_tbl_2_str(parms->type));
514 /* Retrieve the session information */
515 rc = tf_session_get_session_internal(tfp, &tfs);
519 /* Retrieve the device information */
520 rc = tf_session_get_device(tfs, &dev);
524 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
527 "%s: Operation not supported, rc:%s\n",
528 tf_dir_2_str(parms->dir),
533 /* Need to retrieve row size etc */
534 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
542 * Prep the shadow search, reusing the parms from original search
543 * instead of copying them. Shadow will update output in there.
545 memset(&sparms, 0, sizeof(sparms));
546 sparms.sparms = parms;
547 sparms.shadow_db = shadow_tcam_db[parms->dir];
549 rc = tf_shadow_tcam_search(&sparms);
554 * The app didn't request us to alloc the entry, so return now.
555 * The hit should have been updated in the original search parm.
557 if (!parms->alloc || parms->search_status != MISS)
560 /* Caller desires an allocate on miss */
561 if (dev->ops->tf_dev_alloc_tcam == NULL) {
564 "%s: Operation not supported, rc:%s\n",
565 tf_dir_2_str(parms->dir),
569 memset(&aparms, 0, sizeof(aparms));
570 aparms.dir = parms->dir;
571 aparms.type = parms->type;
572 aparms.key_size = parms->key_size;
573 aparms.priority = parms->priority;
574 rc = dev->ops->tf_dev_alloc_tcam(tfp, &aparms);
578 /* Successful allocation, attempt to add it to the shadow */
579 memset(&bparms, 0, sizeof(bparms));
580 bparms.dir = parms->dir;
581 bparms.shadow_db = shadow_tcam_db[parms->dir];
582 bparms.type = parms->type;
583 bparms.key = parms->key;
584 bparms.mask = parms->mask;
585 bparms.key_size = parms->key_size;
586 bparms.idx = aparms.idx;
587 bparms.hb_handle = sparms.hb_handle;
588 rc = tf_shadow_tcam_bind_index(&bparms);
590 /* Error binding entry, need to free the allocated idx */
591 if (dev->ops->tf_dev_free_tcam == NULL) {
594 "%s: Operation not supported, rc:%s\n",
595 tf_dir_2_str(parms->dir),
600 fparms.dir = parms->dir;
601 fparms.type = parms->type;
602 fparms.idx = aparms.idx;
603 rc = dev->ops->tf_dev_free_tcam(tfp, &fparms);
608 /* Add the allocated index to output and done */
609 parms->idx = aparms.idx;
615 tf_tcam_set(struct tf *tfp __rte_unused,
616 struct tf_tcam_set_parms *parms __rte_unused)
619 struct tf_session *tfs;
620 struct tf_dev_info *dev;
621 struct tf_rm_is_allocated_parms aparms;
622 struct tf_rm_get_hcapi_parms hparms;
623 struct tf_shadow_tcam_insert_parms iparms;
624 uint16_t num_slice_per_row = 1;
626 struct tcam_rm_db *tcam_db;
627 void *tcam_db_ptr = NULL;
629 TF_CHECK_PARMS2(tfp, parms);
631 /* Retrieve the session information */
632 rc = tf_session_get_session_internal(tfp, &tfs);
636 /* Retrieve the device information */
637 rc = tf_session_get_device(tfs, &dev);
641 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
644 "%s: Operation not supported, rc:%s\n",
645 tf_dir_2_str(parms->dir),
650 /* Need to retrieve row size etc */
651 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
658 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
661 "Failed to get em_ext_db from session, rc:%s\n",
665 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
667 /* Check if element is in use */
668 memset(&aparms, 0, sizeof(aparms));
670 aparms.rm_db = tcam_db->tcam_db[parms->dir];
671 aparms.subtype = parms->type;
672 aparms.index = parms->idx;
673 aparms.allocated = &allocated;
674 rc = tf_rm_is_allocated(&aparms);
678 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
680 "%s: Entry is not allocated, type:%d, index:%d\n",
681 tf_dir_2_str(parms->dir),
687 /* Convert TF type to HCAPI RM type */
688 memset(&hparms, 0, sizeof(hparms));
690 hparms.rm_db = tcam_db->tcam_db[parms->dir];
691 hparms.subtype = parms->type;
692 hparms.hcapi_type = &parms->hcapi_type;
694 rc = tf_rm_get_hcapi_type(&hparms);
698 rc = tf_msg_tcam_entry_set(tfp, dev, parms);
702 "%s: %s: Entry %d set failed, rc:%s",
703 tf_dir_2_str(parms->dir),
704 tf_tcam_tbl_2_str(parms->type),
710 /* Successfully added to hw, now for shadow if enabled. */
711 if (!shadow_init || !shadow_tcam_db[parms->dir])
714 iparms.shadow_db = shadow_tcam_db[parms->dir];
715 iparms.sparms = parms;
716 rc = tf_shadow_tcam_insert(&iparms);
719 "%s: %s: Entry %d set failed, rc:%s",
720 tf_dir_2_str(parms->dir),
721 tf_tcam_tbl_2_str(parms->type),
731 tf_tcam_get(struct tf *tfp __rte_unused,
732 struct tf_tcam_get_parms *parms)
735 struct tf_session *tfs;
736 struct tf_dev_info *dev;
737 struct tf_rm_is_allocated_parms aparms;
738 struct tf_rm_get_hcapi_parms hparms;
740 struct tcam_rm_db *tcam_db;
741 void *tcam_db_ptr = NULL;
743 TF_CHECK_PARMS2(tfp, parms);
745 /* Retrieve the session information */
746 rc = tf_session_get_session_internal(tfp, &tfs);
750 /* Retrieve the device information */
751 rc = tf_session_get_device(tfs, &dev);
755 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
758 "Failed to get em_ext_db from session, rc:%s\n",
762 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
764 /* Check if element is in use */
765 memset(&aparms, 0, sizeof(aparms));
767 aparms.rm_db = tcam_db->tcam_db[parms->dir];
768 aparms.subtype = parms->type;
769 aparms.index = parms->idx;
770 aparms.allocated = &allocated;
771 rc = tf_rm_is_allocated(&aparms);
775 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
777 "%s: Entry is not allocated, type:%d, index:%d\n",
778 tf_dir_2_str(parms->dir),
784 /* Convert TF type to HCAPI RM type */
785 memset(&hparms, 0, sizeof(hparms));
787 hparms.rm_db = tcam_db->tcam_db[parms->dir];
788 hparms.subtype = parms->type;
789 hparms.hcapi_type = &parms->hcapi_type;
791 rc = tf_rm_get_hcapi_type(&hparms);
795 rc = tf_msg_tcam_entry_get(tfp, dev, parms);
799 "%s: %s: Entry %d set failed, rc:%s",
800 tf_dir_2_str(parms->dir),
801 tf_tcam_tbl_2_str(parms->type),
811 tf_tcam_get_resc_info(struct tf *tfp,
812 struct tf_tcam_resource_info *tcam)
816 struct tf_resource_info *dinfo;
817 struct tf_rm_get_alloc_info_parms ainfo;
818 void *tcam_db_ptr = NULL;
819 struct tcam_rm_db *tcam_db;
821 TF_CHECK_PARMS2(tfp, tcam);
823 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
826 "No resource allocated for tcam from session\n");
829 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
831 /* check if reserved resource for WC is multiple of num_slices */
832 for (d = 0; d < TF_DIR_MAX; d++) {
833 ainfo.rm_db = tcam_db->tcam_db[d];
834 dinfo = tcam[d].info;
836 ainfo.info = (struct tf_rm_alloc_info *)dinfo;
838 rc = tf_rm_get_all_info(&ainfo, TF_TCAM_TBL_TYPE_MAX);
839 if (rc && rc != -ENOTSUP)