net/bnxt: refactor host session failure cleanup
[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 /* Normally, device specific code wouldn't reside here, it belongs
845  * in a separate device specific function in tf_device_pxx.c.
846  * But this code is placed here as it is not a long term solution
847  * and we would like to have this code centrally located for easy
848  * removal
849  */
850 #define TF_TCAM_SHARED_KEY_SLICE_SZ_BYTES_P4 12
851 #define TF_TCAM_SHARED_REMAP_SZ_BYTES_P4 4
852 #define TF_TCAM_SHARED_KEY_SLICE_SZ_BYTES_P58 24
853 #define TF_TCAM_SHARED_REMAP_SZ_BYTES_P58 8
854
855 /* Temporary builder defines pulled in here and adjusted
856  * for max WC TCAM values
857  */
858 union tf_tmp_field_obj {
859         uint32_t words[(TF_TCAM_SHARED_REMAP_SZ_BYTES_P58 + 3) / 4];
860         uint8_t bytes[TF_TCAM_SHARED_REMAP_SZ_BYTES_P58];
861 };
862
863 union tf_tmp_key {
864         uint32_t words[(TF_TCAM_SHARED_KEY_SLICE_SZ_BYTES_P58 + 3) / 4];
865         uint8_t bytes[TF_TCAM_SHARED_KEY_SLICE_SZ_BYTES_P58];
866 };
867
868 /** p58 has an enable bit, p4 does not
869  */
870 #define TF_TCAM_SHARED_ENTRY_ENABLE 0x8
871
872 /** Move a WC TCAM entry from the high offset to the same low offset
873  */
874 static int
875 tf_tcam_shared_move_entry(struct tf *tfp,
876                           struct tf_dev_info *dev,
877                           uint16_t hcapi_type,
878                           enum tf_dir dir,
879                           int sphy_idx,
880                           int dphy_idx,
881                           int key_sz_bytes,
882                           int remap_sz_bytes,
883                           uint16_t num_slices,
884                           bool set_enable_bit)
885 {
886         int rc = 0;
887         struct tf_tcam_get_parms gparms;
888         struct tf_tcam_set_parms sparms;
889         struct tf_tcam_free_parms fparms;
890         union tf_tmp_key tcam_key_obj;
891         union tf_tmp_key tcam_key_msk_obj;
892         union tf_tmp_field_obj tcam_remap_obj;
893
894         memset(&tcam_key_obj, 0, sizeof(tcam_key_obj));
895         memset(&tcam_key_msk_obj, 0, sizeof(tcam_key_msk_obj));
896         memset(&tcam_remap_obj, 0, sizeof(tcam_remap_obj));
897         memset(&gparms, 0, sizeof(gparms));
898
899         if (num_slices > 1) {
900                 TFP_DRV_LOG(ERR,
901                             "Only single slice supported");
902                 return -EOPNOTSUPP;
903         }
904
905         gparms.hcapi_type = hcapi_type;
906         gparms.dir = dir;
907         gparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
908         gparms.idx = sphy_idx;
909         gparms.key = (uint8_t *)&tcam_key_obj;
910         gparms.key_size = key_sz_bytes;
911         gparms.mask = (uint8_t *)&tcam_key_msk_obj;
912         gparms.result = (uint8_t *)&tcam_remap_obj;
913         gparms.result_size = remap_sz_bytes;
914
915         rc = tf_msg_tcam_entry_get(tfp, dev, &gparms);
916         if (rc) {
917                 /* Log error */
918                 TFP_DRV_LOG(ERR,
919                             "%s: WC_TCAM_HIGH: phyid(%d) get failed, rc:%s",
920                             tf_dir_2_str(dir),
921                             gparms.idx,
922                             strerror(-rc));
923                 return rc;
924         }
925
926         if (set_enable_bit)
927                 tcam_key_obj.bytes[0] |= TF_TCAM_SHARED_ENTRY_ENABLE;
928
929         /* Override HI/LO type with parent WC TCAM type */
930         sparms.hcapi_type = hcapi_type;
931         sparms.dir = dir;
932         sparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
933         sparms.idx = dphy_idx;
934         sparms.key = gparms.key;
935         sparms.mask = gparms.mask;
936         sparms.key_size = gparms.key_size;
937         sparms.result = gparms.result;
938         sparms.result_size = gparms.result_size;
939
940         rc = tf_msg_tcam_entry_set(tfp, dev, &sparms);
941         if (rc) {
942                 /* Log error */
943                 TFP_DRV_LOG(ERR,
944                             "%s: WC_TCAM_LOW phyid(%d/0x%x) set failed, rc:%s",
945                             tf_dir_2_str(dir),
946                             sparms.idx,
947                             sparms.idx,
948                             strerror(-rc));
949                 return rc;
950         }
951
952         /* Override HI/LO type with parent WC TCAM type */
953         fparms.dir = dir;
954         fparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
955         fparms.hcapi_type = hcapi_type;
956         fparms.idx = sphy_idx;
957
958         rc = tf_msg_tcam_entry_free(tfp, dev, &fparms);
959         if (rc) {
960                 /* Log error */
961                 TFP_DRV_LOG(ERR,
962                             "%s: %s: phyid(%d/0x%x) free failed, rc:%s\n",
963                             tf_dir_2_str(dir),
964                             tf_tcam_tbl_2_str(fparms.type),
965                             sphy_idx,
966                             sphy_idx,
967                             strerror(-rc));
968                 return rc;
969         }
970         return rc;
971 }
972
973 /** Move all shared WC TCAM entries from the high pool into the low pool
974  *  and clear out the high pool entries.
975  */
976 static
977 int tf_tcam_shared_move(struct tf *tfp,
978                         struct tf_move_tcam_shared_entries_parms *parms,
979                         int key_sz_bytes,
980                         int remap_sz_bytes,
981                         bool set_enable_bit)
982 {
983         int rc;
984         struct tf_session *tfs;
985         struct tf_dev_info *dev;
986         int log_idx;
987         uint16_t num_slices;
988         struct bitalloc *hi_pool, *lo_pool;
989         uint16_t hi_start, lo_start;
990         enum tf_tcam_shared_wc_pool_id hi_id, lo_id;
991         uint16_t hcapi_type;
992         struct tf_rm_alloc_info info;
993         int hi_cnt, i, j;
994         struct tf_tcam_shared_wc_pools *tcam_shared_wc;
995         void *tcam_shared_db_ptr = NULL;
996
997         TF_CHECK_PARMS2(tfp, parms);
998
999         /* Retrieve the session information */
1000         rc = tf_session_get_session_internal(tfp, &tfs);
1001         if (rc)
1002                 return rc;
1003
1004         /* If we aren't the shared session or one of our
1005          * special types
1006          */
1007         if (!tf_session_is_shared_session(tfs) ||
1008             (parms->tcam_tbl_type != TF_TCAM_TBL_TYPE_WC_TCAM_HIGH &&
1009              parms->tcam_tbl_type != TF_TCAM_TBL_TYPE_WC_TCAM_LOW)) {
1010                 TFP_DRV_LOG(ERR,
1011                             "%s: Session must be shared with HI/LO type\n",
1012                             tf_dir_2_str(parms->dir));
1013                 return -EOPNOTSUPP;
1014         }
1015
1016         if (!tf_tcam_db_valid(tfp, parms->dir)) {
1017                 TFP_DRV_LOG(ERR,
1018                             "%s: tcam shared pool doesn't exist\n",
1019                             tf_dir_2_str(parms->dir));
1020                 return -ENOMEM;
1021         }
1022
1023         /* Retrieve the device information */
1024         rc = tf_session_get_device(tfs, &dev);
1025         if (rc) {
1026                 /* TODO print amazing error */
1027                 return rc;
1028         }
1029         rc = tf_tcam_shared_get_slices(tfp, dev, &num_slices);
1030         if (rc)
1031                 return rc;
1032
1033         rc = tf_tcam_shared_get_rm_info(tfp,
1034                                         parms->dir,
1035                                         &hcapi_type,
1036                                         &info);
1037         if (rc) {
1038                 TFP_DRV_LOG(ERR,
1039                             "%s: TCAM rm info get failed\n",
1040                             tf_dir_2_str(parms->dir));
1041                 return rc;
1042         }
1043
1044         rc = tf_session_get_tcam_shared_db(tfp, (void *)&tcam_shared_db_ptr);
1045         if (rc) {
1046                 TFP_DRV_LOG(ERR,
1047                             "Failed to get tcam_shared_db from session, rc:%s\n",
1048                             strerror(-rc));
1049                 return rc;
1050         }
1051         tcam_shared_wc = (struct tf_tcam_shared_wc_pools *)tcam_shared_db_ptr;
1052
1053         hi_id = TF_TCAM_SHARED_WC_POOL_HI;
1054         hi_pool = tcam_shared_wc->db[parms->dir][hi_id].pool;
1055         hi_start = tcam_shared_wc->db[parms->dir][hi_id].info.start;
1056
1057         lo_id = TF_TCAM_SHARED_WC_POOL_LO;
1058         lo_pool = tcam_shared_wc->db[parms->dir][lo_id].pool;
1059         lo_start = tcam_shared_wc->db[parms->dir][lo_id].info.start;
1060
1061         if (hi_pool == NULL || lo_pool == NULL)
1062                 return -ENOMEM;
1063
1064         /* Get the total count of in use entries in the high pool
1065          */
1066         hi_cnt = ba_inuse_count(hi_pool);
1067
1068         /* Copy each valid entry to the same low pool logical offset
1069          */
1070         for (i = 0; i < hi_cnt; i++) {
1071                 /* Go through all the slices
1072                  */
1073                 for (j = 0; j < num_slices; j++) {
1074                         /* Find next free starting from where we left off
1075                          */
1076                         log_idx = ba_find_next_inuse(hi_pool, i);
1077
1078                         if (log_idx < 0) {
1079                                 TFP_DRV_LOG(ERR,
1080                                             "Expected a found %s entry %d\n",
1081                                             tf_pool_2_str(hi_id),
1082                                             i);
1083                                 goto done;
1084                         }
1085                         /* The user should have never allocated from the low
1086                          * pool because the move only happens when switching
1087                          * from the high to the low pool
1088                          */
1089                         if (ba_alloc_index(lo_pool, log_idx) < 0) {
1090                                 TFP_DRV_LOG(ERR,
1091                                             "Cannot allocate %s index %d\n",
1092                                             tf_pool_2_str(lo_id),
1093                                             i);
1094                                 goto done;
1095                         }
1096
1097                         if (j == 0) {
1098                                 rc = tf_tcam_shared_move_entry(tfp, dev,
1099                                                                hcapi_type,
1100                                                                parms->dir,
1101                                                                hi_start + log_idx,
1102                                                                lo_start + log_idx,
1103                                                                key_sz_bytes,
1104                                                                remap_sz_bytes,
1105                                                                num_slices,
1106                                                                set_enable_bit);
1107                                 if (rc) {
1108                                         TFP_DRV_LOG(ERR,
1109                                                     "Cannot allocate %s index %d\n",
1110                                                     tf_pool_2_str(hi_id),
1111                                                     i);
1112                                         goto done;
1113                                 }
1114                                 ba_free(hi_pool, log_idx);
1115                                 TFP_DRV_LOG(DEBUG,
1116                                             "%s: TCAM shared move pool(%s) phyid(%d)\n",
1117                                             tf_dir_2_str(parms->dir),
1118                                             tf_pool_2_str(hi_id),
1119                                             hi_start + log_idx);
1120                                 TFP_DRV_LOG(DEBUG,
1121                                             "to pool(%s) phyid(%d)\n",
1122                                             tf_pool_2_str(lo_id),
1123                                             lo_start + log_idx);
1124                         }
1125                 }
1126         }
1127 done:
1128         return rc;
1129 }
1130
1131 int tf_tcam_shared_move_p4(struct tf *tfp,
1132                            struct tf_move_tcam_shared_entries_parms *parms)
1133 {
1134         int rc = 0;
1135         rc = tf_tcam_shared_move(tfp,
1136                                  parms,
1137                                  TF_TCAM_SHARED_KEY_SLICE_SZ_BYTES_P4,
1138                                  TF_TCAM_SHARED_REMAP_SZ_BYTES_P4,
1139                                  false); /* no enable bit */
1140         return rc;
1141 }
1142
1143
1144 int tf_tcam_shared_move_p58(struct tf *tfp,
1145                             struct tf_move_tcam_shared_entries_parms *parms)
1146 {
1147         int rc = 0;
1148         rc = tf_tcam_shared_move(tfp,
1149                                  parms,
1150                                  TF_TCAM_SHARED_KEY_SLICE_SZ_BYTES_P58,
1151                                  TF_TCAM_SHARED_REMAP_SZ_BYTES_P58,
1152                                  true); /* set enable bit */
1153         return rc;
1154 }