xref: /dpdk/drivers/net/bnxt/tf_core/tf_tcam.c (revision 3cc6ecfdfe85d2577fef30e1791bb7534e3d60b3)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2020 Broadcom
3  * All rights reserved.
4  */
5 
6 #include <string.h>
7 #include <rte_common.h>
8 
9 #include "tf_tcam.h"
10 #include "tf_common.h"
11 #include "tf_util.h"
12 #include "tf_rm.h"
13 #include "tf_device.h"
14 #include "tfp.h"
15 #include "tf_session.h"
16 #include "tf_msg.h"
17 #include "tf_shadow_tcam.h"
18 
19 struct tf;
20 
21 /**
22  * TCAM DBs.
23  */
24 static void *tcam_db[TF_DIR_MAX];
25 
26 /**
27  * TCAM Shadow DBs
28  */
29 static void *shadow_tcam_db[TF_DIR_MAX];
30 
31 /**
32  * Init flag, set on bind and cleared on unbind
33  */
34 static uint8_t init;
35 
36 /**
37  * Shadow init flag, set on bind and cleared on unbind
38  */
39 static uint8_t shadow_init;
40 
41 int
42 tf_tcam_bind(struct tf *tfp,
43 	     struct tf_tcam_cfg_parms *parms)
44 {
45 	int rc;
46 	int i, d;
47 	struct tf_rm_alloc_info info;
48 	struct tf_rm_free_db_parms fparms;
49 	struct tf_rm_create_db_parms db_cfg;
50 	struct tf_tcam_resources *tcam_cnt;
51 	struct tf_shadow_tcam_free_db_parms fshadow;
52 	struct tf_rm_get_alloc_info_parms ainfo;
53 	struct tf_shadow_tcam_cfg_parms shadow_cfg;
54 	struct tf_shadow_tcam_create_db_parms shadow_cdb;
55 
56 	TF_CHECK_PARMS2(tfp, parms);
57 
58 	if (init) {
59 		TFP_DRV_LOG(ERR,
60 			    "TCAM DB already initialized\n");
61 		return -EINVAL;
62 	}
63 
64 	tcam_cnt = parms->resources->tcam_cnt;
65 	if ((tcam_cnt[TF_DIR_RX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % 2) ||
66 	    (tcam_cnt[TF_DIR_TX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % 2)) {
67 		TFP_DRV_LOG(ERR,
68 			    "Number of WC TCAM entries cannot be odd num\n");
69 		return -EINVAL;
70 	}
71 
72 	memset(&db_cfg, 0, sizeof(db_cfg));
73 
74 	db_cfg.type = TF_DEVICE_MODULE_TYPE_TCAM;
75 	db_cfg.num_elements = parms->num_elements;
76 	db_cfg.cfg = parms->cfg;
77 
78 	for (d = 0; d < TF_DIR_MAX; d++) {
79 		db_cfg.dir = d;
80 		db_cfg.alloc_cnt = parms->resources->tcam_cnt[d].cnt;
81 		db_cfg.rm_db = &tcam_db[d];
82 		rc = tf_rm_create_db(tfp, &db_cfg);
83 		if (rc) {
84 			TFP_DRV_LOG(ERR,
85 				    "%s: TCAM DB creation failed\n",
86 				    tf_dir_2_str(d));
87 			return rc;
88 		}
89 	}
90 
91 	/* Initialize the TCAM manager. */
92 	if (parms->shadow_copy) {
93 		for (d = 0; d < TF_DIR_MAX; d++) {
94 			memset(&shadow_cfg, 0, sizeof(shadow_cfg));
95 			memset(&shadow_cdb, 0, sizeof(shadow_cdb));
96 			/* Get the base addresses of the tcams for tcam mgr */
97 			for (i = 0; i < TF_TCAM_TBL_TYPE_MAX; i++) {
98 				memset(&info, 0, sizeof(info));
99 
100 				if (!parms->resources->tcam_cnt[d].cnt[i])
101 					continue;
102 				ainfo.rm_db = tcam_db[d];
103 				ainfo.db_index = i;
104 				ainfo.info = &info;
105 				rc = tf_rm_get_info(&ainfo);
106 				if (rc)
107 					goto error;
108 
109 				shadow_cfg.base_addr[i] = info.entry.start;
110 			}
111 
112 			/* Create the shadow db */
113 			shadow_cfg.alloc_cnt =
114 				parms->resources->tcam_cnt[d].cnt;
115 			shadow_cfg.num_entries = parms->num_elements;
116 
117 			shadow_cdb.shadow_db = &shadow_tcam_db[d];
118 			shadow_cdb.cfg = &shadow_cfg;
119 			rc = tf_shadow_tcam_create_db(&shadow_cdb);
120 			if (rc) {
121 				TFP_DRV_LOG(ERR,
122 					    "TCAM MGR DB creation failed "
123 					    "rc=%d\n", rc);
124 				goto error;
125 			}
126 		}
127 		shadow_init = 1;
128 	}
129 
130 	init = 1;
131 
132 	TFP_DRV_LOG(INFO,
133 		    "TCAM - initialized\n");
134 
135 	return 0;
136 error:
137 	for (i = 0; i < TF_DIR_MAX; i++) {
138 		memset(&fparms, 0, sizeof(fparms));
139 		fparms.dir = i;
140 		fparms.rm_db = tcam_db[i];
141 		/* Ignoring return here since we are in the error case */
142 		(void)tf_rm_free_db(tfp, &fparms);
143 
144 		if (parms->shadow_copy) {
145 			fshadow.shadow_db = shadow_tcam_db[i];
146 			tf_shadow_tcam_free_db(&fshadow);
147 			shadow_tcam_db[i] = NULL;
148 		}
149 
150 		tcam_db[i] = NULL;
151 	}
152 
153 	shadow_init = 0;
154 	init = 0;
155 
156 	return rc;
157 }
158 
159 int
160 tf_tcam_unbind(struct tf *tfp)
161 {
162 	int rc;
163 	int i;
164 	struct tf_rm_free_db_parms fparms;
165 	struct tf_shadow_tcam_free_db_parms fshadow;
166 
167 	TF_CHECK_PARMS1(tfp);
168 
169 	/* Bail if nothing has been initialized */
170 	if (!init) {
171 		TFP_DRV_LOG(INFO,
172 			    "No TCAM DBs created\n");
173 		return 0;
174 	}
175 
176 	for (i = 0; i < TF_DIR_MAX; i++) {
177 		memset(&fparms, 0, sizeof(fparms));
178 		fparms.dir = i;
179 		fparms.rm_db = tcam_db[i];
180 		rc = tf_rm_free_db(tfp, &fparms);
181 		if (rc)
182 			return rc;
183 
184 		tcam_db[i] = NULL;
185 
186 		if (shadow_init) {
187 			memset(&fshadow, 0, sizeof(fshadow));
188 
189 			fshadow.shadow_db = shadow_tcam_db[i];
190 			tf_shadow_tcam_free_db(&fshadow);
191 			shadow_tcam_db[i] = NULL;
192 		}
193 	}
194 
195 	shadow_init = 0;
196 	init = 0;
197 
198 	return 0;
199 }
200 
201 int
202 tf_tcam_alloc(struct tf *tfp,
203 	      struct tf_tcam_alloc_parms *parms)
204 {
205 	int rc;
206 	struct tf_session *tfs;
207 	struct tf_dev_info *dev;
208 	struct tf_rm_allocate_parms aparms;
209 	uint16_t num_slice_per_row = 1;
210 
211 	TF_CHECK_PARMS2(tfp, parms);
212 
213 	if (!init) {
214 		TFP_DRV_LOG(ERR,
215 			    "%s: No TCAM DBs created\n",
216 			    tf_dir_2_str(parms->dir));
217 		return -EINVAL;
218 	}
219 
220 	/* Retrieve the session information */
221 	rc = tf_session_get_session_internal(tfp, &tfs);
222 	if (rc)
223 		return rc;
224 
225 	/* Retrieve the device information */
226 	rc = tf_session_get_device(tfs, &dev);
227 	if (rc)
228 		return rc;
229 
230 	if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
231 		rc = -EOPNOTSUPP;
232 		TFP_DRV_LOG(ERR,
233 			    "%s: Operation not supported, rc:%s\n",
234 			    tf_dir_2_str(parms->dir),
235 			    strerror(-rc));
236 		return rc;
237 	}
238 
239 	/* Need to retrieve row size etc */
240 	rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
241 						  parms->type,
242 						  parms->key_size,
243 						  &num_slice_per_row);
244 	if (rc)
245 		return rc;
246 
247 	/* Allocate requested element */
248 	memset(&aparms, 0, sizeof(aparms));
249 
250 	aparms.rm_db = tcam_db[parms->dir];
251 	aparms.db_index = parms->type;
252 	aparms.priority = parms->priority;
253 	aparms.index = (uint32_t *)&parms->idx;
254 	rc = tf_rm_allocate(&aparms);
255 	if (rc) {
256 		TFP_DRV_LOG(ERR,
257 			    "%s: Failed tcam, type:%d\n",
258 			    tf_dir_2_str(parms->dir),
259 			    parms->type);
260 		return rc;
261 	}
262 
263 	if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM &&
264 	    (parms->idx % 2) != 0) {
265 		rc = tf_rm_allocate(&aparms);
266 		if (rc) {
267 			TFP_DRV_LOG(ERR,
268 				    "%s: Failed tcam, type:%d\n",
269 				    tf_dir_2_str(parms->dir),
270 				    parms->type);
271 			return rc;
272 		}
273 	}
274 
275 	parms->idx *= num_slice_per_row;
276 
277 	return 0;
278 }
279 
280 int
281 tf_tcam_free(struct tf *tfp,
282 	     struct tf_tcam_free_parms *parms)
283 {
284 	int rc;
285 	struct tf_session *tfs;
286 	struct tf_dev_info *dev;
287 	struct tf_rm_is_allocated_parms aparms;
288 	struct tf_rm_free_parms fparms;
289 	struct tf_rm_get_hcapi_parms hparms;
290 	uint16_t num_slice_per_row = 1;
291 	int allocated = 0;
292 	struct tf_shadow_tcam_remove_parms shparms;
293 
294 	TF_CHECK_PARMS2(tfp, parms);
295 
296 	if (!init) {
297 		TFP_DRV_LOG(ERR,
298 			    "%s: No TCAM DBs created\n",
299 			    tf_dir_2_str(parms->dir));
300 		return -EINVAL;
301 	}
302 
303 	/* Retrieve the session information */
304 	rc = tf_session_get_session_internal(tfp, &tfs);
305 	if (rc)
306 		return rc;
307 
308 	/* Retrieve the device information */
309 	rc = tf_session_get_device(tfs, &dev);
310 	if (rc)
311 		return rc;
312 
313 	if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
314 		rc = -EOPNOTSUPP;
315 		TFP_DRV_LOG(ERR,
316 			    "%s: Operation not supported, rc:%s\n",
317 			    tf_dir_2_str(parms->dir),
318 			    strerror(-rc));
319 		return rc;
320 	}
321 
322 	/* Need to retrieve row size etc */
323 	rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
324 						  parms->type,
325 						  0,
326 						  &num_slice_per_row);
327 	if (rc)
328 		return rc;
329 
330 	/* Check if element is in use */
331 	memset(&aparms, 0, sizeof(aparms));
332 
333 	aparms.rm_db = tcam_db[parms->dir];
334 	aparms.db_index = parms->type;
335 	aparms.index = parms->idx / num_slice_per_row;
336 	aparms.allocated = &allocated;
337 	rc = tf_rm_is_allocated(&aparms);
338 	if (rc)
339 		return rc;
340 
341 	if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
342 		TFP_DRV_LOG(ERR,
343 			    "%s: Entry already free, type:%d, index:%d\n",
344 			    tf_dir_2_str(parms->dir),
345 			    parms->type,
346 			    parms->idx);
347 		return -EINVAL;
348 	}
349 
350 	/*
351 	 * The Shadow mgmt, if enabled, determines if the entry needs
352 	 * to be deleted.
353 	 */
354 	if (shadow_init) {
355 		shparms.shadow_db = shadow_tcam_db[parms->dir];
356 		shparms.fparms = parms;
357 		rc = tf_shadow_tcam_remove(&shparms);
358 		if (rc) {
359 			/*
360 			 * Should not get here, log it and let the entry be
361 			 * deleted.
362 			 */
363 			TFP_DRV_LOG(ERR, "%s: Shadow free fail, "
364 				    "type:%d index:%d deleting the entry.\n",
365 				    tf_dir_2_str(parms->dir),
366 				    parms->type,
367 				    parms->idx);
368 		} else {
369 			/*
370 			 * If the entry still has references, just return the
371 			 * ref count to the caller.  No need to remove entry
372 			 * from rm or hw
373 			 */
374 			if (parms->ref_cnt >= 1)
375 				return rc;
376 		}
377 	}
378 
379 	/* Free requested element */
380 	memset(&fparms, 0, sizeof(fparms));
381 	fparms.rm_db = tcam_db[parms->dir];
382 	fparms.db_index = parms->type;
383 	fparms.index = parms->idx / num_slice_per_row;
384 	rc = tf_rm_free(&fparms);
385 	if (rc) {
386 		TFP_DRV_LOG(ERR,
387 			    "%s: Free failed, type:%d, index:%d\n",
388 			    tf_dir_2_str(parms->dir),
389 			    parms->type,
390 			    parms->idx);
391 		return rc;
392 	}
393 
394 	if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM) {
395 		int i;
396 
397 		for (i = -1; i < 3; i += 3) {
398 			aparms.index += i;
399 			rc = tf_rm_is_allocated(&aparms);
400 			if (rc)
401 				return rc;
402 
403 			if (allocated == TF_RM_ALLOCATED_ENTRY_IN_USE) {
404 				/* Free requested element */
405 				fparms.index = aparms.index;
406 				rc = tf_rm_free(&fparms);
407 				if (rc) {
408 					TFP_DRV_LOG(ERR,
409 						    "%s: Free failed, type:%d, "
410 						    "index:%d\n",
411 						    tf_dir_2_str(parms->dir),
412 						    parms->type,
413 						    fparms.index);
414 					return rc;
415 				}
416 			}
417 		}
418 	}
419 
420 	/* Convert TF type to HCAPI RM type */
421 	memset(&hparms, 0, sizeof(hparms));
422 
423 	hparms.rm_db = tcam_db[parms->dir];
424 	hparms.db_index = parms->type;
425 	hparms.hcapi_type = &parms->hcapi_type;
426 
427 	rc = tf_rm_get_hcapi_type(&hparms);
428 	if (rc)
429 		return rc;
430 
431 	rc = tf_msg_tcam_entry_free(tfp, parms);
432 	if (rc) {
433 		/* Log error */
434 		TFP_DRV_LOG(ERR,
435 			    "%s: %s: Entry %d free failed, rc:%s\n",
436 			    tf_dir_2_str(parms->dir),
437 			    tf_tcam_tbl_2_str(parms->type),
438 			    parms->idx,
439 			    strerror(-rc));
440 		return rc;
441 	}
442 
443 	return 0;
444 }
445 
446 int
447 tf_tcam_alloc_search(struct tf *tfp,
448 		     struct tf_tcam_alloc_search_parms *parms)
449 {
450 	struct tf_shadow_tcam_search_parms sparms;
451 	struct tf_shadow_tcam_bind_index_parms bparms;
452 	struct tf_tcam_alloc_parms aparms;
453 	struct tf_tcam_free_parms fparms;
454 	uint16_t num_slice_per_row = 1;
455 	struct tf_session *tfs;
456 	struct tf_dev_info *dev;
457 	int rc;
458 
459 	TF_CHECK_PARMS2(tfp, parms);
460 
461 	if (!init) {
462 		TFP_DRV_LOG(ERR,
463 			    "%s: No TCAM DBs created\n",
464 			    tf_dir_2_str(parms->dir));
465 		return -EINVAL;
466 	}
467 
468 	if (!shadow_init || !shadow_tcam_db[parms->dir]) {
469 		TFP_DRV_LOG(ERR, "%s: TCAM Shadow not initialized for %s\n",
470 			    tf_dir_2_str(parms->dir),
471 			    tf_tcam_tbl_2_str(parms->type));
472 		return -EINVAL;
473 	}
474 
475 	/* Retrieve the session information */
476 	rc = tf_session_get_session_internal(tfp, &tfs);
477 	if (rc)
478 		return rc;
479 
480 	/* Retrieve the device information */
481 	rc = tf_session_get_device(tfs, &dev);
482 	if (rc)
483 		return rc;
484 
485 	if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
486 		rc = -EOPNOTSUPP;
487 		TFP_DRV_LOG(ERR,
488 			    "%s: Operation not supported, rc:%s\n",
489 			    tf_dir_2_str(parms->dir),
490 			    strerror(-rc));
491 		return rc;
492 	}
493 
494 	/* Need to retrieve row size etc */
495 	rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
496 						  parms->type,
497 						  parms->key_size,
498 						  &num_slice_per_row);
499 	if (rc)
500 		return rc;
501 
502 	/*
503 	 * Prep the shadow search, reusing the parms from original search
504 	 * instead of copying them.  Shadow will update output in there.
505 	 */
506 	memset(&sparms, 0, sizeof(sparms));
507 	sparms.sparms = parms;
508 	sparms.shadow_db = shadow_tcam_db[parms->dir];
509 
510 	rc = tf_shadow_tcam_search(&sparms);
511 	if (rc)
512 		return rc;
513 
514 	/*
515 	 * The app didn't request us to alloc the entry, so return now.
516 	 * The hit should have been updated in the original search parm.
517 	 */
518 	if (!parms->alloc || parms->search_status != MISS)
519 		return rc;
520 
521 	/* Caller desires an allocate on miss */
522 	if (dev->ops->tf_dev_alloc_tcam == NULL) {
523 		rc = -EOPNOTSUPP;
524 		TFP_DRV_LOG(ERR,
525 			    "%s: Operation not supported, rc:%s\n",
526 			    tf_dir_2_str(parms->dir),
527 			    strerror(-rc));
528 		return rc;
529 	}
530 	memset(&aparms, 0, sizeof(aparms));
531 	aparms.dir = parms->dir;
532 	aparms.type = parms->type;
533 	aparms.key_size = parms->key_size;
534 	aparms.priority = parms->priority;
535 	rc = dev->ops->tf_dev_alloc_tcam(tfp, &aparms);
536 	if (rc)
537 		return rc;
538 
539 	/* Successful allocation, attempt to add it to the shadow */
540 	memset(&bparms, 0, sizeof(bparms));
541 	bparms.dir = parms->dir;
542 	bparms.shadow_db = shadow_tcam_db[parms->dir];
543 	bparms.type = parms->type;
544 	bparms.key = parms->key;
545 	bparms.mask = parms->mask;
546 	bparms.key_size = parms->key_size;
547 	bparms.idx = aparms.idx;
548 	bparms.hb_handle = sparms.hb_handle;
549 	rc = tf_shadow_tcam_bind_index(&bparms);
550 	if (rc) {
551 		/* Error binding entry, need to free the allocated idx */
552 		if (dev->ops->tf_dev_free_tcam == NULL) {
553 			rc = -EOPNOTSUPP;
554 			TFP_DRV_LOG(ERR,
555 				    "%s: Operation not supported, rc:%s\n",
556 				    tf_dir_2_str(parms->dir),
557 				    strerror(-rc));
558 			return rc;
559 		}
560 
561 		fparms.dir = parms->dir;
562 		fparms.type = parms->type;
563 		fparms.idx = aparms.idx;
564 		rc = dev->ops->tf_dev_free_tcam(tfp, &fparms);
565 		if (rc)
566 			return rc;
567 	}
568 
569 	/* Add the allocated index to output and done */
570 	parms->idx = aparms.idx;
571 
572 	return 0;
573 }
574 
575 int
576 tf_tcam_set(struct tf *tfp __rte_unused,
577 	    struct tf_tcam_set_parms *parms __rte_unused)
578 {
579 	int rc;
580 	struct tf_session *tfs;
581 	struct tf_dev_info *dev;
582 	struct tf_rm_is_allocated_parms aparms;
583 	struct tf_rm_get_hcapi_parms hparms;
584 	struct tf_shadow_tcam_insert_parms iparms;
585 	uint16_t num_slice_per_row = 1;
586 	int allocated = 0;
587 
588 	TF_CHECK_PARMS2(tfp, parms);
589 
590 	if (!init) {
591 		TFP_DRV_LOG(ERR,
592 			    "%s: No TCAM DBs created\n",
593 			    tf_dir_2_str(parms->dir));
594 		return -EINVAL;
595 	}
596 
597 	/* Retrieve the session information */
598 	rc = tf_session_get_session_internal(tfp, &tfs);
599 	if (rc)
600 		return rc;
601 
602 	/* Retrieve the device information */
603 	rc = tf_session_get_device(tfs, &dev);
604 	if (rc)
605 		return rc;
606 
607 	if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
608 		rc = -EOPNOTSUPP;
609 		TFP_DRV_LOG(ERR,
610 			    "%s: Operation not supported, rc:%s\n",
611 			    tf_dir_2_str(parms->dir),
612 			    strerror(-rc));
613 		return rc;
614 	}
615 
616 	/* Need to retrieve row size etc */
617 	rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
618 						  parms->type,
619 						  parms->key_size,
620 						  &num_slice_per_row);
621 	if (rc)
622 		return rc;
623 
624 	/* Check if element is in use */
625 	memset(&aparms, 0, sizeof(aparms));
626 
627 	aparms.rm_db = tcam_db[parms->dir];
628 	aparms.db_index = parms->type;
629 	aparms.index = parms->idx / num_slice_per_row;
630 	aparms.allocated = &allocated;
631 	rc = tf_rm_is_allocated(&aparms);
632 	if (rc)
633 		return rc;
634 
635 	if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
636 		TFP_DRV_LOG(ERR,
637 			    "%s: Entry is not allocated, type:%d, index:%d\n",
638 			    tf_dir_2_str(parms->dir),
639 			    parms->type,
640 			    parms->idx);
641 		return -EINVAL;
642 	}
643 
644 	/* Convert TF type to HCAPI RM type */
645 	memset(&hparms, 0, sizeof(hparms));
646 
647 	hparms.rm_db = tcam_db[parms->dir];
648 	hparms.db_index = parms->type;
649 	hparms.hcapi_type = &parms->hcapi_type;
650 
651 	rc = tf_rm_get_hcapi_type(&hparms);
652 	if (rc)
653 		return rc;
654 
655 	rc = tf_msg_tcam_entry_set(tfp, parms);
656 	if (rc) {
657 		/* Log error */
658 		TFP_DRV_LOG(ERR,
659 			    "%s: %s: Entry %d set failed, rc:%s",
660 			    tf_dir_2_str(parms->dir),
661 			    tf_tcam_tbl_2_str(parms->type),
662 			    parms->idx,
663 			    strerror(-rc));
664 		return rc;
665 	}
666 
667 	/* Successfully added to hw, now for shadow if enabled. */
668 	if (!shadow_init || !shadow_tcam_db[parms->dir])
669 		return 0;
670 
671 	iparms.shadow_db = shadow_tcam_db[parms->dir];
672 	iparms.sparms = parms;
673 	rc = tf_shadow_tcam_insert(&iparms);
674 	if (rc) {
675 		TFP_DRV_LOG(ERR,
676 			    "%s: %s: Entry %d set failed, rc:%s",
677 			    tf_dir_2_str(parms->dir),
678 			    tf_tcam_tbl_2_str(parms->type),
679 			    parms->idx,
680 			    strerror(-rc));
681 		return rc;
682 	}
683 
684 	return 0;
685 }
686 
687 int
688 tf_tcam_get(struct tf *tfp __rte_unused,
689 	    struct tf_tcam_get_parms *parms __rte_unused)
690 {
691 	return 0;
692 }
693