event/dlb2: add v2.5 sequence number management
[dpdk.git] / drivers / net / bnxt / tf_core / tf_session.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2021 Broadcom
3  * All rights reserved.
4  */
5
6 #include <string.h>
7
8 #include <rte_common.h>
9
10 #include "tf_session.h"
11 #include "tf_common.h"
12 #include "tf_msg.h"
13 #include "tfp.h"
14
15 struct tf_session_client_create_parms {
16         /**
17          * [in] Pointer to the control channel name string
18          */
19         char *ctrl_chan_name;
20
21         /**
22          * [out] Firmware Session Client ID
23          */
24         union tf_session_client_id *session_client_id;
25 };
26
27 struct tf_session_client_destroy_parms {
28         /**
29          * FW Session Client Identifier
30          */
31         union tf_session_client_id session_client_id;
32 };
33
34 /**
35  * Creates a Session and the associated client.
36  *
37  * [in] tfp
38  *   Pointer to TF handle
39  *
40  * [in] parms
41  *   Pointer to session client create parameters
42  *
43  * Returns
44  *   - (0) if successful.
45  *   - (-EINVAL) on failure.
46  *   - (-ENOMEM) if max session clients has been reached.
47  */
48 static int
49 tf_session_create(struct tf *tfp,
50                   struct tf_session_open_session_parms *parms)
51 {
52         int rc;
53         struct tf_session *session = NULL;
54         struct tf_session_client *client;
55         struct tfp_calloc_parms cparms;
56         uint8_t fw_session_id;
57         uint8_t fw_session_client_id;
58         union tf_session_id *session_id;
59
60         TF_CHECK_PARMS2(tfp, parms);
61
62         /* Open FW session and get a new session_id */
63         rc = tf_msg_session_open(tfp,
64                                  parms->open_cfg->ctrl_chan_name,
65                                  &fw_session_id,
66                                  &fw_session_client_id);
67         if (rc) {
68                 /* Log error */
69                 if (rc == -EEXIST)
70                         TFP_DRV_LOG(ERR,
71                                     "Session is already open, rc:%s\n",
72                                     strerror(-rc));
73                 else
74                         TFP_DRV_LOG(ERR,
75                                     "Open message send failed, rc:%s\n",
76                                     strerror(-rc));
77
78                 parms->open_cfg->session_id.id = TF_FW_SESSION_ID_INVALID;
79                 return rc;
80         }
81
82         /* Allocate session */
83         cparms.nitems = 1;
84         cparms.size = sizeof(struct tf_session_info);
85         cparms.alignment = 0;
86         rc = tfp_calloc(&cparms);
87         if (rc) {
88                 /* Log error */
89                 TFP_DRV_LOG(ERR,
90                             "Failed to allocate session info, rc:%s\n",
91                             strerror(-rc));
92                 goto cleanup;
93         }
94         tfp->session = (struct tf_session_info *)cparms.mem_va;
95
96         /* Allocate core data for the session */
97         cparms.nitems = 1;
98         cparms.size = sizeof(struct tf_session);
99         cparms.alignment = 0;
100         rc = tfp_calloc(&cparms);
101         if (rc) {
102                 /* Log error */
103                 TFP_DRV_LOG(ERR,
104                             "Failed to allocate session data, rc:%s\n",
105                             strerror(-rc));
106                 goto cleanup;
107         }
108         tfp->session->core_data = cparms.mem_va;
109         session_id = &parms->open_cfg->session_id;
110
111         /* Update Session Info, which is what is visible to the caller */
112         tfp->session->ver.major = 0;
113         tfp->session->ver.minor = 0;
114         tfp->session->ver.update = 0;
115
116         tfp->session->session_id.internal.domain = session_id->internal.domain;
117         tfp->session->session_id.internal.bus = session_id->internal.bus;
118         tfp->session->session_id.internal.device = session_id->internal.device;
119         tfp->session->session_id.internal.fw_session_id = fw_session_id;
120
121         /* Initialize Session and Device, which is private */
122         session = (struct tf_session *)tfp->session->core_data;
123         session->ver.major = 0;
124         session->ver.minor = 0;
125         session->ver.update = 0;
126
127         session->session_id.internal.domain = session_id->internal.domain;
128         session->session_id.internal.bus = session_id->internal.bus;
129         session->session_id.internal.device = session_id->internal.device;
130         session->session_id.internal.fw_session_id = fw_session_id;
131         /* Return the allocated session id */
132         session_id->id = session->session_id.id;
133
134         session->shadow_copy = parms->open_cfg->shadow_copy;
135
136         /* Init session client list */
137         ll_init(&session->client_ll);
138
139         /* Create the local session client, initialize and attach to
140          * the session
141          */
142         cparms.nitems = 1;
143         cparms.size = sizeof(struct tf_session_client);
144         cparms.alignment = 0;
145         rc = tfp_calloc(&cparms);
146         if (rc) {
147                 /* Log error */
148                 TFP_DRV_LOG(ERR,
149                             "Failed to allocate session client, rc:%s\n",
150                             strerror(-rc));
151                 goto cleanup;
152         }
153         client = cparms.mem_va;
154
155         /* Register FID with the client */
156         rc = tfp_get_fid(tfp, &client->fw_fid);
157         if (rc)
158                 return rc;
159
160         client->session_client_id.internal.fw_session_id = fw_session_id;
161         client->session_client_id.internal.fw_session_client_id =
162                 fw_session_client_id;
163
164         tfp_memcpy(client->ctrl_chan_name,
165                    parms->open_cfg->ctrl_chan_name,
166                    TF_SESSION_NAME_MAX);
167
168         ll_insert(&session->client_ll, &client->ll_entry);
169         session->ref_count++;
170
171         rc = tf_dev_bind(tfp,
172                          parms->open_cfg->device_type,
173                          session->shadow_copy,
174                          &parms->open_cfg->resources,
175                          &session->dev);
176         /* Logging handled by dev_bind */
177         if (rc)
178                 return rc;
179
180         session->dev_init = true;
181
182         return 0;
183
184  cleanup:
185         tfp_free(tfp->session->core_data);
186         tfp_free(tfp->session);
187         tfp->session = NULL;
188         return rc;
189 }
190
191 /**
192  * Creates a Session Client on an existing Session.
193  *
194  * [in] tfp
195  *   Pointer to TF handle
196  *
197  * [in] parms
198  *   Pointer to session client create parameters
199  *
200  * Returns
201  *   - (0) if successful.
202  *   - (-EINVAL) on failure.
203  *   - (-ENOMEM) if max session clients has been reached.
204  */
205 static int
206 tf_session_client_create(struct tf *tfp,
207                          struct tf_session_client_create_parms *parms)
208 {
209         int rc;
210         struct tf_session *session = NULL;
211         struct tf_session_client *client;
212         struct tfp_calloc_parms cparms;
213         union tf_session_client_id session_client_id;
214
215         TF_CHECK_PARMS2(tfp, parms);
216
217         /* Using internal version as session client may not exist yet */
218         rc = tf_session_get_session_internal(tfp, &session);
219         if (rc) {
220                 TFP_DRV_LOG(ERR,
221                             "Failed to lookup session, rc:%s\n",
222                             strerror(-rc));
223                 return rc;
224         }
225
226         client = tf_session_find_session_client_by_name(session,
227                                                         parms->ctrl_chan_name);
228         if (client) {
229                 TFP_DRV_LOG(ERR,
230                             "Client %s, already registered with this session\n",
231                             parms->ctrl_chan_name);
232                 return -EOPNOTSUPP;
233         }
234
235         rc = tf_msg_session_client_register
236                     (tfp,
237                     parms->ctrl_chan_name,
238                     &session_client_id.internal.fw_session_client_id);
239         if (rc) {
240                 TFP_DRV_LOG(ERR,
241                             "Failed to create client on session, rc:%s\n",
242                             strerror(-rc));
243                 return rc;
244         }
245
246         /* Create the local session client, initialize and attach to
247          * the session
248          */
249         cparms.nitems = 1;
250         cparms.size = sizeof(struct tf_session_client);
251         cparms.alignment = 0;
252         rc = tfp_calloc(&cparms);
253         if (rc) {
254                 TFP_DRV_LOG(ERR,
255                             "Failed to allocate session client, rc:%s\n",
256                             strerror(-rc));
257                 goto cleanup;
258         }
259         client = cparms.mem_va;
260
261         /* Register FID with the client */
262         rc = tfp_get_fid(tfp, &client->fw_fid);
263         if (rc)
264                 return rc;
265
266         /* Build the Session Client ID by adding the fw_session_id */
267         rc = tf_session_get_fw_session_id
268                         (tfp,
269                         &session_client_id.internal.fw_session_id);
270         if (rc) {
271                 TFP_DRV_LOG(ERR,
272                             "Session Firmware id lookup failed, rc:%s\n",
273                             strerror(-rc));
274                 return rc;
275         }
276
277         tfp_memcpy(client->ctrl_chan_name,
278                    parms->ctrl_chan_name,
279                    TF_SESSION_NAME_MAX);
280
281         client->session_client_id.id = session_client_id.id;
282
283         ll_insert(&session->client_ll, &client->ll_entry);
284
285         session->ref_count++;
286
287         /* Build the return value */
288         parms->session_client_id->id = session_client_id.id;
289
290  cleanup:
291         /* TBD - Add code to unregister newly create client from fw */
292
293         return rc;
294 }
295
296
297 /**
298  * Destroys a Session Client on an existing Session.
299  *
300  * [in] tfp
301  *   Pointer to TF handle
302  *
303  * [in] parms
304  *   Pointer to the session client destroy parameters
305  *
306  * Returns
307  *   - (0) if successful.
308  *   - (-EINVAL) on failure.
309  *   - (-ENOTFOUND) error, client not owned by the session.
310  *   - (-ENOTSUPP) error, unable to destroy client as its the last
311  *                 client. Please use the tf_session_close().
312  */
313 static int
314 tf_session_client_destroy(struct tf *tfp,
315                           struct tf_session_client_destroy_parms *parms)
316 {
317         int rc;
318         struct tf_session *tfs;
319         struct tf_session_client *client;
320
321         TF_CHECK_PARMS2(tfp, parms);
322
323         rc = tf_session_get_session(tfp, &tfs);
324         if (rc) {
325                 TFP_DRV_LOG(ERR,
326                             "Failed to lookup session, rc:%s\n",
327                             strerror(-rc));
328                 return rc;
329         }
330
331         /* Check session owns this client and that we're not the last client */
332         client = tf_session_get_session_client(tfs,
333                                                parms->session_client_id);
334         if (client == NULL) {
335                 TFP_DRV_LOG(ERR,
336                             "Client %d, not found within this session\n",
337                             parms->session_client_id.id);
338                 return -EINVAL;
339         }
340
341         /* If last client the request is rejected and cleanup should
342          * be done by session close.
343          */
344         if (tfs->ref_count == 1)
345                 return -EOPNOTSUPP;
346
347         rc = tf_msg_session_client_unregister
348                         (tfp,
349                         parms->session_client_id.internal.fw_session_client_id);
350
351         /* Log error, but continue. If FW fails we do not really have
352          * a way to fix this but the client would no longer be valid
353          * thus we remove from the session.
354          */
355         if (rc) {
356                 TFP_DRV_LOG(ERR,
357                             "Client destroy on FW Failed, rc:%s\n",
358                             strerror(-rc));
359         }
360
361         ll_delete(&tfs->client_ll, &client->ll_entry);
362
363         /* Decrement the session ref_count */
364         tfs->ref_count--;
365
366         tfp_free(client);
367
368         return rc;
369 }
370
371 int
372 tf_session_open_session(struct tf *tfp,
373                         struct tf_session_open_session_parms *parms)
374 {
375         int rc;
376         struct tf_session_client_create_parms scparms;
377
378         TF_CHECK_PARMS2(tfp, parms);
379
380         /* Decide if we're creating a new session or session client */
381         if (tfp->session == NULL) {
382                 rc = tf_session_create(tfp, parms);
383                 if (rc) {
384                         TFP_DRV_LOG(ERR,
385                                     "Failed to create session, ctrl_chan_name:%s, rc:%s\n",
386                                     parms->open_cfg->ctrl_chan_name,
387                                     strerror(-rc));
388                         return rc;
389                 }
390
391                 TFP_DRV_LOG(INFO,
392                        "Session created, session_client_id:%d, session_id:%d\n",
393                        parms->open_cfg->session_client_id.id,
394                        parms->open_cfg->session_id.id);
395         } else {
396                 scparms.ctrl_chan_name = parms->open_cfg->ctrl_chan_name;
397                 scparms.session_client_id = &parms->open_cfg->session_client_id;
398
399                 /* Create the new client and get it associated with
400                  * the session.
401                  */
402                 rc = tf_session_client_create(tfp, &scparms);
403                 if (rc) {
404                         TFP_DRV_LOG(ERR,
405                               "Failed to create client on session %d, rc:%s\n",
406                               parms->open_cfg->session_id.id,
407                               strerror(-rc));
408                         return rc;
409                 }
410
411                 TFP_DRV_LOG(INFO,
412                             "Session Client:%d created on session:%d\n",
413                             parms->open_cfg->session_client_id.id,
414                             parms->open_cfg->session_id.id);
415         }
416
417         return 0;
418 }
419
420 int
421 tf_session_attach_session(struct tf *tfp __rte_unused,
422                           struct tf_session_attach_session_parms *parms __rte_unused)
423 {
424         int rc = -EOPNOTSUPP;
425
426         TF_CHECK_PARMS2(tfp, parms);
427
428         TFP_DRV_LOG(ERR,
429                     "Attach not yet supported, rc:%s\n",
430                     strerror(-rc));
431         return rc;
432 }
433
434 int
435 tf_session_close_session(struct tf *tfp,
436                          struct tf_session_close_session_parms *parms)
437 {
438         int rc;
439         struct tf_session *tfs = NULL;
440         struct tf_session_client *client;
441         struct tf_dev_info *tfd = NULL;
442         struct tf_session_client_destroy_parms scdparms;
443         uint16_t fid;
444
445         TF_CHECK_PARMS2(tfp, parms);
446
447         rc = tf_session_get_session(tfp, &tfs);
448         if (rc) {
449                 TFP_DRV_LOG(ERR,
450                             "Session lookup failed, rc:%s\n",
451                             strerror(-rc));
452                 return rc;
453         }
454
455         if (tfs->session_id.id == TF_SESSION_ID_INVALID) {
456                 rc = -EINVAL;
457                 TFP_DRV_LOG(ERR,
458                             "Invalid session id, unable to close, rc:%s\n",
459                             strerror(-rc));
460                 return rc;
461         }
462
463         /* Get the client, we need it independently of the closure
464          * type (client or session closure).
465          *
466          * We find the client by way of the fid. Thus one cannot close
467          * a client on behalf of someone else.
468          */
469         rc = tfp_get_fid(tfp, &fid);
470         if (rc)
471                 return rc;
472
473         client = tf_session_find_session_client_by_fid(tfs,
474                                                        fid);
475         if (!client) {
476                 rc = -EINVAL;
477                 TFP_DRV_LOG(ERR,
478                             "Client not part of the session, unable to close, rc:%s\n",
479                             strerror(-rc));
480                 return rc;
481         }
482
483         /* In case multiple clients we chose to close those first */
484         if (tfs->ref_count > 1) {
485                 /* Linaro gcc can't static init this structure */
486                 memset(&scdparms,
487                        0,
488                        sizeof(struct tf_session_client_destroy_parms));
489
490                 scdparms.session_client_id = client->session_client_id;
491                 /* Destroy requested client so its no longer
492                  * registered with this session.
493                  */
494                 rc = tf_session_client_destroy(tfp, &scdparms);
495                 if (rc) {
496                         TFP_DRV_LOG(ERR,
497                                     "Failed to unregister Client %d, rc:%s\n",
498                                     client->session_client_id.id,
499                                     strerror(-rc));
500                         return rc;
501                 }
502
503                 TFP_DRV_LOG(INFO,
504                             "Closed session client, session_client_id:%d\n",
505                             client->session_client_id.id);
506
507                 TFP_DRV_LOG(INFO,
508                             "session_id:%d, ref_count:%d\n",
509                             tfs->session_id.id,
510                             tfs->ref_count);
511
512                 return 0;
513         }
514
515         /* Record the session we're closing so the caller knows the
516          * details.
517          */
518         *parms->session_id = tfs->session_id;
519
520         rc = tf_session_get_device(tfs, &tfd);
521         if (rc) {
522                 TFP_DRV_LOG(ERR,
523                             "Device lookup failed, rc:%s\n",
524                             strerror(-rc));
525                 return rc;
526         }
527
528         /* Unbind the device */
529         rc = tf_dev_unbind(tfp, tfd);
530         if (rc) {
531                 /* Log error */
532                 TFP_DRV_LOG(ERR,
533                             "Device unbind failed, rc:%s\n",
534                             strerror(-rc));
535         }
536
537         rc = tf_msg_session_close(tfp);
538         if (rc) {
539                 /* Log error */
540                 TFP_DRV_LOG(ERR,
541                             "FW Session close failed, rc:%s\n",
542                             strerror(-rc));
543         }
544
545         /* Final cleanup as we're last user of the session thus we
546          * also delete the last client.
547          */
548         ll_delete(&tfs->client_ll, &client->ll_entry);
549         tfp_free(client);
550
551         tfs->ref_count--;
552
553         TFP_DRV_LOG(INFO,
554                     "Closed session, session_id:%d, ref_count:%d\n",
555                     tfs->session_id.id,
556                     tfs->ref_count);
557
558         tfs->dev_init = false;
559
560         tfp_free(tfp->session->core_data);
561         tfp_free(tfp->session);
562         tfp->session = NULL;
563
564         return 0;
565 }
566
567 bool
568 tf_session_is_fid_supported(struct tf_session *tfs,
569                             uint16_t fid)
570 {
571         struct ll_entry *c_entry;
572         struct tf_session_client *client;
573
574         for (c_entry = tfs->client_ll.head;
575              c_entry != NULL;
576              c_entry = c_entry->next) {
577                 client = (struct tf_session_client *)c_entry;
578                 if (client->fw_fid == fid)
579                         return true;
580         }
581
582         return false;
583 }
584
585 int
586 tf_session_get_session_internal(struct tf *tfp,
587                                 struct tf_session **tfs)
588 {
589         int rc = 0;
590
591         /* Skip using the check macro as we want to control the error msg */
592         if (tfp->session == NULL || tfp->session->core_data == NULL) {
593                 rc = -EINVAL;
594                 TFP_DRV_LOG(ERR,
595                             "Session not created, rc:%s\n",
596                             strerror(-rc));
597                 return rc;
598         }
599
600         *tfs = (struct tf_session *)(tfp->session->core_data);
601
602         return rc;
603 }
604
605 int
606 tf_session_get_session(struct tf *tfp,
607                        struct tf_session **tfs)
608 {
609         int rc;
610         uint16_t fw_fid;
611         bool supported = false;
612
613         rc = tf_session_get_session_internal(tfp,
614                                              tfs);
615         /* Logging done by tf_session_get_session_internal */
616         if (rc)
617                 return rc;
618
619         /* As session sharing among functions aka 'individual clients'
620          * is supported we have to assure that the client is indeed
621          * registered before we get deep in the TruFlow api stack.
622          */
623         rc = tfp_get_fid(tfp, &fw_fid);
624         if (rc) {
625                 TFP_DRV_LOG(ERR,
626                             "Internal FID lookup\n, rc:%s\n",
627                             strerror(-rc));
628                 return rc;
629         }
630
631         supported = tf_session_is_fid_supported(*tfs, fw_fid);
632         if (!supported) {
633                 TFP_DRV_LOG
634                         (ERR,
635                         "Ctrl channel not registered with session\n, rc:%s\n",
636                         strerror(-rc));
637                 return -EINVAL;
638         }
639
640         return rc;
641 }
642
643 struct tf_session_client *
644 tf_session_get_session_client(struct tf_session *tfs,
645                               union tf_session_client_id session_client_id)
646 {
647         struct ll_entry *c_entry;
648         struct tf_session_client *client;
649
650         /* Skip using the check macro as we just want to return */
651         if (tfs == NULL)
652                 return NULL;
653
654         for (c_entry = tfs->client_ll.head;
655              c_entry != NULL;
656              c_entry = c_entry->next) {
657                 client = (struct tf_session_client *)c_entry;
658                 if (client->session_client_id.id == session_client_id.id)
659                         return client;
660         }
661
662         return NULL;
663 }
664
665 struct tf_session_client *
666 tf_session_find_session_client_by_name(struct tf_session *tfs,
667                                        const char *ctrl_chan_name)
668 {
669         struct ll_entry *c_entry;
670         struct tf_session_client *client;
671
672         /* Skip using the check macro as we just want to return */
673         if (tfs == NULL || ctrl_chan_name == NULL)
674                 return NULL;
675
676         for (c_entry = tfs->client_ll.head;
677              c_entry != NULL;
678              c_entry = c_entry->next) {
679                 client = (struct tf_session_client *)c_entry;
680                 if (strncmp(client->ctrl_chan_name,
681                             ctrl_chan_name,
682                             TF_SESSION_NAME_MAX) == 0)
683                         return client;
684         }
685
686         return NULL;
687 }
688
689 struct tf_session_client *
690 tf_session_find_session_client_by_fid(struct tf_session *tfs,
691                                       uint16_t fid)
692 {
693         struct ll_entry *c_entry;
694         struct tf_session_client *client;
695
696         /* Skip using the check macro as we just want to return */
697         if (tfs == NULL)
698                 return NULL;
699
700         for (c_entry = tfs->client_ll.head;
701              c_entry != NULL;
702              c_entry = c_entry->next) {
703                 client = (struct tf_session_client *)c_entry;
704                 if (client->fw_fid == fid)
705                         return client;
706         }
707
708         return NULL;
709 }
710
711 int
712 tf_session_get_device(struct tf_session *tfs,
713                       struct tf_dev_info **tfd)
714 {
715         *tfd = &tfs->dev;
716
717         return 0;
718 }
719
720 int
721 tf_session_get_fw_session_id(struct tf *tfp,
722                              uint8_t *fw_session_id)
723 {
724         int rc;
725         struct tf_session *tfs = NULL;
726
727         /* Skip using the check macro as we want to control the error msg */
728         if (tfp->session == NULL) {
729                 rc = -EINVAL;
730                 TFP_DRV_LOG(ERR,
731                             "Session not created, rc:%s\n",
732                             strerror(-rc));
733                 return rc;
734         }
735
736         if (fw_session_id == NULL) {
737                 rc = -EINVAL;
738                 TFP_DRV_LOG(ERR,
739                             "Invalid Argument(s), rc:%s\n",
740                             strerror(-rc));
741                 return rc;
742         }
743
744         rc = tf_session_get_session_internal(tfp, &tfs);
745         if (rc)
746                 return rc;
747
748         *fw_session_id = tfs->session_id.internal.fw_session_id;
749
750         return 0;
751 }
752
753 int
754 tf_session_get_session_id(struct tf *tfp,
755                           union tf_session_id *session_id)
756 {
757         int rc;
758         struct tf_session *tfs = NULL;
759
760         if (tfp->session == NULL) {
761                 rc = -EINVAL;
762                 TFP_DRV_LOG(ERR,
763                             "Session not created, rc:%s\n",
764                             strerror(-rc));
765                 return rc;
766         }
767
768         if (session_id == NULL) {
769                 rc = -EINVAL;
770                 TFP_DRV_LOG(ERR,
771                             "Invalid Argument(s), rc:%s\n",
772                             strerror(-rc));
773                 return rc;
774         }
775
776         /* Using internal version as session client may not exist yet */
777         rc = tf_session_get_session_internal(tfp, &tfs);
778         if (rc)
779                 return rc;
780
781         *session_id = tfs->session_id;
782
783         return 0;
784 }