From: Farah Smith <[email protected]>
Track per-port table-scope teardown state (scope type and, for GLOBAL
scope, a shared FID reference count) and clean up in the correct
order on bnxt_en/DPDK shutdown.
Previously, unloading the L2 kernel driver with DPDK shutdown could
crash because table-scope resources were torn down without properly
tracking which FID was the last user of a GLOBAL scope. Fix this by
introducing glb_tbl_scope_fid_cnt bookkeeping and freeing the per-port
CPM before removing the FID from the scope, and only fully retiring
shared GLOBAL-scope memory once the reference count reaches zero.
The teardown order was initially fid_rem -> mem_free, but that
sequence was found to trigger PXP errors: fid_rem disables the scope
in firmware, so any subsequent mem_free on that scope is operating on
an already-disabled scope. Reordered to cpm_free -> fid_rem -> mem_free
so the scope is only disabled and its memory released after this
port's CPM is torn down, with fid_rem no longer preceding mem_free.
Fixes: 23e0dc62d19e ("net/bnxt/tf_core: add global table scope")
Cc: [email protected]
Signed-off-by: Farah Smith <[email protected]>
Signed-off-by: Kishore Padmanabha <[email protected]>
Signed-off-by: Manish Kurup <[email protected]>
---
drivers/net/bnxt/tf_ulp/bnxt_ulp.h | 3 +
drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c | 162 ++++++++++++++++++++++---
drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.h | 23 ++++
3 files changed, 172 insertions(+), 16 deletions(-)
diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp.h
b/drivers/net/bnxt/tf_ulp/bnxt_ulp.h
index afd883df2c..ba526e838d 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp.h
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp.h
@@ -15,6 +15,7 @@
#include "rte_mtr.h"
#include "bnxt.h"
+#include "cfa_types.h"
#include "ulp_template_db_enum.h"
#include "ulp_tun.h"
#include "bnxt_tf_common.h"
@@ -115,6 +116,8 @@ struct bnxt_ulp_vfr_rule_info {
struct bnxt_ulp_data {
uint32_t tbl_scope_id;
+ enum cfa_scope_type tbl_scope_type; /* for deinit */
+ uint16_t glb_tbl_scope_fid_cnt; /* only for
GLOBAL scope */
struct bnxt_ulp_mark_tbl *mark_tbl;
uint32_t dev_id; /* Hardware device id */
uint32_t ref_cnt;
diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
index d5ce4c3c18..dcd64fa598 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
@@ -111,6 +111,64 @@ bnxt_ulp_cntxt_tbl_scope_max_pools_set(struct
bnxt_ulp_context *ulp_ctx,
return 0;
}
+int32_t
+bnxt_ulp_cntxt_tbl_scope_type_get(struct bnxt_ulp_context *ulp_ctx,
+ enum cfa_scope_type *scope_type)
+{
+ if (ulp_ctx == NULL || ulp_ctx->cfg_data == NULL || scope_type == NULL)
+ return -EINVAL;
+ *scope_type = ulp_ctx->cfg_data->tbl_scope_type;
+ return 0;
+}
+
+int32_t
+bnxt_ulp_cntxt_tbl_scope_type_set(struct bnxt_ulp_context *ulp_ctx,
+ enum cfa_scope_type scope_type)
+{
+ if (ulp_ctx == NULL || ulp_ctx->cfg_data == NULL)
+ return -EINVAL;
+ ulp_ctx->cfg_data->tbl_scope_type = scope_type;
+ return 0;
+}
+
+uint16_t
+bnxt_ulp_cntxt_glb_tbl_scope_fid_cnt_get(struct bnxt_ulp_context *ulp_ctx)
+{
+ if (ulp_ctx == NULL || ulp_ctx->cfg_data == NULL)
+ return 0;
+ return ulp_ctx->cfg_data->glb_tbl_scope_fid_cnt;
+}
+
+int32_t
+bnxt_ulp_cntxt_glb_tbl_scope_fid_cnt_set(struct bnxt_ulp_context *ulp_ctx,
+ uint16_t fid_cnt)
+{
+ if (ulp_ctx == NULL || ulp_ctx->cfg_data == NULL)
+ return -EINVAL;
+ ulp_ctx->cfg_data->glb_tbl_scope_fid_cnt = fid_cnt;
+ return 0;
+}
+
+int32_t
+bnxt_ulp_cntxt_glb_tbl_scope_fid_cnt_inc(struct bnxt_ulp_context *ulp_ctx)
+{
+ if (ulp_ctx == NULL || ulp_ctx->cfg_data == NULL)
+ return -EINVAL;
+ ulp_ctx->cfg_data->glb_tbl_scope_fid_cnt++;
+ return 0;
+}
+
+int32_t
+bnxt_ulp_cntxt_glb_tbl_scope_fid_cnt_dec(struct bnxt_ulp_context *ulp_ctx)
+{
+ if (ulp_ctx == NULL || ulp_ctx->cfg_data == NULL)
+ return -EINVAL;
+ if (ulp_ctx->cfg_data->glb_tbl_scope_fid_cnt == 0)
+ return -EINVAL;
+ ulp_ctx->cfg_data->glb_tbl_scope_fid_cnt--;
+ return 0;
+}
+
enum tfc_tbl_scope_bucket_factor
bnxt_ulp_cntxt_em_mulitplier_get(struct bnxt_ulp_context *ulp_ctx)
{
@@ -299,39 +357,82 @@ ulp_tfc_dparms_init(struct bnxt *bp,
static void
ulp_tfc_tbl_scope_deinit(struct bnxt *bp)
{
- uint16_t fid = 0, fid_cnt = 0;
- struct tfc *tfcp;
+ uint16_t fid = 0;
+ uint16_t our_fid_cnt = 0;
+ struct tfc *tfcp = NULL;
uint8_t tsid = 0;
int32_t rc;
+ enum cfa_scope_type scope_type = CFA_SCOPE_TYPE_INVALID;
+ int32_t scope_rc;
+ bool have_scope = false;
tfcp = bnxt_ulp_cntxt_tfcp_get(bp->ulp_ctx);
if (tfcp == NULL)
- return;
+ goto cleanup;
rc = bnxt_ulp_cntxt_tsid_get(bp->ulp_ctx, &tsid);
- if (unlikely(rc))
- BNXT_DRV_DBG(ERR, "Failed to get the table scope\n");
+ if (rc) {
+ BNXT_DRV_DBG(ERR, "tsid_get failed rc=%d, skipping table-scope
deinit", rc);
+ goto cleanup;
+ }
rc = bnxt_ulp_cntxt_fid_get(bp->ulp_ctx, &fid);
- if (rc)
+ if (rc) {
+ BNXT_DRV_DBG(ERR, "fid_get failed rc=%d, skipping table-scope
deinit", rc);
+ goto cleanup;
+ }
+
+ have_scope = true;
+
+ if (bnxt_ulp_cntxt_acquire_fdb_lock(bp->ulp_ctx)) {
+ BNXT_DRV_DBG(ERR, "acquire_fdb_lock failed, proceeding with
teardown using conservative fid_cnt");
+ our_fid_cnt = 1; /* Conservative: avoid invalidating shared
scope in mem_free */
+ } else {
+ scope_rc = bnxt_ulp_cntxt_tbl_scope_type_get(bp->ulp_ctx,
&scope_type);
+ if (scope_rc) {
+ BNXT_DRV_DBG(ERR,
+ "tbl_scope_type_get failed rc=%d,
proceeding with teardown using conservative fid_cnt",
+ scope_rc);
+ our_fid_cnt = 1; /* avoid invalidating shared scope in
mem_free */
+ } else if (scope_type == CFA_SCOPE_TYPE_GLOBAL) {
+ rc =
bnxt_ulp_cntxt_glb_tbl_scope_fid_cnt_dec(bp->ulp_ctx);
+ if (rc) {
+ BNXT_DRV_DBG(WARNING,
+ "glb_tbl_scope_fid_cnt dec failed
(e.g. already 0), continuing teardown TSID:%d FID:%d",
+ tsid, fid);
+ /* Pass 1 so mem_free won't treat as last FID &
invalidate scope */
+ our_fid_cnt = 1;
+ } else {
+ our_fid_cnt =
bnxt_ulp_cntxt_glb_tbl_scope_fid_cnt_get(bp->ulp_ctx);
+ }
+ } else {
+ our_fid_cnt = 0;
+ }
+ bnxt_ulp_cntxt_release_fdb_lock(bp->ulp_ctx);
+ }
+
+cleanup:
+ if (!have_scope)
return;
- rc = tfc_tbl_scope_fid_rem(tfcp, fid, tsid, &fid_cnt);
+ /* Free this port's CPM before mem_free; mem_free invalidates tsid
scope state */
+ rc = tfc_tbl_scope_cpm_free(tfcp, tsid);
if (rc)
- BNXT_DRV_DBG(ERR, "Failed removing FID from TSID:%d FID:%d",
+ BNXT_DRV_DBG(ERR, "Failed Freeing CPM TSID:%d FID:%d",
tsid, fid);
else
- BNXT_DRV_DBG(DEBUG, "Removed FID from TSID:%d FID:%d",
- tsid, fid);
+ BNXT_DRV_DBG(DEBUG, "Freed CPM TSID:%d FID: %d", tsid, fid);
- rc = tfc_tbl_scope_cpm_free(tfcp, tsid);
+ rc = tfc_tbl_scope_fid_rem(tfcp, fid, tsid, NULL);
if (rc)
- BNXT_DRV_DBG(ERR, "Failed Freeing CPM TSID:%d FID:%d",
+ BNXT_DRV_DBG(ERR, "Failed removing FID from TSID:%d FID:%d",
tsid, fid);
else
- BNXT_DRV_DBG(DEBUG, "Freed CPM TSID:%d FID: %d", tsid, fid);
+ BNXT_DRV_DBG(DEBUG, "Removed FID from TSID:%d FID:%d, remaining
FID count:%d",
+ tsid, fid, our_fid_cnt);
- rc = tfc_tbl_scope_mem_free(tfcp, fid, tsid, fid_cnt);
+ /* Still attempt mem_free and fid_rem to avoid FW/driver state
divergence. */
+ rc = tfc_tbl_scope_mem_free(tfcp, fid, tsid, our_fid_cnt);
if (rc)
BNXT_DRV_DBG(ERR, "Failed freeing tscope mem TSID:%d FID:%d",
tsid, fid);
@@ -506,13 +607,42 @@ ulp_tfc_tbl_scope_init(struct bnxt *bp)
cparms.max_pools = max_pools;
rc = tfc_tbl_scope_cpm_alloc(tfcp, tsid, &cparms);
- if (rc)
+ if (rc) {
BNXT_DRV_DBG(ERR, "Failed to allocate CPM TSID:%d FID:%d\n",
tsid, fid);
- else
+ } else {
BNXT_DRV_DBG(DEBUG, "Allocated CPM TSID:%d FID:%d\n", tsid,
fid);
+ /* Inc before setting type so type==GLOBAL never without count
incremented. */
+ if (bnxt_ulp_cntxt_acquire_fdb_lock(bp->ulp_ctx)) {
+ BNXT_DRV_DBG(ERR, "acquire_fdb_lock failed after CPM
alloc, rolling back");
+ goto rollback;
+ }
+ if (scope_type == CFA_SCOPE_TYPE_GLOBAL) {
+ rc =
bnxt_ulp_cntxt_glb_tbl_scope_fid_cnt_inc(bp->ulp_ctx);
+ if (rc) {
+ BNXT_DRV_DBG(ERR, "Failed to increment
glb_tbl_scope_fid_cnt");
+ bnxt_ulp_cntxt_release_fdb_lock(bp->ulp_ctx);
+ return rc;
+ }
+ }
+ rc = bnxt_ulp_cntxt_tbl_scope_type_set(bp->ulp_ctx, scope_type);
+ bnxt_ulp_cntxt_release_fdb_lock(bp->ulp_ctx);
+ }
return rc;
+
+rollback:
+ /* Rollback: only FID in scope (glb_tbl_scope_fid_cnt_inc never ran). */
+ rc = tfc_tbl_scope_cpm_free(tfcp, tsid);
+ if (rc)
+ BNXT_DRV_DBG(INFO, "Rollback: cpm_free failed TSID:%d FID:%d
rc=%d", tsid, fid, rc);
+ rc = tfc_tbl_scope_mem_free(tfcp, fid, tsid, 0);
+ if (rc)
+ BNXT_DRV_DBG(INFO, "Rollback: mem_free failed TSID:%d FID:%d
rc=%d", tsid, fid, rc);
+ rc = tfc_tbl_scope_fid_rem(tfcp, fid, tsid, NULL);
+ if (rc)
+ BNXT_DRV_DBG(INFO, "Rollback: fid_rem failed TSID:%d FID:%d
rc=%d", tsid, fid, rc);
+ return -1;
}
static int32_t
diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.h
b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.h
index ab6608ac74..2b73043ab8 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.h
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.h
@@ -7,6 +7,7 @@
#define _BNXT_ULP_TFC_H_
#include "bnxt.h"
+#include "cfa_types.h"
#include <inttypes.h>
bool
@@ -24,6 +25,28 @@ bnxt_ulp_cntxt_tbl_scope_max_pools_get(struct
bnxt_ulp_context *ulp_ctx);
int32_t
bnxt_ulp_cntxt_tbl_scope_max_pools_set(struct bnxt_ulp_context *ulp_ctx,
uint32_t max);
+
+int32_t
+bnxt_ulp_cntxt_tbl_scope_type_get(struct bnxt_ulp_context *ulp_ctx,
+ enum cfa_scope_type *scope_type);
+
+int32_t
+bnxt_ulp_cntxt_tbl_scope_type_set(struct bnxt_ulp_context *ulp_ctx,
+ enum cfa_scope_type scope_type);
+
+uint16_t
+bnxt_ulp_cntxt_glb_tbl_scope_fid_cnt_get(struct bnxt_ulp_context *ulp_ctx);
+
+int32_t
+bnxt_ulp_cntxt_glb_tbl_scope_fid_cnt_set(struct bnxt_ulp_context *ulp_ctx,
+ uint16_t fid_cnt);
+
+int32_t
+bnxt_ulp_cntxt_glb_tbl_scope_fid_cnt_inc(struct bnxt_ulp_context *ulp_ctx);
+
+int32_t
+bnxt_ulp_cntxt_glb_tbl_scope_fid_cnt_dec(struct bnxt_ulp_context *ulp_ctx);
+
enum tfc_tbl_scope_bucket_factor
bnxt_ulp_cntxt_em_mulitplier_get(struct bnxt_ulp_context *ulp_ctx);
--
2.31.1