6ab8088f0f67aabe1ae12f0a31b30b5d9f04ce83
[dpdk.git] / drivers / net / bnxt / tf_core / tf_session.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2020 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         /* In case multiple clients we chose to close those first */
476         if (tfs->ref_count > 1) {
477                 /* Linaro gcc can't static init this structure */
478                 memset(&scdparms,
479                        0,
480                        sizeof(struct tf_session_client_destroy_parms));
481
482                 scdparms.session_client_id = client->session_client_id;
483                 /* Destroy requested client so its no longer
484                  * registered with this session.
485                  */
486                 rc = tf_session_client_destroy(tfp, &scdparms);
487                 if (rc) {
488                         TFP_DRV_LOG(ERR,
489                                     "Failed to unregister Client %d, rc:%s\n",
490                                     client->session_client_id.id,
491                                     strerror(-rc));
492                         return rc;
493                 }
494
495                 TFP_DRV_LOG(INFO,
496                             "Closed session client, session_client_id:%d\n",
497                             client->session_client_id.id);
498
499                 TFP_DRV_LOG(INFO,
500                             "session_id:%d, ref_count:%d\n",
501                             tfs->session_id.id,
502                             tfs->ref_count);
503
504                 return 0;
505         }
506
507         /* Record the session we're closing so the caller knows the
508          * details.
509          */
510         *parms->session_id = tfs->session_id;
511
512         rc = tf_session_get_device(tfs, &tfd);
513         if (rc) {
514                 TFP_DRV_LOG(ERR,
515                             "Device lookup failed, rc:%s\n",
516                             strerror(-rc));
517                 return rc;
518         }
519
520         /* Unbind the device */
521         rc = tf_dev_unbind(tfp, tfd);
522         if (rc) {
523                 /* Log error */
524                 TFP_DRV_LOG(ERR,
525                             "Device unbind failed, rc:%s\n",
526                             strerror(-rc));
527         }
528
529         rc = tf_msg_session_close(tfp);
530         if (rc) {
531                 /* Log error */
532                 TFP_DRV_LOG(ERR,
533                             "FW Session close failed, rc:%s\n",
534                             strerror(-rc));
535         }
536
537         /* Final cleanup as we're last user of the session thus we
538          * also delete the last client.
539          */
540         ll_delete(&tfs->client_ll, &client->ll_entry);
541         tfp_free(client);
542
543         tfs->ref_count--;
544
545         TFP_DRV_LOG(INFO,
546                     "Closed session, session_id:%d, ref_count:%d\n",
547                     tfs->session_id.id,
548                     tfs->ref_count);
549
550         tfs->dev_init = false;
551
552         tfp_free(tfp->session->core_data);
553         tfp_free(tfp->session);
554         tfp->session = NULL;
555
556         return 0;
557 }
558
559 bool
560 tf_session_is_fid_supported(struct tf_session *tfs,
561                             uint16_t fid)
562 {
563         struct ll_entry *c_entry;
564         struct tf_session_client *client;
565
566         for (c_entry = tfs->client_ll.head;
567              c_entry != NULL;
568              c_entry = c_entry->next) {
569                 client = (struct tf_session_client *)c_entry;
570                 if (client->fw_fid == fid)
571                         return true;
572         }
573
574         return false;
575 }
576
577 int
578 tf_session_get_session_internal(struct tf *tfp,
579                                 struct tf_session **tfs)
580 {
581         int rc = 0;
582
583         /* Skip using the check macro as we want to control the error msg */
584         if (tfp->session == NULL || tfp->session->core_data == NULL) {
585                 rc = -EINVAL;
586                 TFP_DRV_LOG(ERR,
587                             "Session not created, rc:%s\n",
588                             strerror(-rc));
589                 return rc;
590         }
591
592         *tfs = (struct tf_session *)(tfp->session->core_data);
593
594         return rc;
595 }
596
597 int
598 tf_session_get_session(struct tf *tfp,
599                        struct tf_session **tfs)
600 {
601         int rc;
602         uint16_t fw_fid;
603         bool supported = false;
604
605         rc = tf_session_get_session_internal(tfp,
606                                              tfs);
607         /* Logging done by tf_session_get_session_internal */
608         if (rc)
609                 return rc;
610
611         /* As session sharing among functions aka 'individual clients'
612          * is supported we have to assure that the client is indeed
613          * registered before we get deep in the TruFlow api stack.
614          */
615         rc = tfp_get_fid(tfp, &fw_fid);
616         if (rc) {
617                 TFP_DRV_LOG(ERR,
618                             "Internal FID lookup\n, rc:%s\n",
619                             strerror(-rc));
620                 return rc;
621         }
622
623         supported = tf_session_is_fid_supported(*tfs, fw_fid);
624         if (!supported) {
625                 TFP_DRV_LOG
626                         (ERR,
627                         "Ctrl channel not registered with session\n, rc:%s\n",
628                         strerror(-rc));
629                 return -EINVAL;
630         }
631
632         return rc;
633 }
634
635 struct tf_session_client *
636 tf_session_get_session_client(struct tf_session *tfs,
637                               union tf_session_client_id session_client_id)
638 {
639         struct ll_entry *c_entry;
640         struct tf_session_client *client;
641
642         /* Skip using the check macro as we just want to return */
643         if (tfs == NULL)
644                 return NULL;
645
646         for (c_entry = tfs->client_ll.head;
647              c_entry != NULL;
648              c_entry = c_entry->next) {
649                 client = (struct tf_session_client *)c_entry;
650                 if (client->session_client_id.id == session_client_id.id)
651                         return client;
652         }
653
654         return NULL;
655 }
656
657 struct tf_session_client *
658 tf_session_find_session_client_by_name(struct tf_session *tfs,
659                                        const char *ctrl_chan_name)
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 || ctrl_chan_name == 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 (strncmp(client->ctrl_chan_name,
673                             ctrl_chan_name,
674                             TF_SESSION_NAME_MAX) == 0)
675                         return client;
676         }
677
678         return NULL;
679 }
680
681 struct tf_session_client *
682 tf_session_find_session_client_by_fid(struct tf_session *tfs,
683                                       uint16_t fid)
684 {
685         struct ll_entry *c_entry;
686         struct tf_session_client *client;
687
688         /* Skip using the check macro as we just want to return */
689         if (tfs == NULL)
690                 return NULL;
691
692         for (c_entry = tfs->client_ll.head;
693              c_entry != NULL;
694              c_entry = c_entry->next) {
695                 client = (struct tf_session_client *)c_entry;
696                 if (client->fw_fid == fid)
697                         return client;
698         }
699
700         return NULL;
701 }
702
703 int
704 tf_session_get_device(struct tf_session *tfs,
705                       struct tf_dev_info **tfd)
706 {
707         *tfd = &tfs->dev;
708
709         return 0;
710 }
711
712 int
713 tf_session_get_fw_session_id(struct tf *tfp,
714                              uint8_t *fw_session_id)
715 {
716         int rc;
717         struct tf_session *tfs = NULL;
718
719         /* Skip using the check macro as we want to control the error msg */
720         if (tfp->session == NULL) {
721                 rc = -EINVAL;
722                 TFP_DRV_LOG(ERR,
723                             "Session not created, rc:%s\n",
724                             strerror(-rc));
725                 return rc;
726         }
727
728         if (fw_session_id == NULL) {
729                 rc = -EINVAL;
730                 TFP_DRV_LOG(ERR,
731                             "Invalid Argument(s), rc:%s\n",
732                             strerror(-rc));
733                 return rc;
734         }
735
736         rc = tf_session_get_session_internal(tfp, &tfs);
737         if (rc)
738                 return rc;
739
740         *fw_session_id = tfs->session_id.internal.fw_session_id;
741
742         return 0;
743 }
744
745 int
746 tf_session_get_session_id(struct tf *tfp,
747                           union tf_session_id *session_id)
748 {
749         int rc;
750         struct tf_session *tfs = NULL;
751
752         if (tfp->session == NULL) {
753                 rc = -EINVAL;
754                 TFP_DRV_LOG(ERR,
755                             "Session not created, rc:%s\n",
756                             strerror(-rc));
757                 return rc;
758         }
759
760         if (session_id == NULL) {
761                 rc = -EINVAL;
762                 TFP_DRV_LOG(ERR,
763                             "Invalid Argument(s), rc:%s\n",
764                             strerror(-rc));
765                 return rc;
766         }
767
768         /* Using internal version as session client may not exist yet */
769         rc = tf_session_get_session_internal(tfp, &tfs);
770         if (rc)
771                 return rc;
772
773         *session_id = tfs->session_id;
774
775         return 0;
776 }