net/bnxt: support shared TCAM region
authorFarah Smith <farah.smith@broadcom.com>
Sun, 30 May 2021 08:58:49 +0000 (14:28 +0530)
committerAjit Khaparde <ajit.khaparde@broadcom.com>
Thu, 8 Jul 2021 00:01:52 +0000 (02:01 +0200)
- switch to single slice management on Wh+
- Support of shared session WC_TCAM_HIGH and WC_TCAM_LOW regions
- Enable/disable using TF_TCAM_SHARED flag in tf_core.h
- Fix empty session module DBs in the case that none are
  allocated for a given module type

Signed-off-by: Farah Smith <farah.smith@broadcom.com>
Signed-off-by: Jay Ding <jay.ding@broadcom.com>
Signed-off-by: Randy Schacher <stuart.schacher@broadcom.com>
Signed-off-by: Venkat Duvvuru <venkatkumar.duvvuru@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
12 files changed:
drivers/net/bnxt/tf_core/meson.build
drivers/net/bnxt/tf_core/tf_core.h
drivers/net/bnxt/tf_core/tf_device.c
drivers/net/bnxt/tf_core/tf_device.h
drivers/net/bnxt/tf_core/tf_device_p4.c
drivers/net/bnxt/tf_core/tf_device_p58.c
drivers/net/bnxt/tf_core/tf_identifier.c
drivers/net/bnxt/tf_core/tf_tbl.c
drivers/net/bnxt/tf_core/tf_tcam.c
drivers/net/bnxt/tf_core/tf_tcam_shared.c [new file with mode: 0644]
drivers/net/bnxt/tf_core/tf_tcam_shared.h [new file with mode: 0644]
drivers/net/bnxt/tf_core/tf_util.c

index 3a91f04..f28e77e 100644 (file)
@@ -10,26 +10,27 @@ sources += files(
         'tf_core.c',
         'bitalloc.c',
         'tf_msg.c',
-       'dpool.c',
+        'll.c',
+        'dpool.c',
         'rand.c',
         'stack.c',
-        'tf_em_common.c',
-        'tf_em_internal.c',
         'tf_rm.c',
         'tf_tbl.c',
+        'tf_em_common.c',
+        'tf_em_host.c',
+        'tf_em_internal.c',
+        'tf_em_hash_internal.c',
         'tfp.c',
-        'tf_session.c',
+        'tf_util.c',
         'tf_device.c',
         'tf_device_p4.c',
-        'tf_device_p58.c',
+        'tf_global_cfg.c',
         'tf_identifier.c',
+        'tf_if_tbl.c',
+        'tf_session.c',
         'tf_shadow_tcam.c',
         'tf_tcam.c',
-        'tf_util.c',
-        'tf_if_tbl.c',
-        'll.c',
-        'tf_global_cfg.c',
-        'tf_em_host.c',
-        'tf_em_hash_internal.c',
+        'tf_tcam_shared.c',
         'tf_shadow_identifier.c',
-        'tf_hash.c')
+        'tf_hash.c',
+        'tf_device_p58.c')
index 3d14dc5..39a4981 100644 (file)
@@ -21,7 +21,6 @@
 
 /********** BEGIN Truflow Core DEFINITIONS **********/
 
-
 #define TF_KILOBYTE  1024
 #define TF_MEGABYTE  (1024 * 1024)
 
