From f4a4421c146e55605fb5f83af7bb90cf38eba1aa Mon Sep 17 00:00:00 2001 From: Kishore Padmanabha Date: Fri, 9 Oct 2020 16:41:26 +0530 Subject: [PATCH] net/bnxt: support parent child flow database Added support for parent child flow database apis. This feature adds support to enable vxlan decap support where flows needs to maintain parent-child flow relationship. Signed-off-by: Kishore Padmanabha Reviewed-by: Mike Baucom Reviewed-by: Ajit Khaparde --- drivers/net/bnxt/tf_ulp/ulp_flow_db.c | 348 +++++++++++++++++- drivers/net/bnxt/tf_ulp/ulp_flow_db.h | 84 +++++ drivers/net/bnxt/tf_ulp/ulp_template_db_tbl.c | 1 + drivers/net/bnxt/tf_ulp/ulp_template_struct.h | 1 + drivers/net/bnxt/tf_ulp/ulp_utils.h | 4 + 5 files changed, 435 insertions(+), 3 deletions(-) diff --git a/drivers/net/bnxt/tf_ulp/ulp_flow_db.c b/drivers/net/bnxt/tf_ulp/ulp_flow_db.c index da012451db..a1c39329f7 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_flow_db.c +++ b/drivers/net/bnxt/tf_ulp/ulp_flow_db.c @@ -207,13 +207,16 @@ ulp_flow_db_alloc_resource(struct bnxt_ulp_flow_db *flow_db) return -ENOMEM; } size = (flow_tbl->num_flows / sizeof(uint64_t)) + 1; - flow_tbl->active_reg_flows = rte_zmalloc("active reg flows", size, 0); + size = ULP_BYTE_ROUND_OFF_8(size); + flow_tbl->active_reg_flows = rte_zmalloc("active reg flows", size, + ULP_BUFFER_ALIGN_64_BYTE); if (!flow_tbl->active_reg_flows) { BNXT_TF_DBG(ERR, "Failed to alloc memory active reg flows\n"); return -ENOMEM; } - flow_tbl->active_dflt_flows = rte_zmalloc("active dflt flows", size, 0); + flow_tbl->active_dflt_flows = rte_zmalloc("active dflt flows", size, + ULP_BUFFER_ALIGN_64_BYTE); if (!flow_tbl->active_dflt_flows) { BNXT_TF_DBG(ERR, "Failed to alloc memory active dflt flows\n"); return -ENOMEM; @@ -284,6 +287,86 @@ ulp_flow_db_func_id_set(struct bnxt_ulp_flow_db *flow_db, BNXT_TF_DBG(ERR, "Invalid flow id, flowdb corrupt\n"); } +/* + * Initialize the parent-child database. Memory is allocated in this + * call and assigned to the database + * + * flow_db [in] Ptr to flow table + * num_entries[in] - number of entries to allocate + * + * Returns 0 on success or negative number on failure. + */ +static int32_t +ulp_flow_db_parent_tbl_init(struct bnxt_ulp_flow_db *flow_db, + uint32_t num_entries) +{ + struct ulp_fdb_parent_child_db *p_db; + uint32_t size, idx; + + /* update the sizes for the allocation */ + p_db = &flow_db->parent_child_db; + p_db->child_bitset_size = (flow_db->flow_tbl.num_flows / + sizeof(uint64_t)) + 1; /* size in bytes */ + p_db->child_bitset_size = ULP_BYTE_ROUND_OFF_8(p_db->child_bitset_size); + p_db->entries_count = num_entries; + + /* allocate the memory */ + p_db->parent_flow_tbl = rte_zmalloc("fdb parent flow tbl", + sizeof(struct ulp_fdb_parent_info) * + p_db->entries_count, 0); + if (!p_db->parent_flow_tbl) { + BNXT_TF_DBG(ERR, + "Failed to allocate memory fdb parent flow tbl\n"); + return -ENOMEM; + } + size = p_db->child_bitset_size * p_db->entries_count; + + /* + * allocate the big chunk of memory to be statically carved into + * child_fid_bitset pointer. + */ + p_db->parent_flow_tbl_mem = rte_zmalloc("fdb parent flow tbl mem", + size, + ULP_BUFFER_ALIGN_64_BYTE); + if (!p_db->parent_flow_tbl_mem) { + BNXT_TF_DBG(ERR, + "Failed to allocate memory fdb parent flow mem\n"); + return -ENOMEM; + } + + /* set the pointers in parent table to their offsets */ + for (idx = 0 ; idx < p_db->entries_count; idx++) { + p_db->parent_flow_tbl[idx].child_fid_bitset = + (uint64_t *)&p_db->parent_flow_tbl_mem[idx * + p_db->child_bitset_size]; + } + /* success */ + return 0; +} + +/* + * Deinitialize the parent-child database. Memory is deallocated in + * this call and all flows should have been purged before this + * call. + * + * flow_db [in] Ptr to flow table + * + * Returns none + */ +static void +ulp_flow_db_parent_tbl_deinit(struct bnxt_ulp_flow_db *flow_db) +{ + /* free the memory related to parent child database */ + if (flow_db->parent_child_db.parent_flow_tbl_mem) { + rte_free(flow_db->parent_child_db.parent_flow_tbl_mem); + flow_db->parent_child_db.parent_flow_tbl_mem = NULL; + } + if (flow_db->parent_child_db.parent_flow_tbl) { + rte_free(flow_db->parent_child_db.parent_flow_tbl); + flow_db->parent_child_db.parent_flow_tbl = NULL; + } +} + /* * Initialize the flow database. Memory is allocated in this * call and assigned to the flow database. @@ -357,6 +440,14 @@ ulp_flow_db_init(struct bnxt_ulp_context *ulp_ctxt) "Failed to allocate mem for flow table func id\n"); goto error_free; } + /* initialize the parent child database */ + if (ulp_flow_db_parent_tbl_init(flow_db, + dparms->fdb_parent_flow_entries)) { + BNXT_TF_DBG(ERR, + "Failed to allocate mem for parent child db\n"); + goto error_free; + } + /* All good so return. */ BNXT_TF_DBG(INFO, "FlowDB initialized with %d flows.\n", flow_tbl->num_flows); @@ -388,6 +479,7 @@ ulp_flow_db_deinit(struct bnxt_ulp_context *ulp_ctxt) bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, NULL); /* Free up all the memory. */ + ulp_flow_db_parent_tbl_deinit(flow_db); ulp_flow_db_dealloc_resource(flow_db); rte_free(flow_db->func_id_tbl); rte_free(flow_db); @@ -578,7 +670,7 @@ ulp_flow_db_resource_del(struct bnxt_ulp_context *ulp_ctxt, flow_tbl = &flow_db->flow_tbl; /* check for max flows */ if (fid >= flow_tbl->num_flows || !fid) { - BNXT_TF_DBG(ERR, "Invalid flow index\n"); + BNXT_TF_DBG(ERR, "Invalid flow index %x\n", fid); return -EINVAL; } @@ -1050,3 +1142,253 @@ ulp_default_flow_db_cfa_action_get(struct bnxt_ulp_context *ulp_ctx, *cfa_action = hndl; return 0; } + +/* + * Allocate the entry in the parent-child database + * + * ulp_ctxt [in] Ptr to ulp_context + * fid [in] The flow id to the flow entry + * + * returns index on success and negative on failure. + */ +int32_t +ulp_flow_db_parent_flow_alloc(struct bnxt_ulp_context *ulp_ctxt, + uint32_t fid) +{ + struct bnxt_ulp_flow_db *flow_db; + struct ulp_fdb_parent_child_db *p_pdb; + uint32_t idx, free_idx = 0; + + flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); + if (!flow_db) { + BNXT_TF_DBG(ERR, "Invalid Arguments\n"); + return -EINVAL; + } + + /* check for max flows */ + if (fid >= flow_db->flow_tbl.num_flows || !fid) { + BNXT_TF_DBG(ERR, "Invalid flow index\n"); + return -EINVAL; + } + + p_pdb = &flow_db->parent_child_db; + for (idx = 0; idx <= p_pdb->entries_count; idx++) { + if (p_pdb->parent_flow_tbl[idx].parent_fid == fid) { + BNXT_TF_DBG(ERR, "fid is already allocated\n"); + return -EINVAL; + } + if (!p_pdb->parent_flow_tbl[idx].parent_fid && !free_idx) + free_idx = idx + 1; + } + /* no free slots */ + if (!free_idx) { + BNXT_TF_DBG(ERR, "parent child db is full\n"); + return -ENOMEM; + } + + free_idx -= 1; + /* set the Fid in the parent child */ + p_pdb->parent_flow_tbl[free_idx].parent_fid = fid; + return free_idx; +} + +/* + * Free the entry in the parent-child database + * + * ulp_ctxt [in] Ptr to ulp_context + * fid [in] The flow id to the flow entry + * + * returns 0 on success and negative on failure. + */ +int32_t +ulp_flow_db_parent_flow_free(struct bnxt_ulp_context *ulp_ctxt, + uint32_t fid) +{ + struct bnxt_ulp_flow_db *flow_db; + struct ulp_fdb_parent_child_db *p_pdb; + uint32_t idx; + + flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); + if (!flow_db) { + BNXT_TF_DBG(ERR, "Invalid Arguments\n"); + return -EINVAL; + } + + /* check for max flows */ + if (fid >= flow_db->flow_tbl.num_flows || !fid) { + BNXT_TF_DBG(ERR, "Invalid flow index\n"); + return -EINVAL; + } + + p_pdb = &flow_db->parent_child_db; + for (idx = 0; idx <= p_pdb->entries_count; idx++) { + if (p_pdb->parent_flow_tbl[idx].parent_fid == fid) { + /* free the contents */ + p_pdb->parent_flow_tbl[idx].parent_fid = 0; + memset(p_pdb->parent_flow_tbl[idx].child_fid_bitset, + 0, p_pdb->child_bitset_size); + return 0; + } + } + BNXT_TF_DBG(ERR, "parent entry not found = %x\n", fid); + return -EINVAL; +} + +/* + * Set or reset the child flow in the parent-child database + * + * ulp_ctxt [in] Ptr to ulp_context + * parent_fid [in] The flow id of the parent flow entry + * child_fid [in] The flow id of the child flow entry + * set_flag [in] Use 1 for setting child, 0 to reset + * + * returns zero on success and negative on failure. + */ +int32_t +ulp_flow_db_parent_child_flow_set(struct bnxt_ulp_context *ulp_ctxt, + uint32_t parent_fid, + uint32_t child_fid, + uint32_t set_flag) +{ + struct bnxt_ulp_flow_db *flow_db; + struct ulp_fdb_parent_child_db *p_pdb; + uint32_t idx, a_idx; + uint64_t *t; + + flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); + if (!flow_db) { + BNXT_TF_DBG(ERR, "Invalid Arguments\n"); + return -EINVAL; + } + + /* check for fid validity */ + if (parent_fid >= flow_db->flow_tbl.num_flows || !parent_fid) { + BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_fid); + return -EINVAL; + } + + /* check for fid validity */ + if (child_fid >= flow_db->flow_tbl.num_flows || !child_fid) { + BNXT_TF_DBG(ERR, "Invalid child flow index %x\n", child_fid); + return -EINVAL; + } + + p_pdb = &flow_db->parent_child_db; + a_idx = child_fid / ULP_INDEX_BITMAP_SIZE; + for (idx = 0; idx <= p_pdb->entries_count; idx++) { + if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) { + t = p_pdb->parent_flow_tbl[idx].child_fid_bitset; + if (set_flag) + ULP_INDEX_BITMAP_SET(t[a_idx], child_fid); + else + ULP_INDEX_BITMAP_RESET(t[a_idx], child_fid); + return 0; + } + } + BNXT_TF_DBG(ERR, "Unable to set the parent-child flow %x:%x\n", + parent_fid, child_fid); + return -1; +} + +/* + * Get the parent index from the parent-child database + * + * ulp_ctxt [in] Ptr to ulp_context + * parent_fid [in] The flow id of the parent flow entry + * parent_idx [out] The parent index of parent flow entry + * + * returns zero on success and negative on failure. + */ +int32_t +ulp_flow_db_parent_flow_idx_get(struct bnxt_ulp_context *ulp_ctxt, + uint32_t parent_fid, + uint32_t *parent_idx) +{ + struct bnxt_ulp_flow_db *flow_db; + struct ulp_fdb_parent_child_db *p_pdb; + uint32_t idx; + + flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); + if (!flow_db) { + BNXT_TF_DBG(ERR, "Invalid Arguments\n"); + return -EINVAL; + } + + /* check for fid validity */ + if (parent_fid >= flow_db->flow_tbl.num_flows || !parent_fid) { + BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_fid); + return -EINVAL; + } + + p_pdb = &flow_db->parent_child_db; + for (idx = 0; idx <= p_pdb->entries_count; idx++) { + if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) { + *parent_idx = idx; + return 0; + } + } + BNXT_TF_DBG(ERR, "Unable to get the parent flow %x\n", parent_fid); + return -1; +} + +/* + * Get the next child flow in the parent-child database + * + * ulp_ctxt [in] Ptr to ulp_context + * parent_fid [in] The flow id of the parent flow entry + * child_fid [in/out] The flow id of the child flow entry + * + * returns zero on success and negative on failure. + * Pass child_fid as zero for first entry. + */ +int32_t +ulp_flow_db_parent_child_flow_next_entry_get(struct bnxt_ulp_flow_db *flow_db, + uint32_t parent_idx, + uint32_t *child_fid) +{ + struct ulp_fdb_parent_child_db *p_pdb; + uint32_t idx, s_idx, mod_fid; + uint32_t next_fid = *child_fid; + uint64_t *child_bitset; + uint64_t bs; + + /* check for fid validity */ + p_pdb = &flow_db->parent_child_db; + if (parent_idx >= p_pdb->entries_count || + !p_pdb->parent_flow_tbl[parent_idx].parent_fid) { + BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_idx); + return -EINVAL; + } + + child_bitset = p_pdb->parent_flow_tbl[parent_idx].child_fid_bitset; + do { + /* increment the flow id to find the next valid flow id */ + next_fid++; + if (next_fid >= flow_db->flow_tbl.num_flows) + return -ENOENT; + idx = next_fid / ULP_INDEX_BITMAP_SIZE; + mod_fid = next_fid % ULP_INDEX_BITMAP_SIZE; + s_idx = idx; + while (!(bs = child_bitset[idx])) { + idx++; + if ((idx * ULP_INDEX_BITMAP_SIZE) >= + flow_db->flow_tbl.num_flows) + return -ENOENT; + } + /* + * remove the previous bits in the bitset bs to find the + * next non zero bit in the bitset. This needs to be done + * only if the idx is same as he one you started. + */ + if (s_idx == idx) + bs &= (-1UL >> mod_fid); + next_fid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs); + if (*child_fid >= next_fid) { + BNXT_TF_DBG(ERR, "Parent Child Database is corrupt\n"); + return -ENOENT; + } + idx = next_fid / ULP_INDEX_BITMAP_SIZE; + } while (!ULP_INDEX_BITMAP_GET(child_bitset[idx], next_fid)); + *child_fid = next_fid; + return 0; +} diff --git a/drivers/net/bnxt/tf_ulp/ulp_flow_db.h b/drivers/net/bnxt/tf_ulp/ulp_flow_db.h index 7ec4b8ae03..87bcd69aee 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_flow_db.h +++ b/drivers/net/bnxt/tf_ulp/ulp_flow_db.h @@ -52,11 +52,26 @@ struct bnxt_ulp_flow_tbl { uint32_t num_resources; }; +/* Structure to maintain parent-child flow relationships */ +struct ulp_fdb_parent_info { + uint32_t parent_fid; + uint64_t *child_fid_bitset; +}; + +/* Structure to maintain parent-child flow relationships */ +struct ulp_fdb_parent_child_db { + struct ulp_fdb_parent_info *parent_flow_tbl; + uint32_t child_bitset_size; + uint32_t entries_count; + uint8_t *parent_flow_tbl_mem; +}; + /* Structure for the flow database resource information. */ struct bnxt_ulp_flow_db { struct bnxt_ulp_flow_tbl flow_tbl; uint16_t *func_id_tbl; uint32_t func_id_tbl_size; + struct ulp_fdb_parent_child_db parent_child_db; }; /* flow db resource params to add resources */ @@ -235,5 +250,74 @@ int32_t ulp_default_flow_db_cfa_action_get(struct bnxt_ulp_context *ulp_ctx, uint32_t flow_id, uint16_t *cfa_action); +/* + * Allocate the entry in the parent-child database + * + * ulp_ctxt [in] Ptr to ulp_context + * fid [in] The flow id to the flow entry + * + * returns index on success and negative on failure. + */ +int32_t +ulp_flow_db_parent_flow_alloc(struct bnxt_ulp_context *ulp_ctxt, + uint32_t fid); + +/* + * Free the entry in the parent-child database + * + * ulp_ctxt [in] Ptr to ulp_context + * fid [in] The flow id to the flow entry + * + * returns 0 on success and negative on failure. + */ +int32_t +ulp_flow_db_parent_flow_free(struct bnxt_ulp_context *ulp_ctxt, + uint32_t fid); + +/* + * Set or reset the child flow in the parent-child database + * + * ulp_ctxt [in] Ptr to ulp_context + * parent_fid [in] The flow id of the parent flow entry + * child_fid [in] The flow id of the child flow entry + * set_flag [in] Use 1 for setting child, 0 to reset + * + * returns zero on success and negative on failure. + */ +int32_t +ulp_flow_db_parent_child_flow_set(struct bnxt_ulp_context *ulp_ctxt, + uint32_t parent_fid, + uint32_t child_fid, + uint32_t set_flag); + +/* + * Get the parent index from the parent-child database + * + * ulp_ctxt [in] Ptr to ulp_context + * parent_fid [in] The flow id of the parent flow entry + * parent_idx [out] The parent index of parent flow entry + * + * returns zero on success and negative on failure. + */ +int32_t +ulp_flow_db_parent_flow_idx_get(struct bnxt_ulp_context *ulp_ctxt, + uint32_t parent_fid, + uint32_t *parent_idx); + +/* + * Get the next child flow in the parent-child database + * + * ulp_ctxt [in] Ptr to ulp_context + * parent_fid [in] The flow id of the parent flow entry + * child_fid [in/out] The flow id of the child flow entry + * + * returns zero on success and negative on failure. + * Pass child_fid as zero for first entry. + */ +int32_t +ulp_flow_db_parent_child_flow_next_entry_get(struct bnxt_ulp_flow_db *flow_db, + uint32_t parent_idx, + uint32_t *child_fid); + #endif /* _ULP_FLOW_DB_H_ */ diff --git a/drivers/net/bnxt/tf_ulp/ulp_template_db_tbl.c b/drivers/net/bnxt/tf_ulp/ulp_template_db_tbl.c index 4904a41c33..a677b0ca57 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_template_db_tbl.c +++ b/drivers/net/bnxt/tf_ulp/ulp_template_db_tbl.c @@ -368,6 +368,7 @@ struct bnxt_ulp_device_params ulp_device_params[BNXT_ULP_DEVICE_ID_LAST] = { .mark_db_lfid_entries = 65536, .mark_db_gfid_entries = 65536, .flow_count_db_entries = 16384, + .fdb_parent_flow_entries = 2, .num_resources_per_flow = 8, .num_phy_ports = 2, .ext_cntr_table_type = 0, diff --git a/drivers/net/bnxt/tf_ulp/ulp_template_struct.h b/drivers/net/bnxt/tf_ulp/ulp_template_struct.h index 50a986c89e..2e94b6f191 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_template_struct.h +++ b/drivers/net/bnxt/tf_ulp/ulp_template_struct.h @@ -160,6 +160,7 @@ struct bnxt_ulp_device_params { uint64_t int_flow_db_num_entries; uint64_t ext_flow_db_num_entries; uint32_t flow_count_db_entries; + uint32_t fdb_parent_flow_entries; uint32_t num_resources_per_flow; uint32_t ext_cntr_table_type; uint64_t byte_count_mask; diff --git a/drivers/net/bnxt/tf_ulp/ulp_utils.h b/drivers/net/bnxt/tf_ulp/ulp_utils.h index c054a77a90..898e85123e 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_utils.h +++ b/drivers/net/bnxt/tf_ulp/ulp_utils.h @@ -11,6 +11,7 @@ #define ULP_BUFFER_ALIGN_8_BYTE 8 #define ULP_BUFFER_ALIGN_16_BYTE 16 +#define ULP_BUFFER_ALIGN_64_BYTE 64 /* * Macros for bitmap sets and gets @@ -53,6 +54,9 @@ /* Macro to convert bits to bytes with no round off*/ #define ULP_BITS_2_BYTE_NR(bits_x) ((bits_x) / 8) +/* Macro to round off to next multiple of 8*/ +#define ULP_BYTE_ROUND_OFF_8(x) (((x) + 7) & ~7) + /* Macros to read the computed fields */ #define ULP_COMP_FLD_IDX_RD(params, idx) \ rte_be_to_cpu_32((params)->comp_fld[(idx)]) -- 2.20.1