From 872860927003ab731bc1dfa69c6027e132d0ee07 Mon Sep 17 00:00:00 2001 From: Farah Smith Date: Sun, 30 May 2021 14:28:49 +0530 Subject: [PATCH] net/bnxt: support shared TCAM region - 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 Signed-off-by: Jay Ding Signed-off-by: Randy Schacher Signed-off-by: Venkat Duvvuru Reviewed-by: Ajit Khaparde --- drivers/net/bnxt/tf_core/meson.build | 25 +- drivers/net/bnxt/tf_core/tf_core.h | 45 +- drivers/net/bnxt/tf_core/tf_device.c | 72 ++- drivers/net/bnxt/tf_core/tf_device.h | 4 +- drivers/net/bnxt/tf_core/tf_device_p4.c | 17 +- drivers/net/bnxt/tf_core/tf_device_p58.c | 13 +- drivers/net/bnxt/tf_core/tf_identifier.c | 2 +- drivers/net/bnxt/tf_core/tf_tbl.c | 5 +- drivers/net/bnxt/tf_core/tf_tcam.c | 5 +- drivers/net/bnxt/tf_core/tf_tcam_shared.c | 743 ++++++++++++++++++++++ drivers/net/bnxt/tf_core/tf_tcam_shared.h | 127 ++++ drivers/net/bnxt/tf_core/tf_util.c | 6 + 12 files changed, 1013 insertions(+), 51 deletions(-) create mode 100644 drivers/net/bnxt/tf_core/tf_tcam_shared.c create mode 100644 drivers/net/bnxt/tf_core/tf_tcam_shared.h diff --git a/drivers/net/bnxt/tf_core/meson.build b/drivers/net/bnxt/tf_core/meson.build index 3a91f04bc0..f28e77ec2e 100644 --- a/drivers/net/bnxt/tf_core/meson.build +++ b/drivers/net/bnxt/tf_core/meson.build @@ -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') diff --git a/drivers/net/bnxt/tf_core/tf_core.h b/drivers/net/bnxt/tf_core/tf_core.h index 3d14dc5391..39a498122b 100644 --- a/drivers/net/bnxt/tf_core/tf_core.h +++ b/drivers/net/bnxt/tf_core/tf_core.h @@ -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 */ diff --git a/drivers/net/bnxt/tf_core/tf_device.c b/drivers/net/bnxt/tf_core/tf_device.c index 97ae73fa5a..55cf55886a 100644 --- a/drivers/net/bnxt/tf_core/tf_device.c +++ b/drivers/net/bnxt/tf_core/tf_device.c @@ -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"); diff --git a/drivers/net/bnxt/tf_core/tf_device.h b/drivers/net/bnxt/tf_core/tf_device.h index 31806bb289..ea4dcfb8e2 100644 --- a/drivers/net/bnxt/tf_core/tf_device.h +++ b/drivers/net/bnxt/tf_core/tf_device.h @@ -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. diff --git a/drivers/net/bnxt/tf_core/tf_device_p4.c b/drivers/net/bnxt/tf_core/tf_device_p4.c index e74ba6cd8f..0d3c35ae3b 100644 --- a/drivers/net/bnxt/tf_core/tf_device_p4.c +++ b/drivers/net/bnxt/tf_core/tf_device_p4.c @@ -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, diff --git a/drivers/net/bnxt/tf_core/tf_device_p58.c b/drivers/net/bnxt/tf_core/tf_device_p58.c index a5b055bac7..5bf52379a7 100644 --- a/drivers/net/bnxt/tf_core/tf_device_p58.c +++ b/drivers/net/bnxt/tf_core/tf_device_p58.c @@ -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, diff --git a/drivers/net/bnxt/tf_core/tf_identifier.c b/drivers/net/bnxt/tf_core/tf_identifier.c index 3cc87de4ef..3575c3e1a0 100644 --- a/drivers/net/bnxt/tf_core/tf_identifier.c +++ b/drivers/net/bnxt/tf_core/tf_identifier.c @@ -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)); } diff --git a/drivers/net/bnxt/tf_core/tf_tbl.c b/drivers/net/bnxt/tf_core/tf_tbl.c index 192115183b..295204ac87 100644 --- a/drivers/net/bnxt/tf_core/tf_tbl.c +++ b/drivers/net/bnxt/tf_core/tf_tbl.c @@ -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; } diff --git a/drivers/net/bnxt/tf_core/tf_tcam.c b/drivers/net/bnxt/tf_core/tf_tcam.c index ce959e3923..5c018f7003 100644 --- a/drivers/net/bnxt/tf_core/tf_tcam.c +++ b/drivers/net/bnxt/tf_core/tf_tcam.c @@ -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 index 0000000000..18beae78bb --- /dev/null +++ b/drivers/net/bnxt/tf_core/tf_tcam_shared.c @@ -0,0 +1,743 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019-2021 Broadcom + * All rights reserved. + */ + +#include +#include + +#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 index 0000000000..fad6e23b4c --- /dev/null +++ b/drivers/net/bnxt/tf_core/tf_tcam_shared.h @@ -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 */ diff --git a/drivers/net/bnxt/tf_core/tf_util.c b/drivers/net/bnxt/tf_core/tf_util.c index 25f5c152d2..e712816209 100644 --- a/drivers/net/bnxt/tf_core/tf_util.c +++ b/drivers/net/bnxt/tf_core/tf_util.c @@ -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"; } -- 2.20.1