1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019-2021 Broadcom
3 * All rights reserved.
4 */
5
6 #include <string.h>
7 #include <rte_common.h>
8
9 #include "tf_tcam_shared.h"
10 #include "tf_tcam.h"
11 #include "tf_common.h"
12 #include "tf_util.h"
13 #include "tf_rm.h"
14 #include "tf_device.h"
15 #include "tfp.h"
16 #include "tf_session.h"
17 #include "tf_msg.h"
18 #include "bitalloc.h"
19 #include "tf_core.h"
20
21 /** Shared WC TCAM pool identifiers
22 */
23 enum tf_tcam_shared_wc_pool_id {
24 TF_TCAM_SHARED_WC_POOL_HI = 0,
25 TF_TCAM_SHARED_WC_POOL_LO = 1,
26 TF_TCAM_SHARED_WC_POOL_MAX = 2
27 };
28
29 /** Get string representation of a WC TCAM shared pool id
30 */
31 static const char *
tf_pool_2_str(enum tf_tcam_shared_wc_pool_id id)32 tf_pool_2_str(enum tf_tcam_shared_wc_pool_id id)
33 {
34 switch (id) {
35 case TF_TCAM_SHARED_WC_POOL_HI:
36 return "TCAM_SHARED_WC_POOL_HI";
37 case TF_TCAM_SHARED_WC_POOL_LO:
38 return "TCAM_SHARED_WC_POOL_LO";
39 default:
40 return "Invalid TCAM_SHARED_WC_POOL";
41 }
42 }
43
44 /** The WC TCAM shared pool datastructure
45 */
46 struct tf_tcam_shared_wc_pool {
47 /** Start and stride data */
48 struct tf_resource_info info;
49 /** bitalloc pool */
50 struct bitalloc *pool;
51 };
52
53 struct tf_tcam_shared_wc_pools {
54 struct tf_tcam_shared_wc_pool db[TF_DIR_MAX][TF_TCAM_SHARED_WC_POOL_MAX];
55 };
56
57 /** The WC TCAM shared pool declarations
58 */
59 /* struct tf_tcam_shared_wc_pool tcam_shared_wc[TF_DIR_MAX][TF_TCAM_SHARED_WC_POOL_MAX]; */
60
61 static int
tf_tcam_shared_create_db(struct tf_tcam_shared_wc_pools ** db)62 tf_tcam_shared_create_db(struct tf_tcam_shared_wc_pools **db)
63 {
64 struct tfp_calloc_parms cparms;
65 int rc = 0;
66
67 cparms.nitems = 1;
68 cparms.alignment = 0;
69 cparms.size = sizeof(struct tf_tcam_shared_wc_pools);
70 rc = tfp_calloc(&cparms);
71 if (rc) {
72 TFP_DRV_LOG(ERR,
73 "TCAM shared db allocation failed (%s)\n",
74 strerror(-rc));
75 return rc;
76 }
77 *db = cparms.mem_va;
78
79 return rc;
80 }
81
82 /** Create a WC TCAM shared pool
83 */
84 static int
tf_tcam_shared_create_wc_pool(int dir,enum tf_tcam_shared_wc_pool_id id,int start,int stride,struct tf_tcam_shared_wc_pools * tcam_shared_wc)85 tf_tcam_shared_create_wc_pool(int dir,
86 enum tf_tcam_shared_wc_pool_id id,
87 int start,
88 int stride,
89 struct tf_tcam_shared_wc_pools *tcam_shared_wc)
90 {
91 int rc = 0;
92 bool free = true;
93 struct tfp_calloc_parms cparms;
94 uint32_t pool_size;
95
96 /* Create pool */
97 pool_size = (BITALLOC_SIZEOF(stride) / sizeof(struct bitalloc));
98 cparms.nitems = pool_size;
99 cparms.alignment = 0;
100 cparms.size = sizeof(struct bitalloc);
101 rc = tfp_calloc(&cparms);
102 if (rc) {
103 TFP_DRV_LOG(ERR,
104 "%s: pool memory alloc failed %s:%s\n",
105 tf_dir_2_str(dir), tf_pool_2_str(id),
106 strerror(-rc));
107 return rc;
108 }
109 tcam_shared_wc->db[dir][id].pool = (struct bitalloc *)cparms.mem_va;
110
111 rc = ba_init(tcam_shared_wc->db[dir][id].pool,
112 stride,
113 free);
114
115 if (rc) {
116 TFP_DRV_LOG(ERR,
117 "%s: pool bitalloc failed %s\n",
118 tf_dir_2_str(dir), tf_pool_2_str(id));
119 return rc;
120 }
121
122 tcam_shared_wc->db[dir][id].info.start = start;
123 tcam_shared_wc->db[dir][id].info.stride = stride;
124
125 return rc;
126 }
127 /** Free a WC TCAM shared pool
128 */
129 static int
tf_tcam_shared_free_wc_pool(int dir,enum tf_tcam_shared_wc_pool_id id,struct tf_tcam_shared_wc_pools * tcam_shared_wc)130 tf_tcam_shared_free_wc_pool(int dir,
131 enum tf_tcam_shared_wc_pool_id id,
132 struct tf_tcam_shared_wc_pools *tcam_shared_wc)
133 {
134 int rc = 0;
135 TF_CHECK_PARMS1(tcam_shared_wc);
136
137 tcam_shared_wc->db[dir][id].info.start = 0;
138 tcam_shared_wc->db[dir][id].info.stride = 0;
139
140 if (tcam_shared_wc->db[dir][id].pool)
141 tfp_free((void *)tcam_shared_wc->db[dir][id].pool);
142 return rc;
143 }
144
145 /** Get the number of WC TCAM slices allocated during 1 allocation/free
146 */
147 static int
tf_tcam_shared_get_slices(struct tf * tfp,struct tf_dev_info * dev,uint16_t * num_slices)148 tf_tcam_shared_get_slices(struct tf *tfp,
149 struct tf_dev_info *dev,
150 uint16_t *num_slices)
151 {
152 int rc;
153
154 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
155 rc = -EOPNOTSUPP;
156 TFP_DRV_LOG(ERR,
157 "Operation not supported, rc:%s\n", strerror(-rc));
158 return rc;
159 }
160 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
161 TF_TCAM_TBL_TYPE_WC_TCAM,
162 0,
163 num_slices);
164 return rc;
165 }
166
167 static bool
tf_tcam_db_valid(struct tf * tfp,enum tf_dir dir)168 tf_tcam_db_valid(struct tf *tfp,
169 enum tf_dir dir)
170 {
171 struct tcam_rm_db *tcam_db;
172 void *tcam_db_ptr = NULL;
173 int rc;
174
175 TF_CHECK_PARMS1(tfp);
176
177 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
178 if (rc)
179 return false;
180
181 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
182
183 if (tcam_db->tcam_db[dir])
184 return true;
185
186 return false;
187 }
188
189 static int
tf_tcam_shared_get_rm_info(struct tf * tfp,enum tf_dir dir,uint16_t * hcapi_type,struct tf_rm_alloc_info * info)190 tf_tcam_shared_get_rm_info(struct tf *tfp,
191 enum tf_dir dir,
192 uint16_t *hcapi_type,
193 struct tf_rm_alloc_info *info)
194 {
195 int rc;
196 struct tcam_rm_db *tcam_db;
197 void *tcam_db_ptr = NULL;
198 struct tf_rm_get_alloc_info_parms ainfo;
199 struct tf_rm_get_hcapi_parms hparms;
200
201 TF_CHECK_PARMS3(tfp, hcapi_type, info);
202
203 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
204 if (rc) {
205 TFP_DRV_LOG(INFO,
206 "Tcam_db is not initialized, rc:%s\n",
207 strerror(-rc));
208 return 0;
209 }
210 tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
211
212 /* Convert TF type to HCAPI RM type */
213 memset(&hparms, 0, sizeof(hparms));
214 hparms.rm_db = tcam_db->tcam_db[dir];
215 hparms.subtype = TF_TCAM_TBL_TYPE_WC_TCAM;
216 hparms.hcapi_type = hcapi_type;
217
218 rc = tf_rm_get_hcapi_type(&hparms);
219 if (rc) {
220 TFP_DRV_LOG(ERR,
221 "%s: Get RM hcapi type failed %s\n",
222 tf_dir_2_str(dir),
223 strerror(-rc));
224 return rc;
225 }
226
227 memset(info, 0, sizeof(struct tf_rm_alloc_info));
228 ainfo.rm_db = tcam_db->tcam_db[dir];
229 ainfo.subtype = TF_TCAM_TBL_TYPE_WC_TCAM;
230 ainfo.info = info;
231
232 rc = tf_rm_get_info(&ainfo);
233 if (rc) {
234 TFP_DRV_LOG(ERR,
235 "%s: TCAM rm info get failed %s\n",
236 tf_dir_2_str(dir),
237 strerror(-rc));
238 return rc;
239 }
240 return rc;
241 }
242
243 /**
244 * tf_tcam_shared_bind
245 */
246 int
tf_tcam_shared_bind(struct tf * tfp,struct tf_tcam_cfg_parms * parms)247 tf_tcam_shared_bind(struct tf *tfp,
248 struct tf_tcam_cfg_parms *parms)
249 {
250 int rc, dir;
251 struct tf_session *tfs;
252 struct tf_dev_info *dev;
253 struct tf_rm_alloc_info info;
254 uint16_t start, stride;
255 uint16_t num_slices;
256 uint16_t hcapi_type;
257 struct tf_tcam_shared_wc_pools *tcam_shared_wc = NULL;
258
259 TF_CHECK_PARMS2(tfp, parms);
260
261 /* Perform normal bind
262 */
263 rc = tf_tcam_bind(tfp, parms);
264 if (rc)
265 return rc;
266
267 /* After the normal TCAM bind, if this is a shared session
268 * create all required databases for the WC_HI and WC_LO pools
269 */
270 rc = tf_session_get_session_internal(tfp, &tfs);
271 if (rc) {
272 TFP_DRV_LOG(ERR,
273 "Session access failure: %s\n", strerror(-rc));
274 return rc;
275 }
276 if (tf_session_is_shared_session(tfs)) {
277 /* Retrieve the device information */
278 rc = tf_session_get_device(tfs, &dev);
279 if (rc)
280 return rc;
281
282 tf_tcam_shared_create_db(&tcam_shared_wc);
283
284
285 /* If there are WC TCAM entries, create 2 pools each with 1/2
286 * the total number of entries
287 */
288 for (dir = 0; dir < TF_DIR_MAX; dir++) {
289 if (!tf_tcam_db_valid(tfp, dir))
290 continue;
291
292 rc = tf_tcam_shared_get_rm_info(tfp,
293 dir,
294 &hcapi_type,
295 &info);
296 if (rc) {
297 TFP_DRV_LOG(ERR,
298 "%s: TCAM rm info get failed\n",
299 tf_dir_2_str(dir));
300 goto done;
301 }
302
303 start = info.entry.start;
304 stride = info.entry.stride / 2;
305
306 tf_tcam_shared_create_wc_pool(dir,
307 TF_TCAM_SHARED_WC_POOL_HI,
308 start,
309 stride,
310 tcam_shared_wc);
311
312 start += stride;
313 tf_tcam_shared_create_wc_pool(dir,
314 TF_TCAM_SHARED_WC_POOL_LO,
315 start,
316 stride,
317 tcam_shared_wc);
318
319 tf_session_set_tcam_shared_db(tfp, (void *)tcam_shared_wc);
320 }
321
322 rc = tf_tcam_shared_get_slices(tfp,
323 dev,
324 &num_slices);
325 if (rc)
326 return rc;
327
328 if (num_slices > 1) {
329 TFP_DRV_LOG(ERR,
330 "Only single slice supported\n");
331 return -EOPNOTSUPP;
332 }
333 }
334 done:
335 return rc;
336 }
337 /**
338 * tf_tcam_shared_unbind
339 */
340 int
tf_tcam_shared_unbind(struct tf * tfp)341 tf_tcam_shared_unbind(struct tf *tfp)
342 {
343 int rc, dir;
344 struct tf_dev_info *dev;
345 struct tf_session *tfs;
346 void *tcam_shared_db_ptr = NULL;
347 struct tf_tcam_shared_wc_pools *tcam_shared_wc;
348 enum tf_tcam_shared_wc_pool_id pool_id;
349 struct tf_tcam_free_parms parms;
350 struct bitalloc *pool;
351 uint16_t start;
352 int log_idx, phy_idx;
353 uint16_t hcapi_type;
354 struct tf_rm_alloc_info info;
355 int i, pool_cnt;
356
357 TF_CHECK_PARMS1(tfp);
358
359 /* Retrieve the session information */
360 rc = tf_session_get_session_internal(tfp, &tfs);
361 if (rc)
362 return rc;
363
364 /* If not the shared session, call the normal
365 * tcam unbind and exit
366 */
367 if (!tf_session_is_shared_session(tfs)) {
368 rc = tf_tcam_unbind(tfp);
369 return rc;
370 }
371
372 /* We must be a shared session, get the database
373 */
374 rc = tf_session_get_tcam_shared_db(tfp,
375 (void *)&tcam_shared_db_ptr);
376 if (rc) {
377 TFP_DRV_LOG(ERR,
378 "Failed to get tcam_shared_db, rc:%s\n",
379 strerror(-rc));
380 return rc;
381 }
382
383 tcam_shared_wc =
384 (struct tf_tcam_shared_wc_pools *)tcam_shared_db_ptr;
385
386
387 /* Get the device
388 */
389 rc = tf_session_get_device(tfs, &dev);
390 if (rc)
391 return rc;
392
393
394 /* If there are WC TCAM entries allocated, free them
395 */
396 for (dir = 0; dir < TF_DIR_MAX; dir++) {
397 /* If the database is invalid, skip
398 */
399 if (!tf_tcam_db_valid(tfp, dir))
400 continue;
401
402 rc = tf_tcam_shared_get_rm_info(tfp,
403 dir,
404 &hcapi_type,
405 &info);
406 if (rc) {
407 TFP_DRV_LOG(ERR,
408 "%s: TCAM shared rm info get failed\n",
409 tf_dir_2_str(dir));
410 return rc;
411 }
412
413 for (pool_id = TF_TCAM_SHARED_WC_POOL_HI;
414 pool_id < TF_TCAM_SHARED_WC_POOL_MAX;
415 pool_id++) {
416 pool = tcam_shared_wc->db[dir][pool_id].pool;
417 start = tcam_shared_wc->db[dir][pool_id].info.start;
418 pool_cnt = ba_inuse_count(pool);
419
420 if (pool_cnt) {
421 TFP_DRV_LOG(INFO,
422 "%s: %s: %d residuals found, freeing\n",
423 tf_dir_2_str(dir),
424 tf_pool_2_str(pool_id),
425 pool_cnt);
426 }
427
428 log_idx = 0;
429
430 for (i = 0; i < pool_cnt; i++) {
431 log_idx = ba_find_next_inuse(pool, log_idx);
432
433 if (log_idx < 0) {
434 TFP_DRV_LOG(ERR,
435 "Expected a found %s entry %d\n",
436 tf_pool_2_str(pool_id),
437 i);
438 /* attempt normal unbind
439 */
440 goto done;
441 }
442 phy_idx = start + log_idx;
443
444 parms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
445 parms.hcapi_type = hcapi_type;
446 parms.idx = phy_idx;
447 parms.dir = dir;
448 rc = tf_msg_tcam_entry_free(tfp, dev, &parms);
449 if (rc) {
450 /* Log error */
451 TFP_DRV_LOG(ERR,
452 "%s: %s: %d free failed, rc:%s\n",
453 tf_dir_2_str(parms.dir),
454 tf_tcam_tbl_2_str(parms.type),
455 phy_idx,
456 strerror(-rc));
457 return rc;
458 }
459 }
460 /* Free the pool once all the entries
461 * have been cleared
462 */
463 tf_tcam_shared_free_wc_pool(dir,
464 pool_id,
465 tcam_shared_wc);
466 }
467 }
468 done:
469 rc = tf_tcam_unbind(tfp);
470 return rc;
471 }
472
473 /**
474 * tf_tcam_shared_alloc
475 */
476 int
tf_tcam_shared_alloc(struct tf * tfp,struct tf_tcam_alloc_parms * parms)477 tf_tcam_shared_alloc(struct tf *tfp,
478 struct tf_tcam_alloc_parms *parms)
479 {
480 int rc;
481 struct tf_session *tfs;
482 struct tf_dev_info *dev;
483 int log_idx;
484 struct bitalloc *pool;
485 enum tf_tcam_shared_wc_pool_id id;
486 struct tf_tcam_shared_wc_pools *tcam_shared_wc;
487 void *tcam_shared_db_ptr = NULL;
488
489 TF_CHECK_PARMS2(tfp, parms);
490
491 /* Retrieve the session information */
492 rc = tf_session_get_session_internal(tfp, &tfs);
493 if (rc)
494 return rc;
495
496 /* If we aren't the shared session or the type is
497 * not one of the special WC TCAM types, call the normal
498 * allocation.
499 */
500 if (!tf_session_is_shared_session(tfs) ||
501 (parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_HIGH &&
502 parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_LOW)) {
503 /* Perform normal alloc
504 */
505 rc = tf_tcam_alloc(tfp, parms);
506 return rc;
507 }
508
509 if (!tf_tcam_db_valid(tfp, parms->dir)) {
510 TFP_DRV_LOG(ERR,
511 "%s: tcam shared pool doesn't exist\n",
512 tf_dir_2_str(parms->dir));
513 return -ENOMEM;
514 }
515
516 rc = tf_session_get_tcam_shared_db(tfp, (void *)&tcam_shared_db_ptr);
517 if (rc) {
518 TFP_DRV_LOG(ERR,
519 "Failed to get tcam_shared_db from session, rc:%s\n",
520 strerror(-rc));
521 return rc;
522 }
523 tcam_shared_wc = (struct tf_tcam_shared_wc_pools *)tcam_shared_db_ptr;
524
525 if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM_HIGH)
526 id = TF_TCAM_SHARED_WC_POOL_HI;
527 else
528 id = TF_TCAM_SHARED_WC_POOL_LO;
529
530 /* Retrieve the device information */
531 rc = tf_session_get_device(tfs, &dev);
532 if (rc)
533 return rc;
534
535 pool = tcam_shared_wc->db[parms->dir][id].pool;
536
537 /*
538 * priority 0: allocate from top of the tcam i.e. high
539 * priority !0: allocate index from bottom i.e lowest
540 */
541 if (parms->priority)
542 log_idx = ba_alloc_reverse(pool);
543 else
544 log_idx = ba_alloc(pool);
545 if (log_idx == BA_FAIL) {
546 TFP_DRV_LOG(ERR,
547 "%s: Allocation failed, rc:%s\n",
548 tf_dir_2_str(parms->dir),
549 strerror(ENOMEM));
550 return -ENOMEM;
551 }
552 parms->idx = log_idx;
553 return 0;
554 }
555
556 int
tf_tcam_shared_free(struct tf * tfp,struct tf_tcam_free_parms * parms)557 tf_tcam_shared_free(struct tf *tfp,
558 struct tf_tcam_free_parms *parms)
559 {
560 int rc;
561 struct tf_session *tfs;
562 struct tf_dev_info *dev;
563 int allocated = 0;
564 uint16_t start;
565 int phy_idx;
566 struct bitalloc *pool;
567 enum tf_tcam_shared_wc_pool_id id;
568 struct tf_tcam_free_parms nparms;
569 uint16_t hcapi_type;
570 struct tf_rm_alloc_info info;
571 void *tcam_shared_db_ptr = NULL;
572 struct tf_tcam_shared_wc_pools *tcam_shared_wc;
573
574 TF_CHECK_PARMS2(tfp, parms);
575
576 /* Retrieve the session information */
577 rc = tf_session_get_session_internal(tfp, &tfs);
578 if (rc)
579 return rc;
580
581 /* If we aren't the shared session or the type is
582 * not one of the special WC TCAM types, call the normal
583 * allocation.
584 */
585 if (!tf_session_is_shared_session(tfs) ||
586 (parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_HIGH &&
587 parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_LOW)) {
588 /* Perform normal free
589 */
590 rc = tf_tcam_free(tfp, parms);
591 return rc;
592 }
593
594 if (!tf_tcam_db_valid(tfp, parms->dir)) {
595 TFP_DRV_LOG(ERR,
596 "%s: tcam shared pool doesn't exist\n",
597 tf_dir_2_str(parms->dir));
598 return -ENOMEM;
599 }
600
601 rc = tf_session_get_tcam_shared_db(tfp, (void *)&tcam_shared_db_ptr);
602 if (rc) {
603 TFP_DRV_LOG(ERR,
604 "Failed to get tcam_shared_db from session, rc:%s\n",
605 strerror(-rc));
606 return rc;
607 }
608 tcam_shared_wc = (struct tf_tcam_shared_wc_pools *)tcam_shared_db_ptr;
609
610
611 if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM_HIGH)
612 id = TF_TCAM_SHARED_WC_POOL_HI;
613 else
614 id = TF_TCAM_SHARED_WC_POOL_LO;
615
616 /* Retrieve the device information */
617 rc = tf_session_get_device(tfs, &dev);
618 if (rc)
619 return rc;
620
621 rc = tf_tcam_shared_get_rm_info(tfp,
622 parms->dir,
623 &hcapi_type,
624 &info);
625 if (rc) {
626 TFP_DRV_LOG(ERR,
627 "%s: TCAM rm info get failed\n",
628 tf_dir_2_str(parms->dir));
629 return rc;
630 }
631
632 pool = tcam_shared_wc->db[parms->dir][id].pool;
633 start = tcam_shared_wc->db[parms->dir][id].info.start;
634
635 phy_idx = parms->idx + start;
636 allocated = ba_inuse(pool, parms->idx);
637
638 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
639 TFP_DRV_LOG(ERR,
640 "%s: Entry already free, type:%d, idx:%d\n",
641 tf_dir_2_str(parms->dir), parms->type, parms->idx);
642 return -EINVAL;
643 }
644
645 rc = ba_free(pool, parms->idx);
646 if (rc) {
647 TFP_DRV_LOG(ERR,
648 "%s: Free failed, type:%s, idx:%d\n",
649 tf_dir_2_str(parms->dir),
650 tf_tcam_tbl_2_str(parms->type),
651 parms->idx);
652 return rc;
653 }
654
655 /* Override HI/LO type with parent WC TCAM type */
656 nparms = *parms;
657 nparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
658 nparms.hcapi_type = hcapi_type;
659 nparms.idx = phy_idx;
660
661 rc = tf_msg_tcam_entry_free(tfp, dev, &nparms);
662 if (rc) {
663 /* Log error */
664 TFP_DRV_LOG(ERR,
665 "%s: %s: log%d free failed, rc:%s\n",
666 tf_dir_2_str(nparms.dir),
667 tf_tcam_tbl_2_str(nparms.type),
668 phy_idx,
669 strerror(-rc));
670 return rc;
671 }
672 return 0;
673 }
674
675 int
tf_tcam_shared_set(struct tf * tfp __rte_unused,struct tf_tcam_set_parms * parms __rte_unused)676 tf_tcam_shared_set(struct tf *tfp __rte_unused,
677 struct tf_tcam_set_parms *parms __rte_unused)
678 {
679 int rc;
680 struct tf_session *tfs;
681 struct tf_dev_info *dev;
682 int allocated = 0;
683 int phy_idx, log_idx;
684 struct tf_tcam_set_parms nparms;
685 struct bitalloc *pool;
686 uint16_t start;
687 enum tf_tcam_shared_wc_pool_id id;
688 uint16_t hcapi_type;
689 struct tf_rm_alloc_info info;
690 struct tf_tcam_shared_wc_pools *tcam_shared_wc;
691 void *tcam_shared_db_ptr = NULL;
692
693
694 TF_CHECK_PARMS2(tfp, parms);
695
696 /* Retrieve the session information */
697 rc = tf_session_get_session_internal(tfp, &tfs);
698 if (rc)
699 return rc;
700
701 /* If we aren't the shared session or one of our
702 * special types
703 */
704 if (!tf_session_is_shared_session(tfs) ||
705 (parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_HIGH &&
706 parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_LOW)) {
707 /* Perform normal set and exit
708 */
709 rc = tf_tcam_set(tfp, parms);
710 return rc;
711 }
712
713 if (!tf_tcam_db_valid(tfp, parms->dir)) {
714 TFP_DRV_LOG(ERR,
715 "%s: tcam shared pool doesn't exist\n",
716 tf_dir_2_str(parms->dir));
717 return -ENOMEM;
718 }
719
720 /* Retrieve the device information */
721 rc = tf_session_get_device(tfs, &dev);
722 if (rc)
723 return rc;
724
725 if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM_HIGH)
726 id = TF_TCAM_SHARED_WC_POOL_HI;
727 else
728 id = TF_TCAM_SHARED_WC_POOL_LO;
729
730 rc = tf_session_get_tcam_shared_db(tfp, (void *)&tcam_shared_db_ptr);
731 if (rc) {
732 TFP_DRV_LOG(ERR,
733 "Failed to get tcam_shared_db from session, rc:%s\n",
734 strerror(-rc));
735 return rc;
736 }
737 tcam_shared_wc = (struct tf_tcam_shared_wc_pools *)tcam_shared_db_ptr;
738
739 pool = tcam_shared_wc->db[parms->dir][id].pool;
740 start = tcam_shared_wc->db[parms->dir][id].info.start;
741
742 log_idx = parms->idx;
743 phy_idx = parms->idx + start;
744 allocated = ba_inuse(pool, parms->idx);
745
746 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
747 TFP_DRV_LOG(ERR,
748 "%s: Entry is not allocated, type:%d, logid:%d\n",
749 tf_dir_2_str(parms->dir), parms->type, log_idx);
750 return -EINVAL;
751 }
752
753 rc = tf_tcam_shared_get_rm_info(tfp,
754 parms->dir,
755 &hcapi_type,
756 &info);
757 if (rc)
758 return rc;
759
760 /* Override HI/LO type with parent WC TCAM type */
761 nparms.hcapi_type = hcapi_type;
762 nparms.dir = parms->dir;
763 nparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
764 nparms.idx = phy_idx;
765 nparms.key = parms->key;
766 nparms.mask = parms->mask;
767 nparms.key_size = parms->key_size;
768 nparms.result = parms->result;
769 nparms.result_size = parms->result_size;
770
771 rc = tf_msg_tcam_entry_set(tfp, dev, &nparms);
772 if (rc) {
773 /* Log error */
774 TFP_DRV_LOG(ERR,
775 "%s: %s: phy entry %d set failed, rc:%s",
776 tf_dir_2_str(parms->dir),
777 tf_tcam_tbl_2_str(nparms.type),
778 phy_idx,
779 strerror(-rc));
780 return rc;
781 }
782 return 0;
783 }
784
785 int
tf_tcam_shared_get(struct tf * tfp __rte_unused,struct tf_tcam_get_parms * parms)786 tf_tcam_shared_get(struct tf *tfp __rte_unused,
787 struct tf_tcam_get_parms *parms)
788 {
789 int rc;
790 struct tf_session *tfs;
791 struct tf_dev_info *dev;
792 int allocated = 0;
793 int phy_idx, log_idx;
794 struct tf_tcam_get_parms nparms;
795 struct bitalloc *pool;
796 uint16_t start;
797 enum tf_tcam_shared_wc_pool_id id;
798 uint16_t hcapi_type;
799 struct tf_rm_alloc_info info;
800 struct tf_tcam_shared_wc_pools *tcam_shared_wc;
801 void *tcam_shared_db_ptr = NULL;
802
803 TF_CHECK_PARMS2(tfp, parms);
804
805 /* Retrieve the session information */
806 rc = tf_session_get_session_internal(tfp, &tfs);
807 if (rc)
808 return rc;
809
810 /* If we aren't the shared session or one of our
811 * special types
812 */
813 if (!tf_session_is_shared_session(tfs) ||
814 (parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_HIGH &&
815 parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_LOW)) {
816 /* Perform normal get and exit
817 */
818 rc = tf_tcam_get(tfp, parms);
819 return rc;
820 }
821
822 if (!tf_tcam_db_valid(tfp, parms->dir)) {
823 TFP_DRV_LOG(ERR,
824 "%s: tcam shared pool doesn't exist\n",
825 tf_dir_2_str(parms->dir));
826 return -ENOMEM;
827 }
828
829 /* Retrieve the device information */
830 rc = tf_session_get_device(tfs, &dev);
831 if (rc)
832 return rc;
833 if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM_HIGH)
834 id = TF_TCAM_SHARED_WC_POOL_HI;
835 else
836 id = TF_TCAM_SHARED_WC_POOL_LO;
837
838
839 rc = tf_session_get_tcam_shared_db(tfp, (void *)&tcam_shared_db_ptr);
840 if (rc) {
841 TFP_DRV_LOG(ERR,
842 "Failed to get tcam_shared_db from session, rc:%s\n",
843 strerror(-rc));
844 return rc;
845 }
846 tcam_shared_wc = (struct tf_tcam_shared_wc_pools *)tcam_shared_db_ptr;
847
848 pool = tcam_shared_wc->db[parms->dir][id].pool;
849 start = tcam_shared_wc->db[parms->dir][id].info.start;
850
851 log_idx = parms->idx;
852 phy_idx = parms->idx + start;
853 allocated = ba_inuse(pool, parms->idx);
854
855 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
856 TFP_DRV_LOG(ERR,
857 "%s: Entry is not allocated, type:%d, logid:%d\n",
858 tf_dir_2_str(parms->dir), parms->type, log_idx);
859 return -EINVAL;
860 }
861
862 rc = tf_tcam_shared_get_rm_info(tfp,
863 parms->dir,
864 &hcapi_type,
865 &info);
866 if (rc)
867 return rc;
868
869 /* Override HI/LO type with parent WC TCAM type */
870 nparms = *parms;
871 nparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
872 nparms.hcapi_type = hcapi_type;
873 nparms.idx = phy_idx;
874
875 rc = tf_msg_tcam_entry_get(tfp, dev, &nparms);
876 if (rc) {
877 /* Log error */
878 TFP_DRV_LOG(ERR,
879 "%s: %s: Entry %d set failed, rc:%s",
880 tf_dir_2_str(nparms.dir),
881 tf_tcam_tbl_2_str(nparms.type),
882 nparms.idx,
883 strerror(-rc));
884 return rc;
885 }
886 return 0;
887 }
888
889 /* Normally, device specific code wouldn't reside here, it belongs
890 * in a separate device specific function in tf_device_pxx.c.
891 * But this code is placed here as it is not a long term solution
892 * and we would like to have this code centrally located for easy
893 * removal
894 */
895 #define TF_TCAM_SHARED_KEY_SLICE_SZ_BYTES_P4 12
896 #define TF_TCAM_SHARED_REMAP_SZ_BYTES_P4 4
897 #define TF_TCAM_SHARED_KEY_SLICE_SZ_BYTES_P58 24
898 #define TF_TCAM_SHARED_REMAP_SZ_BYTES_P58 8
899
900 /* Temporary builder defines pulled in here and adjusted
901 * for max WC TCAM values
902 */
903 union tf_tmp_field_obj {
904 uint32_t words[(TF_TCAM_SHARED_REMAP_SZ_BYTES_P58 + 3) / 4];
905 uint8_t bytes[TF_TCAM_SHARED_REMAP_SZ_BYTES_P58];
906 };
907
908 union tf_tmp_key {
909 uint32_t words[(TF_TCAM_SHARED_KEY_SLICE_SZ_BYTES_P58 + 3) / 4];
910 uint8_t bytes[TF_TCAM_SHARED_KEY_SLICE_SZ_BYTES_P58];
911 };
912
913 /** p58 has an enable bit, p4 does not
914 */
915 #define TF_TCAM_SHARED_ENTRY_ENABLE 0x8
916
917 /** Move a WC TCAM entry from the high offset to the same low offset
918 */
919 static int
tf_tcam_shared_move_entry(struct tf * tfp,struct tf_dev_info * dev,uint16_t hcapi_type,enum tf_dir dir,int sphy_idx,int dphy_idx,int key_sz_bytes,int remap_sz_bytes,bool set_enable_bit)920 tf_tcam_shared_move_entry(struct tf *tfp,
921 struct tf_dev_info *dev,
922 uint16_t hcapi_type,
923 enum tf_dir dir,
924 int sphy_idx,
925 int dphy_idx,
926 int key_sz_bytes,
927 int remap_sz_bytes,
928 bool set_enable_bit)
929 {
930 int rc = 0;
931 struct tf_tcam_get_parms gparms;
932 struct tf_tcam_set_parms sparms;
933 struct tf_tcam_free_parms fparms;
934 union tf_tmp_key tcam_key_obj;
935 union tf_tmp_key tcam_key_msk_obj;
936 union tf_tmp_field_obj tcam_remap_obj;
937
938 memset(&tcam_key_obj, 0, sizeof(tcam_key_obj));
939 memset(&tcam_key_msk_obj, 0, sizeof(tcam_key_msk_obj));
940 memset(&tcam_remap_obj, 0, sizeof(tcam_remap_obj));
941 memset(&gparms, 0, sizeof(gparms));
942
943 gparms.hcapi_type = hcapi_type;
944 gparms.dir = dir;
945 gparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
946 gparms.idx = sphy_idx;
947 gparms.key = (uint8_t *)&tcam_key_obj;
948 gparms.key_size = key_sz_bytes;
949 gparms.mask = (uint8_t *)&tcam_key_msk_obj;
950 gparms.result = (uint8_t *)&tcam_remap_obj;
951 gparms.result_size = remap_sz_bytes;
952
953 rc = tf_msg_tcam_entry_get(tfp, dev, &gparms);
954 if (rc) {
955 /* Log error */
956 TFP_DRV_LOG(ERR,
957 "%s: %s: phyid(%d) get failed, rc:%s\n",
958 tf_tcam_tbl_2_str(gparms.type),
959 tf_dir_2_str(dir),
960 gparms.idx,
961 strerror(-rc));
962 return rc;
963 }
964
965 if (set_enable_bit)
966 tcam_key_obj.bytes[0] |= TF_TCAM_SHARED_ENTRY_ENABLE;
967
968 /* Override HI/LO type with parent WC TCAM type */
969 sparms.hcapi_type = hcapi_type;
970 sparms.dir = dir;
971 sparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
972 sparms.idx = dphy_idx;
973 sparms.key = gparms.key;
974 sparms.mask = gparms.mask;
975 sparms.key_size = key_sz_bytes;
976 sparms.result = gparms.result;
977 sparms.result_size = remap_sz_bytes;
978
979 rc = tf_msg_tcam_entry_set(tfp, dev, &sparms);
980 if (rc) {
981 /* Log error */
982 TFP_DRV_LOG(ERR,
983 "%s: %s phyid(%d/0x%x) set failed, rc:%s\n",
984 tf_tcam_tbl_2_str(sparms.type),
985 tf_dir_2_str(dir),
986 sparms.idx,
987 sparms.idx,
988 strerror(-rc));
989 return rc;
990 }
991
992 /* Override HI/LO type with parent WC TCAM type */
993 fparms.dir = dir;
994 fparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
995 fparms.hcapi_type = hcapi_type;
996 fparms.idx = sphy_idx;
997
998 rc = tf_msg_tcam_entry_free(tfp, dev, &fparms);
999 if (rc) {
1000 /* Log error */
1001 TFP_DRV_LOG(ERR,
1002 "%s: %s: phyid(%d/0x%x) free failed, rc:%s\n",
1003 tf_dir_2_str(dir),
1004 tf_tcam_tbl_2_str(fparms.type),
1005 sphy_idx,
1006 sphy_idx,
1007 strerror(-rc));
1008 return rc;
1009 }
1010 return rc;
1011 }
1012
1013 /** Move all shared WC TCAM entries from the high pool into the low pool
1014 * and clear out the high pool entries.
1015 */
1016 static
tf_tcam_shared_move(struct tf * tfp,struct tf_move_tcam_shared_entries_parms * parms,int key_sz_bytes,int remap_sz_bytes,bool set_enable_bit)1017 int tf_tcam_shared_move(struct tf *tfp,
1018 struct tf_move_tcam_shared_entries_parms *parms,
1019 int key_sz_bytes,
1020 int remap_sz_bytes,
1021 bool set_enable_bit)
1022 {
1023 int rc;
1024 struct tf_session *tfs;
1025 struct tf_dev_info *dev;
1026 int log_idx;
1027 struct bitalloc *hi_pool, *lo_pool;
1028 uint16_t hi_start, lo_start;
1029 enum tf_tcam_shared_wc_pool_id hi_id, lo_id;
1030 uint16_t hcapi_type;
1031 struct tf_rm_alloc_info info;
1032 int hi_cnt, i;
1033 struct tf_tcam_shared_wc_pools *tcam_shared_wc;
1034 void *tcam_shared_db_ptr = NULL;
1035
1036 TF_CHECK_PARMS2(tfp, parms);
1037
1038 /* Retrieve the session information */
1039 rc = tf_session_get_session_internal(tfp, &tfs);
1040 if (rc)
1041 return rc;
1042
1043 /* If we aren't the shared session or one of our
1044 * special types
1045 */
1046 if (!tf_session_is_shared_session(tfs) ||
1047 (parms->tcam_tbl_type != TF_TCAM_TBL_TYPE_WC_TCAM_HIGH &&
1048 parms->tcam_tbl_type != TF_TCAM_TBL_TYPE_WC_TCAM_LOW)) {
1049 TFP_DRV_LOG(ERR,
1050 "%s: Session must be shared with HI/LO type\n",
1051 tf_dir_2_str(parms->dir));
1052 return -EOPNOTSUPP;
1053 }
1054
1055 if (!tf_tcam_db_valid(tfp, parms->dir)) {
1056 TFP_DRV_LOG(ERR,
1057 "%s: tcam shared pool doesn't exist\n",
1058 tf_dir_2_str(parms->dir));
1059 return -ENOMEM;
1060 }
1061
1062 /* Retrieve the device information */
1063 rc = tf_session_get_device(tfs, &dev);
1064 if (rc) {
1065 /* TODO print amazing error */
1066 return rc;
1067 }
1068
1069 rc = tf_tcam_shared_get_rm_info(tfp,
1070 parms->dir,
1071 &hcapi_type,
1072 &info);
1073 if (rc) {
1074 TFP_DRV_LOG(ERR,
1075 "%s: TCAM rm info get failed\n",
1076 tf_dir_2_str(parms->dir));
1077 return rc;
1078 }
1079
1080 rc = tf_session_get_tcam_shared_db(tfp, (void *)&tcam_shared_db_ptr);
1081 if (rc) {
1082 TFP_DRV_LOG(ERR,
1083 "Failed to get tcam_shared_db from session, rc:%s\n",
1084 strerror(-rc));
1085 return rc;
1086 }
1087 tcam_shared_wc = (struct tf_tcam_shared_wc_pools *)tcam_shared_db_ptr;
1088
1089 hi_id = TF_TCAM_SHARED_WC_POOL_HI;
1090 hi_pool = tcam_shared_wc->db[parms->dir][hi_id].pool;
1091 hi_start = tcam_shared_wc->db[parms->dir][hi_id].info.start;
1092
1093 lo_id = TF_TCAM_SHARED_WC_POOL_LO;
1094 lo_pool = tcam_shared_wc->db[parms->dir][lo_id].pool;
1095 lo_start = tcam_shared_wc->db[parms->dir][lo_id].info.start;
1096
1097 if (hi_pool == NULL || lo_pool == NULL)
1098 return -ENOMEM;
1099
1100 /* Get the total count of in use entries in the high pool
1101 */
1102 hi_cnt = ba_inuse_count(hi_pool);
1103
1104 /* Copy each valid entry to the same low pool logical offset
1105 */
1106 log_idx = 0;
1107
1108 for (i = 0; i < hi_cnt; i++) {
1109 /* Find next free index starting from where we left off
1110 */
1111 log_idx = ba_find_next_inuse(hi_pool, log_idx);
1112 if (log_idx < 0) {
1113 TFP_DRV_LOG(ERR,
1114 "Expected a found %s entry %d\n",
1115 tf_pool_2_str(hi_id),
1116 i);
1117 goto done;
1118 }
1119 /* The user should have never allocated from the low
1120 * pool because the move only happens when switching
1121 * from the high to the low pool
1122 */
1123 if (ba_alloc_index(lo_pool, log_idx) < 0) {
1124 TFP_DRV_LOG(ERR,
1125 "Warning %s index %d already allocated\n",
1126 tf_pool_2_str(lo_id),
1127 i);
1128
1129 /* Since already allocated, continue with move
1130 */
1131 }
1132
1133 rc = tf_tcam_shared_move_entry(tfp, dev,
1134 hcapi_type,
1135 parms->dir,
1136 hi_start + log_idx,
1137 lo_start + log_idx,
1138 key_sz_bytes,
1139 remap_sz_bytes,
1140 set_enable_bit);
1141 if (rc) {
1142 TFP_DRV_LOG(ERR,
1143 "%s: Move error %s to %s index %d\n",
1144 tf_dir_2_str(parms->dir),
1145 tf_pool_2_str(hi_id),
1146 tf_pool_2_str(lo_id),
1147 i);
1148 goto done;
1149 }
1150 ba_free(hi_pool, log_idx);
1151 }
1152 done:
1153 return rc;
1154 }
1155
1156 int
tf_tcam_shared_move_p4(struct tf * tfp,struct tf_move_tcam_shared_entries_parms * parms)1157 tf_tcam_shared_move_p4(struct tf *tfp,
1158 struct tf_move_tcam_shared_entries_parms *parms)
1159 {
1160 int rc = 0;
1161 rc = tf_tcam_shared_move(tfp,
1162 parms,
1163 TF_TCAM_SHARED_KEY_SLICE_SZ_BYTES_P4,
1164 TF_TCAM_SHARED_REMAP_SZ_BYTES_P4,
1165 false); /* no enable bit */
1166 return rc;
1167 }
1168
1169
1170 int
tf_tcam_shared_move_p58(struct tf * tfp,struct tf_move_tcam_shared_entries_parms * parms)1171 tf_tcam_shared_move_p58(struct tf *tfp,
1172 struct tf_move_tcam_shared_entries_parms *parms)
1173 {
1174 int rc = 0;
1175 rc = tf_tcam_shared_move(tfp,
1176 parms,
1177 TF_TCAM_SHARED_KEY_SLICE_SZ_BYTES_P58,
1178 TF_TCAM_SHARED_REMAP_SZ_BYTES_P58,
1179 true); /* set enable bit */
1180 return rc;
1181 }
1182
1183 int
tf_tcam_shared_clear(struct tf * tfp,struct tf_clear_tcam_shared_entries_parms * parms)1184 tf_tcam_shared_clear(struct tf *tfp,
1185 struct tf_clear_tcam_shared_entries_parms *parms)
1186 {
1187 int rc = 0;
1188 struct tf_session *tfs;
1189 struct tf_dev_info *dev;
1190 uint16_t start;
1191 int phy_idx;
1192 enum tf_tcam_shared_wc_pool_id id;
1193 struct tf_tcam_free_parms nparms;
1194 uint16_t hcapi_type;
1195 struct tf_rm_alloc_info info;
1196 void *tcam_shared_db_ptr = NULL;
1197 struct tf_tcam_shared_wc_pools *tcam_shared_wc;
1198 int i, cnt;
1199
1200 TF_CHECK_PARMS2(tfp, parms);
1201
1202 /* Retrieve the session information */
1203 rc = tf_session_get_session_internal(tfp, &tfs);
1204 if (rc)
1205 return rc;
1206
1207 if (!tf_session_is_shared_session(tfs) ||
1208 (parms->tcam_tbl_type != TF_TCAM_TBL_TYPE_WC_TCAM_HIGH &&
1209 parms->tcam_tbl_type != TF_TCAM_TBL_TYPE_WC_TCAM_LOW))
1210 return -EOPNOTSUPP;
1211
1212 if (!tf_tcam_db_valid(tfp, parms->dir)) {
1213 TFP_DRV_LOG(ERR,
1214 "%s: tcam shared pool doesn't exist\n",
1215 tf_dir_2_str(parms->dir));
1216 return -ENOMEM;
1217 }
1218
1219 rc = tf_session_get_tcam_shared_db(tfp, (void *)&tcam_shared_db_ptr);
1220 if (rc) {
1221 TFP_DRV_LOG(ERR,
1222 "Failed to get tcam_shared_db from session, rc:%s\n",
1223 strerror(-rc));
1224 return rc;
1225 }
1226 tcam_shared_wc = (struct tf_tcam_shared_wc_pools *)tcam_shared_db_ptr;
1227
1228
1229 if (parms->tcam_tbl_type == TF_TCAM_TBL_TYPE_WC_TCAM_HIGH)
1230 id = TF_TCAM_SHARED_WC_POOL_HI;
1231 else
1232 id = TF_TCAM_SHARED_WC_POOL_LO;
1233
1234
1235 /* Retrieve the device information */
1236 rc = tf_session_get_device(tfs, &dev);
1237 if (rc)
1238 return rc;
1239
1240 rc = tf_tcam_shared_get_rm_info(tfp,
1241 parms->dir,
1242 &hcapi_type,
1243 &info);
1244 if (rc) {
1245 TFP_DRV_LOG(ERR,
1246 "%s: TCAM rm info get failed\n",
1247 tf_dir_2_str(parms->dir));
1248 return rc;
1249 }
1250
1251 start = tcam_shared_wc->db[parms->dir][id].info.start;
1252 cnt = tcam_shared_wc->db[parms->dir][id].info.stride;
1253
1254 /* Override HI/LO type with parent WC TCAM type */
1255 nparms.dir = parms->dir;
1256 nparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
1257 nparms.hcapi_type = hcapi_type;
1258
1259 for (i = 0; i < cnt; i++) {
1260 phy_idx = start + i;
1261 nparms.idx = phy_idx;
1262
1263 /* Clear entry */
1264 rc = tf_msg_tcam_entry_free(tfp, dev, &nparms);
1265 if (rc) {
1266 /* Log error */
1267 TFP_DRV_LOG(ERR,
1268 "%s: %s: log%d free failed, rc:%s\n",
1269 tf_dir_2_str(nparms.dir),
1270 tf_tcam_tbl_2_str(nparms.type),
1271 phy_idx,
1272 strerror(-rc));
1273 return rc;
1274 }
1275 }
1276
1277 TFP_DRV_LOG(DEBUG,
1278 "%s: TCAM shared clear pool(%s)\n",
1279 tf_dir_2_str(nparms.dir),
1280 tf_pool_2_str(id));
1281 return 0;
1282 }
1283