DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH v1 0/2] add support for flow aging in CNXK driver
@ 2023-07-27 11:59 Ankur Dwivedi
  2023-07-27 11:59 ` [PATCH v1 1/2] common/cnxk: add support to get aged flows Ankur Dwivedi
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Ankur Dwivedi @ 2023-07-27 11:59 UTC (permalink / raw)
  To: dev; +Cc: jerinj, ndabilpuram, kirankumark, skori, skoteshwar, Ankur Dwivedi

Adds support for flow aging in CNXK driver.
This patch series is for DPDK 23.11.

Ankur Dwivedi (2):
  common/cnxk: add support to get aged flows
  net/cnxk: add get flow aged ops

 doc/guides/nics/cnxk.rst               |  12 +
 doc/guides/nics/features/cnxk.ini      |   1 +
 doc/guides/nics/features/cnxk_vf.ini   |   1 +
 drivers/common/cnxk/meson.build        |   1 +
 drivers/common/cnxk/roc_mbox.h         |  27 +++
 drivers/common/cnxk/roc_npc.c          |  22 ++
 drivers/common/cnxk/roc_npc.h          |  28 +++
 drivers/common/cnxk/roc_npc_aging.c    | 315 +++++++++++++++++++++++++
 drivers/common/cnxk/roc_npc_priv.h     |  17 ++
 drivers/common/cnxk/roc_platform.h     |   8 +
 drivers/common/cnxk/version.map        |   1 +
 drivers/net/cnxk/cnxk_ethdev_devargs.c |  21 +-
 drivers/net/cnxk/cnxk_flow.c           |  45 ++++
 13 files changed, 498 insertions(+), 1 deletion(-)
 create mode 100644 drivers/common/cnxk/roc_npc_aging.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 1/2] common/cnxk: add support to get aged flows
  2023-07-27 11:59 [PATCH v1 0/2] add support for flow aging in CNXK driver Ankur Dwivedi
@ 2023-07-27 11:59 ` Ankur Dwivedi
  2023-07-27 11:59 ` [PATCH v1 2/2] net/cnxk: add get flow aged ops Ankur Dwivedi
  2023-08-08  8:49 ` [PATCH v2 0/2] add support for flow aging in CNXK driver Ankur Dwivedi
  2 siblings, 0 replies; 9+ messages in thread
From: Ankur Dwivedi @ 2023-07-27 11:59 UTC (permalink / raw)
  To: dev; +Cc: jerinj, ndabilpuram, kirankumark, skori, skoteshwar, Ankur Dwivedi

Adds support to get aged flows in CNXK driver.
The control thread polls the status of flows having age action, every 10
seconds and updates a bitmap array with the aged flows. The poll frequency
of control thread can be set by devargs.

Signed-off-by: Ankur Dwivedi <adwivedi@marvell.com>
---
 drivers/common/cnxk/meson.build     |   1 +
 drivers/common/cnxk/roc_mbox.h      |  27 +++
 drivers/common/cnxk/roc_npc.c       |  22 ++
 drivers/common/cnxk/roc_npc.h       |  28 +++
 drivers/common/cnxk/roc_npc_aging.c | 315 ++++++++++++++++++++++++++++
 drivers/common/cnxk/roc_npc_priv.h  |  17 ++
 drivers/common/cnxk/roc_platform.h  |   8 +
 drivers/common/cnxk/version.map     |   1 +
 8 files changed, 419 insertions(+)
 create mode 100644 drivers/common/cnxk/roc_npc_aging.c

