'tf_core/tf_tcam.c',
'tf_core/tf_util.c',
'tf_core/tf_if_tbl.c',
+ 'tf_core/ll.c',
'hcapi/hcapi_cfa_p4.c',
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/bitalloc.c
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/rand.c
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/stack.c
+SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/ll.c
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/tf_core.c
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/tf_rm.c
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/tfp.c
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019-2020 Broadcom
+ * All rights reserved.
+ */
+
+/* Linked List Functions */
+
+#include <stdio.h>
+#include "ll.h"
+
+/* init linked list */
+void ll_init(struct ll *ll)
+{
+ ll->head = NULL;
+ ll->tail = NULL;
+}
+
+/* insert entry in linked list */
+void ll_insert(struct ll *ll,
+ struct ll_entry *entry)
+{
+ if (ll->head == NULL) {
+ ll->head = entry;
+ ll->tail = entry;
+ entry->next = NULL;
+ entry->prev = NULL;
+ } else {
+ entry->next = ll->head;
+ entry->prev = NULL;
+ entry->next->prev = entry;
+ ll->head = entry->next->prev;
+ }
+}
+
+/* delete entry from linked list */
+void ll_delete(struct ll *ll,
+ struct ll_entry *entry)
+{
+ if (ll->head == entry && ll->tail == entry) {
+ ll->head = NULL;
+ ll->tail = NULL;
+ } else if (ll->head == entry) {
+ ll->head = entry->next;
+ ll->head->prev = NULL;
+ } else if (ll->tail == entry) {
+ ll->tail = entry->prev;
+ ll->tail->next = NULL;
+ } else {
+ entry->prev->next = entry->next;
+ entry->next->prev = entry->prev;
+ }
+}
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019-2020 Broadcom
+ * All rights reserved.
+ */
+
+/* Linked List Header File */
+
+#ifndef _LL_H_
+#define _LL_H_
+
+/* linked list entry */
+struct ll_entry {
+ struct ll_entry *prev;
+ struct ll_entry *next;
+};
+
+/* linked list */
+struct ll {
+ struct ll_entry *head;
+ struct ll_entry *tail;
+};
+
+/**
+ * Linked list initialization.
+ *
+ * [in] ll, linked list to be initialized
+ */
+void ll_init(struct ll *ll);
+
+/**
+ * Linked list insert
+ *
+ * [in] ll, linked list where element is inserted
+ * [in] entry, entry to be added
+ */
+void ll_insert(struct ll *ll, struct ll_entry *entry);
+
+/**
+ * Linked list delete
+ *
+ * [in] ll, linked list where element is removed
+ * [in] entry, entry to be deleted
+ */
+void ll_delete(struct ll *ll, struct ll_entry *entry);
+
+#endif /* _LL_H_ */
parms->session_id.internal.device = device;
oparms.open_cfg = parms;
+ /* Session vs session client is decided in
+ * tf_session_open_session()
+ */
+ printf("TF_OPEN, %s\n", parms->ctrl_chan_name);
rc = tf_session_open_session(tfp, &oparms);
/* Logging handled by tf_session_open_session */
if (rc)
return rc;
TFP_DRV_LOG(INFO,
- "Session created, session_id:%d\n",
- parms->session_id.id);
-
- TFP_DRV_LOG(INFO,
- "domain:%d, bus:%d, device:%d, fw_session_id:%d\n",
+ "domain:%d, bus:%d, device:%d\n",
parms->session_id.internal.domain,
parms->session_id.internal.bus,
- parms->session_id.internal.device,
- parms->session_id.internal.fw_session_id);
+ parms->session_id.internal.device);
return 0;
}
cparms.ref_count = &ref_count;
cparms.session_id = &session_id;
+ /* Session vs session client is decided in
+ * tf_session_close_session()
+ */
rc = tf_session_close_session(tfp,
&cparms);
/* Logging handled by tf_session_close_session */
return rc;
TFP_DRV_LOG(INFO,
- "Closed session, session_id:%d, ref_count:%d\n",
- cparms.session_id->id,
- *cparms.ref_count);
-
- TFP_DRV_LOG(INFO,
- "domain:%d, bus:%d, device:%d, fw_session_id:%d\n",
+ "domain:%d, bus:%d, device:%d\n",
cparms.session_id->internal.domain,
cparms.session_id->internal.bus,
- cparms.session_id->internal.device,
- cparms.session_id->internal.fw_session_id);
+ cparms.session_id->internal.device);
return rc;
}
* @ref tf_close_session
*/
-
/**
* Session Version defines
*
} internal;
};
+/**
+ * Session Client Identifier
+ *
+ * Unique identifier for a client within a session. Session Client ID
+ * is constructed from the passed in session and a firmware allocated
+ * fw_session_client_id. Done by TruFlow on tf_open_session().
+ */
+union tf_session_client_id {
+ uint16_t id;
+ struct {
+ uint8_t fw_session_id;
+ uint8_t fw_session_client_id;
+ } internal;
+};
+
/**
* Session Version
*
*
* Contains a pointer to the session info. Allocated by ULP and passed
* to TruFlow using tf_open_session(). TruFlow will populate the
- * session info at that time. Additional 'opens' can be done using
- * same session_info by using tf_attach_session().
+ * session info at that time. A TruFlow Session can be used by more
+ * than one PF/VF by using the tf_open_session().
*
* It is expected that ULP allocates this memory as shared memory.
*
* The session_id allows a session to be shared between devices.
*/
union tf_session_id session_id;
+ /**
+ * [in/out] session_client_id
+ *
+ * Session_client_id is unique per client.
+ *
+ * Session_client_id is composed of session_id and the
+ * fw_session_client_id fw_session_id. The construction is
+ * done by parsing the ctrl_chan_name together with allocation
+ * of a fw_session_client_id during tf_open_session().
+ *
+ * A reference count will be incremented in the session on
+ * which a client is created.
+ *
+ * A session can first be closed if there is one Session
+ * Client left. Session Clients should closed using
+ * tf_close_session().
+ */
+ union tf_session_client_id session_client_id;
/**
* [in] device type
*
- * Device type is passed, one of Wh+, SR, Thor, SR2
+ * Device type for the session.
*/
enum tf_device_type device_type;
- /** [in] resources
+ /**
+ * [in] resources
*
- * Resource allocation
+ * Resource allocation for the session.
*/
struct tf_session_resources resources;
};
/**
- * Opens a new TruFlow management session.
+ * Opens a new TruFlow Session or session client.
+ *
+ * What gets created depends on the passed in tfp content. If the tfp
+ * does not have prior session data a new session with associated
+ * session client. If tfp has a session already a session client will
+ * be created. In both cases the session client is created using the
+ * provided ctrl_chan_name.
*
- * TruFlow will allocate session specific memory, shared memory, to
- * hold its session data. This data is private to TruFlow.
+ * In case of session creation TruFlow will allocate session specific
+ * memory, shared memory, to hold its session data. This data is
+ * private to TruFlow.
*
- * Multiple PFs can share the same session. An association, refcount,
- * between session and PFs is maintained within TruFlow. Thus, a PF
- * can attach to an existing session, see tf_attach_session().
+ * No other TruFlow APIs will succeed unless this API is first called
+ * and succeeds.
*
- * No other TruFlow APIs will succeed unless this API is first called and
- * succeeds.
+ * tf_open_session() returns a session id and session client id that
+ * is used on all other TF APIs.
*
- * tf_open_session() returns a session id that can be used on attach.
+ * A Session or session client can be closed using tf_close_session().
*
* [in] tfp
* Pointer to TF handle
+ *
* [in] parms
* Pointer to open parameters
*
int tf_open_session(struct tf *tfp,
struct tf_open_session_parms *parms);
+/**
+ * Experimental
+ *
+ * tf_attach_session parameters definition.
+ */
struct tf_attach_session_parms {
/**
* [in] ctrl_chan_name
};
/**
- * Attaches to an existing session. Used when more than one PF wants
- * to share a single session. In that case all TruFlow management
- * traffic will be sent to the TruFlow firmware using the 'PF' that
- * did the attach not the session ctrl channel.
+ * Experimental
+ *
+ * Allows a 2nd application instance to attach to an existing
+ * session. Used when a session is to be shared between two processes.
*
* Attach will increment a ref count as to manage the shared session data.
*
- * [in] tfp, pointer to TF handle
- * [in] parms, pointer to attach parameters
+ * [in] tfp
+ * Pointer to TF handle
+ *
+ * [in] parms
+ * Pointer to attach parameters
*
* Returns
* - (0) if successful.
struct tf_attach_session_parms *parms);
/**
- * Closes an existing session. Cleans up all hardware and firmware
- * state associated with the TruFlow application session when the last
- * PF associated with the session results in refcount to be zero.
+ * Closes an existing session client or the session it self. The
+ * session client is default closed and if the session reference count
+ * is 0 then the session is closed as well.
+ *
+ * On session close all hardware and firmware state associated with
+ * the TruFlow application is cleaned up.
+ *
+ * The session client is extracted from the tfp. Thus tf_close_session()
+ * cannot close a session client on behalf of another function.
*
* Returns success or failure code.
*/
* @ref tf_set_tbl_entry
*
* @ref tf_get_tbl_entry
+ *
+ * @ref tf_bulk_get_tbl_entry
*/
-
/**
* tf_alloc_tbl_entry parameter definition
*/
int
tf_msg_session_open(struct tf *tfp,
char *ctrl_chan_name,
- uint8_t *fw_session_id)
+ uint8_t *fw_session_id,
+ uint8_t *fw_session_client_id)
{
int rc;
struct hwrm_tf_session_open_input req = { 0 };
if (rc)
return rc;
- *fw_session_id = resp.fw_session_id;
+ *fw_session_id = (uint8_t)tfp_le_to_cpu_32(resp.fw_session_id);
+ *fw_session_client_id = (uint8_t)tfp_le_to_cpu_32(resp.fw_session_id);
return rc;
}
return -1;
}
+int
+tf_msg_session_client_register(struct tf *tfp,
+ char *ctrl_channel_name,
+ uint8_t *fw_session_client_id)
+{
+ int rc;
+ struct hwrm_tf_session_register_input req = { 0 };
+ struct hwrm_tf_session_register_output resp = { 0 };
+ struct tfp_send_msg_parms parms = { 0 };
+ uint8_t fw_session_id;
+
+ rc = tf_session_get_fw_session_id(tfp, &fw_session_id);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "Unable to lookup FW id, rc:%s\n",
+ strerror(-rc));
+ return rc;
+ }
+
+ /* Populate the request */
+ req.fw_session_id = tfp_cpu_to_le_32(fw_session_id);
+ tfp_memcpy(&req.session_client_name,
+ ctrl_channel_name,
+ TF_SESSION_NAME_MAX);
+
+ parms.tf_type = HWRM_TF_SESSION_REGISTER;
+ parms.req_data = (uint32_t *)&req;
+ parms.req_size = sizeof(req);
+ parms.resp_data = (uint32_t *)&resp;
+ parms.resp_size = sizeof(resp);
+ parms.mailbox = TF_KONG_MB;
+
+ rc = tfp_send_msg_direct(tfp,
+ &parms);
+ if (rc)
+ return rc;
+
+ *fw_session_client_id =
+ (uint8_t)tfp_le_to_cpu_32(resp.fw_session_client_id);
+
+ return rc;
+}
+
+int
+tf_msg_session_client_unregister(struct tf *tfp,
+ uint8_t fw_session_client_id)
+{
+ int rc;
+ struct hwrm_tf_session_unregister_input req = { 0 };
+ struct hwrm_tf_session_unregister_output resp = { 0 };
+ struct tfp_send_msg_parms parms = { 0 };
+ uint8_t fw_session_id;
+
+ rc = tf_session_get_fw_session_id(tfp, &fw_session_id);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "Unable to lookup FW id, rc:%s\n",
+ strerror(-rc));
+ return rc;
+ }
+
+ /* Populate the request */
+ req.fw_session_id = tfp_cpu_to_le_32(fw_session_id);
+ req.fw_session_client_id = tfp_cpu_to_le_32(fw_session_client_id);
+
+ parms.tf_type = HWRM_TF_SESSION_UNREGISTER;
+ parms.req_data = (uint32_t *)&req;
+ parms.req_size = sizeof(req);
+ parms.resp_data = (uint32_t *)&resp;
+ parms.resp_size = sizeof(resp);
+ parms.mailbox = TF_KONG_MB;
+
+ rc = tfp_send_msg_direct(tfp,
+ &parms);
+
+ return rc;
+}
+
int
tf_msg_session_close(struct tf *tfp)
{
*/
int tf_msg_session_open(struct tf *tfp,
char *ctrl_chan_name,
- uint8_t *fw_session_id);
+ uint8_t *fw_session_id,
+ uint8_t *fw_session_client_id);
/**
* Sends session close request to Firmware
* [in] session
* Pointer to session handle
*
+ * [in] ctrl_chan_name
+ * PCI name of the control channel
+ *
* [in] fw_session_id
* Pointer to the fw_session_id that is assigned to the session at
* time of session open
char *ctrl_channel_name,
uint8_t tf_fw_session_id);
+/**
+ * Sends session client register request to Firmware
+ *
+ * [in] session
+ * Pointer to session handle
+ *
+ * [in] ctrl_chan_name
+ * PCI name of the control channel
+ *
+ * [in/out] fw_session_client_id
+ * Pointer to the fw_session_client_id that is allocated on firmware
+ * side
+ *
+ * Returns:
+ * 0 on Success else internal Truflow error
+ */
+int tf_msg_session_client_register(struct tf *tfp,
+ char *ctrl_channel_name,
+ uint8_t *fw_session_client_id);
+
+/**
+ * Sends session client unregister request to Firmware
+ *
+ * [in] session
+ * Pointer to session handle
+ *
+ * [in/out] fw_session_client_id
+ * Pointer to the fw_session_client_id that is allocated on firmware
+ * side
+ *
+ * Returns:
+ * 0 on Success else internal Truflow error
+ */
+int tf_msg_session_client_unregister(struct tf *tfp,
+ uint8_t fw_session_client_id);
+
/**
* Sends session close request to Firmware
*
TF_CHECK_PARMS2(tfp, parms);
/* Retrieve the session information */
- rc = tf_session_get_session(tfp, &tfs);
+ rc = tf_session_get_session_internal(tfp, &tfs);
if (rc)
return rc;
#include "tf_msg.h"
#include "tfp.h"
-int
-tf_session_open_session(struct tf *tfp,
- struct tf_session_open_session_parms *parms)
+struct tf_session_client_create_parms {
+ /**
+ * [in] Pointer to the control channel name string
+ */
+ char *ctrl_chan_name;
+
+ /**
+ * [out] Firmware Session Client ID
+ */
+ union tf_session_client_id *session_client_id;
+};
+
+struct tf_session_client_destroy_parms {
+ /**
+ * FW Session Client Identifier
+ */
+ union tf_session_client_id session_client_id;
+};
+
+/**
+ * Creates a Session and the associated client.
+ *
+ * [in] tfp
+ * Pointer to TF handle
+ *
+ * [in] parms
+ * Pointer to session client create parameters
+ *
+ * Returns
+ * - (0) if successful.
+ * - (-EINVAL) on failure.
+ * - (-ENOMEM) if max session clients has been reached.
+ */
+static int
+tf_session_create(struct tf *tfp,
+ struct tf_session_open_session_parms *parms)
{
int rc;
struct tf_session *session = NULL;
+ struct tf_session_client *client;
struct tfp_calloc_parms cparms;
uint8_t fw_session_id;
+ uint8_t fw_session_client_id;
union tf_session_id *session_id;
TF_CHECK_PARMS2(tfp, parms);
/* Open FW session and get a new session_id */
rc = tf_msg_session_open(tfp,
parms->open_cfg->ctrl_chan_name,
- &fw_session_id);
+ &fw_session_id,
+ &fw_session_client_id);
if (rc) {
/* Log error */
if (rc == -EEXIST)
session->session_id.internal.bus = session_id->internal.bus;
session->session_id.internal.device = session_id->internal.device;
session->session_id.internal.fw_session_id = fw_session_id;
- /* Return the allocated fw session id */
- session_id->internal.fw_session_id = fw_session_id;
+ /* Return the allocated session id */
+ session_id->id = session->session_id.id;
session->shadow_copy = parms->open_cfg->shadow_copy;
- tfp_memcpy(session->ctrl_chan_name,
+ /* Init session client list */
+ ll_init(&session->client_ll);
+
+ /* Create the local session client, initialize and attach to
+ * the session
+ */
+ cparms.nitems = 1;
+ cparms.size = sizeof(struct tf_session_client);
+ cparms.alignment = 0;
+ rc = tfp_calloc(&cparms);
+ if (rc) {
+ /* Log error */
+ TFP_DRV_LOG(ERR,
+ "Failed to allocate session client, rc:%s\n",
+ strerror(-rc));
+ goto cleanup;
+ }
+ client = cparms.mem_va;
+
+ /* Register FID with the client */
+ rc = tfp_get_fid(tfp, &client->fw_fid);
+ if (rc)
+ return rc;
+
+ client->session_client_id.internal.fw_session_id = fw_session_id;
+ client->session_client_id.internal.fw_session_client_id =
+ fw_session_client_id;
+
+ tfp_memcpy(client->ctrl_chan_name,
parms->open_cfg->ctrl_chan_name,
TF_SESSION_NAME_MAX);
+ ll_insert(&session->client_ll, &client->ll_entry);
+ session->ref_count++;
+
rc = tf_dev_bind(tfp,
parms->open_cfg->device_type,
session->shadow_copy,
if (rc)
return rc;
- session->ref_count++;
+ session->dev_init = true;
return 0;
return rc;
}
+/**
+ * Creates a Session Client on an existing Session.
+ *
+ * [in] tfp
+ * Pointer to TF handle
+ *
+ * [in] parms
+ * Pointer to session client create parameters
+ *
+ * Returns
+ * - (0) if successful.
+ * - (-EINVAL) on failure.
+ * - (-ENOMEM) if max session clients has been reached.
+ */
+static int
+tf_session_client_create(struct tf *tfp,
+ struct tf_session_client_create_parms *parms)
+{
+ int rc;
+ struct tf_session *session = NULL;
+ struct tf_session_client *client;
+ struct tfp_calloc_parms cparms;
+ union tf_session_client_id session_client_id;
+
+ TF_CHECK_PARMS2(tfp, parms);
+
+ /* Using internal version as session client may not exist yet */
+ rc = tf_session_get_session_internal(tfp, &session);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "Failed to lookup session, rc:%s\n",
+ strerror(-rc));
+ return rc;
+ }
+
+ client = tf_session_find_session_client_by_name(session,
+ parms->ctrl_chan_name);
+ if (client) {
+ TFP_DRV_LOG(ERR,
+ "Client %s, already registered with this session\n",
+ parms->ctrl_chan_name);
+ return -EOPNOTSUPP;
+ }
+
+ rc = tf_msg_session_client_register
+ (tfp,
+ parms->ctrl_chan_name,
+ &session_client_id.internal.fw_session_client_id);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "Failed to create client on session, rc:%s\n",
+ strerror(-rc));
+ return rc;
+ }
+
+ /* Create the local session client, initialize and attach to
+ * the session
+ */
+ cparms.nitems = 1;
+ cparms.size = sizeof(struct tf_session_client);
+ cparms.alignment = 0;
+ rc = tfp_calloc(&cparms);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "Failed to allocate session client, rc:%s\n",
+ strerror(-rc));
+ goto cleanup;
+ }
+ client = cparms.mem_va;
+
+ /* Register FID with the client */
+ rc = tfp_get_fid(tfp, &client->fw_fid);
+ if (rc)
+ return rc;
+
+ /* Build the Session Client ID by adding the fw_session_id */
+ rc = tf_session_get_fw_session_id
+ (tfp,
+ &session_client_id.internal.fw_session_id);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "Session Firmware id lookup failed, rc:%s\n",
+ strerror(-rc));
+ return rc;
+ }
+
+ tfp_memcpy(client->ctrl_chan_name,
+ parms->ctrl_chan_name,
+ TF_SESSION_NAME_MAX);
+
+ client->session_client_id.id = session_client_id.id;
+
+ ll_insert(&session->client_ll, &client->ll_entry);
+
+ session->ref_count++;
+
+ /* Build the return value */
+ parms->session_client_id->id = session_client_id.id;
+
+ cleanup:
+ /* TBD - Add code to unregister newly create client from fw */
+
+ return rc;
+}
+
+
+/**
+ * Destroys a Session Client on an existing Session.
+ *
+ * [in] tfp
+ * Pointer to TF handle
+ *
+ * [in] parms
+ * Pointer to the session client destroy parameters
+ *
+ * Returns
+ * - (0) if successful.
+ * - (-EINVAL) on failure.
+ * - (-ENOTFOUND) error, client not owned by the session.
+ * - (-ENOTSUPP) error, unable to destroy client as its the last
+ * client. Please use the tf_session_close().
+ */
+static int
+tf_session_client_destroy(struct tf *tfp,
+ struct tf_session_client_destroy_parms *parms)
+{
+ int rc;
+ struct tf_session *tfs;
+ struct tf_session_client *client;
+
+ TF_CHECK_PARMS2(tfp, parms);
+
+ rc = tf_session_get_session(tfp, &tfs);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "Failed to lookup session, rc:%s\n",
+ strerror(-rc));
+ return rc;
+ }
+
+ /* Check session owns this client and that we're not the last client */
+ client = tf_session_get_session_client(tfs,
+ parms->session_client_id);
+ if (client == NULL) {
+ TFP_DRV_LOG(ERR,
+ "Client %d, not found within this session\n",
+ parms->session_client_id.id);
+ return -EINVAL;
+ }
+
+ /* If last client the request is rejected and cleanup should
+ * be done by session close.
+ */
+ if (tfs->ref_count == 1)
+ return -EOPNOTSUPP;
+
+ rc = tf_msg_session_client_unregister
+ (tfp,
+ parms->session_client_id.internal.fw_session_client_id);
+
+ /* Log error, but continue. If FW fails we do not really have
+ * a way to fix this but the client would no longer be valid
+ * thus we remove from the session.
+ */
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "Client destroy on FW Failed, rc:%s\n",
+ strerror(-rc));
+ }
+
+ ll_delete(&tfs->client_ll, &client->ll_entry);
+
+ /* Decrement the session ref_count */
+ tfs->ref_count--;
+
+ tfp_free(client);
+
+ return rc;
+}
+
+int
+tf_session_open_session(struct tf *tfp,
+ struct tf_session_open_session_parms *parms)
+{
+ int rc;
+ struct tf_session_client_create_parms scparms;
+
+ TF_CHECK_PARMS2(tfp, parms);
+
+ /* Decide if we're creating a new session or session client */
+ if (tfp->session == NULL) {
+ rc = tf_session_create(tfp, parms);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "Failed to create session, ctrl_chan_name:%s, rc:%s\n",
+ parms->open_cfg->ctrl_chan_name,
+ strerror(-rc));
+ return rc;
+ }
+
+ TFP_DRV_LOG(INFO,
+ "Session created, session_client_id:%d, session_id:%d\n",
+ parms->open_cfg->session_client_id.id,
+ parms->open_cfg->session_id.id);
+ } else {
+ scparms.ctrl_chan_name = parms->open_cfg->ctrl_chan_name;
+ scparms.session_client_id = &parms->open_cfg->session_client_id;
+
+ /* Create the new client and get it associated with
+ * the session.
+ */
+ rc = tf_session_client_create(tfp, &scparms);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "Failed to create client on session %d, rc:%s\n",
+ parms->open_cfg->session_id.id,
+ strerror(-rc));
+ return rc;
+ }
+
+ TFP_DRV_LOG(INFO,
+ "Session Client:%d created on session:%d\n",
+ parms->open_cfg->session_client_id.id,
+ parms->open_cfg->session_id.id);
+ }
+
+ return 0;
+}
+
int
tf_session_attach_session(struct tf *tfp __rte_unused,
struct tf_session_attach_session_parms *parms __rte_unused)
{
int rc;
struct tf_session *tfs = NULL;
+ struct tf_session_client *client;
struct tf_dev_info *tfd = NULL;
+ struct tf_session_client_destroy_parms scdparms;
+ uint16_t fid;
TF_CHECK_PARMS2(tfp, parms);
return rc;
}
- tfs->ref_count--;
+ /* Get the client, we need it independently of the closure
+ * type (client or session closure).
+ *
+ * We find the client by way of the fid. Thus one cannot close
+ * a client on behalf of someone else.
+ */
+ rc = tfp_get_fid(tfp, &fid);
+ if (rc)
+ return rc;
+
+ client = tf_session_find_session_client_by_fid(tfs,
+ fid);
+ /* In case multiple clients we chose to close those first */
+ if (tfs->ref_count > 1) {
+ /* Linaro gcc can't static init this structure */
+ memset(&scdparms,
+ 0,
+ sizeof(struct tf_session_client_destroy_parms));
+
+ scdparms.session_client_id = client->session_client_id;
+ /* Destroy requested client so its no longer
+ * registered with this session.
+ */
+ rc = tf_session_client_destroy(tfp, &scdparms);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "Failed to unregister Client %d, rc:%s\n",
+ client->session_client_id.id,
+ strerror(-rc));
+ return rc;
+ }
+
+ TFP_DRV_LOG(INFO,
+ "Closed session client, session_client_id:%d\n",
+ client->session_client_id.id);
+
+ TFP_DRV_LOG(INFO,
+ "session_id:%d, ref_count:%d\n",
+ tfs->session_id.id,
+ tfs->ref_count);
+
+ return 0;
+ }
/* Record the session we're closing so the caller knows the
* details.
return rc;
}
- if (tfs->ref_count > 0) {
- /* In case we're attached only the session client gets
- * closed.
- */
- rc = tf_msg_session_close(tfp);
- if (rc) {
- /* Log error */
- TFP_DRV_LOG(ERR,
- "FW Session close failed, rc:%s\n",
- strerror(-rc));
- }
-
- return 0;
- }
-
- /* Final cleanup as we're last user of the session */
-
/* Unbind the device */
rc = tf_dev_unbind(tfp, tfd);
if (rc) {
strerror(-rc));
}
- /* In case we're attached only the session client gets closed */
rc = tf_msg_session_close(tfp);
if (rc) {
/* Log error */
strerror(-rc));
}
+ /* Final cleanup as we're last user of the session thus we
+ * also delete the last client.
+ */
+ ll_delete(&tfs->client_ll, &client->ll_entry);
+ tfp_free(client);
+
+ tfs->ref_count--;
+
+ TFP_DRV_LOG(INFO,
+ "Closed session, session_id:%d, ref_count:%d\n",
+ tfs->session_id.id,
+ tfs->ref_count);
+
+ tfs->dev_init = false;
+
tfp_free(tfp->session->core_data);
tfp_free(tfp->session);
tfp->session = NULL;
return 0;
}
+bool
+tf_session_is_fid_supported(struct tf_session *tfs,
+ uint16_t fid)
+{
+ struct ll_entry *c_entry;
+ struct tf_session_client *client;
+
+ for (c_entry = tfs->client_ll.head;
+ c_entry != NULL;
+ c_entry = c_entry->next) {
+ client = (struct tf_session_client *)c_entry;
+ if (client->fw_fid == fid)
+ return true;
+ }
+
+ return false;
+}
+
int
-tf_session_get_session(struct tf *tfp,
- struct tf_session **tfs)
+tf_session_get_session_internal(struct tf *tfp,
+ struct tf_session **tfs)
{
- int rc;
+ int rc = 0;
+ /* Skip using the check macro as we want to control the error msg */
if (tfp->session == NULL || tfp->session->core_data == NULL) {
rc = -EINVAL;
TFP_DRV_LOG(ERR,
*tfs = (struct tf_session *)(tfp->session->core_data);
- return 0;
+ return rc;
+}
+
+int
+tf_session_get_session(struct tf *tfp,
+ struct tf_session **tfs)
+{
+ int rc;
+ uint16_t fw_fid;
+ bool supported = false;
+
+ rc = tf_session_get_session_internal(tfp,
+ tfs);
+ /* Logging done by tf_session_get_session_internal */
+ if (rc)
+ return rc;
+
+ /* As session sharing among functions aka 'individual clients'
+ * is supported we have to assure that the client is indeed
+ * registered before we get deep in the TruFlow api stack.
+ */
+ rc = tfp_get_fid(tfp, &fw_fid);
+ if (rc) {
+ TFP_DRV_LOG(ERR,
+ "Internal FID lookup\n, rc:%s\n",
+ strerror(-rc));
+ return rc;
+ }
+
+ supported = tf_session_is_fid_supported(*tfs, fw_fid);
+ if (!supported) {
+ TFP_DRV_LOG
+ (ERR,
+ "Ctrl channel not registered with session\n, rc:%s\n",
+ strerror(-rc));
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+struct tf_session_client *
+tf_session_get_session_client(struct tf_session *tfs,
+ union tf_session_client_id session_client_id)
+{
+ struct ll_entry *c_entry;
+ struct tf_session_client *client;
+
+ /* Skip using the check macro as we just want to return */
+ if (tfs == NULL)
+ return NULL;
+
+ for (c_entry = tfs->client_ll.head;
+ c_entry != NULL;
+ c_entry = c_entry->next) {
+ client = (struct tf_session_client *)c_entry;
+ if (client->session_client_id.id == session_client_id.id)
+ return client;
+ }
+
+ return NULL;
+}
+
+struct tf_session_client *
+tf_session_find_session_client_by_name(struct tf_session *tfs,
+ const char *ctrl_chan_name)
+{
+ struct ll_entry *c_entry;
+ struct tf_session_client *client;
+
+ /* Skip using the check macro as we just want to return */
+ if (tfs == NULL || ctrl_chan_name == NULL)
+ return NULL;
+
+ for (c_entry = tfs->client_ll.head;
+ c_entry != NULL;
+ c_entry = c_entry->next) {
+ client = (struct tf_session_client *)c_entry;
+ if (strncmp(client->ctrl_chan_name,
+ ctrl_chan_name,
+ TF_SESSION_NAME_MAX) == 0)
+ return client;
+ }
+
+ return NULL;
+}
+
+struct tf_session_client *
+tf_session_find_session_client_by_fid(struct tf_session *tfs,
+ uint16_t fid)
+{
+ struct ll_entry *c_entry;
+ struct tf_session_client *client;
+
+ /* Skip using the check macro as we just want to return */
+ if (tfs == NULL)
+ return NULL;
+
+ for (c_entry = tfs->client_ll.head;
+ c_entry != NULL;
+ c_entry = c_entry->next) {
+ client = (struct tf_session_client *)c_entry;
+ if (client->fw_fid == fid)
+ return client;
+ }
+
+ return NULL;
}
int
int rc;
struct tf_session *tfs = NULL;
+ /* Skip using the check macro as we want to control the error msg */
if (tfp->session == NULL) {
rc = -EINVAL;
TFP_DRV_LOG(ERR,
return rc;
}
- rc = tf_session_get_session(tfp, &tfs);
+ if (fw_session_id == NULL) {
+ rc = -EINVAL;
+ TFP_DRV_LOG(ERR,
+ "Invalid Argument(s), rc:%s\n",
+ strerror(-rc));
+ return rc;
+ }
+
+ rc = tf_session_get_session_internal(tfp, &tfs);
if (rc)
return rc;
return 0;
}
+
+int
+tf_session_get_session_id(struct tf *tfp,
+ union tf_session_id *session_id)
+{
+ int rc;
+ struct tf_session *tfs = NULL;
+
+ if (tfp->session == NULL) {
+ rc = -EINVAL;
+ TFP_DRV_LOG(ERR,
+ "Session not created, rc:%s\n",
+ strerror(-rc));
+ return rc;
+ }
+
+ if (session_id == NULL) {
+ rc = -EINVAL;
+ TFP_DRV_LOG(ERR,
+ "Invalid Argument(s), rc:%s\n",
+ strerror(-rc));
+ return rc;
+ }
+
+ /* Using internal version as session client may not exist yet */
+ rc = tf_session_get_session_internal(tfp, &tfs);
+ if (rc)
+ return rc;
+
+ *session_id = tfs->session_id;
+
+ return 0;
+}
#include "tf_tbl.h"
#include "tf_resources.h"
#include "stack.h"
+#include "ll.h"
/**
* The Session module provides session control support. A session is
/** Session defines
*/
-#define TF_SESSIONS_MAX 1 /** max # sessions */
#define TF_SESSION_ID_INVALID 0xFFFFFFFF /** Invalid Session ID define */
/**
* Shared memory containing private TruFlow session information.
* Through this structure the session can keep track of resource
* allocations and (if so configured) any shadow copy of flow
- * information.
+ * information. It also holds info about Session Clients.
*
* Memory is assigned to the Truflow instance by way of
* tf_open_session. Memory is allocated and owned by i.e. ULP.
*/
struct tf_session_version ver;
- /** Session ID, allocated by FW on tf_open_session() */
- union tf_session_id session_id;
-
/**
- * String containing name of control channel interface to be
- * used for this session to communicate with firmware.
- *
- * ctrl_chan_name will be used as part of a name for any
- * shared memory allocation.
+ * Session ID, allocated by FW on tf_open_session()
*/
- char ctrl_chan_name[TF_SESSION_NAME_MAX];
+ union tf_session_id session_id;
/**
* Boolean controlling the use and availability of shadow
/**
* Session Reference Count. To keep track of functions per
- * session the ref_count is incremented. There is also a
+ * session the ref_count is updated. There is also a
* parallel TruFlow Firmware ref_count in case the TruFlow
* Core goes away without informing the Firmware.
*/
uint8_t ref_count;
- /** Device handle */
+ /**
+ * Session Reference Count for attached sessions. To keep
+ * track of application sharing of a session the
+ * ref_count_attach is updated.
+ */
+ uint8_t ref_count_attach;
+
+ /**
+ * Device handle
+ */
struct tf_dev_info dev;
+ /**
+ * Device init flag. False if Device is not fully initialized,
+ * else true.
+ */
+ bool dev_init;
+
+ /**
+ * Linked list of clients registered for this session
+ */
+ struct ll client_ll;
+};
+
+/**
+ * Session Client
+ *
+ * Shared memory for each of the Session Clients. A session can have
+ * one or more clients.
+ */
+struct tf_session_client {
+ /**
+ * Linked list of clients
+ */
+ struct ll_entry ll_entry; /* For inserting in link list, must be
+ * first field of struct.
+ */
+
+ /**
+ * String containing name of control channel interface to be
+ * used for this session to communicate with firmware.
+ *
+ * ctrl_chan_name will be used as part of a name for any
+ * shared memory allocation.
+ */
+ char ctrl_chan_name[TF_SESSION_NAME_MAX];
+
+ /**
+ * Firmware FID, learned at time of Session Client create.
+ */
+ uint16_t fw_fid;
+
+ /**
+ * Session Client ID, allocated by FW on tf_register_session()
+ */
+ union tf_session_client_id session_client_id;
};
/**
* Session close parameter definition
*/
struct tf_session_close_session_parms {
+ /**
+ * []
+ */
uint8_t *ref_count;
+ /**
+ * []
+ */
union tf_session_id *session_id;
};
*
* @ref tf_session_close_session
*
+ * @ref tf_session_is_fid_supported
+ *
+ * @ref tf_session_get_session_internal
+ *
* @ref tf_session_get_session
*
+ * @ref tf_session_get_session_client
+ *
+ * @ref tf_session_find_session_client_by_name
+ *
+ * @ref tf_session_find_session_client_by_fid
+ *
* @ref tf_session_get_device
*
* @ref tf_session_get_fw_session_id
+ *
+ * @ref tf_session_get_session_id
*/
/**
struct tf_session_attach_session_parms *parms);
/**
- * Closes a previous created session.
+ * Closes a previous created session. Only possible if previous
+ * registered Clients had been unregistered first.
*
* [in] tfp
* Pointer to TF handle
*
* Returns
* - (0) if successful.
+ * - (-EUSERS) if clients are still registered with the session.
* - (-EINVAL) on failure.
*/
int tf_session_close_session(struct tf *tfp,
struct tf_session_close_session_parms *parms);
/**
- * Looks up the private session information from the TF session info.
+ * Verifies that the fid is supported by the session. Used to assure
+ * that a function i.e. client/control channel is registered with the
+ * session.
+ *
+ * [in] tfs
+ * Pointer to TF Session handle
+ *
+ * [in] fid
+ * FID value to check
+ *
+ * Returns
+ * - (true) if successful, else false
+ * - (-EINVAL) on failure.
+ */
+bool
+tf_session_is_fid_supported(struct tf_session *tfs,
+ uint16_t fid);
+
+/**
+ * Looks up the private session information from the TF session
+ * info. Does not perform a fid check against the registered
+ * clients. Should be used if tf_session_get_session() was used
+ * previously i.e. at the TF API boundary.
+ *
+ * [in] tfp
+ * Pointer to TF handle
+ *
+ * [out] tfs
+ * Pointer pointer to the session
+ *
+ * Returns
+ * - (0) if successful.
+ * - (-EINVAL) on failure.
+ */
+int tf_session_get_session_internal(struct tf *tfp,
+ struct tf_session **tfs);
+
+/**
+ * Looks up the private session information from the TF session
+ * info. Performs a fid check against the clients on the session.
*
* [in] tfp
* Pointer to TF handle
int tf_session_get_session(struct tf *tfp,
struct tf_session **tfs);
+/**
+ * Looks up client within the session.
+ *
+ * [in] tfs
+ * Pointer pointer to the session
+ *
+ * [in] session_client_id
+ * Client id to look for within the session
+ *
+ * Returns
+ * client if successful.
+ * - (NULL) on failure, client not found.
+ */
+struct tf_session_client *
+tf_session_get_session_client(struct tf_session *tfs,
+ union tf_session_client_id session_client_id);
+
+/**
+ * Looks up client using name within the session.
+ *
+ * [in] session, pointer to the session
+ *
+ * [in] session_client_name, name of the client to lookup in the session
+ *
+ * Returns:
+ * - Pointer to the session, if found.
+ * - (NULL) on failure, client not found.
+ */
+struct tf_session_client *
+tf_session_find_session_client_by_name(struct tf_session *tfs,
+ const char *ctrl_chan_name);
+
+/**
+ * Looks up client using the fid.
+ *
+ * [in] session, pointer to the session
+ *
+ * [in] fid, fid of the client to find
+ *
+ * Returns:
+ * - Pointer to the session, if found.
+ * - (NULL) on failure, client not found.
+ */
+struct tf_session_client *
+tf_session_find_session_client_by_fid(struct tf_session *tfs,
+ uint16_t fid);
+
/**
* Looks up the device information from the TF Session.
*
struct tf_dev_info **tfd);
/**
- * Looks up the FW session id of the firmware connection for the
- * requested TF handle.
+ * Looks up the FW Session id the requested TF handle.
*
* [in] tfp
* Pointer to TF handle
int tf_session_get_fw_session_id(struct tf *tfp,
uint8_t *fw_session_id);
+/**
+ * Looks up the Session id the requested TF handle.
+ *
+ * [in] tfp
+ * Pointer to TF handle
+ *
+ * [out] session_id
+ * Pointer to the session_id
+ *
+ * Returns
+ * - (0) if successful.
+ * - (-EINVAL) on failure.
+ */
+int tf_session_get_session_id(struct tf *tfp,
+ union tf_session_id *session_id);
+
#endif /* _TF_SESSION_H_ */
tf_dir_2_str(parms->dir),
parms->type,
strerror(-rc));
+ return rc;
}
return 0;
tf_dir_2_str(parms->dir),
parms->type,
strerror(-rc));
+ return rc;
}
return 0;
}
/* Retrieve the session information */
- rc = tf_session_get_session(tfp, &tfs);
+ rc = tf_session_get_session_internal(tfp, &tfs);
if (rc)
return rc;
}
/* Retrieve the session information */
- rc = tf_session_get_session(tfp, &tfs);
+ rc = tf_session_get_session_internal(tfp, &tfs);
if (rc)
return rc;
tf_tcam_tbl_2_str(parms->type),
parms->idx,
strerror(-rc));
+ return rc;
}
return 0;
}
/* Retrieve the session information */
- rc = tf_session_get_session(tfp, &tfs);
+ rc = tf_session_get_session_internal(tfp, &tfs);
if (rc)
return rc;
tf_tcam_tbl_2_str(parms->type),
parms->idx,
strerror(-rc));
+ return rc;
}
return 0;
{
rte_spinlock_unlock(&parms->slock);
}
+
+int
+tfp_get_fid(struct tf *tfp, uint16_t *fw_fid)
+{
+ struct bnxt *bp = NULL;
+
+ if (tfp == NULL || fw_fid == NULL)
+ return -EINVAL;
+
+ bp = container_of(tfp, struct bnxt, tfp);
+ if (bp == NULL)
+ return -EINVAL;
+
+ *fw_fid = bp->fw_fid;
+
+ return 0;
+}
#define tfp_bswap_32(val) rte_bswap32(val)
#define tfp_bswap_64(val) rte_bswap64(val)
+/**
+ * Lookup of the FID in the platform specific structure.
+ *
+ * [in] session
+ * Pointer to session handle
+ *
+ * [out] fw_fid
+ * Pointer to the fw_fid
+ *
+ * Returns:
+ * 0 - Success
+ * -EINVAL - Parameter error
+ */
+int tfp_get_fid(struct tf *tfp, uint16_t *fw_fid);
+
#endif /* _TFP_H_ */