From: Mike Baucom <michael.bau...@broadcom.com> This patch does the following 1. Gets all the flow resources from the flow id 2. Frees all the table resources 3. Frees the flow in the flow table
Signed-off-by: Mike Baucom <michael.bau...@broadcom.com> Signed-off-by: Kishore Padmanabha <kishore.padmana...@broadcom.com> Signed-off-by: Venkat Duvvuru <venkatkumar.duvv...@broadcom.com> Reviewed-by: Lance Richardson <lance.richard...@broadcom.com> Reviewed-by: Ajit Kumar Khaparde <ajit.khapa...@broadcom.com> --- drivers/net/bnxt/tf_ulp/ulp_flow_db.c | 199 ++++++++++++++++++++++++++++++++- drivers/net/bnxt/tf_ulp/ulp_flow_db.h | 30 +++++ drivers/net/bnxt/tf_ulp/ulp_mapper.c | 193 ++++++++++++++++++++++++++++++++ drivers/net/bnxt/tf_ulp/ulp_mapper.h | 15 +++ drivers/net/bnxt/tf_ulp/ulp_mark_mgr.c | 23 +++- drivers/net/bnxt/tf_ulp/ulp_mark_mgr.h | 18 +++ 6 files changed, 476 insertions(+), 2 deletions(-) diff --git a/drivers/net/bnxt/tf_ulp/ulp_flow_db.c b/drivers/net/bnxt/tf_ulp/ulp_flow_db.c index 0e7b433..8449db3 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_flow_db.c +++ b/drivers/net/bnxt/tf_ulp/ulp_flow_db.c @@ -23,6 +23,32 @@ #define ULP_FLOW_DB_RES_NXT_RESET(dst) ((dst) &= ~(ULP_FLOW_DB_RES_NXT_MASK)) /* + * Helper function to set the bit in the active flow table + * No validation is done in this function. + * + * flow_tbl [in] Ptr to flow table + * idx [in] The index to bit to be set or reset. + * flag [in] 1 to set and 0 to reset. + * + * returns none + */ +static void +ulp_flow_db_active_flow_set(struct bnxt_ulp_flow_tbl *flow_tbl, + uint32_t idx, + uint32_t flag) +{ + uint32_t active_index; + + active_index = idx / ULP_INDEX_BITMAP_SIZE; + if (flag) + ULP_INDEX_BITMAP_SET(flow_tbl->active_flow_tbl[active_index], + idx); + else + ULP_INDEX_BITMAP_RESET(flow_tbl->active_flow_tbl[active_index], + idx); +} + +/* * Helper function to allocate the flow table and initialize * is set.No validation being done in this function. * @@ -71,6 +97,35 @@ ulp_flow_db_res_params_to_info(struct ulp_fdb_resource_info *resource_info, } /* + * Helper function to copy the resource params to resource info + * No validation being done in this function. + * + * resource_info [in] Ptr to resource information + * params [out] The output params to the caller + * + * returns none + */ +static void +ulp_flow_db_res_info_to_params(struct ulp_fdb_resource_info *resource_info, + struct ulp_flow_db_res_params *params) +{ + memset(params, 0, sizeof(struct ulp_flow_db_res_params)); + params->direction = ((resource_info->nxt_resource_idx & + ULP_FLOW_DB_RES_DIR_MASK) >> + ULP_FLOW_DB_RES_DIR_BIT); + params->resource_func = ((resource_info->nxt_resource_idx & + ULP_FLOW_DB_RES_FUNC_MASK) >> + ULP_FLOW_DB_RES_FUNC_BITS); + + if (params->resource_func != BNXT_ULP_RESOURCE_FUNC_EM_TABLE) { + params->resource_hndl = resource_info->resource_hndl; + params->resource_type = resource_info->resource_type; + } else { + params->resource_hndl = resource_info->resource_em_handle; + } +} + +/* * Helper function to allocate the flow table and initialize * the stack for allocation operations. * @@ -122,7 +177,7 @@ ulp_flow_db_alloc_resource(struct bnxt_ulp_flow_db *flow_db, } /* - * Helper function to de allocate the flow table. + * Helper function to deallocate the flow table. * * flow_db [in] Ptr to flow database structure * tbl_idx [in] The index to table creation. @@ -321,3 +376,145 @@ int32_t ulp_flow_db_resource_add(struct bnxt_ulp_context *ulp_ctxt, /* all good, return success */ return 0; } + +/* + * Free the flow database entry. + * The params->critical_resource has to be set to 1 to free the first resource. + * + * ulp_ctxt [in] Ptr to ulp_context + * tbl_idx [in] Specify it is regular or default flow + * fid [in] The index to the flow entry + * params [in/out] The contents to be copied into params. + * Onlythe critical_resource needs to be set by the caller. + * + * Returns 0 on success and negative on failure. + */ +int32_t ulp_flow_db_resource_del(struct bnxt_ulp_context *ulp_ctxt, + enum bnxt_ulp_flow_db_tables tbl_idx, + uint32_t fid, + struct ulp_flow_db_res_params *params) +{ + struct bnxt_ulp_flow_db *flow_db; + struct bnxt_ulp_flow_tbl *flow_tbl; + struct ulp_fdb_resource_info *nxt_resource, *fid_resource; + uint32_t nxt_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; + } + + if (tbl_idx < 0 || tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) { + BNXT_TF_DBG(ERR, "Invalid table index\n"); + return -EINVAL; + } + flow_tbl = &flow_db->flow_tbl[tbl_idx]; + + /* check for max flows */ + if (fid >= flow_tbl->num_flows || !fid) { + BNXT_TF_DBG(ERR, "Invalid flow index\n"); + return -EINVAL; + } + + /* check if the flow is active or not */ + if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) { + BNXT_TF_DBG(ERR, "flow does not exist\n"); + return -EINVAL; + } + + fid_resource = &flow_tbl->flow_resources[fid]; + if (!params->critical_resource) { + /* Not the critical resource so free the resource */ + ULP_FLOW_DB_RES_NXT_SET(nxt_idx, + fid_resource->nxt_resource_idx); + if (!nxt_idx) { + /* reached end of resources */ + return -ENOENT; + } + nxt_resource = &flow_tbl->flow_resources[nxt_idx]; + + /* connect the fid resource to the next resource */ + ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx); + ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx, + nxt_resource->nxt_resource_idx); + + /* update the contents to be given to caller */ + ulp_flow_db_res_info_to_params(nxt_resource, params); + + /* Delete the nxt_resource */ + memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info)); + + /* add it to the free list */ + flow_tbl->tail_index++; + if (flow_tbl->tail_index >= flow_tbl->num_resources) { + BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n"); + return -ENOENT; + } + flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx; + + } else { + /* Critical resource. copy the contents and exit */ + ulp_flow_db_res_info_to_params(fid_resource, params); + ULP_FLOW_DB_RES_NXT_SET(nxt_idx, + fid_resource->nxt_resource_idx); + memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info)); + ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx, + nxt_idx); + } + + /* all good, return success */ + return 0; +} + +/* + * Free the flow database entry + * + * ulp_ctxt [in] Ptr to ulp_context + * tbl_idx [in] Specify it is regular or default flow + * fid [in] The index to the flow entry + * + * returns 0 on success and negative on failure. + */ +int32_t ulp_flow_db_fid_free(struct bnxt_ulp_context *ulp_ctxt, + enum bnxt_ulp_flow_db_tables tbl_idx, + uint32_t fid) +{ + struct bnxt_ulp_flow_db *flow_db; + struct bnxt_ulp_flow_tbl *flow_tbl; + + flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); + if (!flow_db) { + BNXT_TF_DBG(ERR, "Invalid Arguments\n"); + return -EINVAL; + } + + if (tbl_idx < 0 || tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) { + BNXT_TF_DBG(ERR, "Invalid table index\n"); + return -EINVAL; + } + + flow_tbl = &flow_db->flow_tbl[tbl_idx]; + + /* check for limits of fid */ + if (fid >= flow_tbl->num_flows || !fid) { + BNXT_TF_DBG(ERR, "Invalid flow index\n"); + return -EINVAL; + } + + /* check if the flow is active or not */ + if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) { + BNXT_TF_DBG(ERR, "flow does not exist\n"); + return -EINVAL; + } + flow_tbl->head_index--; + if (!flow_tbl->head_index) { + BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n"); + return -ENOENT; + } + flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid; + ulp_flow_db_active_flow_set(flow_tbl, fid, 0); + + /* all good, return success */ + 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 f6055a5..20109b9 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_flow_db.h +++ b/drivers/net/bnxt/tf_ulp/ulp_flow_db.h @@ -99,4 +99,34 @@ int32_t ulp_flow_db_resource_add(struct bnxt_ulp_context *ulp_ctxt, uint32_t fid, struct ulp_flow_db_res_params *params); +/* + * Free the flow database entry. + * The params->critical_resource has to be set to 1 to free the first resource. + * + * ulp_ctxt [in] Ptr to ulp_context + * tbl_idx [in] Specify it is regular or default flow + * fid [in] The index to the flow entry + * params [in/out] The contents to be copied into params. + * Only the critical_resource needs to be set by the caller. + * + * Returns 0 on success and negative on failure. + */ +int32_t ulp_flow_db_resource_del(struct bnxt_ulp_context *ulp_ctxt, + enum bnxt_ulp_flow_db_tables tbl_idx, + uint32_t fid, + struct ulp_flow_db_res_params *params); + +/* + * Free the flow database entry + * + * ulp_ctxt [in] Ptr to ulp_context + * tbl_idx [in] Specify it is regular or default flow + * fid [in] The index to the flow entry + * + * returns 0 on success and negative on failure. + */ +int32_t ulp_flow_db_fid_free(struct bnxt_ulp_context *ulp_ctxt, + enum bnxt_ulp_flow_db_tables tbl_idx, + uint32_t fid); + #endif /* _ULP_FLOW_DB_H_ */ diff --git a/drivers/net/bnxt/tf_ulp/ulp_mapper.c b/drivers/net/bnxt/tf_ulp/ulp_mapper.c index a041394..cc85557 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_mapper.c +++ b/drivers/net/bnxt/tf_ulp/ulp_mapper.c @@ -143,6 +143,87 @@ ulp_mapper_ident_fields_get(struct bnxt_ulp_mapper_class_tbl_info *tbl, return &ulp_ident_list[idx]; } +static inline int32_t +ulp_mapper_tcam_entry_free(struct bnxt_ulp_context *ulp __rte_unused, + struct tf *tfp, + struct ulp_flow_db_res_params *res) +{ + struct tf_free_tcam_entry_parms fparms = { + .dir = res->direction, + .tcam_tbl_type = res->resource_type, + .idx = (uint16_t)res->resource_hndl + }; + + return tf_free_tcam_entry(tfp, &fparms); +} + +static inline int32_t +ulp_mapper_index_entry_free(struct bnxt_ulp_context *ulp __rte_unused, + struct tf *tfp, + struct ulp_flow_db_res_params *res) +{ + struct tf_free_tbl_entry_parms fparms = { + .dir = res->direction, + .type = res->resource_type, + .idx = (uint32_t)res->resource_hndl + }; + + return tf_free_tbl_entry(tfp, &fparms); +} + +static inline int32_t +ulp_mapper_eem_entry_free(struct bnxt_ulp_context *ulp, + struct tf *tfp, + struct ulp_flow_db_res_params *res) +{ + struct tf_delete_em_entry_parms fparms = { 0 }; + int32_t rc; + + fparms.dir = res->direction; + fparms.mem = TF_MEM_EXTERNAL; + fparms.flow_handle = res->resource_hndl; + + rc = bnxt_ulp_cntxt_tbl_scope_id_get(ulp, &fparms.tbl_scope_id); + if (rc) { + BNXT_TF_DBG(ERR, "Failed to get table scope\n"); + return -EINVAL; + } + + return tf_delete_em_entry(tfp, &fparms); +} + +static inline int32_t +ulp_mapper_ident_free(struct bnxt_ulp_context *ulp __rte_unused, + struct tf *tfp, + struct ulp_flow_db_res_params *res) +{ + struct tf_free_identifier_parms fparms = { + .dir = res->direction, + .ident_type = res->resource_type, + .id = (uint16_t)res->resource_hndl + }; + + return tf_free_identifier(tfp, &fparms); +} + +static inline int32_t +ulp_mapper_mark_free(struct bnxt_ulp_context *ulp, + struct ulp_flow_db_res_params *res) +{ + uint32_t flag; + uint32_t fid; + uint32_t gfid; + + fid = (uint32_t)res->resource_hndl; + TF_GET_FLAG_FROM_FLOW_ID(fid, flag); + TF_GET_GFID_FROM_FLOW_ID(fid, gfid); + + return ulp_mark_db_mark_del(ulp, + (flag == TF_GFID_TABLE_EXTERNAL), + gfid, + 0); +} + static int32_t ulp_mapper_ident_process(struct bnxt_ulp_mapper_parms *parms, struct bnxt_ulp_mapper_class_tbl_info *tbl, @@ -1131,3 +1212,115 @@ ulp_mapper_class_tbls_process(struct bnxt_ulp_mapper_parms *parms) return rc; } + +static int32_t +ulp_mapper_resource_free(struct bnxt_ulp_context *ulp, + struct ulp_flow_db_res_params *res) +{ + struct tf *tfp; + int32_t rc; + + if (!res || !ulp) { + BNXT_TF_DBG(ERR, "Unable to free resource\n "); + return -EINVAL; + } + + tfp = bnxt_ulp_cntxt_tfp_get(ulp); + if (!tfp) { + BNXT_TF_DBG(ERR, "Unable to free resource failed to get tfp\n"); + return -EINVAL; + } + + switch (res->resource_func) { + case BNXT_ULP_RESOURCE_FUNC_TCAM_TABLE: + rc = ulp_mapper_tcam_entry_free(ulp, tfp, res); + break; + case BNXT_ULP_RESOURCE_FUNC_EM_TABLE: + rc = ulp_mapper_eem_entry_free(ulp, tfp, res); + break; + case BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE: + rc = ulp_mapper_index_entry_free(ulp, tfp, res); + break; + case BNXT_ULP_RESOURCE_FUNC_IDENTIFIER: + rc = ulp_mapper_ident_free(ulp, tfp, res); + break; + case BNXT_ULP_RESOURCE_FUNC_HW_FID: + rc = ulp_mapper_mark_free(ulp, res); + break; + default: + break; + } + + return rc; +} + +int32_t +ulp_mapper_resources_free(struct bnxt_ulp_context *ulp_ctx, + uint32_t fid, + enum bnxt_ulp_flow_db_tables tbl_type) +{ + struct ulp_flow_db_res_params res_parms = { 0 }; + int32_t rc, trc; + + if (!ulp_ctx) { + BNXT_TF_DBG(ERR, "Invalid parms, unable to free flow\n"); + return -EINVAL; + } + + /* + * Set the critical resource on the first resource del, then iterate + * while status is good + */ + res_parms.critical_resource = 1; + rc = ulp_flow_db_resource_del(ulp_ctx, tbl_type, fid, &res_parms); + + if (rc) { + /* + * This is unexpected on the first call to resource del. + * It likely means that the flow did not exist in the flow db. + */ + BNXT_TF_DBG(ERR, "Flow[%d][0x%08x] failed to free (rc=%d)\n", + tbl_type, fid, rc); + return rc; + } + + while (!rc) { + trc = ulp_mapper_resource_free(ulp_ctx, &res_parms); + if (trc) + /* + * On fail, we still need to attempt to free the + * remaining resources. Don't return + */ + BNXT_TF_DBG(ERR, + "Flow[%d][0x%x] Res[%d][0x%016" PRIx64 + "] failed rc=%d.\n", + tbl_type, fid, res_parms.resource_func, + res_parms.resource_hndl, trc); + + /* All subsequent call require the critical_resource be zero */ + res_parms.critical_resource = 0; + + rc = ulp_flow_db_resource_del(ulp_ctx, + tbl_type, + fid, + &res_parms); + } + + /* Free the Flow ID since we've removed all resources */ + rc = ulp_flow_db_fid_free(ulp_ctx, tbl_type, fid); + + return rc; +} + +int32_t +ulp_mapper_flow_destroy(struct bnxt_ulp_context *ulp_ctx, uint32_t fid) +{ + if (!ulp_ctx) { + BNXT_TF_DBG(ERR, "Invalid parms, unable to free flow\n"); + return -EINVAL; + } + + return ulp_mapper_resources_free(ulp_ctx, + fid, + BNXT_ULP_REGULAR_FLOW_TABLE); +} diff --git a/drivers/net/bnxt/tf_ulp/ulp_mapper.h b/drivers/net/bnxt/tf_ulp/ulp_mapper.h index adbcec2..8655728 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_mapper.h +++ b/drivers/net/bnxt/tf_ulp/ulp_mapper.h @@ -15,6 +15,8 @@ #include "bnxt_ulp.h" #include "ulp_utils.h" +#define ULP_SZ_BITS2BYTES(x) (((x) + 7) / 8) + /* Internal Structure for passing the arguments around */ struct bnxt_ulp_mapper_parms { uint32_t dev_id; @@ -36,4 +38,17 @@ struct bnxt_ulp_mapper_parms { enum bnxt_ulp_flow_db_tables tbl_idx; }; +/* Function that frees all resources associated with the flow. */ +int32_t +ulp_mapper_flow_destroy(struct bnxt_ulp_context *ulp_ctx, uint32_t fid); + +/* + * Function that frees all resources and can be called on default or regular + * flows + */ +int32_t +ulp_mapper_resources_free(struct bnxt_ulp_context *ulp_ctx, + uint32_t fid, + enum bnxt_ulp_flow_db_tables tbl_type); + #endif /* _ULP_MAPPER_H_ */ diff --git a/drivers/net/bnxt/tf_ulp/ulp_mark_mgr.c b/drivers/net/bnxt/tf_ulp/ulp_mark_mgr.c index 837064e..566668e 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_mark_mgr.c +++ b/drivers/net/bnxt/tf_ulp/ulp_mark_mgr.c @@ -135,7 +135,7 @@ ulp_mark_db_init(struct bnxt_ulp_context *ctxt) mark_tbl->gfid_max, mark_tbl->gfid_mask); - /* Add the mart tbl to the ulp context. */ + /* Add the mark tbl to the ulp context. */ bnxt_ulp_cntxt_ptr2_mark_db_set(ctxt, mark_tbl); return 0; @@ -195,3 +195,24 @@ ulp_mark_db_mark_add(struct bnxt_ulp_context *ctxt, { return ulp_mark_db_mark_set(ctxt, is_gfid, gfid, mark); } + +/* + * Removes a Mark from the Mark Manager + * + * ctxt [in] The ulp context for the mark manager + * + * is_gfid [in] The type of fid (GFID or LFID) + * + * fid [in] The flow id that is returned by HW in BD + * + * mark [in] The mark to be associated with the FID + * + */ +int32_t +ulp_mark_db_mark_del(struct bnxt_ulp_context *ctxt, + bool is_gfid, + uint32_t gfid, + uint32_t mark __rte_unused) +{ + return ulp_mark_db_mark_set(ctxt, is_gfid, gfid, ULP_MARK_INVALID); +} diff --git a/drivers/net/bnxt/tf_ulp/ulp_mark_mgr.h b/drivers/net/bnxt/tf_ulp/ulp_mark_mgr.h index 18abea4..f0d1515 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_mark_mgr.h +++ b/drivers/net/bnxt/tf_ulp/ulp_mark_mgr.h @@ -72,4 +72,22 @@ ulp_mark_db_mark_add(struct bnxt_ulp_context *ctxt, uint32_t gfid, uint32_t mark); +/* + * Removes a Mark from the Mark Manager + * + * ctxt [in] The ulp context for the mark manager + * + * is_gfid [in] The type of fid (GFID or LFID) + * + * fid [in] The flow id that is returned by HW in BD + * + * mark [in] The mark to be associated with the FID + * + */ +int32_t +ulp_mark_db_mark_del(struct bnxt_ulp_context *ctxt, + bool is_gfid, + uint32_t gfid, + uint32_t mark); + #endif /* _ULP_MARK_MGR_H_ */ -- 2.7.4