net/bnxt: update external action record pool
[dpdk.git] / drivers / net / bnxt / tf_core / tf_core.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2020 Broadcom
3  * All rights reserved.
4  */
5
6 #include <stdio.h>
7
8 #include "tf_core.h"
9 #include "tf_session.h"
10 #include "tf_tbl.h"
11 #include "tf_em.h"
12 #include "tf_rm.h"
13 #include "tf_msg.h"
14 #include "tfp.h"
15 #include "bitalloc.h"
16 #include "bnxt.h"
17 #include "rand.h"
18
19 static inline uint32_t SWAP_WORDS32(uint32_t val32)
20 {
21         return (((val32 & 0x0000ffff) << 16) |
22                 ((val32 & 0xffff0000) >> 16));
23 }
24
25 static void tf_seeds_init(struct tf_session *session)
26 {
27         int i;
28         uint32_t r;
29
30         /* Initialize the lfsr */
31         rand_init();
32
33         /* RX and TX use the same seed values */
34         session->lkup_lkup3_init_cfg[TF_DIR_RX] =
35                 session->lkup_lkup3_init_cfg[TF_DIR_TX] =
36                                                 SWAP_WORDS32(rand32());
37
38         for (i = 0; i < TF_LKUP_SEED_MEM_SIZE / 2; i++) {
39                 r = SWAP_WORDS32(rand32());
40                 session->lkup_em_seed_mem[TF_DIR_RX][i * 2] = r;
41                 session->lkup_em_seed_mem[TF_DIR_TX][i * 2] = r;
42                 r = SWAP_WORDS32(rand32());
43                 session->lkup_em_seed_mem[TF_DIR_RX][i * 2 + 1] = (r & 0x1);
44                 session->lkup_em_seed_mem[TF_DIR_TX][i * 2 + 1] = (r & 0x1);
45         }
46 }
47
48 int
49 tf_open_session(struct tf                    *tfp,
50                 struct tf_open_session_parms *parms)
51 {
52         int rc;
53         struct tf_session *session;
54         struct tfp_calloc_parms alloc_parms;
55         unsigned int domain, bus, slot, device;
56         uint8_t fw_session_id;
57
58         if (tfp == NULL || parms == NULL)
59                 return -EINVAL;
60
61         /* Filter out any non-supported device types on the Core
62          * side. It is assumed that the Firmware will be supported if
63          * firmware open session succeeds.
64          */
65         if (parms->device_type != TF_DEVICE_TYPE_WH)
66                 return -ENOTSUP;
67
68         /* Build the beginning of session_id */
69         rc = sscanf(parms->ctrl_chan_name,
70                     "%x:%x:%x.%d",
71                     &domain,
72                     &bus,
73                     &slot,
74                     &device);
75         if (rc != 4) {
76                 PMD_DRV_LOG(ERR,
77                             "Failed to scan device ctrl_chan_name\n");
78                 return -EINVAL;
79         }
80
81         /* open FW session and get a new session_id */
82         rc = tf_msg_session_open(tfp,
83                                  parms->ctrl_chan_name,
84                                  &fw_session_id);
85         if (rc) {
86                 /* Log error */
87                 if (rc == -EEXIST)
88                         PMD_DRV_LOG(ERR,
89                                     "Session is already open, rc:%d\n",
90                                     rc);
91                 else
92                         PMD_DRV_LOG(ERR,
93                                     "Open message send failed, rc:%d\n",
94                                     rc);
95
96                 parms->session_id.id = TF_FW_SESSION_ID_INVALID;
97                 return rc;
98         }
99
100         /* Allocate session */
101         alloc_parms.nitems = 1;
102         alloc_parms.size = sizeof(struct tf_session_info);
103         alloc_parms.alignment = 0;
104         rc = tfp_calloc(&alloc_parms);
105         if (rc) {
106                 /* Log error */
107                 PMD_DRV_LOG(ERR,
108                             "Failed to allocate session info, rc:%d\n",
109                             rc);
110                 goto cleanup;
111         }
112
113         tfp->session = (struct tf_session_info *)alloc_parms.mem_va;
114
115         /* Allocate core data for the session */
116         alloc_parms.nitems = 1;
117         alloc_parms.size = sizeof(struct tf_session);
118         alloc_parms.alignment = 0;
119         rc = tfp_calloc(&alloc_parms);
120         if (rc) {
121                 /* Log error */
122                 PMD_DRV_LOG(ERR,
123                             "Failed to allocate session data, rc:%d\n",
124                             rc);
125                 goto cleanup;
126         }
127
128         tfp->session->core_data = alloc_parms.mem_va;
129
130         session = (struct tf_session *)tfp->session->core_data;
131         tfp_memcpy(session->ctrl_chan_name,
132                    parms->ctrl_chan_name,
133                    TF_SESSION_NAME_MAX);
134
135         /* Initialize Session */
136         session->device_type = parms->device_type;
137         tf_rm_init(tfp);
138
139         /* Construct the Session ID */
140         session->session_id.internal.domain = domain;
141         session->session_id.internal.bus = bus;
142         session->session_id.internal.device = device;
143         session->session_id.internal.fw_session_id = fw_session_id;
144
145         rc = tf_msg_session_qcfg(tfp);
146         if (rc) {
147                 /* Log error */
148                 PMD_DRV_LOG(ERR,
149                             "Query config message send failed, rc:%d\n",
150                             rc);
151                 goto cleanup_close;
152         }
153
154         /* Shadow DB configuration */
155         if (parms->shadow_copy) {
156                 /* Ignore shadow_copy setting */
157                 session->shadow_copy = 0;/* parms->shadow_copy; */
158 #if (TF_SHADOW == 1)
159                 rc = tf_rm_shadow_db_init(tfs);
160                 if (rc)
161                         PMD_DRV_LOG(ERR,
162                                     "Shadow DB Initialization failed\n, rc:%d",
163                                     rc);
164                 /* Add additional processing */
165 #endif /* TF_SHADOW */
166         }
167
168         /* Adjust the Session with what firmware allowed us to get */
169         rc = tf_rm_allocate_validate(tfp);
170         if (rc) {
171                 /* Log error */
172                 goto cleanup_close;
173         }
174
175         /* Setup hash seeds */
176         tf_seeds_init(session);
177
178         session->ref_count++;
179
180         /* Return session ID */
181         parms->session_id = session->session_id;
182
183         PMD_DRV_LOG(INFO,
184                     "Session created, session_id:%d\n",
185                     parms->session_id.id);
186
187         PMD_DRV_LOG(INFO,
188                     "domain:%d, bus:%d, device:%d, fw_session_id:%d\n",
189                     parms->session_id.internal.domain,
190                     parms->session_id.internal.bus,
191                     parms->session_id.internal.device,
192                     parms->session_id.internal.fw_session_id);
193
194         return 0;
195
196  cleanup:
197         tfp_free(tfp->session->core_data);
198         tfp_free(tfp->session);
199         tfp->session = NULL;
200         return rc;
201
202  cleanup_close:
203         tf_close_session(tfp);
204         return -EINVAL;
205 }
206
207 int
208 tf_attach_session(struct tf *tfp __rte_unused,
209                   struct tf_attach_session_parms *parms __rte_unused)
210 {
211 #if (TF_SHARED == 1)
212         int rc;
213
214         if (tfp == NULL)
215                 return -EINVAL;
216
217         /* - Open the shared memory for the attach_chan_name
218          * - Point to the shared session for this Device instance
219          * - Check that session is valid
220          * - Attach to the firmware so it can record there is more
221          *   than one client of the session.
222          */
223
224         if (tfp->session) {
225                 if (tfp->session->session_id.id != TF_SESSION_ID_INVALID) {
226                         rc = tf_msg_session_attach(tfp,
227                                                    parms->ctrl_chan_name,
228                                                    parms->session_id);
229                 }
230         }
231 #endif /* TF_SHARED */
232         return -1;
233 }
234
235 int
236 tf_close_session(struct tf *tfp)
237 {
238         int rc;
239         int rc_close = 0;
240         struct tf_session *tfs;
241         union tf_session_id session_id;
242
243         if (tfp == NULL || tfp->session == NULL)
244                 return -EINVAL;
245
246         tfs = (struct tf_session *)(tfp->session->core_data);
247
248         /* Cleanup if we're last user of the session */
249         if (tfs->ref_count == 1) {
250                 /* Cleanup any outstanding resources */
251                 rc_close = tf_rm_close(tfp);
252         }
253
254         if (tfs->session_id.id != TF_SESSION_ID_INVALID) {
255                 rc = tf_msg_session_close(tfp);
256                 if (rc) {
257                         /* Log error */
258                         PMD_DRV_LOG(ERR,
259                                     "Message send failed, rc:%d\n",
260                                     rc);
261                 }
262
263                 /* Update the ref_count */
264                 tfs->ref_count--;
265         }
266
267         session_id = tfs->session_id;
268
269         /* Final cleanup as we're last user of the session */
270         if (tfs->ref_count == 0) {
271                 tfp_free(tfp->session->core_data);
272                 tfp_free(tfp->session);
273                 tfp->session = NULL;
274         }
275
276         PMD_DRV_LOG(INFO,
277                     "Session closed, session_id:%d\n",
278                     session_id.id);
279
280         PMD_DRV_LOG(INFO,
281                     "domain:%d, bus:%d, device:%d, fw_session_id:%d\n",
282                     session_id.internal.domain,
283                     session_id.internal.bus,
284                     session_id.internal.device,
285                     session_id.internal.fw_session_id);
286
287         return rc_close;
288 }
289
290 /** insert EM hash entry API
291  *
292  *    returns:
293  *    0       - Success
294  *    -EINVAL - Error
295  */
296 int tf_insert_em_entry(struct tf *tfp,
297                        struct tf_insert_em_entry_parms *parms)
298 {
299         struct tf_tbl_scope_cb     *tbl_scope_cb;
300
301         if (tfp == NULL || parms == NULL)
302                 return -EINVAL;
303
304         tbl_scope_cb =
305                 tbl_scope_cb_find((struct tf_session *)tfp->session->core_data,
306                                   parms->tbl_scope_id);
307         if (tbl_scope_cb == NULL)
308                 return -EINVAL;
309
310         /* Process the EM entry per Table Scope type */
311         return tf_insert_eem_entry((struct tf_session *)tfp->session->core_data,
312                                    tbl_scope_cb,
313                                    parms);
314 }
315
316 /** Delete EM hash entry API
317  *
318  *    returns:
319  *    0       - Success
320  *    -EINVAL - Error
321  */
322 int tf_delete_em_entry(struct tf *tfp,
323                        struct tf_delete_em_entry_parms *parms)
324 {
325         struct tf_tbl_scope_cb     *tbl_scope_cb;
326
327         if (tfp == NULL || parms == NULL)
328                 return -EINVAL;
329
330         tbl_scope_cb =
331                 tbl_scope_cb_find((struct tf_session *)tfp->session->core_data,
332                                   parms->tbl_scope_id);
333         if (tbl_scope_cb == NULL)
334                 return -EINVAL;
335
336         return tf_delete_eem_entry(tfp, parms);
337 }
338
339 /** allocate identifier resource
340  *
341  * Returns success or failure code.
342  */
343 int tf_alloc_identifier(struct tf *tfp,
344                         struct tf_alloc_identifier_parms *parms)
345 {
346         struct bitalloc *session_pool;
347         struct tf_session *tfs;
348         int id;
349         int rc;
350
351         if (parms == NULL || tfp == NULL)
352                 return -EINVAL;
353
354         if (tfp->session == NULL || tfp->session->core_data == NULL) {
355                 PMD_DRV_LOG(ERR, "%s: session error\n",
356                             tf_dir_2_str(parms->dir));
357                 return -EINVAL;
358         }
359
360         tfs = (struct tf_session *)(tfp->session->core_data);
361
362         switch (parms->ident_type) {
363         case TF_IDENT_TYPE_L2_CTXT:
364                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
365                                 TF_L2_CTXT_REMAP_POOL_NAME,
366                                 rc);
367                 break;
368         case TF_IDENT_TYPE_PROF_FUNC:
369                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
370                                 TF_PROF_FUNC_POOL_NAME,
371                                 rc);
372                 break;
373         case TF_IDENT_TYPE_EM_PROF:
374                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
375                                 TF_EM_PROF_ID_POOL_NAME,
376                                 rc);
377                 break;
378         case TF_IDENT_TYPE_WC_PROF:
379                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
380                                 TF_WC_TCAM_PROF_ID_POOL_NAME,
381                                 rc);
382                 break;
383         case TF_IDENT_TYPE_L2_FUNC:
384                 PMD_DRV_LOG(ERR, "%s: unsupported %s\n",
385                             tf_dir_2_str(parms->dir),
386                             tf_ident_2_str(parms->ident_type));
387                 rc = -EOPNOTSUPP;
388                 break;
389         default:
390                 PMD_DRV_LOG(ERR, "%s: %s\n",
391                             tf_dir_2_str(parms->dir),
392                             tf_ident_2_str(parms->ident_type));
393                 rc = -EINVAL;
394                 break;
395         }
396
397         if (rc) {
398                 PMD_DRV_LOG(ERR, "%s: identifier pool %s failure\n",
399                             tf_dir_2_str(parms->dir),
400                             tf_ident_2_str(parms->ident_type));
401                 return rc;
402         }
403
404         id = ba_alloc(session_pool);
405
406         if (id == BA_FAIL) {
407                 PMD_DRV_LOG(ERR, "%s: %s: No resource available\n",
408                             tf_dir_2_str(parms->dir),
409                             tf_ident_2_str(parms->ident_type));
410                 return -ENOMEM;
411         }
412         parms->id = id;
413         return 0;
414 }
415
416 /** free identifier resource
417  *
418  * Returns success or failure code.
419  */
420 int tf_free_identifier(struct tf *tfp,
421                        struct tf_free_identifier_parms *parms)
422 {
423         struct bitalloc *session_pool;
424         int rc;
425         int ba_rc;
426         struct tf_session *tfs;
427
428         if (parms == NULL || tfp == NULL)
429                 return -EINVAL;
430
431         if (tfp->session == NULL || tfp->session->core_data == NULL) {
432                 PMD_DRV_LOG(ERR, "%s: Session error\n",
433                             tf_dir_2_str(parms->dir));
434                 return -EINVAL;
435         }
436
437         tfs = (struct tf_session *)(tfp->session->core_data);
438
439         switch (parms->ident_type) {
440         case TF_IDENT_TYPE_L2_CTXT:
441                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
442                                 TF_L2_CTXT_REMAP_POOL_NAME,
443                                 rc);
444                 break;
445         case TF_IDENT_TYPE_PROF_FUNC:
446                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
447                                 TF_PROF_FUNC_POOL_NAME,
448                                 rc);
449                 break;
450         case TF_IDENT_TYPE_EM_PROF:
451                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
452                                 TF_EM_PROF_ID_POOL_NAME,
453                                 rc);
454                 break;
455         case TF_IDENT_TYPE_WC_PROF:
456                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
457                                 TF_WC_TCAM_PROF_ID_POOL_NAME,
458                                 rc);
459                 break;
460         case TF_IDENT_TYPE_L2_FUNC:
461                 PMD_DRV_LOG(ERR, "%s: unsupported %s\n",
462                             tf_dir_2_str(parms->dir),
463                             tf_ident_2_str(parms->ident_type));
464                 rc = -EOPNOTSUPP;
465                 break;
466         default:
467                 PMD_DRV_LOG(ERR, "%s: invalid %s\n",
468                             tf_dir_2_str(parms->dir),
469                             tf_ident_2_str(parms->ident_type));
470                 rc = -EINVAL;
471                 break;
472         }
473         if (rc) {
474                 PMD_DRV_LOG(ERR, "%s: %s Identifier pool access failed\n",
475                             tf_dir_2_str(parms->dir),
476                             tf_ident_2_str(parms->ident_type));
477                 return rc;
478         }
479
480         ba_rc = ba_inuse(session_pool, (int)parms->id);
481
482         if (ba_rc == BA_FAIL || ba_rc == BA_ENTRY_FREE) {
483                 PMD_DRV_LOG(ERR, "%s: %s: Entry %d already free",
484                             tf_dir_2_str(parms->dir),
485                             tf_ident_2_str(parms->ident_type),
486                             parms->id);
487                 return -EINVAL;
488         }
489
490         ba_free(session_pool, (int)parms->id);
491
492         return 0;
493 }
494
495 int
496 tf_alloc_tcam_entry(struct tf *tfp,
497                     struct tf_alloc_tcam_entry_parms *parms)
498 {
499         int rc;
500         int index;
501         struct tf_session *tfs;
502         struct bitalloc *session_pool;
503
504         if (parms == NULL || tfp == NULL)
505                 return -EINVAL;
506
507         if (tfp->session == NULL || tfp->session->core_data == NULL) {
508                 PMD_DRV_LOG(ERR, "%s: session error\n",
509                             tf_dir_2_str(parms->dir));
510                 return -EINVAL;
511         }
512
513         tfs = (struct tf_session *)(tfp->session->core_data);
514
515         rc = tf_rm_lookup_tcam_type_pool(tfs,
516                                          parms->dir,
517                                          parms->tcam_tbl_type,
518                                          &session_pool);
519         /* Error logging handled by tf_rm_lookup_tcam_type_pool */
520         if (rc)
521                 return rc;
522
523         index = ba_alloc(session_pool);
524         if (index == BA_FAIL) {
525                 PMD_DRV_LOG(ERR, "%s: %s: No resource available\n",
526                             tf_dir_2_str(parms->dir),
527                             tf_tcam_tbl_2_str(parms->tcam_tbl_type));
528                 return -ENOMEM;
529         }
530
531         parms->idx = index;
532         return 0;
533 }
534
535 int
536 tf_set_tcam_entry(struct tf *tfp,
537                   struct tf_set_tcam_entry_parms *parms)
538 {
539         int rc;
540         int id;
541         struct tf_session *tfs;
542         struct bitalloc *session_pool;
543
544         if (tfp == NULL || parms == NULL) {
545                 PMD_DRV_LOG(ERR, "Invalid parameters\n");
546                 return -EINVAL;
547         }
548
549         if (tfp->session == NULL || tfp->session->core_data == NULL) {
550                 PMD_DRV_LOG(ERR,
551                             "%s, Session info invalid\n",
552                             tf_dir_2_str(parms->dir));
553                 return -EINVAL;
554         }
555
556         tfs = (struct tf_session *)(tfp->session->core_data);
557
558         /*
559          * Each tcam send msg function should check for key sizes range
560          */
561
562         rc = tf_rm_lookup_tcam_type_pool(tfs,
563                                          parms->dir,
564                                          parms->tcam_tbl_type,
565                                          &session_pool);
566         /* Error logging handled by tf_rm_lookup_tcam_type_pool */
567         if (rc)
568                 return rc;
569
570
571         /* Verify that the entry has been previously allocated */
572         id = ba_inuse(session_pool, parms->idx);
573         if (id != 1) {
574                 PMD_DRV_LOG(ERR,
575                    "%s: %s: Invalid or not allocated index, idx:%d\n",
576                    tf_dir_2_str(parms->dir),
577                    tf_tcam_tbl_2_str(parms->tcam_tbl_type),
578                    parms->idx);
579                 return -EINVAL;
580         }
581
582         rc = tf_msg_tcam_entry_set(tfp, parms);
583
584         return rc;
585 }
586
587 int
588 tf_get_tcam_entry(struct tf *tfp __rte_unused,
589                   struct tf_get_tcam_entry_parms *parms __rte_unused)
590 {
591         int rc = -EOPNOTSUPP;
592
593         if (tfp == NULL || parms == NULL) {
594                 PMD_DRV_LOG(ERR, "Invalid parameters\n");
595                 return -EINVAL;
596         }
597
598         if (tfp->session == NULL || tfp->session->core_data == NULL) {
599                 PMD_DRV_LOG(ERR,
600                             "%s, Session info invalid\n",
601                             tf_dir_2_str(parms->dir));
602                 return -EINVAL;
603         }
604
605         return rc;
606 }
607
608 int
609 tf_free_tcam_entry(struct tf *tfp,
610                    struct tf_free_tcam_entry_parms *parms)
611 {
612         int rc;
613         struct tf_session *tfs;
614         struct bitalloc *session_pool;
615
616         if (parms == NULL || tfp == NULL)
617                 return -EINVAL;
618
619         if (tfp->session == NULL || tfp->session->core_data == NULL) {
620                 PMD_DRV_LOG(ERR, "%s: Session error\n",
621                             tf_dir_2_str(parms->dir));
622                 return -EINVAL;
623         }
624
625         tfs = (struct tf_session *)(tfp->session->core_data);
626
627         rc = tf_rm_lookup_tcam_type_pool(tfs,
628                                          parms->dir,
629                                          parms->tcam_tbl_type,
630                                          &session_pool);
631         /* Error logging handled by tf_rm_lookup_tcam_type_pool */
632         if (rc)
633                 return rc;
634
635         rc = ba_inuse(session_pool, (int)parms->idx);
636         if (rc == BA_FAIL || rc == BA_ENTRY_FREE) {
637                 PMD_DRV_LOG(ERR, "%s: %s: Entry %d already free",
638                             tf_dir_2_str(parms->dir),
639                             tf_tcam_tbl_2_str(parms->tcam_tbl_type),
640                             parms->idx);
641                 return -EINVAL;
642         }
643
644         ba_free(session_pool, (int)parms->idx);
645
646         rc = tf_msg_tcam_entry_free(tfp, parms);
647         if (rc) {
648                 /* Log error */
649                 PMD_DRV_LOG(ERR, "%s: %s: Entry %d free failed",
650                             tf_dir_2_str(parms->dir),
651                             tf_tcam_tbl_2_str(parms->tcam_tbl_type),
652                             parms->idx);
653         }
654
655         return rc;
656 }