get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 71412,
    "url": "http://patches.dpdk.org/api/patches/71412/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20200612132934.16488-21-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-21-somnath.kotur@broadcom.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200612132934.16488-21-somnath.kotur@broadcom.com",
    "date": "2020-06-12T13:29:04",
    "name": "[20/50] net/bnxt: update RM with residual checker",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "091d3e9c62d0daf8a96f1c538422e815cdbb5af6",
    "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-21-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/71412/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/71412/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 71FF0A00BE;\n\tFri, 12 Jun 2020 15:43:35 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id C0BA31C07E;\n\tFri, 12 Jun 2020 15:34:35 +0200 (CEST)",
            "from relay.smtp.broadcom.com (unknown [192.19.232.149])\n by dpdk.org (Postfix) with ESMTP id EF8251C001\n for <dev@dpdk.org>; Fri, 12 Jun 2020 15:34:31 +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 C91A41BD7A4;\n Fri, 12 Jun 2020 06:34:30 -0700 (PDT)"
        ],
        "DKIM-Filter": "OpenDKIM Filter v2.10.3 relay.smtp.broadcom.com C91A41BD7A4",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=broadcom.com;\n s=dkimrelay; t=1591968871;\n bh=yC7ZTY0vclQDZgazHdYXTPHzC5mU8Y/P+hX7ibCshf8=;\n h=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n b=tVE2KE2gBbARtIT6nK3f1xOrZ9XjhBhJqrA1tA7SXT5paUwkU/qUC2LNwHnO/4bQ9\n QlTGB67zq79wCSsZyXt3K98ChNSPLoUOzj+w3ZhOMP5UnTFbtj8thyeFvbmrMyL7dW\n MAT3UA12h44bL063PFyTUqjwgvH9ZU4rwMM1Fb8Y=",
        "From": "Somnath Kotur <somnath.kotur@broadcom.com>",
        "To": "dev@dpdk.org",
        "Cc": "ferruh.yigit@intel.com",
        "Date": "Fri, 12 Jun 2020 18:59:04 +0530",
        "Message-Id": "<20200612132934.16488-21-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 20/50] net/bnxt: update RM with residual checker",
        "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 residual checker to the TF Host RM as well as new RM APIs. On\n  close it will scan the DB and check of any remaining elements. If\n  found they will be logged and FW msg sent for FW to scrub that\n  specific type of resources.\n- Update the module bind to be aware of the module type, for each of\n  the modules.\n- Add additional type 2 string util functions.\n- Fix the device naming to be in compliance with TF.\n- Update the device unbind order as to assure TCAMs gets flushed\n  first.\n- Update the close functionality such that the session gets\n  closed after the device is unbound.\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/tf_core/tf_device.c     |  53 +++---\n drivers/net/bnxt/tf_core/tf_device.h     |  25 ++-\n drivers/net/bnxt/tf_core/tf_device_p4.h  |   1 -\n drivers/net/bnxt/tf_core/tf_identifier.c |  10 +-\n drivers/net/bnxt/tf_core/tf_msg.c        |  67 +++++++-\n drivers/net/bnxt/tf_core/tf_msg.h        |   7 +\n drivers/net/bnxt/tf_core/tf_rm_new.c     | 287 +++++++++++++++++++++++++++++--\n drivers/net/bnxt/tf_core/tf_rm_new.h     |  45 ++++-\n drivers/net/bnxt/tf_core/tf_session.c    |  58 ++++---\n drivers/net/bnxt/tf_core/tf_tbl_type.c   |   5 +-\n drivers/net/bnxt/tf_core/tf_tcam.c       |   5 +-\n drivers/net/bnxt/tf_core/tf_tcam.h       |   4 +\n drivers/net/bnxt/tf_core/tf_util.c       |  55 ++++--\n drivers/net/bnxt/tf_core/tf_util.h       |  32 ++++\n 14 files changed, 561 insertions(+), 93 deletions(-)",
    "diff": "diff --git a/drivers/net/bnxt/tf_core/tf_device.c b/drivers/net/bnxt/tf_core/tf_device.c\nindex b474e8c..441d0c6 100644\n--- a/drivers/net/bnxt/tf_core/tf_device.c\n+++ b/drivers/net/bnxt/tf_core/tf_device.c\n@@ -10,7 +10,7 @@\n struct tf;\n \n /* Forward declarations */\n-static int dev_unbind_p4(struct tf *tfp);\n+static int tf_dev_unbind_p4(struct tf *tfp);\n \n /**\n  * Device specific bind function, WH+\n@@ -32,10 +32,10 @@ static int dev_unbind_p4(struct tf *tfp);\n  *   - (-EINVAL) on parameter or internal failure.\n  */\n static int\n-dev_bind_p4(struct tf *tfp,\n-\t    bool shadow_copy,\n-\t    struct tf_session_resources *resources,\n-\t    struct tf_dev_info *dev_handle)\n+tf_dev_bind_p4(struct tf *tfp,\n+\t       bool shadow_copy,\n+\t       struct tf_session_resources *resources,\n+\t       struct tf_dev_info *dev_handle)\n {\n \tint rc;\n \tint frc;\n@@ -93,7 +93,7 @@ dev_bind_p4(struct tf *tfp,\n \n  fail:\n \t/* Cleanup of already created modules */\n-\tfrc = dev_unbind_p4(tfp);\n+\tfrc = tf_dev_unbind_p4(tfp);\n \tif (frc)\n \t\treturn frc;\n \n@@ -111,7 +111,7 @@ dev_bind_p4(struct tf *tfp,\n  *   - (-EINVAL) on failure.\n  */\n static int\n-dev_unbind_p4(struct tf *tfp)\n+tf_dev_unbind_p4(struct tf *tfp)\n {\n \tint rc = 0;\n \tbool fail = false;\n@@ -119,25 +119,28 @@ dev_unbind_p4(struct tf *tfp)\n \t/* Unbind all the support modules. As this is only done on\n \t * close we only report errors as everything has to be cleaned\n \t * up regardless.\n+\t *\n+\t * In case of residuals TCAMs are cleaned up first as to\n+\t * invalidate the pipeline in a clean manner.\n \t */\n-\trc = tf_ident_unbind(tfp);\n+\trc = tf_tcam_unbind(tfp);\n \tif (rc) {\n \t\tTFP_DRV_LOG(ERR,\n-\t\t\t    \"Device unbind failed, Identifier\\n\");\n+\t\t\t    \"Device unbind failed, TCAM\\n\");\n \t\tfail = true;\n \t}\n \n-\trc = tf_tbl_unbind(tfp);\n+\trc = tf_ident_unbind(tfp);\n \tif (rc) {\n \t\tTFP_DRV_LOG(ERR,\n-\t\t\t    \"Device unbind failed, Table Type\\n\");\n+\t\t\t    \"Device unbind failed, Identifier\\n\");\n \t\tfail = true;\n \t}\n \n-\trc = tf_tcam_unbind(tfp);\n+\trc = tf_tbl_unbind(tfp);\n \tif (rc) {\n \t\tTFP_DRV_LOG(ERR,\n-\t\t\t    \"Device unbind failed, TCAM\\n\");\n+\t\t\t    \"Device unbind failed, Table Type\\n\");\n \t\tfail = true;\n \t}\n \n@@ -148,18 +151,18 @@ dev_unbind_p4(struct tf *tfp)\n }\n \n int\n-dev_bind(struct tf *tfp __rte_unused,\n-\t enum tf_device_type type,\n-\t bool shadow_copy,\n-\t struct tf_session_resources *resources,\n-\t struct tf_dev_info *dev_handle)\n+tf_dev_bind(struct tf *tfp __rte_unused,\n+\t    enum tf_device_type type,\n+\t    bool shadow_copy,\n+\t    struct tf_session_resources *resources,\n+\t    struct tf_dev_info *dev_handle)\n {\n \tswitch (type) {\n \tcase TF_DEVICE_TYPE_WH:\n-\t\treturn dev_bind_p4(tfp,\n-\t\t\t\t   shadow_copy,\n-\t\t\t\t   resources,\n-\t\t\t\t   dev_handle);\n+\t\treturn tf_dev_bind_p4(tfp,\n+\t\t\t\t      shadow_copy,\n+\t\t\t\t      resources,\n+\t\t\t\t      dev_handle);\n \tdefault:\n \t\tTFP_DRV_LOG(ERR,\n \t\t\t    \"No such device\\n\");\n@@ -168,12 +171,12 @@ dev_bind(struct tf *tfp __rte_unused,\n }\n \n int\n-dev_unbind(struct tf *tfp,\n-\t   struct tf_dev_info *dev_handle)\n+tf_dev_unbind(struct tf *tfp,\n+\t      struct tf_dev_info *dev_handle)\n {\n \tswitch (dev_handle->type) {\n \tcase TF_DEVICE_TYPE_WH:\n-\t\treturn dev_unbind_p4(tfp);\n+\t\treturn tf_dev_unbind_p4(tfp);\n \tdefault:\n \t\tTFP_DRV_LOG(ERR,\n \t\t\t    \"No such device\\n\");\ndiff --git a/drivers/net/bnxt/tf_core/tf_device.h b/drivers/net/bnxt/tf_core/tf_device.h\nindex c31bf23..c8feac5 100644\n--- a/drivers/net/bnxt/tf_core/tf_device.h\n+++ b/drivers/net/bnxt/tf_core/tf_device.h\n@@ -15,6 +15,17 @@ struct tf;\n struct tf_session;\n \n /**\n+ *\n+ */\n+enum tf_device_module_type {\n+\tTF_DEVICE_MODULE_TYPE_IDENTIFIER,\n+\tTF_DEVICE_MODULE_TYPE_TABLE,\n+\tTF_DEVICE_MODULE_TYPE_TCAM,\n+\tTF_DEVICE_MODULE_TYPE_EM,\n+\tTF_DEVICE_MODULE_TYPE_MAX\n+};\n+\n+/**\n  * The Device module provides a general device template. A supported\n  * device type should implement one or more of the listed function\n  * pointers according to its capabilities.\n@@ -60,11 +71,11 @@ struct tf_dev_info {\n  *   - (-EINVAL) parameter failure.\n  *   - (-ENODEV) no such device supported.\n  */\n-int dev_bind(struct tf *tfp,\n-\t     enum tf_device_type type,\n-\t     bool shadow_copy,\n-\t     struct tf_session_resources *resources,\n-\t     struct tf_dev_info *dev_handle);\n+int tf_dev_bind(struct tf *tfp,\n+\t\tenum tf_device_type type,\n+\t\tbool shadow_copy,\n+\t\tstruct tf_session_resources *resources,\n+\t\tstruct tf_dev_info *dev_handle);\n \n /**\n  * Device release handles cleanup of the device specific information.\n@@ -80,8 +91,8 @@ int dev_bind(struct tf *tfp,\n  *   - (-EINVAL) parameter failure.\n  *   - (-ENODEV) no such device supported.\n  */\n-int dev_unbind(struct tf *tfp,\n-\t       struct tf_dev_info *dev_handle);\n+int tf_dev_unbind(struct tf *tfp,\n+\t\t  struct tf_dev_info *dev_handle);\n \n /**\n  * Truflow device specific function hooks structure\ndiff --git a/drivers/net/bnxt/tf_core/tf_device_p4.h b/drivers/net/bnxt/tf_core/tf_device_p4.h\nindex 235d81f..411e216 100644\n--- a/drivers/net/bnxt/tf_core/tf_device_p4.h\n+++ b/drivers/net/bnxt/tf_core/tf_device_p4.h\n@@ -77,5 +77,4 @@ struct tf_rm_element_cfg tf_tbl_p4[TF_TBL_TYPE_MAX] = {\n \t/* CFA_RESOURCE_TYPE_P4_EXT */\n \t{ TF_RM_ELEM_CFG_NULL, CFA_RESOURCE_TYPE_INVALID }\n };\n-\n #endif /* _TF_DEVICE_P4_H_ */\ndiff --git a/drivers/net/bnxt/tf_core/tf_identifier.c b/drivers/net/bnxt/tf_core/tf_identifier.c\nindex ee07a6a..b197bb2 100644\n--- a/drivers/net/bnxt/tf_core/tf_identifier.c\n+++ b/drivers/net/bnxt/tf_core/tf_identifier.c\n@@ -39,12 +39,12 @@ tf_ident_bind(struct tf *tfp,\n \t\treturn -EINVAL;\n \t}\n \n+\tdb_cfg.type = TF_DEVICE_MODULE_TYPE_IDENTIFIER;\n \tdb_cfg.num_elements = parms->num_elements;\n+\tdb_cfg.cfg = parms->cfg;\n \n \tfor (i = 0; i < TF_DIR_MAX; i++) {\n \t\tdb_cfg.dir = i;\n-\t\tdb_cfg.num_elements = parms->num_elements;\n-\t\tdb_cfg.cfg = parms->cfg;\n \t\tdb_cfg.alloc_cnt = parms->resources->ident_cnt[i].cnt;\n \t\tdb_cfg.rm_db = &ident_db[i];\n \t\trc = tf_rm_create_db(tfp, &db_cfg);\n@@ -86,8 +86,10 @@ tf_ident_unbind(struct tf *tfp __rte_unused)\n \t\tfparms.dir = i;\n \t\tfparms.rm_db = ident_db[i];\n \t\trc = tf_rm_free_db(tfp, &fparms);\n-\t\tif (rc)\n-\t\t\treturn rc;\n+\t\tif (rc) {\n+\t\t\tTFP_DRV_LOG(ERR,\n+\t\t\t\t    \"rm free failed on unbind\\n\");\n+\t\t}\n \n \t\tident_db[i] = NULL;\n \t}\ndiff --git a/drivers/net/bnxt/tf_core/tf_msg.c b/drivers/net/bnxt/tf_core/tf_msg.c\nindex 5ec2f83..5020433 100644\n--- a/drivers/net/bnxt/tf_core/tf_msg.c\n+++ b/drivers/net/bnxt/tf_core/tf_msg.c\n@@ -1110,6 +1110,69 @@ tf_msg_session_resc_alloc(struct tf *tfp,\n \treturn rc;\n }\n \n+int\n+tf_msg_session_resc_flush(struct tf *tfp,\n+\t\t\t  enum tf_dir dir,\n+\t\t\t  uint16_t size,\n+\t\t\t  struct tf_rm_resc_entry *resv)\n+{\n+\tint rc;\n+\tint i;\n+\tstruct tfp_send_msg_parms parms = { 0 };\n+\tstruct hwrm_tf_session_resc_flush_input req = { 0 };\n+\tstruct hwrm_tf_session_resc_flush_output resp = { 0 };\n+\tuint8_t fw_session_id;\n+\tstruct tf_msg_dma_buf resv_buf = { 0 };\n+\tstruct tf_rm_resc_entry *resv_data;\n+\tint dma_size;\n+\n+\tTF_CHECK_PARMS2(tfp, resv);\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    \"%s: Unable to lookup FW id, rc:%s\\n\",\n+\t\t\t    tf_dir_2_str(dir),\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\t/* Prepare DMA buffers */\n+\tdma_size = size * sizeof(struct tf_rm_resc_entry);\n+\trc = tf_msg_alloc_dma_buf(&resv_buf, dma_size);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\t/* Populate the request */\n+\treq.fw_session_id = tfp_cpu_to_le_32(fw_session_id);\n+\treq.flags = tfp_cpu_to_le_16(dir);\n+\treq.flush_size = size;\n+\n+\tresv_data = (struct tf_rm_resc_entry *)resv_buf.va_addr;\n+\tfor (i = 0; i < size; i++) {\n+\t\tresv_data[i].type = tfp_cpu_to_le_32(resv[i].type);\n+\t\tresv_data[i].start = tfp_cpu_to_le_16(resv[i].start);\n+\t\tresv_data[i].stride = tfp_cpu_to_le_16(resv[i].stride);\n+\t}\n+\n+\treq.flush_addr = tfp_cpu_to_le_64(resv_buf.pa_addr);\n+\n+\tparms.tf_type = HWRM_TF_SESSION_RESC_FLUSH;\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, &parms);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\ttf_msg_free_dma_buf(&resv_buf);\n+\n+\treturn rc;\n+}\n+\n /**\n  * Sends EM mem register request to Firmware\n  */\n@@ -1511,9 +1574,7 @@ tf_msg_tcam_entry_set(struct tf *tfp,\n \tuint8_t *data = NULL;\n \tint data_size = 0;\n \n-\trc = tf_tcam_tbl_2_hwrm(parms->type, &req.type);\n-\tif (rc != 0)\n-\t\treturn rc;\n+\treq.type = parms->type;\n \n \treq.idx = tfp_cpu_to_le_16(parms->idx);\n \tif (parms->dir == TF_DIR_TX)\ndiff --git a/drivers/net/bnxt/tf_core/tf_msg.h b/drivers/net/bnxt/tf_core/tf_msg.h\nindex fb635f6..1ff1044 100644\n--- a/drivers/net/bnxt/tf_core/tf_msg.h\n+++ b/drivers/net/bnxt/tf_core/tf_msg.h\n@@ -182,6 +182,13 @@ int tf_msg_session_resc_alloc(struct tf *tfp,\n \t\t\t      struct tf_rm_resc_entry *resv);\n \n /**\n+ * Sends session resource flush request to TF Firmware\n+ */\n+int tf_msg_session_resc_flush(struct tf *tfp,\n+\t\t\t      enum tf_dir dir,\n+\t\t\t      uint16_t size,\n+\t\t\t      struct tf_rm_resc_entry *resv);\n+/**\n  * Sends EM internal insert request to Firmware\n  */\n int tf_msg_insert_em_internal_entry(struct tf *tfp,\ndiff --git a/drivers/net/bnxt/tf_core/tf_rm_new.c b/drivers/net/bnxt/tf_core/tf_rm_new.c\nindex 6abf79a..02b4b5c 100644\n--- a/drivers/net/bnxt/tf_core/tf_rm_new.c\n+++ b/drivers/net/bnxt/tf_core/tf_rm_new.c\n@@ -61,6 +61,11 @@ struct tf_rm_new_db {\n \tenum tf_dir dir;\n \n \t/**\n+\t * Module type, used for logging purposes.\n+\t */\n+\tenum tf_device_module_type type;\n+\n+\t/**\n \t * The DB consists of an array of elements\n \t */\n \tstruct tf_rm_element *db;\n@@ -167,6 +172,178 @@ tf_rm_adjust_index(struct tf_rm_element *db,\n \treturn rc;\n }\n \n+/**\n+ * Logs an array of found residual entries to the console.\n+ *\n+ * [in] dir\n+ *   Receive or transmit direction\n+ *\n+ * [in] type\n+ *   Type of Device Module\n+ *\n+ * [in] count\n+ *   Number of entries in the residual array\n+ *\n+ * [in] residuals\n+ *   Pointer to an array of residual entries. Array is index same as\n+ *   the DB in which this function is used. Each entry holds residual\n+ *   value for that entry.\n+ */\n+static void\n+tf_rm_log_residuals(enum tf_dir dir,\n+\t\t    enum tf_device_module_type type,\n+\t\t    uint16_t count,\n+\t\t    uint16_t *residuals)\n+{\n+\tint i;\n+\n+\t/* Walk the residual array and log the types that wasn't\n+\t * cleaned up to the console.\n+\t */\n+\tfor (i = 0; i < count; i++) {\n+\t\tif (residuals[i] != 0)\n+\t\t\tTFP_DRV_LOG(ERR,\n+\t\t\t\t\"%s, %s was not cleaned up, %d outstanding\\n\",\n+\t\t\t\ttf_dir_2_str(dir),\n+\t\t\t\ttf_device_module_type_subtype_2_str(type, i),\n+\t\t\t\tresiduals[i]);\n+\t}\n+}\n+\n+/**\n+ * Performs a check of the passed in DB for any lingering elements. If\n+ * a resource type was found to not have been cleaned up by the caller\n+ * then its residual values are recorded, logged and passed back in an\n+ * allocate reservation array that the caller can pass to the FW for\n+ * cleanup.\n+ *\n+ * [in] db\n+ *   Pointer to the db, used for the lookup\n+ *\n+ * [out] resv_size\n+ *   Pointer to the reservation size of the generated reservation\n+ *   array.\n+ *\n+ * [in/out] resv\n+ *   Pointer Pointer to a reservation array. The reservation array is\n+ *   allocated after the residual scan and holds any found residual\n+ *   entries. Thus it can be smaller than the DB that the check was\n+ *   performed on. Array must be freed by the caller.\n+ *\n+ * [out] residuals_present\n+ *   Pointer to a bool flag indicating if residual was present in the\n+ *   DB\n+ *\n+ * Returns:\n+ *     0          - Success\n+ *   - EOPNOTSUPP - Operation not supported\n+ */\n+static int\n+tf_rm_check_residuals(struct tf_rm_new_db *rm_db,\n+\t\t      uint16_t *resv_size,\n+\t\t      struct tf_rm_resc_entry **resv,\n+\t\t      bool *residuals_present)\n+{\n+\tint rc;\n+\tint i;\n+\tint f;\n+\tuint16_t count;\n+\tuint16_t found;\n+\tuint16_t *residuals = NULL;\n+\tuint16_t hcapi_type;\n+\tstruct tf_rm_get_inuse_count_parms iparms;\n+\tstruct tf_rm_get_alloc_info_parms aparms;\n+\tstruct tf_rm_get_hcapi_parms hparms;\n+\tstruct tf_rm_alloc_info info;\n+\tstruct tfp_calloc_parms cparms;\n+\tstruct tf_rm_resc_entry *local_resv = NULL;\n+\n+\t/* Create array to hold the entries that have residuals */\n+\tcparms.nitems = rm_db->num_entries;\n+\tcparms.size = sizeof(uint16_t);\n+\tcparms.alignment = 0;\n+\trc = tfp_calloc(&cparms);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\tresiduals = (uint16_t *)cparms.mem_va;\n+\n+\t/* Traverse the DB and collect any residual elements */\n+\tiparms.rm_db = rm_db;\n+\tiparms.count = &count;\n+\tfor (i = 0, found = 0; i < rm_db->num_entries; i++) {\n+\t\tiparms.db_index = i;\n+\t\trc = tf_rm_get_inuse_count(&iparms);\n+\t\t/* Not a device supported entry, just skip */\n+\t\tif (rc == -ENOTSUP)\n+\t\t\tcontinue;\n+\t\tif (rc)\n+\t\t\tgoto cleanup_residuals;\n+\n+\t\tif (count) {\n+\t\t\tfound++;\n+\t\t\tresiduals[i] = count;\n+\t\t\t*residuals_present = true;\n+\t\t}\n+\t}\n+\n+\tif (*residuals_present) {\n+\t\t/* Populate a reduced resv array with only the entries\n+\t\t * that have residuals.\n+\t\t */\n+\t\tcparms.nitems = found;\n+\t\tcparms.size = sizeof(struct tf_rm_resc_entry);\n+\t\tcparms.alignment = 0;\n+\t\trc = tfp_calloc(&cparms);\n+\t\tif (rc)\n+\t\t\treturn rc;\n+\n+\t\tlocal_resv = (struct tf_rm_resc_entry *)cparms.mem_va;\n+\n+\t\taparms.rm_db = rm_db;\n+\t\thparms.rm_db = rm_db;\n+\t\thparms.hcapi_type = &hcapi_type;\n+\t\tfor (i = 0, f = 0; i < rm_db->num_entries; i++) {\n+\t\t\tif (residuals[i] == 0)\n+\t\t\t\tcontinue;\n+\t\t\taparms.db_index = i;\n+\t\t\taparms.info = &info;\n+\t\t\trc = tf_rm_get_info(&aparms);\n+\t\t\tif (rc)\n+\t\t\t\tgoto cleanup_all;\n+\n+\t\t\thparms.db_index = i;\n+\t\t\trc = tf_rm_get_hcapi_type(&hparms);\n+\t\t\tif (rc)\n+\t\t\t\tgoto cleanup_all;\n+\n+\t\t\tlocal_resv[f].type = hcapi_type;\n+\t\t\tlocal_resv[f].start = info.entry.start;\n+\t\t\tlocal_resv[f].stride = info.entry.stride;\n+\t\t\tf++;\n+\t\t}\n+\t\t*resv_size = found;\n+\t}\n+\n+\ttf_rm_log_residuals(rm_db->dir,\n+\t\t\t    rm_db->type,\n+\t\t\t    rm_db->num_entries,\n+\t\t\t    residuals);\n+\n+\ttfp_free((void *)residuals);\n+\t*resv = local_resv;\n+\n+\treturn 0;\n+\n+ cleanup_all:\n+\ttfp_free((void *)local_resv);\n+\t*resv = NULL;\n+ cleanup_residuals:\n+\ttfp_free((void *)residuals);\n+\n+\treturn rc;\n+}\n+\n int\n tf_rm_create_db(struct tf *tfp,\n \t\tstruct tf_rm_create_db_parms *parms)\n@@ -373,6 +550,7 @@ tf_rm_create_db(struct tf *tfp,\n \n \trm_db->num_entries = i;\n \trm_db->dir = parms->dir;\n+\trm_db->type = parms->type;\n \t*parms->rm_db = (void *)rm_db;\n \n \ttfp_free((void *)req);\n@@ -392,20 +570,69 @@ tf_rm_create_db(struct tf *tfp,\n }\n \n int\n-tf_rm_free_db(struct tf *tfp __rte_unused,\n+tf_rm_free_db(struct tf *tfp,\n \t      struct tf_rm_free_db_parms *parms)\n {\n-\tint rc = 0;\n+\tint rc;\n \tint i;\n+\tuint16_t resv_size = 0;\n \tstruct tf_rm_new_db *rm_db;\n+\tstruct tf_rm_resc_entry *resv;\n+\tbool residuals_found = false;\n \n-\tTF_CHECK_PARMS1(parms);\n+\tTF_CHECK_PARMS2(parms, parms->rm_db);\n \n-\t/* Traverse the DB and clear each pool.\n-\t * NOTE:\n-\t *   Firmware is not cleared. It will be cleared on close only.\n+\t/* Device unbind happens when the TF Session is closed and the\n+\t * session ref count is 0. Device unbind will cleanup each of\n+\t * its support modules, i.e. Identifier, thus we're ending up\n+\t * here to close the DB.\n+\t *\n+\t * On TF Session close it is assumed that the session has already\n+\t * cleaned up all its resources, individually, while\n+\t * destroying its flows.\n+\t *\n+\t * To assist in the 'cleanup checking' the DB is checked for any\n+\t * remaining elements and logged if found to be the case.\n+\t *\n+\t * Any such elements will need to be 'cleared' ahead of\n+\t * returning the resources to the HCAPI RM.\n+\t *\n+\t * RM will signal FW to flush the DB resources. FW will\n+\t * perform the invalidation. TF Session close will return the\n+\t * previous allocated elements to the RM and then close the\n+\t * HCAPI RM registration. That then saves several 'free' msgs\n+\t * from being required.\n \t */\n+\n \trm_db = (struct tf_rm_new_db *)parms->rm_db;\n+\n+\t/* Check for residuals that the client didn't clean up */\n+\trc = tf_rm_check_residuals(rm_db,\n+\t\t\t\t   &resv_size,\n+\t\t\t\t   &resv,\n+\t\t\t\t   &residuals_found);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\t/* Invalidate any residuals followed by a DB traversal for\n+\t * pool cleanup.\n+\t */\n+\tif (residuals_found) {\n+\t\trc = tf_msg_session_resc_flush(tfp,\n+\t\t\t\t\t       parms->dir,\n+\t\t\t\t\t       resv_size,\n+\t\t\t\t\t       resv);\n+\t\ttfp_free((void *)resv);\n+\t\t/* On failure we still have to cleanup so we can only\n+\t\t * log that FW failed.\n+\t\t */\n+\t\tif (rc)\n+\t\t\tTFP_DRV_LOG(ERR,\n+\t\t\t\t    \"%s: Internal Flush error, module:%s\\n\",\n+\t\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t\t    tf_device_module_type_2_str(rm_db->type));\n+\t}\n+\n \tfor (i = 0; i < rm_db->num_entries; i++)\n \t\ttfp_free((void *)rm_db->db[i].pool);\n \n@@ -417,7 +644,7 @@ tf_rm_free_db(struct tf *tfp __rte_unused,\n int\n tf_rm_allocate(struct tf_rm_allocate_parms *parms)\n {\n-\tint rc = 0;\n+\tint rc;\n \tint id;\n \tuint32_t index;\n \tstruct tf_rm_new_db *rm_db;\n@@ -446,11 +673,12 @@ tf_rm_allocate(struct tf_rm_allocate_parms *parms)\n \n \tid = ba_alloc(rm_db->db[parms->db_index].pool);\n \tif (id == BA_FAIL) {\n+\t\trc = -ENOMEM;\n \t\tTFP_DRV_LOG(ERR,\n \t\t\t    \"%s: Allocation failed, rc:%s\\n\",\n \t\t\t    tf_dir_2_str(rm_db->dir),\n \t\t\t    strerror(-rc));\n-\t\treturn -ENOMEM;\n+\t\treturn rc;\n \t}\n \n \t/* Adjust for any non zero start value */\n@@ -475,7 +703,7 @@ tf_rm_allocate(struct tf_rm_allocate_parms *parms)\n int\n tf_rm_free(struct tf_rm_free_parms *parms)\n {\n-\tint rc = 0;\n+\tint rc;\n \tuint32_t adj_index;\n \tstruct tf_rm_new_db *rm_db;\n \tenum tf_rm_elem_cfg_type cfg_type;\n@@ -521,7 +749,7 @@ tf_rm_free(struct tf_rm_free_parms *parms)\n int\n tf_rm_is_allocated(struct tf_rm_is_allocated_parms *parms)\n {\n-\tint rc = 0;\n+\tint rc;\n \tuint32_t adj_index;\n \tstruct tf_rm_new_db *rm_db;\n \tenum tf_rm_elem_cfg_type cfg_type;\n@@ -565,7 +793,6 @@ tf_rm_is_allocated(struct tf_rm_is_allocated_parms *parms)\n int\n tf_rm_get_info(struct tf_rm_get_alloc_info_parms *parms)\n {\n-\tint rc = 0;\n \tstruct tf_rm_new_db *rm_db;\n \tenum tf_rm_elem_cfg_type cfg_type;\n \n@@ -579,15 +806,16 @@ tf_rm_get_info(struct tf_rm_get_alloc_info_parms *parms)\n \t    cfg_type != TF_RM_ELEM_CFG_PRIVATE)\n \t\treturn -ENOTSUP;\n \n-\tparms->info = &rm_db->db[parms->db_index].alloc;\n+\tmemcpy(parms->info,\n+\t       &rm_db->db[parms->db_index].alloc,\n+\t       sizeof(struct tf_rm_alloc_info));\n \n-\treturn rc;\n+\treturn 0;\n }\n \n int\n tf_rm_get_hcapi_type(struct tf_rm_get_hcapi_parms *parms)\n {\n-\tint rc = 0;\n \tstruct tf_rm_new_db *rm_db;\n \tenum tf_rm_elem_cfg_type cfg_type;\n \n@@ -603,5 +831,36 @@ tf_rm_get_hcapi_type(struct tf_rm_get_hcapi_parms *parms)\n \n \t*parms->hcapi_type = rm_db->db[parms->db_index].hcapi_type;\n \n+\treturn 0;\n+}\n+\n+int\n+tf_rm_get_inuse_count(struct tf_rm_get_inuse_count_parms *parms)\n+{\n+\tint rc = 0;\n+\tstruct tf_rm_new_db *rm_db;\n+\tenum tf_rm_elem_cfg_type cfg_type;\n+\n+\tTF_CHECK_PARMS2(parms, parms->rm_db);\n+\n+\trm_db = (struct tf_rm_new_db *)parms->rm_db;\n+\tcfg_type = rm_db->db[parms->db_index].cfg_type;\n+\n+\t/* Bail out if not controlled by RM */\n+\tif (cfg_type != TF_RM_ELEM_CFG_HCAPI &&\n+\t    cfg_type != TF_RM_ELEM_CFG_PRIVATE)\n+\t\treturn -ENOTSUP;\n+\n+\t/* Bail silently (no logging), if the pool is not valid there\n+\t * was no elements allocated for it.\n+\t */\n+\tif (rm_db->db[parms->db_index].pool == NULL) {\n+\t\t*parms->count = 0;\n+\t\treturn 0;\n+\t}\n+\n+\t*parms->count = ba_inuse_count(rm_db->db[parms->db_index].pool);\n+\n \treturn rc;\n+\n }\ndiff --git a/drivers/net/bnxt/tf_core/tf_rm_new.h b/drivers/net/bnxt/tf_core/tf_rm_new.h\nindex ebf38c4..a40296e 100644\n--- a/drivers/net/bnxt/tf_core/tf_rm_new.h\n+++ b/drivers/net/bnxt/tf_core/tf_rm_new.h\n@@ -8,6 +8,7 @@\n \n #include \"tf_core.h\"\n #include \"bitalloc.h\"\n+#include \"tf_device.h\"\n \n struct tf;\n \n@@ -57,9 +58,9 @@ struct tf_rm_new_entry {\n enum tf_rm_elem_cfg_type {\n \t/** No configuration */\n \tTF_RM_ELEM_CFG_NULL,\n-\t/** HCAPI 'controlled' */\n+\t/** HCAPI 'controlled', uses a Pool for internal storage */\n \tTF_RM_ELEM_CFG_HCAPI,\n-\t/** Private thus not HCAPI 'controlled' */\n+\t/** Private thus not HCAPI 'controlled', creates a Pool for storage */\n \tTF_RM_ELEM_CFG_PRIVATE,\n \t/**\n \t * Shared element thus it belongs to a shared FW Session and\n@@ -123,7 +124,11 @@ struct tf_rm_alloc_info {\n  */\n struct tf_rm_create_db_parms {\n \t/**\n-\t * [in] Receive or transmit direction\n+\t * [in] Device module type. Used for logging purposes.\n+\t */\n+\tenum tf_device_module_type type;\n+\t/**\n+\t * [in] Receive or transmit direction.\n \t */\n \tenum tf_dir dir;\n \t/**\n@@ -264,6 +269,25 @@ struct tf_rm_get_hcapi_parms {\n };\n \n /**\n+ * Get InUse count parameters for single element\n+ */\n+struct tf_rm_get_inuse_count_parms {\n+\t/**\n+\t * [in] RM DB Handle\n+\t */\n+\tvoid *rm_db;\n+\t/**\n+\t * [in] DB Index, indicates which DB entry to perform the\n+\t * action on.\n+\t */\n+\tuint16_t db_index;\n+\t/**\n+\t * [out] Pointer to the inuse count for the specified db_index\n+\t */\n+\tuint16_t *count;\n+};\n+\n+/**\n  * @page rm Resource Manager\n  *\n  * @ref tf_rm_create_db\n@@ -279,6 +303,8 @@ struct tf_rm_get_hcapi_parms {\n  * @ref tf_rm_get_info\n  *\n  * @ref tf_rm_get_hcapi_type\n+ *\n+ * @ref tf_rm_get_inuse_count\n  */\n \n /**\n@@ -396,4 +422,17 @@ int tf_rm_get_info(struct tf_rm_get_alloc_info_parms *parms);\n  */\n int tf_rm_get_hcapi_type(struct tf_rm_get_hcapi_parms *parms);\n \n+/**\n+ * Performs a lookup in the Resource Manager DB and retrives the\n+ * requested HCAPI RM type inuse count.\n+ *\n+ * [in] parms\n+ *   Pointer to get inuse parameters\n+ *\n+ * Returns\n+ *   - (0) if successful.\n+ *   - (-EINVAL) on failure.\n+ */\n+int tf_rm_get_inuse_count(struct tf_rm_get_inuse_count_parms *parms);\n+\n #endif /* TF_RM_NEW_H_ */\ndiff --git a/drivers/net/bnxt/tf_core/tf_session.c b/drivers/net/bnxt/tf_core/tf_session.c\nindex bac9c76..ab9e05f 100644\n--- a/drivers/net/bnxt/tf_core/tf_session.c\n+++ b/drivers/net/bnxt/tf_core/tf_session.c\n@@ -91,11 +91,11 @@ tf_session_open_session(struct tf *tfp,\n \t\t   parms->open_cfg->ctrl_chan_name,\n \t\t   TF_SESSION_NAME_MAX);\n \n-\trc = dev_bind(tfp,\n-\t\t      parms->open_cfg->device_type,\n-\t\t      session->shadow_copy,\n-\t\t      &parms->open_cfg->resources,\n-\t\t      &session->dev);\n+\trc = tf_dev_bind(tfp,\n+\t\t\t parms->open_cfg->device_type,\n+\t\t\t session->shadow_copy,\n+\t\t\t &parms->open_cfg->resources,\n+\t\t\t &session->dev);\n \t/* Logging handled by dev_bind */\n \tif (rc)\n \t\treturn rc;\n@@ -151,6 +151,8 @@ tf_session_close_session(struct tf *tfp,\n \t\treturn rc;\n \t}\n \n+\ttfs->ref_count--;\n+\n \t/* Record the session we're closing so the caller knows the\n \t * details.\n \t */\n@@ -164,6 +166,32 @@ 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+\t\t/* Log error */\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"Device unbind failed, rc:%s\\n\",\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@@ -173,23 +201,9 @@ tf_session_close_session(struct tf *tfp,\n \t\t\t    strerror(-rc));\n \t}\n \n-\ttfs->ref_count--;\n-\n-\t/* Final cleanup as we're last user of the session */\n-\tif (tfs->ref_count == 0) {\n-\t\t/* Unbind the device */\n-\t\trc = dev_unbind(tfp, tfd);\n-\t\tif (rc) {\n-\t\t\t/* Log error */\n-\t\t\tTFP_DRV_LOG(ERR,\n-\t\t\t\t    \"Device unbind failed, rc:%s\\n\",\n-\t\t\t\t    strerror(-rc));\n-\t\t}\n-\n-\t\ttfp_free(tfp->session->core_data);\n-\t\ttfp_free(tfp->session);\n-\t\ttfp->session = NULL;\n-\t}\n+\ttfp_free(tfp->session->core_data);\n+\ttfp_free(tfp->session);\n+\ttfp->session = NULL;\n \n \treturn 0;\n }\ndiff --git a/drivers/net/bnxt/tf_core/tf_tbl_type.c b/drivers/net/bnxt/tf_core/tf_tbl_type.c\nindex 51f8f07..bdf7d20 100644\n--- a/drivers/net/bnxt/tf_core/tf_tbl_type.c\n+++ b/drivers/net/bnxt/tf_core/tf_tbl_type.c\n@@ -51,11 +51,12 @@ tf_tbl_bind(struct tf *tfp,\n \t}\n \n \tdb_cfg.num_elements = parms->num_elements;\n+\tdb_cfg.type = TF_DEVICE_MODULE_TYPE_TABLE;\n+\tdb_cfg.num_elements = parms->num_elements;\n+\tdb_cfg.cfg = parms->cfg;\n \n \tfor (i = 0; i < TF_DIR_MAX; i++) {\n \t\tdb_cfg.dir = i;\n-\t\tdb_cfg.num_elements = parms->num_elements;\n-\t\tdb_cfg.cfg = parms->cfg;\n \t\tdb_cfg.alloc_cnt = parms->resources->tbl_cnt[i].cnt;\n \t\tdb_cfg.rm_db = &tbl_db[i];\n \t\trc = tf_rm_create_db(tfp, &db_cfg);\ndiff --git a/drivers/net/bnxt/tf_core/tf_tcam.c b/drivers/net/bnxt/tf_core/tf_tcam.c\nindex e0fac31..2f4441d 100644\n--- a/drivers/net/bnxt/tf_core/tf_tcam.c\n+++ b/drivers/net/bnxt/tf_core/tf_tcam.c\n@@ -54,11 +54,12 @@ tf_tcam_bind(struct tf *tfp,\n \t}\n \n \tdb_cfg.num_elements = parms->num_elements;\n+\tdb_cfg.type = TF_DEVICE_MODULE_TYPE_TCAM;\n+\tdb_cfg.num_elements = parms->num_elements;\n+\tdb_cfg.cfg = parms->cfg;\n \n \tfor (i = 0; i < TF_DIR_MAX; i++) {\n \t\tdb_cfg.dir = i;\n-\t\tdb_cfg.num_elements = parms->num_elements;\n-\t\tdb_cfg.cfg = parms->cfg;\n \t\tdb_cfg.alloc_cnt = parms->resources->tcam_cnt[i].cnt;\n \t\tdb_cfg.rm_db = &tcam_db[i];\n \t\trc = tf_rm_create_db(tfp, &db_cfg);\ndiff --git a/drivers/net/bnxt/tf_core/tf_tcam.h b/drivers/net/bnxt/tf_core/tf_tcam.h\nindex 67c3bcb..5090dfd 100644\n--- a/drivers/net/bnxt/tf_core/tf_tcam.h\n+++ b/drivers/net/bnxt/tf_core/tf_tcam.h\n@@ -147,6 +147,10 @@ struct tf_tcam_set_parms {\n \t */\n \tenum tf_tcam_tbl_type type;\n \t/**\n+\t * [in] Type of HCAPI\n+\t */\n+\tuint16_t hcapi_type;\n+\t/**\n \t * [in] Entry index to write to\n \t */\n \tuint32_t idx;\ndiff --git a/drivers/net/bnxt/tf_core/tf_util.c b/drivers/net/bnxt/tf_core/tf_util.c\nindex a901054..16c43eb 100644\n--- a/drivers/net/bnxt/tf_core/tf_util.c\n+++ b/drivers/net/bnxt/tf_core/tf_util.c\n@@ -7,8 +7,8 @@\n \n #include \"tf_util.h\"\n \n-const char\n-*tf_dir_2_str(enum tf_dir dir)\n+const char *\n+tf_dir_2_str(enum tf_dir dir)\n {\n \tswitch (dir) {\n \tcase TF_DIR_RX:\n@@ -20,8 +20,8 @@ const char\n \t}\n }\n \n-const char\n-*tf_ident_2_str(enum tf_identifier_type id_type)\n+const char *\n+tf_ident_2_str(enum tf_identifier_type id_type)\n {\n \tswitch (id_type) {\n \tcase TF_IDENT_TYPE_L2_CTXT:\n@@ -39,8 +39,8 @@ const char\n \t}\n }\n \n-const char\n-*tf_tcam_tbl_2_str(enum tf_tcam_tbl_type tcam_type)\n+const char *\n+tf_tcam_tbl_2_str(enum tf_tcam_tbl_type tcam_type)\n {\n \tswitch (tcam_type) {\n \tcase TF_TCAM_TBL_TYPE_L2_CTXT_TCAM:\n@@ -60,8 +60,8 @@ const char\n \t}\n }\n \n-const char\n-*tf_tbl_type_2_str(enum tf_tbl_type tbl_type)\n+const char *\n+tf_tbl_type_2_str(enum tf_tbl_type tbl_type)\n {\n \tswitch (tbl_type) {\n \tcase TF_TBL_TYPE_FULL_ACT_RECORD:\n@@ -131,8 +131,8 @@ const char\n \t}\n }\n \n-const char\n-*tf_em_tbl_type_2_str(enum tf_em_tbl_type em_type)\n+const char *\n+tf_em_tbl_type_2_str(enum tf_em_tbl_type em_type)\n {\n \tswitch (em_type) {\n \tcase TF_EM_TBL_TYPE_EM_RECORD:\n@@ -143,3 +143,38 @@ const char\n \t\treturn \"Invalid EM type\";\n \t}\n }\n+\n+const char *\n+tf_device_module_type_subtype_2_str(enum tf_device_module_type dm_type,\n+\t\t\t\t    uint16_t mod_type)\n+{\n+\tswitch (dm_type) {\n+\tcase TF_DEVICE_MODULE_TYPE_IDENTIFIER:\n+\t\treturn tf_ident_2_str(mod_type);\n+\tcase TF_DEVICE_MODULE_TYPE_TABLE:\n+\t\treturn tf_tcam_tbl_2_str(mod_type);\n+\tcase TF_DEVICE_MODULE_TYPE_TCAM:\n+\t\treturn tf_tbl_type_2_str(mod_type);\n+\tcase TF_DEVICE_MODULE_TYPE_EM:\n+\t\treturn tf_em_tbl_type_2_str(mod_type);\n+\tdefault:\n+\t\treturn \"Invalid Device Module type\";\n+\t}\n+}\n+\n+const char *\n+tf_device_module_type_2_str(enum tf_device_module_type dm_type)\n+{\n+\tswitch (dm_type) {\n+\tcase TF_DEVICE_MODULE_TYPE_IDENTIFIER:\n+\t\treturn \"Identifer\";\n+\tcase TF_DEVICE_MODULE_TYPE_TABLE:\n+\t\treturn \"Table\";\n+\tcase TF_DEVICE_MODULE_TYPE_TCAM:\n+\t\treturn \"TCAM\";\n+\tcase TF_DEVICE_MODULE_TYPE_EM:\n+\t\treturn \"EM\";\n+\tdefault:\n+\t\treturn \"Invalid Device Module type\";\n+\t}\n+}\ndiff --git a/drivers/net/bnxt/tf_core/tf_util.h b/drivers/net/bnxt/tf_core/tf_util.h\nindex ad8edaf..c97e2a6 100644\n--- a/drivers/net/bnxt/tf_core/tf_util.h\n+++ b/drivers/net/bnxt/tf_core/tf_util.h\n@@ -7,6 +7,7 @@\n #define _TF_UTIL_H_\n \n #include \"tf_core.h\"\n+#include \"tf_device.h\"\n \n /**\n  * Helper function converting direction to text string\n@@ -63,4 +64,35 @@ const char *tf_tbl_type_2_str(enum tf_tbl_type tbl_type);\n  */\n const char *tf_em_tbl_type_2_str(enum tf_em_tbl_type em_type);\n \n+/**\n+ * Helper function converting device module type and module type to\n+ * text string.\n+ *\n+ * [in] dm_type\n+ *   Device Module type\n+ *\n+ * [in] mod_type\n+ *   Module specific type\n+ *\n+ * Returns:\n+ *   Pointer to a char string holding the string for the EM type\n+ */\n+const char *tf_device_module_type_subtype_2_str\n+\t\t\t\t\t(enum tf_device_module_type dm_type,\n+\t\t\t\t\t uint16_t mod_type);\n+\n+/**\n+ * Helper function converting device module type to text string\n+ *\n+ * [in] dm_type\n+ *   Device Module type\n+ *\n+ * [in] mod_type\n+ *   Module specific type\n+ *\n+ * Returns:\n+ *   Pointer to a char string holding the string for the EM type\n+ */\n+const char *tf_device_module_type_2_str(enum tf_device_module_type dm_type);\n+\n #endif /* _TF_UTIL_H_ */\n",
    "prefixes": [
        "20/50"
    ]
}