1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019-2020 Broadcom
8 #include <rte_common.h>
10 #include "tf_session.h"
11 #include "tf_common.h"
15 struct tf_session_client_create_parms {
17 * [in] Pointer to the control channel name string
22 * [out] Firmware Session Client ID
24 union tf_session_client_id *session_client_id;
27 struct tf_session_client_destroy_parms {
29 * FW Session Client Identifier
31 union tf_session_client_id session_client_id;
35 * Creates a Session and the associated client.
38 * Pointer to TF handle
41 * Pointer to session client create parameters
44 * - (0) if successful.
45 * - (-EINVAL) on failure.
46 * - (-ENOMEM) if max session clients has been reached.
49 tf_session_create(struct tf *tfp,
50 struct tf_session_open_session_parms *parms)
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;
60 TF_CHECK_PARMS2(tfp, parms);
62 /* Open FW session and get a new session_id */
63 rc = tf_msg_session_open(tfp,
64 parms->open_cfg->ctrl_chan_name,
66 &fw_session_client_id);
71 "Session is already open, rc:%s\n",
75 "Open message send failed, rc:%s\n",
78 parms->open_cfg->session_id.id = TF_FW_SESSION_ID_INVALID;
82 /* Allocate session */
84 cparms.size = sizeof(struct tf_session_info);
86 rc = tfp_calloc(&cparms);
90 "Failed to allocate session info, rc:%s\n",
94 tfp->session = (struct tf_session_info *)cparms.mem_va;
96 /* Allocate core data for the session */
98 cparms.size = sizeof(struct tf_session);
100 rc = tfp_calloc(&cparms);
104 "Failed to allocate session data, rc:%s\n",
108 tfp->session->core_data = cparms.mem_va;
109 session_id = &parms->open_cfg->session_id;
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;
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;
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;
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;
134 session->shadow_copy = parms->open_cfg->shadow_copy;
136 /* Init session client list */
137 ll_init(&session->client_ll);
139 /* Create the local session client, initialize and attach to
143 cparms.size = sizeof(struct tf_session_client);
144 cparms.alignment = 0;
145 rc = tfp_calloc(&cparms);
149 "Failed to allocate session client, rc:%s\n",
153 client = cparms.mem_va;
155 /* Register FID with the client */
156 rc = tfp_get_fid(tfp, &client->fw_fid);
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;
164 tfp_memcpy(client->ctrl_chan_name,
165 parms->open_cfg->ctrl_chan_name,
166 TF_SESSION_NAME_MAX);
168 ll_insert(&session->client_ll, &client->ll_entry);
169 session->ref_count++;
171 rc = tf_dev_bind(tfp,
172 parms->open_cfg->device_type,
173 session->shadow_copy,
174 &parms->open_cfg->resources,
176 /* Logging handled by dev_bind */
180 session->dev_init = true;
185 tfp_free(tfp->session->core_data);
186 tfp_free(tfp->session);
192 * Creates a Session Client on an existing Session.
195 * Pointer to TF handle
198 * Pointer to session client create parameters
201 * - (0) if successful.
202 * - (-EINVAL) on failure.
203 * - (-ENOMEM) if max session clients has been reached.
206 tf_session_client_create(struct tf *tfp,
207 struct tf_session_client_create_parms *parms)
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;
215 TF_CHECK_PARMS2(tfp, parms);
217 /* Using internal version as session client may not exist yet */
218 rc = tf_session_get_session_internal(tfp, &session);
221 "Failed to lookup session, rc:%s\n",
226 client = tf_session_find_session_client_by_name(session,
227 parms->ctrl_chan_name);
230 "Client %s, already registered with this session\n",
231 parms->ctrl_chan_name);
235 rc = tf_msg_session_client_register
237 parms->ctrl_chan_name,
238 &session_client_id.internal.fw_session_client_id);
241 "Failed to create client on session, rc:%s\n",
246 /* Create the local session client, initialize and attach to
250 cparms.size = sizeof(struct tf_session_client);
251 cparms.alignment = 0;
252 rc = tfp_calloc(&cparms);
255 "Failed to allocate session client, rc:%s\n",
259 client = cparms.mem_va;
261 /* Register FID with the client */
262 rc = tfp_get_fid(tfp, &client->fw_fid);
266 /* Build the Session Client ID by adding the fw_session_id */
267 rc = tf_session_get_fw_session_id
269 &session_client_id.internal.fw_session_id);
272 "Session Firmware id lookup failed, rc:%s\n",
277 tfp_memcpy(client->ctrl_chan_name,
278 parms->ctrl_chan_name,
279 TF_SESSION_NAME_MAX);
281 client->session_client_id.id = session_client_id.id;
283 ll_insert(&session->client_ll, &client->ll_entry);
285 session->ref_count++;
287 /* Build the return value */
288 parms->session_client_id->id = session_client_id.id;
291 /* TBD - Add code to unregister newly create client from fw */
298 * Destroys a Session Client on an existing Session.
301 * Pointer to TF handle
304 * Pointer to the session client destroy parameters
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().
314 tf_session_client_destroy(struct tf *tfp,
315 struct tf_session_client_destroy_parms *parms)
318 struct tf_session *tfs;
319 struct tf_session_client *client;
321 TF_CHECK_PARMS2(tfp, parms);
323 rc = tf_session_get_session(tfp, &tfs);
326 "Failed to lookup session, rc:%s\n",
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) {
336 "Client %d, not found within this session\n",
337 parms->session_client_id.id);
341 /* If last client the request is rejected and cleanup should
342 * be done by session close.
344 if (tfs->ref_count == 1)
347 rc = tf_msg_session_client_unregister
349 parms->session_client_id.internal.fw_session_client_id);
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.
357 "Client destroy on FW Failed, rc:%s\n",
361 ll_delete(&tfs->client_ll, &client->ll_entry);
363 /* Decrement the session ref_count */
372 tf_session_open_session(struct tf *tfp,
373 struct tf_session_open_session_parms *parms)
376 struct tf_session_client_create_parms scparms;
378 TF_CHECK_PARMS2(tfp, parms);
380 /* Decide if we're creating a new session or session client */
381 if (tfp->session == NULL) {
382 rc = tf_session_create(tfp, parms);
385 "Failed to create session, ctrl_chan_name:%s, rc:%s\n",
386 parms->open_cfg->ctrl_chan_name,
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);
396 scparms.ctrl_chan_name = parms->open_cfg->ctrl_chan_name;
397 scparms.session_client_id = &parms->open_cfg->session_client_id;
399 /* Create the new client and get it associated with
402 rc = tf_session_client_create(tfp, &scparms);
405 "Failed to create client on session %d, rc:%s\n",
406 parms->open_cfg->session_id.id,
412 "Session Client:%d created on session:%d\n",
413 parms->open_cfg->session_client_id.id,
414 parms->open_cfg->session_id.id);
421 tf_session_attach_session(struct tf *tfp __rte_unused,
422 struct tf_session_attach_session_parms *parms __rte_unused)
424 int rc = -EOPNOTSUPP;
426 TF_CHECK_PARMS2(tfp, parms);
429 "Attach not yet supported, rc:%s\n",
435 tf_session_close_session(struct tf *tfp,
436 struct tf_session_close_session_parms *parms)
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;
445 TF_CHECK_PARMS2(tfp, parms);
447 rc = tf_session_get_session(tfp, &tfs);
450 "Session lookup failed, rc:%s\n",
455 if (tfs->session_id.id == TF_SESSION_ID_INVALID) {
458 "Invalid session id, unable to close, rc:%s\n",
463 /* Get the client, we need it independently of the closure
464 * type (client or session closure).
466 * We find the client by way of the fid. Thus one cannot close
467 * a client on behalf of someone else.
469 rc = tfp_get_fid(tfp, &fid);
473 client = tf_session_find_session_client_by_fid(tfs,
478 "Client not part of the session, unable to close, rc:%s\n",
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 */
488 sizeof(struct tf_session_client_destroy_parms));
490 scdparms.session_client_id = client->session_client_id;
491 /* Destroy requested client so its no longer
492 * registered with this session.
494 rc = tf_session_client_destroy(tfp, &scdparms);
497 "Failed to unregister Client %d, rc:%s\n",
498 client->session_client_id.id,
504 "Closed session client, session_client_id:%d\n",
505 client->session_client_id.id);
508 "session_id:%d, ref_count:%d\n",
515 /* Record the session we're closing so the caller knows the
518 *parms->session_id = tfs->session_id;
520 rc = tf_session_get_device(tfs, &tfd);
523 "Device lookup failed, rc:%s\n",
528 /* Unbind the device */
529 rc = tf_dev_unbind(tfp, tfd);
533 "Device unbind failed, rc:%s\n",
537 rc = tf_msg_session_close(tfp);
541 "FW Session close failed, rc:%s\n",
545 /* Final cleanup as we're last user of the session thus we
546 * also delete the last client.
548 ll_delete(&tfs->client_ll, &client->ll_entry);
554 "Closed session, session_id:%d, ref_count:%d\n",
558 tfs->dev_init = false;
560 tfp_free(tfp->session->core_data);
561 tfp_free(tfp->session);
568 tf_session_is_fid_supported(struct tf_session *tfs,
571 struct ll_entry *c_entry;
572 struct tf_session_client *client;
574 for (c_entry = tfs->client_ll.head;
576 c_entry = c_entry->next) {
577 client = (struct tf_session_client *)c_entry;
578 if (client->fw_fid == fid)
586 tf_session_get_session_internal(struct tf *tfp,
587 struct tf_session **tfs)
591 /* Skip using the check macro as we want to control the error msg */
592 if (tfp->session == NULL || tfp->session->core_data == NULL) {
595 "Session not created, rc:%s\n",
600 *tfs = (struct tf_session *)(tfp->session->core_data);
606 tf_session_get_session(struct tf *tfp,
607 struct tf_session **tfs)
611 bool supported = false;
613 rc = tf_session_get_session_internal(tfp,
615 /* Logging done by tf_session_get_session_internal */
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.
623 rc = tfp_get_fid(tfp, &fw_fid);
626 "Internal FID lookup\n, rc:%s\n",
631 supported = tf_session_is_fid_supported(*tfs, fw_fid);
635 "Ctrl channel not registered with session\n, rc:%s\n",
643 struct tf_session_client *
644 tf_session_get_session_client(struct tf_session *tfs,
645 union tf_session_client_id session_client_id)
647 struct ll_entry *c_entry;
648 struct tf_session_client *client;
650 /* Skip using the check macro as we just want to return */
654 for (c_entry = tfs->client_ll.head;
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)
665 struct tf_session_client *
666 tf_session_find_session_client_by_name(struct tf_session *tfs,
667 const char *ctrl_chan_name)
669 struct ll_entry *c_entry;
670 struct tf_session_client *client;
672 /* Skip using the check macro as we just want to return */
673 if (tfs == NULL || ctrl_chan_name == NULL)
676 for (c_entry = tfs->client_ll.head;
678 c_entry = c_entry->next) {
679 client = (struct tf_session_client *)c_entry;
680 if (strncmp(client->ctrl_chan_name,
682 TF_SESSION_NAME_MAX) == 0)
689 struct tf_session_client *
690 tf_session_find_session_client_by_fid(struct tf_session *tfs,
693 struct ll_entry *c_entry;
694 struct tf_session_client *client;
696 /* Skip using the check macro as we just want to return */
700 for (c_entry = tfs->client_ll.head;
702 c_entry = c_entry->next) {
703 client = (struct tf_session_client *)c_entry;
704 if (client->fw_fid == fid)
712 tf_session_get_device(struct tf_session *tfs,
713 struct tf_dev_info **tfd)
721 tf_session_get_fw_session_id(struct tf *tfp,
722 uint8_t *fw_session_id)
725 struct tf_session *tfs = NULL;
727 /* Skip using the check macro as we want to control the error msg */
728 if (tfp->session == NULL) {
731 "Session not created, rc:%s\n",
736 if (fw_session_id == NULL) {
739 "Invalid Argument(s), rc:%s\n",
744 rc = tf_session_get_session_internal(tfp, &tfs);
748 *fw_session_id = tfs->session_id.internal.fw_session_id;
754 tf_session_get_session_id(struct tf *tfp,
755 union tf_session_id *session_id)
758 struct tf_session *tfs = NULL;
760 if (tfp->session == NULL) {
763 "Session not created, rc:%s\n",
768 if (session_id == NULL) {
771 "Invalid Argument(s), rc:%s\n",
776 /* Using internal version as session client may not exist yet */
777 rc = tf_session_get_session_internal(tfp, &tfs);
781 *session_id = tfs->session_id;