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