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
tf_tcam_bind(struct tf * tfp,struct tf_tcam_cfg_parms * parms)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
tf_tcam_unbind(struct tf * tfp)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
tf_tcam_alloc(struct tf * tfp,struct tf_tcam_alloc_parms * parms)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
tf_tcam_free(struct tf * tfp,struct tf_tcam_free_parms * parms)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
tf_tcam_alloc_search(struct tf * tfp,struct tf_tcam_alloc_search_parms * parms)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
tf_tcam_set(struct tf * tfp __rte_unused,struct tf_tcam_set_parms * parms __rte_unused)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
tf_tcam_get(struct tf * tfp __rte_unused,struct tf_tcam_get_parms * parms __rte_unused)688 tf_tcam_get(struct tf *tfp __rte_unused,
689 struct tf_tcam_get_parms *parms __rte_unused)
690 {
691 return 0;
692 }
693