diff --git a/drivers/common/cnxk/meson.build b/drivers/common/cnxk/meson.build
index 79e10bac74..d5dfd93e31 100644
--- a/drivers/common/cnxk/meson.build
+++ b/drivers/common/cnxk/meson.build
@@ -57,6 +57,7 @@ sources = files(
         'roc_npa_irq.c',
         'roc_npa_type.c',
         'roc_npc.c',
+        'roc_npc_aging.c',
         'roc_npc_mcam.c',
         'roc_npc_mcam_dump.c',
         'roc_npc_parse.c',
diff --git a/drivers/common/cnxk/roc_mbox.h b/drivers/common/cnxk/roc_mbox.h
index 2f85b2f755..6db46a86f4 100644
--- a/drivers/common/cnxk/roc_mbox.h
+++ b/drivers/common/cnxk/roc_mbox.h
@@ -227,6 +227,8 @@ struct mbox_msghdr {
 	  npc_mcam_get_stats_req, npc_mcam_get_stats_rsp)                      \
 	M(NPC_GET_FIELD_HASH_INFO, 0x6013, npc_get_field_hash_info,            \
 	  npc_get_field_hash_info_req, npc_get_field_hash_info_rsp)            \
+	M(NPC_MCAM_GET_HIT_STATUS, 0x6015, npc_mcam_get_hit_status,            \
+	  npc_mcam_get_hit_status_req, npc_mcam_get_hit_status_rsp)            \
 	/* NIX mbox IDs (range 0x8000 - 0xFFFF) */                             \
 	M(NIX_LF_ALLOC, 0x8000, nix_lf_alloc, nix_lf_alloc_req,                \
 	  nix_lf_alloc_rsp)                                                    \
@@ -2466,6 +2468,31 @@ struct npc_mcam_get_stats_rsp {
 	uint8_t __io stat_ena; /* enabled */
 };
 
+#define MCAM_ARR_SIZE    256
+#define MCAM_ARR_ELEM_SZ 64
+
+struct npc_mcam_get_hit_status_req {
+	struct mbox_msghdr hdr;
+	/* If clear == true, then if the hit status bit for mcam id is set,
+	 * then needs to cleared by writing 1 back.
+	 * If clear == false, then leave the hit status bit as is.
+	 */
+	bool __io clear;
+	uint8_t __io reserved[3];
+	/* Start range of mcam id */
+	uint32_t __io range_valid_mcam_ids_start;
+	/* End range of mcam id */
+	uint32_t __io range_valid_mcam_ids_end;
+	/* Bitmap of mcam ids for which the hit status needs to checked */
+	uint64_t __io mcam_ids[MCAM_ARR_SIZE];
+};
+
+struct npc_mcam_get_hit_status_rsp {
+	struct mbox_msghdr hdr;
+	/* Bitmap of mcam hit status, prior to clearing */
+	uint64_t __io mcam_hit_status[MCAM_ARR_SIZE];
+};
+
 /* TIM mailbox error codes
  * Range 801 - 900.
  */
diff --git a/drivers/common/cnxk/roc_npc.c b/drivers/common/cnxk/roc_npc.c
index 848086c8de..f0bb0aa931 100644
--- a/drivers/common/cnxk/roc_npc.c
+++ b/drivers/common/cnxk/roc_npc.c
@@ -302,6 +302,7 @@ roc_npc_init(struct roc_npc *roc_npc)
 	npc_mem = mem;
 
 	TAILQ_INIT(&npc->ipsec_list);
+	TAILQ_INIT(&npc->age_flow_list);
 	for (idx = 0; idx < npc->flow_max_priority; idx++) {
 		TAILQ_INIT(&npc->flow_list[idx]);
 		TAILQ_INIT(&npc->prio_flow_list[idx]);
@@ -330,6 +331,9 @@ roc_npc_init(struct roc_npc *roc_npc)
 	 */
 	plt_bitmap_set(npc->rss_grp_entries, 0);
 
+	rc = npc_aged_flows_bitmap_alloc(roc_npc);
+	if (rc != 0)
+		goto done;
 	return rc;
 
 done:
@@ -610,6 +614,17 @@ npc_parse_actions(struct roc_npc *roc_npc, const struct roc_npc_attr *attr,
 			flow->mtr_id = act_mtr->mtr_id;
 			req_act |= ROC_NPC_ACTION_TYPE_METER;
 			break;
+		case ROC_NPC_ACTION_TYPE_AGE:
+			if (flow->is_validate == true)
+				break;
+			plt_seqcount_init(&roc_npc->flow_age.seq_cnt);
+			errcode = npc_aging_ctrl_thread_create(roc_npc,
+							       actions->conf,
+							       flow);
+			if (errcode != 0)
+				goto err_exit;
+			req_act |= ROC_NPC_ACTION_TYPE_AGE;
+			break;
 		default:
 			errcode = NPC_ERR_ACTION_NOTSUP;
 			goto err_exit;
@@ -1485,6 +1500,9 @@ roc_npc_flow_create(struct roc_npc *roc_npc, const struct roc_npc_attr *attr,
 		}
 	}
 	TAILQ_INSERT_TAIL(list, flow, next);
+
+	npc_age_flow_list_entry_add(roc_npc, flow);
+
 	return flow;
 
 set_rss_failed:
@@ -1582,6 +1600,10 @@ roc_npc_flow_destroy(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
 
 	npc_delete_prio_list_entry(npc, flow);
 
+	npc_age_flow_list_entry_delete(roc_npc, flow);
+	if (roc_npc->flow_age.age_flow_refcnt == 0 && roc_npc->flow_age.aged_flows_poll_thread)
+		npc_aging_ctrl_thread_destroy(roc_npc);
+
 done:
 	plt_free(flow);
 	return 0;
diff --git a/drivers/common/cnxk/roc_npc.h b/drivers/common/cnxk/roc_npc.h
index 07e6634aa7..8b8a2eb343 100644
--- a/drivers/common/cnxk/roc_npc.h
+++ b/drivers/common/cnxk/roc_npc.h
@@ -180,6 +180,7 @@ enum roc_npc_action_type {
 	ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT = (1 << 15),
 	ROC_NPC_ACTION_TYPE_PORT_ID = (1 << 16),
 	ROC_NPC_ACTION_TYPE_METER = (1 << 17),
+	ROC_NPC_ACTION_TYPE_AGE = (1 << 18),
 };
 
 struct roc_npc_action {
@@ -203,6 +204,13 @@ struct roc_npc_action_port_id {
 	uint32_t id;		/**< port ID. */
 };
 
+struct roc_npc_action_age {
+	uint32_t timeout : 24; /**< Time in seconds. */
+	uint32_t reserved : 8; /**< Reserved, must be zero. */
+	/** The user flow context, NULL means the rte_flow pointer. */
+	void *context;
+};
+
 /**
  * ESP Header
  */
@@ -295,6 +303,9 @@ struct roc_npc_flow {
 	uint16_t match_id;
 	uint8_t is_inline_dev;
 	bool use_pre_alloc;
+	uint64_t timeout_cycles;
+	void *age_context;
+	uint32_t timeout;
 
 	TAILQ_ENTRY(roc_npc_flow) next;
 };
@@ -327,6 +338,19 @@ enum flow_vtag_cfg_dir { VTAG_TX, VTAG_RX };
 #define ROC_ETHER_TYPE_VLAN 0x8100 /**< IEEE 802.1Q VLAN tagging. */
 #define ROC_ETHER_TYPE_QINQ 0x88A8 /**< IEEE 802.1ad QinQ tagging. */
 
+struct roc_npc_flow_age {
+	plt_seqcount_t seq_cnt;
+	uint32_t aging_poll_freq;
+	uint32_t age_flow_refcnt;
+	uint32_t aged_flows_cnt;
+	uint32_t start_id;
+	uint32_t end_id;
+	pthread_t aged_flows_poll_thread;
+	struct plt_bitmap *aged_flows;
+	void *age_mem;
+	bool aged_flows_get_thread_exit;
+};
+
 struct roc_npc {
 	struct roc_nix *roc_nix;
 	uint8_t switch_header_type;
@@ -349,11 +373,14 @@ struct roc_npc {
 	bool is_sdp_mask_set;
 	uint16_t sdp_channel;
 	uint16_t sdp_channel_mask;
+	struct roc_npc_flow_age flow_age;
 
 #define ROC_NPC_MEM_SZ (6 * 1024)
 	uint8_t reserved[ROC_NPC_MEM_SZ];
 } __plt_cache_aligned;
 
+#define ROC_NPC_AGE_POLL_FREQ_MIN 10
+
 int __roc_api roc_npc_init(struct roc_npc *roc_npc);
 int __roc_api roc_npc_fini(struct roc_npc *roc_npc);
 const char *__roc_api roc_npc_profile_name_get(struct roc_npc *roc_npc);
@@ -397,4 +424,5 @@ int __roc_api roc_npc_validate_portid_action(struct roc_npc *roc_npc_src,
 					     struct roc_npc *roc_npc_dst);
 int __roc_api roc_npc_mcam_init(struct roc_npc *roc_npc, struct roc_npc_flow *flow, int mcam_id);
 int __roc_api roc_npc_mcam_move(struct roc_npc *roc_npc, uint16_t old_ent, uint16_t new_ent);
+void *__roc_api roc_npc_aged_flow_ctx_get(struct roc_npc *roc_npc, uint32_t mcam_id);
 #endif /* _ROC_NPC_H_ */
diff --git a/drivers/common/cnxk/roc_npc_aging.c b/drivers/common/cnxk/roc_npc_aging.c
new file mode 100644
index 0000000000..94126fe9fd
--- /dev/null
+++ b/drivers/common/cnxk/roc_npc_aging.c
@@ -0,0 +1,315 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include "roc_api.h"
+#include "roc_priv.h"
+
+int
+npc_aged_flows_bitmap_alloc(struct roc_npc *roc_npc)
+{
+	struct roc_npc_flow_age *flow_age;
+	uint8_t *age_mem = NULL;
+	uint32_t bmap_sz;
+	int rc = 0;
+
+	bmap_sz = plt_bitmap_get_memory_footprint(MCAM_ARR_ELEM_SZ *
+						  MCAM_ARR_SIZE);
+	age_mem = plt_zmalloc(bmap_sz, 0);
+	if (age_mem == NULL) {
+		plt_err("Bmap alloc failed");
+		rc = NPC_ERR_NO_MEM;
+		goto done;
+	}
+
+	flow_age = &roc_npc->flow_age;
+	flow_age->age_mem = age_mem;
+	flow_age->aged_flows = plt_bitmap_init(MCAM_ARR_ELEM_SZ * MCAM_ARR_SIZE,
+					       age_mem, bmap_sz);
+	if (!flow_age->aged_flows) {
+		plt_err("Bitmap init failed");
+		plt_free(age_mem);
+		rc = NPC_ERR_NO_MEM;
+		goto done;
+	}
+
+	flow_age->age_flow_refcnt = 0;
+done:
+	return rc;
+}
+
+void
+npc_aged_flows_bitmap_free(struct roc_npc *roc_npc)
+{
+	struct roc_npc_flow_age *flow_age;
+
+	flow_age = &roc_npc->flow_age;
+	plt_bitmap_free(flow_age->aged_flows);
+	if (flow_age->age_mem)
+		plt_free(roc_npc->flow_age.age_mem);
+}
+
+static void
+check_timeout_cycles(struct roc_npc *roc_npc, uint32_t mcam_id)
+{
+	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+	struct npc_age_flow_list_head *list;
+	struct npc_age_flow_entry *fl_iter;
+	struct roc_npc_flow_age *flow_age;
+	bool aging_enabled = false;
+
+	flow_age = &roc_npc->flow_age;
+	list = &npc->age_flow_list;
+	TAILQ_FOREACH(fl_iter, list, next) {
+		if (fl_iter->flow->mcam_id == mcam_id &&
+		    fl_iter->flow->timeout_cycles < rte_get_timer_cycles()) {
+			/* update bitmap */
+			plt_bitmap_set(flow_age->aged_flows, mcam_id);
+			if (!aging_enabled) {
+				flow_age->start_id = mcam_id;
+				flow_age->end_id = mcam_id;
+				aging_enabled = true;
+			}
+			if (flow_age->start_id > mcam_id)
+				flow_age->start_id = mcam_id;
+			else if (flow_age->end_id < mcam_id)
+				flow_age->end_id = mcam_id;
+			flow_age->aged_flows_cnt += 1;
+			break;
+		}
+	}
+}
+
+static void
+update_timeout_cycles(struct roc_npc *roc_npc, uint32_t mcam_id)
+{
+	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+	struct npc_age_flow_list_head *list;
+	struct npc_age_flow_entry *fl_iter;
+
+	list = &npc->age_flow_list;
+	TAILQ_FOREACH(fl_iter, list, next) {
+		if (fl_iter->flow->mcam_id == mcam_id) {
+			fl_iter->flow->timeout_cycles = rte_get_timer_cycles() +
+				fl_iter->flow->timeout * rte_get_timer_hz();
+			break;
+		}
+	}
+}
+
+static int
+npc_mcam_get_hit_status(struct npc *npc, uint64_t *mcam_ids, uint16_t start_id,
+			uint16_t end_id, uint64_t *hit_status, bool clear)
+{
+	struct npc_mcam_get_hit_status_req *req;
+	struct npc_mcam_get_hit_status_rsp *rsp;
+	struct mbox *mbox = mbox_get(npc->mbox);
+	uint8_t idx_start;
+	uint8_t idx_end;
+	int rc;
+	int i;
+
+	req = mbox_alloc_msg_npc_mcam_get_hit_status(mbox);
+	if (req == NULL)
+		return -ENOSPC;
+
+	idx_start = start_id / MCAM_ARR_ELEM_SZ;
+	idx_end = end_id / MCAM_ARR_ELEM_SZ;
+
+	for (i = idx_start; i <= idx_end; i++)
+		req->mcam_ids[i] = mcam_ids[i];
+
+	req->range_valid_mcam_ids_start = start_id;
+	req->range_valid_mcam_ids_end = end_id;
+	req->clear = clear;
+
+	rc = mbox_process_msg(mbox, (void *)&rsp);
+	if (rc)
+		goto exit;
+
+	for (i = idx_start; i <= idx_end; i++)
+		hit_status[i] = rsp->mcam_hit_status[i];
+
+	rc = 0;
+exit:
+	mbox_put(mbox);
+	return rc;
+}
+
+void *
+npc_aged_flows_get(void *args)
+{
+	uint64_t hit_status[MCAM_ARR_SIZE] = {0};
+	uint64_t mcam_ids[MCAM_ARR_SIZE] = {0};
+	struct npc_age_flow_list_head *list;
+	struct npc_age_flow_entry *fl_iter;
+	struct roc_npc *roc_npc = args;
+	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+	struct roc_npc_flow_age *flow_age;
+	bool aging_enabled;
+	uint32_t start_id;
+	uint32_t end_id;
+	uint32_t mcam_id;
+	uint32_t idx;
+	uint32_t i;
+	int rc;
+
+	flow_age = &roc_npc->flow_age;
+	list = &npc->age_flow_list;
+	while (!flow_age->aged_flows_get_thread_exit) {
+		start_id = 0;
+		end_id = 0;
+		aging_enabled = false;
+		memset(mcam_ids, 0, sizeof(mcam_ids));
+		TAILQ_FOREACH(fl_iter, list, next) {
+			mcam_id = fl_iter->flow->mcam_id;
+			idx = mcam_id / MCAM_ARR_ELEM_SZ;
+			mcam_ids[idx] |= BIT_ULL(mcam_id % MCAM_ARR_ELEM_SZ);
+
+			if (!aging_enabled) {
+				start_id = mcam_id;
+				end_id = mcam_id;
+				aging_enabled = true;
+			}
+
+			if (mcam_id < start_id)
+				start_id = mcam_id;
+			else if (mcam_id > end_id)
+				end_id = mcam_id;
+		}
+
+		if (!aging_enabled)
+			goto lbl_sleep;
+
+		rc = npc_mcam_get_hit_status(npc, mcam_ids, start_id, end_id,
+					     hit_status, true);
+		if (rc)
+			return NULL;
+
+		plt_seqcount_write_begin(&flow_age->seq_cnt);
+		flow_age->aged_flows_cnt = 0;
+		for (i = start_id; i <= end_id; i++) {
+			idx = i / MCAM_ARR_ELEM_SZ;
+			if (mcam_ids[idx] & BIT_ULL(i % MCAM_ARR_ELEM_SZ)) {
+				if (!(hit_status[idx] & BIT_ULL(i % MCAM_ARR_ELEM_SZ)))
+					check_timeout_cycles(roc_npc, i);
+				else
+					update_timeout_cycles(roc_npc, i);
+			}
+		}
+		plt_seqcount_write_end(&flow_age->seq_cnt);
+
+lbl_sleep:
+		sleep(flow_age->aging_poll_freq);
+	}
+
+	return NULL;
+}
+
+void
+npc_age_flow_list_entry_add(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
+{
+	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+	struct npc_age_flow_entry *age_fl_iter;
+	struct npc_age_flow_entry *new_entry;
+
+	new_entry = plt_zmalloc(sizeof(*new_entry), 0);
+	new_entry->flow = flow;
+	roc_npc->flow_age.age_flow_refcnt++;
+	/* List in ascending order of mcam entries */
+	TAILQ_FOREACH(age_fl_iter, &npc->age_flow_list, next) {
+		if (age_fl_iter->flow->mcam_id > flow->mcam_id) {
+			TAILQ_INSERT_BEFORE(age_fl_iter, new_entry, next);
+			return;
+		}
+	}
+	TAILQ_INSERT_TAIL(&npc->age_flow_list, new_entry, next);
+}
+
+void
+npc_age_flow_list_entry_delete(struct roc_npc *roc_npc,
+			       struct roc_npc_flow *flow)
+{
+	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+	struct npc_age_flow_list_head *list;
+	struct npc_age_flow_entry *curr;
+
+	list = &npc->age_flow_list;
+	curr = TAILQ_FIRST(list);
+
+	if (!curr)
+		return;
+
+	while (curr) {
+		if (flow->mcam_id == curr->flow->mcam_id) {
+			TAILQ_REMOVE(list, curr, next);
+			plt_free(curr);
+			break;
+		}
+		curr = TAILQ_NEXT(curr, next);
+	}
+	roc_npc->flow_age.age_flow_refcnt--;
+}
+
+int
+npc_aging_ctrl_thread_create(struct roc_npc *roc_npc,
+			     const struct roc_npc_action_age *age,
+			     struct roc_npc_flow *flow)
+{
+	struct roc_npc_flow_age *flow_age;
+	int errcode = 0;
+
+	flow_age = &roc_npc->flow_age;
+	if (age->timeout < flow_age->aging_poll_freq) {
+		plt_err("Age timeout should be greater or equal to %u seconds",
+			flow_age->aging_poll_freq);
+		errcode = NPC_ERR_ACTION_NOTSUP;
+		goto done;
+	}
+
+	flow->age_context = age->context == NULL ? flow : age->context;
+	flow->timeout = age->timeout;
+	flow->timeout_cycles = rte_get_timer_cycles() + age->timeout *
+			       rte_get_timer_hz();
+
+	if (flow_age->age_flow_refcnt == 0) {
+		flow_age->aged_flows_get_thread_exit = false;
+		if (plt_ctrl_thread_create(&flow_age->aged_flows_poll_thread,
+					   "Aged Flows Get Ctrl Thread", NULL,
+					   npc_aged_flows_get, roc_npc) != 0) {
+			plt_err("Failed to create thread for age flows");
+			errcode = NPC_ERR_ACTION_NOTSUP;
+			goto done;
+		}
+	}
+done:
+	return errcode;
+}
+
+void
+npc_aging_ctrl_thread_destroy(struct roc_npc *roc_npc)
+{
+	struct roc_npc_flow_age *flow_age;
+
+	flow_age = &roc_npc->flow_age;
+	flow_age->aged_flows_get_thread_exit = true;
+	pthread_join(flow_age->aged_flows_poll_thread, NULL);
+	npc_aged_flows_bitmap_free(roc_npc);
+}
+
+void *
+roc_npc_aged_flow_ctx_get(struct roc_npc *roc_npc, uint32_t mcam_id)
+{
+	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+	struct npc_age_flow_list_head *list;
+	struct npc_age_flow_entry *fl_iter;
+
+	list = &npc->age_flow_list;
+
+	TAILQ_FOREACH(fl_iter, list, next) {
+		if (fl_iter->flow->mcam_id == mcam_id)
+			return fl_iter->flow->age_context;
+	}
+
+	return NULL;
+}
diff --git a/drivers/common/cnxk/roc_npc_priv.h b/drivers/common/cnxk/roc_npc_priv.h
index 593dca353b..6d6cb64c65 100644
--- a/drivers/common/cnxk/roc_npc_priv.h
+++ b/drivers/common/cnxk/roc_npc_priv.h
@@ -378,6 +378,13 @@ struct npc_prio_flow_entry {
 
 TAILQ_HEAD(npc_prio_flow_list_head, npc_prio_flow_entry);
 
+struct npc_age_flow_entry {
+	struct roc_npc_flow *flow;
+	TAILQ_ENTRY(npc_age_flow_entry) next;
+};
+
+TAILQ_HEAD(npc_age_flow_list_head, npc_age_flow_entry);
+
 struct npc {
 	struct mbox *mbox;			/* Mbox */
 	uint32_t keyx_supp_nmask[NPC_MAX_INTF]; /* nibble mask */
@@ -403,6 +410,7 @@ struct npc {
 	npc_ld_flags_t prx_lfcfg;    /* KEX LD_Flags CFG */
 	struct npc_flow_list *flow_list;
 	struct npc_prio_flow_list_head *prio_flow_list;
+	struct npc_age_flow_list_head age_flow_list;
 	struct plt_bitmap *rss_grp_entries;
 	struct npc_flow_list ipsec_list;
 	uint8_t exact_match_ena;
@@ -480,4 +488,13 @@ int npc_rss_action_program(struct roc_npc *roc_npc, const struct roc_npc_action
 int npc_rss_group_free(struct npc *npc, struct roc_npc_flow *flow);
 int npc_mcam_init(struct npc *npc, struct roc_npc_flow *flow, int mcam_id);
 int npc_mcam_move(struct mbox *mbox, uint16_t old_ent, uint16_t new_ent);
+void npc_age_flow_list_entry_add(struct roc_npc *npc, struct roc_npc_flow *flow);
+void npc_age_flow_list_entry_delete(struct roc_npc *npc, struct roc_npc_flow *flow);
+void *npc_aged_flows_get(void *args);
+int npc_aged_flows_bitmap_alloc(struct roc_npc *roc_npc);
+void npc_aged_flows_bitmap_free(struct roc_npc *roc_npc);
+int npc_aging_ctrl_thread_create(struct roc_npc *roc_npc,
+				 const struct roc_npc_action_age *age,
+				 struct roc_npc_flow *flow);
+void npc_aging_ctrl_thread_destroy(struct roc_npc *roc_npc);
 #endif /* _ROC_NPC_PRIV_H_ */
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index 9884398a99..e7a6564163 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -20,6 +20,7 @@
 #include <rte_malloc.h>
 #include <rte_memzone.h>
 #include <rte_pci.h>
+#include <rte_seqcount.h>
 #include <rte_spinlock.h>
 #include <rte_string_fns.h>
 #include <rte_tailq.h>
@@ -130,6 +131,13 @@
 #define plt_spinlock_unlock  rte_spinlock_unlock
 #define plt_spinlock_trylock rte_spinlock_trylock
 
+#define plt_seqcount_t			rte_seqcount_t
+#define plt_seqcount_init		rte_seqcount_init
+#define plt_seqcount_read_begin		rte_seqcount_read_begin
+#define plt_seqcount_read_retry		rte_seqcount_read_retry
+#define plt_seqcount_write_begin	rte_seqcount_write_begin
+#define plt_seqcount_write_end		rte_seqcount_write_end
+
 #define plt_intr_callback_register   rte_intr_callback_register
 #define plt_intr_callback_unregister rte_intr_callback_unregister
 #define plt_intr_disable	     rte_intr_disable
diff --git a/drivers/common/cnxk/version.map b/drivers/common/cnxk/version.map
index 8c71497df8..28f0f55934 100644
--- a/drivers/common/cnxk/version.map
+++ b/drivers/common/cnxk/version.map
@@ -425,6 +425,7 @@ INTERNAL {
 	roc_npa_pool_op_range_set;
 	roc_npa_pool_range_update_check;
 	roc_npa_zero_aura_handle;
+	roc_npc_aged_flow_ctx_get;
 	roc_npc_fini;
 	roc_npc_flow_create;
 	roc_npc_flow_destroy;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 2/2] net/cnxk: add get flow aged ops
  2023-07-27 11:59 [PATCH v1 0/2] add support for flow aging in CNXK driver Ankur Dwivedi
  2023-07-27 11:59 ` [PATCH v1 1/2] common/cnxk: add support to get aged flows Ankur Dwivedi
@ 2023-07-27 11:59 ` Ankur Dwivedi
  2023-08-08  8:49 ` [PATCH v2 0/2] add support for flow aging in CNXK driver Ankur Dwivedi
  2 siblings, 0 replies; 9+ messages in thread
From: Ankur Dwivedi @ 2023-07-27 11:59 UTC (permalink / raw)
  To: dev; +Cc: jerinj, ndabilpuram, kirankumark, skori, skoteshwar, Ankur Dwivedi

Adds get flow aged ops in CNXK driver. Also adds the devargs to get the
poll frequency of control thread.

Signed-off-by: Ankur Dwivedi <adwivedi@marvell.com>
---
 doc/guides/nics/cnxk.rst               | 12 +++++++
 doc/guides/nics/features/cnxk.ini      |  1 +
 doc/guides/nics/features/cnxk_vf.ini   |  1 +
 drivers/net/cnxk/cnxk_ethdev_devargs.c | 21 +++++++++++-
 drivers/net/cnxk/cnxk_flow.c           | 45 ++++++++++++++++++++++++++
 5 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/cnxk.rst b/doc/guides/nics/cnxk.rst
index 9229056f6f..dc71ab7fc3 100644
--- a/doc/guides/nics/cnxk.rst
+++ b/doc/guides/nics/cnxk.rst
@@ -581,6 +581,18 @@ Runtime Config Options for inline device
    With the above configuration, driver would poll for soft expiry events every
    1000 usec.
 
+- ``NPC MCAM Aging poll frequency in seconds`` (default ``10``)
+
+   Poll frequency for aging control thread can be specified by
+   ``aging_poll_freq`` ``devargs`` parameter.
+
+   For example::
+
+      -a 0002:01:00.2,aging_poll_freq=50
+
+   With the above configuration, driver would poll for aging flows every 50
+   seconds.
+
 Debugging Options
 -----------------
 
diff --git a/doc/guides/nics/features/cnxk.ini b/doc/guides/nics/features/cnxk.ini
index 838e781d6d..ebedbd0588 100644
--- a/doc/guides/nics/features/cnxk.ini
+++ b/doc/guides/nics/features/cnxk.ini
@@ -80,6 +80,7 @@ vxlan                = Y
 vxlan_gpe            = Y
 
 [rte_flow actions]
+age                  = Y
 count                = Y
 drop                 = Y
 flag                 = Y
diff --git a/doc/guides/nics/features/cnxk_vf.ini b/doc/guides/nics/features/cnxk_vf.ini
index 470c45ce59..0e9ad94382 100644
--- a/doc/guides/nics/features/cnxk_vf.ini
+++ b/doc/guides/nics/features/cnxk_vf.ini
@@ -71,6 +71,7 @@ vxlan                = Y
 vxlan_gpe            = Y
 
 [rte_flow actions]
+age                  = Y
 count                = Y
 drop                 = Y
 flag                 = Y
diff --git a/drivers/net/cnxk/cnxk_ethdev_devargs.c b/drivers/net/cnxk/cnxk_ethdev_devargs.c
index e1a0845ece..8e862be933 100644
--- a/drivers/net/cnxk/cnxk_ethdev_devargs.c
+++ b/drivers/net/cnxk/cnxk_ethdev_devargs.c
@@ -245,6 +245,19 @@ parse_sdp_channel_mask(const char *key, const char *value, void *extra_args)
 	return 0;
 }
 
+static int
+parse_val_u16(const char *key, const char *value, void *extra_args)
+{
+	RTE_SET_USED(key);
+	uint16_t val;
+
+	val = atoi(value);
+
+	*(uint16_t *)extra_args = val;
+
+	return 0;
+}
+
 #define CNXK_RSS_RETA_SIZE	"reta_size"
 #define CNXK_SCL_ENABLE		"scalar_enable"
 #define CNXK_TX_COMPL_ENA       "tx_compl_ena"
@@ -265,10 +278,12 @@ parse_sdp_channel_mask(const char *key, const char *value, void *extra_args)
 #define CNXK_CUSTOM_SA_ACT	"custom_sa_act"
 #define CNXK_SQB_SLACK		"sqb_slack"
 #define CNXK_NIX_META_BUF_SZ	"meta_buf_sz"
+#define CNXK_FLOW_AGING_POLL_FREQ	"aging_poll_freq"
 
 int
 cnxk_ethdev_parse_devargs(struct rte_devargs *devargs, struct cnxk_eth_dev *dev)
 {
+	uint16_t aging_thread_poll_freq = ROC_NPC_AGE_POLL_FREQ_MIN;
 	uint16_t reta_sz = ROC_NIX_RSS_RETA_SZ_64;
 	uint16_t sqb_count = CNXK_NIX_TX_MAX_SQB;
 	struct flow_pre_l2_size_info pre_l2_info;
@@ -338,6 +353,8 @@ cnxk_ethdev_parse_devargs(struct rte_devargs *devargs, struct cnxk_eth_dev *dev)
 	rte_kvargs_process(kvlist, CNXK_SQB_SLACK, &parse_sqb_count,
 			   &sqb_slack);
 	rte_kvargs_process(kvlist, CNXK_NIX_META_BUF_SZ, &parse_meta_bufsize, &meta_buf_sz);
+	rte_kvargs_process(kvlist, CNXK_FLOW_AGING_POLL_FREQ, &parse_val_u16,
+			   &aging_thread_poll_freq);
 	rte_kvargs_free(kvlist);
 
 null_devargs:
@@ -369,6 +386,7 @@ cnxk_ethdev_parse_devargs(struct rte_devargs *devargs, struct cnxk_eth_dev *dev)
 	dev->npc.pre_l2_size_offset = pre_l2_info.pre_l2_size_off;
 	dev->npc.pre_l2_size_offset_mask = pre_l2_info.pre_l2_size_off_mask;
 	dev->npc.pre_l2_size_shift_dir = pre_l2_info.pre_l2_size_shift_dir;
+	dev->npc.flow_age.aging_poll_freq = aging_thread_poll_freq;
 	return 0;
 exit:
 	return -EINVAL;
@@ -390,4 +408,5 @@ RTE_PMD_REGISTER_PARAM_STRING(net_cnxk,
 			      CNXK_NO_INL_DEV "=0"
 			      CNXK_SDP_CHANNEL_MASK "=<1-4095>/<1-4095>"
 			      CNXK_CUSTOM_SA_ACT "=1"
-			      CNXK_SQB_SLACK "=<12-512>");
+			      CNXK_SQB_SLACK "=<12-512>"
+			      CNXK_FLOW_AGING_POLL_FREQ "=<10-65535>");
diff --git a/drivers/net/cnxk/cnxk_flow.c b/drivers/net/cnxk/cnxk_flow.c
index 3b8348ae9c..9d69dd90e3 100644
--- a/drivers/net/cnxk/cnxk_flow.c
+++ b/drivers/net/cnxk/cnxk_flow.c
@@ -230,6 +230,10 @@ cnxk_map_actions(struct rte_eth_dev *eth_dev, const struct rte_flow_attr *attr,
 			in_actions[i].type = ROC_NPC_ACTION_TYPE_METER;
 			in_actions[i].conf = actions->conf;
 			break;
+		case RTE_FLOW_ACTION_TYPE_AGE:
+			in_actions[i].type = ROC_NPC_ACTION_TYPE_AGE;
+			in_actions[i].conf = actions->conf;
+			break;
 		default:
 			plt_npc_dbg("Action is not supported = %d",
 				    actions->type);
@@ -480,10 +484,51 @@ cnxk_flow_dev_dump(struct rte_eth_dev *eth_dev, struct rte_flow *flow,
 	return 0;
 }
 
+static int
+cnxk_flow_get_aged_flows(struct rte_eth_dev *eth_dev, void **context,
+			 uint32_t nb_contexts, struct rte_flow_error *err)
+{
+	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
+	struct roc_npc *roc_npc = &dev->npc;
+	struct roc_npc_flow_age *flow_age;
+	uint32_t start_id;
+	uint32_t end_id;
+	int cnt = 0;
+	uint32_t sn;
+	uint32_t i;
+
+	RTE_SET_USED(err);
+
+	flow_age = &roc_npc->flow_age;
+
+	do {
+		sn = plt_seqcount_read_begin(&flow_age->seq_cnt);
+
+		if (nb_contexts == 0)
+			cnt = flow_age->aged_flows_cnt;
+		else {
+			start_id = flow_age->start_id;
+			end_id = flow_age->end_id;
+			for (i = start_id; i <= end_id; i++) {
+				if ((int)nb_contexts == cnt)
+					break;
+				if (plt_bitmap_get(flow_age->aged_flows, i)) {
+					context[cnt] =
+						roc_npc_aged_flow_ctx_get(roc_npc, i);
+					cnt++;
+				}
+			}
+		}
+	} while (plt_seqcount_read_retry(&flow_age->seq_cnt, sn));
+
+	return cnt;
+}
+
 struct rte_flow_ops cnxk_flow_ops = {
 	.validate = cnxk_flow_validate,
 	.flush = cnxk_flow_flush,
 	.query = cnxk_flow_query,
 	.isolate = cnxk_flow_isolate,
 	.dev_dump = cnxk_flow_dev_dump,
+	.get_aged_flows = cnxk_flow_get_aged_flows,
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 0/2] add support for flow aging in CNXK driver
  2023-07-27 11:59 [PATCH v1 0/2] add support for flow aging in CNXK driver Ankur Dwivedi
  2023-07-27 11:59 ` [PATCH v1 1/2] common/cnxk: add support to get aged flows Ankur Dwivedi
  2023-07-27 11:59 ` [PATCH v1 2/2] net/cnxk: add get flow aged ops Ankur Dwivedi
@ 2023-08-08  8:49 ` Ankur Dwivedi
  2023-08-08  8:49   ` [PATCH v2 1/2] common/cnxk: add support to get aged flows Ankur Dwivedi
  2023-08-08  8:49   ` [PATCH v2 2/2] net/cnxk: add get flow aged ops Ankur Dwivedi
  2 siblings, 2 replies; 9+ messages in thread
From: Ankur Dwivedi @ 2023-08-08  8:49 UTC (permalink / raw)
  To: dev; +Cc: jerinj, ndabilpuram, kirankumark, skori, skoteshwar, Ankur Dwivedi

Adds support for flow aging in CNXK driver.

v2:
- Resolved checkpatch warning in patch (2/2)
  net/cnxk: add get flow aged ops.

Ankur Dwivedi (2):
  common/cnxk: add support to get aged flows
  net/cnxk: add get flow aged ops

 doc/guides/nics/cnxk.rst               |  12 +
 doc/guides/nics/features/cnxk.ini      |   1 +
 doc/guides/nics/features/cnxk_vf.ini   |   1 +
 drivers/common/cnxk/meson.build        |   1 +
 drivers/common/cnxk/roc_mbox.h         |  27 +++
 drivers/common/cnxk/roc_npc.c          |  22 ++
 drivers/common/cnxk/roc_npc.h          |  28 +++
 drivers/common/cnxk/roc_npc_aging.c    | 315 +++++++++++++++++++++++++
 drivers/common/cnxk/roc_npc_priv.h     |  17 ++
 drivers/common/cnxk/roc_platform.h     |   8 +
 drivers/common/cnxk/version.map        |   1 +
 drivers/net/cnxk/cnxk_ethdev_devargs.c |  21 +-
 drivers/net/cnxk/cnxk_flow.c           |  45 ++++
 13 files changed, 498 insertions(+), 1 deletion(-)
 create mode 100644 drivers/common/cnxk/roc_npc_aging.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 1/2] common/cnxk: add support to get aged flows
  2023-08-08  8:49 ` [PATCH v2 0/2] add support for flow aging in CNXK driver Ankur Dwivedi
@ 2023-08-08  8:49   ` Ankur Dwivedi
  2023-08-14  6:56     ` Jerin Jacob
  2023-08-08  8:49   ` [PATCH v2 2/2] net/cnxk: add get flow aged ops Ankur Dwivedi
  1 sibling, 1 reply; 9+ messages in thread
From: Ankur Dwivedi @ 2023-08-08  8:49 UTC (permalink / raw)
  To: dev; +Cc: jerinj, ndabilpuram, kirankumark, skori, skoteshwar, Ankur Dwivedi

Adds support to get aged flows in CNXK driver.
The control thread polls the status of flows having age action, every 10
seconds and updates a bitmap array with the aged flows. The poll frequency
of control thread can be set by devargs.

Signed-off-by: Ankur Dwivedi <adwivedi@marvell.com>
---
 drivers/common/cnxk/meson.build     |   1 +
 drivers/common/cnxk/roc_mbox.h      |  27 +++
 drivers/common/cnxk/roc_npc.c       |  22 ++
 drivers/common/cnxk/roc_npc.h       |  28 +++
 drivers/common/cnxk/roc_npc_aging.c | 315 ++++++++++++++++++++++++++++
 drivers/common/cnxk/roc_npc_priv.h  |  17 ++
 drivers/common/cnxk/roc_platform.h  |   8 +
 drivers/common/cnxk/version.map     |   1 +
 8 files changed, 419 insertions(+)
 create mode 100644 drivers/common/cnxk/roc_npc_aging.c

diff --git a/drivers/common/cnxk/meson.build b/drivers/common/cnxk/meson.build
index 79e10bac74..d5dfd93e31 100644
--- a/drivers/common/cnxk/meson.build
+++ b/drivers/common/cnxk/meson.build
@@ -57,6 +57,7 @@ sources = files(
         'roc_npa_irq.c',
         'roc_npa_type.c',
         'roc_npc.c',
+        'roc_npc_aging.c',
         'roc_npc_mcam.c',
         'roc_npc_mcam_dump.c',
         'roc_npc_parse.c',
diff --git a/drivers/common/cnxk/roc_mbox.h b/drivers/common/cnxk/roc_mbox.h
index 2f85b2f755..6db46a86f4 100644
--- a/drivers/common/cnxk/roc_mbox.h
+++ b/drivers/common/cnxk/roc_mbox.h
@@ -227,6 +227,8 @@ struct mbox_msghdr {
 	  npc_mcam_get_stats_req, npc_mcam_get_stats_rsp)                      \
 	M(NPC_GET_FIELD_HASH_INFO, 0x6013, npc_get_field_hash_info,            \
 	  npc_get_field_hash_info_req, npc_get_field_hash_info_rsp)            \
+	M(NPC_MCAM_GET_HIT_STATUS, 0x6015, npc_mcam_get_hit_status,            \
+	  npc_mcam_get_hit_status_req, npc_mcam_get_hit_status_rsp)            \
 	/* NIX mbox IDs (range 0x8000 - 0xFFFF) */                             \
 	M(NIX_LF_ALLOC, 0x8000, nix_lf_alloc, nix_lf_alloc_req,                \
 	  nix_lf_alloc_rsp)                                                    \
@@ -2466,6 +2468,31 @@ struct npc_mcam_get_stats_rsp {
 	uint8_t __io stat_ena; /* enabled */
 };
 
+#define MCAM_ARR_SIZE    256
+#define MCAM_ARR_ELEM_SZ 64
+
+struct npc_mcam_get_hit_status_req {
+	struct mbox_msghdr hdr;
+	/* If clear == true, then if the hit status bit for mcam id is set,
+	 * then needs to cleared by writing 1 back.
+	 * If clear == false, then leave the hit status bit as is.
+	 */
+	bool __io clear;
+	uint8_t __io reserved[3];
+	/* Start range of mcam id */
+	uint32_t __io range_valid_mcam_ids_start;
+	/* End range of mcam id */
+	uint32_t __io range_valid_mcam_ids_end;
+	/* Bitmap of mcam ids for which the hit status needs to checked */
+	uint64_t __io mcam_ids[MCAM_ARR_SIZE];
+};
+
+struct npc_mcam_get_hit_status_rsp {
+	struct mbox_msghdr hdr;
+	/* Bitmap of mcam hit status, prior to clearing */
+	uint64_t __io mcam_hit_status[MCAM_ARR_SIZE];
+};
+
 /* TIM mailbox error codes
  * Range 801 - 900.
  */
diff --git a/drivers/common/cnxk/roc_npc.c b/drivers/common/cnxk/roc_npc.c
index 848086c8de..f0bb0aa931 100644
--- a/drivers/common/cnxk/roc_npc.c
+++ b/drivers/common/cnxk/roc_npc.c
@@ -302,6 +302,7 @@ roc_npc_init(struct roc_npc *roc_npc)
 	npc_mem = mem;
 
 	TAILQ_INIT(&npc->ipsec_list);
+	TAILQ_INIT(&npc->age_flow_list);
 	for (idx = 0; idx < npc->flow_max_priority; idx++) {
 		TAILQ_INIT(&npc->flow_list[idx]);
 		TAILQ_INIT(&npc->prio_flow_list[idx]);
@@ -330,6 +331,9 @@ roc_npc_init(struct roc_npc *roc_npc)
 	 */
 	plt_bitmap_set(npc->rss_grp_entries, 0);
 
+	rc = npc_aged_flows_bitmap_alloc(roc_npc);
+	if (rc != 0)
+		goto done;
 	return rc;
 
 done:
@@ -610,6 +614,17 @@ npc_parse_actions(struct roc_npc *roc_npc, const struct roc_npc_attr *attr,
 			flow->mtr_id = act_mtr->mtr_id;
 			req_act |= ROC_NPC_ACTION_TYPE_METER;
 			break;
+		case ROC_NPC_ACTION_TYPE_AGE:
+			if (flow->is_validate == true)
+				break;
+			plt_seqcount_init(&roc_npc->flow_age.seq_cnt);
+			errcode = npc_aging_ctrl_thread_create(roc_npc,
+							       actions->conf,
+							       flow);
+			if (errcode != 0)
+				goto err_exit;
+			req_act |= ROC_NPC_ACTION_TYPE_AGE;
+			break;
 		default:
 			errcode = NPC_ERR_ACTION_NOTSUP;
 			goto err_exit;
@@ -1485,6 +1500,9 @@ roc_npc_flow_create(struct roc_npc *roc_npc, const struct roc_npc_attr *attr,
 		}
 	}
 	TAILQ_INSERT_TAIL(list, flow, next);
+
+	npc_age_flow_list_entry_add(roc_npc, flow);
+
 	return flow;
 
 set_rss_failed:
@@ -1582,6 +1600,10 @@ roc_npc_flow_destroy(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
 
 	npc_delete_prio_list_entry(npc, flow);
 
+	npc_age_flow_list_entry_delete(roc_npc, flow);
+	if (roc_npc->flow_age.age_flow_refcnt == 0 && roc_npc->flow_age.aged_flows_poll_thread)
+		npc_aging_ctrl_thread_destroy(roc_npc);
+
 done:
 	plt_free(flow);
 	return 0;
diff --git a/drivers/common/cnxk/roc_npc.h b/drivers/common/cnxk/roc_npc.h
index 07e6634aa7..8b8a2eb343 100644
--- a/drivers/common/cnxk/roc_npc.h
+++ b/drivers/common/cnxk/roc_npc.h
@@ -180,6 +180,7 @@ enum roc_npc_action_type {
 	ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT = (1 << 15),
 	ROC_NPC_ACTION_TYPE_PORT_ID = (1 << 16),
 	ROC_NPC_ACTION_TYPE_METER = (1 << 17),
+	ROC_NPC_ACTION_TYPE_AGE = (1 << 18),
 };
 
 struct roc_npc_action {
@@ -203,6 +204,13 @@ struct roc_npc_action_port_id {
 	uint32_t id;		/**< port ID. */
 };
 
+struct roc_npc_action_age {
+	uint32_t timeout : 24; /**< Time in seconds. */
+	uint32_t reserved : 8; /**< Reserved, must be zero. */
+	/** The user flow context, NULL means the rte_flow pointer. */
+	void *context;
+};
+
 /**
  * ESP Header
  */
@@ -295,6 +303,9 @@ struct roc_npc_flow {
 	uint16_t match_id;
 	uint8_t is_inline_dev;
 	bool use_pre_alloc;
+	uint64_t timeout_cycles;
+	void *age_context;
+	uint32_t timeout;
 
 	TAILQ_ENTRY(roc_npc_flow) next;
 };
@@ -327,6 +338,19 @@ enum flow_vtag_cfg_dir { VTAG_TX, VTAG_RX };
 #define ROC_ETHER_TYPE_VLAN 0x8100 /**< IEEE 802.1Q VLAN tagging. */
 #define ROC_ETHER_TYPE_QINQ 0x88A8 /**< IEEE 802.1ad QinQ tagging. */
 
+struct roc_npc_flow_age {
+	plt_seqcount_t seq_cnt;
+	uint32_t aging_poll_freq;
+	uint32_t age_flow_refcnt;
+	uint32_t aged_flows_cnt;
+	uint32_t start_id;
+	uint32_t end_id;
+	pthread_t aged_flows_poll_thread;
+	struct plt_bitmap *aged_flows;
+	void *age_mem;
+	bool aged_flows_get_thread_exit;
+};
+
 struct roc_npc {
 	struct roc_nix *roc_nix;
 	uint8_t switch_header_type;
@@ -349,11 +373,14 @@ struct roc_npc {
 	bool is_sdp_mask_set;
 	uint16_t sdp_channel;
 	uint16_t sdp_channel_mask;
+	struct roc_npc_flow_age flow_age;
 
 #define ROC_NPC_MEM_SZ (6 * 1024)
 	uint8_t reserved[ROC_NPC_MEM_SZ];
 } __plt_cache_aligned;
 
+#define ROC_NPC_AGE_POLL_FREQ_MIN 10
+
 int __roc_api roc_npc_init(struct roc_npc *roc_npc);
 int __roc_api roc_npc_fini(struct roc_npc *roc_npc);
 const char *__roc_api roc_npc_profile_name_get(struct roc_npc *roc_npc);
@@ -397,4 +424,5 @@ int __roc_api roc_npc_validate_portid_action(struct roc_npc *roc_npc_src,
 					     struct roc_npc *roc_npc_dst);
 int __roc_api roc_npc_mcam_init(struct roc_npc *roc_npc, struct roc_npc_flow *flow, int mcam_id);
 int __roc_api roc_npc_mcam_move(struct roc_npc *roc_npc, uint16_t old_ent, uint16_t new_ent);
+void *__roc_api roc_npc_aged_flow_ctx_get(struct roc_npc *roc_npc, uint32_t mcam_id);
 #endif /* _ROC_NPC_H_ */
diff --git a/drivers/common/cnxk/roc_npc_aging.c b/drivers/common/cnxk/roc_npc_aging.c
new file mode 100644
index 0000000000..94126fe9fd
--- /dev/null
+++ b/drivers/common/cnxk/roc_npc_aging.c
@@ -0,0 +1,315 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include "roc_api.h"
+#include "roc_priv.h"
+
+int
+npc_aged_flows_bitmap_alloc(struct roc_npc *roc_npc)
+{
+	struct roc_npc_flow_age *flow_age;
+	uint8_t *age_mem = NULL;
+	uint32_t bmap_sz;
+	int rc = 0;
+
+	bmap_sz = plt_bitmap_get_memory_footprint(MCAM_ARR_ELEM_SZ *
+						  MCAM_ARR_SIZE);
+	age_mem = plt_zmalloc(bmap_sz, 0);
+	if (age_mem == NULL) {
+		plt_err("Bmap alloc failed");
+		rc = NPC_ERR_NO_MEM;
+		goto done;
+	}
+
+	flow_age = &roc_npc->flow_age;
+	flow_age->age_mem = age_mem;
+	flow_age->aged_flows = plt_bitmap_init(MCAM_ARR_ELEM_SZ * MCAM_ARR_SIZE,
+					       age_mem, bmap_sz);
+	if (!flow_age->aged_flows) {
+		plt_err("Bitmap init failed");
+		plt_free(age_mem);
+		rc = NPC_ERR_NO_MEM;
+		goto done;
+	}
+
+	flow_age->age_flow_refcnt = 0;
+done:
+	return rc;
+}
+
+void
+npc_aged_flows_bitmap_free(struct roc_npc *roc_npc)
+{
+	struct roc_npc_flow_age *flow_age;
+
+	flow_age = &roc_npc->flow_age;
+	plt_bitmap_free(flow_age->aged_flows);
+	if (flow_age->age_mem)
+		plt_free(roc_npc->flow_age.age_mem);
+}
+
+static void
+check_timeout_cycles(struct roc_npc *roc_npc, uint32_t mcam_id)
+{
+	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+	struct npc_age_flow_list_head *list;
+	struct npc_age_flow_entry *fl_iter;
+	struct roc_npc_flow_age *flow_age;
+	bool aging_enabled = false;
+
+	flow_age = &roc_npc->flow_age;
+	list = &npc->age_flow_list;
+	TAILQ_FOREACH(fl_iter, list, next) {
+		if (fl_iter->flow->mcam_id == mcam_id &&
+		    fl_iter->flow->timeout_cycles < rte_get_timer_cycles()) {
+			/* update bitmap */
+			plt_bitmap_set(flow_age->aged_flows, mcam_id);
+			if (!aging_enabled) {
+				flow_age->start_id = mcam_id;
+				flow_age->end_id = mcam_id;
+				aging_enabled = true;
+			}
+			if (flow_age->start_id > mcam_id)
+				flow_age->start_id = mcam_id;
+			else if (flow_age->end_id < mcam_id)
+				flow_age->end_id = mcam_id;
+			flow_age->aged_flows_cnt += 1;
+			break;
+		}
+	}
+}
+
+static void
+update_timeout_cycles(struct roc_npc *roc_npc, uint32_t mcam_id)
+{
+	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+	struct npc_age_flow_list_head *list;
+	struct npc_age_flow_entry *fl_iter;
+
+	list = &npc->age_flow_list;
+	TAILQ_FOREACH(fl_iter, list, next) {
+		if (fl_iter->flow->mcam_id == mcam_id) {
+			fl_iter->flow->timeout_cycles = rte_get_timer_cycles() +
+				fl_iter->flow->timeout * rte_get_timer_hz();
+			break;
+		}
+	}
+}
+
+static int
+npc_mcam_get_hit_status(struct npc *npc, uint64_t *mcam_ids, uint16_t start_id,
+			uint16_t end_id, uint64_t *hit_status, bool clear)
+{
+	struct npc_mcam_get_hit_status_req *req;
+	struct npc_mcam_get_hit_status_rsp *rsp;
+	struct mbox *mbox = mbox_get(npc->mbox);
+	uint8_t idx_start;
+	uint8_t idx_end;
+	int rc;
+	int i;
+
+	req = mbox_alloc_msg_npc_mcam_get_hit_status(mbox);
+	if (req == NULL)
+		return -ENOSPC;
+
+	idx_start = start_id / MCAM_ARR_ELEM_SZ;
+	idx_end = end_id / MCAM_ARR_ELEM_SZ;
+
+	for (i = idx_start; i <= idx_end; i++)
+		req->mcam_ids[i] = mcam_ids[i];
+
+	req->range_valid_mcam_ids_start = start_id;
+	req->range_valid_mcam_ids_end = end_id;
+	req->clear = clear;
+
+	rc = mbox_process_msg(mbox, (void *)&rsp);
+	if (rc)
+		goto exit;
+
+	for (i = idx_start; i <= idx_end; i++)
+		hit_status[i] = rsp->mcam_hit_status[i];
+
+	rc = 0;
+exit:
+	mbox_put(mbox);
+	return rc;
+}
+
+void *
+npc_aged_flows_get(void *args)
+{
+	uint64_t hit_status[MCAM_ARR_SIZE] = {0};
+	uint64_t mcam_ids[MCAM_ARR_SIZE] = {0};
+	struct npc_age_flow_list_head *list;
+	struct npc_age_flow_entry *fl_iter;
+	struct roc_npc *roc_npc = args;
+	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+	struct roc_npc_flow_age *flow_age;
+	bool aging_enabled;
+	uint32_t start_id;
+	uint32_t end_id;
+	uint32_t mcam_id;
+	uint32_t idx;
+	uint32_t i;
+	int rc;
+
+	flow_age = &roc_npc->flow_age;
+	list = &npc->age_flow_list;
+	while (!flow_age->aged_flows_get_thread_exit) {
+		start_id = 0;
+		end_id = 0;
+		aging_enabled = false;
+		memset(mcam_ids, 0, sizeof(mcam_ids));
+		TAILQ_FOREACH(fl_iter, list, next) {
+			mcam_id = fl_iter->flow->mcam_id;
+			idx = mcam_id / MCAM_ARR_ELEM_SZ;
+			mcam_ids[idx] |= BIT_ULL(mcam_id % MCAM_ARR_ELEM_SZ);
+
+			if (!aging_enabled) {
+				start_id = mcam_id;
+				end_id = mcam_id;
+				aging_enabled = true;
+			}
+
+			if (mcam_id < start_id)
+				start_id = mcam_id;
+			else if (mcam_id > end_id)
+				end_id = mcam_id;
+		}
+
+		if (!aging_enabled)
+			goto lbl_sleep;
+
+		rc = npc_mcam_get_hit_status(npc, mcam_ids, start_id, end_id,
+					     hit_status, true);
+		if (rc)
+			return NULL;
+
+		plt_seqcount_write_begin(&flow_age->seq_cnt);
+		flow_age->aged_flows_cnt = 0;
+		for (i = start_id; i <= end_id; i++) {
+			idx = i / MCAM_ARR_ELEM_SZ;
+			if (mcam_ids[idx] & BIT_ULL(i % MCAM_ARR_ELEM_SZ)) {
+				if (!(hit_status[idx] & BIT_ULL(i % MCAM_ARR_ELEM_SZ)))
+					check_timeout_cycles(roc_npc, i);
+				else
+					update_timeout_cycles(roc_npc, i);
+			}
+		}
+		plt_seqcount_write_end(&flow_age->seq_cnt);
+
+lbl_sleep:
+		sleep(flow_age->aging_poll_freq);
+	}
+
+	return NULL;
+}
+
+void
+npc_age_flow_list_entry_add(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
+{
+	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+	struct npc_age_flow_entry *age_fl_iter;
+	struct npc_age_flow_entry *new_entry;
+
+	new_entry = plt_zmalloc(sizeof(*new_entry), 0);
+	new_entry->flow = flow;
+	roc_npc->flow_age.age_flow_refcnt++;
+	/* List in ascending order of mcam entries */
+	TAILQ_FOREACH(age_fl_iter, &npc->age_flow_list, next) {
+		if (age_fl_iter->flow->mcam_id > flow->mcam_id) {
+			TAILQ_INSERT_BEFORE(age_fl_iter, new_entry, next);
+			return;
+		}
+	}
+	TAILQ_INSERT_TAIL(&npc->age_flow_list, new_entry, next);
+}
+
+void
+npc_age_flow_list_entry_delete(struct roc_npc *roc_npc,
+			       struct roc_npc_flow *flow)
+{
+	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+	struct npc_age_flow_list_head *list;
+	struct npc_age_flow_entry *curr;
+
+	list = &npc->age_flow_list;
+	curr = TAILQ_FIRST(list);
+
+	if (!curr)
+		return;
+
+	while (curr) {
+		if (flow->mcam_id == curr->flow->mcam_id) {
+			TAILQ_REMOVE(list, curr, next);
+			plt_free(curr);
+			break;
+		}
+		curr = TAILQ_NEXT(curr, next);
+	}
+	roc_npc->flow_age.age_flow_refcnt--;
+}
+
+int
+npc_aging_ctrl_thread_create(struct roc_npc *roc_npc,
+			     const struct roc_npc_action_age *age,
+			     struct roc_npc_flow *flow)
+{
+	struct roc_npc_flow_age *flow_age;
+	int errcode = 0;
+
+	flow_age = &roc_npc->flow_age;
+	if (age->timeout < flow_age->aging_poll_freq) {
+		plt_err("Age timeout should be greater or equal to %u seconds",
+			flow_age->aging_poll_freq);
+		errcode = NPC_ERR_ACTION_NOTSUP;
+		goto done;
+	}
+
+	flow->age_context = age->context == NULL ? flow : age->context;
+	flow->timeout = age->timeout;
+	flow->timeout_cycles = rte_get_timer_cycles() + age->timeout *
+			       rte_get_timer_hz();
+
+	if (flow_age->age_flow_refcnt == 0) {
+		flow_age->aged_flows_get_thread_exit = false;
+		if (plt_ctrl_thread_create(&flow_age->aged_flows_poll_thread,
+					   "Aged Flows Get Ctrl Thread", NULL,
+					   npc_aged_flows_get, roc_npc) != 0) {
+			plt_err("Failed to create thread for age flows");
+			errcode = NPC_ERR_ACTION_NOTSUP;
+			goto done;
+		}
+	}
+done:
+	return errcode;
+}
+
+void
+npc_aging_ctrl_thread_destroy(struct roc_npc *roc_npc)
+{
+	struct roc_npc_flow_age *flow_age;
+
+	flow_age = &roc_npc->flow_age;
+	flow_age->aged_flows_get_thread_exit = true;
+	pthread_join(flow_age->aged_flows_poll_thread, NULL);
+	npc_aged_flows_bitmap_free(roc_npc);
+}
+
+void *
+roc_npc_aged_flow_ctx_get(struct roc_npc *roc_npc, uint32_t mcam_id)
+{
+	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+	struct npc_age_flow_list_head *list;
+	struct npc_age_flow_entry *fl_iter;
+
+	list = &npc->age_flow_list;
+
+	TAILQ_FOREACH(fl_iter, list, next) {
+		if (fl_iter->flow->mcam_id == mcam_id)
+			return fl_iter->flow->age_context;
+	}
+
+	return NULL;
+}
diff --git a/drivers/common/cnxk/roc_npc_priv.h b/drivers/common/cnxk/roc_npc_priv.h
index 593dca353b..6d6cb64c65 100644
--- a/drivers/common/cnxk/roc_npc_priv.h
+++ b/drivers/common/cnxk/roc_npc_priv.h
@@ -378,6 +378,13 @@ struct npc_prio_flow_entry {
 
 TAILQ_HEAD(npc_prio_flow_list_head, npc_prio_flow_entry);
 
+struct npc_age_flow_entry {
+	struct roc_npc_flow *flow;
+	TAILQ_ENTRY(npc_age_flow_entry) next;
+};
+
+TAILQ_HEAD(npc_age_flow_list_head, npc_age_flow_entry);
+
 struct npc {
 	struct mbox *mbox;			/* Mbox */
 	uint32_t keyx_supp_nmask[NPC_MAX_INTF]; /* nibble mask */
@@ -403,6 +410,7 @@ struct npc {
 	npc_ld_flags_t prx_lfcfg;    /* KEX LD_Flags CFG */
 	struct npc_flow_list *flow_list;
 	struct npc_prio_flow_list_head *prio_flow_list;
+	struct npc_age_flow_list_head age_flow_list;
 	struct plt_bitmap *rss_grp_entries;
 	struct npc_flow_list ipsec_list;
 	uint8_t exact_match_ena;
@@ -480,4 +488,13 @@ int npc_rss_action_program(struct roc_npc *roc_npc, const struct roc_npc_action
 int npc_rss_group_free(struct npc *npc, struct roc_npc_flow *flow);
 int npc_mcam_init(struct npc *npc, struct roc_npc_flow *flow, int mcam_id);
 int npc_mcam_move(struct mbox *mbox, uint16_t old_ent, uint16_t new_ent);
+void npc_age_flow_list_entry_add(struct roc_npc *npc, struct roc_npc_flow *flow);
+void npc_age_flow_list_entry_delete(struct roc_npc *npc, struct roc_npc_flow *flow);
+void *npc_aged_flows_get(void *args);
+int npc_aged_flows_bitmap_alloc(struct roc_npc *roc_npc);
+void npc_aged_flows_bitmap_free(struct roc_npc *roc_npc);
+int npc_aging_ctrl_thread_create(struct roc_npc *roc_npc,
+				 const struct roc_npc_action_age *age,
+				 struct roc_npc_flow *flow);
+void npc_aging_ctrl_thread_destroy(struct roc_npc *roc_npc);
 #endif /* _ROC_NPC_PRIV_H_ */
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index 9884398a99..e7a6564163 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -20,6 +20,7 @@
 #include <rte_malloc.h>
 #include <rte_memzone.h>
 #include <rte_pci.h>
+#include <rte_seqcount.h>
 #include <rte_spinlock.h>
 #include <rte_string_fns.h>
 #include <rte_tailq.h>
@@ -130,6 +131,13 @@
 #define plt_spinlock_unlock  rte_spinlock_unlock
 #define plt_spinlock_trylock rte_spinlock_trylock
 
+#define plt_seqcount_t			rte_seqcount_t
+#define plt_seqcount_init		rte_seqcount_init
+#define plt_seqcount_read_begin		rte_seqcount_read_begin
+#define plt_seqcount_read_retry		rte_seqcount_read_retry
+#define plt_seqcount_write_begin	rte_seqcount_write_begin
+#define plt_seqcount_write_end		rte_seqcount_write_end
+
 #define plt_intr_callback_register   rte_intr_callback_register
 #define plt_intr_callback_unregister rte_intr_callback_unregister
 #define plt_intr_disable	     rte_intr_disable
diff --git a/drivers/common/cnxk/version.map b/drivers/common/cnxk/version.map
index 8c71497df8..28f0f55934 100644
--- a/drivers/common/cnxk/version.map
+++ b/drivers/common/cnxk/version.map
@@ -425,6 +425,7 @@ INTERNAL {
 	roc_npa_pool_op_range_set;
 	roc_npa_pool_range_update_check;
 	roc_npa_zero_aura_handle;
+	roc_npc_aged_flow_ctx_get;
 	roc_npc_fini;
 	roc_npc_flow_create;
 	roc_npc_flow_destroy;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 2/2] net/cnxk: add get flow aged ops
  2023-08-08  8:49 ` [PATCH v2 0/2] add support for flow aging in CNXK driver Ankur Dwivedi
  2023-08-08  8:49   ` [PATCH v2 1/2] common/cnxk: add support to get aged flows Ankur Dwivedi
@ 2023-08-08  8:49   ` Ankur Dwivedi
  1 sibling, 0 replies; 9+ messages in thread
From: Ankur Dwivedi @ 2023-08-08  8:49 UTC (permalink / raw)
  To: dev; +Cc: jerinj, ndabilpuram, kirankumark, skori, skoteshwar, Ankur Dwivedi

Adds get flow aged ops in CNXK driver. Also adds the devargs to get the
poll frequency of control thread.

Signed-off-by: Ankur Dwivedi <adwivedi@marvell.com>
---
 doc/guides/nics/cnxk.rst               | 12 +++++++
 doc/guides/nics/features/cnxk.ini      |  1 +
 doc/guides/nics/features/cnxk_vf.ini   |  1 +
 drivers/net/cnxk/cnxk_ethdev_devargs.c | 21 +++++++++++-
 drivers/net/cnxk/cnxk_flow.c           | 45 ++++++++++++++++++++++++++
 5 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/cnxk.rst b/doc/guides/nics/cnxk.rst
index 9229056f6f..dc71ab7fc3 100644
--- a/doc/guides/nics/cnxk.rst
+++ b/doc/guides/nics/cnxk.rst
@@ -581,6 +581,18 @@ Runtime Config Options for inline device
    With the above configuration, driver would poll for soft expiry events every
    1000 usec.
 
+- ``NPC MCAM Aging poll frequency in seconds`` (default ``10``)
+
+   Poll frequency for aging control thread can be specified by
+   ``aging_poll_freq`` ``devargs`` parameter.
+
+   For example::
+
+      -a 0002:01:00.2,aging_poll_freq=50
+
+   With the above configuration, driver would poll for aging flows every 50
+   seconds.
+
 Debugging Options
 -----------------
 
diff --git a/doc/guides/nics/features/cnxk.ini b/doc/guides/nics/features/cnxk.ini
index 838e781d6d..ebedbd0588 100644
--- a/doc/guides/nics/features/cnxk.ini
+++ b/doc/guides/nics/features/cnxk.ini
@@ -80,6 +80,7 @@ vxlan                = Y
 vxlan_gpe            = Y
 
 [rte_flow actions]
+age                  = Y
 count                = Y
 drop                 = Y
 flag                 = Y
diff --git a/doc/guides/nics/features/cnxk_vf.ini b/doc/guides/nics/features/cnxk_vf.ini
index 470c45ce59..0e9ad94382 100644
--- a/doc/guides/nics/features/cnxk_vf.ini
+++ b/doc/guides/nics/features/cnxk_vf.ini
@@ -71,6 +71,7 @@ vxlan                = Y
 vxlan_gpe            = Y
 
 [rte_flow actions]
+age                  = Y
 count                = Y
 drop                 = Y
 flag                 = Y
diff --git a/drivers/net/cnxk/cnxk_ethdev_devargs.c b/drivers/net/cnxk/cnxk_ethdev_devargs.c
index e1a0845ece..8e862be933 100644
--- a/drivers/net/cnxk/cnxk_ethdev_devargs.c
+++ b/drivers/net/cnxk/cnxk_ethdev_devargs.c
@@ -245,6 +245,19 @@ parse_sdp_channel_mask(const char *key, const char *value, void *extra_args)
 	return 0;
 }
 
+static int
+parse_val_u16(const char *key, const char *value, void *extra_args)
+{
+	RTE_SET_USED(key);
+	uint16_t val;
+
+	val = atoi(value);
+
+	*(uint16_t *)extra_args = val;
+
+	return 0;
+}
+
 #define CNXK_RSS_RETA_SIZE	"reta_size"
 #define CNXK_SCL_ENABLE		"scalar_enable"
 #define CNXK_TX_COMPL_ENA       "tx_compl_ena"
@@ -265,10 +278,12 @@ parse_sdp_channel_mask(const char *key, const char *value, void *extra_args)
 #define CNXK_CUSTOM_SA_ACT	"custom_sa_act"
 #define CNXK_SQB_SLACK		"sqb_slack"
 #define CNXK_NIX_META_BUF_SZ	"meta_buf_sz"
+#define CNXK_FLOW_AGING_POLL_FREQ	"aging_poll_freq"
 
 int
 cnxk_ethdev_parse_devargs(struct rte_devargs *devargs, struct cnxk_eth_dev *dev)
 {
+	uint16_t aging_thread_poll_freq = ROC_NPC_AGE_POLL_FREQ_MIN;
 	uint16_t reta_sz = ROC_NIX_RSS_RETA_SZ_64;
 	uint16_t sqb_count = CNXK_NIX_TX_MAX_SQB;
 	struct flow_pre_l2_size_info pre_l2_info;
@@ -338,6 +353,8 @@ cnxk_ethdev_parse_devargs(struct rte_devargs *devargs, struct cnxk_eth_dev *dev)
 	rte_kvargs_process(kvlist, CNXK_SQB_SLACK, &parse_sqb_count,
 			   &sqb_slack);
 	rte_kvargs_process(kvlist, CNXK_NIX_META_BUF_SZ, &parse_meta_bufsize, &meta_buf_sz);
+	rte_kvargs_process(kvlist, CNXK_FLOW_AGING_POLL_FREQ, &parse_val_u16,
+			   &aging_thread_poll_freq);
 	rte_kvargs_free(kvlist);
 
 null_devargs:
@@ -369,6 +386,7 @@ cnxk_ethdev_parse_devargs(struct rte_devargs *devargs, struct cnxk_eth_dev *dev)
 	dev->npc.pre_l2_size_offset = pre_l2_info.pre_l2_size_off;
 	dev->npc.pre_l2_size_offset_mask = pre_l2_info.pre_l2_size_off_mask;
 	dev->npc.pre_l2_size_shift_dir = pre_l2_info.pre_l2_size_shift_dir;
+	dev->npc.flow_age.aging_poll_freq = aging_thread_poll_freq;
 	return 0;
 exit:
 	return -EINVAL;
@@ -390,4 +408,5 @@ RTE_PMD_REGISTER_PARAM_STRING(net_cnxk,
 			      CNXK_NO_INL_DEV "=0"
 			      CNXK_SDP_CHANNEL_MASK "=<1-4095>/<1-4095>"
 			      CNXK_CUSTOM_SA_ACT "=1"
-			      CNXK_SQB_SLACK "=<12-512>");
+			      CNXK_SQB_SLACK "=<12-512>"
+			      CNXK_FLOW_AGING_POLL_FREQ "=<10-65535>");
diff --git a/drivers/net/cnxk/cnxk_flow.c b/drivers/net/cnxk/cnxk_flow.c
index 3b8348ae9c..e0aeb5ea5f 100644
--- a/drivers/net/cnxk/cnxk_flow.c
+++ b/drivers/net/cnxk/cnxk_flow.c
@@ -230,6 +230,10 @@ cnxk_map_actions(struct rte_eth_dev *eth_dev, const struct rte_flow_attr *attr,
 			in_actions[i].type = ROC_NPC_ACTION_TYPE_METER;
 			in_actions[i].conf = actions->conf;
 			break;
+		case RTE_FLOW_ACTION_TYPE_AGE:
+			in_actions[i].type = ROC_NPC_ACTION_TYPE_AGE;
+			in_actions[i].conf = actions->conf;
+			break;
 		default:
 			plt_npc_dbg("Action is not supported = %d",
 				    actions->type);
@@ -480,10 +484,51 @@ cnxk_flow_dev_dump(struct rte_eth_dev *eth_dev, struct rte_flow *flow,
 	return 0;
 }
 
+static int
+cnxk_flow_get_aged_flows(struct rte_eth_dev *eth_dev, void **context,
+			 uint32_t nb_contexts, struct rte_flow_error *err)
+{
+	struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
+	struct roc_npc *roc_npc = &dev->npc;
+	struct roc_npc_flow_age *flow_age;
+	uint32_t start_id;
+	uint32_t end_id;
+	int cnt = 0;
+	uint32_t sn;
+	uint32_t i;
+
+	RTE_SET_USED(err);
+
+	flow_age = &roc_npc->flow_age;
+
+	do {
+		sn = plt_seqcount_read_begin(&flow_age->seq_cnt);
+
+		if (nb_contexts == 0) {
+			cnt = flow_age->aged_flows_cnt;
+		} else {
+			start_id = flow_age->start_id;
+			end_id = flow_age->end_id;
+			for (i = start_id; i <= end_id; i++) {
+				if ((int)nb_contexts == cnt)
+					break;
+				if (plt_bitmap_get(flow_age->aged_flows, i)) {
+					context[cnt] =
+						roc_npc_aged_flow_ctx_get(roc_npc, i);
+					cnt++;
+				}
+			}
+		}
+	} while (plt_seqcount_read_retry(&flow_age->seq_cnt, sn));
+
+	return cnt;
+}
+
 struct rte_flow_ops cnxk_flow_ops = {
 	.validate = cnxk_flow_validate,
 	.flush = cnxk_flow_flush,
 	.query = cnxk_flow_query,
 	.isolate = cnxk_flow_isolate,
 	.dev_dump = cnxk_flow_dev_dump,
+	.get_aged_flows = cnxk_flow_get_aged_flows,
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 1/2] common/cnxk: add support to get aged flows
  2023-08-08  8:49   ` [PATCH v2 1/2] common/cnxk: add support to get aged flows Ankur Dwivedi
@ 2023-08-14  6:56     ` Jerin Jacob
  2023-09-28  8:13       ` Jerin Jacob
  0 siblings, 1 reply; 9+ messages in thread
From: Jerin Jacob @ 2023-08-14  6:56 UTC (permalink / raw)
  To: Ankur Dwivedi; +Cc: dev, jerinj, ndabilpuram, kirankumark, skori, skoteshwar

On Tue, Aug 8, 2023 at 2:20 PM Ankur Dwivedi <adwivedi@marvell.com> wrote:
>
> Adds support to get aged flows in CNXK driver.
> The control thread polls the status of flows having age action, every 10
> seconds and updates a bitmap array with the aged flows. The poll frequency
> of control thread can be set by devargs.
>
> Signed-off-by: Ankur Dwivedi <adwivedi@marvell.com>
> ---
>  drivers/common/cnxk/meson.build     |   1 +
>  drivers/common/cnxk/roc_mbox.h      |  27 +++
>  drivers/common/cnxk/roc_npc.c       |  22 ++
>  drivers/common/cnxk/roc_npc.h       |  28 +++
>  drivers/common/cnxk/roc_npc_aging.c | 315 ++++++++++++++++++++++++++++
>  drivers/common/cnxk/roc_npc_priv.h  |  17 ++
>  drivers/common/cnxk/roc_platform.h  |   8 +
>  drivers/common/cnxk/version.map     |   1 +
>  8 files changed, 419 insertions(+)
>  create mode 100644 drivers/common/cnxk/roc_npc_aging.c

Updated the release notes as
diff --git a/doc/guides/rel_notes/release_23_11.rst
b/doc/guides/rel_notes/release_23_11.rst
index 5b01a52593..10d4484685 100644
--- a/doc/guides/rel_notes/release_23_11.rst
+++ b/doc/guides/rel_notes/release_23_11.rst
@@ -58,6 +58,7 @@ New Features
 * **Updated Marvell cnxk ethdev driver.**

   * Added support for ``RTE_FLOW_ITEM_TYPE_IPV6_ROUTING_EXT`` flow item.
+  * Added support for ``RTE_FLOW_ACTION_TYPE_AGE`` flow action.

Updated the git commit as follows and applied to
dpdk-next-net-mrvl/for-next-net. Thanks


commit ebee383fbe9a0ca25e083d26d9b251cb0310a5d2 (HEAD -> for-next-net)
Author: Ankur Dwivedi <adwivedi@marvell.com>
Date:   Tue Aug 8 14:19:52 2023 +0530

    net/cnxk: support flow aging

    Support get flow aged ops in cnxk ethdev driver.
    Also adds the devargs to get the poll frequency of control thread.

    Signed-off-by: Ankur Dwivedi <adwivedi@marvell.com>

commit d110c44d29e73b74834fb795ba18069635cdff6f
Author: Ankur Dwivedi <adwivedi@marvell.com>
Date:   Tue Aug 8 14:19:51 2023 +0530

    common/cnxk: support flow aging

    Added support to get aged flows in base code. The control thread
    polls the status of flows having age action, every 10 seconds and
    updates a bitmap array with the aged flows. The poll frequency
    of control thread can be set by devargs.

    Signed-off-by: Ankur Dwivedi <adwivedi@marvell.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 1/2] common/cnxk: add support to get aged flows
  2023-08-14  6:56     ` Jerin Jacob
@ 2023-09-28  8:13       ` Jerin Jacob
  2023-09-28 13:49         ` [EXT] " Ankur Dwivedi
  0 siblings, 1 reply; 9+ messages in thread
From: Jerin Jacob @ 2023-09-28  8:13 UTC (permalink / raw)
  To: Ankur Dwivedi
  Cc: dev, jerinj, ndabilpuram, kirankumark, skori, skoteshwar,
	Thomas Monjalon

On Mon, Aug 14, 2023 at 12:26 PM Jerin Jacob <jerinjacobk@gmail.com> wrote:
>
> On Tue, Aug 8, 2023 at 2:20 PM Ankur Dwivedi <adwivedi@marvell.com> wrote:
> >
> > Adds support to get aged flows in CNXK driver.
> > The control thread polls the status of flows having age action, every 10
> > seconds and updates a bitmap array with the aged flows. The poll frequency
> > of control thread can be set by devargs.
> >
> > Signed-off-by: Ankur Dwivedi <adwivedi@marvell.com>
> > ---
> >  drivers/common/cnxk/meson.build     |   1 +
> >  drivers/common/cnxk/roc_mbox.h      |  27 +++
> >  drivers/common/cnxk/roc_npc.c       |  22 ++
> >  drivers/common/cnxk/roc_npc.h       |  28 +++
> >  drivers/common/cnxk/roc_npc_aging.c | 315 ++++++++++++++++++++++++++++
> >  drivers/common/cnxk/roc_npc_priv.h  |  17 ++
> >  drivers/common/cnxk/roc_platform.h  |   8 +
> >  drivers/common/cnxk/version.map     |   1 +
> >  8 files changed, 419 insertions(+)
> >  create mode 100644 drivers/common/cnxk/roc_npc_aging.c
>
> Updated the release notes as
> diff --git a/doc/guides/rel_notes/release_23_11.rst
> b/doc/guides/rel_notes/release_23_11.rst
> index 5b01a52593..10d4484685 100644
> --- a/doc/guides/rel_notes/release_23_11.rst
> +++ b/doc/guides/rel_notes/release_23_11.rst
> @@ -58,6 +58,7 @@ New Features
>  * **Updated Marvell cnxk ethdev driver.**
>
>    * Added support for ``RTE_FLOW_ITEM_TYPE_IPV6_ROUTING_EXT`` flow item.
> +  * Added support for ``RTE_FLOW_ACTION_TYPE_AGE`` flow action.
>
> Updated the git commit as follows and applied to
> dpdk-next-net-mrvl/for-next-net. Thanks


Ankur, following changes in upstream changed the thread APIs. I have
adapted to this change in [1]. Please review ASAP - It is blocking rc1
PR.

commit 1c1abf1786a6de044bd396da4cc316961e3fd812
Author: Thomas Monjalon <thomas@monjalon.net>
Date:   Wed Sep 13 13:28:19 2023 +0200

    lib: convert to internal control threads

    Calls to rte_ctrl_thread_create() are replaced with
    rte_thread_create_internal_control().
    Other pthread-related functions are replaced with the rte_thread API.
    Only pthread_cancel() has no replacement.

    Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
    Acked-by: Morten Brørup <mb@smartsharesystems.com>
    Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com>
    Acked-by: Konstantin Ananyev <konstantin.v.ananyev@yandex.ru


[1]

diff --git a/drivers/common/cnxk/roc_npc.c b/drivers/common/cnxk/roc_npc.c
index 83c04880f2..94c8e94400 100644
--- a/drivers/common/cnxk/roc_npc.c
+++ b/drivers/common/cnxk/roc_npc.c
@@ -1623,7 +1623,8 @@ roc_npc_flow_destroy(struct roc_npc *roc_npc,
struct roc_npc_flow *flow)
  npc_delete_prio_list_entry(npc, flow);

  npc_age_flow_list_entry_delete(roc_npc, flow);
- if (roc_npc->flow_age.age_flow_refcnt == 0 &&
roc_npc->flow_age.aged_flows_poll_thread)
+ if (roc_npc->flow_age.age_flow_refcnt == 0 &&
+ plt_thread_is_valid(roc_npc->flow_age.aged_flows_poll_thread))
  npc_aging_ctrl_thread_destroy(roc_npc);

 done:
diff --git a/drivers/common/cnxk/roc_npc.h b/drivers/common/cnxk/roc_npc.h
index ad1c3b08cc..5a7117eae4 100644
--- a/drivers/common/cnxk/roc_npc.h
+++ b/drivers/common/cnxk/roc_npc.h
@@ -359,7 +359,7 @@ struct roc_npc_flow_age {
  uint32_t aged_flows_cnt;
  uint32_t start_id;
  uint32_t end_id;
- pthread_t aged_flows_poll_thread;
+ rte_thread_t aged_flows_poll_thread;
  struct plt_bitmap *aged_flows;
  void *age_mem;
  bool aged_flows_get_thread_exit;
diff --git a/drivers/common/cnxk/roc_npc_aging.c
b/drivers/common/cnxk/roc_npc_aging.c
index 4b845954b4..74543f227b 100644
--- a/drivers/common/cnxk/roc_npc_aging.c
+++ b/drivers/common/cnxk/roc_npc_aging.c
@@ -134,7 +134,7 @@ npc_mcam_get_hit_status(struct npc *npc, uint64_t
*mcam_ids, uint16_t start_id,
  return rc;
 }

-void *
+uint32_t
 npc_aged_flows_get(void *args)
 {
  uint64_t hit_status[MCAM_ARR_SIZE] = {0};
@@ -182,7 +182,7 @@ npc_aged_flows_get(void *args)
  rc = npc_mcam_get_hit_status(npc, mcam_ids, start_id, end_id,
       hit_status, true);
  if (rc)
- return NULL;
+ return 0;

  plt_seqcount_write_begin(&flow_age->seq_cnt);
  flow_age->aged_flows_cnt = 0;
@@ -201,7 +201,7 @@ npc_aged_flows_get(void *args)
  sleep(flow_age->aging_poll_freq);
  }

- return NULL;
+ return 0;
 }

 void
@@ -276,8 +276,8 @@ npc_aging_ctrl_thread_create(struct roc_npc *roc_npc,

  if (flow_age->age_flow_refcnt == 0) {
  flow_age->aged_flows_get_thread_exit = false;
- if (plt_ctrl_thread_create(&flow_age->aged_flows_poll_thread,
-    "Aged Flows Get Ctrl Thread", NULL,
+ if (plt_thread_create_control(&flow_age->aged_flows_poll_thread,
+    "Aged Flows Get Ctrl Thread",
     npc_aged_flows_get, roc_npc) != 0) {
  plt_err("Failed to create thread for age flows");
  errcode = NPC_ERR_ACTION_NOTSUP;
@@ -295,7 +295,7 @@ npc_aging_ctrl_thread_destroy(struct roc_npc *roc_npc)

  flow_age = &roc_npc->flow_age;
  flow_age->aged_flows_get_thread_exit = true;
- pthread_join(flow_age->aged_flows_poll_thread, NULL);
+ plt_thread_join(flow_age->aged_flows_poll_thread, NULL);
  npc_aged_flows_bitmap_free(roc_npc);
 }

diff --git a/drivers/common/cnxk/roc_npc_priv.h
b/drivers/common/cnxk/roc_npc_priv.h
index 6d6cb64c65..424f8e207a 100644
--- a/drivers/common/cnxk/roc_npc_priv.h
+++ b/drivers/common/cnxk/roc_npc_priv.h
@@ -490,7 +490,7 @@ int npc_mcam_init(struct npc *npc, struct
roc_npc_flow *flow, int mcam_id);
 int npc_mcam_move(struct mbox *mbox, uint16_t old_ent, uint16_t new_ent);
 void npc_age_flow_list_entry_add(struct roc_npc *npc, struct
roc_npc_flow *flow);
 void npc_age_flow_list_entry_delete(struct roc_npc *npc, struct
roc_npc_flow *flow);
-void *npc_aged_flows_get(void *args);
+uint32_t npc_aged_flows_get(void *args);
 int npc_aged_flows_bitmap_alloc(struct roc_npc *roc_npc);
 void npc_aged_flows_bitmap_free(struct roc_npc *roc_npc);
 int npc_aging_ctrl_thread_create(struct roc_npc *roc_npc,
diff --git a/drivers/common/cnxk/roc_platform.h
b/drivers/common/cnxk/roc_platform.h
index ad0d1624a3..1e535a527d 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -145,6 +145,12 @@
 #define plt_thread_create_control    rte_thread_create_internal_control
 #define plt_thread_join              rte_thread_join

+static inline bool
+plt_thread_is_valid(rte_thread_t thr)
+{
+ return thr.opaque_id ? true : false;
+}
+
 #define plt_intr_efd_counter_size_get rte_intr_efd_counter_size_get
 #define plt_intr_efd_counter_size_set rte_intr_efd_counter_size_set
 #define plt_intr_vec_list_index_get rte_intr_vec_list_index_get

^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [EXT] Re: [PATCH v2 1/2] common/cnxk: add support to get aged flows
  2023-09-28  8:13       ` Jerin Jacob
@ 2023-09-28 13:49         ` Ankur Dwivedi
  0 siblings, 0 replies; 9+ messages in thread
From: Ankur Dwivedi @ 2023-09-28 13:49 UTC (permalink / raw)
  To: Jerin Jacob
  Cc: dev, Jerin Jacob Kollanukkaran, Nithin Kumar Dabilpuram,
	Kiran Kumar Kokkilagadda, Sunil Kumar Kori,
	Satha Koteswara Rao Kottidi, Thomas Monjalon



>
>
>Ankur, following changes in upstream changed the thread APIs. I have
>adapted to this change in [1]. Please review ASAP - It is blocking rc1 PR.

I have reviewed the changes. The changes are fine.

Thanks.
>
>commit 1c1abf1786a6de044bd396da4cc316961e3fd812
>Author: Thomas Monjalon <thomas@monjalon.net>
>Date:   Wed Sep 13 13:28:19 2023 +0200
>
>    lib: convert to internal control threads
>
>    Calls to rte_ctrl_thread_create() are replaced with
>    rte_thread_create_internal_control().
>    Other pthread-related functions are replaced with the rte_thread API.
>    Only pthread_cancel() has no replacement.
>
>    Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
>    Acked-by: Morten Brørup <mb@smartsharesystems.com>
>    Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com>
>    Acked-by: Konstantin Ananyev <konstantin.v.ananyev@yandex.ru
>
>
>[1]
>
>diff --git a/drivers/common/cnxk/roc_npc.c
>b/drivers/common/cnxk/roc_npc.c index 83c04880f2..94c8e94400 100644
>--- a/drivers/common/cnxk/roc_npc.c
>+++ b/drivers/common/cnxk/roc_npc.c
>@@ -1623,7 +1623,8 @@ roc_npc_flow_destroy(struct roc_npc *roc_npc,
>struct roc_npc_flow *flow)
>  npc_delete_prio_list_entry(npc, flow);
>
>  npc_age_flow_list_entry_delete(roc_npc, flow);
>- if (roc_npc->flow_age.age_flow_refcnt == 0 &&
>roc_npc->flow_age.aged_flows_poll_thread)
>+ if (roc_npc->flow_age.age_flow_refcnt == 0 &&
>+ plt_thread_is_valid(roc_npc->flow_age.aged_flows_poll_thread))
>  npc_aging_ctrl_thread_destroy(roc_npc);
>
> done:
>diff --git a/drivers/common/cnxk/roc_npc.h
>b/drivers/common/cnxk/roc_npc.h index ad1c3b08cc..5a7117eae4 100644
>--- a/drivers/common/cnxk/roc_npc.h
>+++ b/drivers/common/cnxk/roc_npc.h
>@@ -359,7 +359,7 @@ struct roc_npc_flow_age {
>  uint32_t aged_flows_cnt;
>  uint32_t start_id;
>  uint32_t end_id;
>- pthread_t aged_flows_poll_thread;
>+ rte_thread_t aged_flows_poll_thread;
>  struct plt_bitmap *aged_flows;
>  void *age_mem;
>  bool aged_flows_get_thread_exit;
>diff --git a/drivers/common/cnxk/roc_npc_aging.c
>b/drivers/common/cnxk/roc_npc_aging.c
>index 4b845954b4..74543f227b 100644
>--- a/drivers/common/cnxk/roc_npc_aging.c
>+++ b/drivers/common/cnxk/roc_npc_aging.c
>@@ -134,7 +134,7 @@ npc_mcam_get_hit_status(struct npc *npc, uint64_t
>*mcam_ids, uint16_t start_id,
>  return rc;
> }
>
>-void *
>+uint32_t
> npc_aged_flows_get(void *args)
> {
>  uint64_t hit_status[MCAM_ARR_SIZE] = {0}; @@ -182,7 +182,7 @@
>npc_aged_flows_get(void *args)
>  rc = npc_mcam_get_hit_status(npc, mcam_ids, start_id, end_id,
>       hit_status, true);
>  if (rc)
>- return NULL;
>+ return 0;
>
>  plt_seqcount_write_begin(&flow_age->seq_cnt);
>  flow_age->aged_flows_cnt = 0;
>@@ -201,7 +201,7 @@ npc_aged_flows_get(void *args)
>  sleep(flow_age->aging_poll_freq);
>  }
>
>- return NULL;
>+ return 0;
> }
>
> void
>@@ -276,8 +276,8 @@ npc_aging_ctrl_thread_create(struct roc_npc
>*roc_npc,
>
>  if (flow_age->age_flow_refcnt == 0) {
>  flow_age->aged_flows_get_thread_exit = false;
>- if (plt_ctrl_thread_create(&flow_age->aged_flows_poll_thread,
>-    "Aged Flows Get Ctrl Thread", NULL,
>+ if (plt_thread_create_control(&flow_age->aged_flows_poll_thread,
>+    "Aged Flows Get Ctrl Thread",
>     npc_aged_flows_get, roc_npc) != 0) {
>  plt_err("Failed to create thread for age flows");
>  errcode = NPC_ERR_ACTION_NOTSUP;
>@@ -295,7 +295,7 @@ npc_aging_ctrl_thread_destroy(struct roc_npc
>*roc_npc)
>
>  flow_age = &roc_npc->flow_age;
>  flow_age->aged_flows_get_thread_exit = true;
>- pthread_join(flow_age->aged_flows_poll_thread, NULL);
>+ plt_thread_join(flow_age->aged_flows_poll_thread, NULL);
>  npc_aged_flows_bitmap_free(roc_npc);
> }
>
>diff --git a/drivers/common/cnxk/roc_npc_priv.h
>b/drivers/common/cnxk/roc_npc_priv.h
>index 6d6cb64c65..424f8e207a 100644
>--- a/drivers/common/cnxk/roc_npc_priv.h
>+++ b/drivers/common/cnxk/roc_npc_priv.h
>@@ -490,7 +490,7 @@ int npc_mcam_init(struct npc *npc, struct
>roc_npc_flow *flow, int mcam_id);  int npc_mcam_move(struct mbox *mbox,
>uint16_t old_ent, uint16_t new_ent);  void
>npc_age_flow_list_entry_add(struct roc_npc *npc, struct roc_npc_flow
>*flow);  void npc_age_flow_list_entry_delete(struct roc_npc *npc, struct
>roc_npc_flow *flow); -void *npc_aged_flows_get(void *args);
>+uint32_t npc_aged_flows_get(void *args);
> int npc_aged_flows_bitmap_alloc(struct roc_npc *roc_npc);  void
>npc_aged_flows_bitmap_free(struct roc_npc *roc_npc);  int
>npc_aging_ctrl_thread_create(struct roc_npc *roc_npc, diff --git
>a/drivers/common/cnxk/roc_platform.h
>b/drivers/common/cnxk/roc_platform.h
>index ad0d1624a3..1e535a527d 100644
>--- a/drivers/common/cnxk/roc_platform.h
>+++ b/drivers/common/cnxk/roc_platform.h
>@@ -145,6 +145,12 @@
> #define plt_thread_create_control    rte_thread_create_internal_control
> #define plt_thread_join              rte_thread_join
>
>+static inline bool
>+plt_thread_is_valid(rte_thread_t thr)
>+{
>+ return thr.opaque_id ? true : false;
>+}
>+
> #define plt_intr_efd_counter_size_get rte_intr_efd_counter_size_get  #define
>plt_intr_efd_counter_size_set rte_intr_efd_counter_size_set  #define
>plt_intr_vec_list_index_get rte_intr_vec_list_index_get

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2023-09-28 13:49 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-27 11:59 [PATCH v1 0/2] add support for flow aging in CNXK driver Ankur Dwivedi
2023-07-27 11:59 ` [PATCH v1 1/2] common/cnxk: add support to get aged flows Ankur Dwivedi
2023-07-27 11:59 ` [PATCH v1 2/2] net/cnxk: add get flow aged ops Ankur Dwivedi
2023-08-08  8:49 ` [PATCH v2 0/2] add support for flow aging in CNXK driver Ankur Dwivedi
2023-08-08  8:49   ` [PATCH v2 1/2] common/cnxk: add support to get aged flows Ankur Dwivedi
2023-08-14  6:56     ` Jerin Jacob
2023-09-28  8:13       ` Jerin Jacob
2023-09-28 13:49         ` [EXT] " Ankur Dwivedi
2023-08-08  8:49   ` [PATCH v2 2/2] net/cnxk: add get flow aged ops Ankur Dwivedi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).