From aa2be5093363b57a6ad102bad9732b08c8c1f5ab Mon Sep 17 00:00:00 2001 From: Michael Wildt Date: Thu, 2 Jul 2020 16:28:16 -0700 Subject: [PATCH] net/bnxt: add TF register and unregister - Add TF register/unregister support. Session got session clients to keep track of the ctrl-channels/function. - Add support code to tfp layer Signed-off-by: Michael Wildt Signed-off-by: Venkat Duvvuru Reviewed-by: Randy Schacher Reviewed-by: Ajit Khaparde --- drivers/net/bnxt/meson.build | 1 + drivers/net/bnxt/tf_core/Makefile | 1 + drivers/net/bnxt/tf_core/ll.c | 52 +++ drivers/net/bnxt/tf_core/ll.h | 46 +++ drivers/net/bnxt/tf_core/tf_core.c | 26 +- drivers/net/bnxt/tf_core/tf_core.h | 105 +++-- drivers/net/bnxt/tf_core/tf_msg.c | 84 +++- drivers/net/bnxt/tf_core/tf_msg.h | 42 +- drivers/net/bnxt/tf_core/tf_rm.c | 2 +- drivers/net/bnxt/tf_core/tf_session.c | 569 ++++++++++++++++++++++++-- drivers/net/bnxt/tf_core/tf_session.h | 201 ++++++++- drivers/net/bnxt/tf_core/tf_tbl.c | 2 + drivers/net/bnxt/tf_core/tf_tcam.c | 8 +- drivers/net/bnxt/tf_core/tfp.c | 17 + drivers/net/bnxt/tf_core/tfp.h | 15 + 15 files changed, 1075 insertions(+), 96 deletions(-) create mode 100644 drivers/net/bnxt/tf_core/ll.c create mode 100644 drivers/net/bnxt/tf_core/ll.h diff --git a/drivers/net/bnxt/meson.build b/drivers/net/bnxt/meson.build index f25a9448d7..54564e02eb 100644 --- a/drivers/net/bnxt/meson.build +++ b/drivers/net/bnxt/meson.build @@ -44,6 +44,7 @@ sources = files('bnxt_cpr.c', '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', diff --git a/drivers/net/bnxt/tf_core/Makefile b/drivers/net/bnxt/tf_core/Makefile index 469dd9a1f2..2b94543b7e 100644 --- a/drivers/net/bnxt/tf_core/Makefile +++ b/drivers/net/bnxt/tf_core/Makefile @@ -8,6 +8,7 @@ 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 diff --git a/drivers/net/bnxt/tf_core/ll.c b/drivers/net/bnxt/tf_core/ll.c new file mode 100644 index 0000000000..6f58662f55 --- /dev/null +++ b/drivers/net/bnxt/tf_core/ll.c @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019-2020 Broadcom + * All rights reserved. + */ + +/* Linked List Functions */ + +#include +#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; + } +} diff --git a/drivers/net/bnxt/tf_core/ll.h b/drivers/net/bnxt/tf_core/ll.h new file mode 100644 index 0000000000..d709178503 --- /dev/null +++ b/drivers/net/bnxt/tf_core/ll.h @@ -0,0 +1,46 @@ +/* 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_ */ diff --git a/drivers/net/bnxt/tf_core/tf_core.c b/drivers/net/bnxt/tf_core/tf_core.c index a980a20569..489c461d11 100644 --- a/drivers/net/bnxt/tf_core/tf_core.c +++ b/drivers/net/bnxt/tf_core/tf_core.c @@ -58,21 +58,20 @@ tf_open_session(struct tf *tfp, 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; } @@ -152,6 +151,9 @@ tf_close_session(struct tf *tfp) 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 */ @@ -159,16 +161,10 @@ tf_close_session(struct tf *tfp) 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; } diff --git a/drivers/net/bnxt/tf_core/tf_core.h b/drivers/net/bnxt/tf_core/tf_core.h index e3d46bd450..fea222bee4 100644 --- a/drivers/net/bnxt/tf_core/tf_core.h +++ b/drivers/net/bnxt/tf_core/tf_core.h @@ -72,7 +72,6 @@ enum tf_mem { * @ref tf_close_session */ - /** * Session Version defines * @@ -113,6 +112,21 @@ union tf_session_id { } 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 * @@ -368,8 +382,8 @@ struct tf_session_info { * * 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. * @@ -506,36 +520,62 @@ struct tf_open_session_parms { * 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 * @@ -546,6 +586,11 @@ struct tf_open_session_parms { 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 @@ -595,15 +640,18 @@ struct tf_attach_session_parms { }; /** - * 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. @@ -613,9 +661,15 @@ int tf_attach_session(struct tf *tfp, 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. */ @@ -1056,9 +1110,10 @@ int tf_free_tcam_entry(struct tf *tfp, * @ref tf_set_tbl_entry * * @ref tf_get_tbl_entry + * + * @ref tf_bulk_get_tbl_entry */ - /** * tf_alloc_tbl_entry parameter definition */ diff --git a/drivers/net/bnxt/tf_core/tf_msg.c b/drivers/net/bnxt/tf_core/tf_msg.c index 6600a14c82..8c2dff8ad6 100644 --- a/drivers/net/bnxt/tf_core/tf_msg.c +++ b/drivers/net/bnxt/tf_core/tf_msg.c @@ -84,7 +84,8 @@ tf_msg_free_dma_buf(struct tf_msg_dma_buf *buf) 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 }; @@ -106,7 +107,8 @@ tf_msg_session_open(struct tf *tfp, 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; } @@ -119,6 +121,84 @@ tf_msg_session_attach(struct tf *tfp __rte_unused, 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) { diff --git a/drivers/net/bnxt/tf_core/tf_msg.h b/drivers/net/bnxt/tf_core/tf_msg.h index 37f2910162..c02a5203cb 100644 --- a/drivers/net/bnxt/tf_core/tf_msg.h +++ b/drivers/net/bnxt/tf_core/tf_msg.h @@ -34,7 +34,8 @@ struct tf; */ 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 @@ -42,6 +43,9 @@ int tf_msg_session_open(struct tf *tfp, * [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 @@ -53,6 +57,42 @@ int tf_msg_session_attach(struct tf *tfp, 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 * diff --git a/drivers/net/bnxt/tf_core/tf_rm.c b/drivers/net/bnxt/tf_core/tf_rm.c index 30313e2eac..fdb87ecb81 100644 --- a/drivers/net/bnxt/tf_core/tf_rm.c +++ b/drivers/net/bnxt/tf_core/tf_rm.c @@ -389,7 +389,7 @@ tf_rm_create_db(struct tf *tfp, 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; diff --git a/drivers/net/bnxt/tf_core/tf_session.c b/drivers/net/bnxt/tf_core/tf_session.c index 9ff81b047f..6ab8088f0f 100644 --- a/drivers/net/bnxt/tf_core/tf_session.c +++ b/drivers/net/bnxt/tf_core/tf_session.c @@ -12,14 +12,49 @@ #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); @@ -27,7 +62,8 @@ tf_session_open_session(struct tf *tfp, /* 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) @@ -92,15 +128,46 @@ tf_session_open_session(struct tf *tfp, 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, @@ -110,7 +177,7 @@ tf_session_open_session(struct tf *tfp, if (rc) return rc; - session->ref_count++; + session->dev_init = true; return 0; @@ -121,6 +188,235 @@ tf_session_open_session(struct tf *tfp, 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) @@ -141,7 +437,10 @@ tf_session_close_session(struct tf *tfp, { 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); @@ -161,7 +460,49 @@ tf_session_close_session(struct tf *tfp, 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. @@ -176,23 +517,6 @@ tf_session_close_session(struct tf *tfp, 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) { @@ -202,7 +526,6 @@ tf_session_close_session(struct tf *tfp, strerror(-rc)); } - /* In case we're attached only the session client gets closed */ rc = tf_msg_session_close(tfp); if (rc) { /* Log error */ @@ -211,6 +534,21 @@ tf_session_close_session(struct tf *tfp, 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; @@ -218,12 +556,31 @@ tf_session_close_session(struct tf *tfp, 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, @@ -234,7 +591,113 @@ tf_session_get_session(struct tf *tfp, *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 @@ -253,6 +716,7 @@ tf_session_get_fw_session_id(struct tf *tfp, 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, @@ -261,7 +725,15 @@ tf_session_get_fw_session_id(struct tf *tfp, 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; @@ -269,3 +741,36 @@ tf_session_get_fw_session_id(struct tf *tfp, 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; +} diff --git a/drivers/net/bnxt/tf_core/tf_session.h b/drivers/net/bnxt/tf_core/tf_session.h index a303fde515..aa7a27877d 100644 --- a/drivers/net/bnxt/tf_core/tf_session.h +++ b/drivers/net/bnxt/tf_core/tf_session.h @@ -16,6 +16,7 @@ #include "tf_tbl.h" #include "tf_resources.h" #include "stack.h" +#include "ll.h" /** * The Session module provides session control support. A session is @@ -29,7 +30,6 @@ /** Session defines */ -#define TF_SESSIONS_MAX 1 /** max # sessions */ #define TF_SESSION_ID_INVALID 0xFFFFFFFF /** Invalid Session ID define */ /** @@ -50,7 +50,7 @@ * 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. @@ -65,17 +65,10 @@ struct tf_session { */ 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 @@ -92,14 +85,67 @@ struct tf_session { /** * 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; }; /** @@ -126,7 +172,13 @@ struct tf_session_attach_session_parms { * Session close parameter definition */ struct tf_session_close_session_parms { + /** + * [] + */ uint8_t *ref_count; + /** + * [] + */ union tf_session_id *session_id; }; @@ -139,11 +191,23 @@ struct tf_session_close_session_parms { * * @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 */ /** @@ -179,7 +243,8 @@ int tf_session_attach_session(struct tf *tfp, 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 @@ -189,13 +254,53 @@ int tf_session_attach_session(struct tf *tfp, * * 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 @@ -210,6 +315,53 @@ int tf_session_close_session(struct tf *tfp, 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. * @@ -227,8 +379,7 @@ int tf_session_get_device(struct tf_session *tfs, 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 @@ -243,4 +394,20 @@ int tf_session_get_device(struct tf_session *tfs, 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_ */ diff --git a/drivers/net/bnxt/tf_core/tf_tbl.c b/drivers/net/bnxt/tf_core/tf_tbl.c index 7d4daaf2de..2b4a7c5613 100644 --- a/drivers/net/bnxt/tf_core/tf_tbl.c +++ b/drivers/net/bnxt/tf_core/tf_tbl.c @@ -269,6 +269,7 @@ tf_tbl_set(struct tf *tfp, tf_dir_2_str(parms->dir), parms->type, strerror(-rc)); + return rc; } return 0; @@ -338,6 +339,7 @@ tf_tbl_get(struct tf *tfp, tf_dir_2_str(parms->dir), parms->type, strerror(-rc)); + return rc; } return 0; diff --git a/drivers/net/bnxt/tf_core/tf_tcam.c b/drivers/net/bnxt/tf_core/tf_tcam.c index 1c48b5363f..cbfaa94ee3 100644 --- a/drivers/net/bnxt/tf_core/tf_tcam.c +++ b/drivers/net/bnxt/tf_core/tf_tcam.c @@ -138,7 +138,7 @@ tf_tcam_alloc(struct tf *tfp, } /* Retrieve the session information */ - rc = tf_session_get_session(tfp, &tfs); + rc = tf_session_get_session_internal(tfp, &tfs); if (rc) return rc; @@ -218,7 +218,7 @@ tf_tcam_free(struct tf *tfp, } /* Retrieve the session information */ - rc = tf_session_get_session(tfp, &tfs); + rc = tf_session_get_session_internal(tfp, &tfs); if (rc) return rc; @@ -319,6 +319,7 @@ tf_tcam_free(struct tf *tfp, tf_tcam_tbl_2_str(parms->type), parms->idx, strerror(-rc)); + return rc; } return 0; @@ -353,7 +354,7 @@ tf_tcam_set(struct tf *tfp __rte_unused, } /* Retrieve the session information */ - rc = tf_session_get_session(tfp, &tfs); + rc = tf_session_get_session_internal(tfp, &tfs); if (rc) return rc; @@ -415,6 +416,7 @@ tf_tcam_set(struct tf *tfp __rte_unused, tf_tcam_tbl_2_str(parms->type), parms->idx, strerror(-rc)); + return rc; } return 0; diff --git a/drivers/net/bnxt/tf_core/tfp.c b/drivers/net/bnxt/tf_core/tfp.c index 69d1c9a1f9..426a182a90 100644 --- a/drivers/net/bnxt/tf_core/tfp.c +++ b/drivers/net/bnxt/tf_core/tfp.c @@ -161,3 +161,20 @@ tfp_spinlock_unlock(struct tfp_spinlock_parms *parms) { 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; +} diff --git a/drivers/net/bnxt/tf_core/tfp.h b/drivers/net/bnxt/tf_core/tfp.h index fe49b63042..8789eba1f3 100644 --- a/drivers/net/bnxt/tf_core/tfp.h +++ b/drivers/net/bnxt/tf_core/tfp.h @@ -238,4 +238,19 @@ int tfp_get_fid(struct tf *tfp, uint16_t *fw_fid); #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_ */ -- 2.20.1