net/bnxt: support EM/EEM
[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         /* Initialize external pool data structures */
179         tf_init_tbl_pool(session);
180
181         session->ref_count++;
182
183         /* Return session ID */
184         parms->session_id = session->session_id;
185
186         PMD_DRV_LOG(INFO,
187                     "Session created, session_id:%d\n",
188                     parms->session_id.id);
189
190         PMD_DRV_LOG(INFO,
191                     "domain:%d, bus:%d, device:%d, fw_session_id:%d\n",
192                     parms->session_id.internal.domain,
193                     parms->session_id.internal.bus,
194                     parms->session_id.internal.device,
195                     parms->session_id.internal.fw_session_id);
196
197         return 0;
198
199  cleanup:
200         tfp_free(tfp->session->core_data);
201         tfp_free(tfp->session);
202         tfp->session = NULL;
203         return rc;
204
205  cleanup_close:
206         tf_close_session(tfp);
207         return -EINVAL;
208 }
209
210 int
211 tf_attach_session(struct tf *tfp __rte_unused,
212                   struct tf_attach_session_parms *parms __rte_unused)
213 {
214 #if (TF_SHARED == 1)
215         int rc;
216
217         if (tfp == NULL)
218                 return -EINVAL;
219
220         /* - Open the shared memory for the attach_chan_name
221          * - Point to the shared session for this Device instance
222          * - Check that session is valid
223          * - Attach to the firmware so it can record there is more
224          *   than one client of the session.
225          */
226
227         if (tfp->session) {
228                 if (tfp->session->session_id.id != TF_SESSION_ID_INVALID) {
229                         rc = tf_msg_session_attach(tfp,
230                                                    parms->ctrl_chan_name,
231                                                    parms->session_id);
232                 }
233         }
234 #endif /* TF_SHARED */
235         return -1;
236 }
237
238 int
239 tf_close_session(struct tf *tfp)
240 {
241         int rc;
242         int rc_close = 0;
243         struct tf_session *tfs;
244         union tf_session_id session_id;
245
246         if (tfp == NULL || tfp->session == NULL)
247                 return -EINVAL;
248
249         tfs = (struct tf_session *)(tfp->session->core_data);
250
251         /* Cleanup if we're last user of the session */
252         if (tfs->ref_count == 1) {
253                 /* Cleanup any outstanding resources */
254                 rc_close = tf_rm_close(tfp);
255         }
256
257         if (tfs->session_id.id != TF_SESSION_ID_INVALID) {
258                 rc = tf_msg_session_close(tfp);
259                 if (rc) {
260                         /* Log error */
261                         PMD_DRV_LOG(ERR,
262                                     "Message send failed, rc:%d\n",
263                                     rc);
264                 }
265
266                 /* Update the ref_count */
267                 tfs->ref_count--;
268         }
269
270         session_id = tfs->session_id;
271
272         /* Final cleanup as we're last user of the session */
273         if (tfs->ref_count == 0) {
274                 tfp_free(tfp->session->core_data);
275                 tfp_free(tfp->session);
276                 tfp->session = NULL;
277         }
278
279         PMD_DRV_LOG(INFO,
280                     "Session closed, session_id:%d\n",
281                     session_id.id);
282
283         PMD_DRV_LOG(INFO,
284                     "domain:%d, bus:%d, device:%d, fw_session_id:%d\n",
285                     session_id.internal.domain,
286                     session_id.internal.bus,
287                     session_id.internal.device,
288                     session_id.internal.fw_session_id);
289
290         return rc_close;
291 }
292
293 /** insert EM hash entry API
294  *
295  *    returns:
296  *    0       - Success
297  *    -EINVAL - Error
298  */
299 int tf_insert_em_entry(struct tf *tfp,
300                        struct tf_insert_em_entry_parms *parms)
301 {
302         struct tf_tbl_scope_cb     *tbl_scope_cb;
303
304         if (tfp == NULL || parms == NULL)
305                 return -EINVAL;
306
307         tbl_scope_cb =
308                 tbl_scope_cb_find((struct tf_session *)tfp->session->core_data,
309                                   parms->tbl_scope_id);
310         if (tbl_scope_cb == NULL)
311                 return -EINVAL;
312
313         /* Process the EM entry per Table Scope type */
314         return tf_insert_eem_entry((struct tf_session *)tfp->session->core_data,
315                                    tbl_scope_cb,
316                                    parms);
317 }
318
319 /** Delete EM hash entry API
320  *
321  *    returns:
322  *    0       - Success
323  *    -EINVAL - Error
324  */
325 int tf_delete_em_entry(struct tf *tfp,
326                        struct tf_delete_em_entry_parms *parms)
327 {
328         struct tf_tbl_scope_cb     *tbl_scope_cb;
329
330         if (tfp == NULL || parms == NULL)
331                 return -EINVAL;
332
333         tbl_scope_cb =
334                 tbl_scope_cb_find((struct tf_session *)tfp->session->core_data,
335                                   parms->tbl_scope_id);
336         if (tbl_scope_cb == NULL)
337                 return -EINVAL;
338
339         return tf_delete_eem_entry(tfp, parms);
340 }
341
342 /** allocate identifier resource
343  *
344  * Returns success or failure code.
345  */
346 int tf_alloc_identifier(struct tf *tfp,
347                         struct tf_alloc_identifier_parms *parms)
348 {
349         struct bitalloc *session_pool;
350         struct tf_session *tfs;
351         int id;
352         int rc;
353
354         if (parms == NULL || tfp == NULL)
355                 return -EINVAL;
356
357         if (tfp->session == NULL || tfp->session->core_data == NULL) {
358                 PMD_DRV_LOG(ERR, "%s: session error\n",
359                             tf_dir_2_str(parms->dir));
360                 return -EINVAL;
361         }
362
363         tfs = (struct tf_session *)(tfp->session->core_data);
364
365         switch (parms->ident_type) {
366         case TF_IDENT_TYPE_L2_CTXT:
367                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
368                                 TF_L2_CTXT_REMAP_POOL_NAME,
369                                 rc);
370                 break;
371         case TF_IDENT_TYPE_PROF_FUNC:
372                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
373                                 TF_PROF_FUNC_POOL_NAME,
374                                 rc);
375                 break;
376         case TF_IDENT_TYPE_EM_PROF:
377                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
378                                 TF_EM_PROF_ID_POOL_NAME,
379                                 rc);
380                 break;
381         case TF_IDENT_TYPE_WC_PROF:
382                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
383                                 TF_WC_TCAM_PROF_ID_POOL_NAME,
384                                 rc);
385                 break;
386         case TF_IDENT_TYPE_L2_FUNC:
387                 PMD_DRV_LOG(ERR, "%s: unsupported %s\n",
388                             tf_dir_2_str(parms->dir),
389                             tf_ident_2_str(parms->ident_type));
390                 rc = -EOPNOTSUPP;
391                 break;
392         default:
393                 PMD_DRV_LOG(ERR, "%s: %s\n",
394                             tf_dir_2_str(parms->dir),
395                             tf_ident_2_str(parms->ident_type));
396                 rc = -EINVAL;
397                 break;
398         }
399
400         if (rc) {
401                 PMD_DRV_LOG(ERR, "%s: identifier pool %s failure\n",
402                             tf_dir_2_str(parms->dir),
403                             tf_ident_2_str(parms->ident_type));
404                 return rc;
405         }
406
407         id = ba_alloc(session_pool);
408
409         if (id == BA_FAIL) {
410                 PMD_DRV_LOG(ERR, "%s: %s: No resource available\n",
411                             tf_dir_2_str(parms->dir),
412                             tf_ident_2_str(parms->ident_type));
413                 return -ENOMEM;
414         }
415         parms->id = id;
416         return 0;
417 }
418
419 /** free identifier resource
420  *
421  * Returns success or failure code.
422  */
423 int tf_free_identifier(struct tf *tfp,
424                        struct tf_free_identifier_parms *parms)
425 {
426         struct bitalloc *session_pool;
427         int rc;
428         int ba_rc;
429         struct tf_session *tfs;
430
431         if (parms == NULL || tfp == NULL)
432                 return -EINVAL;
433
434         if (tfp->session == NULL || tfp->session->core_data == NULL) {
435                 PMD_DRV_LOG(ERR, "%s: Session error\n",
436                             tf_dir_2_str(parms->dir));
437                 return -EINVAL;
438         }
439
440         tfs = (struct tf_session *)(tfp->session->core_data);
441
442         switch (parms->ident_type) {
443         case TF_IDENT_TYPE_L2_CTXT:
444                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
445                                 TF_L2_CTXT_REMAP_POOL_NAME,
446                                 rc);
447                 break;
448         case TF_IDENT_TYPE_PROF_FUNC:
449                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
450                                 TF_PROF_FUNC_POOL_NAME,
451                                 rc);
452                 break;
453         case TF_IDENT_TYPE_EM_PROF:
454                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
455                                 TF_EM_PROF_ID_POOL_NAME,
456                                 rc);
457                 break;
458         case TF_IDENT_TYPE_WC_PROF:
459                 TF_RM_GET_POOLS(tfs, parms->dir, &session_pool,
460                                 TF_WC_TCAM_PROF_ID_POOL_NAME,
461                                 rc);
462                 break;
463         case TF_IDENT_TYPE_L2_FUNC:
464                 PMD_DRV_LOG(ERR, "%s: unsupported %s\n",
465                             tf_dir_2_str(parms->dir),
466                             tf_ident_2_str(parms->ident_type));
467                 rc = -EOPNOTSUPP;
468                 break;
469         default:
470                 PMD_DRV_LOG(ERR, "%s: invalid %s\n",
471                             tf_dir_2_str(parms->dir),
472                             tf_ident_2_str(parms->ident_type));
473                 rc = -EINVAL;
474                 break;
475         }
476         if (rc) {
477                 PMD_DRV_LOG(ERR, "%s: %s Identifier pool access failed\n",
478                             tf_dir_2_str(parms->dir),
479                             tf_ident_2_str(parms->ident_type));
480                 return rc;
481         }
482
483         ba_rc = ba_inuse(session_pool, (int)parms->id);
484
485         if (ba_rc == BA_FAIL || ba_rc == BA_ENTRY_FREE) {
486                 PMD_DRV_LOG(ERR, "%s: %s: Entry %d already free",
487                             tf_dir_2_str(parms->dir),
488                             tf_ident_2_str(parms->ident_type),
489                             parms->id);
490                 return -EINVAL;
491         }
492
493         ba_free(session_pool, (int)parms->id);
494
495         return 0;
496 }
497
498 int
499 tf_alloc_tcam_entry(struct tf *tfp,
500                     struct tf_alloc_tcam_entry_parms *parms)
501 {
502         int rc;
503         int index;
504         struct tf_session *tfs;
505         struct bitalloc *session_pool;
506
507         if (parms == NULL || tfp == NULL)
508                 return -EINVAL;
509
510         if (tfp->session == NULL || tfp->session->core_data == NULL) {
511                 PMD_DRV_LOG(ERR, "%s: session error\n",
512                             tf_dir_2_str(parms->dir));
513                 return -EINVAL;
514         }
515
516         tfs = (struct tf_session *)(tfp->session->core_data);
517
518         rc = tf_rm_lookup_tcam_type_pool(tfs,
519                                          parms->dir,
520                                          parms->tcam_tbl_type,
521                                          &session_pool);
522         /* Error logging handled by tf_rm_lookup_tcam_type_pool */
523         if (rc)
524                 return rc;
525
526         index = ba_alloc(session_pool);
527         if (index == BA_FAIL) {
528                 PMD_DRV_LOG(ERR, "%s: %s: No resource available\n",
529                             tf_dir_2_str(parms->dir),
530                             tf_tcam_tbl_2_str(parms->tcam_tbl_type));
531                 return -ENOMEM;
532         }
533
534         parms->idx = index;
535         return 0;
536 }
537
538 int
539 tf_set_tcam_entry(struct tf *tfp,
540                   struct tf_set_tcam_entry_parms *parms)
541 {
542         int rc;
543         int id;
544         struct tf_session *tfs;
545         struct bitalloc *session_pool;
546
547         if (tfp == NULL || parms == NULL) {
548                 PMD_DRV_LOG(ERR, "Invalid parameters\n");
549                 return -EINVAL;
550         }
551
552         if (tfp->session == NULL || tfp->session->core_data == NULL) {
553                 PMD_DRV_LOG(ERR,
554                             "%s, Session info invalid\n",
555                             tf_dir_2_str(parms->dir));
556                 return -EINVAL;
557         }
558
559         tfs = (struct tf_session *)(tfp->session->core_data);
560
561         /*
562          * Each tcam send msg function should check for key sizes range
563          */
564
565         rc = tf_rm_lookup_tcam_type_pool(tfs,
566                                          parms->dir,
567                                          parms->tcam_tbl_type,
568                                          &session_pool);
569         /* Error logging handled by tf_rm_lookup_tcam_type_pool */
570         if (rc)
571                 return rc;
572
573
574         /* Verify that the entry has been previously allocated */
575         id = ba_inuse(session_pool, parms->idx);
576         if (id != 1) {
577                 PMD_DRV_LOG(ERR,
578                    "%s: %s: Invalid or not allocated index, idx:%d\n",
579                    tf_dir_2_str(parms->dir),
580                    tf_tcam_tbl_2_str(parms->tcam_tbl_type),
581                    parms->idx);
582                 return -EINVAL;
583         }
584
585         rc = tf_msg_tcam_entry_set(tfp, parms);
586
587         return rc;
588 }
589
590 int
591 tf_get_tcam_entry(struct tf *tfp __rte_unused,
592                   struct tf_get_tcam_entry_parms *parms __rte_unused)
593 {
594         int rc = -EOPNOTSUPP;
595
596         if (tfp == NULL || parms == NULL) {
597                 PMD_DRV_LOG(ERR, "Invalid parameters\n");
598                 return -EINVAL;
599         }
600
601         if (tfp->session == NULL || tfp->session->core_data == NULL) {
602                 PMD_DRV_LOG(ERR,
603                             "%s, Session info invalid\n",
604                             tf_dir_2_str(parms->dir));
605                 return -EINVAL;
606         }
607
608         return rc;
609 }
610
611 int
612 tf_free_tcam_entry(struct tf *tfp,
613                    struct tf_free_tcam_entry_parms *parms)
614 {
615         int rc;
616         struct tf_session *tfs;
617         struct bitalloc *session_pool;
618
619         if (parms == NULL || tfp == NULL)
620                 return -EINVAL;
621
622         if (tfp->session == NULL || tfp->session->core_data == NULL) {
623                 PMD_DRV_LOG(ERR, "%s: Session error\n",
624                             tf_dir_2_str(parms->dir));
625                 return -EINVAL;
626         }
627
628         tfs = (struct tf_session *)(tfp->session->core_data);
629
630         rc = tf_rm_lookup_tcam_type_pool(tfs,
631                                          parms->dir,
632                                          parms->tcam_tbl_type,
633                                          &session_pool);
634         /* Error logging handled by tf_rm_lookup_tcam_type_pool */
635         if (rc)
636                 return rc;
637
638         rc = ba_inuse(session_pool, (int)parms->idx);
639         if (rc == BA_FAIL || rc == BA_ENTRY_FREE) {
640                 PMD_DRV_LOG(ERR, "%s: %s: Entry %d already free",
641                             tf_dir_2_str(parms->dir),
642                             tf_tcam_tbl_2_str(parms->tcam_tbl_type),
643                             parms->idx);
644                 return -EINVAL;
645         }
646
647         ba_free(session_pool, (int)parms->idx);
648
649         rc = tf_msg_tcam_entry_free(tfp, parms);
650         if (rc) {
651                 /* Log error */
652                 PMD_DRV_LOG(ERR, "%s: %s: Entry %d free failed",
653                             tf_dir_2_str(parms->dir),
654                             tf_tcam_tbl_2_str(parms->tcam_tbl_type),
655                             parms->idx);
656         }
657
658         return rc;
659 }