net/bnxt: add shadow and search capability to TCAM
[dpdk.git] / drivers / net / bnxt / tf_core / tf_tcam.c
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 }