[09/13] net/bnxt: add support for parent child flow database

Message ID 20201009111130.10422-10-somnath.kotur@broadcom.com (mailing list archive)
State Superseded, archived
Delegated to: Ajit Khaparde
Headers
Series bnxt patches |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Somnath Kotur Oct. 9, 2020, 11:11 a.m. UTC
  From: Kishore Padmanabha <kishore.padmanabha@broadcom.com>

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 <kishore.padmanabha@broadcom.com>
Reviewed-by: Michael Baucom <michael.baucom@broadcom.com>
---
 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(-)
  

Patch

diff --git a/drivers/net/bnxt/tf_ulp/ulp_flow_db.c b/drivers/net/bnxt/tf_ulp/ulp_flow_db.c
index da01245..a1c3932 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;
@@ -285,6 +288,86 @@  ulp_flow_db_func_id_set(struct bnxt_ulp_flow_db *flow_db,
 }
 
 /*
+ * 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 7ec4b8a..87bcd69 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 4904a41..a677b0c 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 50a986c..2e94b6f 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 c054a77..898e851 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)])