net/bnxt: fix uninitialized variable
[dpdk.git] / drivers / net / bnxt / tf_core / tf_tbl.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2020 Broadcom
3  * All rights reserved.
4  */
5
6 /* Truflow Table APIs and supporting code */
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdbool.h>
11 #include <math.h>
12 #include <sys/param.h>
13 #include <rte_common.h>
14 #include <rte_errno.h>
15 #include "hsi_struct_def_dpdk.h"
16
17 #include "tf_core.h"
18 #include "tf_em.h"
19 #include "tf_msg.h"
20 #include "tfp.h"
21 #include "hwrm_tf.h"
22 #include "bnxt.h"
23 #include "tf_resources.h"
24 #include "tf_rm.h"
25
26 #define PTU_PTE_VALID          0x1UL
27 #define PTU_PTE_LAST           0x2UL
28 #define PTU_PTE_NEXT_TO_LAST   0x4UL
29
30 /* Number of pointers per page_size */
31 #define MAX_PAGE_PTRS(page_size)  ((page_size) / sizeof(void *))
32
33 #define TF_EM_PG_SZ_4K        (1 << 12)
34 #define TF_EM_PG_SZ_8K        (1 << 13)
35 #define TF_EM_PG_SZ_64K       (1 << 16)
36 #define TF_EM_PG_SZ_256K      (1 << 18)
37 #define TF_EM_PG_SZ_1M        (1 << 20)
38 #define TF_EM_PG_SZ_2M        (1 << 21)
39 #define TF_EM_PG_SZ_4M        (1 << 22)
40 #define TF_EM_PG_SZ_1G        (1 << 30)
41
42 #define TF_EM_CTX_ID_INVALID   0xFFFF
43
44 #define TF_EM_MIN_ENTRIES     (1 << 15) /* 32K */
45 #define TF_EM_MAX_ENTRIES     (1 << 27) /* 128M */
46
47 /**
48  * Function to free a page table
49  *
50  * [in] tp
51  *   Pointer to the page table to free
52  */
53 static void
54 tf_em_free_pg_tbl(struct tf_em_page_tbl *tp)
55 {
56         uint32_t i;
57
58         for (i = 0; i < tp->pg_count; i++) {
59                 if (!tp->pg_va_tbl[i]) {
60                         PMD_DRV_LOG(WARNING,
61                                     "No map for page %d table %016" PRIu64 "\n",
62                                     i,
63                                     (uint64_t)(uintptr_t)tp);
64                         continue;
65                 }
66
67                 tfp_free(tp->pg_va_tbl[i]);
68                 tp->pg_va_tbl[i] = NULL;
69         }
70
71         tp->pg_count = 0;
72         tfp_free(tp->pg_va_tbl);
73         tp->pg_va_tbl = NULL;
74         tfp_free(tp->pg_pa_tbl);
75         tp->pg_pa_tbl = NULL;
76 }
77
78 /**
79  * Function to free an EM table
80  *
81  * [in] tbl
82  *   Pointer to the EM table to free
83  */
84 static void
85 tf_em_free_page_table(struct tf_em_table *tbl)
86 {
87         struct tf_em_page_tbl *tp;
88         int i;
89
90         for (i = 0; i < tbl->num_lvl; i++) {
91                 tp = &tbl->pg_tbl[i];
92
93                 PMD_DRV_LOG(INFO,
94                            "EEM: Freeing page table: size %u lvl %d cnt %u\n",
95                            TF_EM_PAGE_SIZE,
96                             i,
97                             tp->pg_count);
98
99                 tf_em_free_pg_tbl(tp);
100         }
101
102         tbl->l0_addr = NULL;
103         tbl->l0_dma_addr = 0;
104         tbl->num_lvl = 0;
105         tbl->num_data_pages = 0;
106 }
107
108 /**
109  * Allocation of page tables
110  *
111  * [in] tfp
112  *   Pointer to a TruFlow handle
113  *
114  * [in] pg_count
115  *   Page count to allocate
116  *
117  * [in] pg_size
118  *   Size of each page
119  *
120  * Returns:
121  *   0       - Success
122  *   -ENOMEM - Out of memory
123  */
124 static int
125 tf_em_alloc_pg_tbl(struct tf_em_page_tbl *tp,
126                    uint32_t pg_count,
127                    uint32_t pg_size)
128 {
129         uint32_t i;
130         struct tfp_calloc_parms parms;
131
132         parms.nitems = pg_count;
133         parms.size = sizeof(void *);
134         parms.alignment = 0;
135
136         if (tfp_calloc(&parms) != 0)
137                 return -ENOMEM;
138
139         tp->pg_va_tbl = parms.mem_va;
140
141         if (tfp_calloc(&parms) != 0) {
142                 tfp_free(tp->pg_va_tbl);
143                 return -ENOMEM;
144         }
145
146         tp->pg_pa_tbl = parms.mem_va;
147
148         tp->pg_count = 0;
149         tp->pg_size = pg_size;
150
151         for (i = 0; i < pg_count; i++) {
152                 parms.nitems = 1;
153                 parms.size = pg_size;
154                 parms.alignment = TF_EM_PAGE_ALIGNMENT;
155
156                 if (tfp_calloc(&parms) != 0)
157                         goto cleanup;
158
159                 tp->pg_pa_tbl[i] = (uint64_t)(uintptr_t)parms.mem_pa;
160                 tp->pg_va_tbl[i] = parms.mem_va;
161
162                 memset(tp->pg_va_tbl[i], 0, pg_size);
163                 tp->pg_count++;
164         }
165
166         return 0;
167
168 cleanup:
169         tf_em_free_pg_tbl(tp);
170         return -ENOMEM;
171 }
172
173 /**
174  * Allocates EM page tables
175  *
176  * [in] tbl
177  *   Table to allocate pages for
178  *
179  * Returns:
180  *   0       - Success
181  *   -ENOMEM - Out of memory
182  */
183 static int
184 tf_em_alloc_page_table(struct tf_em_table *tbl)
185 {
186         struct tf_em_page_tbl *tp;
187         int rc = 0;
188         int i;
189         uint32_t j;
190
191         for (i = 0; i < tbl->num_lvl; i++) {
192                 tp = &tbl->pg_tbl[i];
193
194                 rc = tf_em_alloc_pg_tbl(tp,
195                                         tbl->page_cnt[i],
196                                         TF_EM_PAGE_SIZE);
197                 if (rc) {
198                         PMD_DRV_LOG(WARNING,
199                                 "Failed to allocate page table: lvl: %d\n",
200                                 i);
201                         goto cleanup;
202                 }
203
204                 for (j = 0; j < tp->pg_count; j++) {
205                         PMD_DRV_LOG(INFO,
206                                 "EEM: Allocated page table: size %u lvl %d cnt"
207                                 " %u VA:%p PA:%p\n",
208                                 TF_EM_PAGE_SIZE,
209                                 i,
210                                 tp->pg_count,
211                                 (uint32_t *)tp->pg_va_tbl[j],
212                                 (uint32_t *)(uintptr_t)tp->pg_pa_tbl[j]);
213                 }
214         }
215         return rc;
216
217 cleanup:
218         tf_em_free_page_table(tbl);
219         return rc;
220 }
221
222 /**
223  * Links EM page tables
224  *
225  * [in] tp
226  *   Pointer to page table
227  *
228  * [in] tp_next
229  *   Pointer to the next page table
230  *
231  * [in] set_pte_last
232  *   Flag controlling if the page table is last
233  */
234 static void
235 tf_em_link_page_table(struct tf_em_page_tbl *tp,
236                       struct tf_em_page_tbl *tp_next,
237                       bool set_pte_last)
238 {
239         uint64_t *pg_pa = tp_next->pg_pa_tbl;
240         uint64_t *pg_va;
241         uint64_t valid;
242         uint32_t k = 0;
243         uint32_t i;
244         uint32_t j;
245
246         for (i = 0; i < tp->pg_count; i++) {
247                 pg_va = tp->pg_va_tbl[i];
248
249                 for (j = 0; j < MAX_PAGE_PTRS(tp->pg_size); j++) {
250                         if (k == tp_next->pg_count - 2 && set_pte_last)
251                                 valid = PTU_PTE_NEXT_TO_LAST | PTU_PTE_VALID;
252                         else if (k == tp_next->pg_count - 1 && set_pte_last)
253                                 valid = PTU_PTE_LAST | PTU_PTE_VALID;
254                         else
255                                 valid = PTU_PTE_VALID;
256
257                         pg_va[j] = tfp_cpu_to_le_64(pg_pa[k] | valid);
258                         if (++k >= tp_next->pg_count)
259                                 return;
260                 }
261         }
262 }
263
264 /**
265  * Setup a EM page table
266  *
267  * [in] tbl
268  *   Pointer to EM page table
269  */
270 static void
271 tf_em_setup_page_table(struct tf_em_table *tbl)
272 {
273         struct tf_em_page_tbl *tp_next;
274         struct tf_em_page_tbl *tp;
275         bool set_pte_last = 0;
276         int i;
277
278         for (i = 0; i < tbl->num_lvl - 1; i++) {
279                 tp = &tbl->pg_tbl[i];
280                 tp_next = &tbl->pg_tbl[i + 1];
281                 if (i == tbl->num_lvl - 2)
282                         set_pte_last = 1;
283                 tf_em_link_page_table(tp, tp_next, set_pte_last);
284         }
285
286         tbl->l0_addr = tbl->pg_tbl[PT_LVL_0].pg_va_tbl[0];
287         tbl->l0_dma_addr = tbl->pg_tbl[PT_LVL_0].pg_pa_tbl[0];
288 }
289
290 /**
291  * Given the page size, size of each data item (entry size),
292  * and the total number of entries needed, determine the number
293  * of page table levels and the number of data pages required.
294  *
295  * [in] page_size
296  *   Page size
297  *
298  * [in] entry_size
299  *   Entry size
300  *
301  * [in] num_entries
302  *   Number of entries needed
303  *
304  * [out] num_data_pages
305  *   Number of pages required
306  *
307  * Returns:
308  *   Success  - Number of EM page levels required
309  *   -ENOMEM  - Out of memory
310  */
311 static int
312 tf_em_size_page_tbl_lvl(uint32_t page_size,
313                         uint32_t entry_size,
314                         uint32_t num_entries,
315                         uint64_t *num_data_pages)
316 {
317         uint64_t lvl_data_size = page_size;
318         int lvl = PT_LVL_0;
319         uint64_t data_size;
320
321         *num_data_pages = 0;
322         data_size = (uint64_t)num_entries * entry_size;
323
324         while (lvl_data_size < data_size) {
325                 lvl++;
326
327                 if (lvl == PT_LVL_1)
328                         lvl_data_size = (uint64_t)MAX_PAGE_PTRS(page_size) *
329                                 page_size;
330                 else if (lvl == PT_LVL_2)
331                         lvl_data_size = (uint64_t)MAX_PAGE_PTRS(page_size) *
332                                 MAX_PAGE_PTRS(page_size) * page_size;
333                 else
334                         return -ENOMEM;
335         }
336
337         *num_data_pages = roundup(data_size, page_size) / page_size;
338
339         return lvl;
340 }
341
342 /**
343  * Return the number of page table pages needed to
344  * reference the given number of next level pages.
345  *
346  * [in] num_pages
347  *   Number of EM pages
348  *
349  * [in] page_size
350  *   Size of each EM page
351  *
352  * Returns:
353  *   Number of EM page table pages
354  */
355 static uint32_t
356 tf_em_page_tbl_pgcnt(uint32_t num_pages,
357                      uint32_t page_size)
358 {
359         return roundup(num_pages, MAX_PAGE_PTRS(page_size)) /
360                        MAX_PAGE_PTRS(page_size);
361         return 0;
362 }
363
364 /**
365  * Given the number of data pages, page_size and the maximum
366  * number of page table levels (already determined), size
367  * the number of page table pages required at each level.
368  *
369  * [in] max_lvl
370  *   Max number of levels
371  *
372  * [in] num_data_pages
373  *   Number of EM data pages
374  *
375  * [in] page_size
376  *   Size of an EM page
377  *
378  * [out] *page_cnt
379  *   EM page count
380  */
381 static void
382 tf_em_size_page_tbls(int max_lvl,
383                      uint64_t num_data_pages,
384                      uint32_t page_size,
385                      uint32_t *page_cnt)
386 {
387         if (max_lvl == PT_LVL_0) {
388                 page_cnt[PT_LVL_0] = num_data_pages;
389         } else if (max_lvl == PT_LVL_1) {
390                 page_cnt[PT_LVL_1] = num_data_pages;
391                 page_cnt[PT_LVL_0] =
392                 tf_em_page_tbl_pgcnt(page_cnt[PT_LVL_1], page_size);
393         } else if (max_lvl == PT_LVL_2) {
394                 page_cnt[PT_LVL_2] = num_data_pages;
395                 page_cnt[PT_LVL_1] =
396                 tf_em_page_tbl_pgcnt(page_cnt[PT_LVL_2], page_size);
397                 page_cnt[PT_LVL_0] =
398                 tf_em_page_tbl_pgcnt(page_cnt[PT_LVL_1], page_size);
399         } else {
400                 return;
401         }
402 }
403
404 /**
405  * Size the EM table based on capabilities
406  *
407  * [in] tbl
408  *   EM table to size
409  *
410  * Returns:
411  *   0        - Success
412  *   - EINVAL - Parameter error
413  *   - ENOMEM - Out of memory
414  */
415 static int
416 tf_em_size_table(struct tf_em_table *tbl)
417 {
418         uint64_t num_data_pages;
419         uint32_t *page_cnt;
420         int max_lvl;
421         uint32_t num_entries;
422         uint32_t cnt = TF_EM_MIN_ENTRIES;
423
424         /* Ignore entry if both size and number are zero */
425         if (!tbl->entry_size && !tbl->num_entries)
426                 return 0;
427
428         /* If only one is set then error */
429         if (!tbl->entry_size || !tbl->num_entries)
430                 return -EINVAL;
431
432         /* Determine number of page table levels and the number
433          * of data pages needed to process the given eem table.
434          */
435         if (tbl->type == RECORD_TABLE) {
436                 /*
437                  * For action records just a memory size is provided. Work
438                  * backwards to resolve to number of entries
439                  */
440                 num_entries = tbl->num_entries / tbl->entry_size;
441                 if (num_entries < TF_EM_MIN_ENTRIES) {
442                         num_entries = TF_EM_MIN_ENTRIES;
443                 } else {
444                         while (num_entries > cnt && cnt <= TF_EM_MAX_ENTRIES)
445                                 cnt *= 2;
446                         num_entries = cnt;
447                 }
448         } else {
449                 num_entries = tbl->num_entries;
450         }
451
452         max_lvl = tf_em_size_page_tbl_lvl(TF_EM_PAGE_SIZE,
453                                           tbl->entry_size,
454                                           tbl->num_entries,
455                                           &num_data_pages);
456         if (max_lvl < 0) {
457                 PMD_DRV_LOG(WARNING, "EEM: Failed to size page table levels\n");
458                 PMD_DRV_LOG(WARNING,
459                             "table: %d data-sz: %016" PRIu64 " page-sz: %u\n",
460                             tbl->type,
461                             (uint64_t)num_entries * tbl->entry_size,
462                             TF_EM_PAGE_SIZE);
463                 return -ENOMEM;
464         }
465
466         tbl->num_lvl = max_lvl + 1;
467         tbl->num_data_pages = num_data_pages;
468
469         /* Determine the number of pages needed at each level */
470         page_cnt = tbl->page_cnt;
471         memset(page_cnt, 0, sizeof(tbl->page_cnt));
472         tf_em_size_page_tbls(max_lvl, num_data_pages, TF_EM_PAGE_SIZE,
473                                 page_cnt);
474
475         PMD_DRV_LOG(INFO, "EEM: Sized page table: %d\n", tbl->type);
476         PMD_DRV_LOG(INFO,
477                     "EEM: lvls: %d sz: %016" PRIu64 " pgs: %016" PRIu64 " l0: %u l1: %u l2: %u\n",
478                     max_lvl + 1,
479                     (uint64_t)num_data_pages * TF_EM_PAGE_SIZE,
480                     num_data_pages,
481                     page_cnt[PT_LVL_0],
482                     page_cnt[PT_LVL_1],
483                     page_cnt[PT_LVL_2]);
484
485         return 0;
486 }
487
488 /**
489  * Unregisters EM Ctx in Firmware
490  *
491  * [in] tfp
492  *   Pointer to a TruFlow handle
493  *
494  * [in] tbl_scope_cb
495  *   Pointer to a table scope control block
496  *
497  * [in] dir
498  *   Receive or transmit direction
499  */
500 static void
501 tf_em_ctx_unreg(struct tf *tfp,
502                 struct tf_tbl_scope_cb *tbl_scope_cb,
503                 int dir)
504 {
505         struct tf_em_ctx_mem_info *ctxp = &tbl_scope_cb->em_ctx_info[dir];
506         struct tf_em_table *tbl;
507         int i;
508
509         for (i = KEY0_TABLE; i < MAX_TABLE; i++) {
510                 tbl = &ctxp->em_tables[i];
511
512                 if (tbl->num_entries != 0 && tbl->entry_size != 0) {
513                         tf_msg_em_mem_unrgtr(tfp, &tbl->ctx_id);
514                         tf_em_free_page_table(tbl);
515                 }
516         }
517 }
518
519 /**
520  * Registers EM Ctx in Firmware
521  *
522  * [in] tfp
523  *   Pointer to a TruFlow handle
524  *
525  * [in] tbl_scope_cb
526  *   Pointer to a table scope control block
527  *
528  * [in] dir
529  *   Receive or transmit direction
530  *
531  * Returns:
532  *   0       - Success
533  *   -ENOMEM - Out of Memory
534  */
535 static int
536 tf_em_ctx_reg(struct tf *tfp,
537               struct tf_tbl_scope_cb *tbl_scope_cb,
538               int dir)
539 {
540         struct tf_em_ctx_mem_info *ctxp = &tbl_scope_cb->em_ctx_info[dir];
541         struct tf_em_table *tbl;
542         int rc = 0;
543         int i;
544
545         for (i = KEY0_TABLE; i < MAX_TABLE; i++) {
546                 tbl = &ctxp->em_tables[i];
547
548                 if (tbl->num_entries && tbl->entry_size) {
549                         rc = tf_em_size_table(tbl);
550
551                         if (rc)
552                                 goto cleanup;
553
554                         rc = tf_em_alloc_page_table(tbl);
555                         if (rc)
556                                 goto cleanup;
557
558                         tf_em_setup_page_table(tbl);
559                         rc = tf_msg_em_mem_rgtr(tfp,
560                                                 tbl->num_lvl - 1,
561                                                 TF_EM_PAGE_SIZE_ENUM,
562                                                 tbl->l0_dma_addr,
563                                                 &tbl->ctx_id);
564                         if (rc)
565                                 goto cleanup;
566                 }
567         }
568         return rc;
569
570 cleanup:
571         tf_em_ctx_unreg(tfp, tbl_scope_cb, dir);
572         return rc;
573 }
574
575 /**
576  * Validates EM number of entries requested
577  *
578  * [in] tbl_scope_cb
579  *   Pointer to table scope control block to be populated
580  *
581  * [in] parms
582  *   Pointer to input parameters
583  *
584  * Returns:
585  *   0       - Success
586  *   -EINVAL - Parameter error
587  */
588 static int
589 tf_em_validate_num_entries(struct tf_tbl_scope_cb *tbl_scope_cb,
590                            struct tf_alloc_tbl_scope_parms *parms)
591 {
592         uint32_t cnt;
593
594         if (parms->rx_mem_size_in_mb != 0) {
595                 uint32_t key_b = 2 * ((parms->rx_max_key_sz_in_bits / 8) + 1);
596                 uint32_t action_b = ((parms->rx_max_action_entry_sz_in_bits / 8)
597                                      + 1);
598                 uint32_t num_entries = (parms->rx_mem_size_in_mb *
599                                         TF_MEGABYTE) / (key_b + action_b);
600
601                 if (num_entries < TF_EM_MIN_ENTRIES) {
602                         PMD_DRV_LOG(ERR, "EEM: Insufficient memory requested:"
603                                     "%uMB\n",
604                                     parms->rx_mem_size_in_mb);
605                         return -EINVAL;
606                 }
607
608                 cnt = TF_EM_MIN_ENTRIES;
609                 while (num_entries > cnt &&
610                        cnt <= TF_EM_MAX_ENTRIES)
611                         cnt *= 2;
612
613                 if (cnt > TF_EM_MAX_ENTRIES) {
614                         PMD_DRV_LOG(ERR, "EEM: Invalid number of Tx requested: "
615                                     "%u\n",
616                        (parms->tx_num_flows_in_k * TF_KILOBYTE));
617                         return -EINVAL;
618                 }
619
620                 parms->rx_num_flows_in_k = cnt / TF_KILOBYTE;
621         } else {
622                 if ((parms->rx_num_flows_in_k * TF_KILOBYTE) <
623                     TF_EM_MIN_ENTRIES ||
624                     (parms->rx_num_flows_in_k * TF_KILOBYTE) >
625                     tbl_scope_cb->em_caps[TF_DIR_RX].max_entries_supported) {
626                         PMD_DRV_LOG(ERR,
627                                     "EEM: Invalid number of Rx flows "
628                                     "requested:%u max:%u\n",
629                                     parms->rx_num_flows_in_k * TF_KILOBYTE,
630                         tbl_scope_cb->em_caps[TF_DIR_RX].max_entries_supported);
631                         return -EINVAL;
632                 }
633
634                 /* must be a power-of-2 supported value
635                  * in the range 32K - 128M
636                  */
637                 cnt = TF_EM_MIN_ENTRIES;
638                 while ((parms->rx_num_flows_in_k * TF_KILOBYTE) != cnt &&
639                        cnt <= TF_EM_MAX_ENTRIES)
640                         cnt *= 2;
641
642                 if (cnt > TF_EM_MAX_ENTRIES) {
643                         PMD_DRV_LOG(ERR,
644                                     "EEM: Invalid number of Rx requested: %u\n",
645                                     (parms->rx_num_flows_in_k * TF_KILOBYTE));
646                         return -EINVAL;
647                 }
648         }
649
650         if (parms->tx_mem_size_in_mb != 0) {
651                 uint32_t key_b = 2 * (parms->tx_max_key_sz_in_bits / 8 + 1);
652                 uint32_t action_b = ((parms->tx_max_action_entry_sz_in_bits / 8)
653                                      + 1);
654                 uint32_t num_entries = (parms->tx_mem_size_in_mb *
655                                         (TF_KILOBYTE * TF_KILOBYTE)) /
656                         (key_b + action_b);
657
658                 if (num_entries < TF_EM_MIN_ENTRIES) {
659                         PMD_DRV_LOG(ERR,
660                                     "EEM: Insufficient memory requested:%uMB\n",
661                                     parms->rx_mem_size_in_mb);
662                         return -EINVAL;
663                 }
664
665                 cnt = TF_EM_MIN_ENTRIES;
666                 while (num_entries > cnt &&
667                        cnt <= TF_EM_MAX_ENTRIES)
668                         cnt *= 2;
669
670                 if (cnt > TF_EM_MAX_ENTRIES) {
671                         PMD_DRV_LOG(ERR,
672                                     "EEM: Invalid number of Tx requested: %u\n",
673                        (parms->tx_num_flows_in_k * TF_KILOBYTE));
674                         return -EINVAL;
675                 }
676
677                 parms->tx_num_flows_in_k = cnt / TF_KILOBYTE;
678         } else {
679                 if ((parms->tx_num_flows_in_k * TF_KILOBYTE) <
680                     TF_EM_MIN_ENTRIES ||
681                     (parms->tx_num_flows_in_k * TF_KILOBYTE) >
682                     tbl_scope_cb->em_caps[TF_DIR_TX].max_entries_supported) {
683                         PMD_DRV_LOG(ERR,
684                                     "EEM: Invalid number of Tx flows "
685                                     "requested:%u max:%u\n",
686                                     (parms->tx_num_flows_in_k * TF_KILOBYTE),
687                         tbl_scope_cb->em_caps[TF_DIR_TX].max_entries_supported);
688                         return -EINVAL;
689                 }
690
691                 cnt = TF_EM_MIN_ENTRIES;
692                 while ((parms->tx_num_flows_in_k * TF_KILOBYTE) != cnt &&
693                        cnt <= TF_EM_MAX_ENTRIES)
694                         cnt *= 2;
695
696                 if (cnt > TF_EM_MAX_ENTRIES) {
697                         PMD_DRV_LOG(ERR,
698                                     "EEM: Invalid number of Tx requested: %u\n",
699                        (parms->tx_num_flows_in_k * TF_KILOBYTE));
700                         return -EINVAL;
701                 }
702         }
703
704         if (parms->rx_num_flows_in_k != 0 &&
705             (parms->rx_max_key_sz_in_bits / 8 == 0)) {
706                 PMD_DRV_LOG(ERR,
707                             "EEM: Rx key size required: %u\n",
708                             (parms->rx_max_key_sz_in_bits));
709                 return -EINVAL;
710         }
711
712         if (parms->tx_num_flows_in_k != 0 &&
713             (parms->tx_max_key_sz_in_bits / 8 == 0)) {
714                 PMD_DRV_LOG(ERR,
715                             "EEM: Tx key size required: %u\n",
716                             (parms->tx_max_key_sz_in_bits));
717                 return -EINVAL;
718         }
719         /* Rx */
720         tbl_scope_cb->em_ctx_info[TF_DIR_RX].em_tables[KEY0_TABLE].num_entries =
721                 parms->rx_num_flows_in_k * TF_KILOBYTE;
722         tbl_scope_cb->em_ctx_info[TF_DIR_RX].em_tables[KEY0_TABLE].entry_size =
723                 parms->rx_max_key_sz_in_bits / 8;
724
725         tbl_scope_cb->em_ctx_info[TF_DIR_RX].em_tables[KEY1_TABLE].num_entries =
726                 parms->rx_num_flows_in_k * TF_KILOBYTE;
727         tbl_scope_cb->em_ctx_info[TF_DIR_RX].em_tables[KEY1_TABLE].entry_size =
728                 parms->rx_max_key_sz_in_bits / 8;
729
730         tbl_scope_cb->em_ctx_info[TF_DIR_RX].em_tables[RECORD_TABLE].num_entries =
731                 parms->rx_num_flows_in_k * TF_KILOBYTE;
732         tbl_scope_cb->em_ctx_info[TF_DIR_RX].em_tables[RECORD_TABLE].entry_size =
733                 parms->rx_max_action_entry_sz_in_bits / 8;
734
735         tbl_scope_cb->em_ctx_info[TF_DIR_RX].em_tables[EFC_TABLE].num_entries =
736                 0;
737
738         /* Tx */
739         tbl_scope_cb->em_ctx_info[TF_DIR_TX].em_tables[KEY0_TABLE].num_entries =
740                 parms->tx_num_flows_in_k * TF_KILOBYTE;
741         tbl_scope_cb->em_ctx_info[TF_DIR_TX].em_tables[KEY0_TABLE].entry_size =
742                 parms->tx_max_key_sz_in_bits / 8;
743
744         tbl_scope_cb->em_ctx_info[TF_DIR_TX].em_tables[KEY1_TABLE].num_entries =
745                 parms->tx_num_flows_in_k * TF_KILOBYTE;
746         tbl_scope_cb->em_ctx_info[TF_DIR_TX].em_tables[KEY1_TABLE].entry_size =
747                 parms->tx_max_key_sz_in_bits / 8;
748
749         tbl_scope_cb->em_ctx_info[TF_DIR_TX].em_tables[RECORD_TABLE].num_entries =
750                 parms->tx_num_flows_in_k * TF_KILOBYTE;
751         tbl_scope_cb->em_ctx_info[TF_DIR_TX].em_tables[RECORD_TABLE].entry_size =
752                 parms->tx_max_action_entry_sz_in_bits / 8;
753
754         tbl_scope_cb->em_ctx_info[TF_DIR_TX].em_tables[EFC_TABLE].num_entries =
755                 0;
756
757         return 0;
758 }
759
760 /**
761  * Internal function to set a Table Entry. Supports all internal Table Types
762  *
763  * [in] tfp
764  *   Pointer to TruFlow handle
765  *
766  * [in] parms
767  *   Pointer to input parameters
768  *
769  * Returns:
770  *   0       - Success
771  *   -EINVAL - Parameter error
772  */
773 static int
774 tf_set_tbl_entry_internal(struct tf *tfp,
775                           struct tf_set_tbl_entry_parms *parms)
776 {
777         int rc;
778         int id;
779         uint32_t index;
780         struct bitalloc *session_pool;
781         struct tf_session *tfs = (struct tf_session *)(tfp->session->core_data);
782
783         /* Lookup the pool using the table type of the element */
784         rc = tf_rm_lookup_tbl_type_pool(tfs,
785                                         parms->dir,
786                                         parms->type,
787                                         &session_pool);
788         /* Error logging handled by tf_rm_lookup_tbl_type_pool */
789         if (rc)
790                 return rc;
791
792         index = parms->idx;
793
794         if (parms->type != TF_TBL_TYPE_FULL_ACT_RECORD &&
795             parms->type != TF_TBL_TYPE_ACT_SP_SMAC_IPV4) {
796                 PMD_DRV_LOG(ERR,
797                             "dir:%d, Type not supported, type:%d\n",
798                             parms->dir,
799                             parms->type);
800                 return -EOPNOTSUPP;
801         }
802
803         /* Adjust the returned index/offset as there is no guarantee
804          * that the start is 0 at time of RM allocation
805          */
806         tf_rm_convert_index(tfs,
807                             parms->dir,
808                             parms->type,
809                             TF_RM_CONVERT_RM_BASE,
810                             parms->idx,
811                             &index);
812
813         /* Verify that the entry has been previously allocated */
814         id = ba_inuse(session_pool, index);
815         if (id != 1) {
816                 PMD_DRV_LOG(ERR,
817                    "dir:%d, Invalid or not allocated index, type:%d, idx:%d\n",
818                    parms->dir,
819                    parms->type,
820                    index);
821                 return -EINVAL;
822         }
823
824         /* Set the entry */
825         rc = tf_msg_set_tbl_entry(tfp,
826                                   parms->dir,
827                                   parms->type,
828                                   parms->data_sz_in_bytes,
829                                   parms->data,
830                                   parms->idx);
831         if (rc) {
832                 PMD_DRV_LOG(ERR,
833                             "dir:%d, Set failed, type:%d, rc:%d\n",
834                             parms->dir,
835                             parms->type,
836                             rc);
837         }
838
839         return rc;
840 }
841
842 /**
843  * Internal function to get a Table Entry. Supports all Table Types
844  * except the TF_TBL_TYPE_EXT as that is handled as a table scope.
845  *
846  * [in] tfp
847  *   Pointer to TruFlow handle
848  *
849  * [in] parms
850  *   Pointer to input parameters
851  *
852  * Returns:
853  *   0       - Success
854  *   -EINVAL - Parameter error
855  */
856 static int
857 tf_get_tbl_entry_internal(struct tf *tfp,
858                           struct tf_get_tbl_entry_parms *parms)
859 {
860         int rc;
861         int id;
862         uint32_t index;
863         struct bitalloc *session_pool;
864         struct tf_session *tfs = (struct tf_session *)(tfp->session->core_data);
865
866         /* Lookup the pool using the table type of the element */
867         rc = tf_rm_lookup_tbl_type_pool(tfs,
868                                         parms->dir,
869                                         parms->type,
870                                         &session_pool);
871         /* Error logging handled by tf_rm_lookup_tbl_type_pool */
872         if (rc)
873                 return rc;
874
875         index = parms->idx;
876
877         /* Adjust the returned index/offset as there is no guarantee
878          * that the start is 0 at time of RM allocation
879          */
880         tf_rm_convert_index(tfs,
881                             parms->dir,
882                             parms->type,
883                             TF_RM_CONVERT_RM_BASE,
884                             parms->idx,
885                             &index);
886
887         /* Verify that the entry has been previously allocated */
888         id = ba_inuse(session_pool, index);
889         if (id != 1) {
890                 PMD_DRV_LOG(ERR,
891                    "dir:%d, Invalid or not allocated index, type:%d, idx:%d\n",
892                    parms->dir,
893                    parms->type,
894                    index);
895                 return -EINVAL;
896         }
897
898         /* Get the entry */
899         rc = tf_msg_get_tbl_entry(tfp,
900                                   parms->dir,
901                                   parms->type,
902                                   parms->data_sz_in_bytes,
903                                   parms->data,
904                                   parms->idx);
905         if (rc) {
906                 PMD_DRV_LOG(ERR,
907                             "dir:%d, Get failed, type:%d, rc:%d\n",
908                             parms->dir,
909                             parms->type,
910                             rc);
911         }
912
913         return rc;
914 }
915
916 #if (TF_SHADOW == 1)
917 /**
918  * Allocate Tbl entry from the Shadow DB. Shadow DB is searched for
919  * the requested entry. If found the ref count is incremente and
920  * returned.
921  *
922  * [in] tfs
923  *   Pointer to session
924  * [in] parms
925  *   Allocation parameters
926  *
927  * Return:
928  *  0       - Success, entry found and ref count incremented
929  *  -ENOENT - Failure, entry not found
930  */
931 static int
932 tf_alloc_tbl_entry_shadow(struct tf_session *tfs __rte_unused,
933                           struct tf_alloc_tbl_entry_parms *parms __rte_unused)
934 {
935         PMD_DRV_LOG(ERR,
936                     "dir:%d, Entry Alloc with search not supported\n",
937                     parms->dir);
938
939
940         return -EOPNOTSUPP;
941 }
942
943 /**
944  * Free Tbl entry from the Shadow DB. Shadow DB is searched for
945  * the requested entry. If found the ref count is decremente and
946  * new ref_count returned.
947  *
948  * [in] tfs
949  *   Pointer to session
950  * [in] parms
951  *   Allocation parameters
952  *
953  * Return:
954  *  0       - Success, entry found and ref count decremented
955  *  -ENOENT - Failure, entry not found
956  */
957 static int
958 tf_free_tbl_entry_shadow(struct tf_session *tfs,
959                          struct tf_free_tbl_entry_parms *parms)
960 {
961         PMD_DRV_LOG(ERR,
962                     "dir:%d, Entry Free with search not supported\n",
963                     parms->dir);
964
965         return -EOPNOTSUPP;
966 }
967 #endif /* TF_SHADOW */
968
969 /**
970  * Create External Tbl pool of memory indexes.
971  *
972  * [in] dir
973  *   direction
974  * [in] tbl_scope_cb
975  *   pointer to the table scope
976  * [in] num_entries
977  *   number of entries to write
978  * [in] entry_sz_bytes
979  *   size of each entry
980  *
981  * Return:
982  *  0       - Success, entry allocated - no search support
983  *  -ENOMEM -EINVAL -EOPNOTSUPP
984  *          - Failure, entry not allocated, out of resources
985  */
986 static int
987 tf_create_tbl_pool_external(enum tf_dir dir,
988                             struct tf_tbl_scope_cb *tbl_scope_cb,
989                             uint32_t num_entries,
990                             uint32_t entry_sz_bytes)
991 {
992         struct tfp_calloc_parms parms;
993         uint32_t i;
994         int32_t j;
995         int rc = 0;
996         struct stack *pool = &tbl_scope_cb->ext_act_pool[dir];
997
998         parms.nitems = num_entries;
999         parms.size = sizeof(uint32_t);
1000         parms.alignment = 0;
1001
1002         if (tfp_calloc(&parms) != 0) {
1003                 PMD_DRV_LOG(ERR, "%d: TBL: external pool failure %s\n",
1004                             dir, strerror(-ENOMEM));
1005                 return -ENOMEM;
1006         }
1007
1008         /* Create empty stack
1009          */
1010         rc = stack_init(num_entries, parms.mem_va, pool);
1011
1012         if (rc != 0) {
1013                 PMD_DRV_LOG(ERR, "%d: TBL: stack init failure %s\n",
1014                             dir, strerror(-rc));
1015                 goto cleanup;
1016         }
1017
1018         /* Save the  malloced memory address so that it can
1019          * be freed when the table scope is freed.
1020          */
1021         tbl_scope_cb->ext_act_pool_mem[dir] = (uint32_t *)parms.mem_va;
1022
1023         /* Fill pool with indexes in reverse
1024          */
1025         j = (num_entries - 1) * entry_sz_bytes;
1026
1027         for (i = 0; i < num_entries; i++) {
1028                 rc = stack_push(pool, j);
1029                 if (rc != 0) {
1030                         PMD_DRV_LOG(ERR, "%s TBL: stack failure %s\n",
1031                                     tf_dir_2_str(dir), strerror(-rc));
1032                         goto cleanup;
1033                 }
1034
1035                 if (j < 0) {
1036                         PMD_DRV_LOG(ERR, "%d TBL: invalid offset (%d)\n",
1037                                     dir, j);
1038                         goto cleanup;
1039                 }
1040                 j -= entry_sz_bytes;
1041         }
1042
1043         if (!stack_is_full(pool)) {
1044                 rc = -EINVAL;
1045                 PMD_DRV_LOG(ERR, "%d TBL: stack failure %s\n",
1046                             dir, strerror(-rc));
1047                 goto cleanup;
1048         }
1049         return 0;
1050 cleanup:
1051         tfp_free((void *)parms.mem_va);
1052         return rc;
1053 }
1054
1055 /**
1056  * Destroy External Tbl pool of memory indexes.
1057  *
1058  * [in] dir
1059  *   direction
1060  * [in] tbl_scope_cb
1061  *   pointer to the table scope
1062  *
1063  */
1064 static void
1065 tf_destroy_tbl_pool_external(enum tf_dir dir,
1066                              struct tf_tbl_scope_cb *tbl_scope_cb)
1067 {
1068         uint32_t *ext_act_pool_mem =
1069                 tbl_scope_cb->ext_act_pool_mem[dir];
1070
1071         tfp_free(ext_act_pool_mem);
1072 }
1073
1074 /**
1075  * Allocate External Tbl entry from the Session Pool.
1076  *
1077  * [in] tfp
1078  *   Pointer to Truflow Handle
1079  * [in] parms
1080  *   Allocation parameters
1081  *
1082  * Return:
1083  *  0       - Success, entry allocated - no search support
1084  *  -ENOMEM -EINVAL -EOPNOTSUPP
1085  *          - Failure, entry not allocated, out of resources
1086  */
1087 static int
1088 tf_alloc_tbl_entry_pool_external(struct tf *tfp,
1089                                  struct tf_alloc_tbl_entry_parms *parms)
1090 {
1091         int rc;
1092         uint32_t index;
1093         struct tf_session *tfs;
1094         struct tf_tbl_scope_cb *tbl_scope_cb;
1095         struct stack *pool;
1096
1097         /* Check parameters */
1098         if (tfp == NULL || parms == NULL) {
1099                 PMD_DRV_LOG(ERR, "Invalid parameters\n");
1100                 return -EINVAL;
1101         }
1102
1103         if (tfp->session == NULL || tfp->session->core_data == NULL) {
1104                 PMD_DRV_LOG(ERR,
1105                             "dir:%d, Session info invalid\n",
1106                             parms->dir);
1107                 return -EINVAL;
1108         }
1109
1110         tfs = (struct tf_session *)(tfp->session->core_data);
1111
1112         /* Get the pool info from the table scope
1113          */
1114         tbl_scope_cb = tbl_scope_cb_find(tfs, parms->tbl_scope_id);
1115
1116         if (tbl_scope_cb == NULL) {
1117                 PMD_DRV_LOG(ERR,
1118                                         "%s, table scope not allocated\n",
1119                                         tf_dir_2_str(parms->dir));
1120                 return -EINVAL;
1121         }
1122         pool = &tbl_scope_cb->ext_act_pool[parms->dir];
1123
1124         /* Allocate an element
1125          */
1126         rc = stack_pop(pool, &index);
1127
1128         if (rc != 0) {
1129                 PMD_DRV_LOG(ERR,
1130                    "dir:%d, Allocation failed, type:%d\n",
1131                    parms->dir,
1132                    parms->type);
1133                 return rc;
1134         }
1135         parms->idx = index;
1136         return rc;
1137 }
1138
1139 /**
1140  * Allocate Internal Tbl entry from the Session Pool.
1141  *
1142  * [in] tfp
1143  *   Pointer to Truflow Handle
1144  * [in] parms
1145  *   Allocation parameters
1146  *
1147  * Return:
1148  *  0       - Success, entry found and ref count decremented
1149  *  -ENOMEM - Failure, entry not allocated, out of resources
1150  */
1151 static int
1152 tf_alloc_tbl_entry_pool_internal(struct tf *tfp,
1153                                  struct tf_alloc_tbl_entry_parms *parms)
1154 {
1155         int rc;
1156         int id;
1157         int free_cnt;
1158         uint32_t index;
1159         struct bitalloc *session_pool;
1160         struct tf_session *tfs;
1161
1162         /* Check parameters */
1163         if (tfp == NULL || parms == NULL) {
1164                 PMD_DRV_LOG(ERR, "Invalid parameters\n");
1165                 return -EINVAL;
1166         }
1167
1168         if (tfp->session == NULL || tfp->session->core_data == NULL) {
1169                 PMD_DRV_LOG(ERR,
1170                             "dir:%d, Session info invalid\n",
1171                             parms->dir);
1172                 return -EINVAL;
1173         }
1174
1175         tfs = (struct tf_session *)(tfp->session->core_data);
1176
1177         if (parms->type != TF_TBL_TYPE_FULL_ACT_RECORD &&
1178             parms->type != TF_TBL_TYPE_ACT_SP_SMAC &&
1179             parms->type != TF_TBL_TYPE_ACT_SP_SMAC_IPV4 &&
1180             parms->type != TF_TBL_TYPE_ACT_ENCAP_8B &&
1181             parms->type != TF_TBL_TYPE_ACT_ENCAP_16B &&
1182             parms->type != TF_TBL_TYPE_ACT_ENCAP_64B) {
1183                 PMD_DRV_LOG(ERR,
1184                             "dir:%d, Type not supported, type:%d\n",
1185                             parms->dir,
1186                             parms->type);
1187                 return -EOPNOTSUPP;
1188         }
1189
1190         /* Lookup the pool using the table type of the element */
1191         rc = tf_rm_lookup_tbl_type_pool(tfs,
1192                                         parms->dir,
1193                                         parms->type,
1194                                         &session_pool);
1195         /* Error logging handled by tf_rm_lookup_tbl_type_pool */
1196         if (rc)
1197                 return rc;
1198
1199         id = ba_alloc(session_pool);
1200         if (id == -1) {
1201                 free_cnt = ba_free_count(session_pool);
1202
1203                 PMD_DRV_LOG(ERR,
1204                    "dir:%d, Allocation failed, type:%d, free:%d\n",
1205                    parms->dir,
1206                    parms->type,
1207                    free_cnt);
1208                 return -ENOMEM;
1209         }
1210
1211         /* Adjust the returned index/offset as there is no guarantee
1212          * that the start is 0 at time of RM allocation
1213          */
1214         tf_rm_convert_index(tfs,
1215                             parms->dir,
1216                             parms->type,
1217                             TF_RM_CONVERT_ADD_BASE,
1218                             id,
1219                             &index);
1220         parms->idx = index;
1221         return rc;
1222 }
1223
1224 /**
1225  * Free External Tbl entry to the session pool.
1226  *
1227  * [in] tfp
1228  *   Pointer to Truflow Handle
1229  * [in] parms
1230  *   Allocation parameters
1231  *
1232  * Return:
1233  *  0       - Success, entry freed
1234  *
1235  * - Failure, entry not successfully freed for these reasons
1236  *  -ENOMEM
1237  *  -EOPNOTSUPP
1238  *  -EINVAL
1239  */
1240 static int
1241 tf_free_tbl_entry_pool_external(struct tf *tfp,
1242                                 struct tf_free_tbl_entry_parms *parms)
1243 {
1244         int rc = 0;
1245         struct tf_session *tfs;
1246         uint32_t index;
1247         struct tf_tbl_scope_cb *tbl_scope_cb;
1248         struct stack *pool;
1249
1250         /* Check parameters */
1251         if (tfp == NULL || parms == NULL) {
1252                 PMD_DRV_LOG(ERR, "Invalid parameters\n");
1253                 return -EINVAL;
1254         }
1255
1256         if (tfp->session == NULL || tfp->session->core_data == NULL) {
1257                 PMD_DRV_LOG(ERR,
1258                             "dir:%d, Session info invalid\n",
1259                             parms->dir);
1260                 return -EINVAL;
1261         }
1262
1263         tfs = (struct tf_session *)(tfp->session->core_data);
1264
1265         /* Get the pool info from the table scope
1266          */
1267         tbl_scope_cb = tbl_scope_cb_find(tfs, parms->tbl_scope_id);
1268
1269         if (tbl_scope_cb == NULL) {
1270                 PMD_DRV_LOG(ERR,
1271                             "dir:%d, Session info invalid\n",
1272                             parms->dir);
1273                 return -EINVAL;
1274         }
1275         pool = &tbl_scope_cb->ext_act_pool[parms->dir];
1276
1277         index = parms->idx;
1278
1279         rc = stack_push(pool, index);
1280
1281         if (rc != 0) {
1282                 PMD_DRV_LOG(ERR,
1283                    "dir:%d, consistency error, stack full, type:%d, idx:%d\n",
1284                    parms->dir,
1285                    parms->type,
1286                    index);
1287         }
1288         return rc;
1289 }
1290
1291 /**
1292  * Free Internal Tbl entry from the Session Pool.
1293  *
1294  * [in] tfp
1295  *   Pointer to Truflow Handle
1296  * [in] parms
1297  *   Allocation parameters
1298  *
1299  * Return:
1300  *  0       - Success, entry found and ref count decremented
1301  *  -ENOMEM - Failure, entry not allocated, out of resources
1302  */
1303 static int
1304 tf_free_tbl_entry_pool_internal(struct tf *tfp,
1305                        struct tf_free_tbl_entry_parms *parms)
1306 {
1307         int rc = 0;
1308         int id;
1309         struct bitalloc *session_pool;
1310         struct tf_session *tfs;
1311         uint32_t index;
1312
1313         /* Check parameters */
1314         if (tfp == NULL || parms == NULL) {
1315                 PMD_DRV_LOG(ERR, "Invalid parameters\n");
1316                 return -EINVAL;
1317         }
1318
1319         if (tfp->session == NULL || tfp->session->core_data == NULL) {
1320                 PMD_DRV_LOG(ERR,
1321                             "dir:%d, Session info invalid\n",
1322                             parms->dir);
1323                 return -EINVAL;
1324         }
1325
1326         tfs = (struct tf_session *)(tfp->session->core_data);
1327
1328         if (parms->type != TF_TBL_TYPE_FULL_ACT_RECORD &&
1329             parms->type != TF_TBL_TYPE_ACT_SP_SMAC &&
1330             parms->type != TF_TBL_TYPE_ACT_SP_SMAC_IPV4 &&
1331             parms->type != TF_TBL_TYPE_ACT_ENCAP_8B &&
1332             parms->type != TF_TBL_TYPE_ACT_ENCAP_16B &&
1333             parms->type != TF_TBL_TYPE_ACT_ENCAP_64B) {
1334                 PMD_DRV_LOG(ERR,
1335                             "dir:%d, Type not supported, type:%d\n",
1336                             parms->dir,
1337                             parms->type);
1338                 return -EOPNOTSUPP;
1339         }
1340
1341         /* Lookup the pool using the table type of the element */
1342         rc = tf_rm_lookup_tbl_type_pool(tfs,
1343                                         parms->dir,
1344                                         parms->type,
1345                                         &session_pool);
1346         /* Error logging handled by tf_rm_lookup_tbl_type_pool */
1347         if (rc)
1348                 return rc;
1349
1350         index = parms->idx;
1351
1352         /* Adjust the returned index/offset as there is no guarantee
1353          * that the start is 0 at time of RM allocation
1354          */
1355         tf_rm_convert_index(tfs,
1356                             parms->dir,
1357                             parms->type,
1358                             TF_RM_CONVERT_RM_BASE,
1359                             parms->idx,
1360                             &index);
1361
1362         /* Check if element was indeed allocated */
1363         id = ba_inuse_free(session_pool, index);
1364         if (id == -1) {
1365                 PMD_DRV_LOG(ERR,
1366                    "dir:%d, Element not previously alloc'ed, type:%d, idx:%d\n",
1367                    parms->dir,
1368                    parms->type,
1369                    index);
1370                 return -ENOMEM;
1371         }
1372
1373         return rc;
1374 }
1375
1376 /* API defined in tf_em.h */
1377 struct tf_tbl_scope_cb *
1378 tbl_scope_cb_find(struct tf_session *session,
1379                   uint32_t tbl_scope_id)
1380 {
1381         int i;
1382
1383         /* Check that id is valid */
1384         i = ba_inuse(session->tbl_scope_pool_rx, tbl_scope_id);
1385         if (i < 0)
1386                 return NULL;
1387
1388         for (i = 0; i < TF_NUM_TBL_SCOPE; i++) {
1389                 if (session->tbl_scopes[i].tbl_scope_id == tbl_scope_id)
1390                         return &session->tbl_scopes[i];
1391         }
1392
1393         return NULL;
1394 }
1395
1396 /* API defined in tf_core.h */
1397 int
1398 tf_free_eem_tbl_scope_cb(struct tf *tfp,
1399                          struct tf_free_tbl_scope_parms *parms)
1400 {
1401         int rc = 0;
1402         enum tf_dir  dir;
1403         struct tf_tbl_scope_cb *tbl_scope_cb;
1404         struct tf_session *session;
1405
1406         session = (struct tf_session *)(tfp->session->core_data);
1407
1408         tbl_scope_cb = tbl_scope_cb_find(session,
1409                                          parms->tbl_scope_id);
1410
1411         if (tbl_scope_cb == NULL)
1412                 return -EINVAL;
1413
1414         /* Free Table control block */
1415         ba_free(session->tbl_scope_pool_rx, tbl_scope_cb->index);
1416
1417         /* free table scope locks */
1418         for (dir = 0; dir < TF_DIR_MAX; dir++) {
1419                 /* Free associated external pools
1420                  */
1421                 tf_destroy_tbl_pool_external(dir,
1422                                              tbl_scope_cb);
1423                 tf_msg_em_op(tfp,
1424                              dir,
1425                              HWRM_TF_EXT_EM_OP_INPUT_OP_EXT_EM_DISABLE);
1426
1427                 /* free table scope and all associated resources */
1428                 tf_em_ctx_unreg(tfp, tbl_scope_cb, dir);
1429         }
1430
1431         return rc;
1432 }
1433
1434 /* API defined in tf_em.h */
1435 int
1436 tf_alloc_eem_tbl_scope(struct tf *tfp,
1437                        struct tf_alloc_tbl_scope_parms *parms)
1438 {
1439         int rc;
1440         enum tf_dir dir;
1441         struct tf_tbl_scope_cb *tbl_scope_cb;
1442         struct tf_em_table *em_tables;
1443         int index;
1444         struct tf_session *session;
1445         struct tf_free_tbl_scope_parms free_parms;
1446
1447         /* check parameters */
1448         if (parms == NULL || tfp->session == NULL) {
1449                 PMD_DRV_LOG(ERR, "TBL: Invalid parameters\n");
1450                 return -EINVAL;
1451         }
1452
1453         session = (struct tf_session *)tfp->session->core_data;
1454
1455         /* Get Table Scope control block from the session pool */
1456         index = ba_alloc(session->tbl_scope_pool_rx);
1457         if (index == -1) {
1458                 PMD_DRV_LOG(ERR, "EEM: Unable to allocate table scope "
1459                             "Control Block\n");
1460                 return -ENOMEM;
1461         }
1462
1463         tbl_scope_cb = &session->tbl_scopes[index];
1464         tbl_scope_cb->index = index;
1465         tbl_scope_cb->tbl_scope_id = index;
1466         parms->tbl_scope_id = index;
1467
1468         for (dir = 0; dir < TF_DIR_MAX; dir++) {
1469                 rc = tf_msg_em_qcaps(tfp,
1470                                      dir,
1471                                      &tbl_scope_cb->em_caps[dir]);
1472                 if (rc) {
1473                         PMD_DRV_LOG(ERR,
1474                                 "EEM: Unable to query for EEM capability\n");
1475                         goto cleanup;
1476                 }
1477         }
1478
1479         /*
1480          * Validate and setup table sizes
1481          */
1482         if (tf_em_validate_num_entries(tbl_scope_cb, parms))
1483                 goto cleanup;
1484
1485         for (dir = 0; dir < TF_DIR_MAX; dir++) {
1486                 /*
1487                  * Allocate tables and signal configuration to FW
1488                  */
1489                 rc = tf_em_ctx_reg(tfp, tbl_scope_cb, dir);
1490                 if (rc) {
1491                         PMD_DRV_LOG(ERR,
1492                                     "EEM: Unable to register for EEM ctx\n");
1493                         goto cleanup;
1494                 }
1495
1496                 em_tables = tbl_scope_cb->em_ctx_info[dir].em_tables;
1497                 rc = tf_msg_em_cfg(tfp,
1498                                    em_tables[KEY0_TABLE].num_entries,
1499                                    em_tables[KEY0_TABLE].ctx_id,
1500                                    em_tables[KEY1_TABLE].ctx_id,
1501                                    em_tables[RECORD_TABLE].ctx_id,
1502                                    em_tables[EFC_TABLE].ctx_id,
1503                                    parms->hw_flow_cache_flush_timer,
1504                                    dir);
1505                 if (rc) {
1506                         PMD_DRV_LOG(ERR,
1507                                 "TBL: Unable to configure EEM in firmware\n");
1508                         goto cleanup_full;
1509                 }
1510
1511                 rc = tf_msg_em_op(tfp,
1512                                   dir,
1513                                   HWRM_TF_EXT_EM_OP_INPUT_OP_EXT_EM_ENABLE);
1514
1515                 if (rc) {
1516                         PMD_DRV_LOG(ERR,
1517                                     "EEM: Unable to enable EEM in firmware\n");
1518                         goto cleanup_full;
1519                 }
1520
1521                 /* Allocate the pool of offsets of the external memory.
1522                  * Initially, this is a single fixed size pool for all external
1523                  * actions related to a single table scope.
1524                  */
1525                 rc = tf_create_tbl_pool_external(dir,
1526                                             tbl_scope_cb,
1527                                             em_tables[RECORD_TABLE].num_entries,
1528                                             em_tables[RECORD_TABLE].entry_size);
1529                 if (rc) {
1530                         PMD_DRV_LOG(ERR,
1531                                     "%d TBL: Unable to allocate idx pools %s\n",
1532                                     dir,
1533                                     strerror(-rc));
1534                         goto cleanup_full;
1535                 }
1536         }
1537
1538         return 0;
1539
1540 cleanup_full:
1541         free_parms.tbl_scope_id = index;
1542         tf_free_eem_tbl_scope_cb(tfp, &free_parms);
1543         return -EINVAL;
1544
1545 cleanup:
1546         /* Free Table control block */
1547         ba_free(session->tbl_scope_pool_rx, tbl_scope_cb->index);
1548         return -EINVAL;
1549 }
1550
1551 /* API defined in tf_core.h */
1552 int
1553 tf_set_tbl_entry(struct tf *tfp,
1554                  struct tf_set_tbl_entry_parms *parms)
1555 {
1556         int rc = 0;
1557         struct tf_tbl_scope_cb *tbl_scope_cb;
1558         struct tf_session *session;
1559
1560         if (tfp == NULL || parms == NULL || parms->data == NULL)
1561                 return -EINVAL;
1562
1563         if (tfp->session == NULL || tfp->session->core_data == NULL) {
1564                 PMD_DRV_LOG(ERR,
1565                             "dir:%d, Session info invalid\n",
1566                             parms->dir);
1567                 return -EINVAL;
1568         }
1569
1570         if (parms->type == TF_TBL_TYPE_EXT) {
1571                 void *base_addr;
1572                 uint32_t offset = parms->idx;
1573                 uint32_t tbl_scope_id;
1574
1575                 session = (struct tf_session *)(tfp->session->core_data);
1576
1577                 tbl_scope_id = parms->tbl_scope_id;
1578
1579                 if (tbl_scope_id == TF_TBL_SCOPE_INVALID)  {
1580                         PMD_DRV_LOG(ERR,
1581                                     "dir:%d, Table scope not allocated\n",
1582                                     parms->dir);
1583                         return -EINVAL;
1584                 }
1585
1586                 /* Get the table scope control block associated with the
1587                  * external pool
1588                  */
1589                 tbl_scope_cb = tbl_scope_cb_find(session, tbl_scope_id);
1590
1591                 if (tbl_scope_cb == NULL)
1592                         return -EINVAL;
1593
1594                 /* External table, implicitly the Action table */
1595                 base_addr = tf_em_get_table_page(tbl_scope_cb,
1596                                                  parms->dir,
1597                                                  offset,
1598                                                  RECORD_TABLE);
1599                 if (base_addr == NULL) {
1600                         PMD_DRV_LOG(ERR,
1601                                     "dir:%d, Base address lookup failed\n",
1602                                     parms->dir);
1603                         return -EINVAL;
1604                 }
1605
1606                 offset %= TF_EM_PAGE_SIZE;
1607                 rte_memcpy((char *)base_addr + offset,
1608                            parms->data,
1609                            parms->data_sz_in_bytes);
1610         } else {
1611                 /* Internal table type processing */
1612                 rc = tf_set_tbl_entry_internal(tfp, parms);
1613                 if (rc) {
1614                         PMD_DRV_LOG(ERR,
1615                                     "dir:%d, Set failed, type:%d, rc:%d\n",
1616                                     parms->dir,
1617                                     parms->type,
1618                                     rc);
1619                 }
1620         }
1621
1622         return rc;
1623 }
1624
1625 /* API defined in tf_core.h */
1626 int
1627 tf_get_tbl_entry(struct tf *tfp,
1628                  struct tf_get_tbl_entry_parms *parms)
1629 {
1630         int rc = 0;
1631
1632         if (tfp == NULL || parms == NULL)
1633                 return -EINVAL;
1634
1635         if (tfp->session == NULL || tfp->session->core_data == NULL) {
1636                 PMD_DRV_LOG(ERR,
1637                             "dir:%d, Session info invalid\n",
1638                             parms->dir);
1639                 return -EINVAL;
1640         }
1641
1642         if (parms->type == TF_TBL_TYPE_EXT) {
1643                 PMD_DRV_LOG(ERR,
1644                             "dir:%d, External table type not supported\n",
1645                             parms->dir);
1646
1647                 rc = -EOPNOTSUPP;
1648         } else {
1649                 /* Internal table type processing */
1650                 rc = tf_get_tbl_entry_internal(tfp, parms);
1651                 if (rc)
1652                         PMD_DRV_LOG(ERR,
1653                                     "dir:%d, Get failed, type:%d, rc:%d\n",
1654                                     parms->dir,
1655                                     parms->type,
1656                                     rc);
1657         }
1658
1659         return rc;
1660 }
1661
1662 /* API defined in tf_core.h */
1663 int
1664 tf_alloc_tbl_scope(struct tf *tfp,
1665                    struct tf_alloc_tbl_scope_parms *parms)
1666 {
1667         int rc;
1668
1669         /* check parameters */
1670         if (parms == NULL || tfp == NULL) {
1671                 PMD_DRV_LOG(ERR, "TBL: Invalid parameters\n");
1672                 return -EINVAL;
1673         }
1674
1675         rc = tf_alloc_eem_tbl_scope(tfp, parms);
1676
1677         return rc;
1678 }
1679
1680 /* API defined in tf_core.h */
1681 int
1682 tf_free_tbl_scope(struct tf *tfp,
1683                   struct tf_free_tbl_scope_parms *parms)
1684 {
1685         int rc;
1686
1687         /* check parameters */
1688         if (parms == NULL || tfp == NULL) {
1689                 PMD_DRV_LOG(ERR, "TBL: Invalid parameters\n");
1690                 return -EINVAL;
1691         }
1692
1693         /* free table scope and all associated resources */
1694         rc = tf_free_eem_tbl_scope_cb(tfp, parms);
1695
1696         return rc;
1697 }
1698
1699 /* API defined in tf_core.h */
1700 int
1701 tf_alloc_tbl_entry(struct tf *tfp,
1702                    struct tf_alloc_tbl_entry_parms *parms)
1703 {
1704         int rc;
1705 #if (TF_SHADOW == 1)
1706         struct tf_session *tfs;
1707 #endif /* TF_SHADOW */
1708
1709         /* Check parameters */
1710         if (parms == NULL || tfp == NULL) {
1711                 PMD_DRV_LOG(ERR, "TBL: Invalid parameters\n");
1712                 return -EINVAL;
1713         }
1714         /*
1715          * No shadow copy support for external tables, allocate and return
1716          */
1717         if (parms->type == TF_TBL_TYPE_EXT) {
1718                 rc = tf_alloc_tbl_entry_pool_external(tfp, parms);
1719                 return rc;
1720         }
1721
1722 #if (TF_SHADOW == 1)
1723         if (tfp->session == NULL || tfp->session->core_data == NULL) {
1724                 PMD_DRV_LOG(ERR,
1725                             "dir:%d, Session info invalid\n",
1726                             parms->dir);
1727                 return -EINVAL;
1728         }
1729
1730         tfs = (struct tf_session *)(tfp->session->core_data);
1731
1732         /* Search the Shadow DB for requested element. If not found go
1733          * allocate one from the Session Pool
1734          */
1735         if (parms->search_enable && tfs->shadow_copy) {
1736                 rc = tf_alloc_tbl_entry_shadow(tfs, parms);
1737                 /* Entry found and parms populated with return data */
1738                 if (rc == 0)
1739                         return rc;
1740         }
1741 #endif /* TF_SHADOW */
1742
1743         rc = tf_alloc_tbl_entry_pool_internal(tfp, parms);
1744         if (rc)
1745                 PMD_DRV_LOG(ERR, "dir%d, Alloc failed, rc:%d\n",
1746                             parms->dir,
1747                             rc);
1748
1749         return rc;
1750 }
1751
1752 /* API defined in tf_core.h */
1753 int
1754 tf_free_tbl_entry(struct tf *tfp,
1755                   struct tf_free_tbl_entry_parms *parms)
1756 {
1757         int rc;
1758 #if (TF_SHADOW == 1)
1759         struct tf_session *tfs;
1760 #endif /* TF_SHADOW */
1761
1762         /* Check parameters */
1763         if (parms == NULL || tfp == NULL) {
1764                 PMD_DRV_LOG(ERR, "TBL: Invalid parameters\n");
1765                 return -EINVAL;
1766         }
1767         /*
1768          * No shadow of external tables so just free the entry
1769          */
1770         if (parms->type == TF_TBL_TYPE_EXT) {
1771                 rc = tf_free_tbl_entry_pool_external(tfp, parms);
1772                 return rc;
1773         }
1774
1775 #if (TF_SHADOW == 1)
1776         if (tfp->session == NULL || tfp->session->core_data == NULL) {
1777                 PMD_DRV_LOG(ERR,
1778                             "dir:%d, Session info invalid\n",
1779                             parms->dir);
1780                 return -EINVAL;
1781         }
1782
1783         tfs = (struct tf_session *)(tfp->session->core_data);
1784
1785         /* Search the Shadow DB for requested element. If not found go
1786          * allocate one from the Session Pool
1787          */
1788         if (parms->search_enable && tfs->shadow_copy) {
1789                 rc = tf_free_tbl_entry_shadow(tfs, parms);
1790                 /* Entry free'ed and parms populated with return data */
1791                 if (rc == 0)
1792                         return rc;
1793         }
1794 #endif /* TF_SHADOW */
1795
1796         rc = tf_free_tbl_entry_pool_internal(tfp, parms);
1797
1798         if (rc)
1799                 PMD_DRV_LOG(ERR, "dir:%d, Alloc failed, rc:%d\n",
1800                             parms->dir,
1801                             rc);
1802         return rc;
1803 }