From 05a11d7dff9f1c6371ea2a5c697b7797272cb4e5 Mon Sep 17 00:00:00 2001 From: Mike Baucom Date: Wed, 15 Apr 2020 13:48:58 +0530 Subject: [PATCH] net/bnxt: support freeing key and action tables 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 Signed-off-by: Kishore Padmanabha Signed-off-by: Venkat Duvvuru Reviewed-by: Lance Richardson Reviewed-by: Ajit Khaparde --- 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 | 13 ++ drivers/net/bnxt/tf_ulp/ulp_mark_mgr.c | 23 ++- drivers/net/bnxt/tf_ulp/ulp_mark_mgr.h | 18 +++ 6 files changed, 474 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 6e73f25042..eecee6bcd8 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_flow_db.c +++ b/drivers/net/bnxt/tf_ulp/ulp_flow_db.c @@ -22,6 +22,32 @@ ULP_FLOW_DB_RES_NXT_MASK); } #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. @@ -70,6 +96,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 >= 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 >= 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 f6055a56b9..20109b9880 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 31664871ba..1c550b941b 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, @@ -1142,3 +1223,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 = 0; + + 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 2221e12327..8655728813 100644 --- a/drivers/net/bnxt/tf_ulp/ulp_mapper.h +++ b/drivers/net/bnxt/tf_ulp/ulp_mapper.h @@ -38,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 837064eac3..566668eece 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 18abea4693..f0d1515790 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.20.1