Show a patch.

GET /api/patches/74664/
Content-Type: application/json
Vary: Accept

    "id": 74664,
    "url": "",
    "web_url": "",
    "project": {
        "id": 1,
        "url": "",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "",
        "list_email": "",
        "web_url": "",
        "scm_url": "git://",
        "webscm_url": ""
    "msgid": "<>",
    "date": "2020-07-23T11:56:20",
    "name": "[v2,01/20] net/bnxt: add shadow tcam capability with search",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "71a3074fd451b90eb7ece9a9ec3b1d92d83eef29",
    "submitter": {
        "id": 908,
        "url": "",
        "name": "Somnath Kotur",
        "email": ""
    "delegate": {
        "id": 1766,
        "url": "",
        "username": "ajitkhaparde",
        "first_name": "Ajit",
        "last_name": "Khaparde",
        "email": ""
    "mbox": "",
    "series": [
            "id": 11254,
            "url": "",
            "web_url": "",
            "date": "2020-07-23T11:56:19",
            "name": "bnxt patches",
            "version": 2,
            "mbox": ""
    "comments": "",
    "check": "warning",
    "checks": "",
    "tags": {},
    "headers": {
        "List-Subscribe": "<>,\n <>",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "X-Original-To": "",
        "List-Post": "<>",
        "References": "<>\n <>",
        "X-BeenThere": "",
        "List-Id": "DPDK patches and discussions <>",
        "DKIM-Filter": "OpenDKIM Filter v2.10.3 A0F8729AD97",
        "Subject": "[dpdk-dev] [PATCH v2 01/20] net/bnxt: add shadow tcam capability\n\twith search",
        "Sender": "\"dev\" <>",
        "Delivered-To": "",
        "Received": [
            "from ( [])\n\tby (Postfix) with ESMTP id D75B6A0521;\n\tThu, 23 Jul 2020 14:02:22 +0200 (CEST)",
            "from [] (localhost [])\n\tby (Postfix) with ESMTP id 80E581BFFB;\n\tThu, 23 Jul 2020 14:02:09 +0200 (CEST)",
            "from (\n []) by (Postfix) with ESMTP id A147B2C6E\n for <>; Thu, 23 Jul 2020 14:02:02 +0200 (CEST)",
            "from\n ( [])\n by (Postfix) with ESMTP id A0F8729AD97;\n Thu, 23 Jul 2020 05:02:01 -0700 (PDT)"
        "To": "",
        "X-Mailer": "git-send-email",
        "List-Unsubscribe": "<>,\n <>",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple;;\n s=dkimrelay; t=1595505721;\n bh=X56PTMnjrIySKYWM54JIY/COEZDesA0bG9p+nK/tXwc=;\n h=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n b=bsbsaIUckCZgTKrV+DrAPW5v7aC2lfRWCdb4dU+C0s0IQjof60/UyIPFVIbMvdW59\n Mc1j5alVRsqX9G/BQhqdYTpQf81fZ4mv1lTWb5uer1MFdXF3kQTXsUWI6Pl9mmxzb5\n GT6tWPCtKxO07raGCak1oEVKXZzDubHhF8SdSsXA=",
        "Date": "Thu, 23 Jul 2020 17:26:20 +0530",
        "List-Archive": "<>",
        "From": "Somnath Kotur <>",
        "In-Reply-To": "<>",
        "Cc": "",
        "List-Help": "<>",
        "Errors-To": "",
        "Message-Id": "<>",
        "Return-Path": "<>"
    "content": "From: Mike Baucom <>\n\n- Add TCAM shadow tables for searching\n- Add Search API to allow reuse of TCAM entries\n\nSigned-off-by: Mike Baucom <>\nReviewed-by: Randy Schacher <>\n---\n drivers/net/bnxt/tf_core/tf_core.c        |  73 +++\n drivers/net/bnxt/tf_core/tf_core.h        | 101 ++++\n drivers/net/bnxt/tf_core/tf_device_p4.c   |   2 +-\n drivers/net/bnxt/tf_core/tf_shadow_tcam.c | 885 +++++++++++++++++++++++++++++-\n drivers/net/bnxt/tf_core/tf_shadow_tcam.h | 258 ++++-----\n drivers/net/bnxt/tf_core/tf_tcam.c        | 300 +++++++++-\n drivers/net/bnxt/tf_core/tf_tcam.h        |  31 +-\n 7 files changed, 1449 insertions(+), 201 deletions(-)",
    "diff": "diff --git a/drivers/net/bnxt/tf_core/tf_core.c b/drivers/net/bnxt/tf_core/tf_core.c\nindex 97e7952..ca3280b 100644\n--- a/drivers/net/bnxt/tf_core/tf_core.c\n+++ b/drivers/net/bnxt/tf_core/tf_core.c\n@@ -608,6 +608,79 @@ tf_search_identifier(struct tf *tfp,\n }\n \n int\n+tf_search_tcam_entry(struct tf *tfp,\n+\t\t     struct tf_search_tcam_entry_parms *parms)\n+{\n+\tint rc;\n+\tstruct tf_session *tfs;\n+\tstruct tf_dev_info *dev;\n+\tstruct tf_tcam_alloc_search_parms sparms;\n+\n+\tTF_CHECK_PARMS2(tfp, parms);\n+\n+\tmemset(&sparms, 0, sizeof(struct tf_tcam_alloc_search_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_tcam == 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+\tsparms.dir = parms->dir;\n+\tsparms.type = parms->tcam_tbl_type;\n+\tsparms.key = parms->key;\n+\tsparms.key_size = TF_BITS2BYTES_WORD_ALIGN(parms->key_sz_in_bits);\n+\tsparms.mask = parms->mask;\n+\tsparms.priority = parms->priority;\n+\tsparms.alloc = parms->alloc;\n+\n+\t/* Result is an in/out and so no need to copy during outputs */\n+\tsparms.result = parms->result;\n+\tsparms.result_size =\n+\t\tTF_BITS2BYTES_WORD_ALIGN(parms->result_sz_in_bits);\n+\n+\trc = dev->ops->tf_dev_alloc_search_tcam(tfp, &sparms);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"%s: TCAM 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/* Copy the outputs */\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_alloc_tcam_entry(struct tf *tfp,\n \t\t    struct tf_alloc_tcam_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 67415ad..349a1f1 100644\n--- a/drivers/net/bnxt/tf_core/tf_core.h\n+++ b/drivers/net/bnxt/tf_core/tf_core.h\n@@ -291,6 +291,18 @@ enum tf_tcam_tbl_type {\n };\n \n /**\n+ * TCAM SEARCH STATUS\n+ */\n+enum tf_tcam_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+\tHIT,\n+\t/** The entry was not found and the table is full */\n+\tREJECT\n+};\n+\n+/**\n  * EM Resources\n  * These defines are provisioned during\n  * tf_open_session()\n@@ -949,6 +961,8 @@ int tf_free_tbl_scope(struct tf *tfp,\n /**\n  * @page tcam TCAM Access\n  *\n+ * @ref tf_search_tcam_entry\n+ *\n  * @ref tf_alloc_tcam_entry\n  *\n  * @ref tf_set_tcam_entry\n@@ -958,6 +972,93 @@ int tf_free_tbl_scope(struct tf *tfp,\n  * @ref tf_free_tcam_entry\n  */\n \n+/**\n+ * tf_search_tcam_entry parameter definition (experimental)\n+ */\n+struct tf_search_tcam_entry_parms {\n+\t/**\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_tcam_tbl_type tcam_tbl_type;\n+\t/**\n+\t * [in] Key data to match on\n+\t */\n+\tuint8_t *key;\n+\t/**\n+\t * [in] key size in bits\n+\t */\n+\tuint16_t key_sz_in_bits;\n+\t/**\n+\t * [in] Mask data to match on\n+\t */\n+\tuint8_t *mask;\n+\t/**\n+\t * [in] Priority of entry requested (definition TBD)\n+\t */\n+\tuint32_t priority;\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_tcam_search_status search_status;\n+\t/**\n+\t * [out] Current refcnt after allocation\n+\t */\n+\tuint16_t ref_cnt;\n+\t/**\n+\t * [in out] The result data from the search is copied here\n+\t */\n+\tuint8_t *result;\n+\t/**\n+\t * [in out] result size in bits for the result data\n+\t */\n+\tuint16_t result_sz_in_bits;\n+\t/**\n+\t * [out] Index found\n+\t */\n+\tuint16_t idx;\n+};\n+\n+/**\n+ * search TCAM entry (experimental)\n+ *\n+ * Search for a TCAM entry\n+ *\n+ * This function searches the shadow copy of the TCAM table for a matching\n+ * entry.  Key and mask must match for hit to be set.  Only TruFlow core data\n+ * is accessed.  If shadow_copy is not enabled, an error is returned.\n+ *\n+ * Implementation:\n+ *\n+ * A hash is performed on the key/mask data and mapped to a shadow copy entry\n+ * where the full key/mask is populated.  If the full key/mask matches the\n+ * entry, hit is set, ref_cnt is incremented, and 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 create a result and call tf_set_tcam_entry with\n+ * returned index.\n+ *\n+ * - On Reject, the hash table is full and the entry cannot be added.\n+ *\n+ * - On Hit, the result data 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_tcam_entry(struct tf *tfp,\n+\t\t\t struct tf_search_tcam_entry_parms *parms);\n \n /**\n  * tf_alloc_tcam_entry parameter definition\ndiff --git a/drivers/net/bnxt/tf_core/tf_device_p4.c b/drivers/net/bnxt/tf_core/tf_device_p4.c\nindex f38c38e..afb6098 100644\n--- a/drivers/net/bnxt/tf_core/tf_device_p4.c\n+++ b/drivers/net/bnxt/tf_core/tf_device_p4.c\n@@ -133,7 +133,7 @@ const struct tf_dev_ops tf_dev_ops_p4 = {\n \t.tf_dev_get_bulk_tbl = tf_tbl_bulk_get,\n \t.tf_dev_alloc_tcam = tf_tcam_alloc,\n \t.tf_dev_free_tcam = tf_tcam_free,\n-\t.tf_dev_alloc_search_tcam = NULL,\n+\t.tf_dev_alloc_search_tcam = tf_tcam_alloc_search,\n \t.tf_dev_set_tcam = tf_tcam_set,\n \t.tf_dev_get_tcam = NULL,\n \t.tf_dev_insert_int_em_entry = tf_em_insert_int_entry,\ndiff --git a/drivers/net/bnxt/tf_core/tf_shadow_tcam.c b/drivers/net/bnxt/tf_core/tf_shadow_tcam.c\nindex c61b833..51aae4f 100644\n--- a/drivers/net/bnxt/tf_core/tf_shadow_tcam.c\n+++ b/drivers/net/bnxt/tf_core/tf_shadow_tcam.c\n@@ -3,61 +3,902 @@\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_shadow_tcam.h\"\n \n /**\n- * Shadow tcam DB element\n+ * The implementation includes 3 tables per tcam 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 tcam index - the base address\n+ *   - the key and mask are stored in the key table.\n+ *   - The stored key is the AND of the key/mask in order to eliminate the need\n+ *   to compare both the key and mask.\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 tcam 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_tcam_element {\n-\t/**\n-\t * Hash table\n-\t */\n-\tvoid *hash;\n \n-\t/**\n-\t * Reference count, array of number of tcam 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_TCAM_ENTRIES_MAX (1 << 15)\n+\n+/* The number of elements(BE) per hash bucket (HB) */\n+#define TF_SHADOW_TCAM_HB_NUM_ELEM (4)\n+#define TF_SHADOW_TCAM_BE_VALID (1 << 15)\n+#define TF_SHADOW_TCAM_BE_IS_VALID(be) (((be) & TF_SHADOW_TCAM_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_TCAM_HB_HANDLE_IS_VALID(hndl) (((hndl) & (1 << 31)) != 0)\n+#define TF_SHADOW_TCAM_HB_HANDLE_CREATE(idx, be) ((1 << 31) | \\\n+\t\t\t\t\t\t  ((be) << 29) | (idx))\n+\n+#define TF_SHADOW_TCAM_HB_HANDLE_BE_GET(hdl) (((hdl) >> 29) & \\\n+\t\t\t\t\t      (TF_SHADOW_TCAM_HB_NUM_ELEM - 1))\n+\n+#define TF_SHADOW_TCAM_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 tcam index to a shadow index */\n+#define TF_SHADOW_TCAM_IDX_TO_SHIDX(ctxt, idx) ((idx) - \\\n+\t\t\t\t\t\t(ctxt)->shadow_ctxt.base_addr)\n+\n+/* Convert the shadow index to a tcam index */\n+#define TF_SHADOW_TCAM_SHIDX_TO_IDX(ctxt, idx) ((idx) + \\\n+\t\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_TCAM_BE0_MASK_CLEAR(hb) ((hb) & 0xffffffffffff0000ull)\n+#define TF_SHADOW_TCAM_BE1_MASK_CLEAR(hb) ((hb) & 0xffffffff0000ffffull)\n+#define TF_SHADOW_TCAM_BE2_MASK_CLEAR(hb) ((hb) & 0xffff0000ffffffffull)\n+#define TF_SHADOW_TCAM_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 1K bits and no result is bigger than 128 bits.  This makes\n+ * allocation of the hash table easier without having to allocate on the fly.\n+ */\n+#define TF_SHADOW_TCAM_MAX_KEY_SZ 128\n+#define TF_SHADOW_TCAM_MAX_RESULT_SZ 16\n+\n+/*\n+ * Local only defines for the internal data.\n+ */\n+\n+/**\n+ * tf_shadow_tcam_shadow_key_entry is the key/mask entry of the key table.\n+ * The key stored in the table is the masked version of the key.  This is done\n+ * to eliminate the need of comparing both the key and mask.\n+ */\n+struct tf_shadow_tcam_shadow_key_entry {\n+\tuint8_t key[TF_SHADOW_TCAM_MAX_KEY_SZ];\n+\tuint8_t mask[TF_SHADOW_TCAM_MAX_KEY_SZ];\n };\n \n /**\n- * Shadow tcam DB definition\n+ * tf_shadow_tcam_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 result, refcnt, and result size\n+ */\n+struct tf_shadow_tcam_shadow_result_entry {\n+\tuint8_t result[TF_SHADOW_TCAM_MAX_RESULT_SZ];\n+\tuint16_t result_size;\n+\tuint16_t key_size;\n+\tuint32_t refcnt;\n+\tuint32_t hb_handle;\n+};\n+\n+/**\n+ * tf_shadow_tcam_shadow_ctxt holds all information for accessing the key and\n+ * result tables.\n+ */\n+struct tf_shadow_tcam_shadow_ctxt {\n+\tstruct tf_shadow_tcam_shadow_key_entry *sh_key_tbl;\n+\tstruct tf_shadow_tcam_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_tcam_hash_ctxt holds all information related to accessing the hash\n+ * table.\n+ */\n+struct tf_shadow_tcam_hash_ctxt {\n+\tuint64_t *hashtbl;\n+\tuint16_t hid_mask;\n+\tuint16_t hash_entries;\n+};\n+\n+/**\n+ * tf_shadow_tcam_ctxt holds the hash and shadow tables for the current shadow\n+ * tcam db.  This structure is per tcam table type as each tcam table has it's\n+ * own shadow and hash table.\n+ */\n+struct tf_shadow_tcam_ctxt {\n+\tstruct tf_shadow_tcam_shadow_ctxt shadow_ctxt;\n+\tstruct tf_shadow_tcam_hash_ctxt hash_ctxt;\n+};\n+\n+/**\n+ * tf_shadow_tcam_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 tcam associated with the db.\n  */\n struct tf_shadow_tcam_db {\n-\t/**\n-\t * The DB consists of an array of elements\n-\t */\n-\tstruct tf_shadow_tcam_element *db;\n+\t/* Each context holds the shadow and hash table information */\n+\tstruct tf_shadow_tcam_ctxt *ctxt[TF_TCAM_TBL_TYPE_MAX];\n+};\n+\n+/* CRC polynomial 0xedb88320 */\n+static const uint32_t tf_shadow_tcam_crc32tbl[] = {\n+\t0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,\n+\t0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,\n+\t0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,\n+\t0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,\n+\t0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,\n+\t0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\n+\t0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,\n+\t0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,\n+\t0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,\n+\t0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,\n+\t0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,\n+\t0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\n+\t0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,\n+\t0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,\n+\t0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\n+\t0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,\n+\t0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,\n+\t0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n+\t0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,\n+\t0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,\n+\t0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,\n+\t0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,\n+\t0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,\n+\t0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\n+\t0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,\n+\t0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,\n+\t0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,\n+\t0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,\n+\t0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,\n+\t0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n+\t0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,\n+\t0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,\n+\t0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,\n+\t0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,\n+\t0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,\n+\t0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\n+\t0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,\n+\t0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,\n+\t0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,\n+\t0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,\n+\t0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,\n+\t0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n+\t0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,\n+\t0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,\n+\t0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\n+\t0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,\n+\t0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,\n+\t0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\n+\t0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,\n+\t0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,\n+\t0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,\n+\t0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,\n+\t0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,\n+\t0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n+\t0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,\n+\t0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,\n+\t0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,\n+\t0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,\n+\t0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,\n+\t0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n+\t0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,\n+\t0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,\n+\t0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,\n+\t0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d\n };\n \n+/**\n+ * Returns the number of entries in the contexts shadow table.\n+ */\n+static inline uint16_t\n+tf_shadow_tcam_sh_num_entries_get(struct tf_shadow_tcam_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_tcam_key_cmp(struct tf_shadow_tcam_ctxt *ctxt,\n+\t\t       uint8_t *key,\n+\t\t       uint8_t *mask,\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_tcam_sh_num_entries_get(ctxt) || !key || !mask)\n+\t\treturn -1;\n+\n+\treturn memcmp(key, ctxt->shadow_ctxt.sh_key_tbl[sh_idx].key, size);\n+}\n+\n+/**\n+ * Copies the shadow result to the result.\n+ *\n+ * Returns 0 on failure\n+ */\n+static void *\n+tf_shadow_tcam_res_cpy(struct tf_shadow_tcam_ctxt *ctxt,\n+\t\t       uint8_t *result,\n+\t\t       uint16_t sh_idx,\n+\t\t       uint16_t size)\n+{\n+\tif (sh_idx >= tf_shadow_tcam_sh_num_entries_get(ctxt) || !result)\n+\t\treturn 0;\n+\n+\tif (ctxt->shadow_ctxt.sh_res_tbl[sh_idx].result_size != size)\n+\t\treturn 0;\n+\n+\treturn memcpy(result,\n+\t\t      ctxt->shadow_ctxt.sh_res_tbl[sh_idx].result,\n+\t\t      size);\n+}\n+\n+/**\n+ * Using a software based CRC function for now, but will look into using hw\n+ * assisted in the future.\n+ */\n+static uint32_t\n+tf_shadow_tcam_crc32_calc(uint8_t *key, uint32_t len)\n+{\n+\tuint32_t crc = ~0U;\n+\n+\twhile (len--)\n+\t\tcrc = tf_shadow_tcam_crc32tbl[(crc ^ key[len]) & 0xff] ^\n+\t\t\t(crc >> 8);\n+\n+\treturn ~crc;\n+}\n+\n+/**\n+ * Free the memory associated with the context.\n+ */\n+static void\n+tf_shadow_tcam_ctxt_delete(struct tf_shadow_tcam_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 TCAM context is per TCAM 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_tcam_ctxt_delete prior when deleting\n+ * the shadow db.\n+ */\n+static int\n+tf_shadow_tcam_ctxt_create(struct tf_shadow_tcam_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_TCAM_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_TCAM_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_tcam_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_tcam_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_tcam_ctxt_delete(ctxt);\n+\n+\treturn -ENOMEM;\n+}\n+\n+/**\n+ * Get a shadow TCAM context given the db and the TCAM type\n+ */\n+static struct tf_shadow_tcam_ctxt *\n+tf_shadow_tcam_ctxt_get(struct tf_shadow_tcam_db *shadow_db,\n+\t\t\tenum tf_tcam_tbl_type type)\n+{\n+\tif (type >= TF_TCAM_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 TCAM context, hash bucket\n+ * handle, and shadow index.\n+ */\n+static inline int\n+tf_shadow_tcam_set_hash_entry(struct tf_shadow_tcam_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_TCAM_HB_HANDLE_HASH_GET(ctxt, hb_handle);\n+\tuint16_t be = TF_SHADOW_TCAM_HB_HANDLE_BE_GET(hb_handle);\n+\tuint64_t entry = sh_idx | TF_SHADOW_TCAM_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 TCAM context and hash bucket handle.\n+ */\n+static inline void\n+tf_shadow_tcam_clear_hash_entry(struct tf_shadow_tcam_ctxt *ctxt,\n+\t\t\t\tuint32_t hb_handle)\n+{\n+\tuint16_t hid, be;\n+\tuint64_t *bucket;\n+\n+\tif (!TF_SHADOW_TCAM_HB_HANDLE_IS_VALID(hb_handle))\n+\t\treturn;\n+\n+\thid = TF_SHADOW_TCAM_HB_HANDLE_HASH_GET(ctxt, hb_handle);\n+\tbe = TF_SHADOW_TCAM_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_TCAM_BE0_MASK_CLEAR(*bucket);\n+\t\tbreak;\n+\tcase 1:\n+\t\t*bucket = TF_SHADOW_TCAM_BE1_MASK_CLEAR(*bucket);\n+\t\tbreak;\n+\tcase 2:\n+\t\t*bucket = TF_SHADOW_TCAM_BE2_MASK_CLEAR(*bucket);\n+\t\tbreak;\n+\tcase 3:\n+\t\t*bucket = TF_SHADOW_TCAM_BE2_MASK_CLEAR(*bucket);\n+\t\tbreak;\n+\t}\n+}\n+\n+/**\n+ * Clears the shadow key and result entries given the TCAM context and\n+ * shadow index.\n+ */\n+static void\n+tf_shadow_tcam_clear_sh_entry(struct tf_shadow_tcam_ctxt *ctxt,\n+\t\t\t      uint16_t sh_idx)\n+{\n+\tstruct tf_shadow_tcam_shadow_key_entry *sk_entry;\n+\tstruct tf_shadow_tcam_shadow_result_entry *sr_entry;\n+\n+\tif (sh_idx >= tf_shadow_tcam_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_tcam_shadow_key_entry));\n+\tmemset(sr_entry, 0, sizeof(struct tf_shadow_tcam_shadow_result_entry));\n+}\n+\n+/**\n+ * Binds the allocated tcam 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_tcam_create_db(struct tf_shadow_tcam_create_db_parms *parms __rte_unused)\n+tf_shadow_tcam_bind_index(struct tf_shadow_tcam_bind_index_parms *parms)\n {\n+\tint rc;\n+\tint i;\n+\tuint16_t idx, klen;\n+\tstruct tf_shadow_tcam_ctxt *ctxt;\n+\tstruct tf_shadow_tcam_db *shadow_db;\n+\tstruct tf_shadow_tcam_shadow_key_entry *sk_entry;\n+\tstruct tf_shadow_tcam_shadow_result_entry *sr_entry;\n+\tuint8_t tkey[TF_SHADOW_TCAM_MAX_KEY_SZ];\n+\n+\tif (!parms || !TF_SHADOW_TCAM_HB_HANDLE_IS_VALID(parms->hb_handle) ||\n+\t    !parms->key || !parms->mask) {\n+\t\tTFP_DRV_LOG(ERR, \"Invalid parms\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tshadow_db = (struct tf_shadow_tcam_db *)parms->shadow_db;\n+\tctxt = tf_shadow_tcam_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_tcam_tbl_2_str(parms->type));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmemset(tkey, 0, sizeof(tkey));\n+\tidx = TF_SHADOW_TCAM_IDX_TO_SHIDX(ctxt, parms->idx);\n+\tklen = parms->key_size;\n+\tif (idx >= tf_shadow_tcam_sh_num_entries_get(ctxt) ||\n+\t    klen > TF_SHADOW_TCAM_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_tcam_tbl_2_str(parms->type),\n+\t\t\t    klen,\n+\t\t\t    TF_SHADOW_TCAM_MAX_KEY_SZ, idx);\n+\n+\t\treturn -EINVAL;\n+\t}\n+\n+\trc = tf_shadow_tcam_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/*\n+\t * Write the masked key to the table for more efficient comparisons\n+\t * later.\n+\t */\n+\tfor (i = 0; i < klen; i++)\n+\t\ttkey[i] = parms->key[i] & parms->mask[i];\n+\n+\tmemcpy(sk_entry->key, tkey, klen);\n+\tmemcpy(sk_entry->mask, parms->mask, klen);\n+\n+\t/* Write the result table */\n+\tsr_entry->key_size = parms->key_size;\n+\tsr_entry->hb_handle = parms->hb_handle;\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 tcam entry in hardware.\n+ * Returns non-zero - The number of references to the entry\n+ */\n int\n-tf_shadow_tcam_free_db(struct tf_shadow_tcam_free_db_parms *parms __rte_unused)\n+tf_shadow_tcam_remove(struct tf_shadow_tcam_remove_parms *parms)\n {\n+\tuint16_t idx;\n+\tuint32_t hb_handle;\n+\tstruct tf_shadow_tcam_ctxt *ctxt;\n+\tstruct tf_shadow_tcam_db *shadow_db;\n+\tstruct tf_tcam_free_parms *fparms;\n+\tstruct tf_shadow_tcam_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+\n+\t/*\n+\t * Initialize the reference count to zero.  It will only be changed if\n+\t * non-zero.\n+\t */\n+\tfparms->ref_cnt = 0;\n+\n+\tshadow_db = (struct tf_shadow_tcam_db *)parms->shadow_db;\n+\tctxt = tf_shadow_tcam_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_tcam_tbl_2_str(fparms->type));\n+\t\treturn 0;\n+\t}\n+\n+\tidx = TF_SHADOW_TCAM_IDX_TO_SHIDX(ctxt, fparms->idx);\n+\tif (idx >= tf_shadow_tcam_sh_num_entries_get(ctxt)) {\n+\t\tTFP_DRV_LOG(DEBUG, \"%s %d >= %d\\n\",\n+\t\t\t    tf_tcam_tbl_2_str(fparms->type),\n+\t\t\t    fparms->idx,\n+\t\t\t    tf_shadow_tcam_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_tcam_clear_hash_entry(ctxt, hb_handle);\n+\t\ttf_shadow_tcam_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_tcam_search(struct tf_shadow_tcam_search_parms *parms __rte_unused)\n+tf_shadow_tcam_search(struct tf_shadow_tcam_search_parms *parms)\n {\n+\tuint16_t len;\n+\tuint8_t rcopy;\n+\tuint64_t bucket;\n+\tuint32_t i, hid32;\n+\tstruct tf_shadow_tcam_ctxt *ctxt;\n+\tstruct tf_shadow_tcam_db *shadow_db;\n+\tuint16_t hid16, hb_idx, hid_mask, shtbl_idx, shtbl_key, be_valid;\n+\tstruct tf_tcam_alloc_search_parms *sparms;\n+\tuint8_t tkey[TF_SHADOW_TCAM_MAX_KEY_SZ];\n+\tuint32_t be_avail = TF_SHADOW_TCAM_HB_NUM_ELEM;\n+\n+\tif (!parms || !parms->sparms) {\n+\t\tTFP_DRV_LOG(ERR, \"tcam search with invalid parms\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmemset(tkey, 0, sizeof(tkey));\n+\tsparms = parms->sparms;\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+\t/* see if caller wanted the result */\n+\trcopy = sparms->result && sparms->result_size;\n+\n+\tshadow_db = (struct tf_shadow_tcam_db *)parms->shadow_db;\n+\tctxt = tf_shadow_tcam_ctxt_get(shadow_db, sparms->type);\n+\tif (!ctxt) {\n+\t\tTFP_DRV_LOG(ERR, \"%s Unable to get tcam mgr context\\n\",\n+\t\t\t    tf_tcam_tbl_2_str(sparms->type));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\thid_mask = ctxt->hash_ctxt.hid_mask;\n+\n+\tlen = sparms->key_size;\n+\n+\tif (len > TF_SHADOW_TCAM_MAX_KEY_SZ ||\n+\t    !sparms->key || !sparms->mask || !len) {\n+\t\tTFP_DRV_LOG(ERR, \"%s:%s Invalid parms %d : %p : %p\\n\",\n+\t\t\t    tf_dir_2_str(sparms->dir),\n+\t\t\t    tf_tcam_tbl_2_str(sparms->type),\n+\t\t\t    len,\n+\t\t\t    sparms->key,\n+\t\t\t    sparms->mask);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* Combine the key and mask */\n+\tfor (i = 0; i < len; i++)\n+\t\ttkey[i] = sparms->key[i] & sparms->mask[i];\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_shadow_tcam_crc32_calc(tkey, len);\n+\thid16 = (uint16_t)(((hid32 >> 16) & 0xffff) ^ (hid32 & 0xffff));\n+\thb_idx = hid16 & hid_mask;\n+\n+\tbucket = ctxt->hash_ctxt.hashtbl[hb_idx];\n+\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_TCAM_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_TCAM_HB_NUM_ELEM;\n+\tfor (i = 0; i < TF_SHADOW_TCAM_HB_NUM_ELEM; i++) {\n+\t\tshtbl_idx = (uint16_t)((bucket >> (i * 16)) & 0xffff);\n+\t\tbe_valid = TF_SHADOW_TCAM_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_TCAM_BE_VALID;\n+\t\tif (!tf_shadow_tcam_key_cmp(ctxt,\n+\t\t\t\t\t    sparms->key,\n+\t\t\t\t\t    sparms->mask,\n+\t\t\t\t\t    shtbl_key,\n+\t\t\t\t\t    sparms->key_size)) {\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_TCAM_HB_HANDLE_CREATE(hb_idx, i);\n+\t\t\tsparms->idx = TF_SHADOW_TCAM_SHIDX_TO_IDX(ctxt,\n+\t\t\t\t\t\t\t\t  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\t/* copy the result, if caller wanted it. */\n+\t\t\tif (rcopy &&\n+\t\t\t    !tf_shadow_tcam_res_cpy(ctxt,\n+\t\t\t\t\t\t    sparms->result,\n+\t\t\t\t\t\t    shtbl_key,\n+\t\t\t\t\t\t    sparms->result_size)) {\n+\t\t\t\t/*\n+\t\t\t\t * Should never get here, possible memory\n+\t\t\t\t * corruption or something unexpected.\n+\t\t\t\t */\n+\t\t\t\tTFP_DRV_LOG(ERR, \"Error copying result\\n\");\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\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_TCAM_HB_NUM_ELEM) {\n+\t\tparms->hb_handle =\n+\t\t\tTF_SHADOW_TCAM_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\tsparms->search_status = REJECT;\n+\t}\n+\n \treturn 0;\n }\n \n int\n-tf_shadow_tcam_insert(struct tf_shadow_tcam_insert_parms *parms __rte_unused)\n+tf_shadow_tcam_insert(struct tf_shadow_tcam_insert_parms *parms)\n {\n+\tuint16_t idx;\n+\tstruct tf_shadow_tcam_ctxt *ctxt;\n+\tstruct tf_tcam_set_parms *sparms;\n+\tstruct tf_shadow_tcam_db *shadow_db;\n+\tstruct tf_shadow_tcam_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->result || !sparms->result_size) {\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_tcam_tbl_2_str(sparms->type));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tshadow_db = (struct tf_shadow_tcam_db *)parms->shadow_db;\n+\tctxt = tf_shadow_tcam_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 tcam mgr context\\n\",\n+\t\t\t    tf_tcam_tbl_2_str(sparms->type));\n+\t\treturn 0;\n+\t}\n+\n+\tidx = TF_SHADOW_TCAM_IDX_TO_SHIDX(ctxt, sparms->idx);\n+\tif (idx >= tf_shadow_tcam_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_tcam_tbl_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_TCAM_HB_HANDLE_IS_VALID(sr_entry->hb_handle))\n+\t\treturn 0;\n+\n+\tif (sparms->result_size > TF_SHADOW_TCAM_MAX_RESULT_SZ) {\n+\t\tTFP_DRV_LOG(ERR, \"%s:%s Result length %d > %d\\n\",\n+\t\t\t    tf_dir_2_str(sparms->dir),\n+\t\t\t    tf_tcam_tbl_2_str(sparms->type),\n+\t\t\t    sparms->result_size,\n+\t\t\t    TF_SHADOW_TCAM_MAX_RESULT_SZ);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmemcpy(sr_entry->result, sparms->result, sparms->result_size);\n+\tsr_entry->result_size = sparms->result_size;\n+\tsr_entry->refcnt = 1;\n+\n \treturn 0;\n }\n \n int\n-tf_shadow_tcam_remove(struct tf_shadow_tcam_remove_parms *parms __rte_unused)\n+tf_shadow_tcam_free_db(struct tf_shadow_tcam_free_db_parms *parms)\n+{\n+\tstruct tf_shadow_tcam_db *shadow_db;\n+\tint i;\n+\n+\tTF_CHECK_PARMS1(parms);\n+\n+\tshadow_db = (struct tf_shadow_tcam_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_TCAM_TBL_TYPE_MAX; i++) {\n+\t\tif (shadow_db->ctxt[i]) {\n+\t\t\ttf_shadow_tcam_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 TCAM resources for search and allocate\n+ *\n+ */\n+int tf_shadow_tcam_create_db(struct tf_shadow_tcam_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_tcam_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_tcam_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_TCAM_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\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_tcam_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_tcam_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 TCAM - initialized\\n\");\n+\n \treturn 0;\n+error:\n+\tfor (i = 0; i < TF_TCAM_TBL_TYPE_MAX; i++) {\n+\t\tif (shadow_db->ctxt[i]) {\n+\t\t\ttf_shadow_tcam_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_tcam.h b/drivers/net/bnxt/tf_core/tf_shadow_tcam.h\nindex e2c4e06..75c146a 100644\n--- a/drivers/net/bnxt/tf_core/tf_shadow_tcam.h\n+++ b/drivers/net/bnxt/tf_core/tf_shadow_tcam.h\n@@ -8,232 +8,188 @@\n \n #include \"tf_core.h\"\n \n-struct tf;\n-\n-/**\n- * The Shadow tcam module provides shadow DB handling for tcam based\n- * TF types. A shadow DB provides the capability that allows for reuse\n- * of TF resources.\n- *\n- * A Shadow tcam DB is intended to be used by the Tcam module only.\n- */\n-\n /**\n- * Shadow DB configuration information for a single tcam type.\n- *\n- * During Device initialization the HCAPI device specifics are learned\n- * and as well as the RM DB creation. From that those initial steps\n- * this structure can be populated.\n+ * Shadow DB configuration information\n  *\n- * NOTE:\n- * If used in an array of tcam types then such array must be ordered\n- * by the TF type is represents.\n+ * The shadow configuration is for all tcam table types for a direction\n  */\n struct tf_shadow_tcam_cfg_parms {\n \t/**\n-\t * TF tcam 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_TCAM_TBL_TYPE_MAX\n \t */\n-\tenum tf_tcam_tbl_type type;\n-\n+\tint num_entries;\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_TCAM_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 tcam table\n \t */\n-\tint element_width;\n+\tuint16_t base_addr[TF_TCAM_TBL_TYPE_MAX];\n };\n \n /**\n- * Shadow tcam DB creation parameters\n+ * Shadow TCAM  DB creation parameters.  The shadow db for this direction\n+ * is returned\n  */\n struct tf_shadow_tcam_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_tcam_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_tcam_cfg_parms *cfg;\n \t/**\n \t * [out] Shadow tcam DB handle\n \t */\n-\tvoid *tf_shadow_tcam_db;\n+\tvoid **shadow_db;\n };\n \n /**\n- * Shadow tcam DB free parameters\n+ * Create the shadow db for a single direction\n+ *\n+ * The returned shadow db must be free using the free db API when no longer\n+ * needed\n  */\n-struct tf_shadow_tcam_free_db_parms {\n-\t/**\n-\t * Shadow tcam DB handle\n-\t */\n-\tvoid *tf_shadow_tcam_db;\n-};\n+int\n+tf_shadow_tcam_create_db(struct tf_shadow_tcam_create_db_parms *parms);\n \n /**\n- * Shadow tcam search parameters\n+ * Shadow TCAM free parameters\n  */\n-struct tf_shadow_tcam_search_parms {\n+struct tf_shadow_tcam_free_db_parms {\n \t/**\n \t * [in] Shadow tcam DB handle\n \t */\n-\tvoid *tf_shadow_tcam_db;\n-\t/**\n-\t * [in] TCAM tbl type\n-\t */\n-\tenum tf_tcam_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-\t/**\n-\t * [out] Reference count incremented if hit\n-\t */\n-\tuint16_t *ref_cnt;\n+\tvoid *shadow_db;\n };\n \n /**\n- * Shadow tcam insert parameters\n+ * Free all resources associated with the shadow db\n+ */\n+int\n+tf_shadow_tcam_free_db(struct tf_shadow_tcam_free_db_parms *parms);\n+\n+/**\n+ * Shadow TCAM bind index parameters\n  */\n-struct tf_shadow_tcam_insert_parms {\n+struct tf_shadow_tcam_bind_index_parms {\n \t/**\n \t * [in] Shadow tcam DB handle\n \t */\n-\tvoid *tf_shadow_tcam_db;\n+\tvoid *shadow_db;\n \t/**\n-\t * [in] TCAM 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_tcam_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 *key;\n \t/**\n-\t * [in] Entry to update\n+\t * [in] struct containing mask fields\n \t */\n-\tuint16_t index;\n+\tuint8_t *mask;\n \t/**\n-\t * [out] Reference count after insert\n+\t * [in] key size in bits (if search)\n \t */\n-\tuint16_t *ref_cnt;\n+\tuint16_t key_size;\n+\t/**\n+\t * [in] The hash bucket handled returned from the search\n+\t */\n+\tuint32_t hb_handle;\n };\n \n /**\n- * Shadow tcam remove parameters\n+ * Binds the allocated tcam index with the hash and shadow tables\n  */\n-struct tf_shadow_tcam_remove_parms {\n+int\n+tf_shadow_tcam_bind_index(struct tf_shadow_tcam_bind_index_parms *parms);\n+\n+/**\n+ * Shadow TCAM insert parameters\n+ */\n+struct\ttf_shadow_tcam_insert_parms {\n \t/**\n \t * [in] Shadow tcam DB handle\n \t */\n-\tvoid *tf_shadow_tcam_db;\n-\t/**\n-\t * [in] TCAM tbl type\n-\t */\n-\tenum tf_tcam_tbl_type type;\n-\t/**\n-\t * [in] Entry to update\n-\t */\n-\tuint16_t index;\n+\tvoid *shadow_db;\n \t/**\n-\t * [out] Reference count after removal\n+\t * [in] The set parms from tf core\n \t */\n-\tuint16_t *ref_cnt;\n+\tstruct tf_tcam_set_parms *sparms;\n };\n \n /**\n- * @page shadow_tcam Shadow tcam DB\n- *\n- * @ref tf_shadow_tcam_create_db\n- *\n- * @ref tf_shadow_tcam_free_db\n- *\n- * @reg tf_shadow_tcam_search\n- *\n- * @reg tf_shadow_tcam_insert\n- *\n- * @reg tf_shadow_tcam_remove\n- */\n-\n-/**\n- * Creates and fills a Shadow tcam DB. The DB is indexed per the\n- * parms structure.\n- *\n- * [in] parms\n- *   Pointer to create db parameters\n+ * Set the entry into the tcam manager hash and shadow tables\n  *\n- * Returns\n- *   - (0) if successful.\n- *   - (-EINVAL) on failure.\n+ * The search must have been used prior to setting the entry so that the\n+ * hash has been calculated and duplicate entries will not be added\n  */\n-int tf_shadow_tcam_create_db(struct tf_shadow_tcam_create_db_parms *parms);\n+int\n+tf_shadow_tcam_insert(struct tf_shadow_tcam_insert_parms *parms);\n \n /**\n- * Closes the Shadow tcam DB and frees all allocated\n- * resources per the associated database.\n- *\n- * [in] parms\n- *   Pointer to the free DB parameters\n- *\n- * Returns\n- *   - (0) if successful.\n- *   - (-EINVAL) on failure.\n+ * Shadow TCAM remove parameters\n  */\n-int tf_shadow_tcam_free_db(struct tf_shadow_tcam_free_db_parms *parms);\n+struct tf_shadow_tcam_remove_parms {\n+\t/**\n+\t * [in] Shadow tcam DB handle\n+\t */\n+\tvoid *shadow_db;\n+\t/**\n+\t * [inout] The set parms from tf core\n+\t */\n+\tstruct tf_tcam_free_parms *fparms;\n+};\n \n /**\n- * Search Shadow tcam db for matching result\n- *\n- * [in] parms\n- *   Pointer to the search parameters\n+ * Remove the entry from the tcam hash and shadow tables\n  *\n- * Returns\n- *   - (0) if successful, element was found.\n- *   - (-EINVAL) on failure.\n+ * The search must have been used prior to setting the entry so that the\n+ * hash has been calculated and duplicate entries will not be added\n  */\n-int tf_shadow_tcam_search(struct tf_shadow_tcam_search_parms *parms);\n+int\n+tf_shadow_tcam_remove(struct tf_shadow_tcam_remove_parms *parms);\n \n /**\n- * Inserts an element into the Shadow tcam DB. Will fail if the\n- * elements ref_count is different from 0. Ref_count after insert will\n- * be incremented.\n- *\n- * [in] parms\n- *   Pointer to insert parameters\n- *\n- * Returns\n- *   - (0) if successful.\n- *   - (-EINVAL) on failure.\n+ * Shadow TCAM search parameters\n  */\n-int tf_shadow_tcam_insert(struct tf_shadow_tcam_insert_parms *parms);\n+struct tf_shadow_tcam_search_parms {\n+\t/**\n+\t * [in] Shadow tcam DB handle\n+\t */\n+\tvoid *shadow_db;\n+\t/**\n+\t * [inout] The search parameters from tf core\n+\t */\n+\tstruct tf_tcam_alloc_search_parms *sparms;\n+\t/**\n+\t * [out] The hash handle to use for the set\n+\t */\n+\tuint32_t hb_handle;\n+};\n \n /**\n- * Removes an element from the Shadow tcam DB. Will fail if the\n- * elements ref_count is 0. Ref_count after removal will be\n- * decremented.\n+ * Search for an entry in the tcam hash/shadow tables\n  *\n- * [in] parms\n- *   Pointer to remove parameter\n- *\n- * Returns\n- *   - (0) if successful.\n- *   - (-EINVAL) on failure.\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_tcam_remove(struct tf_shadow_tcam_remove_parms *parms);\n-\n-#endif /* _TF_SHADOW_TCAM_H_ */\n+int\n+tf_shadow_tcam_search(struct tf_shadow_tcam_search_parms *parms);\n+#endif\ndiff --git a/drivers/net/bnxt/tf_core/tf_tcam.c b/drivers/net/bnxt/tf_core/tf_tcam.c\nindex cbfaa94..7679d09 100644\n--- a/drivers/net/bnxt/tf_core/tf_tcam.c\n+++ b/drivers/net/bnxt/tf_core/tf_tcam.c\n@@ -14,6 +14,7 @@\n #include \"tfp.h\"\n #include \"tf_session.h\"\n #include \"tf_msg.h\"\n+#include \"tf_shadow_tcam.h\"\n \n struct tf;\n \n@@ -25,7 +26,7 @@ static void *tcam_db[TF_DIR_MAX];\n /**\n  * TCAM Shadow DBs\n  */\n-/* static void *shadow_tcam_db[TF_DIR_MAX]; */\n+static void *shadow_tcam_db[TF_DIR_MAX];\n \n /**\n  * Init flag, set on bind and cleared on unbind\n@@ -35,16 +36,22 @@ 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_tcam_bind(struct tf *tfp,\n \t     struct tf_tcam_cfg_parms *parms)\n {\n \tint rc;\n-\tint i;\n+\tint i, d;\n+\tstruct tf_rm_alloc_info info;\n+\tstruct tf_rm_free_db_parms fparms;\n+\tstruct tf_rm_create_db_parms db_cfg;\n \tstruct tf_tcam_resources *tcam_cnt;\n-\tstruct tf_rm_create_db_parms db_cfg = { 0 };\n+\tstruct tf_shadow_tcam_free_db_parms fshadow;\n+\tstruct tf_rm_get_alloc_info_parms ainfo;\n+\tstruct tf_shadow_tcam_cfg_parms shadow_cfg;\n+\tstruct tf_shadow_tcam_create_db_parms shadow_cdb;\n \n \tTF_CHECK_PARMS2(tfp, parms);\n \n@@ -62,29 +69,91 @@ tf_tcam_bind(struct tf *tfp,\n \t\treturn -EINVAL;\n \t}\n \n+\tmemset(&db_cfg, 0, sizeof(db_cfg));\n+\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.alloc_cnt = parms->resources->tcam_cnt[i].cnt;\n-\t\tdb_cfg.rm_db = &tcam_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->tcam_cnt[d].cnt;\n+\t\tdb_cfg.rm_db = &tcam_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: TCAM 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 \t\t\treturn rc;\n \t\t}\n \t}\n \n+\t/* Initialize the TCAM manager. */\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 tcams for tcam mgr */\n+\t\t\tfor (i = 0; i < TF_TCAM_TBL_TYPE_MAX; i++) {\n+\t\t\t\tmemset(&info, 0, sizeof(info));\n+\n+\t\t\t\tif (!parms->resources->tcam_cnt[d].cnt[i])\n+\t\t\t\t\tcontinue;\n+\t\t\t\tainfo.rm_db = tcam_db[d];\n+\t\t\t\tainfo.db_index = i;\n+\t\t\t\ = &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->tcam_cnt[d].cnt;\n+\t\t\tshadow_cfg.num_entries = parms->num_elements;\n+\n+\t\t\tshadow_cdb.shadow_db = &shadow_tcam_db[d];\n+\t\t\tshadow_cdb.cfg = &shadow_cfg;\n+\t\t\trc = tf_shadow_tcam_create_db(&shadow_cdb);\n+\t\t\tif (rc) {\n+\t\t\t\tTFP_DRV_LOG(ERR,\n+\t\t\t\t\t    \"TCAM MGR 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    \"TCAM - initialized\\n\");\n \n \treturn 0;\n+error:\n+\tfor (i = 0; i < TF_DIR_MAX; i++) {\n+\t\tmemset(&fparms, 0, sizeof(fparms));\n+\t\tfparms.dir = i;\n+\t\tfparms.rm_db = tcam_db[i];\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_tcam_db[i];\n+\t\t\ttf_shadow_tcam_free_db(&fshadow);\n+\t\t\tshadow_tcam_db[i] = NULL;\n+\t\t}\n+\n+\t\ttcam_db[i] = NULL;\n+\t}\n+\n+\tshadow_init = 0;\n+\tinit = 0;\n+\n+\treturn rc;\n }\n \n int\n@@ -92,7 +161,8 @@ tf_tcam_unbind(struct tf *tfp)\n {\n \tint rc;\n \tint i;\n-\tstruct tf_rm_free_db_parms fparms = { 0 };\n+\tstruct tf_rm_free_db_parms fparms;\n+\tstruct tf_shadow_tcam_free_db_parms fshadow;\n \n \tTF_CHECK_PARMS1(tfp);\n \n@@ -104,6 +174,7 @@ tf_tcam_unbind(struct tf *tfp)\n \t}\n \n \tfor (i = 0; i < TF_DIR_MAX; i++) {\n+\t\tmemset(&fparms, 0, sizeof(fparms));\n \t\tfparms.dir = i;\n \t\tfparms.rm_db = tcam_db[i];\n \t\trc = tf_rm_free_db(tfp, &fparms);\n@@ -111,8 +182,17 @@ tf_tcam_unbind(struct tf *tfp)\n \t\t\treturn rc;\n \n \t\ttcam_db[i] = NULL;\n+\n+\t\tif (shadow_init) {\n+\t\t\tmemset(&fshadow, 0, sizeof(fshadow));\n+\n+\t\t\tfshadow.shadow_db = shadow_tcam_db[i];\n+\t\t\ttf_shadow_tcam_free_db(&fshadow);\n+\t\t\tshadow_tcam_db[i] = NULL;\n+\t\t}\n \t}\n \n+\tshadow_init = 0;\n \tinit = 0;\n \n \treturn 0;\n@@ -125,7 +205,7 @@ tf_tcam_alloc(struct tf *tfp,\n \tint rc;\n \tstruct tf_session *tfs;\n \tstruct tf_dev_info *dev;\n-\tstruct tf_rm_allocate_parms aparms = { 0 };\n+\tstruct tf_rm_allocate_parms aparms;\n \tuint16_t num_slice_per_row = 1;\n \n \tTF_CHECK_PARMS2(tfp, parms);\n@@ -165,6 +245,8 @@ tf_tcam_alloc(struct tf *tfp,\n \t\treturn rc;\n \n \t/* Allocate requested element */\n+\tmemset(&aparms, 0, sizeof(aparms));\n+\n \taparms.rm_db = tcam_db[parms->dir];\n \taparms.db_index = parms->type;\n \taparms.priority = parms->priority;\n@@ -202,11 +284,12 @@ tf_tcam_free(struct tf *tfp,\n \tint rc;\n \tstruct tf_session *tfs;\n \tstruct tf_dev_info *dev;\n-\tstruct tf_rm_is_allocated_parms aparms = { 0 };\n-\tstruct tf_rm_free_parms fparms = { 0 };\n-\tstruct tf_rm_get_hcapi_parms hparms = { 0 };\n+\tstruct tf_rm_is_allocated_parms aparms;\n+\tstruct tf_rm_free_parms fparms;\n+\tstruct tf_rm_get_hcapi_parms hparms;\n \tuint16_t num_slice_per_row = 1;\n \tint allocated = 0;\n+\tstruct tf_shadow_tcam_remove_parms shparms;\n \n \tTF_CHECK_PARMS2(tfp, parms);\n \n@@ -245,6 +328,8 @@ tf_tcam_free(struct tf *tfp,\n \t\treturn rc;\n \n \t/* Check if element is in use */\n+\tmemset(&aparms, 0, sizeof(aparms));\n+\n \taparms.rm_db = tcam_db[parms->dir];\n \taparms.db_index = parms->type;\n \taparms.index = parms->idx / num_slice_per_row;\n@@ -262,7 +347,37 @@ tf_tcam_free(struct tf *tfp,\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\tshparms.shadow_db = shadow_tcam_db[parms->dir];\n+\t\tshparms.fparms = parms;\n+\t\trc = tf_shadow_tcam_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 or hw\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+\tmemset(&fparms, 0, sizeof(fparms));\n \tfparms.rm_db = tcam_db[parms->dir];\n \tfparms.db_index = parms->type;\n \tfparms.index = parms->idx / num_slice_per_row;\n@@ -291,7 +406,8 @@ tf_tcam_free(struct tf *tfp,\n \t\t\t\trc = tf_rm_free(&fparms);\n \t\t\t\tif (rc) {\n \t\t\t\t\tTFP_DRV_LOG(ERR,\n-\t\t\t\t\t\t    \"%s: Free failed, type:%d, index:%d\\n\",\n+\t\t\t\t\t\t    \"%s: Free failed, type:%d, \"\n+\t\t\t\t\t\t    \"index:%d\\n\",\n \t\t\t\t\t\t    tf_dir_2_str(parms->dir),\n \t\t\t\t\t\t    parms->type,\n \t\t\t\t\t\t    fparms.index);\n@@ -302,6 +418,8 @@ tf_tcam_free(struct tf *tfp,\n \t}\n \n \t/* Convert TF type to HCAPI RM type */\n+\tmemset(&hparms, 0, sizeof(hparms));\n+\n \thparms.rm_db = tcam_db[parms->dir];\n \thparms.db_index = parms->type;\n \thparms.hcapi_type = &parms->hcapi_type;\n@@ -326,9 +444,131 @@ tf_tcam_free(struct tf *tfp,\n }\n \n int\n-tf_tcam_alloc_search(struct tf *tfp __rte_unused,\n-\t\t     struct tf_tcam_alloc_search_parms *parms __rte_unused)\n+tf_tcam_alloc_search(struct tf *tfp,\n+\t\t     struct tf_tcam_alloc_search_parms *parms)\n {\n+\tstruct tf_shadow_tcam_search_parms sparms;\n+\tstruct tf_shadow_tcam_bind_index_parms bparms;\n+\tstruct tf_tcam_alloc_parms aparms;\n+\tstruct tf_tcam_free_parms fparms;\n+\tuint16_t num_slice_per_row = 1;\n+\tstruct tf_session *tfs;\n+\tstruct tf_dev_info *dev;\n+\tint rc;\n+\n+\tTF_CHECK_PARMS2(tfp, parms);\n+\n+\tif (!init) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"%s: No TCAM DBs created\\n\",\n+\t\t\t    tf_dir_2_str(parms->dir));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!shadow_init || !shadow_tcam_db[parms->dir]) {\n+\t\tTFP_DRV_LOG(ERR, \"%s: TCAM Shadow not initialized for %s\\n\",\n+\t\t\t    tf_dir_2_str(parms->dir),\n+\t\t\t    tf_tcam_tbl_2_str(parms->type));\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* Retrieve the session information */\n+\trc = tf_session_get_session_internal(tfp, &tfs);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\t/* Retrieve the device information */\n+\trc = tf_session_get_device(tfs, &dev);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\tif (dev->ops->tf_dev_get_tcam_slice_info == 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+\t/* Need to retrieve row size etc */\n+\trc = dev->ops->tf_dev_get_tcam_slice_info(tfp,\n+\t\t\t\t\t\t  parms->type,\n+\t\t\t\t\t\t  parms->key_size,\n+\t\t\t\t\t\t  &num_slice_per_row);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\t/*\n+\t * Prep the shadow search, reusing the parms from original search\n+\t * instead of copying them.  Shadow will update output in there.\n+\t */\n+\tmemset(&sparms, 0, sizeof(sparms));\n+\tsparms.sparms = parms;\n+\tsparms.shadow_db = shadow_tcam_db[parms->dir];\n+\n+\trc = tf_shadow_tcam_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/* Caller desires an allocate on miss */\n+\tif (dev->ops->tf_dev_alloc_tcam == 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+\tmemset(&aparms, 0, sizeof(aparms));\n+\taparms.dir = parms->dir;\n+\taparms.type = parms->type;\n+\taparms.key_size = parms->key_size;\n+\taparms.priority = parms->priority;\n+\trc = dev->ops->tf_dev_alloc_tcam(tfp, &aparms);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\t/* Successful allocation, attempt to add it to the shadow */\n+\tmemset(&bparms, 0, sizeof(bparms));\n+\tbparms.dir = parms->dir;\n+\tbparms.shadow_db = shadow_tcam_db[parms->dir];\n+\tbparms.type = parms->type;\n+\tbparms.key = parms->key;\n+\tbparms.mask = parms->mask;\n+\tbparms.key_size = parms->key_size;\n+\tbparms.idx = aparms.idx;\n+\tbparms.hb_handle = sparms.hb_handle;\n+\trc = tf_shadow_tcam_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_tcam == 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\tfparms.dir = parms->dir;\n+\t\tfparms.type = parms->type;\n+\t\tfparms.idx = aparms.idx;\n+\t\trc = dev->ops->tf_dev_free_tcam(tfp, &fparms);\n+\t\tif (rc)\n+\t\t\treturn rc;\n+\t}\n+\n+\t/* Add the allocated index to output and done */\n+\tparms->idx = aparms.idx;\n+\n \treturn 0;\n }\n \n@@ -339,8 +579,9 @@ tf_tcam_set(struct tf *tfp __rte_unused,\n \tint rc;\n \tstruct tf_session *tfs;\n \tstruct tf_dev_info *dev;\n-\tstruct tf_rm_is_allocated_parms aparms = { 0 };\n-\tstruct tf_rm_get_hcapi_parms hparms = { 0 };\n+\tstruct tf_rm_is_allocated_parms aparms;\n+\tstruct tf_rm_get_hcapi_parms hparms;\n+\tstruct tf_shadow_tcam_insert_parms iparms;\n \tuint16_t num_slice_per_row = 1;\n \tint allocated = 0;\n \n@@ -381,6 +622,8 @@ tf_tcam_set(struct tf *tfp __rte_unused,\n \t\treturn rc;\n \n \t/* Check if element is in use */\n+\tmemset(&aparms, 0, sizeof(aparms));\n+\n \taparms.rm_db = tcam_db[parms->dir];\n \taparms.db_index = parms->type;\n \taparms.index = parms->idx / num_slice_per_row;\n@@ -399,6 +642,8 @@ tf_tcam_set(struct tf *tfp __rte_unused,\n \t}\n \n \t/* Convert TF type to HCAPI RM type */\n+\tmemset(&hparms, 0, sizeof(hparms));\n+\n \thparms.rm_db = tcam_db[parms->dir];\n \thparms.db_index = parms->type;\n \thparms.hcapi_type = &parms->hcapi_type;\n@@ -419,6 +664,23 @@ tf_tcam_set(struct tf *tfp __rte_unused,\n \t\treturn rc;\n \t}\n \n+\t/* Successfully added to hw, now for shadow if enabled. */\n+\tif (!shadow_init || !shadow_tcam_db[parms->dir])\n+\t\treturn 0;\n+\n+\tiparms.shadow_db = shadow_tcam_db[parms->dir];\n+\tiparms.sparms = parms;\n+\trc = tf_shadow_tcam_insert(&iparms);\n+\tif (rc) {\n+\t\tTFP_DRV_LOG(ERR,\n+\t\t\t    \"%s: %s: Entry %d set failed, rc:%s\",\n+\t\t\t    tf_dir_2_str(parms->dir),\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 }\n \ndiff --git a/drivers/net/bnxt/tf_core/tf_tcam.h b/drivers/net/bnxt/tf_core/tf_tcam.h\nindex ee5bacc..4722ce0 100644\n--- a/drivers/net/bnxt/tf_core/tf_tcam.h\n+++ b/drivers/net/bnxt/tf_core/tf_tcam.h\n@@ -104,19 +104,19 @@ struct tf_tcam_alloc_search_parms {\n \t */\n \tenum tf_tcam_tbl_type type;\n \t/**\n-\t * [in] Enable search for matching entry\n+\t * [in] Type of HCAPI\n \t */\n-\tuint8_t search_enable;\n+\tuint16_t hcapi_type;\n \t/**\n-\t * [in] Key data to match on (if search)\n+\t * [in] Key data to match on\n \t */\n \tuint8_t *key;\n \t/**\n-\t * [in] key size (if search)\n+\t * [in] key size in bits\n \t */\n \tuint16_t key_size;\n \t/**\n-\t * [in] Mask data to match on (if search)\n+\t * [in] Mask data to match on\n \t */\n \tuint8_t *mask;\n \t/**\n@@ -124,16 +124,31 @@ struct tf_tcam_alloc_search_parms {\n \t */\n \tuint32_t priority;\n \t/**\n-\t * [out] If search, set if matching entry found\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_tcam_search_status search_status;\n+\t/**\n \t * [out] Current refcnt after allocation\n \t */\n \tuint16_t ref_cnt;\n \t/**\n-\t * [out] Idx allocated\n-\t *\n+\t * [inout] The result data from the search is copied here\n+\t */\n+\tuint8_t *result;\n+\t/**\n+\t * [inout] result size in bits for the result data\n+\t */\n+\tuint16_t result_size;\n+\t/**\n+\t * [out] Index found\n \t */\n \tuint16_t idx;\n };\n",
    "prefixes": [