get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/71421/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 71421,
    "url": "http://patches.dpdk.org/api/patches/71421/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20200612132934.16488-30-somnath.kotur@broadcom.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20200612132934.16488-30-somnath.kotur@broadcom.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200612132934.16488-30-somnath.kotur@broadcom.com",
    "date": "2020-06-12T13:29:13",
    "name": "[29/50] net/bnxt: add TF register and unregister",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "aa381f24a6eb3aef2952a5bea2d179e01498f6be",
    "submitter": {
        "id": 908,
        "url": "http://patches.dpdk.org/api/people/908/?format=api",
        "name": "Somnath Kotur",
        "email": "somnath.kotur@broadcom.com"
    },
    "delegate": {
        "id": 1766,
        "url": "http://patches.dpdk.org/api/users/1766/?format=api",
        "username": "ajitkhaparde",
        "first_name": "Ajit",
        "last_name": "Khaparde",
        "email": "ajit.khaparde@broadcom.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20200612132934.16488-30-somnath.kotur@broadcom.com/mbox/",
    "series": [
        {
            "id": 10436,
            "url": "http://patches.dpdk.org/api/series/10436/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=10436",
            "date": "2020-06-12T13:28:44",
            "name": "add features for host-based flow management",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/10436/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/71421/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/71421/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 29A0CA00BE;\n\tFri, 12 Jun 2020 15:47:11 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 3CCDB1C1C3;\n\tFri, 12 Jun 2020 15:34:48 +0200 (CEST)",
            "from relay.smtp.broadcom.com (unknown [192.19.232.149])\n by dpdk.org (Postfix) with ESMTP id DB6CE1C191\n for <dev@dpdk.org>; Fri, 12 Jun 2020 15:34:43 +0200 (CEST)",
            "from dhcp-10-123-153-55.dhcp.broadcom.net\n (dhcp-10-123-153-55.dhcp.broadcom.net [10.123.153.55])\n by relay.smtp.broadcom.com (Postfix) with ESMTP id B3B341BD7A4;\n Fri, 12 Jun 2020 06:34:42 -0700 (PDT)"
        ],
        "DKIM-Filter": "OpenDKIM Filter v2.10.3 relay.smtp.broadcom.com B3B341BD7A4",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=broadcom.com;\n s=dkimrelay; t=1591968883;\n bh=D7/r+97PvLafheQ06wWEsKzRwaKjlJyrwK0113Hio9U=;\n h=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n b=L8U+9Ic+vC2zgqvrZJBIEMbvrROORec+7KGf61UxGfKIkAsCo9ElJ0ng4eo5OqTh9\n GNhiNBwDUmxWUe6HbYexgoTouwtteBuveGX9JVimf1480p1y5EhhC6P3UB0dpNBixO\n Y9lR3mfhTncx7srqthhtc5SMHDs+ehyvUAHcrX9Q=",
        "From": "Somnath Kotur <somnath.kotur@broadcom.com>",
        "To": "dev@dpdk.org",
        "Cc": "ferruh.yigit@intel.com",
        "Date": "Fri, 12 Jun 2020 18:59:13 +0530",
        "Message-Id": "<20200612132934.16488-30-somnath.kotur@broadcom.com>",
        "X-Mailer": "git-send-email 2.10.1.613.g2cc2e70",
        "In-Reply-To": "<20200612132934.16488-1-somnath.kotur@broadcom.com>",
        "References": "<20200612132934.16488-1-somnath.kotur@broadcom.com>",
        "Subject": "[dpdk-dev] [PATCH 29/50] net/bnxt: add TF register and unregister",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Michael Wildt <michael.wildt@broadcom.com>\n\n- Add TF register/unregister support. Session got session clients to\n  keep track of the ctrl-channels/function.\n- Add support code to tfp layer\n\nSigned-off-by: Michael Wildt <michael.wildt@broadcom.com>\nReviewed-by: Randy Schacher <stuart.schacher@broadcom.com>\nReviewed-by: Ajit Kumar Khaparde <ajit.khaparde@broadcom.com>\nSigned-off-by: Venkat Duvvuru <venkatkumar.duvvuru@broadcom.com>\n---\n drivers/net/bnxt/meson.build          |   1 +\n drivers/net/bnxt/tf_core/Makefile     |   1 +\n drivers/net/bnxt/tf_core/ll.c         |  52 ++++\n drivers/net/bnxt/tf_core/ll.h         |  46 +++\n drivers/net/bnxt/tf_core/tf_core.c    |  26 +-\n drivers/net/bnxt/tf_core/tf_core.h    | 105 +++++--\n drivers/net/bnxt/tf_core/tf_msg.c     |  84 ++++-\n drivers/net/bnxt/tf_core/tf_msg.h     |  42 ++-\n drivers/net/bnxt/tf_core/tf_rm.c      |   2 +-\n drivers/net/bnxt/tf_core/tf_session.c | 569 ++++++++++++++++++++++++++++++++--\n drivers/net/bnxt/tf_core/tf_session.h | 201 +++++++++++-\n drivers/net/bnxt/tf_core/tf_tbl.c     |   2 +\n drivers/net/bnxt/tf_core/tf_tcam.c    |   8 +-\n drivers/net/bnxt/tf_core/tfp.c        |  17 +\n drivers/net/bnxt/tf_core/tfp.h        |  15 +\n 15 files changed, 1075 insertions(+), 96 deletions(-)\n create mode 100644 drivers/net/bnxt/tf_core/ll.c\n create mode 100644 drivers/net/bnxt/tf_core/ll.h",
    "diff": "diff --git a/drivers/net/bnxt/meson.build b/drivers/net/bnxt/meson.build\nindex f25a944..54564e0 100644\n--- a/drivers/net/bnxt/meson.build\n+++ b/drivers/net/bnxt/meson.build\n@@ -44,6 +44,7 @@ sources = files('bnxt_cpr.c',\n \t'tf_core/tf_tcam.c',\n \t'tf_core/tf_util.c',\n \t'tf_core/tf_if_tbl.c',\n+\t'tf_core/ll.c',\n \n \t'hcapi/hcapi_cfa_p4.c',\n \ndiff --git a/drivers/net/bnxt/tf_core/Makefile b/drivers/net/bnxt/tf_core/Makefile\nindex b923237..e1c65ca 100644\n--- a/drivers/net/bnxt/tf_core/Makefile\n+++ b/drivers/net/bnxt/tf_core/Makefile\n@@ -8,6 +8,7 @@\n SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/bitalloc.c\n SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/rand.c\n SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/stack.c\n+SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/ll.c\n SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/tf_core.c\n SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/tf_rm.c\n SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/tfp.c\ndiff --git a/drivers/net/bnxt/tf_core/ll.c b/drivers/net/bnxt/tf_core/ll.c\nnew file mode 100644\nindex 0000000..6f58662\n--- /dev/null\n+++ b/drivers/net/bnxt/tf_core/ll.c\n@@ -0,0 +1,52 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2019-2020 Broadcom\n+ * All rights reserved.\n+ */\n+\n+/* Linked List Functions */\n+\n+#include <stdio.h>\n+#include \"ll.h\"\n+\n+/* init linked list */\n+void ll_init(struct ll *ll)\n+{\n+\tll->head = NULL;\n+\tll->tail = NULL;\n+}\n+\n+/* insert entry in linked list */\n+void ll_insert(struct ll *ll,\n+\t       struct ll_entry *entry)\n+{\n+\tif (ll->head == NULL) {\n+\t\tll->head = entry;\n+\t\tll->tail = entry;\n+\t\tentry->next = NULL;\n+\t\tentry->prev = NULL;\n+\t} else {\n+\t\tentry->next = ll->head;\n+\t\tentry->prev = NULL;\n+\t\tentry->next->prev = entry;\n+\t\tll->head = entry->next->prev;\n+\t}\n+}\n+\n+/* delete entry from linked list */\n+void ll_delete(struct ll *ll,\n+\t       struct ll_entry *entry)\n+{\n+\tif (ll->head == entry && ll->tail == entry) {\n+\t\tll->head = NULL;\n+\t\tll->tail = NULL;\n+\t} else if (ll->head == entry) {\n+\t\tll->head = entry->next;\n+\t\tll->head->prev = NULL;\n+\t} else if (ll->tail == entry) {\n+\t\tll->tail = entry->prev;\n+\t\tll->tail->next = NULL;\n+\t} else {\n+\t\tentry->prev->next = entry->next;\n+\t\tentry->next->prev = entry->prev;\n+\t}\n+}\ndiff --git a/drivers/net/bnxt/tf_core/ll.h b/drivers/net/bnxt/tf_core/ll.h\nnew file mode 100644\nindex 0000000..d709178\n--- /dev/null\n+++ b/drivers/net/bnxt/tf_core/ll.h\n@@ -0,0 +1,46 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2019-2020 Broadcom\n+ * All rights reserved.\n+ */\n+\n+/* Linked List Header File */\n+\n+#ifndef _LL_H_\n+#define _LL_H_\n+\n+/* linked list entry */\n+struct ll_entry {\n+\tstruct ll_entry *prev;\n+\tstruct ll_entry *next;\n+};\n+\n+/* linked list */\n+struct ll {\n+\tstruct ll_entry *head;\n+\tstruct ll_entry *tail;\n+};\n+\n+/**\n+ * Linked list initialization.\n+ *\n+ * [in] ll, linked list to be initialized\n+ */\n+void ll_init(struct ll *ll);\n+\n+/**\n+ * Linked list insert\n+ *\n+ * [in] ll, linked list where element is inserted\n+ * [in] entry, entry to be added\n+ */\n+void ll_insert(struct ll *ll, struct ll_entry *entry);\n+\n+/**\n+ * Linked list delete\n+ *\n+ * [in] ll, linked list where element is removed\n+ * [in] entry, entry to be deleted\n+ */\n+void ll_delete(struct ll *ll, struct ll_entry *entry);\n+\n+#endif /* _LL_H_ */\ndiff --git a/drivers/net/bnxt/tf_core/tf_core.c b/drivers/net/bnxt/tf_core/tf_core.c\nindex a980a20..489c461 100644\n--- a/drivers/net/bnxt/tf_core/tf_core.c\n+++ b/drivers/net/bnxt/tf_core/tf_core.c\n@@ -58,21 +58,20 @@ tf_open_session(struct tf *tfp,\n \tparms->session_id.internal.device = device;\n \toparms.open_cfg = parms;\n \n+\t/* Session vs session client is decided in\n+\t * tf_session_open_session()\n+\t */\n+\tprintf(\"TF_OPEN, %s\\n\", parms->ctrl_chan_name);\n \trc = tf_session_open_session(tfp, &oparms);\n \t/* Logging handled by tf_session_open_session */\n \tif (rc)\n \t\treturn rc;\n \n \tTFP_DRV_LOG(INFO,\n-\t\t    \"Session created, session_id:%d\\n\",\n-\t\t    parms->session_id.id);\n-\n-\tTFP_DRV_LOG(INFO,\n-\t\t    \"domain:%d, bus:%d, device:%d, fw_session_id:%d\\n\",\n+\t\t    \"domain:%d, bus:%d, device:%d\\n\",\n \t\t    parms->session_id.internal.domain,\n \t\t    parms->session_id.internal.bus,\n-\t\t    parms->session_id.internal.device,\n-\t\t    parms->session_id.internal.fw_session_id);\n+\t\t    parms->session_id.internal.device);\n \n \treturn 0;\n }\n@@ -152,6 +151,9 @@ tf_close_session(struct tf *tfp)\n \n \tcparms.ref_count = &ref_count;\n \tcparms.session_id = &session_id;\n+\t/* Session vs session client is decided in\n+\t * tf_session_close_session()\n+\t */\n \trc = tf_session_close_session(tfp,\n \t\t\t\t      &cparms);\n \t/* Logging handled by tf_session_close_session */\n@@ -159,16 +161,10 @@ tf_close_session(struct tf *tfp)\n \t\treturn rc;\n \n \tTFP_DRV_LOG(INFO,\n-\t\t    \"Closed session, session_id:%d, ref_count:%d\\n\",\n-\t\t    cparms.session_id->id,\n-\t\t    *cparms.ref_count);\n-\n-\tTFP_DRV_LOG(INFO,\n-\t\t    \"domain:%d, bus:%d, device:%d, fw_session_id:%d\\n\",\n+\t\t    \"domain:%d, bus:%d, device:%d\\n\",\n \t\t    cparms.session_id->internal.domain,\n \t\t    cparms.session_id->internal.bus,\n-\t\t    cparms.session_id->internal.device,\n-\t\t    cparms.session_id->internal.fw_session_id);\n+\t\t    cparms.session_id->internal.device);\n \n \treturn rc;\n }\ndiff --git a/drivers/net/bnxt/tf_core/tf_core.h b/drivers/net/bnxt/tf_core/tf_core.h\nindex e3d46bd..fea222b 100644\n--- a/drivers/net/bnxt/tf_core/tf_core.h\n+++ b/drivers/net/bnxt/tf_core/tf_core.h\n@@ -72,7 +72,6 @@ enum tf_mem {\n  * @ref tf_close_session\n  */\n \n-\n /**\n  * Session Version defines\n  *\n@@ -114,6 +113,21 @@ union tf_session_id {\n };\n \n /**\n+ * Session Client Identifier\n+ *\n+ * Unique identifier for a client within a session. Session Client ID\n+ * is constructed from the passed in session and a firmware allocated\n+ * fw_session_client_id. Done by TruFlow on tf_open_session().\n+ */\n+union tf_session_client_id {\n+\tuint16_t id;\n+\tstruct {\n+\t\tuint8_t fw_session_id;\n+\t\tuint8_t fw_session_client_id;\n+\t} internal;\n+};\n+\n+/**\n  * Session Version\n  *\n  * The version controls the format of the tf_session and\n@@ -368,8 +382,8 @@ struct tf_session_info {\n  *\n  * Contains a pointer to the session info. Allocated by ULP and passed\n  * to TruFlow using tf_open_session(). TruFlow will populate the\n- * session info at that time. Additional 'opens' can be done using\n- * same session_info by using tf_attach_session().\n+ * session info at that time. A TruFlow Session can be used by more\n+ * than one PF/VF by using the tf_open_session().\n  *\n  * It is expected that ULP allocates this memory as shared memory.\n  *\n@@ -507,35 +521,61 @@ struct tf_open_session_parms {\n \t */\n \tunion tf_session_id session_id;\n \t/**\n+\t * [in/out] session_client_id\n+\t *\n+\t * Session_client_id is unique per client.\n+\t *\n+\t * Session_client_id is composed of session_id and the\n+\t * fw_session_client_id fw_session_id. The construction is\n+\t * done by parsing the ctrl_chan_name together with allocation\n+\t * of a fw_session_client_id during tf_open_session().\n+\t *\n+\t * A reference count will be incremented in the session on\n+\t * which a client is created.\n+\t *\n+\t * A session can first be closed if there is one Session\n+\t * Client left. Session Clients should closed using\n+\t * tf_close_session().\n+\t */\n+\tunion tf_session_client_id session_client_id;\n+\t/**\n \t * [in] device type\n \t *\n-\t * Device type is passed, one of Wh+, SR, Thor, SR2\n+\t * Device type for the session.\n \t */\n \tenum tf_device_type device_type;\n-\t/** [in] resources\n+\t/**\n+\t * [in] resources\n \t *\n-\t * Resource allocation\n+\t * Resource allocation for the session.\n \t */\n \tstruct tf_session_resources resources;\n };\n \n /**\n- * Opens a new TruFlow management session.\n+ * Opens a new TruFlow Session or session client.\n+ *\n+ * What gets created depends on the passed in tfp content. If the tfp\n+ * does not have prior session data a new session with associated\n+ * session client. If tfp has a session already a session client will\n+ * be created. In both cases the session client is created using the\n+ * provided ctrl_chan_name.\n  *\n- * TruFlow will allocate session specific memory, shared memory, to\n- * hold its session data. This data is private to TruFlow.\n+ * In case of session creation TruFlow will allocate session specific\n+ * memory, shared memory, to hold its session data. This data is\n+ * private to TruFlow.\n  *\n- * Multiple PFs can share the same session. An association, refcount,\n- * between session and PFs is maintained within TruFlow. Thus, a PF\n- * can attach to an existing session, see tf_attach_session().\n+ * No other TruFlow APIs will succeed unless this API is first called\n+ * and succeeds.\n  *\n- * No other TruFlow APIs will succeed unless this API is first called and\n- * succeeds.\n+ * tf_open_session() returns a session id and session client id that\n+ * is used on all other TF APIs.\n  *\n- * tf_open_session() returns a session id that can be used on attach.\n+ * A Session or session client can be closed using tf_close_session().\n  *\n  * [in] tfp\n  *   Pointer to TF handle\n+ *\n  * [in] parms\n  *   Pointer to open parameters\n  *\n@@ -546,6 +586,11 @@ struct tf_open_session_parms {\n int tf_open_session(struct tf *tfp,\n \t\t    struct tf_open_session_parms *parms);\n \n+/**\n+ * Experimental\n+ *\n+ * tf_attach_session parameters definition.\n+ */\n struct tf_attach_session_parms {\n \t/**\n \t * [in] ctrl_chan_name\n@@ -595,15 +640,18 @@ struct tf_attach_session_parms {\n };\n \n /**\n- * Attaches to an existing session. Used when more than one PF wants\n- * to share a single session. In that case all TruFlow management\n- * traffic will be sent to the TruFlow firmware using the 'PF' that\n- * did the attach not the session ctrl channel.\n+ * Experimental\n+ *\n+ * Allows a 2nd application instance to attach to an existing\n+ * session. Used when a session is to be shared between two processes.\n  *\n  * Attach will increment a ref count as to manage the shared session data.\n  *\n- * [in] tfp, pointer to TF handle\n- * [in] parms, pointer to attach parameters\n+ * [in] tfp\n+ *   Pointer to TF handle\n+ *\n+ * [in] parms\n+ *   Pointer to attach parameters\n  *\n  * Returns\n  *   - (0) if successful.\n@@ -613,9 +661,15 @@ int tf_attach_session(struct tf *tfp,\n \t\t      struct tf_attach_session_parms *parms);\n \n /**\n- * Closes an existing session. Cleans up all hardware and firmware\n- * state associated with the TruFlow application session when the last\n- * PF associated with the session results in refcount to be zero.\n+ * Closes an existing session client or the session it self. The\n+ * session client is default closed and if the session reference count\n+ * is 0 then the session is closed as well.\n+ *\n+ * On session close all hardware and firmware state associated with\n+ * the TruFlow application is cleaned up.\n+ *\n+ * The session client is extracted from the tfp. Thus tf_close_session()\n+ * cannot close a session client on behalf of another function.\n  *\n  * Returns success or failure code.\n  */\n@@ -1056,9 +1110,10 @@ int tf_free_tcam_entry(struct tf *tfp,\n  * @ref tf_set_tbl_entry\n  *\n  * @ref tf_get_tbl_entry\n+ *\n+ * @ref tf_bulk_get_tbl_entry\n  */\n \n-\n /**\n  * tf_alloc_tbl_entry parameter definition\n  */\ndiff --git a/drivers/net/bnxt/tf_core/tf_msg.c b/drivers/net/bnxt/tf_core/tf_msg.c\nindex 6600a14..8c2dff8 100644\n--- a/drivers/net/bnxt/tf_core/tf_msg.c\n+++ b/drivers/net/bnxt/tf_core/tf_msg.c\n@@ -84,7 +84,8 @@ tf_msg_free_dma_buf(struct tf_msg_dma_buf *buf)\n int\n tf_msg_session_open(struct tf *tfp,\n \t\t    char *ctrl_chan_name,\n-\t\t    uint8_t *fw_session_id)\n+\t\t    uint8_t *fw_session_id,\n+\t\t    uint8_t *fw_session_client_id)\n {\n \tint rc;\n \tstruct hwrm_tf_session_open_input req = { 0 };\n@@ -106,7 +107,8 @@ tf_msg_session_open(struct tf *tfp,\n \tif (rc)\n \t\treturn rc;\n \n-\t*fw_session_id = resp.fw_session_id;\n+\t*fw_session_id = (uint8_t)tfp_le_to_cpu_32(resp.fw_session_id);\n+\t*fw_session_client_id = (uint8_t)tfp_le_to_cpu_32(resp.fw_session_id);\n \n \treturn rc;\n }\n@@ -120,6 +122,84 @@ tf_msg_session_attach(struct tf *tfp __rte_unused,\n }\n \n int\n+tf_msg_session_client_register(struct tf *tfp,\n+\t\t\t       char *ctrl_channel_name,\n+\t\t\t       uint8_t *fw_session_client_id)\n+{\n+\tint rc;\n+\tstruct hwrm_tf_session_register_input req = { 0 };\n+\tstruct hwrm_tf_session_register_output resp = { 0 };\n+\tstruct tfp_send_msg_parms parms = { 0 };\n+\tuint8_t fw_session_id;\n+\n+\trc = tf_session_get_fw_session_id(tfp, &fw_session_id);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Unable to lookup FW id, rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\t/* Populate the request */\n+\treq.fw_session_id = tfp_cpu_to_le_32(fw_session_id);\n+\ttfp_memcpy(&req.session_client_name,\n+\t\t   ctrl_channel_name,\n+\t\t   TF_SESSION_NAME_MAX);\n+\n+\tparms.tf_type = HWRM_TF_SESSION_REGISTER;\n+\tparms.req_data = (uint32_t *)&req;\n+\tparms.req_size = sizeof(req);\n+\tparms.resp_data = (uint32_t *)&resp;\n+\tparms.resp_size = sizeof(resp);\n+\tparms.mailbox = TF_KONG_MB;\n+\n+\trc = tfp_send_msg_direct(tfp,\n+\t\t\t\t &parms);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\t*fw_session_client_id =\n+\t\t(uint8_t)tfp_le_to_cpu_32(resp.fw_session_client_id);\n+\n+\treturn rc;\n+}\n+\n+int\n+tf_msg_session_client_unregister(struct tf *tfp,\n+\t\t\t\t uint8_t fw_session_client_id)\n+{\n+\tint rc;\n+\tstruct hwrm_tf_session_unregister_input req = { 0 };\n+\tstruct hwrm_tf_session_unregister_output resp = { 0 };\n+\tstruct tfp_send_msg_parms parms = { 0 };\n+\tuint8_t fw_session_id;\n+\n+\trc = tf_session_get_fw_session_id(tfp, &fw_session_id);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Unable to lookup FW id, rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\t/* Populate the request */\n+\treq.fw_session_id = tfp_cpu_to_le_32(fw_session_id);\n+\treq.fw_session_client_id = tfp_cpu_to_le_32(fw_session_client_id);\n+\n+\tparms.tf_type = HWRM_TF_SESSION_UNREGISTER;\n+\tparms.req_data = (uint32_t *)&req;\n+\tparms.req_size = sizeof(req);\n+\tparms.resp_data = (uint32_t *)&resp;\n+\tparms.resp_size = sizeof(resp);\n+\tparms.mailbox = TF_KONG_MB;\n+\n+\trc = tfp_send_msg_direct(tfp,\n+\t\t\t\t &parms);\n+\n+\treturn rc;\n+}\n+\n+int\n tf_msg_session_close(struct tf *tfp)\n {\n \tint rc;\ndiff --git a/drivers/net/bnxt/tf_core/tf_msg.h b/drivers/net/bnxt/tf_core/tf_msg.h\nindex 37f2910..c02a520 100644\n--- a/drivers/net/bnxt/tf_core/tf_msg.h\n+++ b/drivers/net/bnxt/tf_core/tf_msg.h\n@@ -34,7 +34,8 @@ struct tf;\n  */\n int tf_msg_session_open(struct tf *tfp,\n \t\t\tchar *ctrl_chan_name,\n-\t\t\tuint8_t *fw_session_id);\n+\t\t\tuint8_t *fw_session_id,\n+\t\t\tuint8_t *fw_session_client_id);\n \n /**\n  * Sends session close request to Firmware\n@@ -42,6 +43,9 @@ int tf_msg_session_open(struct tf *tfp,\n  * [in] session\n  *   Pointer to session handle\n  *\n+ * [in] ctrl_chan_name\n+ *   PCI name of the control channel\n+ *\n  * [in] fw_session_id\n  *   Pointer to the fw_session_id that is assigned to the session at\n  *   time of session open\n@@ -54,6 +58,42 @@ int tf_msg_session_attach(struct tf *tfp,\n \t\t\t  uint8_t tf_fw_session_id);\n \n /**\n+ * Sends session client register request to Firmware\n+ *\n+ * [in] session\n+ *   Pointer to session handle\n+ *\n+ * [in] ctrl_chan_name\n+ *   PCI name of the control channel\n+ *\n+ * [in/out] fw_session_client_id\n+ *   Pointer to the fw_session_client_id that is allocated on firmware\n+ *   side\n+ *\n+ * Returns:\n+ *   0 on Success else internal Truflow error\n+ */\n+int tf_msg_session_client_register(struct tf *tfp,\n+\t\t\t\t   char *ctrl_channel_name,\n+\t\t\t\t   uint8_t *fw_session_client_id);\n+\n+/**\n+ * Sends session client unregister request to Firmware\n+ *\n+ * [in] session\n+ *   Pointer to session handle\n+ *\n+ * [in/out] fw_session_client_id\n+ *   Pointer to the fw_session_client_id that is allocated on firmware\n+ *   side\n+ *\n+ * Returns:\n+ *   0 on Success else internal Truflow error\n+ */\n+int tf_msg_session_client_unregister(struct tf *tfp,\n+\t\t\t\t     uint8_t fw_session_client_id);\n+\n+/**\n  * Sends session close request to Firmware\n  *\n  * [in] session\ndiff --git a/drivers/net/bnxt/tf_core/tf_rm.c b/drivers/net/bnxt/tf_core/tf_rm.c\nindex 30313e2..fdb87ec 100644\n--- a/drivers/net/bnxt/tf_core/tf_rm.c\n+++ b/drivers/net/bnxt/tf_core/tf_rm.c\n@@ -389,7 +389,7 @@ tf_rm_create_db(struct tf *tfp,\n \tTF_CHECK_PARMS2(tfp, parms);\n \n \t/* Retrieve the session information */\n-\trc = tf_session_get_session(tfp, &tfs);\n+\trc = tf_session_get_session_internal(tfp, &tfs);\n \tif (rc)\n \t\treturn rc;\n \ndiff --git a/drivers/net/bnxt/tf_core/tf_session.c b/drivers/net/bnxt/tf_core/tf_session.c\nindex 6c07e47..7ebffc3 100644\n--- a/drivers/net/bnxt/tf_core/tf_session.c\n+++ b/drivers/net/bnxt/tf_core/tf_session.c\n@@ -12,14 +12,49 @@\n #include \"tf_msg.h\"\n #include \"tfp.h\"\n \n-int\n-tf_session_open_session(struct tf *tfp,\n-\t\t\tstruct tf_session_open_session_parms *parms)\n+struct tf_session_client_create_parms {\n+\t/**\n+\t * [in] Pointer to the control channel name string\n+\t */\n+\tchar *ctrl_chan_name;\n+\n+\t/**\n+\t * [out] Firmware Session Client ID\n+\t */\n+\tunion tf_session_client_id *session_client_id;\n+};\n+\n+struct tf_session_client_destroy_parms {\n+\t/**\n+\t * FW Session Client Identifier\n+\t */\n+\tunion tf_session_client_id session_client_id;\n+};\n+\n+/**\n+ * Creates a Session and the associated client.\n+ *\n+ * [in] tfp\n+ *   Pointer to TF handle\n+ *\n+ * [in] parms\n+ *   Pointer to session client create parameters\n+ *\n+ * Returns\n+ *   - (0) if successful.\n+ *   - (-EINVAL) on failure.\n+ *   - (-ENOMEM) if max session clients has been reached.\n+ */\n+static int\n+tf_session_create(struct tf *tfp,\n+\t\t  struct tf_session_open_session_parms *parms)\n {\n \tint rc;\n \tstruct tf_session *session;\n+\tstruct tf_session_client *client;\n \tstruct tfp_calloc_parms cparms;\n \tuint8_t fw_session_id;\n+\tuint8_t fw_session_client_id;\n \tunion tf_session_id *session_id;\n \n \tTF_CHECK_PARMS2(tfp, parms);\n@@ -27,7 +62,8 @@ tf_session_open_session(struct tf *tfp,\n \t/* Open FW session and get a new session_id */\n \trc = tf_msg_session_open(tfp,\n \t\t\t\t parms->open_cfg->ctrl_chan_name,\n-\t\t\t\t &fw_session_id);\n+\t\t\t\t &fw_session_id,\n+\t\t\t\t &fw_session_client_id);\n \tif (rc) {\n \t\t/* Log error */\n \t\tif (rc == -EEXIST)\n@@ -92,15 +128,46 @@ tf_session_open_session(struct tf *tfp,\n \tsession->session_id.internal.bus = session_id->internal.bus;\n \tsession->session_id.internal.device = session_id->internal.device;\n \tsession->session_id.internal.fw_session_id = fw_session_id;\n-\t/* Return the allocated fw session id */\n-\tsession_id->internal.fw_session_id = fw_session_id;\n+\t/* Return the allocated session id */\n+\tsession_id->id = session->session_id.id;\n \n \tsession->shadow_copy = parms->open_cfg->shadow_copy;\n \n-\ttfp_memcpy(session->ctrl_chan_name,\n+\t/* Init session client list */\n+\tll_init(&session->client_ll);\n+\n+\t/* Create the local session client, initialize and attach to\n+\t * the session\n+\t */\n+\tcparms.nitems = 1;\n+\tcparms.size = sizeof(struct tf_session_client);\n+\tcparms.alignment = 0;\n+\trc = tfp_calloc(&cparms);\n+\tif (rc) {\n+\t\t/* Log error */\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Failed to allocate session client, rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t\tgoto cleanup;\n+\t}\n+\tclient = cparms.mem_va;\n+\n+\t/* Register FID with the client */\n+\trc = tfp_get_fid(tfp, &client->fw_fid);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\tclient->session_client_id.internal.fw_session_id = fw_session_id;\n+\tclient->session_client_id.internal.fw_session_client_id =\n+\t\tfw_session_client_id;\n+\n+\ttfp_memcpy(client->ctrl_chan_name,\n \t\t   parms->open_cfg->ctrl_chan_name,\n \t\t   TF_SESSION_NAME_MAX);\n \n+\tll_insert(&session->client_ll, &client->ll_entry);\n+\tsession->ref_count++;\n+\n \trc = tf_dev_bind(tfp,\n \t\t\t parms->open_cfg->device_type,\n \t\t\t session->shadow_copy,\n@@ -110,7 +177,7 @@ tf_session_open_session(struct tf *tfp,\n \tif (rc)\n \t\treturn rc;\n \n-\tsession->ref_count++;\n+\tsession->dev_init = true;\n \n \treturn 0;\n \n@@ -121,6 +188,235 @@ tf_session_open_session(struct tf *tfp,\n \treturn rc;\n }\n \n+/**\n+ * Creates a Session Client on an existing Session.\n+ *\n+ * [in] tfp\n+ *   Pointer to TF handle\n+ *\n+ * [in] parms\n+ *   Pointer to session client create parameters\n+ *\n+ * Returns\n+ *   - (0) if successful.\n+ *   - (-EINVAL) on failure.\n+ *   - (-ENOMEM) if max session clients has been reached.\n+ */\n+static int\n+tf_session_client_create(struct tf *tfp,\n+\t\t\t struct tf_session_client_create_parms *parms)\n+{\n+\tint rc;\n+\tstruct tf_session *session;\n+\tstruct tf_session_client *client;\n+\tstruct tfp_calloc_parms cparms;\n+\tunion tf_session_client_id session_client_id;\n+\n+\tTF_CHECK_PARMS2(tfp, parms);\n+\n+\t/* Using internal version as session client may not exist yet */\n+\trc = tf_session_get_session_internal(tfp, &session);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Failed to lookup session, rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\tclient = tf_session_find_session_client_by_name(session,\n+\t\t\t\t\t\t\tparms->ctrl_chan_name);\n+\tif (client) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Client %s, already registered with this session\\n\",\n+\t\t\t    parms->ctrl_chan_name);\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\trc = tf_msg_session_client_register\n+\t\t    (tfp,\n+\t\t    parms->ctrl_chan_name,\n+\t\t    &session_client_id.internal.fw_session_client_id);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Failed to create client on session, rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\t/* Create the local session client, initialize and attach to\n+\t * the session\n+\t */\n+\tcparms.nitems = 1;\n+\tcparms.size = sizeof(struct tf_session_client);\n+\tcparms.alignment = 0;\n+\trc = tfp_calloc(&cparms);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Failed to allocate session client, rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t\tgoto cleanup;\n+\t}\n+\tclient = cparms.mem_va;\n+\n+\t/* Register FID with the client */\n+\trc = tfp_get_fid(tfp, &client->fw_fid);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\t/* Build the Session Client ID by adding the fw_session_id */\n+\trc = tf_session_get_fw_session_id\n+\t\t\t(tfp,\n+\t\t\t&session_client_id.internal.fw_session_id);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Session Firmware id lookup failed, rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\ttfp_memcpy(client->ctrl_chan_name,\n+\t\t   parms->ctrl_chan_name,\n+\t\t   TF_SESSION_NAME_MAX);\n+\n+\tclient->session_client_id.id = session_client_id.id;\n+\n+\tll_insert(&session->client_ll, &client->ll_entry);\n+\n+\tsession->ref_count++;\n+\n+\t/* Build the return value */\n+\tparms->session_client_id->id = session_client_id.id;\n+\n+ cleanup:\n+\t/* TBD - Add code to unregister newly create client from fw */\n+\n+\treturn rc;\n+}\n+\n+\n+/**\n+ * Destroys a Session Client on an existing Session.\n+ *\n+ * [in] tfp\n+ *   Pointer to TF handle\n+ *\n+ * [in] parms\n+ *   Pointer to the session client destroy parameters\n+ *\n+ * Returns\n+ *   - (0) if successful.\n+ *   - (-EINVAL) on failure.\n+ *   - (-ENOTFOUND) error, client not owned by the session.\n+ *   - (-ENOTSUPP) error, unable to destroy client as its the last\n+ *                 client. Please use the tf_session_close().\n+ */\n+static int\n+tf_session_client_destroy(struct tf *tfp,\n+\t\t\t  struct tf_session_client_destroy_parms *parms)\n+{\n+\tint rc;\n+\tstruct tf_session *tfs;\n+\tstruct tf_session_client *client;\n+\n+\tTF_CHECK_PARMS2(tfp, parms);\n+\n+\trc = tf_session_get_session(tfp, &tfs);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Failed to lookup session, rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\t/* Check session owns this client and that we're not the last client */\n+\tclient = tf_session_get_session_client(tfs,\n+\t\t\t\t\t       parms->session_client_id);\n+\tif (client == NULL) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Client %d, not found within this session\\n\",\n+\t\t\t    parms->session_client_id.id);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* If last client the request is rejected and cleanup should\n+\t * be done by session close.\n+\t */\n+\tif (tfs->ref_count == 1)\n+\t\treturn -EOPNOTSUPP;\n+\n+\trc = tf_msg_session_client_unregister\n+\t\t\t(tfp,\n+\t\t\tparms->session_client_id.internal.fw_session_client_id);\n+\n+\t/* Log error, but continue. If FW fails we do not really have\n+\t * a way to fix this but the client would no longer be valid\n+\t * thus we remove from the session.\n+\t */\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Client destroy on FW Failed, rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t}\n+\n+\tll_delete(&tfs->client_ll, &client->ll_entry);\n+\n+\t/* Decrement the session ref_count */\n+\ttfs->ref_count--;\n+\n+\ttfp_free(client);\n+\n+\treturn rc;\n+}\n+\n+int\n+tf_session_open_session(struct tf *tfp,\n+\t\t\tstruct tf_session_open_session_parms *parms)\n+{\n+\tint rc;\n+\tstruct tf_session_client_create_parms scparms;\n+\n+\tTF_CHECK_PARMS2(tfp, parms);\n+\n+\t/* Decide if we're creating a new session or session client */\n+\tif (tfp->session == NULL) {\n+\t\trc = tf_session_create(tfp, parms);\n+\t\tif (rc) {\n+\t\t\tTFP_DRV_LOG(ERR,\n+\t\t\t\t    \"Failed to create session, ctrl_chan_name:%s, rc:%s\\n\",\n+\t\t\t\t    parms->open_cfg->ctrl_chan_name,\n+\t\t\t\t    strerror(-rc));\n+\t\t\treturn rc;\n+\t\t}\n+\n+\t\tTFP_DRV_LOG(INFO,\n+\t\t       \"Session created, session_client_id:%d, session_id:%d\\n\",\n+\t\t       parms->open_cfg->session_client_id.id,\n+\t\t       parms->open_cfg->session_id.id);\n+\t} else {\n+\t\tscparms.ctrl_chan_name = parms->open_cfg->ctrl_chan_name;\n+\t\tscparms.session_client_id = &parms->open_cfg->session_client_id;\n+\n+\t\t/* Create the new client and get it associated with\n+\t\t * the session.\n+\t\t */\n+\t\trc = tf_session_client_create(tfp, &scparms);\n+\t\tif (rc) {\n+\t\t\tTFP_DRV_LOG(ERR,\n+\t\t\t      \"Failed to create client on session %d, rc:%s\\n\",\n+\t\t\t      parms->open_cfg->session_id.id,\n+\t\t\t      strerror(-rc));\n+\t\t\treturn rc;\n+\t\t}\n+\n+\t\tTFP_DRV_LOG(INFO,\n+\t\t\t    \"Session Client:%d created on session:%d\\n\",\n+\t\t\t    parms->open_cfg->session_client_id.id,\n+\t\t\t    parms->open_cfg->session_id.id);\n+\t}\n+\n+\treturn 0;\n+}\n+\n int\n tf_session_attach_session(struct tf *tfp __rte_unused,\n \t\t\t  struct tf_session_attach_session_parms *parms __rte_unused)\n@@ -141,7 +437,10 @@ tf_session_close_session(struct tf *tfp,\n {\n \tint rc;\n \tstruct tf_session *tfs;\n+\tstruct tf_session_client *client;\n \tstruct tf_dev_info *tfd;\n+\tstruct tf_session_client_destroy_parms scdparms;\n+\tuint16_t fid;\n \n \tTF_CHECK_PARMS2(tfp, parms);\n \n@@ -161,7 +460,49 @@ tf_session_close_session(struct tf *tfp,\n \t\treturn rc;\n \t}\n \n-\ttfs->ref_count--;\n+\t/* Get the client, we need it independently of the closure\n+\t * type (client or session closure).\n+\t *\n+\t * We find the client by way of the fid. Thus one cannot close\n+\t * a client on behalf of someone else.\n+\t */\n+\trc = tfp_get_fid(tfp, &fid);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\tclient = tf_session_find_session_client_by_fid(tfs,\n+\t\t\t\t\t\t       fid);\n+\t/* In case multiple clients we chose to close those first */\n+\tif (tfs->ref_count > 1) {\n+\t\t/* Linaro gcc can't static init this structure */\n+\t\tmemset(&scdparms,\n+\t\t       0,\n+\t\t       sizeof(struct tf_session_client_destroy_parms));\n+\n+\t\tscdparms.session_client_id = client->session_client_id;\n+\t\t/* Destroy requested client so its no longer\n+\t\t * registered with this session.\n+\t\t */\n+\t\trc = tf_session_client_destroy(tfp, &scdparms);\n+\t\tif (rc) {\n+\t\t\tTFP_DRV_LOG(ERR,\n+\t\t\t\t    \"Failed to unregister Client %d, rc:%s\\n\",\n+\t\t\t\t    client->session_client_id.id,\n+\t\t\t\t    strerror(-rc));\n+\t\t\treturn rc;\n+\t\t}\n+\n+\t\tTFP_DRV_LOG(INFO,\n+\t\t\t    \"Closed session client, session_client_id:%d\\n\",\n+\t\t\t    client->session_client_id.id);\n+\n+\t\tTFP_DRV_LOG(INFO,\n+\t\t\t    \"session_id:%d, ref_count:%d\\n\",\n+\t\t\t    tfs->session_id.id,\n+\t\t\t    tfs->ref_count);\n+\n+\t\treturn 0;\n+\t}\n \n \t/* Record the session we're closing so the caller knows the\n \t * details.\n@@ -176,23 +517,6 @@ tf_session_close_session(struct tf *tfp,\n \t\treturn rc;\n \t}\n \n-\tif (tfs->ref_count > 0) {\n-\t\t/* In case we're attached only the session client gets\n-\t\t * closed.\n-\t\t */\n-\t\trc = tf_msg_session_close(tfp);\n-\t\tif (rc) {\n-\t\t\t/* Log error */\n-\t\t\tTFP_DRV_LOG(ERR,\n-\t\t\t\t    \"FW Session close failed, rc:%s\\n\",\n-\t\t\t\t    strerror(-rc));\n-\t\t}\n-\n-\t\treturn 0;\n-\t}\n-\n-\t/* Final cleanup as we're last user of the session */\n-\n \t/* Unbind the device */\n \trc = tf_dev_unbind(tfp, tfd);\n \tif (rc) {\n@@ -202,7 +526,6 @@ tf_session_close_session(struct tf *tfp,\n \t\t\t    strerror(-rc));\n \t}\n \n-\t/* In case we're attached only the session client gets closed */\n \trc = tf_msg_session_close(tfp);\n \tif (rc) {\n \t\t/* Log error */\n@@ -211,6 +534,21 @@ tf_session_close_session(struct tf *tfp,\n \t\t\t    strerror(-rc));\n \t}\n \n+\t/* Final cleanup as we're last user of the session thus we\n+\t * also delete the last client.\n+\t */\n+\tll_delete(&tfs->client_ll, &client->ll_entry);\n+\ttfp_free(client);\n+\n+\ttfs->ref_count--;\n+\n+\tTFP_DRV_LOG(INFO,\n+\t\t    \"Closed session, session_id:%d, ref_count:%d\\n\",\n+\t\t    tfs->session_id.id,\n+\t\t    tfs->ref_count);\n+\n+\ttfs->dev_init = false;\n+\n \ttfp_free(tfp->session->core_data);\n \ttfp_free(tfp->session);\n \ttfp->session = NULL;\n@@ -218,12 +556,31 @@ tf_session_close_session(struct tf *tfp,\n \treturn 0;\n }\n \n+bool\n+tf_session_is_fid_supported(struct tf_session *tfs,\n+\t\t\t    uint16_t fid)\n+{\n+\tstruct ll_entry *c_entry;\n+\tstruct tf_session_client *client;\n+\n+\tfor (c_entry = tfs->client_ll.head;\n+\t     c_entry != NULL;\n+\t     c_entry = c_entry->next) {\n+\t\tclient = (struct tf_session_client *)c_entry;\n+\t\tif (client->fw_fid == fid)\n+\t\t\treturn true;\n+\t}\n+\n+\treturn false;\n+}\n+\n int\n-tf_session_get_session(struct tf *tfp,\n-\t\t       struct tf_session **tfs)\n+tf_session_get_session_internal(struct tf *tfp,\n+\t\t\t\tstruct tf_session **tfs)\n {\n-\tint rc;\n+\tint rc = 0;\n \n+\t/* Skip using the check macro as we want to control the error msg */\n \tif (tfp->session == NULL || tfp->session->core_data == NULL) {\n \t\trc = -EINVAL;\n \t\tTFP_DRV_LOG(ERR,\n@@ -234,7 +591,113 @@ tf_session_get_session(struct tf *tfp,\n \n \t*tfs = (struct tf_session *)(tfp->session->core_data);\n \n-\treturn 0;\n+\treturn rc;\n+}\n+\n+int\n+tf_session_get_session(struct tf *tfp,\n+\t\t       struct tf_session **tfs)\n+{\n+\tint rc;\n+\tuint16_t fw_fid;\n+\tbool supported = false;\n+\n+\trc = tf_session_get_session_internal(tfp,\n+\t\t\t\t\t     tfs);\n+\t/* Logging done by tf_session_get_session_internal */\n+\tif (rc)\n+\t\treturn rc;\n+\n+\t/* As session sharing among functions aka 'individual clients'\n+\t * is supported we have to assure that the client is indeed\n+\t * registered before we get deep in the TruFlow api stack.\n+\t */\n+\trc = tfp_get_fid(tfp, &fw_fid);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Internal FID lookup\\n, rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\tsupported = tf_session_is_fid_supported(*tfs, fw_fid);\n+\tif (supported == false) {\n+\t\tTFP_DRV_LOG\n+\t\t\t(ERR,\n+\t\t\t\"Ctrl channel not registered with session\\n, rc:%s\\n\",\n+\t\t\tstrerror(-rc));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn rc;\n+}\n+\n+struct tf_session_client *\n+tf_session_get_session_client(struct tf_session *tfs,\n+\t\t\t      union tf_session_client_id session_client_id)\n+{\n+\tstruct ll_entry *c_entry;\n+\tstruct tf_session_client *client;\n+\n+\t/* Skip using the check macro as we just want to return */\n+\tif (tfs == NULL)\n+\t\treturn NULL;\n+\n+\tfor (c_entry = tfs->client_ll.head;\n+\t     c_entry != NULL;\n+\t     c_entry = c_entry->next) {\n+\t\tclient = (struct tf_session_client *)c_entry;\n+\t\tif (client->session_client_id.id == session_client_id.id)\n+\t\t\treturn client;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+struct tf_session_client *\n+tf_session_find_session_client_by_name(struct tf_session *tfs,\n+\t\t\t\t       const char *ctrl_chan_name)\n+{\n+\tstruct ll_entry *c_entry;\n+\tstruct tf_session_client *client;\n+\n+\t/* Skip using the check macro as we just want to return */\n+\tif (tfs == NULL || ctrl_chan_name == NULL)\n+\t\treturn NULL;\n+\n+\tfor (c_entry = tfs->client_ll.head;\n+\t     c_entry != NULL;\n+\t     c_entry = c_entry->next) {\n+\t\tclient = (struct tf_session_client *)c_entry;\n+\t\tif (strncmp(client->ctrl_chan_name,\n+\t\t\t    ctrl_chan_name,\n+\t\t\t    TF_SESSION_NAME_MAX) == 0)\n+\t\t\treturn client;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+struct tf_session_client *\n+tf_session_find_session_client_by_fid(struct tf_session *tfs,\n+\t\t\t\t      uint16_t fid)\n+{\n+\tstruct ll_entry *c_entry;\n+\tstruct tf_session_client *client;\n+\n+\t/* Skip using the check macro as we just want to return */\n+\tif (tfs == NULL)\n+\t\treturn NULL;\n+\n+\tfor (c_entry = tfs->client_ll.head;\n+\t     c_entry != NULL;\n+\t     c_entry = c_entry->next) {\n+\t\tclient = (struct tf_session_client *)c_entry;\n+\t\tif (client->fw_fid == fid)\n+\t\t\treturn client;\n+\t}\n+\n+\treturn NULL;\n }\n \n int\n@@ -253,6 +716,7 @@ tf_session_get_fw_session_id(struct tf *tfp,\n \tint rc;\n \tstruct tf_session *tfs;\n \n+\t/* Skip using the check macro as we want to control the error msg */\n \tif (tfp->session == NULL) {\n \t\trc = -EINVAL;\n \t\tTFP_DRV_LOG(ERR,\n@@ -261,7 +725,15 @@ tf_session_get_fw_session_id(struct tf *tfp,\n \t\treturn rc;\n \t}\n \n-\trc = tf_session_get_session(tfp, &tfs);\n+\tif (fw_session_id == NULL) {\n+\t\trc = -EINVAL;\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Invalid Argument(s), rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\trc = tf_session_get_session_internal(tfp, &tfs);\n \tif (rc)\n \t\treturn rc;\n \n@@ -269,3 +741,36 @@ tf_session_get_fw_session_id(struct tf *tfp,\n \n \treturn 0;\n }\n+\n+int\n+tf_session_get_session_id(struct tf *tfp,\n+\t\t\t  union tf_session_id *session_id)\n+{\n+\tint rc;\n+\tstruct tf_session *tfs;\n+\n+\tif (tfp->session == NULL) {\n+\t\trc = -EINVAL;\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Session not created, rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\tif (session_id == NULL) {\n+\t\trc = -EINVAL;\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Invalid Argument(s), rc:%s\\n\",\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\t/* Using internal version as session client may not exist yet */\n+\trc = tf_session_get_session_internal(tfp, &tfs);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\t*session_id = tfs->session_id;\n+\n+\treturn 0;\n+}\ndiff --git a/drivers/net/bnxt/tf_core/tf_session.h b/drivers/net/bnxt/tf_core/tf_session.h\nindex a303fde..aa7a278 100644\n--- a/drivers/net/bnxt/tf_core/tf_session.h\n+++ b/drivers/net/bnxt/tf_core/tf_session.h\n@@ -16,6 +16,7 @@\n #include \"tf_tbl.h\"\n #include \"tf_resources.h\"\n #include \"stack.h\"\n+#include \"ll.h\"\n \n /**\n  * The Session module provides session control support. A session is\n@@ -29,7 +30,6 @@\n \n /** Session defines\n  */\n-#define TF_SESSIONS_MAX\t          1          /** max # sessions */\n #define TF_SESSION_ID_INVALID     0xFFFFFFFF /** Invalid Session ID define */\n \n /**\n@@ -50,7 +50,7 @@\n  * Shared memory containing private TruFlow session information.\n  * Through this structure the session can keep track of resource\n  * allocations and (if so configured) any shadow copy of flow\n- * information.\n+ * information. It also holds info about Session Clients.\n  *\n  * Memory is assigned to the Truflow instance by way of\n  * tf_open_session. Memory is allocated and owned by i.e. ULP.\n@@ -65,17 +65,10 @@ struct tf_session {\n \t */\n \tstruct tf_session_version ver;\n \n-\t/** Session ID, allocated by FW on tf_open_session() */\n-\tunion tf_session_id session_id;\n-\n \t/**\n-\t * String containing name of control channel interface to be\n-\t * used for this session to communicate with firmware.\n-\t *\n-\t * ctrl_chan_name will be used as part of a name for any\n-\t * shared memory allocation.\n+\t * Session ID, allocated by FW on tf_open_session()\n \t */\n-\tchar ctrl_chan_name[TF_SESSION_NAME_MAX];\n+\tunion tf_session_id session_id;\n \n \t/**\n \t * Boolean controlling the use and availability of shadow\n@@ -92,14 +85,67 @@ struct tf_session {\n \n \t/**\n \t * Session Reference Count. To keep track of functions per\n-\t * session the ref_count is incremented. There is also a\n+\t * session the ref_count is updated. There is also a\n \t * parallel TruFlow Firmware ref_count in case the TruFlow\n \t * Core goes away without informing the Firmware.\n \t */\n \tuint8_t ref_count;\n \n-\t/** Device handle */\n+\t/**\n+\t * Session Reference Count for attached sessions. To keep\n+\t * track of application sharing of a session the\n+\t * ref_count_attach is updated.\n+\t */\n+\tuint8_t ref_count_attach;\n+\n+\t/**\n+\t * Device handle\n+\t */\n \tstruct tf_dev_info dev;\n+\t/**\n+\t * Device init flag. False if Device is not fully initialized,\n+\t * else true.\n+\t */\n+\tbool dev_init;\n+\n+\t/**\n+\t * Linked list of clients registered for this session\n+\t */\n+\tstruct ll client_ll;\n+};\n+\n+/**\n+ * Session Client\n+ *\n+ * Shared memory for each of the Session Clients. A session can have\n+ * one or more clients.\n+ */\n+struct tf_session_client {\n+\t/**\n+\t * Linked list of clients\n+\t */\n+\tstruct ll_entry ll_entry; /* For inserting in link list, must be\n+\t\t\t\t   * first field of struct.\n+\t\t\t\t   */\n+\n+\t/**\n+\t * String containing name of control channel interface to be\n+\t * used for this session to communicate with firmware.\n+\t *\n+\t * ctrl_chan_name will be used as part of a name for any\n+\t * shared memory allocation.\n+\t */\n+\tchar ctrl_chan_name[TF_SESSION_NAME_MAX];\n+\n+\t/**\n+\t * Firmware FID, learned at time of Session Client create.\n+\t */\n+\tuint16_t fw_fid;\n+\n+\t/**\n+\t * Session Client ID, allocated by FW on tf_register_session()\n+\t */\n+\tunion tf_session_client_id session_client_id;\n };\n \n /**\n@@ -126,7 +172,13 @@ struct tf_session_attach_session_parms {\n  * Session close parameter definition\n  */\n struct tf_session_close_session_parms {\n+\t/**\n+\t * []\n+\t */\n \tuint8_t *ref_count;\n+\t/**\n+\t * []\n+\t */\n \tunion tf_session_id *session_id;\n };\n \n@@ -139,11 +191,23 @@ struct tf_session_close_session_parms {\n  *\n  * @ref tf_session_close_session\n  *\n+ * @ref tf_session_is_fid_supported\n+ *\n+ * @ref tf_session_get_session_internal\n+ *\n  * @ref tf_session_get_session\n  *\n+ * @ref tf_session_get_session_client\n+ *\n+ * @ref tf_session_find_session_client_by_name\n+ *\n+ * @ref tf_session_find_session_client_by_fid\n+ *\n  * @ref tf_session_get_device\n  *\n  * @ref tf_session_get_fw_session_id\n+ *\n+ * @ref tf_session_get_session_id\n  */\n \n /**\n@@ -179,7 +243,8 @@ int tf_session_attach_session(struct tf *tfp,\n \t\t\t      struct tf_session_attach_session_parms *parms);\n \n /**\n- * Closes a previous created session.\n+ * Closes a previous created session. Only possible if previous\n+ * registered Clients had been unregistered first.\n  *\n  * [in] tfp\n  *   Pointer to TF handle\n@@ -189,13 +254,53 @@ int tf_session_attach_session(struct tf *tfp,\n  *\n  * Returns\n  *   - (0) if successful.\n+ *   - (-EUSERS) if clients are still registered with the session.\n  *   - (-EINVAL) on failure.\n  */\n int tf_session_close_session(struct tf *tfp,\n \t\t\t     struct tf_session_close_session_parms *parms);\n \n /**\n- * Looks up the private session information from the TF session info.\n+ * Verifies that the fid is supported by the session. Used to assure\n+ * that a function i.e. client/control channel is registered with the\n+ * session.\n+ *\n+ * [in] tfs\n+ *   Pointer to TF Session handle\n+ *\n+ * [in] fid\n+ *   FID value to check\n+ *\n+ * Returns\n+ *   - (true) if successful, else false\n+ *   - (-EINVAL) on failure.\n+ */\n+bool\n+tf_session_is_fid_supported(struct tf_session *tfs,\n+\t\t\t    uint16_t fid);\n+\n+/**\n+ * Looks up the private session information from the TF session\n+ * info. Does not perform a fid check against the registered\n+ * clients. Should be used if tf_session_get_session() was used\n+ * previously i.e. at the TF API boundary.\n+ *\n+ * [in] tfp\n+ *   Pointer to TF handle\n+ *\n+ * [out] tfs\n+ *   Pointer pointer to the session\n+ *\n+ * Returns\n+ *   - (0) if successful.\n+ *   - (-EINVAL) on failure.\n+ */\n+int tf_session_get_session_internal(struct tf *tfp,\n+\t\t\t\t    struct tf_session **tfs);\n+\n+/**\n+ * Looks up the private session information from the TF session\n+ * info. Performs a fid check against the clients on the session.\n  *\n  * [in] tfp\n  *   Pointer to TF handle\n@@ -211,6 +316,53 @@ int tf_session_get_session(struct tf *tfp,\n \t\t\t   struct tf_session **tfs);\n \n /**\n+ * Looks up client within the session.\n+ *\n+ * [in] tfs\n+ *   Pointer pointer to the session\n+ *\n+ * [in] session_client_id\n+ *   Client id to look for within the session\n+ *\n+ * Returns\n+ *   client if successful.\n+ *   - (NULL) on failure, client not found.\n+ */\n+struct tf_session_client *\n+tf_session_get_session_client(struct tf_session *tfs,\n+\t\t\t      union tf_session_client_id session_client_id);\n+\n+/**\n+ * Looks up client using name within the session.\n+ *\n+ * [in] session, pointer to the session\n+ *\n+ * [in] session_client_name, name of the client to lookup in the session\n+ *\n+ * Returns:\n+ *   - Pointer to the session, if found.\n+ *   - (NULL) on failure, client not found.\n+ */\n+struct tf_session_client *\n+tf_session_find_session_client_by_name(struct tf_session *tfs,\n+\t\t\t\t       const char *ctrl_chan_name);\n+\n+/**\n+ * Looks up client using the fid.\n+ *\n+ * [in] session, pointer to the session\n+ *\n+ * [in] fid, fid of the client to find\n+ *\n+ * Returns:\n+ *   - Pointer to the session, if found.\n+ *   - (NULL) on failure, client not found.\n+ */\n+struct tf_session_client *\n+tf_session_find_session_client_by_fid(struct tf_session *tfs,\n+\t\t\t\t      uint16_t fid);\n+\n+/**\n  * Looks up the device information from the TF Session.\n  *\n  * [in] tfp\n@@ -227,8 +379,7 @@ int tf_session_get_device(struct tf_session *tfs,\n \t\t\t  struct tf_dev_info **tfd);\n \n /**\n- * Looks up the FW session id of the firmware connection for the\n- * requested TF handle.\n+ * Looks up the FW Session id the requested TF handle.\n  *\n  * [in] tfp\n  *   Pointer to TF handle\n@@ -243,4 +394,20 @@ int tf_session_get_device(struct tf_session *tfs,\n int tf_session_get_fw_session_id(struct tf *tfp,\n \t\t\t\t uint8_t *fw_session_id);\n \n+/**\n+ * Looks up the Session id the requested TF handle.\n+ *\n+ * [in] tfp\n+ *   Pointer to TF handle\n+ *\n+ * [out] session_id\n+ *   Pointer to the session_id\n+ *\n+ * Returns\n+ *   - (0) if successful.\n+ *   - (-EINVAL) on failure.\n+ */\n+int tf_session_get_session_id(struct tf *tfp,\n+\t\t\t      union tf_session_id *session_id);\n+\n #endif /* _TF_SESSION_H_ */\ndiff --git a/drivers/net/bnxt/tf_core/tf_tbl.c b/drivers/net/bnxt/tf_core/tf_tbl.c\nindex a864b16..684b544 100644\n--- a/drivers/net/bnxt/tf_core/tf_tbl.c\n+++ b/drivers/net/bnxt/tf_core/tf_tbl.c\n@@ -266,6 +266,7 @@ tf_tbl_set(struct tf *tfp,\n \t\t\t    tf_dir_2_str(parms->dir),\n \t\t\t    parms->type,\n \t\t\t    strerror(-rc));\n+\t\treturn rc;\n \t}\n \n \treturn 0;\n@@ -335,6 +336,7 @@ tf_tbl_get(struct tf *tfp,\n \t\t\t    tf_dir_2_str(parms->dir),\n \t\t\t    parms->type,\n \t\t\t    strerror(-rc));\n+\t\treturn rc;\n \t}\n \n \treturn 0;\ndiff --git a/drivers/net/bnxt/tf_core/tf_tcam.c b/drivers/net/bnxt/tf_core/tf_tcam.c\nindex 1c48b53..cbfaa94 100644\n--- a/drivers/net/bnxt/tf_core/tf_tcam.c\n+++ b/drivers/net/bnxt/tf_core/tf_tcam.c\n@@ -138,7 +138,7 @@ tf_tcam_alloc(struct tf *tfp,\n \t}\n \n \t/* Retrieve the session information */\n-\trc = tf_session_get_session(tfp, &tfs);\n+\trc = tf_session_get_session_internal(tfp, &tfs);\n \tif (rc)\n \t\treturn rc;\n \n@@ -218,7 +218,7 @@ tf_tcam_free(struct tf *tfp,\n \t}\n \n \t/* Retrieve the session information */\n-\trc = tf_session_get_session(tfp, &tfs);\n+\trc = tf_session_get_session_internal(tfp, &tfs);\n \tif (rc)\n \t\treturn rc;\n \n@@ -319,6 +319,7 @@ tf_tcam_free(struct tf *tfp,\n \t\t\t    tf_tcam_tbl_2_str(parms->type),\n \t\t\t    parms->idx,\n \t\t\t    strerror(-rc));\n+\t\treturn rc;\n \t}\n \n \treturn 0;\n@@ -353,7 +354,7 @@ tf_tcam_set(struct tf *tfp __rte_unused,\n \t}\n \n \t/* Retrieve the session information */\n-\trc = tf_session_get_session(tfp, &tfs);\n+\trc = tf_session_get_session_internal(tfp, &tfs);\n \tif (rc)\n \t\treturn rc;\n \n@@ -415,6 +416,7 @@ tf_tcam_set(struct tf *tfp __rte_unused,\n \t\t\t    tf_tcam_tbl_2_str(parms->type),\n \t\t\t    parms->idx,\n \t\t\t    strerror(-rc));\n+\t\treturn rc;\n \t}\n \n \treturn 0;\ndiff --git a/drivers/net/bnxt/tf_core/tfp.c b/drivers/net/bnxt/tf_core/tfp.c\nindex 69d1c9a..426a182 100644\n--- a/drivers/net/bnxt/tf_core/tfp.c\n+++ b/drivers/net/bnxt/tf_core/tfp.c\n@@ -161,3 +161,20 @@ tfp_spinlock_unlock(struct tfp_spinlock_parms *parms)\n {\n \trte_spinlock_unlock(&parms->slock);\n }\n+\n+int\n+tfp_get_fid(struct tf *tfp, uint16_t *fw_fid)\n+{\n+\tstruct bnxt *bp = NULL;\n+\n+\tif (tfp == NULL || fw_fid == NULL)\n+\t\treturn -EINVAL;\n+\n+\tbp = container_of(tfp, struct bnxt, tfp);\n+\tif (bp == NULL)\n+\t\treturn -EINVAL;\n+\n+\t*fw_fid = bp->fw_fid;\n+\n+\treturn 0;\n+}\ndiff --git a/drivers/net/bnxt/tf_core/tfp.h b/drivers/net/bnxt/tf_core/tfp.h\nindex fe49b63..8789eba 100644\n--- a/drivers/net/bnxt/tf_core/tfp.h\n+++ b/drivers/net/bnxt/tf_core/tfp.h\n@@ -238,4 +238,19 @@ int tfp_get_fid(struct tf *tfp, uint16_t *fw_fid);\n #define tfp_bswap_32(val) rte_bswap32(val)\n #define tfp_bswap_64(val) rte_bswap64(val)\n \n+/**\n+ * Lookup of the FID in the platform specific structure.\n+ *\n+ * [in] session\n+ *   Pointer to session handle\n+ *\n+ * [out] fw_fid\n+ *   Pointer to the fw_fid\n+ *\n+ * Returns:\n+ *   0       - Success\n+ *   -EINVAL - Parameter error\n+ */\n+int tfp_get_fid(struct tf *tfp, uint16_t *fw_fid);\n+\n #endif /* _TFP_H_ */\n",
    "prefixes": [
        "29/50"
    ]
}