get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 74653,
    "url": "https://patches.dpdk.org/api/patches/74653/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20200723111329.21855-13-somnath.kotur@broadcom.com/",
    "project": {
        "id": 1,
        "url": "https://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": "<20200723111329.21855-13-somnath.kotur@broadcom.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200723111329.21855-13-somnath.kotur@broadcom.com",
    "date": "2020-07-23T11:13:21",
    "name": "[12/20] net/bnxt: added shadow table capability with search",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "9a727c70f7873dd875ffef5e803dec496f1abf2f",
    "submitter": {
        "id": 908,
        "url": "https://patches.dpdk.org/api/people/908/?format=api",
        "name": "Somnath Kotur",
        "email": "somnath.kotur@broadcom.com"
    },
    "delegate": {
        "id": 1766,
        "url": "https://patches.dpdk.org/api/users/1766/?format=api",
        "username": "ajitkhaparde",
        "first_name": "Ajit",
        "last_name": "Khaparde",
        "email": "ajit.khaparde@broadcom.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20200723111329.21855-13-somnath.kotur@broadcom.com/mbox/",
    "series": [
        {
            "id": 11252,
            "url": "https://patches.dpdk.org/api/series/11252/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=11252",
            "date": "2020-07-23T11:13:09",
            "name": "bnxt patches",
            "version": 1,
            "mbox": "https://patches.dpdk.org/series/11252/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/74653/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/74653/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 BC2BBA0521;\n\tThu, 23 Jul 2020 13:21:25 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 9A0E21C06B;\n\tThu, 23 Jul 2020 13:20:05 +0200 (CEST)",
            "from relay.smtp.broadcom.com (relay.smtp.broadcom.com\n [192.19.232.149]) by dpdk.org (Postfix) with ESMTP id 2CD511BFEE\n for <dev@dpdk.org>; Thu, 23 Jul 2020 13:19:10 +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 7F44E1BD9B4;\n Thu, 23 Jul 2020 04:19:09 -0700 (PDT)"
        ],
        "DKIM-Filter": "OpenDKIM Filter v2.10.3 relay.smtp.broadcom.com 7F44E1BD9B4",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=broadcom.com;\n s=dkimrelay; t=1595503150;\n bh=Tz5kl5QHh3xoG+iTvvGsuKVp7Yhli6pZVaLnr1M+8IQ=;\n h=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n b=Yn4JogZO6IPMnkNjSiPa5BPyGPIgbWiEPQD67gGFP1uOTxSH7SK9wY45YB8DF8+7g\n suq418sFfxiTMkZNJfbEfKdIJdxWxYBCcOViDjuwOal/vbD6Phcog/P1rt/iL2+zja\n mJEZ1MyATNgyTu1Q1MbxkhWGcYopTC2l4HVHStjg=",
        "From": "Somnath Kotur <somnath.kotur@broadcom.com>",
        "To": "dev@dpdk.org",
        "Cc": "ferruh.yigit@intel.com",
        "Date": "Thu, 23 Jul 2020 16:43:21 +0530",
        "Message-Id": "<20200723111329.21855-13-somnath.kotur@broadcom.com>",
        "X-Mailer": "git-send-email 2.10.1.613.g2cc2e70",
        "In-Reply-To": "<20200723111329.21855-1-somnath.kotur@broadcom.com>",
        "References": "<20200723111329.21855-1-somnath.kotur@broadcom.com>",
        "Subject": "[dpdk-dev] [PATCH 12/20] net/bnxt: added shadow table capability\n\twith search",
        "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: Mike Baucom <michael.baucom@broadcom.com>\n\n- Added Index Table shadow tables for searching\n- Added Search API to allow reuse of Table entries\n\nSigned-off-by: Mike Baucom <michael.baucom@broadcom.com>\nReviewed-by: Farah Smith <farah.smith@broadcom.com>\n---\n drivers/net/bnxt/tf_core/tf_core.c        |  66 ++-\n drivers/net/bnxt/tf_core/tf_core.h        |  79 ++-\n drivers/net/bnxt/tf_core/tf_device_p4.c   |   2 +-\n drivers/net/bnxt/tf_core/tf_shadow_tbl.c  | 768 +++++++++++++++++++++++++++++-\n drivers/net/bnxt/tf_core/tf_shadow_tbl.h  | 124 ++---\n drivers/net/bnxt/tf_core/tf_shadow_tcam.c |   6 +\n drivers/net/bnxt/tf_core/tf_tbl.c         | 246 +++++++++-\n drivers/net/bnxt/tf_core/tf_tbl.h         |  22 +-\n drivers/net/bnxt/tf_core/tf_tcam.h        |   2 +-\n 9 files changed, 1211 insertions(+), 104 deletions(-)",
    "diff": "diff --git a/drivers/net/bnxt/tf_core/tf_core.c b/drivers/net/bnxt/tf_core/tf_core.c\nindex ca3280b..0dbde1d 100644\n--- a/drivers/net/bnxt/tf_core/tf_core.c\n+++ b/drivers/net/bnxt/tf_core/tf_core.c\n@@ -75,7 +75,6 @@ tf_open_session(struct tf *tfp,\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@@ -954,6 +953,71 @@ tf_alloc_tbl_entry(struct tf *tfp,\n }\n \n int\n+tf_search_tbl_entry(struct tf *tfp,\n+\t\t    struct tf_search_tbl_entry_parms *parms)\n+{\n+\tint rc;\n+\tstruct tf_session *tfs;\n+\tstruct tf_dev_info *dev;\n+\tstruct tf_tbl_alloc_search_parms sparms;\n+\n+\tTF_CHECK_PARMS2(tfp, parms);\n+\n+\t/* Retrieve the session information */\n+\trc = tf_session_get_session(tfp, &tfs);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"%s: Failed to lookup session, rc:%s\\n\",\n+\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\t/* Retrieve the device information */\n+\trc = tf_session_get_device(tfs, &dev);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"%s: Failed to lookup device, rc:%s\\n\",\n+\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\tif (dev->ops->tf_dev_alloc_search_tbl == NULL) {\n+\t\trc = -EOPNOTSUPP;\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"%s: Operation not supported, rc:%s\\n\",\n+\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\tmemset(&sparms, 0, sizeof(struct tf_tbl_alloc_search_parms));\n+\tsparms.dir = parms->dir;\n+\tsparms.type = parms->type;\n+\tsparms.result = parms->result;\n+\tsparms.result_sz_in_bytes = parms->result_sz_in_bytes;\n+\tsparms.alloc = parms->alloc;\n+\tsparms.tbl_scope_id = parms->tbl_scope_id;\n+\trc = dev->ops->tf_dev_alloc_search_tbl(tfp, &sparms);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"%s: TBL allocation failed, rc:%s\\n\",\n+\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\t/* Return the outputs from the search */\n+\tparms->hit = sparms.hit;\n+\tparms->search_status = sparms.search_status;\n+\tparms->ref_cnt = sparms.ref_cnt;\n+\tparms->idx = sparms.idx;\n+\n+\treturn 0;\n+}\n+\n+int\n tf_free_tbl_entry(struct tf *tfp,\n \t\t  struct tf_free_tbl_entry_parms *parms)\n {\ndiff --git a/drivers/net/bnxt/tf_core/tf_core.h b/drivers/net/bnxt/tf_core/tf_core.h\nindex 349a1f1..db10935 100644\n--- a/drivers/net/bnxt/tf_core/tf_core.h\n+++ b/drivers/net/bnxt/tf_core/tf_core.h\n@@ -291,9 +291,9 @@ enum tf_tcam_tbl_type {\n };\n \n /**\n- * TCAM SEARCH STATUS\n+ * SEARCH STATUS\n  */\n-enum tf_tcam_search_status {\n+enum tf_search_status {\n \t/** The entry was not found, but an idx was allocated if requested. */\n \tMISS,\n \t/** The entry was found, and the result/idx are valid */\n@@ -1011,7 +1011,7 @@ struct tf_search_tcam_entry_parms {\n \t/**\n \t * [out] Search result status (hit, miss, reject)\n \t */\n-\tenum tf_tcam_search_status search_status;\n+\tenum tf_search_status search_status;\n \t/**\n \t * [out] Current refcnt after allocation\n \t */\n@@ -1288,6 +1288,79 @@ int tf_free_tcam_entry(struct tf *tfp,\n /**\n  * tf_alloc_tbl_entry parameter definition\n  */\n+struct tf_search_tbl_entry_parms {\n+\t/**\n+\t * [in] Receive or transmit direction\n+\t */\n+\tenum tf_dir dir;\n+\t/**\n+\t * [in] Type of the allocation\n+\t */\n+\tenum tf_tbl_type type;\n+\t/**\n+\t * [in] Table scope identifier (ignored unless TF_TBL_TYPE_EXT)\n+\t */\n+\tuint32_t tbl_scope_id;\n+\t/**\n+\t * [in] Result data to search for\n+\t */\n+\tuint8_t *result;\n+\t/**\n+\t * [in] Result data size in bytes\n+\t */\n+\tuint16_t result_sz_in_bytes;\n+\t/**\n+\t * [in] Allocate on miss.\n+\t */\n+\tuint8_t alloc;\n+\t/**\n+\t * [out] Set if matching entry found\n+\t */\n+\tuint8_t hit;\n+\t/**\n+\t * [out] Search result status (hit, miss, reject)\n+\t */\n+\tenum tf_search_status search_status;\n+\t/**\n+\t * [out] Current ref count after allocation\n+\t */\n+\tuint16_t ref_cnt;\n+\t/**\n+\t * [out] Idx of allocated entry or found entry\n+\t */\n+\tuint32_t idx;\n+};\n+\n+/**\n+ * search Table Entry (experimental)\n+ *\n+ * This function searches the shadow copy of an index table for a matching\n+ * entry.  The result data must match for hit to be set.  Only TruFlow core\n+ * data is accessed.  If shadow_copy is not enabled, an error is returned.\n+ *\n+ * Implementation:\n+ *\n+ * A hash is performed on the result data and mappe3d to a shadow copy entry\n+ * where the result is populated.  If the result matches the entry, hit is set,\n+ * ref_cnt is incremented (if alloc), and the search status indicates what\n+ * action the caller can take regarding setting the entry.\n+ *\n+ * search status should be used as follows:\n+ * - On MISS, the caller should set the result into the returned index.\n+ *\n+ * - On REJECT, the caller should reject the flow since there are no resources.\n+ *\n+ * - On Hit, the matching index is returned to the caller.  Additionally, the\n+ *   ref_cnt is updated.\n+ *\n+ * Also returns success or failure code.\n+ */\n+int tf_search_tbl_entry(struct tf *tfp,\n+\t\t\tstruct tf_search_tbl_entry_parms *parms);\n+\n+/**\n+ * tf_alloc_tbl_entry parameter definition\n+ */\n struct tf_alloc_tbl_entry_parms {\n \t/**\n \t * [in] Receive or transmit direction\ndiff --git a/drivers/net/bnxt/tf_core/tf_device_p4.c b/drivers/net/bnxt/tf_core/tf_device_p4.c\nindex afb6098..fe8dec3 100644\n--- a/drivers/net/bnxt/tf_core/tf_device_p4.c\n+++ b/drivers/net/bnxt/tf_core/tf_device_p4.c\n@@ -126,7 +126,7 @@ const struct tf_dev_ops tf_dev_ops_p4 = {\n \t.tf_dev_alloc_ext_tbl = tf_tbl_ext_alloc,\n \t.tf_dev_free_tbl = tf_tbl_free,\n \t.tf_dev_free_ext_tbl = tf_tbl_ext_free,\n-\t.tf_dev_alloc_search_tbl = NULL,\n+\t.tf_dev_alloc_search_tbl = tf_tbl_alloc_search,\n \t.tf_dev_set_tbl = tf_tbl_set,\n \t.tf_dev_set_ext_tbl = tf_tbl_ext_common_set,\n \t.tf_dev_get_tbl = tf_tbl_get,\ndiff --git a/drivers/net/bnxt/tf_core/tf_shadow_tbl.c b/drivers/net/bnxt/tf_core/tf_shadow_tbl.c\nindex 8f2b6de..019a26e 100644\n--- a/drivers/net/bnxt/tf_core/tf_shadow_tbl.c\n+++ b/drivers/net/bnxt/tf_core/tf_shadow_tbl.c\n@@ -3,61 +3,785 @@\n  * All rights reserved.\n  */\n \n-#include <rte_common.h>\n-\n+#include \"tf_common.h\"\n+#include \"tf_util.h\"\n+#include \"tfp.h\"\n+#include \"tf_core.h\"\n #include \"tf_shadow_tbl.h\"\n+#include \"tf_hash.h\"\n \n /**\n- * Shadow table DB element\n+ * The implementation includes 3 tables per table table type.\n+ * - hash table\n+ *   - sized so that a minimum of 4 slots per shadow entry are available to\n+ *   minimize the likelihood of collisions.\n+ * - shadow key table\n+ *   - sized to the number of entries requested and is directly indexed\n+ *   - the index is zero based and is the table index - the base address\n+ *   - the data associated with the entry is stored in the key table.\n+ *   - The stored key is actually the data associated with the entry.\n+ * - shadow result table\n+ *   - the result table is stored separately since it only needs to be accessed\n+ *   when the key matches.\n+ *   - the result has a back pointer to the hash table via the hb handle.  The\n+ *   hb handle is a 32 bit represention of the hash with a valid bit, bucket\n+ *   element index, and the hash index.  It is necessary to store the hb handle\n+ *   with the result since subsequent removes only provide the table index.\n+ *\n+ * - Max entries is limited in the current implementation since bit 15 is the\n+ *   valid bit in the hash table.\n+ * - A 16bit hash is calculated and masked based on the number of entries\n+ * - 64b wide bucket is used and broken into 4x16bit elements.\n+ *   This decision is based on quicker bucket scanning to determine if any\n+ *   elements are in use.\n+ * - bit 15 of each bucket element is the valid, this is done to prevent having\n+ *   to read the larger key/result data for determining VALID.  It also aids\n+ *   in the more efficient scanning of the bucket for slot usage.\n  */\n-struct tf_shadow_tbl_element {\n-\t/**\n-\t * Hash table\n-\t */\n-\tvoid *hash;\n \n-\t/**\n-\t * Reference count, array of number of table type entries\n-\t */\n-\tuint16_t *ref_count;\n+/*\n+ * The maximum number of shadow entries supported.  The value also doubles as\n+ * the maximum number of hash buckets.  There are only 15 bits of data per\n+ * bucket to point to the shadow tables.\n+ */\n+#define TF_SHADOW_ENTRIES_MAX (1 << 15)\n+\n+/* The number of elements(BE) per hash bucket (HB) */\n+#define TF_SHADOW_HB_NUM_ELEM (4)\n+#define TF_SHADOW_BE_VALID (1 << 15)\n+#define TF_SHADOW_BE_IS_VALID(be) (((be) & TF_SHADOW_BE_VALID) != 0)\n+\n+/**\n+ * The hash bucket handle is 32b\n+ * - bit 31, the Valid bit\n+ * - bit 29-30, the element\n+ * - bits 0-15, the hash idx (is masked based on the allocated size)\n+ */\n+#define TF_SHADOW_HB_HANDLE_IS_VALID(hndl) (((hndl) & (1 << 31)) != 0)\n+#define TF_SHADOW_HB_HANDLE_CREATE(idx, be) ((1 << 31) | \\\n+\t\t\t\t\t     ((be) << 29) | (idx))\n+\n+#define TF_SHADOW_HB_HANDLE_BE_GET(hdl) (((hdl) >> 29) & \\\n+\t\t\t\t\t (TF_SHADOW_HB_NUM_ELEM - 1))\n+\n+#define TF_SHADOW_HB_HANDLE_HASH_GET(ctxt, hdl)((hdl) & \\\n+\t\t\t\t\t\t(ctxt)->hash_ctxt.hid_mask)\n+\n+/**\n+ * The idx provided by the caller is within a region, so currently the base is\n+ * either added or subtracted from the idx to ensure it can be used as a\n+ * compressed index\n+ */\n+\n+/* Convert the table index to a shadow index */\n+#define TF_SHADOW_IDX_TO_SHIDX(ctxt, idx) ((idx) - \\\n+\t\t\t\t\t   (ctxt)->shadow_ctxt.base_addr)\n+\n+/* Convert the shadow index to a tbl index */\n+#define TF_SHADOW_SHIDX_TO_IDX(ctxt, idx) ((idx) + \\\n+\t\t\t\t\t   (ctxt)->shadow_ctxt.base_addr)\n+\n+/* Simple helper masks for clearing en element from the bucket */\n+#define TF_SHADOW_BE0_MASK_CLEAR(hb) ((hb) & 0xffffffffffff0000ull)\n+#define TF_SHADOW_BE1_MASK_CLEAR(hb) ((hb) & 0xffffffff0000ffffull)\n+#define TF_SHADOW_BE2_MASK_CLEAR(hb) ((hb) & 0xffff0000ffffffffull)\n+#define TF_SHADOW_BE3_MASK_CLEAR(hb) ((hb) & 0x0000ffffffffffffull)\n+\n+/**\n+ * This should be coming from external, but for now it is assumed that no key\n+ * is greater than 512 bits (64B).  This makes allocation of the key table\n+ * easier without having to allocate on the fly.\n+ */\n+#define TF_SHADOW_MAX_KEY_SZ 64\n+\n+/*\n+ * Local only defines for the internal data.\n+ */\n+\n+/**\n+ * tf_shadow_tbl_shadow_key_entry is the key entry of the key table.\n+ * The key stored in the table is the result data of the index table.\n+ */\n+struct tf_shadow_tbl_shadow_key_entry {\n+\tuint8_t key[TF_SHADOW_MAX_KEY_SZ];\n+};\n+\n+/**\n+ * tf_shadow_tbl_shadow_result_entry is the result table entry.\n+ * The result table writes are broken into two phases:\n+ * - The search phase, which stores the hb_handle and key size and\n+ * - The set phase, which writes the refcnt\n+ */\n+struct tf_shadow_tbl_shadow_result_entry {\n+\tuint16_t key_size;\n+\tuint32_t refcnt;\n+\tuint32_t hb_handle;\n+};\n+\n+/**\n+ * tf_shadow_tbl_shadow_ctxt holds all information for accessing the key and\n+ * result tables.\n+ */\n+struct tf_shadow_tbl_shadow_ctxt {\n+\tstruct tf_shadow_tbl_shadow_key_entry *sh_key_tbl;\n+\tstruct tf_shadow_tbl_shadow_result_entry *sh_res_tbl;\n+\tuint32_t base_addr;\n+\tuint16_t num_entries;\n+\tuint16_t alloc_idx;\n+};\n+\n+/**\n+ * tf_shadow_tbl_hash_ctxt holds all information related to accessing the hash\n+ * table.\n+ */\n+struct tf_shadow_tbl_hash_ctxt {\n+\tuint64_t *hashtbl;\n+\tuint16_t hid_mask;\n+\tuint16_t hash_entries;\n };\n \n /**\n- * Shadow table DB definition\n+ * tf_shadow_tbl_ctxt holds the hash and shadow tables for the current shadow\n+ * table db.  This structure is per table table type as each table table has\n+ * it's own shadow and hash table.\n+ */\n+struct tf_shadow_tbl_ctxt {\n+\tstruct tf_shadow_tbl_shadow_ctxt shadow_ctxt;\n+\tstruct tf_shadow_tbl_hash_ctxt hash_ctxt;\n+};\n+\n+/**\n+ * tf_shadow_tbl_db is the allocated db structure returned as an opaque\n+ * void * pointer to the caller during create db.  It holds the pointers for\n+ * each table associated with the db.\n  */\n struct tf_shadow_tbl_db {\n-\t/**\n-\t * The DB consists of an array of elements\n-\t */\n-\tstruct tf_shadow_tbl_element *db;\n+\t/* Each context holds the shadow and hash table information */\n+\tstruct tf_shadow_tbl_ctxt *ctxt[TF_TBL_TYPE_MAX];\n };\n \n+/**\n+ * Simple routine that decides what table types can be searchable.\n+ *\n+ */\n+static int tf_shadow_tbl_is_searchable(enum tf_tbl_type type)\n+{\n+\tint rc = 0;\n+\n+\tswitch (type) {\n+\tcase TF_TBL_TYPE_ACT_ENCAP_8B:\n+\tcase TF_TBL_TYPE_ACT_ENCAP_16B:\n+\tcase TF_TBL_TYPE_ACT_ENCAP_32B:\n+\tcase TF_TBL_TYPE_ACT_ENCAP_64B:\n+\tcase TF_TBL_TYPE_ACT_SP_SMAC:\n+\tcase TF_TBL_TYPE_ACT_SP_SMAC_IPV4:\n+\tcase TF_TBL_TYPE_ACT_SP_SMAC_IPV6:\n+\tcase TF_TBL_TYPE_ACT_MODIFY_IPV4:\n+\tcase TF_TBL_TYPE_ACT_MODIFY_SPORT:\n+\tcase TF_TBL_TYPE_ACT_MODIFY_DPORT:\n+\t\trc = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\trc = 0;\n+\t\tbreak;\n+\t};\n+\n+\treturn rc;\n+}\n+\n+/**\n+ * Returns the number of entries in the contexts shadow table.\n+ */\n+static inline uint16_t\n+tf_shadow_tbl_sh_num_entries_get(struct tf_shadow_tbl_ctxt *ctxt)\n+{\n+\treturn ctxt->shadow_ctxt.num_entries;\n+}\n+\n+/**\n+ * Compare the give key with the key in the shadow table.\n+ *\n+ * Returns 0 if the keys match\n+ */\n+static int\n+tf_shadow_tbl_key_cmp(struct tf_shadow_tbl_ctxt *ctxt,\n+\t\t      uint8_t *key,\n+\t\t      uint16_t sh_idx,\n+\t\t      uint16_t size)\n+{\n+\tif (size != ctxt->shadow_ctxt.sh_res_tbl[sh_idx].key_size ||\n+\t    sh_idx >= tf_shadow_tbl_sh_num_entries_get(ctxt) || !key)\n+\t\treturn -1;\n+\n+\treturn memcmp(key, ctxt->shadow_ctxt.sh_key_tbl[sh_idx].key, size);\n+}\n+\n+/**\n+ * Free the memory associated with the context.\n+ */\n+static void\n+tf_shadow_tbl_ctxt_delete(struct tf_shadow_tbl_ctxt *ctxt)\n+{\n+\tif (!ctxt)\n+\t\treturn;\n+\n+\ttfp_free(ctxt->hash_ctxt.hashtbl);\n+\ttfp_free(ctxt->shadow_ctxt.sh_key_tbl);\n+\ttfp_free(ctxt->shadow_ctxt.sh_res_tbl);\n+}\n+\n+/**\n+ * The TF Shadow TBL context is per TBL and holds all information relating to\n+ * managing the shadow and search capability.  This routine allocated data that\n+ * needs to be deallocated by the tf_shadow_tbl_ctxt_delete prior when deleting\n+ * the shadow db.\n+ */\n+static int\n+tf_shadow_tbl_ctxt_create(struct tf_shadow_tbl_ctxt *ctxt,\n+\t\t\t  uint16_t num_entries,\n+\t\t\t  uint16_t base_addr)\n+{\n+\tstruct tfp_calloc_parms cparms;\n+\tuint16_t hash_size = 1;\n+\tuint16_t hash_mask;\n+\tint rc;\n+\n+\t/* Hash table is a power of two that holds the number of entries */\n+\tif (num_entries > TF_SHADOW_ENTRIES_MAX) {\n+\t\tTFP_DRV_LOG(ERR, \"Too many entries for shadow %d > %d\\n\",\n+\t\t\t    num_entries,\n+\t\t\t    TF_SHADOW_ENTRIES_MAX);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\twhile (hash_size < num_entries)\n+\t\thash_size = hash_size << 1;\n+\n+\thash_mask = hash_size - 1;\n+\n+\t/* Allocate the hash table */\n+\tcparms.nitems = hash_size;\n+\tcparms.size = sizeof(uint64_t);\n+\tcparms.alignment = 0;\n+\trc = tfp_calloc(&cparms);\n+\tif (rc)\n+\t\tgoto error;\n+\tctxt->hash_ctxt.hashtbl = cparms.mem_va;\n+\tctxt->hash_ctxt.hid_mask = hash_mask;\n+\tctxt->hash_ctxt.hash_entries = hash_size;\n+\n+\t/* allocate the shadow tables */\n+\t/* allocate the shadow key table */\n+\tcparms.nitems = num_entries;\n+\tcparms.size = sizeof(struct tf_shadow_tbl_shadow_key_entry);\n+\tcparms.alignment = 0;\n+\trc = tfp_calloc(&cparms);\n+\tif (rc)\n+\t\tgoto error;\n+\tctxt->shadow_ctxt.sh_key_tbl = cparms.mem_va;\n+\n+\t/* allocate the shadow result table */\n+\tcparms.nitems = num_entries;\n+\tcparms.size = sizeof(struct tf_shadow_tbl_shadow_result_entry);\n+\tcparms.alignment = 0;\n+\trc = tfp_calloc(&cparms);\n+\tif (rc)\n+\t\tgoto error;\n+\tctxt->shadow_ctxt.sh_res_tbl = cparms.mem_va;\n+\n+\tctxt->shadow_ctxt.num_entries = num_entries;\n+\tctxt->shadow_ctxt.base_addr = base_addr;\n+\n+\treturn 0;\n+error:\n+\ttf_shadow_tbl_ctxt_delete(ctxt);\n+\n+\treturn -ENOMEM;\n+}\n+\n+/**\n+ * Get a shadow table context given the db and the table type\n+ */\n+static struct tf_shadow_tbl_ctxt *\n+tf_shadow_tbl_ctxt_get(struct tf_shadow_tbl_db *shadow_db,\n+\t\t       enum tf_tbl_type type)\n+{\n+\tif (type >= TF_TBL_TYPE_MAX ||\n+\t    !shadow_db ||\n+\t    !shadow_db->ctxt[type])\n+\t\treturn NULL;\n+\n+\treturn shadow_db->ctxt[type];\n+}\n+\n+/**\n+ * Sets the hash entry into the table given the table context, hash bucket\n+ * handle, and shadow index.\n+ */\n+static inline int\n+tf_shadow_tbl_set_hash_entry(struct tf_shadow_tbl_ctxt *ctxt,\n+\t\t\t     uint32_t hb_handle,\n+\t\t\t     uint16_t sh_idx)\n+{\n+\tuint16_t hid = TF_SHADOW_HB_HANDLE_HASH_GET(ctxt, hb_handle);\n+\tuint16_t be = TF_SHADOW_HB_HANDLE_BE_GET(hb_handle);\n+\tuint64_t entry = sh_idx | TF_SHADOW_BE_VALID;\n+\n+\tif (hid >= ctxt->hash_ctxt.hash_entries)\n+\t\treturn -EINVAL;\n+\n+\tctxt->hash_ctxt.hashtbl[hid] |= entry << (be * 16);\n+\treturn 0;\n+}\n+\n+/**\n+ * Clears the hash entry given the TBL context and hash bucket handle.\n+ */\n+static inline void\n+tf_shadow_tbl_clear_hash_entry(struct tf_shadow_tbl_ctxt *ctxt,\n+\t\t\t       uint32_t hb_handle)\n+{\n+\tuint16_t hid, be;\n+\tuint64_t *bucket;\n+\n+\tif (!TF_SHADOW_HB_HANDLE_IS_VALID(hb_handle))\n+\t\treturn;\n+\n+\thid = TF_SHADOW_HB_HANDLE_HASH_GET(ctxt, hb_handle);\n+\tbe = TF_SHADOW_HB_HANDLE_BE_GET(hb_handle);\n+\tbucket = &ctxt->hash_ctxt.hashtbl[hid];\n+\n+\tswitch (be) {\n+\tcase 0:\n+\t\t*bucket = TF_SHADOW_BE0_MASK_CLEAR(*bucket);\n+\t\tbreak;\n+\tcase 1:\n+\t\t*bucket = TF_SHADOW_BE1_MASK_CLEAR(*bucket);\n+\t\tbreak;\n+\tcase 2:\n+\t\t*bucket = TF_SHADOW_BE2_MASK_CLEAR(*bucket);\n+\t\tbreak;\n+\tcase 3:\n+\t\t*bucket = TF_SHADOW_BE2_MASK_CLEAR(*bucket);\n+\t\tbreak;\n+\tdefault:\n+\t\t/*\n+\t\t * Since the BE_GET masks non-inclusive bits, this will not\n+\t\t * happen.\n+\t\t */\n+\t\tbreak;\n+\t}\n+}\n+\n+/**\n+ * Clears the shadow key and result entries given the table context and\n+ * shadow index.\n+ */\n+static void\n+tf_shadow_tbl_clear_sh_entry(struct tf_shadow_tbl_ctxt *ctxt,\n+\t\t\t     uint16_t sh_idx)\n+{\n+\tstruct tf_shadow_tbl_shadow_key_entry *sk_entry;\n+\tstruct tf_shadow_tbl_shadow_result_entry *sr_entry;\n+\n+\tif (sh_idx >= tf_shadow_tbl_sh_num_entries_get(ctxt))\n+\t\treturn;\n+\n+\tsk_entry = &ctxt->shadow_ctxt.sh_key_tbl[sh_idx];\n+\tsr_entry = &ctxt->shadow_ctxt.sh_res_tbl[sh_idx];\n+\n+\t/*\n+\t * memset key/result to zero for now, possibly leave the data alone\n+\t * in the future and rely on the valid bit in the hash table.\n+\t */\n+\tmemset(sk_entry, 0, sizeof(struct tf_shadow_tbl_shadow_key_entry));\n+\tmemset(sr_entry, 0, sizeof(struct tf_shadow_tbl_shadow_result_entry));\n+}\n+\n+/**\n+ * Binds the allocated tbl index with the hash and shadow tables.\n+ * The entry will be incomplete until the set has happened with the result\n+ * data.\n+ */\n int\n-tf_shadow_tbl_create_db(struct tf_shadow_tbl_create_db_parms *parms __rte_unused)\n+tf_shadow_tbl_bind_index(struct tf_shadow_tbl_bind_index_parms *parms)\n {\n+\tint rc;\n+\tuint16_t idx, len;\n+\tstruct tf_shadow_tbl_ctxt *ctxt;\n+\tstruct tf_shadow_tbl_db *shadow_db;\n+\tstruct tf_shadow_tbl_shadow_key_entry *sk_entry;\n+\tstruct tf_shadow_tbl_shadow_result_entry *sr_entry;\n+\n+\tif (!parms || !TF_SHADOW_HB_HANDLE_IS_VALID(parms->hb_handle) ||\n+\t    !parms->data) {\n+\t\tTFP_DRV_LOG(ERR, \"Invalid parms\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tshadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;\n+\tctxt = tf_shadow_tbl_ctxt_get(shadow_db, parms->type);\n+\tif (!ctxt) {\n+\t\tTFP_DRV_LOG(DEBUG, \"%s no ctxt for table\\n\",\n+\t\t\t    tf_tbl_type_2_str(parms->type));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tidx = TF_SHADOW_IDX_TO_SHIDX(ctxt, parms->idx);\n+\tlen = parms->data_sz_in_bytes;\n+\tif (idx >= tf_shadow_tbl_sh_num_entries_get(ctxt) ||\n+\t    len > TF_SHADOW_MAX_KEY_SZ) {\n+\t\tTFP_DRV_LOG(ERR, \"%s:%s Invalid len (%d) > %d || oob idx %d\\n\",\n+\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t    tf_tbl_type_2_str(parms->type),\n+\t\t\t    len,\n+\t\t\t    TF_SHADOW_MAX_KEY_SZ, idx);\n+\n+\t\treturn -EINVAL;\n+\t}\n+\n+\trc = tf_shadow_tbl_set_hash_entry(ctxt, parms->hb_handle, idx);\n+\tif (rc)\n+\t\treturn -EINVAL;\n+\n+\tsk_entry = &ctxt->shadow_ctxt.sh_key_tbl[idx];\n+\tsr_entry = &ctxt->shadow_ctxt.sh_res_tbl[idx];\n+\n+\t/* For tables, the data is the key */\n+\tmemcpy(sk_entry->key, parms->data, len);\n+\n+\t/* Write the result table */\n+\tsr_entry->key_size = len;\n+\tsr_entry->hb_handle = parms->hb_handle;\n+\tsr_entry->refcnt = 1;\n+\n \treturn 0;\n }\n \n+/**\n+ * Deletes hash/shadow information if no more references.\n+ *\n+ * Returns 0 - The caller should delete the table entry in hardware.\n+ * Returns non-zero - The number of references to the entry\n+ */\n int\n-tf_shadow_tbl_free_db(struct tf_shadow_tbl_free_db_parms *parms __rte_unused)\n+tf_shadow_tbl_remove(struct tf_shadow_tbl_remove_parms *parms)\n {\n+\tuint16_t idx;\n+\tuint32_t hb_handle;\n+\tstruct tf_shadow_tbl_ctxt *ctxt;\n+\tstruct tf_shadow_tbl_db *shadow_db;\n+\tstruct tf_tbl_free_parms *fparms;\n+\tstruct tf_shadow_tbl_shadow_result_entry *sr_entry;\n+\n+\tif (!parms || !parms->fparms) {\n+\t\tTFP_DRV_LOG(ERR, \"Invalid parms\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tfparms = parms->fparms;\n+\tif (!tf_shadow_tbl_is_searchable(fparms->type))\n+\t\treturn 0;\n+\t/*\n+\t * Initialize the ref count to zero.  The default would be to remove\n+\t * the entry.\n+\t */\n+\tfparms->ref_cnt = 0;\n+\n+\tshadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;\n+\tctxt = tf_shadow_tbl_ctxt_get(shadow_db, fparms->type);\n+\tif (!ctxt) {\n+\t\tTFP_DRV_LOG(DEBUG, \"%s no ctxt for table\\n\",\n+\t\t\t    tf_tbl_type_2_str(fparms->type));\n+\t\treturn 0;\n+\t}\n+\n+\tidx = TF_SHADOW_IDX_TO_SHIDX(ctxt, fparms->idx);\n+\tif (idx >= tf_shadow_tbl_sh_num_entries_get(ctxt)) {\n+\t\tTFP_DRV_LOG(DEBUG, \"%s %d >= %d\\n\",\n+\t\t\t    tf_tbl_type_2_str(fparms->type),\n+\t\t\t    fparms->idx,\n+\t\t\t    tf_shadow_tbl_sh_num_entries_get(ctxt));\n+\t\treturn 0;\n+\t}\n+\n+\tsr_entry = &ctxt->shadow_ctxt.sh_res_tbl[idx];\n+\tif (sr_entry->refcnt <= 1) {\n+\t\thb_handle = sr_entry->hb_handle;\n+\t\ttf_shadow_tbl_clear_hash_entry(ctxt, hb_handle);\n+\t\ttf_shadow_tbl_clear_sh_entry(ctxt, idx);\n+\t} else {\n+\t\tsr_entry->refcnt--;\n+\t\tfparms->ref_cnt = sr_entry->refcnt;\n+\t}\n+\n \treturn 0;\n }\n \n int\n-tf_shadow_tbl_search(struct tf_shadow_tbl_search_parms *parms __rte_unused)\n+tf_shadow_tbl_search(struct tf_shadow_tbl_search_parms *parms)\n {\n+\tuint16_t len;\n+\tuint64_t bucket;\n+\tuint32_t i, hid32;\n+\tstruct tf_shadow_tbl_ctxt *ctxt;\n+\tstruct tf_shadow_tbl_db *shadow_db;\n+\tuint16_t hid16, hb_idx, hid_mask, shtbl_idx, shtbl_key, be_valid;\n+\tstruct tf_tbl_alloc_search_parms *sparms;\n+\tuint32_t be_avail = TF_SHADOW_HB_NUM_ELEM;\n+\n+\tif (!parms || !parms->sparms) {\n+\t\tTFP_DRV_LOG(ERR, \"tbl search with invalid parms\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsparms = parms->sparms;\n+\t/* Check that caller was supposed to call search */\n+\tif (!tf_shadow_tbl_is_searchable(sparms->type))\n+\t\treturn -EINVAL;\n+\n+\t/* Initialize return values to invalid */\n+\tsparms->hit = 0;\n+\tsparms->search_status = REJECT;\n+\tparms->hb_handle = 0;\n+\tsparms->ref_cnt = 0;\n+\n+\tshadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;\n+\tctxt = tf_shadow_tbl_ctxt_get(shadow_db, sparms->type);\n+\tif (!ctxt) {\n+\t\tTFP_DRV_LOG(ERR, \"%s Unable to get tbl mgr context\\n\",\n+\t\t\t    tf_tbl_type_2_str(sparms->type));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tlen = sparms->result_sz_in_bytes;\n+\tif (len > TF_SHADOW_MAX_KEY_SZ || !sparms->result || !len) {\n+\t\tTFP_DRV_LOG(ERR, \"%s:%s Invalid parms %d : %p\\n\",\n+\t\t\t    tf_dir_2_str(sparms->dir),\n+\t\t\t    tf_tbl_type_2_str(sparms->type),\n+\t\t\t    len,\n+\t\t\t    sparms->result);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/*\n+\t * Calculate the crc32\n+\t * Fold it to create a 16b value\n+\t * Reduce it to fit the table\n+\t */\n+\thid32 = tf_hash_calc_crc32(sparms->result, len);\n+\thid16 = (uint16_t)(((hid32 >> 16) & 0xffff) ^ (hid32 & 0xffff));\n+\thid_mask = ctxt->hash_ctxt.hid_mask;\n+\thb_idx = hid16 & hid_mask;\n+\n+\tbucket = ctxt->hash_ctxt.hashtbl[hb_idx];\n+\tif (!bucket) {\n+\t\t/* empty bucket means a miss and available entry */\n+\t\tsparms->search_status = MISS;\n+\t\tparms->hb_handle = TF_SHADOW_HB_HANDLE_CREATE(hb_idx, 0);\n+\t\tsparms->idx = 0;\n+\t\treturn 0;\n+\t}\n+\n+\t/* Set the avail to max so we can detect when there is an avail entry */\n+\tbe_avail = TF_SHADOW_HB_NUM_ELEM;\n+\tfor (i = 0; i < TF_SHADOW_HB_NUM_ELEM; i++) {\n+\t\tshtbl_idx = (uint16_t)((bucket >> (i * 16)) & 0xffff);\n+\t\tbe_valid = TF_SHADOW_BE_IS_VALID(shtbl_idx);\n+\t\tif (!be_valid) {\n+\t\t\t/* The element is avail, keep going */\n+\t\t\tbe_avail = i;\n+\t\t\tcontinue;\n+\t\t}\n+\t\t/* There is a valid entry, compare it */\n+\t\tshtbl_key = shtbl_idx & ~TF_SHADOW_BE_VALID;\n+\t\tif (!tf_shadow_tbl_key_cmp(ctxt,\n+\t\t\t\t\t   sparms->result,\n+\t\t\t\t\t   shtbl_key,\n+\t\t\t\t\t   len)) {\n+\t\t\t/*\n+\t\t\t * It matches, increment the ref count if the caller\n+\t\t\t * requested allocation and return the info\n+\t\t\t */\n+\t\t\tif (sparms->alloc)\n+\t\t\t\tctxt->shadow_ctxt.sh_res_tbl[shtbl_key].refcnt =\n+\t\t\tctxt->shadow_ctxt.sh_res_tbl[shtbl_key].refcnt + 1;\n+\n+\t\t\tsparms->hit = 1;\n+\t\t\tsparms->search_status = HIT;\n+\t\t\tparms->hb_handle =\n+\t\t\t\tTF_SHADOW_HB_HANDLE_CREATE(hb_idx, i);\n+\t\t\tsparms->idx = TF_SHADOW_SHIDX_TO_IDX(ctxt, shtbl_key);\n+\t\t\tsparms->ref_cnt =\n+\t\t\t\tctxt->shadow_ctxt.sh_res_tbl[shtbl_key].refcnt;\n+\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\t/* No hits, return avail entry if exists */\n+\tif (be_avail < TF_SHADOW_HB_NUM_ELEM) {\n+\t\t/*\n+\t\t * There is an available hash entry, so return MISS and the\n+\t\t * hash handle for the subsequent bind.\n+\t\t */\n+\t\tparms->hb_handle = TF_SHADOW_HB_HANDLE_CREATE(hb_idx, be_avail);\n+\t\tsparms->search_status = MISS;\n+\t\tsparms->hit = 0;\n+\t\tsparms->idx = 0;\n+\t} else {\n+\t\t/* No room for the entry in the hash table, must REJECT */\n+\t\tsparms->search_status = REJECT;\n+\t}\n+\n \treturn 0;\n }\n \n int\n-tf_shadow_tbl_insert(struct tf_shadow_tbl_insert_parms *parms __rte_unused)\n+tf_shadow_tbl_insert(struct tf_shadow_tbl_insert_parms *parms)\n {\n+\tuint16_t idx;\n+\tstruct tf_shadow_tbl_ctxt *ctxt;\n+\tstruct tf_tbl_set_parms *sparms;\n+\tstruct tf_shadow_tbl_db *shadow_db;\n+\tstruct tf_shadow_tbl_shadow_result_entry *sr_entry;\n+\n+\tif (!parms || !parms->sparms) {\n+\t\tTFP_DRV_LOG(ERR, \"Null parms\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsparms = parms->sparms;\n+\tif (!sparms->data || !sparms->data_sz_in_bytes) {\n+\t\tTFP_DRV_LOG(ERR, \"%s:%s No result to set.\\n\",\n+\t\t\t    tf_dir_2_str(sparms->dir),\n+\t\t\t    tf_tbl_type_2_str(sparms->type));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tshadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;\n+\tctxt = tf_shadow_tbl_ctxt_get(shadow_db, sparms->type);\n+\tif (!ctxt) {\n+\t\t/* We aren't tracking this table, so return success */\n+\t\tTFP_DRV_LOG(DEBUG, \"%s Unable to get tbl mgr context\\n\",\n+\t\t\t    tf_tbl_type_2_str(sparms->type));\n+\t\treturn 0;\n+\t}\n+\n+\tidx = TF_SHADOW_IDX_TO_SHIDX(ctxt, sparms->idx);\n+\tif (idx >= tf_shadow_tbl_sh_num_entries_get(ctxt)) {\n+\t\tTFP_DRV_LOG(ERR, \"%s:%s Invalid idx(0x%x)\\n\",\n+\t\t\t    tf_dir_2_str(sparms->dir),\n+\t\t\t    tf_tbl_type_2_str(sparms->type),\n+\t\t\t    sparms->idx);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* Write the result table, the key/hash has been written already */\n+\tsr_entry = &ctxt->shadow_ctxt.sh_res_tbl[idx];\n+\n+\t/*\n+\t * If the handle is not valid, the bind was never called.  We aren't\n+\t * tracking this entry.\n+\t */\n+\tif (!TF_SHADOW_HB_HANDLE_IS_VALID(sr_entry->hb_handle))\n+\t\treturn 0;\n+\n+\tsr_entry->refcnt = 1;\n+\n \treturn 0;\n }\n \n int\n-tf_shadow_tbl_remove(struct tf_shadow_tbl_remove_parms *parms __rte_unused)\n+tf_shadow_tbl_free_db(struct tf_shadow_tbl_free_db_parms *parms)\n {\n+\tstruct tf_shadow_tbl_db *shadow_db;\n+\tint i;\n+\n+\tTF_CHECK_PARMS1(parms);\n+\n+\tshadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;\n+\tif (!shadow_db) {\n+\t\tTFP_DRV_LOG(DEBUG, \"Shadow db is NULL cannot be freed\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tfor (i = 0; i < TF_TBL_TYPE_MAX; i++) {\n+\t\tif (shadow_db->ctxt[i]) {\n+\t\t\ttf_shadow_tbl_ctxt_delete(shadow_db->ctxt[i]);\n+\t\t\ttfp_free(shadow_db->ctxt[i]);\n+\t\t}\n+\t}\n+\n+\ttfp_free(shadow_db);\n+\n \treturn 0;\n }\n+\n+/**\n+ * Allocate the table resources for search and allocate\n+ *\n+ */\n+int tf_shadow_tbl_create_db(struct tf_shadow_tbl_create_db_parms *parms)\n+{\n+\tint rc;\n+\tint i;\n+\tuint16_t base;\n+\tstruct tfp_calloc_parms cparms;\n+\tstruct tf_shadow_tbl_db *shadow_db = NULL;\n+\n+\tTF_CHECK_PARMS1(parms);\n+\n+\t/* Build the shadow DB per the request */\n+\tcparms.nitems = 1;\n+\tcparms.size = sizeof(struct tf_shadow_tbl_db);\n+\tcparms.alignment = 0;\n+\trc = tfp_calloc(&cparms);\n+\tif (rc)\n+\t\treturn rc;\n+\tshadow_db = (void *)cparms.mem_va;\n+\n+\tfor (i = 0; i < TF_TBL_TYPE_MAX; i++) {\n+\t\t/* If the element didn't request an allocation no need\n+\t\t * to create a pool nor verify if we got a reservation.\n+\t\t */\n+\t\tif (!parms->cfg->alloc_cnt[i] ||\n+\t\t    !tf_shadow_tbl_is_searchable(i)) {\n+\t\t\tshadow_db->ctxt[i] = NULL;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tcparms.nitems = 1;\n+\t\tcparms.size = sizeof(struct tf_shadow_tbl_ctxt);\n+\t\tcparms.alignment = 0;\n+\t\trc = tfp_calloc(&cparms);\n+\t\tif (rc)\n+\t\t\tgoto error;\n+\n+\t\tshadow_db->ctxt[i] = cparms.mem_va;\n+\t\tbase = parms->cfg->base_addr[i];\n+\t\trc = tf_shadow_tbl_ctxt_create(shadow_db->ctxt[i],\n+\t\t\t\t\t\tparms->cfg->alloc_cnt[i],\n+\t\t\t\t\t\tbase);\n+\t\tif (rc)\n+\t\t\tgoto error;\n+\t}\n+\n+\t*parms->shadow_db = (void *)shadow_db;\n+\n+\tTFP_DRV_LOG(INFO,\n+\t\t    \"TF SHADOW TABLE - initialized\\n\");\n+\n+\treturn 0;\n+error:\n+\tfor (i = 0; i < TF_TBL_TYPE_MAX; i++) {\n+\t\tif (shadow_db->ctxt[i]) {\n+\t\t\ttf_shadow_tbl_ctxt_delete(shadow_db->ctxt[i]);\n+\t\t\ttfp_free(shadow_db->ctxt[i]);\n+\t\t}\n+\t}\n+\n+\ttfp_free(shadow_db);\n+\n+\treturn -ENOMEM;\n+}\ndiff --git a/drivers/net/bnxt/tf_core/tf_shadow_tbl.h b/drivers/net/bnxt/tf_core/tf_shadow_tbl.h\nindex dfd336e..e73381f 100644\n--- a/drivers/net/bnxt/tf_core/tf_shadow_tbl.h\n+++ b/drivers/net/bnxt/tf_core/tf_shadow_tbl.h\n@@ -8,8 +8,6 @@\n \n #include \"tf_core.h\"\n \n-struct tf;\n-\n /**\n  * The Shadow Table module provides shadow DB handling for table based\n  * TF types. A shadow DB provides the capability that allows for reuse\n@@ -32,19 +30,22 @@ struct tf;\n  */\n struct tf_shadow_tbl_cfg_parms {\n \t/**\n-\t * TF Table type\n+\t * [in] The number of elements in the alloc_cnt and base_addr\n+\t * For now, it should always be equal to TF_TBL_TYPE_MAX\n \t */\n-\tenum tf_tbl_type type;\n+\tint num_entries;\n \n \t/**\n-\t * Number of entries the Shadow DB needs to hold\n+\t * [in] Resource allocation count array\n+\t * This array content originates from the tf_session_resources\n+\t * that is passed in on session open\n+\t * Array size is TF_TBL_TYPE_MAX\n \t */\n-\tint num_entries;\n-\n+\tuint16_t *alloc_cnt;\n \t/**\n-\t * Element width for this table type\n+\t * [in] The base index for each table\n \t */\n-\tint element_width;\n+\tuint16_t base_addr[TF_TBL_TYPE_MAX];\n };\n \n /**\n@@ -52,17 +53,17 @@ struct tf_shadow_tbl_cfg_parms {\n  */\n struct tf_shadow_tbl_create_db_parms {\n \t/**\n-\t * [in] Configuration information for the shadow db\n+\t * [in] Receive or transmit direction\n \t */\n-\tstruct tf_shadow_tbl_cfg_parms *cfg;\n+\tenum tf_dir dir;\n \t/**\n-\t * [in] Number of elements in the parms structure\n+\t * [in] Configuration information for the shadow db\n \t */\n-\tuint16_t num_elements;\n+\tstruct tf_shadow_tbl_cfg_parms *cfg;\n \t/**\n \t * [out] Shadow table DB handle\n \t */\n-\tvoid *tf_shadow_tbl_db;\n+\tvoid **shadow_db;\n };\n \n /**\n@@ -70,9 +71,9 @@ struct tf_shadow_tbl_create_db_parms {\n  */\n struct tf_shadow_tbl_free_db_parms {\n \t/**\n-\t * Shadow table DB handle\n+\t * [in] Shadow table DB handle\n \t */\n-\tvoid *tf_shadow_tbl_db;\n+\tvoid *shadow_db;\n };\n \n /**\n@@ -82,79 +83,77 @@ struct tf_shadow_tbl_search_parms {\n \t/**\n \t * [in] Shadow table DB handle\n \t */\n-\tvoid *tf_shadow_tbl_db;\n+\tvoid *shadow_db;\n \t/**\n-\t * [in] Table type\n+\t * [inout] The search parms from tf core\n \t */\n-\tenum tf_tbl_type type;\n-\t/**\n-\t * [in] Pointer to entry blob value in remap table to match\n-\t */\n-\tuint8_t *entry;\n-\t/**\n-\t * [in] Size of the entry blob passed in bytes\n-\t */\n-\tuint16_t entry_sz;\n-\t/**\n-\t * [out] Index of the found element returned if hit\n-\t */\n-\tuint16_t *index;\n+\tstruct tf_tbl_alloc_search_parms *sparms;\n \t/**\n \t * [out] Reference count incremented if hit\n \t */\n-\tuint16_t *ref_cnt;\n+\tuint32_t hb_handle;\n };\n \n /**\n- * Shadow table insert parameters\n+ * Shadow Table bind index parameters\n  */\n-struct tf_shadow_tbl_insert_parms {\n+struct tf_shadow_tbl_bind_index_parms {\n \t/**\n-\t * [in] Shadow table DB handle\n+\t * [in] Shadow tcam DB handle\n \t */\n-\tvoid *tf_shadow_tbl_db;\n+\tvoid *shadow_db;\n \t/**\n-\t * [in] Tbl type\n+\t * [in] receive or transmit direction\n+\t */\n+\tenum tf_dir dir;\n+\t/**\n+\t * [in] TCAM table type\n \t */\n \tenum tf_tbl_type type;\n \t/**\n-\t * [in] Pointer to entry blob value in remap table to match\n+\t * [in] index of the entry to program\n \t */\n-\tuint8_t *entry;\n+\tuint16_t idx;\n \t/**\n-\t * [in] Size of the entry blob passed in bytes\n+\t * [in] struct containing key\n \t */\n-\tuint16_t entry_sz;\n+\tuint8_t *data;\n \t/**\n-\t * [in] Entry to update\n+\t * [in] data size in bytes\n \t */\n-\tuint16_t index;\n+\tuint16_t data_sz_in_bytes;\n \t/**\n-\t * [out] Reference count after insert\n+\t * [in] The hash bucket handled returned from the search\n \t */\n-\tuint16_t *ref_cnt;\n+\tuint32_t hb_handle;\n };\n \n /**\n- * Shadow table remove parameters\n+ * Shadow table insert parameters\n  */\n-struct tf_shadow_tbl_remove_parms {\n+struct tf_shadow_tbl_insert_parms {\n \t/**\n \t * [in] Shadow table DB handle\n \t */\n-\tvoid *tf_shadow_tbl_db;\n+\tvoid *shadow_db;\n \t/**\n-\t * [in] Tbl type\n+\t * [in] The insert parms from tf core\n \t */\n-\tenum tf_tbl_type type;\n+\tstruct tf_tbl_set_parms *sparms;\n+};\n+\n+/**\n+ * Shadow table remove parameters\n+ */\n+struct tf_shadow_tbl_remove_parms {\n \t/**\n-\t * [in] Entry to update\n+\t * [in] Shadow table DB handle\n \t */\n-\tuint16_t index;\n+\tvoid *shadow_db;\n \t/**\n-\t * [out] Reference count after removal\n+\t * [in] The free parms from tf core\n \t */\n-\tuint16_t *ref_cnt;\n+\tstruct tf_tbl_free_parms *fparms;\n };\n \n /**\n@@ -206,10 +205,27 @@ int tf_shadow_tbl_free_db(struct tf_shadow_tbl_free_db_parms *parms);\n  * Returns\n  *   - (0) if successful, element was found.\n  *   - (-EINVAL) on failure.\n+ *\n+ * If there is a miss, but there is room for insertion, the hb_handle returned\n+ * is used for insertion during the bind index API\n  */\n int tf_shadow_tbl_search(struct tf_shadow_tbl_search_parms *parms);\n \n /**\n+ * Bind Shadow table db hash and result tables with result from search/alloc\n+ *\n+ * [in] parms\n+ *   Pointer to the search parameters\n+ *\n+ * Returns\n+ *   - (0) if successful\n+ *   - (-EINVAL) on failure.\n+ *\n+ * This is only called after a MISS in the search returns a hb_handle\n+ */\n+int tf_shadow_tbl_bind_index(struct tf_shadow_tbl_bind_index_parms *parms);\n+\n+/**\n  * Inserts an element into the Shadow table DB. Will fail if the\n  * elements ref_count is different from 0. Ref_count after insert will\n  * be incremented.\ndiff --git a/drivers/net/bnxt/tf_core/tf_shadow_tcam.c b/drivers/net/bnxt/tf_core/tf_shadow_tcam.c\nindex beaea03..a0130d6 100644\n--- a/drivers/net/bnxt/tf_core/tf_shadow_tcam.c\n+++ b/drivers/net/bnxt/tf_core/tf_shadow_tcam.c\n@@ -373,6 +373,12 @@ tf_shadow_tcam_clear_hash_entry(struct tf_shadow_tcam_ctxt *ctxt,\n \tcase 3:\n \t\t*bucket = TF_SHADOW_TCAM_BE2_MASK_CLEAR(*bucket);\n \t\tbreak;\n+\tdefault:\n+\t\t/*\n+\t\t * Since the BE_GET masks non-inclusive bits, this will not\n+\t\t * happen.\n+\t\t */\n+\t\tbreak;\n \t}\n }\n \ndiff --git a/drivers/net/bnxt/tf_core/tf_tbl.c b/drivers/net/bnxt/tf_core/tf_tbl.c\nindex 9ebaa34..bec5210 100644\n--- a/drivers/net/bnxt/tf_core/tf_tbl.c\n+++ b/drivers/net/bnxt/tf_core/tf_tbl.c\n@@ -13,6 +13,9 @@\n #include \"tf_util.h\"\n #include \"tf_msg.h\"\n #include \"tfp.h\"\n+#include \"tf_shadow_tbl.h\"\n+#include \"tf_session.h\"\n+#include \"tf_device.h\"\n \n \n struct tf;\n@@ -25,7 +28,7 @@ static void *tbl_db[TF_DIR_MAX];\n /**\n  * Table Shadow DBs\n  */\n-/* static void *shadow_tbl_db[TF_DIR_MAX]; */\n+static void *shadow_tbl_db[TF_DIR_MAX];\n \n /**\n  * Init flag, set on bind and cleared on unbind\n@@ -35,14 +38,19 @@ static uint8_t init;\n /**\n  * Shadow init flag, set on bind and cleared on unbind\n  */\n-/* static uint8_t shadow_init; */\n+static uint8_t shadow_init;\n \n int\n tf_tbl_bind(struct tf *tfp,\n \t    struct tf_tbl_cfg_parms *parms)\n {\n-\tint rc;\n-\tint i;\n+\tint rc, d, i;\n+\tstruct tf_rm_alloc_info info;\n+\tstruct tf_rm_free_db_parms fparms;\n+\tstruct tf_shadow_tbl_free_db_parms fshadow;\n+\tstruct tf_rm_get_alloc_info_parms ainfo;\n+\tstruct tf_shadow_tbl_cfg_parms shadow_cfg;\n+\tstruct tf_shadow_tbl_create_db_parms shadow_cdb;\n \tstruct tf_rm_create_db_parms db_cfg = { 0 };\n \n \tTF_CHECK_PARMS2(tfp, parms);\n@@ -58,26 +66,86 @@ tf_tbl_bind(struct tf *tfp,\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.alloc_cnt = parms->resources->tbl_cnt[i].cnt;\n-\t\tdb_cfg.rm_db = &tbl_db[i];\n+\tfor (d = 0; d < TF_DIR_MAX; d++) {\n+\t\tdb_cfg.dir = d;\n+\t\tdb_cfg.alloc_cnt = parms->resources->tbl_cnt[d].cnt;\n+\t\tdb_cfg.rm_db = &tbl_db[d];\n \t\trc = tf_rm_create_db(tfp, &db_cfg);\n \t\tif (rc) {\n \t\t\tTFP_DRV_LOG(ERR,\n \t\t\t\t    \"%s: Table DB creation failed\\n\",\n-\t\t\t\t    tf_dir_2_str(i));\n+\t\t\t\t    tf_dir_2_str(d));\n \n \t\t\treturn rc;\n \t\t}\n \t}\n \n+\t/* Initialize the Shadow Table. */\n+\tif (parms->shadow_copy) {\n+\t\tfor (d = 0; d < TF_DIR_MAX; d++) {\n+\t\t\tmemset(&shadow_cfg, 0, sizeof(shadow_cfg));\n+\t\t\tmemset(&shadow_cdb, 0, sizeof(shadow_cdb));\n+\t\t\t/* Get the base addresses of the tables */\n+\t\t\tfor (i = 0; i < TF_TBL_TYPE_MAX; i++) {\n+\t\t\t\tmemset(&info, 0, sizeof(info));\n+\n+\t\t\t\tif (!parms->resources->tbl_cnt[d].cnt[i])\n+\t\t\t\t\tcontinue;\n+\t\t\t\tainfo.rm_db = tbl_db[d];\n+\t\t\t\tainfo.db_index = i;\n+\t\t\t\tainfo.info = &info;\n+\t\t\t\trc = tf_rm_get_info(&ainfo);\n+\t\t\t\tif (rc)\n+\t\t\t\t\tgoto error;\n+\n+\t\t\t\tshadow_cfg.base_addr[i] = info.entry.start;\n+\t\t\t}\n+\n+\t\t\t/* Create the shadow db */\n+\t\t\tshadow_cfg.alloc_cnt =\n+\t\t\t\tparms->resources->tbl_cnt[d].cnt;\n+\t\t\tshadow_cfg.num_entries = parms->num_elements;\n+\n+\t\t\tshadow_cdb.shadow_db = &shadow_tbl_db[d];\n+\t\t\tshadow_cdb.cfg = &shadow_cfg;\n+\t\t\trc = tf_shadow_tbl_create_db(&shadow_cdb);\n+\t\t\tif (rc) {\n+\t\t\t\tTFP_DRV_LOG(ERR,\n+\t\t\t\t\t    \"Shadow TBL DB creation failed \"\n+\t\t\t\t\t    \"rc=%d\\n\", rc);\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\t\t}\n+\t\tshadow_init = 1;\n+\t}\n+\n \tinit = 1;\n \n \tTFP_DRV_LOG(INFO,\n \t\t    \"Table Type - initialized\\n\");\n \n \treturn 0;\n+error:\n+\tfor (d = 0; d < TF_DIR_MAX; d++) {\n+\t\tmemset(&fparms, 0, sizeof(fparms));\n+\t\tfparms.dir = d;\n+\t\tfparms.rm_db = tbl_db[d];\n+\t\t/* Ignoring return here since we are in the error case */\n+\t\t(void)tf_rm_free_db(tfp, &fparms);\n+\n+\t\tif (parms->shadow_copy) {\n+\t\t\tfshadow.shadow_db = shadow_tbl_db[d];\n+\t\t\ttf_shadow_tbl_free_db(&fshadow);\n+\t\t\tshadow_tbl_db[d] = NULL;\n+\t\t}\n+\n+\t\ttbl_db[d] = NULL;\n+\t}\n+\n+\tshadow_init = 0;\n+\tinit = 0;\n+\n+\treturn rc;\n }\n \n int\n@@ -86,6 +154,7 @@ tf_tbl_unbind(struct tf *tfp)\n \tint rc;\n \tint i;\n \tstruct tf_rm_free_db_parms fparms = { 0 };\n+\tstruct tf_shadow_tbl_free_db_parms fshadow;\n \n \tTF_CHECK_PARMS1(tfp);\n \n@@ -104,9 +173,17 @@ tf_tbl_unbind(struct tf *tfp)\n \t\t\treturn rc;\n \n \t\ttbl_db[i] = NULL;\n+\n+\t\tif (shadow_init) {\n+\t\t\tmemset(&fshadow, 0, sizeof(fshadow));\n+\t\t\tfshadow.shadow_db = shadow_tbl_db[i];\n+\t\t\ttf_shadow_tbl_free_db(&fshadow);\n+\t\t\tshadow_tbl_db[i] = NULL;\n+\t\t}\n \t}\n \n \tinit = 0;\n+\tshadow_init = 0;\n \n \treturn 0;\n }\n@@ -153,6 +230,7 @@ tf_tbl_free(struct tf *tfp __rte_unused,\n \tint rc;\n \tstruct tf_rm_is_allocated_parms aparms = { 0 };\n \tstruct tf_rm_free_parms fparms = { 0 };\n+\tstruct tf_shadow_tbl_remove_parms shparms;\n \tint allocated = 0;\n \n \tTF_CHECK_PARMS2(tfp, parms);\n@@ -182,6 +260,36 @@ tf_tbl_free(struct tf *tfp __rte_unused,\n \t\treturn -EINVAL;\n \t}\n \n+\t/*\n+\t * The Shadow mgmt, if enabled, determines if the entry needs\n+\t * to be deleted.\n+\t */\n+\tif (shadow_init) {\n+\t\tmemset(&shparms, 0, sizeof(shparms));\n+\t\tshparms.shadow_db = shadow_tbl_db[parms->dir];\n+\t\tshparms.fparms = parms;\n+\t\trc = tf_shadow_tbl_remove(&shparms);\n+\t\tif (rc) {\n+\t\t\t/*\n+\t\t\t * Should not get here, log it and let the entry be\n+\t\t\t * deleted.\n+\t\t\t */\n+\t\t\tTFP_DRV_LOG(ERR, \"%s: Shadow free fail, \"\n+\t\t\t\t    \"type:%d index:%d deleting the entry.\\n\",\n+\t\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t\t    parms->type,\n+\t\t\t\t    parms->idx);\n+\t\t} else {\n+\t\t\t/*\n+\t\t\t * If the entry still has references, just return the\n+\t\t\t * ref count to the caller.  No need to remove entry\n+\t\t\t * from rm.\n+\t\t\t */\n+\t\t\tif (parms->ref_cnt >= 1)\n+\t\t\t\treturn rc;\n+\t\t}\n+\t}\n+\n \t/* Free requested element */\n \tfparms.rm_db = tbl_db[parms->dir];\n \tfparms.db_index = parms->type;\n@@ -200,10 +308,124 @@ tf_tbl_free(struct tf *tfp __rte_unused,\n }\n \n int\n-tf_tbl_alloc_search(struct tf *tfp __rte_unused,\n-\t\t    struct tf_tbl_alloc_search_parms *parms __rte_unused)\n+tf_tbl_alloc_search(struct tf *tfp,\n+\t\t    struct tf_tbl_alloc_search_parms *parms)\n {\n-\treturn 0;\n+\tint rc, frc;\n+\tuint32_t idx;\n+\tstruct tf_session *tfs;\n+\tstruct tf_dev_info *dev;\n+\tstruct tf_tbl_alloc_parms aparms;\n+\tstruct tf_shadow_tbl_search_parms sparms;\n+\tstruct tf_shadow_tbl_bind_index_parms bparms;\n+\tstruct tf_tbl_free_parms fparms;\n+\n+\tTF_CHECK_PARMS2(tfp, parms);\n+\n+\tif (!shadow_init || !shadow_tbl_db[parms->dir]) {\n+\t\tTFP_DRV_LOG(ERR, \"%s: Shadow TBL not initialized.\\n\",\n+\t\t\t    tf_dir_2_str(parms->dir));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmemset(&sparms, 0, sizeof(sparms));\n+\tsparms.sparms = parms;\n+\tsparms.shadow_db = shadow_tbl_db[parms->dir];\n+\trc = tf_shadow_tbl_search(&sparms);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\t/*\n+\t * The app didn't request us to alloc the entry, so return now.\n+\t * The hit should have been updated in the original search parm.\n+\t */\n+\tif (!parms->alloc || parms->search_status != MISS)\n+\t\treturn rc;\n+\n+\t/* Retrieve the session information */\n+\trc = tf_session_get_session(tfp, &tfs);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"%s: Failed to lookup session, rc:%s\\n\",\n+\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\t/* Retrieve the device information */\n+\trc = tf_session_get_device(tfs, &dev);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"%s: Failed to lookup device, rc:%s\\n\",\n+\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\t/* Allocate the index */\n+\tif (dev->ops->tf_dev_alloc_tbl == NULL) {\n+\t\trc = -EOPNOTSUPP;\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"%s: Operation not supported, rc:%s\\n\",\n+\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t    strerror(-rc));\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tmemset(&aparms, 0, sizeof(aparms));\n+\taparms.dir = parms->dir;\n+\taparms.type = parms->type;\n+\taparms.tbl_scope_id = parms->tbl_scope_id;\n+\taparms.idx = &idx;\n+\trc = dev->ops->tf_dev_alloc_tbl(tfp, &aparms);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"%s: Table allocation failed, rc:%s\\n\",\n+\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t    strerror(-rc));\n+\t\treturn rc;\n+\t}\n+\n+\t/* Bind the allocated index to the data */\n+\tmemset(&bparms, 0, sizeof(bparms));\n+\tbparms.shadow_db = shadow_tbl_db[parms->dir];\n+\tbparms.dir = parms->dir;\n+\tbparms.type = parms->type;\n+\tbparms.idx = idx;\n+\tbparms.data = parms->result;\n+\tbparms.data_sz_in_bytes = parms->result_sz_in_bytes;\n+\tbparms.hb_handle = sparms.hb_handle;\n+\trc = tf_shadow_tbl_bind_index(&bparms);\n+\tif (rc) {\n+\t\t/* Error binding entry, need to free the allocated idx */\n+\t\tif (dev->ops->tf_dev_free_tbl == NULL) {\n+\t\t\trc = -EOPNOTSUPP;\n+\t\t\tTFP_DRV_LOG(ERR,\n+\t\t\t\t    \"%s: Operation not supported, rc:%s\\n\",\n+\t\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t\t    strerror(-rc));\n+\t\t\treturn rc;\n+\t\t}\n+\n+\t\tmemset(&fparms, 0, sizeof(fparms));\n+\t\tfparms.dir = parms->dir;\n+\t\tfparms.type = parms->type;\n+\t\tfparms.idx = idx;\n+\t\tfrc = dev->ops->tf_dev_free_tbl(tfp, &fparms);\n+\t\tif (frc) {\n+\t\t\tTFP_DRV_LOG(ERR,\n+\t\t\t\t    \"%s: Failed free index allocated during \"\n+\t\t\t\t    \"search. rc=%s\\n\",\n+\t\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t\t    strerror(-frc));\n+\t\t\t/* return the original failure. */\n+\t\t\treturn rc;\n+\t\t}\n+\t}\n+\n+\tparms->idx = idx;\n+\n+\treturn rc;\n }\n \n int\ndiff --git a/drivers/net/bnxt/tf_core/tf_tbl.h b/drivers/net/bnxt/tf_core/tf_tbl.h\nindex f20e8d7..930fcc3 100644\n--- a/drivers/net/bnxt/tf_core/tf_tbl.h\n+++ b/drivers/net/bnxt/tf_core/tf_tbl.h\n@@ -144,29 +144,31 @@ struct tf_tbl_alloc_search_parms {\n \t */\n \tuint32_t tbl_scope_id;\n \t/**\n-\t * [in] Enable search for matching entry. If the table type is\n-\t * internal the shadow copy will be searched before\n-\t * alloc. Session must be configured with shadow copy enabled.\n-\t */\n-\tuint8_t search_enable;\n-\t/**\n-\t * [in] Result data to search for (if search_enable)\n+\t * [in] Result data to search for\n \t */\n \tuint8_t *result;\n \t/**\n-\t * [in] Result data size in bytes (if search_enable)\n+\t * [in] Result data size in bytes\n \t */\n \tuint16_t result_sz_in_bytes;\n \t/**\n+\t * [in] Whether or not to allocate on MISS, 1 is allocate.\n+\t */\n+\tuint8_t alloc;\n+\t/**\n \t * [out] If search_enable, set if matching entry found\n \t */\n \tuint8_t hit;\n \t/**\n-\t * [out] Current ref count after allocation (if search_enable)\n+\t * [out] The status of the search (REJECT, MISS, HIT)\n+\t */\n+\tenum tf_search_status search_status;\n+\t/**\n+\t * [out] Current ref count after allocation\n \t */\n \tuint16_t ref_cnt;\n \t/**\n-\t * [out] Idx of allocated entry or found entry (if search_enable)\n+\t * [out] Idx of allocated entry or found entry\n \t */\n \tuint32_t idx;\n };\ndiff --git a/drivers/net/bnxt/tf_core/tf_tcam.h b/drivers/net/bnxt/tf_core/tf_tcam.h\nindex 4722ce0..ffa0a94 100644\n--- a/drivers/net/bnxt/tf_core/tf_tcam.h\n+++ b/drivers/net/bnxt/tf_core/tf_tcam.h\n@@ -134,7 +134,7 @@ struct tf_tcam_alloc_search_parms {\n \t/**\n \t * [out] Search result status (hit, miss, reject)\n \t */\n-\tenum tf_tcam_search_status search_status;\n+\tenum tf_search_status search_status;\n \t/**\n \t * [out] Current refcnt after allocation\n \t */\n",
    "prefixes": [
        "12/20"
    ]
}