1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019-2020 Broadcom
3 * All rights reserved.
4 */
5
6 /* Truflow Table APIs and supporting code */
7
8 #include <rte_common.h>
9
10 #include "tf_tbl.h"
11 #include "tf_common.h"
12 #include "tf_rm.h"
13 #include "tf_util.h"
14 #include "tf_msg.h"
15 #include "tfp.h"
16 #include "tf_shadow_tbl.h"
17 #include "tf_session.h"
18 #include "tf_device.h"
19
20
21 struct tf;
22
23 /**
24 * Table DBs.
25 */
26 static void *tbl_db[TF_DIR_MAX];
27
28 /**
29 * Table Shadow DBs
30 */
31 static void *shadow_tbl_db[TF_DIR_MAX];
32
33 /**
34 * Init flag, set on bind and cleared on unbind
35 */
36 static uint8_t init;
37
38 /**
39 * Shadow init flag, set on bind and cleared on unbind
40 */
41 static uint8_t shadow_init;
42
43 int
tf_tbl_bind(struct tf * tfp,struct tf_tbl_cfg_parms * parms)44 tf_tbl_bind(struct tf *tfp,
45 struct tf_tbl_cfg_parms *parms)
46 {
47 int rc, d, i;
48 struct tf_rm_alloc_info info;
49 struct tf_rm_free_db_parms fparms;
50 struct tf_shadow_tbl_free_db_parms fshadow;
51 struct tf_rm_get_alloc_info_parms ainfo;
52 struct tf_shadow_tbl_cfg_parms shadow_cfg;
53 struct tf_shadow_tbl_create_db_parms shadow_cdb;
54 struct tf_rm_create_db_parms db_cfg = { 0 };
55
56 TF_CHECK_PARMS2(tfp, parms);
57
58 if (init) {
59 TFP_DRV_LOG(ERR,
60 "Table DB already initialized\n");
61 return -EINVAL;
62 }
63
64 db_cfg.num_elements = parms->num_elements;
65 db_cfg.type = TF_DEVICE_MODULE_TYPE_TABLE;
66 db_cfg.num_elements = parms->num_elements;
67 db_cfg.cfg = parms->cfg;
68
69 for (d = 0; d < TF_DIR_MAX; d++) {
70 db_cfg.dir = d;
71 db_cfg.alloc_cnt = parms->resources->tbl_cnt[d].cnt;
72 db_cfg.rm_db = &tbl_db[d];
73 rc = tf_rm_create_db(tfp, &db_cfg);
74 if (rc) {
75 TFP_DRV_LOG(ERR,
76 "%s: Table DB creation failed\n",
77 tf_dir_2_str(d));
78
79 return rc;
80 }
81 }
82
83 /* Initialize the Shadow Table. */
84 if (parms->shadow_copy) {
85 for (d = 0; d < TF_DIR_MAX; d++) {
86 memset(&shadow_cfg, 0, sizeof(shadow_cfg));
87 memset(&shadow_cdb, 0, sizeof(shadow_cdb));
88 /* Get the base addresses of the tables */
89 for (i = 0; i < TF_TBL_TYPE_MAX; i++) {
90 memset(&info, 0, sizeof(info));
91
92 if (!parms->resources->tbl_cnt[d].cnt[i])
93 continue;
94 ainfo.rm_db = tbl_db[d];
95 ainfo.db_index = i;
96 ainfo.info = &info;
97 rc = tf_rm_get_info(&ainfo);
98 if (rc)
99 goto error;
100
101 shadow_cfg.base_addr[i] = info.entry.start;
102 }
103
104 /* Create the shadow db */
105 shadow_cfg.alloc_cnt =
106 parms->resources->tbl_cnt[d].cnt;
107 shadow_cfg.num_entries = parms->num_elements;
108
109 shadow_cdb.shadow_db = &shadow_tbl_db[d];
110 shadow_cdb.cfg = &shadow_cfg;
111 rc = tf_shadow_tbl_create_db(&shadow_cdb);
112 if (rc) {
113 TFP_DRV_LOG(ERR,
114 "Shadow TBL DB creation failed "
115 "rc=%d\n", rc);
116 goto error;
117 }
118 }
119 shadow_init = 1;
120 }
121
122 init = 1;
123
124 TFP_DRV_LOG(INFO,
125 "Table Type - initialized\n");
126
127 return 0;
128 error:
129 for (d = 0; d < TF_DIR_MAX; d++) {
130 memset(&fparms, 0, sizeof(fparms));
131 fparms.dir = d;
132 fparms.rm_db = tbl_db[d];
133 /* Ignoring return here since we are in the error case */
134 (void)tf_rm_free_db(tfp, &fparms);
135
136 if (parms->shadow_copy) {
137 fshadow.shadow_db = shadow_tbl_db[d];
138 tf_shadow_tbl_free_db(&fshadow);
139 shadow_tbl_db[d] = NULL;
140 }
141
142 tbl_db[d] = NULL;
143 }
144
145 shadow_init = 0;
146 init = 0;
147
148 return rc;
149 }
150
151 int
tf_tbl_unbind(struct tf * tfp)152 tf_tbl_unbind(struct tf *tfp)
153 {
154 int rc;
155 int i;
156 struct tf_rm_free_db_parms fparms = { 0 };
157 struct tf_shadow_tbl_free_db_parms fshadow;
158
159 TF_CHECK_PARMS1(tfp);
160
161 /* Bail if nothing has been initialized */
162 if (!init) {
163 TFP_DRV_LOG(INFO,
164 "No Table DBs created\n");
165 return 0;
166 }
167
168 for (i = 0; i < TF_DIR_MAX; i++) {
169 fparms.dir = i;
170 fparms.rm_db = tbl_db[i];
171 rc = tf_rm_free_db(tfp, &fparms);
172 if (rc)
173 return rc;
174
175 tbl_db[i] = NULL;
176
177 if (shadow_init) {
178 memset(&fshadow, 0, sizeof(fshadow));
179 fshadow.shadow_db = shadow_tbl_db[i];
180 tf_shadow_tbl_free_db(&fshadow);
181 shadow_tbl_db[i] = NULL;
182 }
183 }
184
185 init = 0;
186 shadow_init = 0;
187
188 return 0;
189 }
190
191 int
tf_tbl_alloc(struct tf * tfp __rte_unused,struct tf_tbl_alloc_parms * parms)192 tf_tbl_alloc(struct tf *tfp __rte_unused,
193 struct tf_tbl_alloc_parms *parms)
194 {
195 int rc;
196 uint32_t idx;
197 struct tf_rm_allocate_parms aparms = { 0 };
198
199 TF_CHECK_PARMS2(tfp, parms);
200
201 if (!init) {
202 TFP_DRV_LOG(ERR,
203 "%s: No Table DBs created\n",
204 tf_dir_2_str(parms->dir));
205 return -EINVAL;
206 }
207
208 /* Allocate requested element */
209 aparms.rm_db = tbl_db[parms->dir];
210 aparms.db_index = parms->type;
211 aparms.index = &idx;
212 rc = tf_rm_allocate(&aparms);
213 if (rc) {
214 TFP_DRV_LOG(ERR,
215 "%s: Failed allocate, type:%d\n",
216 tf_dir_2_str(parms->dir),
217 parms->type);
218 return rc;
219 }
220
221 *parms->idx = idx;
222
223 return 0;
224 }
225
226 int
tf_tbl_free(struct tf * tfp __rte_unused,struct tf_tbl_free_parms * parms)227 tf_tbl_free(struct tf *tfp __rte_unused,
228 struct tf_tbl_free_parms *parms)
229 {
230 int rc;
231 struct tf_rm_is_allocated_parms aparms = { 0 };
232 struct tf_rm_free_parms fparms = { 0 };
233 struct tf_shadow_tbl_remove_parms shparms;
234 int allocated = 0;
235
236 TF_CHECK_PARMS2(tfp, parms);
237
238 if (!init) {
239 TFP_DRV_LOG(ERR,
240 "%s: No Table DBs created\n",
241 tf_dir_2_str(parms->dir));
242 return -EINVAL;
243 }
244
245 /* Check if element is in use */
246 aparms.rm_db = tbl_db[parms->dir];
247 aparms.db_index = parms->type;
248 aparms.index = parms->idx;
249 aparms.allocated = &allocated;
250 rc = tf_rm_is_allocated(&aparms);
251 if (rc)
252 return rc;
253
254 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
255 TFP_DRV_LOG(ERR,
256 "%s: Entry already free, type:%d, index:%d\n",
257 tf_dir_2_str(parms->dir),
258 parms->type,
259 parms->idx);
260 return -EINVAL;
261 }
262
263 /*
264 * The Shadow mgmt, if enabled, determines if the entry needs
265 * to be deleted.
266 */
267 if (shadow_init) {
268 memset(&shparms, 0, sizeof(shparms));
269 shparms.shadow_db = shadow_tbl_db[parms->dir];
270 shparms.fparms = parms;
271 rc = tf_shadow_tbl_remove(&shparms);
272 if (rc) {
273 /*
274 * Should not get here, log it and let the entry be
275 * deleted.
276 */
277 TFP_DRV_LOG(ERR, "%s: Shadow free fail, "
278 "type:%d index:%d deleting the entry.\n",
279 tf_dir_2_str(parms->dir),
280 parms->type,
281 parms->idx);
282 } else {
283 /*
284 * If the entry still has references, just return the
285 * ref count to the caller. No need to remove entry
286 * from rm.
287 */
288 if (parms->ref_cnt >= 1)
289 return rc;
290 }
291 }
292
293 /* Free requested element */
294 fparms.rm_db = tbl_db[parms->dir];
295 fparms.db_index = parms->type;
296 fparms.index = parms->idx;
297 rc = tf_rm_free(&fparms);
298 if (rc) {
299 TFP_DRV_LOG(ERR,
300 "%s: Free failed, type:%d, index:%d\n",
301 tf_dir_2_str(parms->dir),
302 parms->type,
303 parms->idx);
304 return rc;
305 }
306
307 return 0;
308 }
309
310 int
tf_tbl_alloc_search(struct tf * tfp,struct tf_tbl_alloc_search_parms * parms)311 tf_tbl_alloc_search(struct tf *tfp,
312 struct tf_tbl_alloc_search_parms *parms)
313 {
314 int rc, frc;
315 uint32_t idx;
316 struct tf_session *tfs;
317 struct tf_dev_info *dev;
318 struct tf_tbl_alloc_parms aparms;
319 struct tf_shadow_tbl_search_parms sparms;
320 struct tf_shadow_tbl_bind_index_parms bparms;
321 struct tf_tbl_free_parms fparms;
322
323 TF_CHECK_PARMS2(tfp, parms);
324
325 if (!shadow_init || !shadow_tbl_db[parms->dir]) {
326 TFP_DRV_LOG(ERR, "%s: Shadow TBL not initialized.\n",
327 tf_dir_2_str(parms->dir));
328 return -EINVAL;
329 }
330
331 memset(&sparms, 0, sizeof(sparms));
332 sparms.sparms = parms;
333 sparms.shadow_db = shadow_tbl_db[parms->dir];
334 rc = tf_shadow_tbl_search(&sparms);
335 if (rc)
336 return rc;
337
338 /*
339 * The app didn't request us to alloc the entry, so return now.
340 * The hit should have been updated in the original search parm.
341 */
342 if (!parms->alloc || parms->search_status != MISS)
343 return rc;
344
345 /* Retrieve the session information */
346 rc = tf_session_get_session(tfp, &tfs);
347 if (rc) {
348 TFP_DRV_LOG(ERR,
349 "%s: Failed to lookup session, rc:%s\n",
350 tf_dir_2_str(parms->dir),
351 strerror(-rc));
352 return rc;
353 }
354
355 /* Retrieve the device information */
356 rc = tf_session_get_device(tfs, &dev);
357 if (rc) {
358 TFP_DRV_LOG(ERR,
359 "%s: Failed to lookup device, rc:%s\n",
360 tf_dir_2_str(parms->dir),
361 strerror(-rc));
362 return rc;
363 }
364
365 /* Allocate the index */
366 if (dev->ops->tf_dev_alloc_tbl == NULL) {
367 rc = -EOPNOTSUPP;
368 TFP_DRV_LOG(ERR,
369 "%s: Operation not supported, rc:%s\n",
370 tf_dir_2_str(parms->dir),
371 strerror(-rc));
372 return -EOPNOTSUPP;
373 }
374
375 memset(&aparms, 0, sizeof(aparms));
376 aparms.dir = parms->dir;
377 aparms.type = parms->type;
378 aparms.tbl_scope_id = parms->tbl_scope_id;
379 aparms.idx = &idx;
380 rc = dev->ops->tf_dev_alloc_tbl(tfp, &aparms);
381 if (rc) {
382 TFP_DRV_LOG(ERR,
383 "%s: Table allocation failed, rc:%s\n",
384 tf_dir_2_str(parms->dir),
385 strerror(-rc));
386 return rc;
387 }
388
389 /* Bind the allocated index to the data */
390 memset(&bparms, 0, sizeof(bparms));
391 bparms.shadow_db = shadow_tbl_db[parms->dir];
392 bparms.dir = parms->dir;
393 bparms.type = parms->type;
394 bparms.idx = idx;
395 bparms.data = parms->result;
396 bparms.data_sz_in_bytes = parms->result_sz_in_bytes;
397 bparms.hb_handle = sparms.hb_handle;
398 rc = tf_shadow_tbl_bind_index(&bparms);
399 if (rc) {
400 /* Error binding entry, need to free the allocated idx */
401 if (dev->ops->tf_dev_free_tbl == NULL) {
402 rc = -EOPNOTSUPP;
403 TFP_DRV_LOG(ERR,
404 "%s: Operation not supported, rc:%s\n",
405 tf_dir_2_str(parms->dir),
406 strerror(-rc));
407 return rc;
408 }
409
410 memset(&fparms, 0, sizeof(fparms));
411 fparms.dir = parms->dir;
412 fparms.type = parms->type;
413 fparms.idx = idx;
414 frc = dev->ops->tf_dev_free_tbl(tfp, &fparms);
415 if (frc) {
416 TFP_DRV_LOG(ERR,
417 "%s: Failed free index allocated during "
418 "search. rc=%s\n",
419 tf_dir_2_str(parms->dir),
420 strerror(-frc));
421 /* return the original failure. */
422 return rc;
423 }
424 }
425
426 parms->idx = idx;
427
428 return rc;
429 }
430
431 int
tf_tbl_set(struct tf * tfp,struct tf_tbl_set_parms * parms)432 tf_tbl_set(struct tf *tfp,
433 struct tf_tbl_set_parms *parms)
434 {
435 int rc;
436 int allocated = 0;
437 uint16_t hcapi_type;
438 struct tf_rm_is_allocated_parms aparms = { 0 };
439 struct tf_rm_get_hcapi_parms hparms = { 0 };
440
441 TF_CHECK_PARMS3(tfp, parms, parms->data);
442
443 if (!init) {
444 TFP_DRV_LOG(ERR,
445 "%s: No Table DBs created\n",
446 tf_dir_2_str(parms->dir));
447 return -EINVAL;
448 }
449
450 /* Verify that the entry has been previously allocated */
451 aparms.rm_db = tbl_db[parms->dir];
452 aparms.db_index = parms->type;
453 aparms.index = parms->idx;
454 aparms.allocated = &allocated;
455 rc = tf_rm_is_allocated(&aparms);
456 if (rc)
457 return rc;
458
459 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
460 TFP_DRV_LOG(ERR,
461 "%s, Invalid or not allocated index, type:%d, idx:%d\n",
462 tf_dir_2_str(parms->dir),
463 parms->type,
464 parms->idx);
465 return -EINVAL;
466 }
467
468 /* Set the entry */
469 hparms.rm_db = tbl_db[parms->dir];
470 hparms.db_index = parms->type;
471 hparms.hcapi_type = &hcapi_type;
472 rc = tf_rm_get_hcapi_type(&hparms);
473 if (rc) {
474 TFP_DRV_LOG(ERR,
475 "%s, Failed type lookup, type:%d, rc:%s\n",
476 tf_dir_2_str(parms->dir),
477 parms->type,
478 strerror(-rc));
479 return rc;
480 }
481
482 rc = tf_msg_set_tbl_entry(tfp,
483 parms->dir,
484 hcapi_type,
485 parms->data_sz_in_bytes,
486 parms->data,
487 parms->idx);
488 if (rc) {
489 TFP_DRV_LOG(ERR,
490 "%s, Set failed, type:%d, rc:%s\n",
491 tf_dir_2_str(parms->dir),
492 parms->type,
493 strerror(-rc));
494 return rc;
495 }
496
497 return 0;
498 }
499
500 int
tf_tbl_get(struct tf * tfp,struct tf_tbl_get_parms * parms)501 tf_tbl_get(struct tf *tfp,
502 struct tf_tbl_get_parms *parms)
503 {
504 int rc;
505 uint16_t hcapi_type;
506 int allocated = 0;
507 struct tf_rm_is_allocated_parms aparms = { 0 };
508 struct tf_rm_get_hcapi_parms hparms = { 0 };
509
510 TF_CHECK_PARMS3(tfp, parms, parms->data);
511
512 if (!init) {
513 TFP_DRV_LOG(ERR,
514 "%s: No Table DBs created\n",
515 tf_dir_2_str(parms->dir));
516 return -EINVAL;
517 }
518
519 /* Verify that the entry has been previously allocated */
520 aparms.rm_db = tbl_db[parms->dir];
521 aparms.db_index = parms->type;
522 aparms.index = parms->idx;
523 aparms.allocated = &allocated;
524 rc = tf_rm_is_allocated(&aparms);
525 if (rc)
526 return rc;
527
528 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
529 TFP_DRV_LOG(ERR,
530 "%s, Invalid or not allocated index, type:%d, idx:%d\n",
531 tf_dir_2_str(parms->dir),
532 parms->type,
533 parms->idx);
534 return -EINVAL;
535 }
536
537 /* Set the entry */
538 hparms.rm_db = tbl_db[parms->dir];
539 hparms.db_index = parms->type;
540 hparms.hcapi_type = &hcapi_type;
541 rc = tf_rm_get_hcapi_type(&hparms);
542 if (rc) {
543 TFP_DRV_LOG(ERR,
544 "%s, Failed type lookup, type:%d, rc:%s\n",
545 tf_dir_2_str(parms->dir),
546 parms->type,
547 strerror(-rc));
548 return rc;
549 }
550
551 /* Get the entry */
552 rc = tf_msg_get_tbl_entry(tfp,
553 parms->dir,
554 hcapi_type,
555 parms->data_sz_in_bytes,
556 parms->data,
557 parms->idx);
558 if (rc) {
559 TFP_DRV_LOG(ERR,
560 "%s, Get failed, type:%d, rc:%s\n",
561 tf_dir_2_str(parms->dir),
562 parms->type,
563 strerror(-rc));
564 return rc;
565 }
566
567 return 0;
568 }
569
570 int
tf_tbl_bulk_get(struct tf * tfp,struct tf_tbl_get_bulk_parms * parms)571 tf_tbl_bulk_get(struct tf *tfp,
572 struct tf_tbl_get_bulk_parms *parms)
573 {
574 int rc;
575 uint16_t hcapi_type;
576 struct tf_rm_get_hcapi_parms hparms = { 0 };
577 struct tf_rm_check_indexes_in_range_parms cparms = { 0 };
578
579 TF_CHECK_PARMS2(tfp, parms);
580
581 if (!init) {
582 TFP_DRV_LOG(ERR,
583 "%s: No Table DBs created\n",
584 tf_dir_2_str(parms->dir));
585
586 return -EINVAL;
587 }
588
589 /* Verify that the entries are in the range of reserved resources. */
590 cparms.rm_db = tbl_db[parms->dir];
591 cparms.db_index = parms->type;
592 cparms.starting_index = parms->starting_idx;
593 cparms.num_entries = parms->num_entries;
594
595 rc = tf_rm_check_indexes_in_range(&cparms);
596 if (rc) {
597 TFP_DRV_LOG(ERR,
598 "%s, Invalid or %d index starting from %d"
599 " not in range, type:%d",
600 tf_dir_2_str(parms->dir),
601 parms->starting_idx,
602 parms->num_entries,
603 parms->type);
604 return rc;
605 }
606
607 hparms.rm_db = tbl_db[parms->dir];
608 hparms.db_index = parms->type;
609 hparms.hcapi_type = &hcapi_type;
610 rc = tf_rm_get_hcapi_type(&hparms);
611 if (rc) {
612 TFP_DRV_LOG(ERR,
613 "%s, Failed type lookup, type:%d, rc:%s\n",
614 tf_dir_2_str(parms->dir),
615 parms->type,
616 strerror(-rc));
617 return rc;
618 }
619
620 /* Get the entries */
621 rc = tf_msg_bulk_get_tbl_entry(tfp,
622 parms->dir,
623 hcapi_type,
624 parms->starting_idx,
625 parms->num_entries,
626 parms->entry_sz_in_bytes,
627 parms->physical_mem_addr);
628 if (rc) {
629 TFP_DRV_LOG(ERR,
630 "%s, Bulk get failed, type:%d, rc:%s\n",
631 tf_dir_2_str(parms->dir),
632 parms->type,
633 strerror(-rc));
634 }
635
636 return rc;
637 }
638