@@ -77,7 +76,6 @@ enum tf_ext_mem_chan_type {
 #define TF_ACT_REC_OFFSET_2_PTR(offset) ((offset) >> 4)
 #define TF_ACT_REC_PTR_2_OFFSET(offset) ((offset) << 4)
 
-
 /*
  * Helper Macros
  */
@@ -198,7 +196,6 @@ enum tf_module_type {
        TF_MODULE_TYPE_MAX
 };
 
-
 /**
  * Identifier resource types
  */
@@ -317,6 +314,41 @@ enum tf_tbl_type {
        TF_TBL_TYPE_MAX
 };
 
+/** Enable Shared TCAM Management
+ *
+ *  This feature allows for management of high and low pools within
+ *  the WC TCAM.  These pools are only valid when this feature is enabled.
+ *
+ *  For normal OVS-DPDK operation, this feature is not required and can
+ *  be disabled by commenting out TF_TCAM_SHARED in this header file.
+ *
+ *  Operation:
+ *
+ *  When a shared session is created with WC TCAM entries allocated during
+ *  tf_open_session(), the TF_TCAM_TBL_TYPE_WC_TCAM pool entries will be divided
+ *  into 2 equal pools - TF_TCAM_TBL_TYPE_WC_TCAM_HIGH and
+ *  TF_TCAM_TBL_TYPE_WC_TCAM_LOW.
+ *
+ *  The user will allocate and free entries from either of these pools to obtain
+ *  WC_TCAM entry offsets.  For the WC_TCAM_HI/LO management, alloc/free is done
+ *  using the tf_alloc_tcam_entry()/tf_free_tcam_entry() APIs for the shared
+ *  session.
+ *
+ *  The use case for this feature is so that applications can have a shared
+ *  session and use the TF core to allocate/set/free entries within a given
+ *  region of the WC_TCAM within the shared session.  Application A only writes
+ *  to the LOW region for example and Application B only writes to the HIGH
+ *  region during normal operation.  After Application A goes down, Application
+ *  B may decide to overwrite the LOW region with the HIGH region's entries
+ *  and switch to the low region.
+ *
+ *  For other TCAM types in the  shared session, no alloc/free operations are
+ *  permitted. Only set should be used for other TCAM table types after getting
+ *  the range as provided by the tf_get_resource_info() API.
+ *
+ */
+#define TF_TCAM_SHARED 1
+
 /**
  * TCAM table type
  */
@@ -335,6 +367,12 @@ enum tf_tcam_tbl_type {
        TF_TCAM_TBL_TYPE_CT_RULE_TCAM,
        /** Virtual Edge Bridge TCAM */
        TF_TCAM_TBL_TYPE_VEB_TCAM,
+#ifdef TF_TCAM_SHARED
+       /** Wildcard TCAM HI Priority */
+       TF_TCAM_TBL_TYPE_WC_TCAM_HIGH,
+       /** Wildcard TCAM Low Priority */
+       TF_TCAM_TBL_TYPE_WC_TCAM_LOW,
+#endif /* TF_TCAM_SHARED */
        TF_TCAM_TBL_TYPE_MAX
 };
 
@@ -1044,7 +1082,6 @@ int tf_search_identifier(struct tf *tfp,
  * Current thought is that memory is allocated within core.
  */
 
-
 /**
  * tf_alloc_tbl_scope_parms definition
  */
index 97ae73f..55cf558 100644 (file)
@@ -9,6 +9,9 @@
 #include "tfp.h"
 #include "tf_em.h"
 #include "tf_rm.h"
+#ifdef TF_TCAM_SHARED
+#include "tf_tcam_shared.h"
+#endif /* TF_TCAM_SHARED */
 
 struct tf;
 
@@ -92,6 +95,12 @@ tf_dev_bind_p4(struct tf *tfp,
        struct tf_em_cfg_parms em_cfg;
        struct tf_if_tbl_cfg_parms if_tbl_cfg;
        struct tf_global_cfg_cfg_parms global_cfg;
+       struct tf_session *tfs;
+
+       /* Retrieve the session information */
+       rc = tf_session_get_session_internal(tfp, &tfs);
+       if (rc)
+               return rc;
 
        /* Initial function initialization */
        dev_handle->ops = &tf_dev_ops_p4_init;
@@ -142,7 +151,11 @@ tf_dev_bind_p4(struct tf *tfp,
                tcam_cfg.cfg = tf_tcam_p4;
                tcam_cfg.shadow_copy = shadow_copy;
                tcam_cfg.resources = resources;
+#ifdef TF_TCAM_SHARED
+               rc = tf_tcam_shared_bind(tfp, &tcam_cfg);
+#else /* !TF_TCAM_SHARED */
                rc = tf_tcam_bind(tfp, &tcam_cfg);
+#endif
                if (rc) {
                        TFP_DRV_LOG(ERR,
                                    "TCAM initialization failure\n");
@@ -203,31 +216,32 @@ tf_dev_bind_p4(struct tf *tfp,
                return -ENOMEM;
        }
 
-       /*
-        * IF_TBL
-        */
-       if_tbl_cfg.num_elements = TF_IF_TBL_TYPE_MAX;
-       if_tbl_cfg.cfg = tf_if_tbl_p4;
-       if_tbl_cfg.shadow_copy = shadow_copy;
-       rc = tf_if_tbl_bind(tfp, &if_tbl_cfg);
-       if (rc) {
-               TFP_DRV_LOG(ERR,
-                           "IF Table initialization failure\n");
-               goto fail;
-       }
+       if (!tf_session_is_shared_session(tfs)) {
+               /*
+                * IF_TBL
+                */
+               if_tbl_cfg.num_elements = TF_IF_TBL_TYPE_MAX;
+               if_tbl_cfg.cfg = tf_if_tbl_p4;
+               if_tbl_cfg.shadow_copy = shadow_copy;
+               rc = tf_if_tbl_bind(tfp, &if_tbl_cfg);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "IF Table initialization failure\n");
+                       goto fail;
+               }
 
-       /*
-        * GLOBAL_CFG
-        */
-       global_cfg.num_elements = TF_GLOBAL_CFG_TYPE_MAX;
-       global_cfg.cfg = tf_global_cfg_p4;
-       rc = tf_global_cfg_bind(tfp, &global_cfg);
-       if (rc) {
-               TFP_DRV_LOG(ERR,
-                           "Global Cfg initialization failure\n");
-               goto fail;
+               /*
+                * GLOBAL_CFG
+                */
+               global_cfg.num_elements = TF_GLOBAL_CFG_TYPE_MAX;
+               global_cfg.cfg = tf_global_cfg_p4;
+               rc = tf_global_cfg_bind(tfp, &global_cfg);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "Global Cfg initialization failure\n");
+                       goto fail;
+               }
        }
-
        /* Final function initialization */
        dev_handle->ops = &tf_dev_ops_p4;
 
@@ -265,7 +279,11 @@ tf_dev_unbind_p4(struct tf *tfp)
         * In case of residuals TCAMs are cleaned up first as to
         * invalidate the pipeline in a clean manner.
         */
+#ifdef TF_TCAM_SHARED
+       rc = tf_tcam_shared_unbind(tfp);
+#else /* !TF_TCAM_SHARED */
        rc = tf_tcam_unbind(tfp);
+#endif /* TF_TCAM_SHARED */
        if (rc) {
                TFP_DRV_LOG(INFO,
                            "Device unbind failed, TCAM\n");
@@ -407,7 +425,11 @@ tf_dev_bind_p58(struct tf *tfp,
                tcam_cfg.cfg = tf_tcam_p58;
                tcam_cfg.shadow_copy = shadow_copy;
                tcam_cfg.resources = resources;
+#ifdef TF_TCAM_SHARED
+               rc = tf_tcam_shared_bind(tfp, &tcam_cfg);
+#else /* !TF_TCAM_SHARED */
                rc = tf_tcam_bind(tfp, &tcam_cfg);
+#endif
                if (rc) {
                        TFP_DRV_LOG(ERR,
                                    "TCAM initialization failure\n");
@@ -517,7 +539,11 @@ tf_dev_unbind_p58(struct tf *tfp)
         * In case of residuals TCAMs are cleaned up first as to
         * invalidate the pipeline in a clean manner.
         */
+#ifdef TF_TCAM_SHARED
+       rc = tf_tcam_shared_unbind(tfp);
+#else /* !TF_TCAM_SHARED */
        rc = tf_tcam_unbind(tfp);
+#endif /* TF_TCAM_SHARED */
        if (rc) {
                TFP_DRV_LOG(INFO,
                            "Device unbind failed, TCAM\n");
index 31806bb..ea4dcfb 100644 (file)
@@ -10,6 +10,9 @@
 #include "tf_identifier.h"
 #include "tf_tbl.h"
 #include "tf_tcam.h"
+#ifdef TF_TCAM_SHARED
+#include "tf_tcam_shared.h"
+#endif
 #include "tf_if_tbl.h"
 #include "tf_global_cfg.h"
 
@@ -136,7 +139,6 @@ struct tf_dev_ops {
                                       uint16_t resource_id,
                                       const char **resource_str);
 
-
        /**
         * Retrieves the WC TCAM slice information that the device
         * supports.
index e74ba6c..0d3c35a 100644 (file)
@@ -10,6 +10,9 @@
 #include "tf_identifier.h"
 #include "tf_tbl.h"
 #include "tf_tcam.h"
+#ifdef TF_TCAM_SHARED
+#include "tf_tcam_shared.h"
+#endif /* TF_TCAM_SHARED */
 #include "tf_em.h"
 #include "tf_if_tbl.h"
 #include "tfp.h"
@@ -137,7 +140,8 @@ tf_dev_p4_get_tcam_slice_info(struct tf *tfp __rte_unused,
                              uint16_t key_sz,
                              uint16_t *num_slices_per_row)
 {
-#define CFA_P4_WC_TCAM_SLICES_PER_ROW 2
+/* Single slice support */
+#define CFA_P4_WC_TCAM_SLICES_PER_ROW 1
 #define CFA_P4_WC_TCAM_SLICE_SIZE     12
 
        if (type == TF_TCAM_TBL_TYPE_WC_TCAM) {
@@ -263,11 +267,18 @@ const struct tf_dev_ops tf_dev_ops_p4 = {
        .tf_dev_get_tbl = tf_tbl_get,
        .tf_dev_get_bulk_tbl = tf_tbl_bulk_get,
        .tf_dev_get_tbl_resc_info = tf_tbl_get_resc_info,
+#ifdef TF_TCAM_SHARED
+       .tf_dev_alloc_tcam = tf_tcam_shared_alloc,
+       .tf_dev_free_tcam = tf_tcam_shared_free,
+       .tf_dev_set_tcam = tf_tcam_shared_set,
+       .tf_dev_get_tcam = tf_tcam_shared_get,
+#else /* !TF_TCAM_SHARED */
        .tf_dev_alloc_tcam = tf_tcam_alloc,
        .tf_dev_free_tcam = tf_tcam_free,
-       .tf_dev_alloc_search_tcam = tf_tcam_alloc_search,
        .tf_dev_set_tcam = tf_tcam_set,
-       .tf_dev_get_tcam = NULL,
+       .tf_dev_get_tcam = tf_tcam_get,
+#endif
+       .tf_dev_alloc_search_tcam = tf_tcam_alloc_search,
        .tf_dev_get_tcam_resc_info = tf_tcam_get_resc_info,
        .tf_dev_insert_int_em_entry = tf_em_insert_int_entry,
        .tf_dev_delete_int_em_entry = tf_em_delete_int_entry,
index a5b055b..5bf5237 100644 (file)
@@ -10,6 +10,9 @@
 #include "tf_identifier.h"
 #include "tf_tbl.h"
 #include "tf_tcam.h"
+#ifdef TF_TCAM_SHARED
+#include "tf_tcam_shared.h"
+#endif /* TF_TCAM_SHARED */
 #include "tf_em.h"
 #include "tf_if_tbl.h"
 #include "tfp.h"
@@ -148,7 +151,6 @@ static int tf_dev_p58_word_align(uint16_t size)
        return ((((size) + 63) >> 6) * 8);
 }
 
-
 #define TF_DEV_P58_BANK_SZ_64B 2048
 /**
  * Get SRAM table information.
@@ -287,11 +289,18 @@ const struct tf_dev_ops tf_dev_ops_p58 = {
        .tf_dev_get_tbl = tf_tbl_get,
        .tf_dev_get_bulk_tbl = tf_tbl_bulk_get,
        .tf_dev_get_tbl_resc_info = tf_tbl_get_resc_info,
+#ifdef TF_TCAM_SHARED
+       .tf_dev_alloc_tcam = tf_tcam_shared_alloc,
+       .tf_dev_free_tcam = tf_tcam_shared_free,
+       .tf_dev_set_tcam = tf_tcam_set,
+       .tf_dev_get_tcam = tf_tcam_get,
+#else /* !TF_TCAM_SHARED */
        .tf_dev_alloc_tcam = tf_tcam_alloc,
        .tf_dev_free_tcam = tf_tcam_free,
-       .tf_dev_alloc_search_tcam = tf_tcam_alloc_search,
        .tf_dev_set_tcam = tf_tcam_set,
        .tf_dev_get_tcam = tf_tcam_get,
+#endif
+       .tf_dev_alloc_search_tcam = tf_tcam_alloc_search,
        .tf_dev_get_tcam_resc_info = tf_tcam_get_resc_info,
        .tf_dev_insert_int_em_entry = tf_em_hash_insert_int_entry,
        .tf_dev_delete_int_em_entry = tf_em_hash_delete_int_entry,
index 3cc87de..3575c3e 100644 (file)
@@ -76,7 +76,7 @@ tf_ident_bind(struct tf *tfp,
                        db_rc[i] = tf_rm_create_db(tfp, &db_cfg);
                if (db_rc[i]) {
                        TFP_DRV_LOG(INFO,
-                                   "%s: Identifier DB creation failed\n",
+                                   "%s: No Identifier DB required\n",
                                    tf_dir_2_str(i));
                }
 
index 1921151..295204a 100644 (file)
@@ -85,7 +85,7 @@ tf_tbl_bind(struct tf *tfp,
                        db_rc[d] = tf_rm_create_db(tfp, &db_cfg);
                if (db_rc[d]) {
                        TFP_DRV_LOG(ERR,
-                                   "%s: Table DB creation failed\n",
+                                   "%s: No Table DB creation required\n",
                                    tf_dir_2_str(d));
 
                }
@@ -656,7 +656,6 @@ tf_tbl_get_resc_info(struct tf *tfp,
        }
        tbl_db = (struct tbl_rm_db *)tbl_db_ptr;
 
-
        /* check if reserved resource for WC is multiple of num_slices */
        for (d = 0; d < TF_DIR_MAX; d++) {
                ainfo.rm_db = tbl_db->tbl_db[d];
@@ -693,7 +692,5 @@ tf_tbl_get_resc_info(struct tf *tfp,
                }
        }
 
-
-
        return 0;
 }
index ce959e3..5c018f7 100644 (file)
@@ -115,7 +115,7 @@ tf_tcam_bind(struct tf *tfp,
                        db_rc[d] = tf_rm_create_db(tfp, &db_cfg);
                if (db_rc[d]) {
                        TFP_DRV_LOG(INFO,
-                                   "%s: TCAM DB creation failed\n",
+                                   "%s: no TCAM DB required\n",
                                    tf_dir_2_str(d));
                }
        }
@@ -126,6 +126,9 @@ tf_tcam_bind(struct tf *tfp,
 
        /* check if reserved resource for WC is multiple of num_slices */
        for (d = 0; d < TF_DIR_MAX; d++) {
+               if (!tcam_db->tcam_db[d])
+                       continue;
+
                memset(&info, 0, sizeof(info));
                ainfo.rm_db = tcam_db->tcam_db[d];
                ainfo.subtype = TF_TCAM_TBL_TYPE_WC_TCAM;
diff --git a/drivers/net/bnxt/tf_core/tf_tcam_shared.c b/drivers/net/bnxt/tf_core/tf_tcam_shared.c
new file mode 100644 (file)
index 0000000..18beae7
--- /dev/null
@@ -0,0 +1,743 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019-2021 Broadcom
+ * All rights reserved.
+ */
+
+#include <string.h>
+#include <rte_common.h>
+
+#include "tf_tcam_shared.h"
+#include "tf_tcam.h"
+#include "tf_common.h"
+#include "tf_util.h"
+#include "tf_rm.h"
+#include "tf_device.h"
+#include "tfp.h"
+#include "tf_session.h"
+#include "tf_msg.h"
+#include "bitalloc.h"
+#include "tf_core.h"
+
+struct tf;
+
+/** Shared WC TCAM pool identifiers
+ */
+enum tf_tcam_shared_wc_pool_id {
+       TF_TCAM_SHARED_WC_POOL_HI  = 0,
+       TF_TCAM_SHARED_WC_POOL_LO  = 1,
+       TF_TCAM_SHARED_WC_POOL_MAX = 2
+};
+
+/** Get string representation of a WC TCAM shared pool id
+ */
+static const char *
+tf_pool_2_str(enum tf_tcam_shared_wc_pool_id id)
+{
+       switch (id) {
+       case TF_TCAM_SHARED_WC_POOL_HI:
+               return "TCAM_SHARED_WC_POOL_HI";
+       case TF_TCAM_SHARED_WC_POOL_LO:
+               return "TCAM_SHARED_WC_POOL_LO";
+       default:
+               return "Invalid TCAM_SHARED_WC_POOL";
+       }
+}
+
+/** The WC TCAM shared pool datastructure
+ */
+struct tf_tcam_shared_wc_pool {
+       /** Start and stride data */
+       struct tf_resource_info info;
+       /** bitalloc pool */
+       struct bitalloc *pool;
+};
+
+/** The WC TCAM shared pool declarations
+ * TODO: add tcam_shared_wc_db
+ */
+struct tf_tcam_shared_wc_pool tcam_shared_wc[TF_DIR_MAX][TF_TCAM_SHARED_WC_POOL_MAX];
+
+/** Create a WC TCAM shared pool
+ */
+static int
+tf_tcam_shared_create_wc_pool(int dir,
+                             enum tf_tcam_shared_wc_pool_id id,
+                             int start,
+                             int stride)
+{
+       int rc = 0;
+       bool free = true;
+       struct tfp_calloc_parms cparms;
+       uint32_t pool_size;
+
+       /* Create pool */
+       pool_size = (BITALLOC_SIZEOF(stride) / sizeof(struct bitalloc));
+       cparms.nitems = pool_size;
+       cparms.alignment = 0;
+       cparms.size = sizeof(struct bitalloc);
+       rc = tfp_calloc(&cparms);
+       if (rc) {
+               TFP_DRV_LOG(ERR,
+                           "%s: pool memory alloc failed %s:%s\n",
+                           tf_dir_2_str(dir), tf_pool_2_str(id),
+                           strerror(-rc));
+               return rc;
+       }
+       tcam_shared_wc[dir][id].pool = (struct bitalloc *)cparms.mem_va;
+
+       rc = ba_init(tcam_shared_wc[dir][id].pool,
+                    stride,
+                    free);
+
+       if (rc) {
+               TFP_DRV_LOG(ERR,
+                           "%s: pool bitalloc failed %s\n",
+                           tf_dir_2_str(dir), tf_pool_2_str(id));
+               return rc;
+       }
+
+       tcam_shared_wc[dir][id].info.start = start;
+       tcam_shared_wc[dir][id].info.stride = stride;
+       return rc;
+}
+/** Free a WC TCAM shared pool
+ */
+static void
+tf_tcam_shared_free_wc_pool(int dir,
+                           enum tf_tcam_shared_wc_pool_id id)
+{
+       tcam_shared_wc[dir][id].info.start = 0;
+       tcam_shared_wc[dir][id].info.stride = 0;
+
+       if (tcam_shared_wc[dir][id].pool)
+               tfp_free((void *)tcam_shared_wc[dir][id].pool);
+}
+
+/** Get the number of WC TCAM slices allocated during 1 allocation/free
+ */
+static int
+tf_tcam_shared_get_slices(struct tf *tfp,
+                         struct tf_dev_info *dev,
+                         uint16_t *num_slices)
+{
+       int rc;
+
+       if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
+               rc = -EOPNOTSUPP;
+               TFP_DRV_LOG(ERR,
+                           "Operation not supported, rc:%s\n", strerror(-rc));
+               return rc;
+       }
+       rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
+                                                 TF_TCAM_TBL_TYPE_WC_TCAM,
+                                                 0,
+                                                 num_slices);
+       return rc;
+}
+
+static bool
+tf_tcam_shared_db_valid(struct tf *tfp,
+                       enum tf_dir dir)
+{
+       struct tcam_rm_db *tcam_db;
+       void *tcam_db_ptr = NULL;
+       int rc;
+
+       TF_CHECK_PARMS1(tfp);
+
+       rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
+       if (rc)
+               return false;
+
+       tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
+
+       if (tcam_db->tcam_db[dir])
+               return true;
+
+       return false;
+}
+
+static int
+tf_tcam_shared_get_rm_info(struct tf *tfp,
+                          enum tf_dir dir,
+                          uint16_t *hcapi_type,
+                          struct tf_rm_alloc_info *info)
+{
+       int rc;
+       struct tcam_rm_db *tcam_db;
+       void *tcam_db_ptr = NULL;
+       struct tf_rm_get_alloc_info_parms ainfo;
+       struct tf_rm_get_hcapi_parms hparms;
+
+       TF_CHECK_PARMS3(tfp, hcapi_type, info);
+
+       rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
+       if (rc) {
+               TFP_DRV_LOG(INFO,
+                           "Tcam_db is not initialized, rc:%s\n",
+                           strerror(-rc));
+               return 0;
+       }
+       tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
+
+       /* Convert TF type to HCAPI RM type */
+       memset(&hparms, 0, sizeof(hparms));
+       hparms.rm_db = tcam_db->tcam_db[dir];
+       hparms.subtype = TF_TCAM_TBL_TYPE_WC_TCAM;
+       hparms.hcapi_type = hcapi_type;
+
+       rc = tf_rm_get_hcapi_type(&hparms);
+       if (rc) {
+               TFP_DRV_LOG(ERR,
+                           "%s: Get RM hcapi type failed %s\n",
+                           tf_dir_2_str(dir),
+                           strerror(-rc));
+               return rc;
+       }
+
+       memset(info, 0, sizeof(struct tf_rm_alloc_info));
+       ainfo.rm_db = tcam_db->tcam_db[dir];
+       ainfo.subtype = TF_TCAM_TBL_TYPE_WC_TCAM;
+       ainfo.info = info;
+
+       rc = tf_rm_get_info(&ainfo);
+       if (rc) {
+               TFP_DRV_LOG(ERR,
+                           "%s: TCAM rm info get failed %s\n",
+                           tf_dir_2_str(dir),
+                           strerror(-rc));
+               return rc;
+       }
+       return rc;
+}
+
+/**
+ * tf_tcam_shared_bind
+ */
+int
+tf_tcam_shared_bind(struct tf *tfp,
+                   struct tf_tcam_cfg_parms *parms)
+{
+       int rc, dir;
+       struct tf_session *tfs;
+       struct tf_dev_info *dev;
+       struct tf_rm_alloc_info info;
+       uint16_t start, stride;
+       uint16_t num_slices;
+       uint16_t hcapi_type;
+
+       TF_CHECK_PARMS2(tfp, parms);
+
+       /* Perform normal bind
+        */
+       rc = tf_tcam_bind(tfp, parms);
+       if (rc)
+               return rc;
+
+       /* After the normal TCAM bind, if this is a shared session
+        * create all required databases for the WC_HI and WC_LO pools
+        */
+       rc = tf_session_get_session_internal(tfp, &tfs);
+       if (rc) {
+               TFP_DRV_LOG(ERR,
+                           "Session access failure: %s\n", strerror(-rc));
+               return rc;
+       }
+       if (tf_session_is_shared_session(tfs)) {
+               /* Retrieve the device information */
+               rc = tf_session_get_device(tfs, &dev);
+               if (rc)
+                       return rc;
+
+               rc = tf_tcam_shared_get_slices(tfp,
+                                              dev,
+                                              &num_slices);
+               if (rc)
+                       return rc;
+
+               /* If there are WC TCAM entries, create 2 pools each with 1/2
+                * the total number of entries
+                */
+               for (dir = 0; dir < TF_DIR_MAX; dir++) {
+                       if (!tf_tcam_shared_db_valid(tfp, dir))
+                               continue;
+
+                       rc = tf_tcam_shared_get_rm_info(tfp,
+                                                       dir,
+                                                       &hcapi_type,
+                                                       &info);
+                       if (rc) {
+                               TFP_DRV_LOG(ERR,
+                                           "%s: TCAM rm info get failed\n",
+                                           tf_dir_2_str(dir));
+                               goto done;
+                       }
+
+                       start = info.entry.start;
+                       stride = info.entry.stride / 2;
+
+                       tf_tcam_shared_create_wc_pool(dir,
+                                               TF_TCAM_SHARED_WC_POOL_HI,
+                                               start,
+                                               stride);
+
+                       start += stride;
+                       tf_tcam_shared_create_wc_pool(dir,
+                                               TF_TCAM_SHARED_WC_POOL_LO,
+                                               start,
+                                               stride);
+               }
+       }
+done:
+       return rc;
+}
+/**
+ * tf_tcam_shared_unbind
+ */
+int
+tf_tcam_shared_unbind(struct tf *tfp)
+{
+       int rc, dir;
+       struct tf_session *tfs;
+
+       TF_CHECK_PARMS1(tfp);
+
+       /* Perform normal unbind, this will write all the
+        * allocated TCAM entries in the shared session.
+        */
+       rc = tf_tcam_unbind(tfp);
+       if (rc)
+               return rc;
+
+       /* Retrieve the session information */
+       rc = tf_session_get_session_internal(tfp, &tfs);
+       if (rc)
+               return rc;
+
+       /* If we are the shared session
+        */
+       if (tf_session_is_shared_session(tfs)) {
+               /* If there are WC TCAM entries allocated, free them
+                */
+               for (dir = 0; dir < TF_DIR_MAX; dir++) {
+                       tf_tcam_shared_free_wc_pool(dir,
+                                                   TF_TCAM_SHARED_WC_POOL_HI);
+                       tf_tcam_shared_free_wc_pool(dir,
+                                                   TF_TCAM_SHARED_WC_POOL_LO);
+               }
+       }
+       return 0;
+}
+/**
+ * tf_tcam_shared_alloc
+ */
+int
+tf_tcam_shared_alloc(struct tf *tfp,
+                    struct tf_tcam_alloc_parms *parms)
+{
+       int rc, i;
+       struct tf_session *tfs;
+       struct tf_dev_info *dev;
+       int log_idx;
+       struct bitalloc *pool;
+       enum tf_tcam_shared_wc_pool_id id;
+       uint16_t num_slices;
+
+       TF_CHECK_PARMS2(tfp, parms);
+
+       /* Retrieve the session information */
+       rc = tf_session_get_session_internal(tfp, &tfs);
+       if (rc)
+               return rc;
+
+       /* If we aren't the shared session or the type is
+        * not one of the special WC TCAM types, call the normal
+        * allocation.
+        */
+       if (!tf_session_is_shared_session(tfs) ||
+           (parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_HIGH &&
+            parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_LOW)) {
+               /* Perform normal alloc
+                */
+               rc = tf_tcam_alloc(tfp, parms);
+               return rc;
+       }
+
+       if (!tf_tcam_shared_db_valid(tfp, parms->dir)) {
+               TFP_DRV_LOG(ERR,
+                           "%s: tcam shared pool doesn't exist\n",
+                           tf_dir_2_str(parms->dir));
+               return -ENOMEM;
+       }
+
+       if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM_HIGH)
+               id = TF_TCAM_SHARED_WC_POOL_HI;
+       else
+               id = TF_TCAM_SHARED_WC_POOL_LO;
+
+       /* Retrieve the device information */
+       rc = tf_session_get_device(tfs, &dev);
+       if (rc)
+               return rc;
+
+       rc = tf_tcam_shared_get_slices(tfp, dev, &num_slices);
+       if (rc)
+               return rc;
+
+       pool = tcam_shared_wc[parms->dir][id].pool;
+
+       for (i = 0; i < num_slices; i++) {
+               /*
+                * priority  0: allocate from top of the tcam i.e. high
+                * priority !0: allocate index from bottom i.e lowest
+                */
+               if (parms->priority)
+                       log_idx = ba_alloc_reverse(pool);
+               else
+                       log_idx = ba_alloc(pool);
+               if (log_idx == BA_FAIL) {
+                       TFP_DRV_LOG(ERR,
+                                   "%s: Allocation failed, rc:%s\n",
+                                   tf_dir_2_str(parms->dir),
+                                   strerror(ENOMEM));
+                       return -ENOMEM;
+               }
+               /* return the index without the start of each row */
+               if (i == 0)
+                       parms->idx = log_idx;
+       }
+       return 0;
+}
+
+int
+tf_tcam_shared_free(struct tf *tfp,
+                   struct tf_tcam_free_parms *parms)
+{
+       int rc;
+       struct tf_session *tfs;
+       struct tf_dev_info *dev;
+       int allocated = 0;
+       int i;
+       uint16_t start;
+       int phy_idx;
+       struct bitalloc *pool;
+       enum tf_tcam_shared_wc_pool_id id;
+       struct tf_tcam_free_parms nparms;
+       uint16_t num_slices;
+       uint16_t hcapi_type;
+       struct tf_rm_alloc_info info;
+
+       TF_CHECK_PARMS2(tfp, parms);
+
+       /* Retrieve the session information */
+       rc = tf_session_get_session_internal(tfp, &tfs);
+       if (rc)
+               return rc;
+
+       /* If we aren't the shared session or the type is
+        * not one of the special WC TCAM types, call the normal
+        * allocation.
+        */
+       if (!tf_session_is_shared_session(tfs) ||
+           (parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_HIGH &&
+            parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_LOW)) {
+               /* Perform normal free
+                */
+               rc = tf_tcam_free(tfp, parms);
+               return rc;
+       }
+
+       if (!tf_tcam_shared_db_valid(tfp, parms->dir)) {
+               TFP_DRV_LOG(ERR,
+                           "%s: tcam shared pool doesn't exist\n",
+                           tf_dir_2_str(parms->dir));
+               return -ENOMEM;
+       }
+
+       if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM_HIGH)
+               id = TF_TCAM_SHARED_WC_POOL_HI;
+       else
+               id = TF_TCAM_SHARED_WC_POOL_LO;
+
+       /* Retrieve the device information */
+       rc = tf_session_get_device(tfs, &dev);
+       if (rc)
+               return rc;
+
+       rc = tf_tcam_shared_get_slices(tfp, dev, &num_slices);
+       if (rc)
+               return rc;
+
+       rc = tf_tcam_shared_get_rm_info(tfp,
+                                       parms->dir,
+                                       &hcapi_type,
+                                       &info);
+       if (rc) {
+               TFP_DRV_LOG(ERR,
+                           "%s: TCAM rm info get failed\n",
+                           tf_dir_2_str(parms->dir));
+               return rc;
+       }
+
+       pool = tcam_shared_wc[parms->dir][id].pool;
+       start = tcam_shared_wc[parms->dir][id].info.start;
+
+       if (parms->idx % num_slices) {
+               TFP_DRV_LOG(ERR,
+                           "%s: TCAM reserved resource is not multiple of %d\n",
+                           tf_dir_2_str(parms->dir), num_slices);
+               return -EINVAL;
+       }
+
+       phy_idx = parms->idx + start;
+       allocated = ba_inuse(pool, parms->idx);
+
+       if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
+               TFP_DRV_LOG(ERR,
+                           "%s: Entry already free, type:%d, idx:%d\n",
+                           tf_dir_2_str(parms->dir), parms->type, parms->idx);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < num_slices; i++) {
+               rc = ba_free(pool, parms->idx + i);
+               if (rc) {
+                       TFP_DRV_LOG(ERR,
+                                   "%s: Free failed, type:%s, idx:%d\n",
+                                   tf_dir_2_str(parms->dir),
+                                   tf_tcam_tbl_2_str(parms->type),
+                                   parms->idx);
+                       return rc;
+               }
+       }
+
+       /* Override HI/LO type with parent WC TCAM type */
+       nparms = *parms;
+       nparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
+       nparms.hcapi_type = hcapi_type;
+       nparms.idx = phy_idx;
+
+       rc = tf_msg_tcam_entry_free(tfp, dev, &nparms);
+       if (rc) {
+               /* Log error */
+               TFP_DRV_LOG(ERR,
+                           "%s: %s: log%d free failed, rc:%s\n",
+                           tf_dir_2_str(nparms.dir),
+                           tf_tcam_tbl_2_str(nparms.type),
+                           phy_idx,
+                           strerror(-rc));
+               return rc;
+       }
+       return 0;
+}
+
+int
+tf_tcam_shared_set(struct tf *tfp __rte_unused,
+                  struct tf_tcam_set_parms *parms __rte_unused)
+{
+       int rc;
+       struct tf_session *tfs;
+       struct tf_dev_info *dev;
+       int allocated = 0;
+       int phy_idx, log_idx;
+       uint16_t num_slices;
+       struct tf_tcam_set_parms nparms;
+       struct bitalloc *pool;
+       uint16_t start;
+       enum tf_tcam_shared_wc_pool_id id;
+       uint16_t hcapi_type;
+       struct tf_rm_alloc_info info;
+
+       TF_CHECK_PARMS2(tfp, parms);
+
+       /* Retrieve the session information */
+       rc = tf_session_get_session_internal(tfp, &tfs);
+       if (rc)
+               return rc;
+
+       /* If we aren't the shared session or one of our
+        * special types
+        */
+       if (!tf_session_is_shared_session(tfs) ||
+           (parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_HIGH &&
+            parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_LOW)) {
+               /* Perform normal set and exit
+                */
+               rc = tf_tcam_set(tfp, parms);
+               return rc;
+       }
+
+       if (!tf_tcam_shared_db_valid(tfp, parms->dir)) {
+               TFP_DRV_LOG(ERR,
+                           "%s: tcam shared pool doesn't exist\n",
+                           tf_dir_2_str(parms->dir));
+               return -ENOMEM;
+       }
+
+       /* Retrieve the device information */
+       rc = tf_session_get_device(tfs, &dev);
+       if (rc)
+               return rc;
+
+       if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM_HIGH)
+               id = TF_TCAM_SHARED_WC_POOL_HI;
+       else
+               id = TF_TCAM_SHARED_WC_POOL_LO;
+
+       pool = tcam_shared_wc[parms->dir][id].pool;
+       start = tcam_shared_wc[parms->dir][id].info.start;
+
+       log_idx = parms->idx;
+       phy_idx = parms->idx + start;
+       allocated = ba_inuse(pool, parms->idx);
+
+       if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
+               TFP_DRV_LOG(ERR,
+                           "%s: Entry is not allocated, type:%d, logid:%d\n",
+                           tf_dir_2_str(parms->dir), parms->type, log_idx);
+               return -EINVAL;
+       }
+       rc = tf_tcam_shared_get_slices(tfp, dev, &num_slices);
+       if (rc)
+               return rc;
+
+       if (parms->idx % num_slices) {
+               TFP_DRV_LOG(ERR,
+                           "%s: TCAM reserved resource is not multiple of %d\n",
+                           tf_dir_2_str(parms->dir), num_slices);
+               return -EINVAL;
+       }
+       rc = tf_tcam_shared_get_rm_info(tfp,
+                                       parms->dir,
+                                       &hcapi_type,
+                                       &info);
+       if (rc)
+               return rc;
+
+       /* Override HI/LO type with parent WC TCAM type */
+       nparms.hcapi_type = hcapi_type;
+       nparms.dir = parms->dir;
+       nparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
+       nparms.idx = phy_idx;
+       nparms.key = parms->key;
+       nparms.mask = parms->mask;
+       nparms.key_size = parms->key_size;
+       nparms.result = parms->result;
+       nparms.result_size = parms->result_size;
+
+       rc = tf_msg_tcam_entry_set(tfp, dev, &nparms);
+       if (rc) {
+               /* Log error */
+               TFP_DRV_LOG(ERR,
+                           "%s: %s: phy entry %d set failed, rc:%s",
+                           tf_dir_2_str(parms->dir),
+                           tf_tcam_tbl_2_str(nparms.type),
+                           phy_idx,
+                           strerror(-rc));
+               return rc;
+       }
+       return 0;
+}
+
+int
+tf_tcam_shared_get(struct tf *tfp __rte_unused,
+                  struct tf_tcam_get_parms *parms)
+{
+       int rc;
+       struct tf_session *tfs;
+       struct tf_dev_info *dev;
+       int allocated = 0;
+       int phy_idx, log_idx;
+       uint16_t num_slices;
+       struct tf_tcam_get_parms nparms;
+       struct bitalloc *pool;
+       uint16_t start;
+       enum tf_tcam_shared_wc_pool_id id;
+       uint16_t hcapi_type;
+       struct tf_rm_alloc_info info;
+
+       TF_CHECK_PARMS2(tfp, parms);
+
+       /* Retrieve the session information */
+       rc = tf_session_get_session_internal(tfp, &tfs);
+       if (rc)
+               return rc;
+
+       /* If we aren't the shared session or one of our
+        * special types
+        */
+       if (!tf_session_is_shared_session(tfs) ||
+           (parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_HIGH &&
+            parms->type != TF_TCAM_TBL_TYPE_WC_TCAM_LOW)) {
+               /* Perform normal get and exit
+                */
+               rc = tf_tcam_get(tfp, parms);
+               return rc;
+       }
+
+       if (!tf_tcam_shared_db_valid(tfp, parms->dir)) {
+               TFP_DRV_LOG(ERR,
+                           "%s: tcam shared pool doesn't exist\n",
+                           tf_dir_2_str(parms->dir));
+               return -ENOMEM;
+       }
+
+       /* Retrieve the device information */
+       rc = tf_session_get_device(tfs, &dev);
+       if (rc)
+               return rc;
+       if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM_HIGH)
+               id = TF_TCAM_SHARED_WC_POOL_HI;
+       else
+               id = TF_TCAM_SHARED_WC_POOL_LO;
+
+       pool = tcam_shared_wc[parms->dir][id].pool;
+       start = tcam_shared_wc[parms->dir][id].info.start;
+
+       rc = tf_tcam_shared_get_slices(tfp, dev, &num_slices);
+       if (rc)
+               return rc;
+
+       if (parms->idx % num_slices) {
+               TFP_DRV_LOG(ERR,
+                           "%s: TCAM reserved resource is not multiple of %d\n",
+                           tf_dir_2_str(parms->dir), num_slices);
+               return -EINVAL;
+       }
+       log_idx = parms->idx;
+       phy_idx = parms->idx + start;
+       allocated = ba_inuse(pool, parms->idx);
+
+       if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
+               TFP_DRV_LOG(ERR,
+                           "%s: Entry is not allocated, type:%d, logid:%d\n",
+                           tf_dir_2_str(parms->dir), parms->type, log_idx);
+               return -EINVAL;
+       }
+
+       rc = tf_tcam_shared_get_rm_info(tfp,
+                                       parms->dir,
+                                       &hcapi_type,
+                                       &info);
+       if (rc)
+               return rc;
+
+       /* Override HI/LO type with parent WC TCAM type */
+       nparms = *parms;
+       nparms.type = TF_TCAM_TBL_TYPE_WC_TCAM;
+       nparms.hcapi_type = hcapi_type;
+       nparms.idx = phy_idx;
+
+       rc = tf_msg_tcam_entry_get(tfp, dev, &nparms);
+       if (rc) {
+               /* Log error */
+               TFP_DRV_LOG(ERR,
+                           "%s: %s: Entry %d set failed, rc:%s",
+                           tf_dir_2_str(nparms.dir),
+                           tf_tcam_tbl_2_str(nparms.type),
+                           nparms.idx,
+                           strerror(-rc));
+               return rc;
+       }
+       return 0;
+}
diff --git a/drivers/net/bnxt/tf_core/tf_tcam_shared.h b/drivers/net/bnxt/tf_core/tf_tcam_shared.h
new file mode 100644 (file)
index 0000000..fad6e23
--- /dev/null
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019-2021 Broadcom
+ * All rights reserved.
+ */
+
+#ifndef _TF_TCAM_SHARED_H_
+#define _TF_TCAM_SHARED_H_
+
+#include "tf_core.h"
+#include "tf_tcam.h"
+
+/**
+ * @page tcam_shared TCAM SHARED
+ *
+ * @ref tf_tcam_shared_bind
+ *
+ * @ref tf_tcam_shared_unbind
+ *
+ * @ref tf_tcam_shared_alloc
+ *
+ * @ref tf_tcam_shared_free
+ *
+ * @ref tf_tcam_shared_set
+ *
+ * @ref tf_tcam_shared_get
+ *
+ */
+
+/**
+ * Initializes the TCAM shared module with the requested DBs. Must be
+ * invoked as the first thing before any of the access functions.
+ *
+ * [in] tfp
+ *   Pointer to the truflow handle
+ *
+ * [in] parms
+ *   Pointer to parameters
+ *
+ * Returns
+ *   - (0) if successful.
+ *   - (-EINVAL) on failure.
+ */
+int tf_tcam_shared_bind(struct tf *tfp,
+                       struct tf_tcam_cfg_parms *parms);
+
+/**
+ * Cleans up the private DBs and releases all the data.
+ *
+ * [in] tfp
+ *   Pointer to the truflow handle
+ *
+ * [in] parms
+ *   Pointer to parameters
+ *
+ * Returns
+ *   - (0) if successful.
+ *   - (-EINVAL) on failure.
+ */
+int tf_tcam_shared_unbind(struct tf *tfp);
+
+/**
+ * Allocates the requested tcam type from the internal RM DB.
+ *
+ * [in] tfp
+ *   Pointer to the truflow handle
+ *
+ * [in] parms
+ *   Pointer to parameters
+ *
+ * Returns
+ *   - (0) if successful.
+ *   - (-EINVAL) on failure.
+ */
+int tf_tcam_shared_alloc(struct tf *tfp,
+                        struct tf_tcam_alloc_parms *parms);
+
+/**
+ * Free's the requested table type and returns it to the DB.
+ *
+ * [in] tfp
+ *   Pointer to the truflow handle
+ *
+ * [in] parms
+ *   Pointer to parameters
+ *
+ * Returns
+ *   - (0) if successful.
+ *   - (-EINVAL) on failure.
+ */
+int tf_tcam_shared_free(struct tf *tfp,
+                       struct tf_tcam_free_parms *parms);
+
+/**
+ * Configures the requested element by sending a firmware request which
+ * then installs it into the device internal structures.
+ *
+ * [in] tfp
+ *   Pointer to the truflow handle
+ *
+ * [in] parms
+ *   Pointer to parameters
+ *
+ * Returns
+ *   - (0) if successful.
+ *   - (-EINVAL) on failure.
+ */
+int tf_tcam_shared_set(struct tf *tfp,
+                      struct tf_tcam_set_parms *parms);
+
+/**
+ * Retrieves the requested element by sending a firmware request to get
+ * the element.
+ *
+ * [in] tfp
+ *   Pointer to the truflow handle
+ *
+ * [in] parms
+ *   Pointer to parameters
+ *
+ * Returns
+ *   - (0) if successful.
+ *   - (-EINVAL) on failure.
+ */
+int tf_tcam_shared_get(struct tf *tfp,
+                      struct tf_tcam_get_parms *parms);
+
+#endif /* _TF_TCAM_SHARED_H */
index 25f5c15..e712816 100644 (file)
@@ -59,6 +59,12 @@ tf_tcam_tbl_2_str(enum tf_tcam_tbl_type tcam_type)
                return "sp_tcam";
        case TF_TCAM_TBL_TYPE_CT_RULE_TCAM:
                return "ct_rule_tcam";
+#ifdef TF_TCAM_SHARED
+       case TF_TCAM_TBL_TYPE_WC_TCAM_HIGH:
+               return "wc_tcam_hi";
+       case TF_TCAM_TBL_TYPE_WC_TCAM_LOW:
+               return "wc_tcam_lo";
+#endif
        default:
                return "Invalid tcam table type";
        }