eal: remove sys/queue.h from public headers
[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 /** 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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }