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