DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH v1 0/5] Fixes for release 24.07
@ 2024-10-04 15:06 Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 1/5] net/ntnic: update NT NiC PMD driver with FPGA version Serhii Iliushyk
                   ` (51 more replies)
  0 siblings, 52 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev; +Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit

*** BLURB HERE ***

Danylo Vodopianov (2):
  net/ntnic: fix coverity issues:
  net/ntnic: extend and fix logging implementation

Oleksandr Kolomeiets (3):
  net/ntnic: update NT NiC PMD driver with FPGA version
  net/ntnic: update documentation
  net/ntnic: remove extra calling of the API for release port

 .mailmap                                      |  1 +
 doc/guides/nics/features/ntnic.ini            |  1 +
 doc/guides/nics/ntnic.rst                     | 29 +++++++
 drivers/net/ntnic/meson.build                 |  2 +-
 drivers/net/ntnic/nim/i2c_nim.c               | 16 ++--
 .../nthw/core/nt200a0x/nthw_fpga_nt200a0x.c   |  2 +-
 .../core/nt200a0x/reset/nthw_fpga_rst9563.c   | 12 +--
 .../nt200a0x/reset/nthw_fpga_rst_nt200a0x.c   | 12 +--
 drivers/net/ntnic/nthw/core/nthw_fpga.c       | 24 +++---
 drivers/net/ntnic/nthw/core/nthw_hif.c        | 18 +----
 drivers/net/ntnic/nthw/core/nthw_iic.c        |  6 +-
 drivers/net/ntnic/nthw/core/nthw_pcie3.c      |  2 +-
 .../net/ntnic/nthw/model/nthw_fpga_model.c    | 75 ++++++++++---------
 ...9_0000.c => nthw_fpga_9563_055_049_0000.c} | 34 ++++-----
 .../nthw/supported/nthw_fpga_instances.c      |  2 +-
 .../nthw/supported/nthw_fpga_instances.h      |  2 +-
 drivers/net/ntnic/ntlog/ntlog.c               |  2 -
 drivers/net/ntnic/ntlog/ntlog.h               | 63 +++++++++++-----
 drivers/net/ntnic/ntnic_ethdev.c              | 63 +++++++++-------
 drivers/net/ntnic/ntnic_vfio.c                |  5 +-
 drivers/net/ntnic/ntutil/nt_util.c            |  3 +-
 21 files changed, 215 insertions(+), 159 deletions(-)
 rename drivers/net/ntnic/nthw/supported/{nthw_fpga_9563_055_039_0000.c => nthw_fpga_9563_055_049_0000.c} (98%)

-- 
2.45.0


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

* [PATCH v1 1/5] net/ntnic: update NT NiC PMD driver with FPGA version
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
@ 2024-10-04 15:06 ` Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 2/5] net/ntnic: fix coverity issues: Serhii Iliushyk
                   ` (50 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

Update base FPGA files to the new version(39->49)
Fix code style problems

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/meson.build                 |  2 +-
 .../net/ntnic/nthw/model/nthw_fpga_model.c    | 11 +++---
 ...9_0000.c => nthw_fpga_9563_055_049_0000.c} | 34 +++++++++----------
 .../nthw/supported/nthw_fpga_instances.c      |  2 +-
 .../nthw/supported/nthw_fpga_instances.h      |  2 +-
 5 files changed, 25 insertions(+), 26 deletions(-)
 rename drivers/net/ntnic/nthw/supported/{nthw_fpga_9563_055_039_0000.c => nthw_fpga_9563_055_049_0000.c} (98%)

diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 9df2378f7c..e9f2110b8f 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -26,7 +26,7 @@ sources = files(
         'link_mgmt/link_100g/nt4ga_link_100g.c',
         'link_mgmt/nt4ga_link.c',
         'nim/i2c_nim.c',
-        'nthw/supported/nthw_fpga_9563_055_039_0000.c',
+        'nthw/supported/nthw_fpga_9563_055_049_0000.c',
         'nthw/supported/nthw_fpga_instances.c',
         'nthw/supported/nthw_fpga_mod_str_map.c',
         'nthw/core/nt200a0x/clock_profiles/nthw_fpga_clk9563.c',
diff --git a/drivers/net/ntnic/nthw/model/nthw_fpga_model.c b/drivers/net/ntnic/nthw/model/nthw_fpga_model.c
index 8ed00248ea..f8e6da2d7f 100644
--- a/drivers/net/ntnic/nthw/model/nthw_fpga_model.c
+++ b/drivers/net/ntnic/nthw/model/nthw_fpga_model.c
@@ -31,8 +31,7 @@ static const char *get_bus_name(int n_bus_type_id)
 	if (n_bus_type_id >= 1 && n_bus_type_id <= (int)ARRAY_SIZE(sa_nthw_fpga_bus_type_str))
 		return sa_nthw_fpga_bus_type_str[n_bus_type_id];
 
-	else
-		return "ERR";
+	return "ERR";
 }
 
 /*
@@ -1146,16 +1145,16 @@ static int nthw_field_wait_cond32(const nthw_field_t *p, enum nthw_field_match e
 	while (true) {
 		uint32_t val = nthw_field_get_updated(p);
 
-		if (e_match == NTHW_FIELD_MATCH_SET_ANY && val != 0) {
+		if (e_match == NTHW_FIELD_MATCH_SET_ANY && val != 0)
 			return 0;
 
-		} else if (e_match == NTHW_FIELD_MATCH_SET_ALL && val == n_mask) {
+		if (e_match == NTHW_FIELD_MATCH_SET_ALL && val == n_mask)
 			return 0;
 
-		} else if (e_match == NTHW_FIELD_MATCH_CLR_ALL && val == 0) {
+		if (e_match == NTHW_FIELD_MATCH_CLR_ALL && val == 0)
 			return 0;
 
-		} else if (e_match == NTHW_FIELD_MATCH_CLR_ANY) {
+		if (e_match == NTHW_FIELD_MATCH_CLR_ANY) {
 			uint32_t mask = nthw_field_get_mask(p);
 
 			if (val != mask)
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_039_0000.c b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
similarity index 98%
rename from drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_039_0000.c
rename to drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
index e26a275958..cbebcff541 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_039_0000.c
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
@@ -179,7 +179,7 @@ static nthw_fpga_register_init_s gpio_phy_registers[] = {
 };
 
 static nthw_fpga_field_init_s hif_build_time_fields[] = {
-	{ HIF_BUILD_TIME_TIME, 32, 0, 1713859545 },
+	{ HIF_BUILD_TIME_TIME, 32, 0, 1726740521 },
 };
 
 static nthw_fpga_field_init_s hif_config_fields[] = {
@@ -202,7 +202,7 @@ static nthw_fpga_field_init_s hif_prod_id_ex_fields[] = {
 
 static nthw_fpga_field_init_s hif_prod_id_lsb_fields[] = {
 	{ HIF_PROD_ID_LSB_GROUP_ID, 16, 16, 9563 },
-	{ HIF_PROD_ID_LSB_REV_ID, 8, 0, 39 },
+	{ HIF_PROD_ID_LSB_REV_ID, 8, 0, 49 },
 	{ HIF_PROD_ID_LSB_VER_ID, 8, 8, 55 },
 };
 
@@ -247,27 +247,27 @@ static nthw_fpga_field_init_s hif_test1_fields[] = {
 };
 
 static nthw_fpga_field_init_s hif_uuid0_fields[] = {
-	{ HIF_UUID0_UUID0, 32, 0, 1237800326 },
+	{ HIF_UUID0_UUID0, 32, 0, 1021928912 },
 };
 
 static nthw_fpga_field_init_s hif_uuid1_fields[] = {
-	{ HIF_UUID1_UUID1, 32, 0, 3057550372 },
+	{ HIF_UUID1_UUID1, 32, 0, 2998983545 },
 };
 
 static nthw_fpga_field_init_s hif_uuid2_fields[] = {
-	{ HIF_UUID2_UUID2, 32, 0, 2445752330 },
+	{ HIF_UUID2_UUID2, 32, 0, 827210969 },
 };
 
 static nthw_fpga_field_init_s hif_uuid3_fields[] = {
-	{ HIF_UUID3_UUID3, 32, 0, 1864147557 },
+	{ HIF_UUID3_UUID3, 32, 0, 462142918 },
 };
 
 static nthw_fpga_register_init_s hif_registers[] = {
-	{ HIF_BUILD_TIME, 16, 32, NTHW_FPGA_REG_TYPE_RO, 1713859545, 1, hif_build_time_fields },
+	{ HIF_BUILD_TIME, 16, 32, NTHW_FPGA_REG_TYPE_RO, 1726740521, 1, hif_build_time_fields },
 	{ HIF_CONFIG, 24, 7, NTHW_FPGA_REG_TYPE_RW, 0, 3, hif_config_fields },
 	{ HIF_CONTROL, 40, 13, NTHW_FPGA_REG_TYPE_MIXED, 4097, 3, hif_control_fields },
 	{ HIF_PROD_ID_EX, 112, 32, NTHW_FPGA_REG_TYPE_RO, 1, 3, hif_prod_id_ex_fields },
-	{ HIF_PROD_ID_LSB, 0, 32, NTHW_FPGA_REG_TYPE_RO, 626734887, 3, hif_prod_id_lsb_fields },
+	{ HIF_PROD_ID_LSB, 0, 32, NTHW_FPGA_REG_TYPE_RO, 626734897, 3, hif_prod_id_lsb_fields },
 	{ HIF_PROD_ID_MSB, 8, 22, NTHW_FPGA_REG_TYPE_RO, 200, 2, hif_prod_id_msb_fields },
 	{ HIF_SAMPLE_TIME, 96, 1, NTHW_FPGA_REG_TYPE_WO, 0, 1, hif_sample_time_fields },
 	{ HIF_STATUS, 32, 10, NTHW_FPGA_REG_TYPE_MIXED, 0, 3, hif_status_fields },
@@ -277,10 +277,10 @@ static nthw_fpga_register_init_s hif_registers[] = {
 	{ HIF_STAT_TX, 80, 32, NTHW_FPGA_REG_TYPE_RO, 0, 1, hif_stat_tx_fields },
 	{ HIF_TEST0, 48, 32, NTHW_FPGA_REG_TYPE_RW, 287454020, 1, hif_test0_fields },
 	{ HIF_TEST1, 56, 32, NTHW_FPGA_REG_TYPE_RW, 2864434397, 1, hif_test1_fields },
-	{ HIF_UUID0, 128, 32, NTHW_FPGA_REG_TYPE_RO, 1237800326, 1, hif_uuid0_fields },
-	{ HIF_UUID1, 144, 32, NTHW_FPGA_REG_TYPE_RO, 3057550372, 1, hif_uuid1_fields },
-	{ HIF_UUID2, 160, 32, NTHW_FPGA_REG_TYPE_RO, 2445752330, 1, hif_uuid2_fields },
-	{ HIF_UUID3, 176, 32, NTHW_FPGA_REG_TYPE_RO, 1864147557, 1, hif_uuid3_fields },
+	{ HIF_UUID0, 128, 32, NTHW_FPGA_REG_TYPE_RO, 1021928912, 1, hif_uuid0_fields },
+	{ HIF_UUID1, 144, 32, NTHW_FPGA_REG_TYPE_RO, 2998983545, 1, hif_uuid1_fields },
+	{ HIF_UUID2, 160, 32, NTHW_FPGA_REG_TYPE_RO, 827210969, 1, hif_uuid2_fields },
+	{ HIF_UUID3, 176, 32, NTHW_FPGA_REG_TYPE_RO, 462142918, 1, hif_uuid3_fields },
 };
 
 static nthw_fpga_field_init_s iic_adr_fields[] = {
@@ -1071,7 +1071,7 @@ static nthw_fpga_module_init_s fpga_modules[] = {
 
 static nthw_fpga_prod_param_s product_parameters[] = {
 	{ NT_BUILD_NUMBER, 0 },
-	{ NT_BUILD_TIME, 1713859545 },
+	{ NT_BUILD_TIME, 1726740521 },
 	{ NT_CATEGORIES, 64 },
 	{ NT_CAT_DCT_PRESENT, 0 },
 	{ NT_CAT_END_OFS_SUPPORT, 0 },
@@ -1101,7 +1101,7 @@ static nthw_fpga_prod_param_s product_parameters[] = {
 	{ NT_FLM_CACHE, 1 },
 	{ NT_FLM_CATEGORIES, 32 },
 	{ NT_FLM_ENTRY_SIZE, 64 },
-	{ NT_FLM_LOAD_APS_MAX, 260000000 },
+	{ NT_FLM_LOAD_APS_MAX, 270000000 },
 	{ NT_FLM_LOAD_LPS_MAX, 300000000 },
 	{ NT_FLM_PRESENT, 1 },
 	{ NT_FLM_PRIOS, 4 },
@@ -1176,7 +1176,7 @@ static nthw_fpga_prod_param_s product_parameters[] = {
 	{ NT_QUEUES, 128 },
 	{ NT_RAC_RAB_INTERFACES, 3 },
 	{ NT_RAC_RAB_OB_UPDATE, 0 },
-	{ NT_REVISION_ID, 39 },
+	{ NT_REVISION_ID, 49 },
 	{ NT_RMC_LAG_GROUPS, 1 },
 	{ NT_RMC_PRESENT, 1 },
 	{ NT_ROA_CATEGORIES, 1024 },
@@ -1225,6 +1225,6 @@ static nthw_fpga_prod_param_s product_parameters[] = {
 	{ 0, -1 },	/* END */
 };
 
-nthw_fpga_prod_init_s nthw_fpga_9563_055_039_0000 = {
-	200, 9563, 55, 39, 0, 0, 1713859545, 152, product_parameters, 15, fpga_modules,
+nthw_fpga_prod_init_s nthw_fpga_9563_055_049_0000 = {
+	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 15, fpga_modules,
 };
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_instances.c b/drivers/net/ntnic/nthw/supported/nthw_fpga_instances.c
index 4fe7f7ea94..c8a310c415 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_instances.c
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_instances.c
@@ -5,4 +5,4 @@
 
 
 #include "nthw_fpga_instances.h"
-nthw_fpga_prod_init_s *nthw_fpga_instances[] = { &nthw_fpga_9563_055_039_0000, NULL };
+nthw_fpga_prod_init_s *nthw_fpga_instances[] = { &nthw_fpga_9563_055_049_0000, NULL };
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_instances.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_instances.h
index d0e6f7b429..3e5983f763 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_instances.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_instances.h
@@ -6,4 +6,4 @@
 
 #include "fpga_model.h"
 extern nthw_fpga_prod_init_s *nthw_fpga_instances[];
-extern nthw_fpga_prod_init_s nthw_fpga_9563_055_039_0000;
+extern nthw_fpga_prod_init_s nthw_fpga_9563_055_049_0000;
-- 
2.45.0


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

* [PATCH v1 2/5] net/ntnic: fix coverity issues:
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 1/5] net/ntnic: update NT NiC PMD driver with FPGA version Serhii Iliushyk
@ 2024-10-04 15:06 ` Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 3/5] net/ntnic: update documentation Serhii Iliushyk
                   ` (49 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Danylo Vodopianov, Thomas Monjalon

From: Danylo Vodopianov <dvo-plv@napatech.com>

CI founc couple coverity problems which were fixed in this commit.

CID 440550, 440551, 440545, 440553, 440552, 440547:
Null pointer dereferences  (REVERSE_INULL)
These issues were fixed by reworking variable NULL checking and adding
NULL checking before var using.

CID 440543:  Incorrect expression  (IDENTICAL_BRANCHES)
This issue was fixed by removing useless if statements from the code.

CID 440548:  Null pointer dereferences  (FORWARD_NULL)
This issue was fixed by adding NULL checking before
mp_fld_rst_serdes_rx var using.

CID 440546:  Resource leaks  (RESOURCE_LEAK)
This issue was fixed by moving NULL checking before var using.

CID 440540:  Error handling issues  (CHECKED_RETURN)
This issue was fixed with return value checking adding.

CID 440549:  (OVERRUN)
This issue was fixed with array edge values fixing.

Coverity issue: 440550
Fixes: 51052594f795 ("net/ntnic: add physical layer control module")

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 .mailmap                                      |  1 +
 .../nt200a0x/reset/nthw_fpga_rst_nt200a0x.c   |  2 +-
 drivers/net/ntnic/nthw/core/nthw_fpga.c       | 24 ++++----
 drivers/net/ntnic/nthw/core/nthw_hif.c        | 18 +-----
 .../net/ntnic/nthw/model/nthw_fpga_model.c    | 58 ++++++++++---------
 drivers/net/ntnic/ntnic_ethdev.c              | 21 +++----
 drivers/net/ntnic/ntnic_vfio.c                |  5 +-
 drivers/net/ntnic/ntutil/nt_util.c            |  3 +-
 8 files changed, 66 insertions(+), 66 deletions(-)

diff --git a/.mailmap b/.mailmap
index d2f30cf8eb..3ea3a70762 100644
--- a/.mailmap
+++ b/.mailmap
@@ -295,6 +295,7 @@ Dan Nowlin <dan.nowlin@intel.com>
 Danny Patel <dannyp@marvell.com>
 Danny Zhou <danny.zhou@intel.com>
 Dan Wei <dan.wei@intel.com>
+Danylo Vodopianov <dvo-plv@napatech.com>
 Dapeng Yu <dapengx.yu@intel.com>
 Darek Stojaczyk <dariusz.stojaczyk@intel.com>
 Daria Kolistratova <daria.kolistratova@intel.com>
diff --git a/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c
index ea0276a90c..aa0d97dafd 100644
--- a/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c
+++ b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c
@@ -263,7 +263,7 @@ static int nthw_fpga_rst_nt200a0x_reset(nthw_fpga_t *p_fpga,
 	if (p->mp_fld_rst_serdes_rx)
 		nthw_field_set_flush(p->mp_fld_rst_serdes_rx);	/* 0x03 2 ports */
 
-	if (p->mp_fld_rst_serdes_rx_datapath) {
+	if (p->mp_fld_rst_serdes_rx_datapath && p->mp_fld_rst_serdes_rx) {
 		nthw_field_set_flush(p->mp_fld_rst_serdes_rx_datapath);
 		nthw_field_clr_flush(p->mp_fld_rst_serdes_rx);
 	}
diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga.c b/drivers/net/ntnic/nthw/core/nthw_fpga.c
index d70205e5e3..082d3950bb 100644
--- a/drivers/net/ntnic/nthw/core/nthw_fpga.c
+++ b/drivers/net/ntnic/nthw/core/nthw_fpga.c
@@ -217,19 +217,19 @@ int nthw_fpga_init(struct fpga_info_s *p_fpga_info)
 	n_fpga_ident = p_fpga_info->n_fpga_ident;
 
 	p_fpga_mgr = nthw_fpga_mgr_new();
-	nthw_fpga_mgr_init(p_fpga_mgr, nthw_fpga_instances,
-		(const void *)sa_nthw_fpga_mod_str_map);
-	nthw_fpga_mgr_log_dump(p_fpga_mgr);
-	p_fpga = nthw_fpga_mgr_query_fpga(p_fpga_mgr, n_fpga_ident, p_fpga_info);
-	p_fpga_info->mp_fpga = p_fpga;
-
-	if (p_fpga == NULL) {
-		NT_LOG(ERR, NTHW, "%s: Unsupported FPGA: %s (%08X)\n", p_adapter_id_str,
-			s_fpga_prod_ver_rev_str, p_fpga_info->n_fpga_build_time);
-		return -1;
-	}
-
 	if (p_fpga_mgr) {
+		nthw_fpga_mgr_init(p_fpga_mgr, nthw_fpga_instances,
+			(const void *)sa_nthw_fpga_mod_str_map);
+		nthw_fpga_mgr_log_dump(p_fpga_mgr);
+		p_fpga = nthw_fpga_mgr_query_fpga(p_fpga_mgr, n_fpga_ident, p_fpga_info);
+		p_fpga_info->mp_fpga = p_fpga;
+
+		if (p_fpga == NULL) {
+			NT_LOG(ERR, NTHW, "%s: Unsupported FPGA: %s (%08X)\n", p_adapter_id_str,
+				s_fpga_prod_ver_rev_str, p_fpga_info->n_fpga_build_time);
+			return -1;
+		}
+
 		nthw_fpga_mgr_delete(p_fpga_mgr);
 		p_fpga_mgr = NULL;
 	}
diff --git a/drivers/net/ntnic/nthw/core/nthw_hif.c b/drivers/net/ntnic/nthw/core/nthw_hif.c
index f05e1a0c51..cc2aaf83e4 100644
--- a/drivers/net/ntnic/nthw/core/nthw_hif.c
+++ b/drivers/net/ntnic/nthw/core/nthw_hif.c
@@ -83,23 +83,11 @@ int nthw_hif_init(nthw_hif_t *p, nthw_fpga_t *p_fpga, int n_instance)
 		p->mn_instance, p->mn_fpga_hif_ref_clk_freq, p->mn_fpga_param_hif_per_ps);
 
 	p->mp_reg_build_seed = NULL;	/* Reg/Fld not present on HIF */
-
-	if (p->mp_reg_build_seed)
-		p->mp_fld_build_seed = NULL;	/* Reg/Fld not present on HIF */
-	else
-		p->mp_fld_build_seed = NULL;
+	p->mp_fld_build_seed = NULL;	/* Reg/Fld not present on HIF */
 
 	p->mp_reg_core_speed = NULL;	/* Reg/Fld not present on HIF */
-
-	if (p->mp_reg_core_speed) {
-		p->mp_fld_core_speed = NULL;	/* Reg/Fld not present on HIF */
-		p->mp_fld_ddr3_speed = NULL;	/* Reg/Fld not present on HIF */
-
-	} else {
-		p->mp_reg_core_speed = NULL;
-		p->mp_fld_core_speed = NULL;
-		p->mp_fld_ddr3_speed = NULL;
-	}
+	p->mp_fld_core_speed = NULL;	/* Reg/Fld not present on HIF */
+	p->mp_fld_ddr3_speed = NULL;	/* Reg/Fld not present on HIF */
 
 	/* Optional registers since: 2018-04-25 */
 	p->mp_reg_int_mask = NULL;	/* Reg/Fld not present on HIF */
diff --git a/drivers/net/ntnic/nthw/model/nthw_fpga_model.c b/drivers/net/ntnic/nthw/model/nthw_fpga_model.c
index f8e6da2d7f..14d1ebf5fa 100644
--- a/drivers/net/ntnic/nthw/model/nthw_fpga_model.c
+++ b/drivers/net/ntnic/nthw/model/nthw_fpga_model.c
@@ -28,7 +28,7 @@ static const char *const sa_nthw_fpga_bus_type_str[] = {
 
 static const char *get_bus_name(int n_bus_type_id)
 {
-	if (n_bus_type_id >= 1 && n_bus_type_id <= (int)ARRAY_SIZE(sa_nthw_fpga_bus_type_str))
+	if (n_bus_type_id >= 0 && n_bus_type_id < (int)ARRAY_SIZE(sa_nthw_fpga_bus_type_str))
 		return sa_nthw_fpga_bus_type_str[n_bus_type_id];
 
 	return "ERR";
@@ -678,45 +678,51 @@ void nthw_register_set_debug_mode(nthw_register_t *p, unsigned int debug_mode)
 static int nthw_register_read_data(const nthw_register_t *p)
 {
 	int rc = -1;
+	if (p) {
+		if (p->mp_owner) {
+			const int n_bus_type_id = nthw_module_get_bus(p->mp_owner);
+			const uint32_t addr = p->mn_addr;
+			const uint32_t len = p->mn_len;
+			uint32_t *const p_data = p->mp_shadow;
+			const bool trc = (p->mn_debug_mode & NTHW_REG_TRACE_ON_READ);
 
-	const int n_bus_type_id = nthw_module_get_bus(p->mp_owner);
-	const uint32_t addr = p->mn_addr;
-	const uint32_t len = p->mn_len;
-	uint32_t *const p_data = p->mp_shadow;
-	const bool trc = (p->mn_debug_mode & NTHW_REG_TRACE_ON_READ);
+			struct fpga_info_s *p_fpga_info = NULL;
 
-	struct fpga_info_s *p_fpga_info = NULL;
+			if (p->mp_owner->mp_owner)
+				p_fpga_info = p->mp_owner->mp_owner->p_fpga_info;
 
-	if (p && p->mp_owner && p->mp_owner->mp_owner)
-		p_fpga_info = p->mp_owner->mp_owner->p_fpga_info;
+			assert(p_fpga_info);
+			assert(p_data);
 
-	assert(p_fpga_info);
-	assert(p_data);
-
-	rc = nthw_read_data(p_fpga_info, trc, n_bus_type_id, addr, len, p_data);
+			rc = nthw_read_data(p_fpga_info, trc, n_bus_type_id, addr, len, p_data);
+		}
+	}
 	return rc;
 }
 
 static int nthw_register_write_data(const nthw_register_t *p, uint32_t cnt)
 {
 	int rc = -1;
+	if (p) {
+		if (p->mp_owner) {
+			const int n_bus_type_id = nthw_module_get_bus(p->mp_owner);
+			const uint32_t addr = p->mn_addr;
+			const uint32_t len = p->mn_len;
+			uint32_t *const p_data = p->mp_shadow;
+			const bool trc = (p->mn_debug_mode & NTHW_REG_TRACE_ON_WRITE);
 
-	const int n_bus_type_id = nthw_module_get_bus(p->mp_owner);
-	const uint32_t addr = p->mn_addr;
-	const uint32_t len = p->mn_len;
-	uint32_t *const p_data = p->mp_shadow;
-	const bool trc = (p->mn_debug_mode & NTHW_REG_TRACE_ON_WRITE);
+			struct fpga_info_s *p_fpga_info = NULL;
 
-	struct fpga_info_s *p_fpga_info = NULL;
+			if (p->mp_owner->mp_owner)
+				p_fpga_info = p->mp_owner->mp_owner->p_fpga_info;
 
-	if (p && p->mp_owner && p->mp_owner->mp_owner)
-		p_fpga_info = p->mp_owner->mp_owner->p_fpga_info;
-
-	assert(p_fpga_info);
-	assert(p_data);
-
-	rc = nthw_write_data(p_fpga_info, trc, n_bus_type_id, addr, (len * cnt), p_data);
+			assert(p_fpga_info);
+			assert(p_data);
 
+			rc = nthw_write_data(p_fpga_info, trc, n_bus_type_id, addr, (len * cnt),
+				p_data);
+		}
+	}
 	return rc;
 }
 
diff --git a/drivers/net/ntnic/ntnic_ethdev.c b/drivers/net/ntnic/ntnic_ethdev.c
index 8568798ec8..f351469d0a 100644
--- a/drivers/net/ntnic/ntnic_ethdev.c
+++ b/drivers/net/ntnic/ntnic_ethdev.c
@@ -42,7 +42,7 @@ static struct drv_s *_g_p_drv[NUM_ADAPTER_MAX] = { NULL };
 static void
 store_pdrv(struct drv_s *p_drv)
 {
-	if (p_drv->adapter_no > NUM_ADAPTER_MAX) {
+	if (p_drv->adapter_no >= NUM_ADAPTER_MAX) {
 		NT_LOG(ERR, NTNIC,
 			"Internal error adapter number %u out of range. Max number of adapters: %u\n",
 			p_drv->adapter_no, NUM_ADAPTER_MAX);
@@ -384,16 +384,17 @@ eth_dev_close(struct rte_eth_dev *eth_dev)
 	internals->p_drv = NULL;
 
 	rte_eth_dev_release_port(eth_dev);
+	if (p_drv) {
+		/* decrease initialized ethernet devices */
+		p_drv->n_eth_dev_init_count--;
 
-	/* decrease initialized ethernet devices */
-	p_drv->n_eth_dev_init_count--;
-
-	/*
-	 * rte_pci_dev has no private member for p_drv
-	 * wait until all rte_eth_dev's are closed - then close adapters via p_drv
-	 */
-	if (!p_drv->n_eth_dev_init_count && p_drv)
-		drv_deinit(p_drv);
+		/*
+		 * rte_pci_dev has no private member for p_drv
+		 * wait until all rte_eth_dev's are closed - then close adapters via p_drv
+		 */
+		if (!p_drv->n_eth_dev_init_count)
+			drv_deinit(p_drv);
+	}
 
 	return 0;
 }
diff --git a/drivers/net/ntnic/ntnic_vfio.c b/drivers/net/ntnic/ntnic_vfio.c
index f4433152b7..0542b1ce62 100644
--- a/drivers/net/ntnic/ntnic_vfio.c
+++ b/drivers/net/ntnic/ntnic_vfio.c
@@ -49,6 +49,7 @@ vfio_get(int vf_num)
 int
 nt_vfio_setup(struct rte_pci_device *dev)
 {
+	int ret;
 	char devname[RTE_DEV_NAME_MAX_LEN] = { 0 };
 	int iommu_group_num;
 	int vf_num;
@@ -71,7 +72,9 @@ nt_vfio_setup(struct rte_pci_device *dev)
 	vfio->iova_addr = START_VF_IOVA;
 
 	rte_pci_device_name(&dev->addr, devname, RTE_DEV_NAME_MAX_LEN);
-	rte_vfio_get_group_num(rte_pci_get_sysfs_path(), devname, &iommu_group_num);
+	ret = rte_vfio_get_group_num(rte_pci_get_sysfs_path(), devname, &iommu_group_num);
+	if (ret <= 0)
+		return -1;
 
 	if (vf_num == 0) {
 		/* use default container for pf0 */
diff --git a/drivers/net/ntnic/ntutil/nt_util.c b/drivers/net/ntnic/ntutil/nt_util.c
index 9904e3df3b..a69a8e10c1 100644
--- a/drivers/net/ntnic/ntutil/nt_util.c
+++ b/drivers/net/ntnic/ntutil/nt_util.c
@@ -31,7 +31,8 @@ uint64_t nt_os_get_time_monotonic_counter(void)
 /* Allocation size matching minimum alignment of specified size */
 uint64_t nt_util_align_size(uint64_t size)
 {
-	return 1 << rte_log2_u64(size);
+	uint64_t alignment_size = 1ULL << rte_log2_u64(size);
+	return alignment_size;
 }
 
 void nt_util_vfio_init(struct nt_util_vfio_impl *impl)
-- 
2.45.0


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

* [PATCH v1 3/5] net/ntnic: update documentation
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 1/5] net/ntnic: update NT NiC PMD driver with FPGA version Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 2/5] net/ntnic: fix coverity issues: Serhii Iliushyk
@ 2024-10-04 15:06 ` Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 4/5] net/ntnic: remove extra calling of the API for release port Serhii Iliushyk
                   ` (48 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

Add forgotten feature to the documentation (ntnic.ini)

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 doc/guides/nics/features/ntnic.ini | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/guides/nics/features/ntnic.ini b/doc/guides/nics/features/ntnic.ini
index 0a74817fcf..b6d92c7ee1 100644
--- a/doc/guides/nics/features/ntnic.ini
+++ b/doc/guides/nics/features/ntnic.ini
@@ -6,6 +6,7 @@
 [Features]
 FW version           = Y
 Speed capabilities   = Y
+Link status          = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
 Linux                = Y
-- 
2.45.0


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

* [PATCH v1 4/5] net/ntnic: remove extra calling of the API for release port
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (2 preceding siblings ...)
  2024-10-04 15:06 ` [PATCH v1 3/5] net/ntnic: update documentation Serhii Iliushyk
@ 2024-10-04 15:06 ` Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 5/5] net/ntnic: extend and fix logging implementation Serhii Iliushyk
                   ` (47 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

During rte_eth_dev_close execution,
eth_dev_close function exported by ntnic is called,
followed by a call to rte_eth_dev_release_port.

Since there is no possible returns between the calls,
calling rte_eth_dev_release_port from eth_dev_close
is redundant and error-prone.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/ntnic_ethdev.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/ntnic/ntnic_ethdev.c b/drivers/net/ntnic/ntnic_ethdev.c
index f351469d0a..52ca8f2844 100644
--- a/drivers/net/ntnic/ntnic_ethdev.c
+++ b/drivers/net/ntnic/ntnic_ethdev.c
@@ -383,7 +383,6 @@ eth_dev_close(struct rte_eth_dev *eth_dev)
 
 	internals->p_drv = NULL;
 
-	rte_eth_dev_release_port(eth_dev);
 	if (p_drv) {
 		/* decrease initialized ethernet devices */
 		p_drv->n_eth_dev_init_count--;
-- 
2.45.0


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

* [PATCH v1 5/5] net/ntnic: extend and fix logging implementation
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (3 preceding siblings ...)
  2024-10-04 15:06 ` [PATCH v1 4/5] net/ntnic: remove extra calling of the API for release port Serhii Iliushyk
@ 2024-10-04 15:06 ` Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 00/31] Enable flow filter initialization Serhii Iliushyk
                   ` (46 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Danylo Vodopianov, Oleksandr Kolomeiets

From: Danylo Vodopianov <dvo-plv@napatech.com>

Add suffixes logging
Fix the issue with the configuration log level for a specific module
Fix extended debug logging
        3-letter abbreviation for log type
Update documentation
new log modules were added
        Log level in functions that initialize feature operations
        was updated from INFO to DEBUG to avoid noisy traces
        during driver startup.
log level for ops init was changed
nim and PMD modules was replaced with NTNIC
        NIM module was replaced with NTNIC according to the ntnic log
        convention.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 doc/guides/nics/ntnic.rst                     | 29 +++++++++
 drivers/net/ntnic/nim/i2c_nim.c               | 16 ++---
 .../nthw/core/nt200a0x/nthw_fpga_nt200a0x.c   |  2 +-
 .../core/nt200a0x/reset/nthw_fpga_rst9563.c   | 12 ++--
 .../nt200a0x/reset/nthw_fpga_rst_nt200a0x.c   | 10 +--
 drivers/net/ntnic/nthw/core/nthw_iic.c        |  6 +-
 drivers/net/ntnic/nthw/core/nthw_pcie3.c      |  2 +-
 .../net/ntnic/nthw/model/nthw_fpga_model.c    |  6 +-
 drivers/net/ntnic/ntlog/ntlog.c               |  2 -
 drivers/net/ntnic/ntlog/ntlog.h               | 63 +++++++++++++------
 drivers/net/ntnic/ntnic_ethdev.c              | 41 ++++++------
 11 files changed, 123 insertions(+), 66 deletions(-)

diff --git a/doc/guides/nics/ntnic.rst b/doc/guides/nics/ntnic.rst
index 88d95832e5..7ac92c891c 100644
--- a/doc/guides/nics/ntnic.rst
+++ b/doc/guides/nics/ntnic.rst
@@ -49,3 +49,32 @@ which is required for the PMD to use vfio-pci on the PF.
 This support has been back-ported to older Linux distributions
 and they are also supported.
 If vfio-pci is not required, kernel version 4.18 is supported.
+
+
+Logging and Debugging
+---------------------
+
+NTNIC supports several groups of logging that can be enabled with ``--log-level``
+parameter:
+
+- NTNIC.
+
+    Logging info from the main PMD code. i.e. code that is related to DPDK::
+
+        --log-level=pmd.net.ntnic.ntnic,8
+
+- NTHW.
+
+    Logging info from NTHW. i.e. code that is related to the FPGA and the Adapter::
+
+        --log-level=pmd.net.ntnic.nthw,8
+
+- FILTER.
+
+    Logging info from filter. i.e. code that is related to the binary filter::
+
+        --log-level=pmd.net.ntnic.filter,8
+
+To enable logging on all levels use wildcard in the following way::
+
+    --log-level=pmd.net.ntnic.*,8
diff --git a/drivers/net/ntnic/nim/i2c_nim.c b/drivers/net/ntnic/nim/i2c_nim.c
index e6e256b062..310d5d2598 100644
--- a/drivers/net/ntnic/nim/i2c_nim.c
+++ b/drivers/net/ntnic/nim/i2c_nim.c
@@ -219,7 +219,7 @@ static int i2c_nim_common_construct(nim_i2c_ctx_p ctx)
 		res = -1;
 
 	if (res) {
-		NT_LOG(ERR, PMD, "Can't read NIM id.");
+		NT_LOG(ERR, NTNIC, "Can't read NIM id.");
 		return res;
 	}
 
@@ -308,7 +308,7 @@ static int qsfp_nim_state_build(nim_i2c_ctx_t *ctx, sfp_nim_state_t *state)
 		break;
 
 	default:
-		NT_LOG(INF, NIM, "nim_id = %u is not an QSFP/QSFP+/QSFP28 module\n", ctx->nim_id);
+		NT_LOG(INF, NTNIC, "nim_id = %u is not an QSFP/QSFP+/QSFP28 module\n", ctx->nim_id);
 		res = -1;
 	}
 
@@ -419,7 +419,7 @@ static int qsfpplus_read_basic_data(nim_i2c_ctx_t *ctx)
 		yes_no[ctx->avg_pwr]);
 
 	qsfp_read_vendor_info(ctx);
-	NT_LOG(DBG, PMD,
+	NT_LOG(DBG, NTNIC,
 		"Instance %d: NIM info: (Vendor: %s, PN: %s, SN: %s, Date: %s, Rev: %s)\n",
 		ctx->instance, ctx->vendor_name, ctx->prod_no, ctx->serial_no, ctx->date, ctx->rev);
 
@@ -540,7 +540,7 @@ static bool qsfp28_is_rate_selection_enabled(nim_i2c_ctx_p ctx)
 		(read_byte(ctx, enh_options_reg_addr) >> 2) & 0x03;	/* bit 3..2 */
 
 	if (rate_select_type != 2) {
-		NT_LOG(DBG, PMD, "NIM has unhandled rate select type (%d)", rate_select_type);
+		NT_LOG(DBG, NTNIC, "NIM has unhandled rate select type (%d)", rate_select_type);
 		return false;
 	}
 
@@ -548,7 +548,7 @@ static bool qsfp28_is_rate_selection_enabled(nim_i2c_ctx_p ctx)
 		read_byte(ctx, ext_rate_select_compl_reg_addr) & 0x03;	/* bit 1..0 */
 
 	if (ext_rate_select_ver != 0x02) {
-		NT_LOG(DBG, PMD, "NIM has unhandled extended rate select version (%d)",
+		NT_LOG(DBG, NTNIC, "NIM has unhandled extended rate select version (%d)",
 			ext_rate_select_ver);
 		return false;
 	}
@@ -669,7 +669,7 @@ static void qsfp28_wait_for_ready_after_reset(nim_i2c_ctx_p ctx)
 	 */
 	read_data_lin(ctx, 1, sizeof(ctx->specific_u.qsfp.specific_u.qsfp28.rev_compliance),
 		&ctx->specific_u.qsfp.specific_u.qsfp28.rev_compliance);
-	NT_LOG(DBG, NTHW, "NIM RevCompliance = %d",
+	NT_LOG(DBG, NTHW, "NIM RevCompliance = %d\n",
 		ctx->specific_u.qsfp.specific_u.qsfp28.rev_compliance);
 
 	/* Wait if lane_idx == -1 (all lanes are used) or lane_idx == 0 (the first lane) */
@@ -682,7 +682,7 @@ static void qsfp28_wait_for_ready_after_reset(nim_i2c_ctx_p ctx)
 		init_complete_flag_present = (data & (1 << 4)) != 0;
 	}
 
-	NT_LOG(DBG, NTHW, "NIM InitCompleteFlagPresent = %d", init_complete_flag_present);
+	NT_LOG(DBG, NTHW, "NIM InitCompleteFlagPresent = %d\n", init_complete_flag_present);
 
 	/*
 	 * If the init complete flag is not present then wait 500ms that together with 500ms
@@ -708,7 +708,7 @@ static void qsfp28_wait_for_ready_after_reset(nim_i2c_ctx_p ctx)
 		read_data_lin(ctx, 6, sizeof(data), &data);
 
 		if (data & 0x01) {
-			NT_LOG(DBG, NTHW, "Module ready after %dms", count * 100);
+			NT_LOG(DBG, NTHW, "Module ready after %dms\n", count * 100);
 			break;
 		}
 
diff --git a/drivers/net/ntnic/nthw/core/nt200a0x/nthw_fpga_nt200a0x.c b/drivers/net/ntnic/nthw/core/nt200a0x/nthw_fpga_nt200a0x.c
index 3009e30670..e5e9bb9025 100644
--- a/drivers/net/ntnic/nthw/core/nt200a0x/nthw_fpga_nt200a0x.c
+++ b/drivers/net/ntnic/nthw/core/nt200a0x/nthw_fpga_nt200a0x.c
@@ -71,6 +71,6 @@ static struct nt200a0x_ops nt200a0x_ops = { .nthw_fpga_nt200a0x_init = nthw_fpga
 
 void nt200a0x_ops_init(void)
 {
-	NT_LOG(INF, NTHW, "NT200A0X OPS INIT\n");
+	NT_LOG(DBG, NTHW, "NT200A0X OPS INIT\n");
 	register_nt200a0x_ops(&nt200a0x_ops);
 }
diff --git a/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst9563.c b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst9563.c
index 380f877096..da70379dcb 100644
--- a/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst9563.c
+++ b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst9563.c
@@ -26,7 +26,7 @@ static int nthw_fpga_rst9563_setup(nthw_fpga_t *p_fpga, struct nthw_fpga_rst_nt2
 	p->mn_fpga_version = n_fpga_version;
 	p->mn_fpga_revision = n_fpga_revision;
 
-	NT_LOG_DBGX(DEBUG, NTHW, "%s: FPGA reset setup: FPGA %04d-%02d-%02d\n", p_adapter_id_str,
+	NT_LOG_DBGX(DBG, NTHW, "%s: FPGA reset setup: FPGA %04d-%02d-%02d\n", p_adapter_id_str,
 				n_fpga_product_id, n_fpga_version, n_fpga_revision);
 
 	p_mod_rst = nthw_fpga_query_module(p_fpga, MOD_RST9563, 0);
@@ -212,7 +212,7 @@ static int nthw_fpga_rst9563_init(struct fpga_info_s *p_fpga_info,
 	res = nthw_fpga_rst9563_periph_reset(p_fpga);
 
 	if (res) {
-		NT_LOG_DBGX(DEBUG, NTHW, "%s: ERROR: res=%d\n", p_adapter_id_str, res);
+		NT_LOG_DBGX(DBG, NTHW, "%s: ERROR: res=%d\n", p_adapter_id_str, res);
 		return res;
 	}
 
@@ -220,14 +220,14 @@ static int nthw_fpga_rst9563_init(struct fpga_info_s *p_fpga_info,
 			n_si_labs_clock_synth_i2c_addr);
 
 	if (res) {
-		NT_LOG_DBGX(DEBUG, NTHW, "%s: ERROR: res=%d\n", p_adapter_id_str, res);
+		NT_LOG_DBGX(DBG, NTHW, "%s: ERROR: res=%d\n", p_adapter_id_str, res);
 		return res;
 	}
 
 	res = nthw_fpga_rst9563_setup(p_fpga, p_rst);
 
 	if (res) {
-		NT_LOG_DBGX(DEBUG, NTHW, "%s: ERROR: res=%d\n", p_adapter_id_str, res);
+		NT_LOG_DBGX(DBG, NTHW, "%s: ERROR: res=%d\n", p_adapter_id_str, res);
 		return res;
 	}
 
@@ -235,7 +235,7 @@ static int nthw_fpga_rst9563_init(struct fpga_info_s *p_fpga_info,
 	res = rst_ops != NULL ? rst_ops->nthw_fpga_rst_nt200a0x_reset(p_fpga, p_rst) : -1;
 
 	if (res) {
-		NT_LOG_DBGX(DEBUG, NTHW, "%s: ERROR: res=%d\n", p_adapter_id_str, res);
+		NT_LOG_DBGX(DBG, NTHW, "%s: ERROR: res=%d\n", p_adapter_id_str, res);
 		return res;
 	}
 
@@ -246,6 +246,6 @@ static struct rst9563_ops rst9563_ops = { .nthw_fpga_rst9563_init = nthw_fpga_rs
 
 void rst9563_ops_init(void)
 {
-	NT_LOG(INF, NTHW, "RST9563 OPS INIT\n");
+	NT_LOG(DBG, NTHW, "RST9563 OPS INIT\n");
 	register_rst9563_ops(&rst9563_ops);
 }
diff --git a/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c
index aa0d97dafd..e930d0a09d 100644
--- a/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c
+++ b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c
@@ -221,7 +221,7 @@ static int nthw_fpga_rst_nt200a0x_reset(nthw_fpga_t *p_fpga,
 	int locked;
 	int res = -1;
 
-	NT_LOG_DBGX(DEBUG, NTHW, "%s: FPGA reset sequence: FPGA %04d-%02d-%02d @ HWId%d\n",
+	NT_LOG_DBGX(DBG, NTHW, "%s: FPGA reset sequence: FPGA %04d-%02d-%02d @ HWId%d\n",
 		p_adapter_id_str, n_fpga_product_id, n_fpga_version, n_fpga_revision,
 		n_hw_id);
 	assert(n_fpga_product_id == p_fpga->mn_product_id);
@@ -505,7 +505,7 @@ static int nthw_fpga_rst_nt200a0x_reset(nthw_fpga_t *p_fpga,
 		nthw_field_clr_flush(p->mp_fld_power_pu_nseb);	/* NSEB power down */
 	}
 
-	NT_LOG_DBGX(DEBUG, NTHW, "%s END\n", p_adapter_id_str);
+	NT_LOG_DBGX(DBG, NTHW, "%s END\n", p_adapter_id_str);
 
 	return 0;
 }
@@ -523,7 +523,7 @@ static int nthw_fpga_rst_nt200a0x_init(struct fpga_info_s *p_fpga_info,
 
 	p_fpga = p_fpga_info->mp_fpga;
 
-	NT_LOG_DBGX(DEBUG, NTHW, "%s: RAB init/reset\n", p_adapter_id_str);
+	NT_LOG_DBGX(DBG, NTHW, "%s: RAB init/reset\n", p_adapter_id_str);
 	nthw_rac_rab_reset(p_fpga_info->mp_nthw_rac);
 	nthw_rac_rab_setup(p_fpga_info->mp_nthw_rac);
 
@@ -554,7 +554,7 @@ static int nthw_fpga_rst_nt200a0x_init(struct fpga_info_s *p_fpga_info,
 	p_rst->mn_si_labs_clock_synth_model = n_si_labs_clock_synth_model;
 	p_rst->mn_si_labs_clock_synth_i2c_addr = n_si_labs_clock_synth_i2c_addr;
 	p_rst->mn_hw_id = p_fpga_info->nthw_hw_info.hw_id;
-	NT_LOG_DBGX(DEBUG, NTHW, "%s: Si%04d @ 0x%02x\n", p_adapter_id_str,
+	NT_LOG_DBGX(DBG, NTHW, "%s: Si%04d @ 0x%02x\n", p_adapter_id_str,
 		p_rst->mn_si_labs_clock_synth_model, p_rst->mn_si_labs_clock_synth_i2c_addr);
 
 	return res;
@@ -568,6 +568,6 @@ static struct rst_nt200a0x_ops rst_nt200a0x_ops = { .nthw_fpga_rst_nt200a0x_init
 
 void rst_nt200a0x_ops_init(void)
 {
-	NT_LOG(INF, NTHW, "RST NT200A0X OPS INIT\n");
+	NT_LOG(DBG, NTHW, "RST NT200A0X OPS INIT\n");
 	register_rst_nt200a0x_ops(&rst_nt200a0x_ops);
 }
diff --git a/drivers/net/ntnic/nthw/core/nthw_iic.c b/drivers/net/ntnic/nthw/core/nthw_iic.c
index 7f324dec78..a08f8d90f6 100644
--- a/drivers/net/ntnic/nthw/core/nthw_iic.c
+++ b/drivers/net/ntnic/nthw/core/nthw_iic.c
@@ -422,11 +422,11 @@ int nthw_iic_writebyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint
 		nthw_iic_reg_tx_fifo_write(p, *p_byte, 0, 1);
 
 		if (!nthw_iic_bus_ready(p)) {
-			NT_LOG_DBGX(WARNING, NTHW, "%s: warn: !busReady\n", p_adapter_id_str);
+			NT_LOG_DBGX(WRN, NTHW, "%s: warn: !busReady\n", p_adapter_id_str);
 
 			while (true)
 				if (nthw_iic_bus_ready(p)) {
-					NT_LOG_DBGX(DEBUG, NTHW, "%s: info: busReady\n",
+					NT_LOG_DBGX(DBG, NTHW, "%s: info: busReady\n",
 					p_adapter_id_str);
 					break;
 				}
@@ -435,7 +435,7 @@ int nthw_iic_writebyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint
 		return 0;
 
 	} else {
-		NT_LOG_DBGX(WARNING, NTHW, "%s\n", p_adapter_id_str);
+		NT_LOG_DBGX(WRN, NTHW, "%s\n", p_adapter_id_str);
 		return -1;
 	}
 }
diff --git a/drivers/net/ntnic/nthw/core/nthw_pcie3.c b/drivers/net/ntnic/nthw/core/nthw_pcie3.c
index c6cb3ce8de..16c2a816e2 100644
--- a/drivers/net/ntnic/nthw/core/nthw_pcie3.c
+++ b/drivers/net/ntnic/nthw/core/nthw_pcie3.c
@@ -250,7 +250,7 @@ int nthw_pcie3_get_stat_rate(nthw_pcie3_t *p, uint64_t *p_pci_rx_rate, uint64_t
 int nthw_pcie3_end_point_counters_sample_post(nthw_pcie3_t *p,
 	struct nthw_hif_end_point_counters *epc)
 {
-	NT_LOG_DBGX(DEBUG, NTHW);
+	NT_LOG_DBGX(DBG, NTHW);
 	assert(epc);
 	nthw_pcie3_get_stat_rate(p, &epc->cur_tx, &epc->cur_rx, &epc->n_ref_clk_cnt,
 		&epc->n_tags_in_use, &epc->cur_pci_nt_util,
diff --git a/drivers/net/ntnic/nthw/model/nthw_fpga_model.c b/drivers/net/ntnic/nthw/model/nthw_fpga_model.c
index 14d1ebf5fa..37a0b10c93 100644
--- a/drivers/net/ntnic/nthw/model/nthw_fpga_model.c
+++ b/drivers/net/ntnic/nthw/model/nthw_fpga_model.c
@@ -250,12 +250,12 @@ void nthw_fpga_mgr_log_dump(nthw_fpga_mgr_t *p)
 {
 	int i;
 
-	NT_LOG_DBGX(DEBUG, NTHW, "fpgas=%d\n", p->mn_fpgas);
+	NT_LOG_DBGX(DBG, NTHW, "fpgas=%d\n", p->mn_fpgas);
 
 	for (i = 0; i < p->mn_fpgas; i++) {
 		nthw_fpga_prod_init_s *p_init = p->mpa_fpga_prod_init[i];
 		(void)p_init;
-		NT_LOG_DBGX(DEBUG, NTHW, "fpga=%d/%d: %04d-%02d-%02d\n", i, p->mn_fpgas,
+		NT_LOG_DBGX(DBG, NTHW, "fpga=%d/%d: %04d-%02d-%02d\n", i, p->mn_fpgas,
 			p_init->fpga_product_id, p_init->fpga_version, p_init->fpga_revision);
 	}
 }
@@ -903,7 +903,7 @@ void nthw_field_init(nthw_field_t *p, nthw_register_t *p_reg, const nthw_fpga_fi
 		p->mn_tail_mask = (1 << bits_remaining) - 1;
 
 		if (p->mn_debug_mode >= 0x100) {
-			NT_LOG_DBGX(DEBUG, NTHW,
+			NT_LOG_DBGX(DBG, NTHW,
 				"fldid=%08d: [%08d:%08d] %08d/%08d: (%08d,%08d) (0x%08X,%08d,0x%08X)\n",
 				p_init->id, p_init->low, (p_init->low + p_init->bw),
 				p_init->bw, ((p_init->bw + 31) / 32), p->mn_first_word,
diff --git a/drivers/net/ntnic/ntlog/ntlog.c b/drivers/net/ntnic/ntlog/ntlog.c
index 2e4fba799d..7b7f583364 100644
--- a/drivers/net/ntnic/ntlog/ntlog.c
+++ b/drivers/net/ntnic/ntlog/ntlog.c
@@ -16,8 +16,6 @@
 
 #define NTLOG_HELPER_STR_SIZE_MAX (1024)
 
-RTE_LOG_REGISTER_DEFAULT(nt_logtype, NOTICE)
-
 char *ntlog_helper_str_alloc(const char *sinit)
 {
 	char *s = malloc(NTLOG_HELPER_STR_SIZE_MAX);
diff --git a/drivers/net/ntnic/ntlog/ntlog.h b/drivers/net/ntnic/ntlog/ntlog.h
index 58dcce0580..1d0fc2329f 100644
--- a/drivers/net/ntnic/ntlog/ntlog.h
+++ b/drivers/net/ntnic/ntlog/ntlog.h
@@ -10,30 +10,57 @@
 #include <stdint.h>
 #include <rte_log.h>
 
-extern int nt_logtype;
+extern int nt_log_general;
+extern int nt_log_nthw;
+extern int nt_log_filter;
+extern int nt_log_ntnic;
 
 #define NT_DRIVER_NAME "ntnic"
 
-#define NT_PMD_DRV_LOG(level, ...) \
-	rte_log(RTE_LOG_ ## level, nt_logtype, \
-		RTE_FMT(NT_DRIVER_NAME ": " \
-			RTE_FMT_HEAD(__VA_ARGS__, ""), \
-		RTE_FMT_TAIL(__VA_ARGS__, "")))
+/* Common log format */
+#define NT_LOG_TEMPLATE_COM(level, module, ...) \
+	RTE_FMT(NT_DRIVER_NAME " " module ": " level ": " RTE_FMT_HEAD(__VA_ARGS__, ""), \
+		RTE_FMT_TAIL(__VA_ARGS__, ""))
 
+/* Extended log format */
+#define NT_LOG_TEMPLATE_EXT(level, module, ...) \
+	RTE_FMT(NT_DRIVER_NAME " " module ": " level ": [%s: %u] " RTE_FMT_HEAD(__VA_ARGS__, ""), \
+		__func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__, ""))
 
-#define NT_LOG_ERR(...) NT_PMD_DRV_LOG(ERR, __VA_ARGS__)
-#define NT_LOG_WRN(...) NT_PMD_DRV_LOG(WARNING, __VA_ARGS__)
-#define NT_LOG_INF(...) NT_PMD_DRV_LOG(INFO, __VA_ARGS__)
-#define NT_LOG_DBG(...) NT_PMD_DRV_LOG(DEBUG, __VA_ARGS__)
+#define NT_PMD_DRV_GENERAL_LOG(level, module, format, ...) \
+	rte_log(RTE_LOG_##level, nt_log_general, \
+		NT_LOG_TEMPLATE_##format(#level, #module, __VA_ARGS__))
 
-#define NT_LOG(level, module, ...) \
-	NT_LOG_##level(#module ": " #level ":" __VA_ARGS__)
+#define NT_PMD_DRV_NTHW_LOG(level, module, format, ...) \
+	rte_log(RTE_LOG_##level, nt_log_nthw, \
+		NT_LOG_TEMPLATE_##format(#level, #module, __VA_ARGS__))
+
+#define NT_PMD_DRV_FILTER_LOG(level, module, format, ...) \
+	rte_log(RTE_LOG_##level, nt_log_filter, \
+		NT_LOG_TEMPLATE_##format(#level, #module, __VA_ARGS__))
+
+#define NT_PMD_DRV_NTNIC_LOG(level, module, format, ...) \
+	rte_log(RTE_LOG_##level, nt_log_ntnic, \
+		NT_LOG_TEMPLATE_##format(#level, #module, __VA_ARGS__))
+
+#define NT_LOG_ERR(level, module, ...) NT_PMD_DRV_##module##_LOG(ERR, module, COM, __VA_ARGS__)
+#define NT_LOG_WRN(level, module, ...) NT_PMD_DRV_##module##_LOG(WARNING, module, COM, __VA_ARGS__)
+#define NT_LOG_INF(level, module, ...) NT_PMD_DRV_##module##_LOG(INFO, module, COM, __VA_ARGS__)
+#define NT_LOG_DBG(level, module, ...) NT_PMD_DRV_##module##_LOG(DEBUG, module, COM, __VA_ARGS__)
+
+#define NT_LOG_DBGX_ERR(level, module, ...) \
+	NT_PMD_DRV_##module##_LOG(ERR, module, EXT, __VA_ARGS__)
+#define NT_LOG_DBGX_WRN(level, module, ...) \
+	NT_PMD_DRV_##module##_LOG(WARNING, module, EXT, __VA_ARGS__)
+#define NT_LOG_DBGX_INF(level, module, ...) \
+	NT_PMD_DRV_##module##_LOG(INFO, module, EXT, __VA_ARGS__)
+#define NT_LOG_DBGX_DBG(level, module, ...) \
+	NT_PMD_DRV_##module##_LOG(DEBUG, module, EXT, __VA_ARGS__)
+
+#define NT_LOG(level, module, ...) NT_LOG_##level(level, module, __VA_ARGS__)
+
+#define NT_LOG_DBGX(level, module, ...) NT_LOG_DBGX_##level(level, module, __VA_ARGS__)
 
-#define NT_LOG_DBGX(level, module, ...) \
-		rte_log(RTE_LOG_ ##level, nt_logtype, \
-				RTE_FMT(NT_DRIVER_NAME #module ": [%s:%u]" \
-					RTE_FMT_HEAD(__VA_ARGS__, ""), __func__, __LINE__, \
-				RTE_FMT_TAIL(__VA_ARGS__, "")))
 /*
  * nt log helper functions
  * to create a string for NT_LOG usage to output a one-liner log
@@ -41,9 +68,7 @@ extern int nt_logtype;
  * you do not know the number of parameters at programming time or it is variable
  */
 char *ntlog_helper_str_alloc(const char *sinit);
-
 void ntlog_helper_str_add(char *s, const char *format, ...);
-
 void ntlog_helper_str_free(char *s);
 
 #endif	/* NTOSS_SYSTEM_NTLOG_H */
diff --git a/drivers/net/ntnic/ntnic_ethdev.c b/drivers/net/ntnic/ntnic_ethdev.c
index 52ca8f2844..5af18a3b27 100644
--- a/drivers/net/ntnic/ntnic_ethdev.c
+++ b/drivers/net/ntnic/ntnic_ethdev.c
@@ -174,7 +174,7 @@ eth_mac_addr_add(struct rte_eth_dev *eth_dev,
 	if (index >= NUM_MAC_ADDRS_PER_PORT) {
 		const struct pmd_internals *const internals =
 			(struct pmd_internals *)eth_dev->data->dev_private;
-		NT_LOG_DBGX(DEBUG, NTNIC, "Port %i: illegal index %u (>= %u)\n",
+		NT_LOG_DBGX(DBG, NTNIC, "Port %i: illegal index %u (>= %u)\n",
 			internals->n_intf_no, index, NUM_MAC_ADDRS_PER_PORT);
 		return -1;
 	}
@@ -204,7 +204,7 @@ eth_set_mc_addr_list(struct rte_eth_dev *eth_dev,
 	size_t i;
 
 	if (nb_mc_addr >= NUM_MULTICAST_ADDRS_PER_PORT) {
-		NT_LOG_DBGX(DEBUG, NTNIC,
+		NT_LOG_DBGX(DBG, NTNIC,
 			"Port %i: too many multicast addresses %u (>= %u)\n",
 			internals->n_intf_no, nb_mc_addr, NUM_MULTICAST_ADDRS_PER_PORT);
 		return -1;
@@ -223,7 +223,7 @@ eth_set_mc_addr_list(struct rte_eth_dev *eth_dev,
 static int
 eth_dev_configure(struct rte_eth_dev *eth_dev)
 {
-	NT_LOG_DBGX(DEBUG, NTNIC, "Called for eth_dev %p\n", eth_dev);
+	NT_LOG_DBGX(DBG, NTNIC, "Called for eth_dev %p\n", eth_dev);
 
 	/* The device is ALWAYS running promiscuous mode. */
 	eth_dev->data->promiscuous ^= ~eth_dev->data->promiscuous;
@@ -245,7 +245,7 @@ eth_dev_start(struct rte_eth_dev *eth_dev)
 	const int n_intf_no = internals->n_intf_no;
 	struct adapter_info_s *p_adapter_info = &internals->p_drv->ntdrv.adapter_info;
 
-	NT_LOG_DBGX(DEBUG, NTNIC, "Port %u\n", internals->n_intf_no);
+	NT_LOG_DBGX(DBG, NTNIC, "Port %u\n", internals->n_intf_no);
 
 	if (internals->type == PORT_TYPE_VIRTUAL || internals->type == PORT_TYPE_OVERRIDE) {
 		eth_dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
@@ -264,7 +264,7 @@ eth_dev_start(struct rte_eth_dev *eth_dev)
 		while (port_ops->get_link_status(p_adapter_info, n_intf_no) == RTE_ETH_LINK_DOWN) {
 			/* break out after 5 sec */
 			if (++loop >= 50) {
-				NT_LOG_DBGX(DEBUG, NTNIC,
+				NT_LOG_DBGX(DBG, NTNIC,
 					"TIMEOUT No link on port %i (5sec timeout)\n",
 					internals->n_intf_no);
 				break;
@@ -294,7 +294,7 @@ eth_dev_stop(struct rte_eth_dev *eth_dev)
 {
 	struct pmd_internals *internals = (struct pmd_internals *)eth_dev->data->dev_private;
 
-	NT_LOG_DBGX(DEBUG, NTNIC, "Port %u\n", internals->n_intf_no);
+	NT_LOG_DBGX(DBG, NTNIC, "Port %u\n", internals->n_intf_no);
 
 	eth_dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
 	return 0;
@@ -424,7 +424,7 @@ eth_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version, size_t fw_size
 static int
 promiscuous_enable(struct rte_eth_dev __rte_unused(*dev))
 {
-	NT_LOG(DBG, NTHW, "The device always run promiscuous mode.");
+	NT_LOG(DBG, NTHW, "The device always run promiscuous mode\n");
 	return 0;
 }
 
@@ -472,7 +472,7 @@ nthw_pci_dev_init(struct rte_pci_device *pci_dev)
 	int n_phy_ports;
 	struct port_link_speed pls_mbps[NUM_ADAPTER_PORTS_MAX] = { 0 };
 	int num_port_speeds = 0;
-	NT_LOG_DBGX(DEBUG, NTNIC, "Dev %s PF #%i Init : %02x:%02x:%i\n", pci_dev->name,
+	NT_LOG_DBGX(DBG, NTNIC, "Dev %s PF #%i Init : %02x:%02x:%i\n", pci_dev->name,
 		pci_dev->addr.function, pci_dev->addr.bus, pci_dev->addr.devid,
 		pci_dev->addr.function);
 
@@ -491,7 +491,7 @@ nthw_pci_dev_init(struct rte_pci_device *pci_dev)
 	int vfio = nt_vfio_setup(pci_dev);
 
 	if (vfio < 0) {
-		NT_LOG_DBGX(ERR, TNIC, "%s: vfio_setup error %d\n",
+		NT_LOG_DBGX(ERR, NTNIC, "%s: vfio_setup error %d\n",
 			(pci_dev->name[0] ? pci_dev->name : "NA"), -1);
 		rte_free(p_drv);
 		return -1;
@@ -583,14 +583,14 @@ nthw_pci_dev_init(struct rte_pci_device *pci_dev)
 		char name[32];
 
 		if ((1 << n_intf_no) & ~n_port_mask) {
-			NT_LOG_DBGX(DEBUG, NTNIC,
+			NT_LOG_DBGX(DBG, NTNIC,
 				"%s: interface #%d: skipping due to portmask 0x%02X\n",
 				p_port_id_str, n_intf_no, n_port_mask);
 			continue;
 		}
 
 		snprintf(name, sizeof(name), "ntnic%d", n_intf_no);
-		NT_LOG_DBGX(DEBUG, NTNIC, "%s: interface #%d: %s: '%s'\n", p_port_id_str,
+		NT_LOG_DBGX(DBG, NTNIC, "%s: interface #%d: %s: '%s'\n", p_port_id_str,
 			n_intf_no, (pci_dev->name[0] ? pci_dev->name : "NA"), name);
 
 		internals = rte_zmalloc_socket(name, sizeof(struct pmd_internals),
@@ -674,7 +674,7 @@ nthw_pci_dev_init(struct rte_pci_device *pci_dev)
 static int
 nthw_pci_dev_deinit(struct rte_eth_dev *eth_dev __rte_unused)
 {
-	NT_LOG_DBGX(DEBUG, NTNIC, "PCI device deinitialization\n");
+	NT_LOG_DBGX(DBG, NTNIC, "PCI device deinitialization\n");
 
 	int i;
 	char name[32];
@@ -701,13 +701,13 @@ nthw_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 {
 	int ret;
 
-	NT_LOG_DBGX(DEBUG, NTNIC, "pcidev: name: '%s'\n", pci_dev->name);
-	NT_LOG_DBGX(DEBUG, NTNIC, "devargs: name: '%s'\n", pci_dev->device.name);
+	NT_LOG_DBGX(DBG, NTNIC, "pcidev: name: '%s'\n", pci_dev->name);
+	NT_LOG_DBGX(DBG, NTNIC, "devargs: name: '%s'\n", pci_dev->device.name);
 
 	if (pci_dev->device.devargs) {
-		NT_LOG_DBGX(DEBUG, NTNIC, "devargs: args: '%s'\n",
+		NT_LOG_DBGX(DBG, NTNIC, "devargs: args: '%s'\n",
 			(pci_dev->device.devargs->args ? pci_dev->device.devargs->args : "NULL"));
-		NT_LOG_DBGX(DEBUG, NTNIC, "devargs: data: '%s'\n",
+		NT_LOG_DBGX(DBG, NTNIC, "devargs: data: '%s'\n",
 			(pci_dev->device.devargs->data ? pci_dev->device.devargs->data : "NULL"));
 	}
 
@@ -737,14 +737,14 @@ nthw_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 
 	ret = nthw_pci_dev_init(pci_dev);
 
-	NT_LOG_DBGX(DEBUG, NTNIC, "leave: ret=%d\n", ret);
+	NT_LOG_DBGX(DBG, NTNIC, "leave: ret=%d\n", ret);
 	return ret;
 }
 
 static int
 nthw_pci_remove(struct rte_pci_device *pci_dev)
 {
-	NT_LOG_DBGX(DEBUG, NTNIC);
+	NT_LOG_DBGX(DBG, NTNIC);
 
 	struct drv_s *p_drv = get_pdrv_from_pci(pci_dev->addr);
 	drv_deinit(p_drv);
@@ -762,3 +762,8 @@ static struct rte_pci_driver rte_nthw_pmd = {
 RTE_PMD_REGISTER_PCI(net_ntnic, rte_nthw_pmd);
 RTE_PMD_REGISTER_PCI_TABLE(net_ntnic, nthw_pci_id_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_ntnic, "* vfio-pci");
+
+RTE_LOG_REGISTER_SUFFIX(nt_log_general, general, INFO);
+RTE_LOG_REGISTER_SUFFIX(nt_log_nthw, nthw, INFO);
+RTE_LOG_REGISTER_SUFFIX(nt_log_filter, filter, INFO);
+RTE_LOG_REGISTER_SUFFIX(nt_log_ntnic, ntnic, INFO);
-- 
2.45.0


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

* [PATCH v1 00/31] Enable flow filter initialization
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (4 preceding siblings ...)
  2024-10-04 15:06 ` [PATCH v1 5/5] net/ntnic: extend and fix logging implementation Serhii Iliushyk
@ 2024-10-04 15:06 ` Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 01/31] net/ntnic: add flow filter init API Serhii Iliushyk
                   ` (45 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev; +Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit

*** BLURB HERE ***

Oleksandr Kolomeiets (30):
  net/ntnic: add flow filter init API
  net/ntnic: add flow filter deinitialization API
  net/ntnic: add flow backend initialization API
  net/ntnic: add flow backend deinitialization API
  net/ntnic: add INFO flow module
  net/ntnic: add categorizer (CAT) flow module
  net/ntnic: add key match (KM) flow module
  net/ntnic: add flow matcher (FLM) flow module
  net/ntnic: add IP fragmenter (IFR) flow module
  net/ntnic: add hasher (HSH) flow module
  net/ntnic: add queue select (QSL) flow module
  net/ntnic: add slicer (SLC LR) flow module
  net/ntnic: add packet descriptor builder (PDB) flow module
  net/ntnic: add header field update (HFU) flow module
  net/ntnic: add RPP local retransmit (RPP LR) flow module
  net/ntnic: add copier (Tx CPY) flow module
  net/ntnic: add checksum update (CSU) flow module
  net/ntnic: add insert (Tx INS) flow module
  net/ntnic: add replacer (Tx RPL) flow module
  net/ntnic: add base init and deinit of the NT flow API
  net/ntnic: add base init and deinit the NT flow backend
  net/ntnic: add categorizer (CAT) FPGA module
  net/ntnic: add key match (KM) FPGA module
  net/ntnic: add flow matcher (FLM) FPGA module
  net/ntnic: add hasher (HSH) FPGA module
  net/ntnic: add queue select (QSL) FPGA module
  net/ntnic: add slicer (SLC LR) FPGA module
  net/ntnic: add packet descriptor builder (PDB) FPGA module
  net/ntnic: add Tx Packet Editor (TPE) FPGA module
  net/ntnic: add receive MAC converter (RMC) core module

Serhii Iliushyk (1):
  net/ntnic: add Tx Packet Editor (TPE) flow module

 drivers/net/ntnic/adapter/nt4ga_adapter.c     |   49 +
 drivers/net/ntnic/include/flow_api.h          |  104 +
 drivers/net/ntnic/include/flow_api_engine.h   |   48 +
 drivers/net/ntnic/include/flow_filter.h       |   15 +
 drivers/net/ntnic/include/hw_mod_backend.h    |  910 +++++++
 drivers/net/ntnic/include/hw_mod_cat_v18.h    |  141 ++
 drivers/net/ntnic/include/hw_mod_cat_v21.h    |   91 +
 drivers/net/ntnic/include/hw_mod_flm_v25.h    |  342 +++
 drivers/net/ntnic/include/hw_mod_hsh_v5.h     |   46 +
 drivers/net/ntnic/include/hw_mod_km_v7.h      |   96 +
 drivers/net/ntnic/include/hw_mod_pdb_v9.h     |   42 +
 drivers/net/ntnic/include/hw_mod_qsl_v7.h     |   48 +
 drivers/net/ntnic/include/hw_mod_slc_lr_v2.h  |   25 +
 drivers/net/ntnic/include/hw_mod_tpe_v3.h     |  126 +
 drivers/net/ntnic/include/nt4ga_adapter.h     |    7 +
 drivers/net/ntnic/include/nt4ga_filter.h      |   13 +
 drivers/net/ntnic/include/ntnic_stat.h        |   11 +
 .../ntnic/include/stream_binary_flow_api.h    |   22 +
 drivers/net/ntnic/meson.build                 |   31 +
 .../net/ntnic/nthw/core/include/nthw_rmc.h    |   49 +
 drivers/net/ntnic/nthw/core/nthw_rmc.c        |   90 +
 drivers/net/ntnic/nthw/flow_api/flow_api.c    |  391 +++
 .../ntnic/nthw/flow_api/flow_api_nic_setup.h  |   20 +
 .../nthw/flow_api/flow_backend/flow_backend.c | 2255 +++++++++++++++++
 drivers/net/ntnic/nthw/flow_api/flow_filter.c |   55 +
 drivers/net/ntnic/nthw/flow_api/flow_kcc.c    |   19 +
 drivers/net/ntnic/nthw/flow_api/flow_km.c     |   19 +
 .../nthw/flow_api/hw_mod/hw_mod_backend.c     |  145 ++
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c   |  985 +++++++
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_flm.c   |  300 +++
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_hsh.c   |   84 +
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_km.c    |  278 ++
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_pdb.c   |   86 +
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_qsl.c   |  170 ++
 .../nthw/flow_api/hw_mod/hw_mod_slc_lr.c      |   65 +
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_tpe.c   |  277 ++
 .../ntnic/nthw/flow_filter/flow_nthw_cat.c    |  872 +++++++
 .../ntnic/nthw/flow_filter/flow_nthw_cat.h    |  291 +++
 .../ntnic/nthw/flow_filter/flow_nthw_csu.c    |  141 ++
 .../ntnic/nthw/flow_filter/flow_nthw_csu.h    |   44 +
 .../ntnic/nthw/flow_filter/flow_nthw_flm.c    | 1225 +++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_flm.h    |  433 ++++
 .../ntnic/nthw/flow_filter/flow_nthw_hfu.c    |  230 ++
 .../ntnic/nthw/flow_filter/flow_nthw_hfu.h    |   84 +
 .../ntnic/nthw/flow_filter/flow_nthw_hsh.c    |  260 ++
 .../ntnic/nthw/flow_filter/flow_nthw_hsh.h    |   87 +
 .../ntnic/nthw/flow_filter/flow_nthw_ifr.c    |  123 +
 .../ntnic/nthw/flow_filter/flow_nthw_ifr.h    |   54 +
 .../ntnic/nthw/flow_filter/flow_nthw_info.c   |  341 +++
 .../ntnic/nthw/flow_filter/flow_nthw_info.h   |  110 +
 .../net/ntnic/nthw/flow_filter/flow_nthw_km.c |  610 +++++
 .../net/ntnic/nthw/flow_filter/flow_nthw_km.h |  214 ++
 .../ntnic/nthw/flow_filter/flow_nthw_pdb.c    |  210 ++
 .../ntnic/nthw/flow_filter/flow_nthw_pdb.h    |   85 +
 .../ntnic/nthw/flow_filter/flow_nthw_qsl.c    |  295 +++
 .../ntnic/nthw/flow_filter/flow_nthw_qsl.h    |  113 +
 .../ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c |  157 ++
 .../ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h |   61 +
 .../ntnic/nthw/flow_filter/flow_nthw_slc_lr.c |  126 +
 .../ntnic/nthw/flow_filter/flow_nthw_slc_lr.h |   54 +
 .../ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c |  388 +++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h |   59 +
 .../ntnic/nthw/flow_filter/flow_nthw_tx_ins.c |   98 +
 .../ntnic/nthw/flow_filter/flow_nthw_tx_ins.h |   44 +
 .../ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c |  172 ++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h |   74 +
 drivers/net/ntnic/nthw/nthw_drv.h             |    2 +
 drivers/net/ntnic/nthw/nthw_helper.h          |   11 +
 drivers/net/ntnic/nthw/nthw_rac.c             |  181 ++
 drivers/net/ntnic/nthw/nthw_rac.h             |    9 +
 .../supported/nthw_fpga_9563_055_049_0000.c   |  513 +++-
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |   15 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |   19 +
 .../nthw/supported/nthw_fpga_reg_defs_cat.h   |  238 ++
 .../nthw/supported/nthw_fpga_reg_defs_cpy.h   |  113 +
 .../nthw/supported/nthw_fpga_reg_defs_csu.h   |   31 +
 .../nthw/supported/nthw_fpga_reg_defs_flm.h   |  242 ++
 .../nthw/supported/nthw_fpga_reg_defs_hfu.h   |   49 +
 .../nthw/supported/nthw_fpga_reg_defs_hsh.h   |   50 +
 .../nthw/supported/nthw_fpga_reg_defs_ifr.h   |   42 +
 .../nthw/supported/nthw_fpga_reg_defs_ins.h   |   30 +
 .../nthw/supported/nthw_fpga_reg_defs_km.h    |  126 +
 .../nthw/supported/nthw_fpga_reg_defs_pdb.h   |   48 +
 .../nthw/supported/nthw_fpga_reg_defs_qsl.h   |   66 +
 .../nthw/supported/nthw_fpga_reg_defs_rmc.h   |   36 +
 .../nthw/supported/nthw_fpga_reg_defs_rpl.h   |   43 +
 .../supported/nthw_fpga_reg_defs_rpp_lr.h     |   37 +
 .../nthw/supported/nthw_fpga_reg_defs_slc.h   |   34 +
 .../supported/nthw_fpga_reg_defs_slc_lr.h     |   23 +
 .../supported/nthw_fpga_reg_defs_tx_cpy.h     |   23 +
 .../supported/nthw_fpga_reg_defs_tx_ins.h     |   23 +
 .../supported/nthw_fpga_reg_defs_tx_rpl.h     |   23 +
 drivers/net/ntnic/ntnic_mod_reg.c             |   30 +
 drivers/net/ntnic/ntnic_mod_reg.h             |   21 +
 drivers/net/ntnic/ntutil/nt_util.c            |    6 +
 drivers/net/ntnic/ntutil/nt_util.h            |    6 +
 96 files changed, 16599 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ntnic/include/flow_api.h
 create mode 100644 drivers/net/ntnic/include/flow_api_engine.h
 create mode 100644 drivers/net/ntnic/include/flow_filter.h
 create mode 100644 drivers/net/ntnic/include/hw_mod_backend.h
 create mode 100644 drivers/net/ntnic/include/hw_mod_cat_v18.h
 create mode 100644 drivers/net/ntnic/include/hw_mod_cat_v21.h
 create mode 100644 drivers/net/ntnic/include/hw_mod_flm_v25.h
 create mode 100644 drivers/net/ntnic/include/hw_mod_hsh_v5.h
 create mode 100644 drivers/net/ntnic/include/hw_mod_km_v7.h
 create mode 100644 drivers/net/ntnic/include/hw_mod_pdb_v9.h
 create mode 100644 drivers/net/ntnic/include/hw_mod_qsl_v7.h
 create mode 100644 drivers/net/ntnic/include/hw_mod_slc_lr_v2.h
 create mode 100644 drivers/net/ntnic/include/hw_mod_tpe_v3.h
 create mode 100644 drivers/net/ntnic/include/nt4ga_filter.h
 create mode 100644 drivers/net/ntnic/include/ntnic_stat.h
 create mode 100644 drivers/net/ntnic/include/stream_binary_flow_api.h
 create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_rmc.h
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_rmc.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_api.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_filter.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_kcc.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_km.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_cat.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_cat.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_info.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_info.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_km.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_km.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_pdb.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_pdb.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc_lr.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc_lr.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h
 create mode 100644 drivers/net/ntnic/nthw/nthw_helper.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_cat.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_cpy.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_csu.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_flm.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_hfu.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_hsh.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_ifr.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_ins.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_km.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_pdb.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_qsl.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rmc.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rpl.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rpp_lr.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_slc.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_slc_lr.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_cpy.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_ins.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_rpl.h

-- 
2.45.0


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

* [PATCH v1 01/31] net/ntnic: add flow filter init API
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (5 preceding siblings ...)
  2024-10-04 15:06 ` [PATCH v1 00/31] Enable flow filter initialization Serhii Iliushyk
@ 2024-10-04 15:06 ` Serhii Iliushyk
  2024-10-21 23:24   ` Stephen Hemminger
  2024-10-04 15:06 ` [PATCH v1 02/31] net/ntnic: add flow filter deinitialization API Serhii Iliushyk
                   ` (44 subsequent siblings)
  51 siblings, 1 reply; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

Add high-level interfaces for the initialization of the flow filter.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/adapter/nt4ga_adapter.c | 18 ++++++++++++++++++
 drivers/net/ntnic/include/flow_api.h      | 12 ++++++++++++
 drivers/net/ntnic/include/nt4ga_adapter.h |  6 ++++++
 drivers/net/ntnic/include/nt4ga_filter.h  | 13 +++++++++++++
 drivers/net/ntnic/ntnic_mod_reg.c         |  7 +++++++
 drivers/net/ntnic/ntnic_mod_reg.h         |  8 ++++++++
 6 files changed, 64 insertions(+)
 create mode 100644 drivers/net/ntnic/include/flow_api.h
 create mode 100644 drivers/net/ntnic/include/nt4ga_filter.h

diff --git a/drivers/net/ntnic/adapter/nt4ga_adapter.c b/drivers/net/ntnic/adapter/nt4ga_adapter.c
index b704a256c6..4105a6eb5a 100644
--- a/drivers/net/ntnic/adapter/nt4ga_adapter.c
+++ b/drivers/net/ntnic/adapter/nt4ga_adapter.c
@@ -75,6 +75,11 @@ static int nt4ga_adapter_show_info(struct adapter_info_s *p_adapter_info, FILE *
 
 static int nt4ga_adapter_init(struct adapter_info_s *p_adapter_info)
 {
+	const struct flow_filter_ops *flow_filter_ops = get_flow_filter_ops();
+
+	if (flow_filter_ops == NULL)
+		NT_LOG(ERR, NTNIC, "%s: flow_filter module uninitialized\n", __func__);
+
 	char *const p_dev_name = malloc(24);
 	char *const p_adapter_id_str = malloc(24);
 	fpga_info_t *fpga_info = &p_adapter_info->fpga_info;
@@ -155,6 +160,19 @@ static int nt4ga_adapter_init(struct adapter_info_s *p_adapter_info)
 	n_nim_ports = fpga_info->n_nims;
 	assert(n_nim_ports >= 1);
 
+	/* Nt4ga Init Filter */
+	nt4ga_filter_t *p_filter = &p_adapter_info->nt4ga_filter;
+
+	if (flow_filter_ops != NULL) {
+		res = flow_filter_ops->flow_filter_init(p_fpga, &p_filter->mp_flow_device,
+				p_adapter_info->adapter_no);
+
+		if (res != 0) {
+			NT_LOG(ERR, NTNIC, "%s: Cannot initialize filter\n", p_adapter_id_str);
+			return res;
+		}
+	}
+
 	{
 		int i;
 		const struct link_ops_s *link_ops = NULL;
diff --git a/drivers/net/ntnic/include/flow_api.h b/drivers/net/ntnic/include/flow_api.h
new file mode 100644
index 0000000000..036e652b76
--- /dev/null
+++ b/drivers/net/ntnic/include/flow_api.h
@@ -0,0 +1,12 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _FLOW_API_H_
+#define _FLOW_API_H_
+
+/* registered NIC backends */
+struct flow_nic_dev;
+
+#endif
diff --git a/drivers/net/ntnic/include/nt4ga_adapter.h b/drivers/net/ntnic/include/nt4ga_adapter.h
index 4b204742a2..93218fd45b 100644
--- a/drivers/net/ntnic/include/nt4ga_adapter.h
+++ b/drivers/net/ntnic/include/nt4ga_adapter.h
@@ -23,7 +23,13 @@ typedef struct hw_info_s {
 	int hw_reserved1;
 } hw_info_t;
 
+/*
+ * Services provided by the adapter module
+ */
+#include "nt4ga_filter.h"
+
 typedef struct adapter_info_s {
+	struct nt4ga_filter_s nt4ga_filter;
 	struct nt4ga_link_s nt4ga_link;
 
 	struct hw_info_s hw_info;
diff --git a/drivers/net/ntnic/include/nt4ga_filter.h b/drivers/net/ntnic/include/nt4ga_filter.h
new file mode 100644
index 0000000000..2024b500f3
--- /dev/null
+++ b/drivers/net/ntnic/include/nt4ga_filter.h
@@ -0,0 +1,13 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef NT4GA_FILTER_H_
+#define NT4GA_FILTER_H_
+
+typedef struct nt4ga_filter_s {
+	struct flow_nic_dev *mp_flow_device;
+} nt4ga_filter_t;
+
+#endif  /* NT4GA_FILTER_H_ */
diff --git a/drivers/net/ntnic/ntnic_mod_reg.c b/drivers/net/ntnic/ntnic_mod_reg.c
index 40e22c60fa..45cc767c90 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.c
+++ b/drivers/net/ntnic/ntnic_mod_reg.c
@@ -88,3 +88,10 @@ struct rst9563_ops *get_rst9563_ops(void)
 		rst9563_ops_init();
 	return rst9563_ops;
 }
+
+static const struct flow_filter_ops *flow_filter_ops;
+
+const struct flow_filter_ops *get_flow_filter_ops(void)
+{
+	return flow_filter_ops;
+}
diff --git a/drivers/net/ntnic/ntnic_mod_reg.h b/drivers/net/ntnic/ntnic_mod_reg.h
index 3189b04f33..6dd6240c6f 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.h
+++ b/drivers/net/ntnic/ntnic_mod_reg.h
@@ -7,6 +7,7 @@
 #define __NTNIC_MOD_REG_H__
 
 #include <stdint.h>
+#include "flow_api.h"
 #include "nthw_fpga_model.h"
 #include "nthw_platform_drv.h"
 #include "nthw_drv.h"
@@ -117,4 +118,11 @@ void register_rst9563_ops(struct rst9563_ops *ops);
 struct rst9563_ops *get_rst9563_ops(void);
 void rst9563_ops_init(void);
 
+struct flow_filter_ops {
+	int (*flow_filter_init)(nthw_fpga_t *p_fpga, struct flow_nic_dev **p_flow_device,
+		int adapter_no);
+};
+
+const struct flow_filter_ops *get_flow_filter_ops(void);
+
 #endif	/* __NTNIC_MOD_REG_H__ */
-- 
2.45.0


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

* [PATCH v1 02/31] net/ntnic: add flow filter deinitialization API
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (6 preceding siblings ...)
  2024-10-04 15:06 ` [PATCH v1 01/31] net/ntnic: add flow filter init API Serhii Iliushyk
@ 2024-10-04 15:06 ` Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 03/31] net/ntnic: add flow backend initialization API Serhii Iliushyk
                   ` (43 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

Add high-level interfaces for the deinitialization of the flow filter.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/adapter/nt4ga_adapter.c | 17 +++++++++++++++++
 drivers/net/ntnic/ntnic_mod_reg.h         |  1 +
 2 files changed, 18 insertions(+)

diff --git a/drivers/net/ntnic/adapter/nt4ga_adapter.c b/drivers/net/ntnic/adapter/nt4ga_adapter.c
index 4105a6eb5a..fd90f31abd 100644
--- a/drivers/net/ntnic/adapter/nt4ga_adapter.c
+++ b/drivers/net/ntnic/adapter/nt4ga_adapter.c
@@ -217,12 +217,29 @@ static int nt4ga_adapter_init(struct adapter_info_s *p_adapter_info)
 
 static int nt4ga_adapter_deinit(struct adapter_info_s *p_adapter_info)
 {
+	const struct flow_filter_ops *flow_filter_ops = get_flow_filter_ops();
+
+	if (flow_filter_ops == NULL)
+		NT_LOG(ERR, NTNIC, "%s: flow_filter module uninitialized\n", __func__);
+
 	fpga_info_t *fpga_info = &p_adapter_info->fpga_info;
 	int i;
 	int res = -1;
 
 	stop_monitor_tasks(-1);
 
+	/* Nt4ga Deinit Filter */
+	nt4ga_filter_t *p_filter = &p_adapter_info->nt4ga_filter;
+
+	if (flow_filter_ops != NULL) {
+		res = flow_filter_ops->flow_filter_done(p_filter->mp_flow_device);
+
+		if (res != 0) {
+			NT_LOG(ERR, NTNIC, "Cannot deinitialize filter\n");
+			return res;
+		}
+	}
+
 	nthw_fpga_shutdown(&p_adapter_info->fpga_info);
 
 	/* Rac rab reset flip flop */
diff --git a/drivers/net/ntnic/ntnic_mod_reg.h b/drivers/net/ntnic/ntnic_mod_reg.h
index 6dd6240c6f..fd9e595f50 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.h
+++ b/drivers/net/ntnic/ntnic_mod_reg.h
@@ -121,6 +121,7 @@ void rst9563_ops_init(void);
 struct flow_filter_ops {
 	int (*flow_filter_init)(nthw_fpga_t *p_fpga, struct flow_nic_dev **p_flow_device,
 		int adapter_no);
+	int (*flow_filter_done)(struct flow_nic_dev *dev);
 };
 
 const struct flow_filter_ops *get_flow_filter_ops(void);
-- 
2.45.0


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

* [PATCH v1 03/31] net/ntnic: add flow backend initialization API
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (7 preceding siblings ...)
  2024-10-04 15:06 ` [PATCH v1 02/31] net/ntnic: add flow filter deinitialization API Serhii Iliushyk
@ 2024-10-04 15:06 ` Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 04/31] net/ntnic: add flow backend deinitialization API Serhii Iliushyk
                   ` (42 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

Add high-level interfaces for the initialization of the backend.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/flow_api.h          |  2 ++
 drivers/net/ntnic/include/flow_filter.h       | 14 ++++++++++
 drivers/net/ntnic/meson.build                 |  2 ++
 drivers/net/ntnic/nthw/flow_api/flow_api.c    | 17 ++++++++++++
 drivers/net/ntnic/nthw/flow_api/flow_filter.c | 27 +++++++++++++++++++
 drivers/net/ntnic/ntnic_mod_reg.c             | 15 +++++++++++
 drivers/net/ntnic/ntnic_mod_reg.h             |  9 +++++++
 7 files changed, 86 insertions(+)
 create mode 100644 drivers/net/ntnic/include/flow_filter.h
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_api.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_filter.c

diff --git a/drivers/net/ntnic/include/flow_api.h b/drivers/net/ntnic/include/flow_api.h
index 036e652b76..112bcabdb5 100644
--- a/drivers/net/ntnic/include/flow_api.h
+++ b/drivers/net/ntnic/include/flow_api.h
@@ -6,6 +6,8 @@
 #ifndef _FLOW_API_H_
 #define _FLOW_API_H_
 
+#include "ntlog.h"
+
 /* registered NIC backends */
 struct flow_nic_dev;
 
diff --git a/drivers/net/ntnic/include/flow_filter.h b/drivers/net/ntnic/include/flow_filter.h
new file mode 100644
index 0000000000..01cfce03d7
--- /dev/null
+++ b/drivers/net/ntnic/include/flow_filter.h
@@ -0,0 +1,14 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_FILTER_HPP__
+#define __FLOW_FILTER_HPP__
+
+#include "flow_api.h"
+#include "nthw_fpga_model.h"
+
+int flow_filter_init(nthw_fpga_t *p_fpga, struct flow_nic_dev **p_flow_device, int adapter_no);
+
+#endif  /* __FLOW_FILTER_HPP__ */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index e9f2110b8f..00b1ae4c70 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -42,6 +42,8 @@ sources = files(
         'nthw/core/nthw_pcie3.c',
         'nthw/core/nthw_sdc.c',
         'nthw/core/nthw_si5340.c',
+        'nthw/flow_api/flow_api.c',
+        'nthw/flow_api/flow_filter.c',
         'nthw/model/nthw_fpga_model.c',
         'nthw/nthw_platform.c',
         'nthw/nthw_rac.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
new file mode 100644
index 0000000000..b4866d4bdf
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -0,0 +1,17 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntnic_mod_reg.h"
+
+#include "flow_filter.h"
+
+static const struct flow_filter_ops ops = {
+	.flow_filter_init = flow_filter_init,
+};
+
+void init_flow_filter(void)
+{
+	register_flow_filter_ops(&ops);
+}
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_filter.c b/drivers/net/ntnic/nthw/flow_api/flow_filter.c
new file mode 100644
index 0000000000..7b6e122190
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/flow_filter.c
@@ -0,0 +1,27 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "flow_filter.h"
+#include "ntnic_mod_reg.h"
+
+int flow_filter_init(nthw_fpga_t *p_fpga, struct flow_nic_dev **p_flow_device, int adapter_no)
+{
+	(void)p_flow_device;
+	(void)adapter_no;
+
+	void *be_dev = NULL;
+
+	const struct flow_backend_ops *flow_backend_ops = get_flow_backend_ops();
+
+	if (flow_backend_ops == NULL) {
+		NT_LOG(ERR, FILTER, "%s: flow_backend module uninitialized\n", __func__);
+		return -1;
+	}
+
+	NT_LOG(DBG, FILTER, "Initializing flow filter api\n");
+	flow_backend_ops->bin_flow_backend_init(p_fpga, &be_dev);
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/ntnic_mod_reg.c b/drivers/net/ntnic/ntnic_mod_reg.c
index 45cc767c90..2094e1fbb9 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.c
+++ b/drivers/net/ntnic/ntnic_mod_reg.c
@@ -89,9 +89,24 @@ struct rst9563_ops *get_rst9563_ops(void)
 	return rst9563_ops;
 }
 
+static const struct flow_backend_ops *flow_backend_ops;
+
+const struct flow_backend_ops *get_flow_backend_ops(void)
+{
+	return flow_backend_ops;
+}
+
 static const struct flow_filter_ops *flow_filter_ops;
 
+void register_flow_filter_ops(const struct flow_filter_ops *ops)
+{
+	flow_filter_ops = ops;
+}
+
 const struct flow_filter_ops *get_flow_filter_ops(void)
 {
+	if (flow_filter_ops == NULL)
+		init_flow_filter();
+
 	return flow_filter_ops;
 }
diff --git a/drivers/net/ntnic/ntnic_mod_reg.h b/drivers/net/ntnic/ntnic_mod_reg.h
index fd9e595f50..3251f651be 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.h
+++ b/drivers/net/ntnic/ntnic_mod_reg.h
@@ -118,12 +118,21 @@ void register_rst9563_ops(struct rst9563_ops *ops);
 struct rst9563_ops *get_rst9563_ops(void);
 void rst9563_ops_init(void);
 
+struct flow_backend_ops {
+	const struct flow_api_backend_ops *(*bin_flow_backend_init)(nthw_fpga_t *p_fpga,
+		void **be_dev);
+};
+
+const struct flow_backend_ops *get_flow_backend_ops(void);
+
 struct flow_filter_ops {
 	int (*flow_filter_init)(nthw_fpga_t *p_fpga, struct flow_nic_dev **p_flow_device,
 		int adapter_no);
 	int (*flow_filter_done)(struct flow_nic_dev *dev);
 };
 
+void register_flow_filter_ops(const struct flow_filter_ops *ops);
 const struct flow_filter_ops *get_flow_filter_ops(void);
+void init_flow_filter(void);
 
 #endif	/* __NTNIC_MOD_REG_H__ */
-- 
2.45.0


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

* [PATCH v1 04/31] net/ntnic: add flow backend deinitialization API
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (8 preceding siblings ...)
  2024-10-04 15:06 ` [PATCH v1 03/31] net/ntnic: add flow backend initialization API Serhii Iliushyk
@ 2024-10-04 15:06 ` Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 05/31] net/ntnic: add INFO flow module Serhii Iliushyk
                   ` (41 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

Add high-level interfaces for the deinitialization of the backend.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/flow_api.h          |  7 ++++++-
 drivers/net/ntnic/include/flow_filter.h       |  1 +
 drivers/net/ntnic/include/hw_mod_backend.h    | 13 ++++++++++++
 drivers/net/ntnic/nthw/flow_api/flow_api.c    | 12 +++++++++++
 .../ntnic/nthw/flow_api/flow_api_nic_setup.h  | 14 +++++++++++++
 drivers/net/ntnic/nthw/flow_api/flow_filter.c | 21 +++++++++++++++++++
 drivers/net/ntnic/ntnic_mod_reg.h             |  1 +
 7 files changed, 68 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ntnic/include/hw_mod_backend.h
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h

diff --git a/drivers/net/ntnic/include/flow_api.h b/drivers/net/ntnic/include/flow_api.h
index 112bcabdb5..6a2277c2ca 100644
--- a/drivers/net/ntnic/include/flow_api.h
+++ b/drivers/net/ntnic/include/flow_api.h
@@ -8,7 +8,12 @@
 
 #include "ntlog.h"
 
+#include "hw_mod_backend.h"
+
 /* registered NIC backends */
-struct flow_nic_dev;
+struct flow_nic_dev {
+	/* NIC backend API */
+	struct flow_api_backend_s be;
+};
 
 #endif
diff --git a/drivers/net/ntnic/include/flow_filter.h b/drivers/net/ntnic/include/flow_filter.h
index 01cfce03d7..d204c0d882 100644
--- a/drivers/net/ntnic/include/flow_filter.h
+++ b/drivers/net/ntnic/include/flow_filter.h
@@ -10,5 +10,6 @@
 #include "nthw_fpga_model.h"
 
 int flow_filter_init(nthw_fpga_t *p_fpga, struct flow_nic_dev **p_flow_device, int adapter_no);
+int flow_filter_done(struct flow_nic_dev *dev);
 
 #endif  /* __FLOW_FILTER_HPP__ */
diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
new file mode 100644
index 0000000000..46054a6a85
--- /dev/null
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -0,0 +1,13 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _HW_MOD_BACKEND_H_
+#define _HW_MOD_BACKEND_H_
+
+struct flow_api_backend_s {
+	void *be_dev;
+};
+
+#endif  /* _HW_MOD_BACKEND_H_ */
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
index b4866d4bdf..9671a20e0b 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -3,12 +3,24 @@
  * Copyright(c) 2023 Napatech A/S
  */
 
+#include "flow_api_nic_setup.h"
 #include "ntnic_mod_reg.h"
 
 #include "flow_filter.h"
 
+void *flow_api_get_be_dev(struct flow_nic_dev *ndev)
+{
+	if (!ndev) {
+		NT_LOG(DBG, FILTER, "ERR: %s\n", __func__);
+		return NULL;
+	}
+
+	return ndev->be.be_dev;
+}
+
 static const struct flow_filter_ops ops = {
 	.flow_filter_init = flow_filter_init,
+	.flow_filter_done = flow_filter_done,
 };
 
 void init_flow_filter(void)
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h b/drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h
new file mode 100644
index 0000000000..da083f050a
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h
@@ -0,0 +1,14 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_API_NIC_SETUP_H__
+#define __FLOW_API_NIC_SETUP_H__
+
+#include "hw_mod_backend.h"
+#include "flow_api.h"
+
+void *flow_api_get_be_dev(struct flow_nic_dev *dev);
+
+#endif  /* __FLOW_API_NIC_SETUP_H__ */
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_filter.c b/drivers/net/ntnic/nthw/flow_api/flow_filter.c
index 7b6e122190..e822ba7df9 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_filter.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_filter.c
@@ -5,6 +5,7 @@
 
 #include "flow_filter.h"
 #include "ntnic_mod_reg.h"
+#include "flow_api_nic_setup.h"
 
 int flow_filter_init(nthw_fpga_t *p_fpga, struct flow_nic_dev **p_flow_device, int adapter_no)
 {
@@ -25,3 +26,23 @@ int flow_filter_init(nthw_fpga_t *p_fpga, struct flow_nic_dev **p_flow_device, i
 
 	return 0;
 }
+
+int flow_filter_done(struct flow_nic_dev *dev)
+{
+	void *be_dev = flow_api_get_be_dev(dev);
+
+	int res = 0;
+
+	if (be_dev) {
+		const struct flow_backend_ops *flow_backend_ops = get_flow_backend_ops();
+
+		if (flow_backend_ops == NULL) {
+			NT_LOG(WRN, FILTER, "%s: flow_backend module uninitialized\n", __func__);
+			return res;
+		}
+
+		flow_backend_ops->bin_flow_backend_done(be_dev);
+	}
+
+	return res;
+}
diff --git a/drivers/net/ntnic/ntnic_mod_reg.h b/drivers/net/ntnic/ntnic_mod_reg.h
index 3251f651be..90d9c73f9f 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.h
+++ b/drivers/net/ntnic/ntnic_mod_reg.h
@@ -121,6 +121,7 @@ void rst9563_ops_init(void);
 struct flow_backend_ops {
 	const struct flow_api_backend_ops *(*bin_flow_backend_init)(nthw_fpga_t *p_fpga,
 		void **be_dev);
+	void (*bin_flow_backend_done)(void *be_dev);
 };
 
 const struct flow_backend_ops *get_flow_backend_ops(void);
-- 
2.45.0


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

* [PATCH v1 05/31] net/ntnic: add INFO flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (9 preceding siblings ...)
  2024-10-04 15:06 ` [PATCH v1 04/31] net/ntnic: add flow backend deinitialization API Serhii Iliushyk
@ 2024-10-04 15:06 ` Serhii Iliushyk
  2024-10-04 15:06 ` [PATCH v1 06/31] net/ntnic: add categorizer (CAT) " Serhii Iliushyk
                   ` (40 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The info module keeps track of the hardcoded parameters of the FPGA
and provides an abstraction that can support if parameter is unsupported
for a given FPGA.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    |  57 +++
 drivers/net/ntnic/meson.build                 |   3 +
 .../nthw/flow_api/flow_backend/flow_backend.c | 384 ++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_info.c   | 341 ++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_info.h   | 110 +++++
 drivers/net/ntnic/nthw/nthw_drv.h             |   2 +
 drivers/net/ntnic/nthw/nthw_helper.h          |  11 +
 drivers/net/ntnic/ntnic_mod_reg.c             |   8 +
 drivers/net/ntnic/ntnic_mod_reg.h             |   2 +
 drivers/net/ntnic/ntutil/nt_util.h            |   5 +
 10 files changed, 923 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_info.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_info.h
 create mode 100644 drivers/net/ntnic/nthw/nthw_helper.h

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 46054a6a85..11a0d62c41 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -6,6 +6,63 @@
 #ifndef _HW_MOD_BACKEND_H_
 #define _HW_MOD_BACKEND_H_
 
+#define MAX_PHYS_ADAPTERS 8
+
+enum debug_mode_e {
+	FLOW_BACKEND_DEBUG_MODE_NONE = 0x0000,
+	FLOW_BACKEND_DEBUG_MODE_WRITE = 0x0001
+};
+
+struct flow_api_backend_ops {
+	int version;
+	int (*set_debug_mode)(void *dev, enum debug_mode_e mode);
+	int (*get_nb_phy_port)(void *dev);
+	int (*get_nb_rx_port)(void *dev);
+	int (*get_ltx_avail)(void *dev);
+	int (*get_nb_cat_funcs)(void *dev);
+	int (*get_nb_categories)(void *dev);
+	int (*get_nb_cat_km_if_cnt)(void *dev);
+	int (*get_nb_cat_km_if_m0)(void *dev);
+	int (*get_nb_cat_km_if_m1)(void *dev);
+
+	int (*get_nb_queues)(void *dev);
+	int (*get_nb_km_flow_types)(void *dev);
+	int (*get_nb_pm_ext)(void *dev);
+	int (*get_nb_len)(void *dev);
+	int (*get_kcc_size)(void *dev);
+	int (*get_kcc_banks)(void *dev);
+	int (*get_nb_km_categories)(void *dev);
+	int (*get_nb_km_cam_banks)(void *dev);
+	int (*get_nb_km_cam_record_words)(void *dev);
+	int (*get_nb_km_cam_records)(void *dev);
+	int (*get_nb_km_tcam_banks)(void *dev);
+	int (*get_nb_km_tcam_bank_width)(void *dev);
+	int (*get_nb_flm_categories)(void *dev);
+	int (*get_nb_flm_size_mb)(void *dev);
+	int (*get_nb_flm_entry_size)(void *dev);
+	int (*get_nb_flm_variant)(void *dev);
+	int (*get_nb_flm_prios)(void *dev);
+	int (*get_nb_flm_pst_profiles)(void *dev);
+	int (*get_nb_flm_scrub_profiles)(void *dev);
+	int (*get_nb_flm_load_aps_max)(void *dev);
+	int (*get_nb_qsl_categories)(void *dev);
+	int (*get_nb_qsl_qst_entries)(void *dev);
+	int (*get_nb_pdb_categories)(void *dev);
+	int (*get_nb_roa_categories)(void *dev);
+	int (*get_nb_tpe_categories)(void *dev);
+	int (*get_nb_tx_cpy_writers)(void *dev);
+	int (*get_nb_tx_cpy_mask_mem)(void *dev);
+	int (*get_nb_tx_rpl_depth)(void *dev);
+	int (*get_nb_tx_rpl_ext_categories)(void *dev);
+	int (*get_nb_tpe_ifr_categories)(void *dev);
+	int (*get_nb_rpp_per_ps)(void *dev);
+	int (*get_nb_hsh_categories)(void *dev);
+	int (*get_nb_hsh_toeplitz)(void *dev);
+
+	int (*alloc_rx_queue)(void *dev, int queue_id);
+	int (*free_rx_queue)(void *dev, int hw_queue);
+};
+
 struct flow_api_backend_s {
 	void *be_dev;
 };
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 00b1ae4c70..b771a600e4 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -17,6 +17,7 @@ includes = [
         include_directories('nthw'),
         include_directories('nthw/supported'),
         include_directories('nthw/model'),
+        include_directories('nthw/flow_filter'),
         include_directories('nim/'),
 ]
 
@@ -43,7 +44,9 @@ sources = files(
         'nthw/core/nthw_sdc.c',
         'nthw/core/nthw_si5340.c',
         'nthw/flow_api/flow_api.c',
+        'nthw/flow_api/flow_backend/flow_backend.c',
         'nthw/flow_api/flow_filter.c',
+        'nthw/flow_filter/flow_nthw_info.c',
         'nthw/model/nthw_fpga_model.c',
         'nthw/nthw_platform.c',
         'nthw/nthw_rac.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
new file mode 100644
index 0000000000..f3ad3686d4
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -0,0 +1,384 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdint.h>
+
+#include "flow_nthw_info.h"
+#include "ntnic_mod_reg.h"
+#include "nthw_fpga_model.h"
+#include "hw_mod_backend.h"
+
+/*
+ * Binary Flow API backend implementation into ntservice driver
+ *
+ * General note on this backend implementation:
+ * Maybe use shadow class to combine multiple writes. However, this backend is only for dev/testing
+ */
+
+static struct backend_dev_s {
+	uint8_t adapter_no;
+	enum debug_mode_e dmode;
+	struct info_nthw *p_info_nthw;
+} be_devs[MAX_PHYS_ADAPTERS];
+
+const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, void **be_dev);
+static void bin_flow_backend_done(void *be_dev);
+
+static int set_debug_mode(void *be_dev, enum debug_mode_e mode)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	be->dmode = mode;
+	return 0;
+}
+
+/*
+ * INFO
+ */
+
+static int get_nb_phy_ports(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_phy_ports(be->p_info_nthw);
+}
+
+static int get_nb_rx_ports(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_rx_ports(be->p_info_nthw);
+}
+
+static int get_ltx_avail(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_ltx_avail(be->p_info_nthw);
+}
+
+static int get_nb_cat_funcs(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_cat_funcs(be->p_info_nthw);
+}
+
+static int get_nb_categories(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_categories(be->p_info_nthw);
+}
+
+static int get_nb_cat_km_if_cnt(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_cat_km_if_cnt(be->p_info_nthw);
+}
+
+static int get_nb_cat_km_if_m0(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_cat_km_if_m0(be->p_info_nthw);
+}
+
+static int get_nb_cat_km_if_m1(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_cat_km_if_m1(be->p_info_nthw);
+}
+
+static int get_nb_queues(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_queues(be->p_info_nthw);
+}
+
+static int get_nb_km_flow_types(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_km_flow_types(be->p_info_nthw);
+}
+
+static int get_nb_pm_ext(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_pm_ext(be->p_info_nthw);
+}
+
+static int get_nb_len(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_len(be->p_info_nthw);
+}
+
+static int get_kcc_size(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_kcc_size(be->p_info_nthw);
+}
+
+static int get_kcc_banks(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_kcc_banks(be->p_info_nthw);
+}
+
+static int get_nb_km_categories(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_km_categories(be->p_info_nthw);
+}
+
+static int get_nb_km_cam_banks(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_km_cam_banks(be->p_info_nthw);
+}
+
+static int get_nb_km_cam_record_words(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_km_cam_record_words(be->p_info_nthw);
+}
+
+static int get_nb_km_cam_records(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_km_cam_records(be->p_info_nthw);
+}
+
+static int get_nb_km_tcam_banks(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_km_tcam_banks(be->p_info_nthw);
+}
+
+static int get_nb_km_tcam_bank_width(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_km_tcam_bank_width(be->p_info_nthw);
+}
+
+static int get_nb_flm_categories(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_flm_categories(be->p_info_nthw);
+}
+
+static int get_nb_flm_size_mb(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_flm_size_mb(be->p_info_nthw);
+}
+
+static int get_nb_flm_entry_size(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_flm_entry_size(be->p_info_nthw);
+}
+
+static int get_nb_flm_variant(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_flm_variant(be->p_info_nthw);
+}
+
+static int get_nb_flm_prios(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_flm_prios(be->p_info_nthw);
+}
+
+static int get_nb_flm_pst_profiles(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_flm_pst_profiles(be->p_info_nthw);
+}
+
+static int get_nb_flm_scrub_profiles(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_flm_scrub_profiles(be->p_info_nthw);
+}
+
+static int get_nb_flm_load_aps_max(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_flm_load_aps_max(be->p_info_nthw);
+}
+
+static int get_nb_qsl_categories(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_qsl_categories(be->p_info_nthw);
+}
+
+static int get_nb_qsl_qst_entries(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_qsl_qst_entries(be->p_info_nthw);
+}
+
+static int get_nb_pdb_categories(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_pdb_categories(be->p_info_nthw);
+}
+
+static int get_nb_roa_categories(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_roa_categories(be->p_info_nthw);
+}
+
+static int get_nb_tpe_categories(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_tpe_categories(be->p_info_nthw);
+}
+
+static int get_nb_tx_cpy_writers(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_tx_cpy_writers(be->p_info_nthw);
+}
+
+static int get_nb_tx_cpy_mask_mem(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_tx_cpy_mask_mem(be->p_info_nthw);
+}
+
+static int get_nb_tx_rpl_depth(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_tx_rpl_depth(be->p_info_nthw);
+}
+
+static int get_nb_tx_rpl_ext_categories(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_tx_rpl_ext_categories(be->p_info_nthw);
+}
+
+static int get_nb_tpe_ifr_categories(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_tpe_ifr_categories(be->p_info_nthw);
+}
+
+static int get_nb_rpp_per_ps(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_rpp_per_ps(be->p_info_nthw);
+}
+
+static int get_nb_hsh_categories(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_hsh_categories(be->p_info_nthw);
+}
+
+static int get_nb_hsh_toeplitz(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return info_nthw_get_nb_hsh_toeplitz(be->p_info_nthw);
+}
+
+/*
+ * DBS
+ */
+
+static int alloc_rx_queue(void *be_dev, int queue_id)
+{
+	(void)be_dev;
+	(void)queue_id;
+	NT_LOG(ERR, FILTER, "ERROR alloc Rx queue\n");
+	return -1;
+}
+
+static int free_rx_queue(void *be_dev, int hw_queue)
+{
+	(void)be_dev;
+	(void)hw_queue;
+	NT_LOG(ERR, FILTER, "ERROR free Rx queue\n");
+	return 0;
+}
+
+const struct flow_api_backend_ops flow_be_iface = {
+	1,
+
+	set_debug_mode,
+	get_nb_phy_ports,
+	get_nb_rx_ports,
+	get_ltx_avail,
+	get_nb_cat_funcs,
+	get_nb_categories,
+	get_nb_cat_km_if_cnt,
+	get_nb_cat_km_if_m0,
+	get_nb_cat_km_if_m1,
+	get_nb_queues,
+	get_nb_km_flow_types,
+	get_nb_pm_ext,
+	get_nb_len,
+	get_kcc_size,
+	get_kcc_banks,
+	get_nb_km_categories,
+	get_nb_km_cam_banks,
+	get_nb_km_cam_record_words,
+	get_nb_km_cam_records,
+	get_nb_km_tcam_banks,
+	get_nb_km_tcam_bank_width,
+	get_nb_flm_categories,
+	get_nb_flm_size_mb,
+	get_nb_flm_entry_size,
+	get_nb_flm_variant,
+	get_nb_flm_prios,
+	get_nb_flm_pst_profiles,
+	get_nb_flm_scrub_profiles,
+	get_nb_flm_load_aps_max,
+	get_nb_qsl_categories,
+	get_nb_qsl_qst_entries,
+	get_nb_pdb_categories,
+	get_nb_roa_categories,
+	get_nb_tpe_categories,
+	get_nb_tx_cpy_writers,
+	get_nb_tx_cpy_mask_mem,
+	get_nb_tx_rpl_depth,
+	get_nb_tx_rpl_ext_categories,
+	get_nb_tpe_ifr_categories,
+	get_nb_rpp_per_ps,
+	get_nb_hsh_categories,
+	get_nb_hsh_toeplitz,
+
+	alloc_rx_queue,
+	free_rx_queue,
+};
+
+const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, void **dev)
+{
+	uint8_t physical_adapter_no = (uint8_t)p_fpga->p_fpga_info->adapter_no;
+
+	struct info_nthw *pinfonthw = info_nthw_new();
+	info_nthw_init(pinfonthw, p_fpga, physical_adapter_no);
+	be_devs[physical_adapter_no].p_info_nthw = pinfonthw;
+
+	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
+	*dev = (void *)&be_devs[physical_adapter_no];
+
+	return &flow_be_iface;
+}
+
+static void bin_flow_backend_done(void *dev)
+{
+	struct backend_dev_s *be_dev = (struct backend_dev_s *)dev;
+	info_nthw_delete(be_dev->p_info_nthw);
+}
+
+static const struct flow_backend_ops ops = {
+	.bin_flow_backend_init = bin_flow_backend_init,
+	.bin_flow_backend_done = bin_flow_backend_done,
+};
+
+void flow_backend_init(void)
+{
+	register_flow_backend_ops(&ops);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_info.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_info.c
new file mode 100644
index 0000000000..8e0b24dd9a
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_info.c
@@ -0,0 +1,341 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "nt_util.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_info.h"
+
+static inline unsigned int clamp_one(unsigned int val)
+{
+	return val > 1 ? 1 : val;
+}
+
+struct info_nthw *info_nthw_new(void)
+{
+	struct info_nthw *p = malloc(sizeof(struct info_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void info_nthw_delete(struct info_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int info_nthw_init(struct info_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	assert(n_instance >= 0 && n_instance < 256);
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+
+	unsigned int km_present = clamp_one(nthw_fpga_get_product_param(p_fpga, NT_KM_PRESENT, 0));
+	unsigned int kcc_present =
+		clamp_one(nthw_fpga_get_product_param(p_fpga, NT_CAT_KCC_PRESENT, 0));
+	unsigned int roa_present =
+		clamp_one(nthw_fpga_get_product_param(p_fpga, NT_ROA_PRESENT, 0));
+	unsigned int dbs_present =
+		clamp_one(nthw_fpga_get_product_param(p_fpga, NT_DBS_PRESENT, 0));
+	unsigned int flm_present =
+		clamp_one(nthw_fpga_get_product_param(p_fpga, NT_FLM_PRESENT, 0));
+	unsigned int hst_present =
+		clamp_one(nthw_fpga_get_product_param(p_fpga, NT_HST_PRESENT, 0));
+
+	/* Modules for Tx Packet Edit function */
+	unsigned int hfu_present =
+		clamp_one(nthw_fpga_get_product_param(p_fpga, NT_HFU_PRESENT, 0));
+	unsigned int tx_cpy_present =
+		clamp_one(nthw_fpga_get_product_param(p_fpga, NT_TX_CPY_PRESENT, 0));
+	unsigned int tx_ins_present =
+		clamp_one(nthw_fpga_get_product_param(p_fpga, NT_TX_INS_PRESENT, 0));
+	unsigned int tx_rpl_present =
+		clamp_one(nthw_fpga_get_product_param(p_fpga, NT_TX_RPL_PRESENT, 0));
+	unsigned int csu_present =
+		clamp_one(nthw_fpga_get_product_param(p_fpga, NT_CSU_PRESENT, 0));
+	unsigned int tpe_present =
+		(hfu_present && tx_cpy_present && tx_ins_present && tx_rpl_present && csu_present)
+		? 1
+		: 0;
+
+	p->n_phy_ports = nthw_fpga_get_product_param(p_fpga, NT_PHY_PORTS, 0);
+	p->n_rx_ports = nthw_fpga_get_product_param(p_fpga, NT_RX_PORTS, 0);
+	p->n_ltx_avail = nthw_fpga_get_product_param(p_fpga, NT_LR_PRESENT, 0);
+	p->nb_cat_func = nthw_fpga_get_product_param(p_fpga, NT_CAT_FUNCS, 0);
+	p->nb_categories = nthw_fpga_get_product_param(p_fpga, NT_CATEGORIES, 0);
+	p->nb_queues = nthw_fpga_get_product_param(p_fpga, NT_QUEUES, 0);
+	p->nb_flow_types = nthw_fpga_get_product_param(p_fpga, NT_KM_FLOW_TYPES, 0) *
+		clamp_one(km_present + flm_present);
+	p->nb_pm_ext = nthw_fpga_get_product_param(p_fpga, NT_CAT_N_EXT, 0);
+	p->nb_len = nthw_fpga_get_product_param(p_fpga, NT_CAT_N_LEN, 0);
+	p->nb_kcc_size = nthw_fpga_get_product_param(p_fpga, NT_CAT_KCC_SIZE, 0) * kcc_present;
+	p->nb_kcc_banks = nthw_fpga_get_product_param(p_fpga, NT_CAT_KCC_BANKS, 0) * kcc_present;
+	p->nb_km_categories =
+		nthw_fpga_get_product_param(p_fpga, NT_KM_CATEGORIES, 0) * km_present;
+	p->nb_km_cam_banks = nthw_fpga_get_product_param(p_fpga, NT_KM_CAM_BANKS, 0) * km_present;
+	p->nb_km_cam_record_words =
+		nthw_fpga_get_product_param(p_fpga, NT_KM_CAM_REC_WORDS, 0) * km_present;
+	p->nb_km_cam_records =
+		nthw_fpga_get_product_param(p_fpga, NT_KM_CAM_RECORDS, 0) * km_present;
+	p->nb_km_tcam_banks =
+		nthw_fpga_get_product_param(p_fpga, NT_KM_TCAM_BANKS, 0) * km_present;
+	p->nb_km_tcam_bank_width =
+		nthw_fpga_get_product_param(p_fpga, NT_KM_TCAM_BANK_WIDTH, 0) * km_present;
+	p->nb_flm_categories =
+		nthw_fpga_get_product_param(p_fpga, NT_FLM_CATEGORIES, 0) * flm_present;
+	p->nb_flm_size_mb = nthw_fpga_get_product_param(p_fpga, NT_FLM_SIZE_MB, 0);
+	p->nb_flm_entry_size = nthw_fpga_get_product_param(p_fpga, NT_FLM_ENTRY_SIZE, 0);
+	p->nb_flm_variant = nthw_fpga_get_product_param(p_fpga, NT_FLM_VARIANT, 0);
+	p->nb_flm_prios = nthw_fpga_get_product_param(p_fpga, NT_FLM_PRIOS, 0) * flm_present;
+	p->nb_flm_pst_profiles =
+		nthw_fpga_get_product_param(p_fpga, NT_FLM_PST_PROFILES, 0) * flm_present;
+	p->nb_flm_scrub_profiles =
+		nthw_fpga_get_product_param(p_fpga, NT_FLM_SCRUB_PROFILES, 0) * flm_present;
+	p->nb_flm_load_aps_max = nthw_fpga_get_product_param(p_fpga, NT_FLM_LOAD_APS_MAX, 0);
+	p->nb_hst_categories =
+		nthw_fpga_get_product_param(p_fpga, NT_HST_CATEGORIES, 0) * hst_present;
+	p->nb_qsl_categories = nthw_fpga_get_product_param(p_fpga, NT_QSL_CATEGORIES, 0);
+	p->nb_qsl_qst_entries = nthw_fpga_get_product_param(p_fpga, NT_QSL_QST_SIZE, 0);
+	p->nb_pdb_categories = nthw_fpga_get_product_param(p_fpga, NT_PDB_CATEGORIES, 0);
+	p->nb_roa_categories =
+		nthw_fpga_get_product_param(p_fpga, NT_ROA_CATEGORIES, 0) * roa_present;
+	p->nb_dbs_categories = min(nthw_fpga_get_product_param(p_fpga, NT_DBS_RX_QUEUES, 0),
+			nthw_fpga_get_product_param(p_fpga, NT_DBS_TX_QUEUES, 0)) *
+		dbs_present;
+	p->nb_cat_km_if_cnt =
+		nthw_fpga_get_product_param(p_fpga, NT_CAT_KM_IF_CNT, km_present + flm_present);
+	p->m_cat_km_if_m0 = nthw_fpga_get_product_param(p_fpga, NT_CAT_KM_IF_M0, -1);
+	p->m_cat_km_if_m1 = nthw_fpga_get_product_param(p_fpga, NT_CAT_KM_IF_M1, -1);
+	p->nb_tpe_categories =
+		nthw_fpga_get_product_param(p_fpga, NT_TPE_CATEGORIES, 0) * tpe_present;
+	p->nb_tx_cpy_writers =
+		nthw_fpga_get_product_param(p_fpga, NT_TX_CPY_WRITERS, 0) * tpe_present;
+	p->nb_tx_cpy_mask_mem =
+		nthw_fpga_get_product_param(p_fpga, NT_CPY_MASK_MEM, 0) * tpe_present;
+	p->nb_tx_rpl_depth = nthw_fpga_get_product_param(p_fpga, NT_TX_RPL_DEPTH, 0) * tpe_present;
+	p->nb_tx_rpl_ext_categories =
+		nthw_fpga_get_product_param(p_fpga, NT_TX_RPL_EXT_CATEGORIES, 0) * tpe_present;
+	p->nb_tpe_ifr_categories = nthw_fpga_get_product_param(p_fpga, NT_TX_MTU_PROFILE_IFR, 0);
+	p->nb_rpp_per_ps = nthw_fpga_get_product_param(p_fpga, NT_RPP_PER_PS, 0);
+	p->nb_hsh_categories = nthw_fpga_get_product_param(p_fpga, NT_HSH_CATEGORIES, 0);
+	p->nb_hsh_toeplitz = nthw_fpga_get_product_param(p_fpga, NT_HSH_TOEPLITZ, 0);
+	return 0;
+}
+
+unsigned int info_nthw_get_nb_phy_ports(const struct info_nthw *p)
+{
+	return p->n_phy_ports;
+}
+
+unsigned int info_nthw_get_nb_rx_ports(const struct info_nthw *p)
+{
+	return p->n_rx_ports;
+}
+
+unsigned int info_nthw_get_ltx_avail(const struct info_nthw *p)
+{
+	return p->n_ltx_avail;
+}
+
+unsigned int info_nthw_get_nb_categories(const struct info_nthw *p)
+{
+	return p->nb_categories;
+}
+
+unsigned int info_nthw_get_kcc_size(const struct info_nthw *p)
+{
+	return p->nb_kcc_size;
+}
+
+unsigned int info_nthw_get_kcc_banks(const struct info_nthw *p)
+{
+	return p->nb_kcc_banks;
+}
+
+unsigned int info_nthw_get_nb_queues(const struct info_nthw *p)
+{
+	return p->nb_queues;
+}
+
+unsigned int info_nthw_get_nb_cat_funcs(const struct info_nthw *p)
+{
+	return p->nb_cat_func;
+}
+
+unsigned int info_nthw_get_nb_km_flow_types(const struct info_nthw *p)
+{
+	return p->nb_flow_types;
+}
+
+unsigned int info_nthw_get_nb_pm_ext(const struct info_nthw *p)
+{
+	return p->nb_pm_ext;
+}
+
+unsigned int info_nthw_get_nb_len(const struct info_nthw *p)
+{
+	return p->nb_len;
+}
+
+unsigned int info_nthw_get_nb_km_categories(const struct info_nthw *p)
+{
+	return p->nb_km_categories;
+}
+
+unsigned int info_nthw_get_nb_km_cam_banks(const struct info_nthw *p)
+{
+	return p->nb_km_cam_banks;
+}
+
+unsigned int info_nthw_get_nb_km_cam_record_words(const struct info_nthw *p)
+{
+	return p->nb_km_cam_record_words;
+}
+
+unsigned int info_nthw_get_nb_km_cam_records(const struct info_nthw *p)
+{
+	return p->nb_km_cam_records;
+}
+
+unsigned int info_nthw_get_nb_km_tcam_banks(const struct info_nthw *p)
+{
+	return p->nb_km_tcam_banks;
+}
+
+unsigned int info_nthw_get_nb_km_tcam_bank_width(const struct info_nthw *p)
+{
+	return p->nb_km_tcam_bank_width;
+}
+
+unsigned int info_nthw_get_nb_flm_categories(const struct info_nthw *p)
+{
+	return p->nb_flm_categories;
+}
+
+unsigned int info_nthw_get_nb_flm_size_mb(const struct info_nthw *p)
+{
+	return p->nb_flm_size_mb;
+}
+
+unsigned int info_nthw_get_nb_flm_entry_size(const struct info_nthw *p)
+{
+	return p->nb_flm_entry_size;
+}
+
+unsigned int info_nthw_get_nb_flm_variant(const struct info_nthw *p)
+{
+	return p->nb_flm_variant;
+}
+
+unsigned int info_nthw_get_nb_flm_prios(const struct info_nthw *p)
+{
+	return p->nb_flm_prios;
+}
+
+unsigned int info_nthw_get_nb_flm_pst_profiles(const struct info_nthw *p)
+{
+	return p->nb_flm_pst_profiles;
+}
+
+unsigned int info_nthw_get_nb_flm_scrub_profiles(const struct info_nthw *p)
+{
+	return p->nb_flm_scrub_profiles;
+}
+
+unsigned int info_nthw_get_nb_flm_load_aps_max(const struct info_nthw *p)
+{
+	return p->nb_flm_load_aps_max;
+}
+
+unsigned int info_nthw_get_nb_qsl_categories(const struct info_nthw *p)
+{
+	return p->nb_qsl_categories;
+}
+
+unsigned int info_nthw_get_nb_qsl_qst_entries(const struct info_nthw *p)
+{
+	return p->nb_qsl_qst_entries;
+}
+
+unsigned int info_nthw_get_nb_pdb_categories(const struct info_nthw *p)
+{
+	return p->nb_pdb_categories;
+}
+
+unsigned int info_nthw_get_nb_roa_categories(const struct info_nthw *p)
+{
+	return p->nb_roa_categories;
+}
+
+unsigned int info_nthw_get_nb_cat_km_if_cnt(const struct info_nthw *p)
+{
+	return p->nb_cat_km_if_cnt;
+}
+
+unsigned int info_nthw_get_nb_cat_km_if_m0(const struct info_nthw *p)
+{
+	return p->m_cat_km_if_m0;
+}
+
+unsigned int info_nthw_get_nb_cat_km_if_m1(const struct info_nthw *p)
+{
+	return p->m_cat_km_if_m1;
+}
+
+unsigned int info_nthw_get_nb_tpe_categories(const struct info_nthw *p)
+{
+	return p->nb_tpe_categories;
+}
+
+unsigned int info_nthw_get_nb_tx_cpy_writers(const struct info_nthw *p)
+{
+	return p->nb_tx_cpy_writers;
+}
+
+unsigned int info_nthw_get_nb_tx_cpy_mask_mem(const struct info_nthw *p)
+{
+	return p->nb_tx_cpy_mask_mem;
+}
+
+unsigned int info_nthw_get_nb_tx_rpl_depth(const struct info_nthw *p)
+{
+	return p->nb_tx_rpl_depth;
+}
+
+unsigned int info_nthw_get_nb_tx_rpl_ext_categories(const struct info_nthw *p)
+{
+	return p->nb_tx_rpl_ext_categories;
+}
+
+unsigned int info_nthw_get_nb_tpe_ifr_categories(const struct info_nthw *p)
+{
+	return p->nb_tpe_ifr_categories;
+}
+
+unsigned int info_nthw_get_nb_rpp_per_ps(const struct info_nthw *p)
+{
+	return p->nb_rpp_per_ps;
+}
+
+unsigned int info_nthw_get_nb_hsh_categories(const struct info_nthw *p)
+{
+	return p->nb_hsh_categories;
+}
+
+unsigned int info_nthw_get_nb_hsh_toeplitz(const struct info_nthw *p)
+{
+	return p->nb_hsh_toeplitz;
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_info.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_info.h
new file mode 100644
index 0000000000..d726e89e57
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_info.h
@@ -0,0 +1,110 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_INFO_H__
+#define __FLOW_NTHW_INFO_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct info_nthw;
+
+struct info_nthw *info_nthw_new(void);
+void info_nthw_delete(struct info_nthw *p);
+int info_nthw_init(struct info_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+unsigned int info_nthw_get_nb_phy_ports(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_rx_ports(const struct info_nthw *p);
+unsigned int info_nthw_get_ltx_avail(const struct info_nthw *p);
+
+unsigned int info_nthw_get_nb_categories(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_queues(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_cat_funcs(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_km_flow_types(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_pm_ext(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_len(const struct info_nthw *p);
+unsigned int info_nthw_get_kcc_size(const struct info_nthw *p);
+unsigned int info_nthw_get_kcc_banks(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_km_categories(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_km_cam_banks(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_km_cam_record_words(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_km_cam_records(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_km_tcam_banks(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_km_tcam_bank_width(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_flm_categories(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_flm_size_mb(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_flm_entry_size(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_flm_variant(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_flm_prios(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_flm_pst_profiles(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_flm_scrub_profiles(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_flm_load_aps_max(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_qsl_categories(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_qsl_qst_entries(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_pdb_categories(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_roa_categories(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_cat_km_if_cnt(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_cat_km_if_m0(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_cat_km_if_m1(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_tpe_categories(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_tx_cpy_writers(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_tx_cpy_mask_mem(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_tx_rpl_depth(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_tx_rpl_ext_categories(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_tpe_ifr_categories(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_rpp_per_ps(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_hsh_categories(const struct info_nthw *p);
+unsigned int info_nthw_get_nb_hsh_toeplitz(const struct info_nthw *p);
+
+struct info_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+	unsigned int n_phy_ports;
+	unsigned int n_rx_ports;
+	unsigned int n_ltx_avail;
+	unsigned int nb_cat_func;
+	unsigned int nb_categories;
+	unsigned int nb_queues;
+	unsigned int nb_flow_types;
+	unsigned int nb_pm_ext;
+	unsigned int nb_len;
+	unsigned int nb_kcc_size;
+	unsigned int nb_kcc_banks;
+	unsigned int nb_km_categories;
+	unsigned int nb_km_cam_banks;
+	unsigned int nb_km_cam_record_words;
+	unsigned int nb_km_cam_records;
+	unsigned int nb_km_tcam_banks;
+	unsigned int nb_km_tcam_bank_width;
+	unsigned int nb_flm_categories;
+	unsigned int nb_flm_size_mb;
+	unsigned int nb_flm_entry_size;
+	unsigned int nb_flm_variant;
+	unsigned int nb_flm_prios;
+	unsigned int nb_flm_pst_profiles;
+	unsigned int nb_flm_scrub_profiles;
+	unsigned int nb_flm_load_aps_max;
+	unsigned int nb_hst_categories;
+	unsigned int nb_qsl_categories;
+	unsigned int nb_qsl_qst_entries;
+	unsigned int nb_pdb_categories;
+	unsigned int nb_roa_categories;
+	unsigned int nb_dbs_categories;
+	unsigned int nb_cat_km_if_cnt;
+	unsigned int m_cat_km_if_m0;
+	unsigned int m_cat_km_if_m1;
+	unsigned int nb_tpe_categories;
+	unsigned int nb_tx_cpy_writers;
+	unsigned int nb_tx_cpy_mask_mem;
+	unsigned int nb_tx_rpl_depth;
+	unsigned int nb_tx_rpl_ext_categories;
+	unsigned int nb_tpe_ifr_categories;
+	unsigned int nb_rpp_per_ps;
+	unsigned int nb_hsh_categories;
+	unsigned int nb_hsh_toeplitz;
+};
+
+#endif  /* __FLOW_NTHW_INFO_H__ */
diff --git a/drivers/net/ntnic/nthw/nthw_drv.h b/drivers/net/ntnic/nthw/nthw_drv.h
index de60ae171e..41500f49dd 100644
--- a/drivers/net/ntnic/nthw/nthw_drv.h
+++ b/drivers/net/ntnic/nthw/nthw_drv.h
@@ -14,6 +14,8 @@ typedef enum nt_meta_port_type_e {
 	PORT_TYPE_OVERRIDE,
 } nt_meta_port_type_t;
 
+#include "nthw_helper.h"
+
 enum fpga_info_profile {
 	FPGA_INFO_PROFILE_UNKNOWN = 0,
 	FPGA_INFO_PROFILE_VSWITCH = 1,
diff --git a/drivers/net/ntnic/nthw/nthw_helper.h b/drivers/net/ntnic/nthw/nthw_helper.h
new file mode 100644
index 0000000000..25a8d2a947
--- /dev/null
+++ b/drivers/net/ntnic/nthw/nthw_helper.h
@@ -0,0 +1,11 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NTHW_HELPER_H__
+#define __NTHW_HELPER_H__
+
+#include <assert.h>
+
+#endif  /* __NTHW_HELPER_H__ */
diff --git a/drivers/net/ntnic/ntnic_mod_reg.c b/drivers/net/ntnic/ntnic_mod_reg.c
index 2094e1fbb9..ff9afbeb7c 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.c
+++ b/drivers/net/ntnic/ntnic_mod_reg.c
@@ -91,8 +91,16 @@ struct rst9563_ops *get_rst9563_ops(void)
 
 static const struct flow_backend_ops *flow_backend_ops;
 
+void register_flow_backend_ops(const struct flow_backend_ops *ops)
+{
+	flow_backend_ops = ops;
+}
+
 const struct flow_backend_ops *get_flow_backend_ops(void)
 {
+	if (flow_backend_ops == NULL)
+		flow_backend_init();
+
 	return flow_backend_ops;
 }
 
diff --git a/drivers/net/ntnic/ntnic_mod_reg.h b/drivers/net/ntnic/ntnic_mod_reg.h
index 90d9c73f9f..602f5de77d 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.h
+++ b/drivers/net/ntnic/ntnic_mod_reg.h
@@ -124,7 +124,9 @@ struct flow_backend_ops {
 	void (*bin_flow_backend_done)(void *be_dev);
 };
 
+void register_flow_backend_ops(const struct flow_backend_ops *ops);
 const struct flow_backend_ops *get_flow_backend_ops(void);
+void flow_backend_init(void);
 
 struct flow_filter_ops {
 	int (*flow_filter_init)(nthw_fpga_t *p_fpga, struct flow_nic_dev **p_flow_device,
diff --git a/drivers/net/ntnic/ntutil/nt_util.h b/drivers/net/ntnic/ntutil/nt_util.h
index ea91181a06..540cd615f2 100644
--- a/drivers/net/ntnic/ntutil/nt_util.h
+++ b/drivers/net/ntnic/ntutil/nt_util.h
@@ -23,6 +23,11 @@
 uint64_t nt_os_get_time_monotonic_counter(void);
 void nt_os_wait_usec(int val);
 
+static inline int min(int a, int b)
+{
+	return (a < b) ? a : b;
+}
+
 uint64_t nt_util_align_size(uint64_t size);
 
 struct nt_dma_s {
-- 
2.45.0


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

* [PATCH v1 06/31] net/ntnic: add categorizer (CAT) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (10 preceding siblings ...)
  2024-10-04 15:06 ` [PATCH v1 05/31] net/ntnic: add INFO flow module Serhii Iliushyk
@ 2024-10-04 15:06 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 07/31] net/ntnic: add key match (KM) " Serhii Iliushyk
                   ` (39 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:06 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Categorizer module’s main purpose is to select the behavior
of other modules in the FPGA pipeline, depending on a protocol check.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    |  51 +
 drivers/net/ntnic/include/hw_mod_cat_v18.h    | 141 +++
 drivers/net/ntnic/include/hw_mod_cat_v21.h    |  91 ++
 drivers/net/ntnic/meson.build                 |   1 +
 .../nthw/flow_api/flow_backend/flow_backend.c | 465 ++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_cat.c    | 872 ++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_cat.h    | 291 ++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |   1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |   1 +
 .../nthw/supported/nthw_fpga_reg_defs_cat.h   | 238 +++++
 10 files changed, 2152 insertions(+)
 create mode 100644 drivers/net/ntnic/include/hw_mod_cat_v18.h
 create mode 100644 drivers/net/ntnic/include/hw_mod_cat_v21.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_cat.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_cat.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_cat.h

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 11a0d62c41..ce2c0cf7cf 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -6,8 +6,40 @@
 #ifndef _HW_MOD_BACKEND_H_
 #define _HW_MOD_BACKEND_H_
 
+#include <stdbool.h>
+
+#include "hw_mod_cat_v18.h"
+#include "hw_mod_cat_v21.h"
+
 #define MAX_PHYS_ADAPTERS 8
 
+#define COMMON_FUNC_INFO_S                                                                        \
+	int ver;                                                                                  \
+	void *base;                                                                               \
+	unsigned int alloced_size;                                                                \
+	int debug
+
+struct cat_func_s {
+	COMMON_FUNC_INFO_S;
+	uint32_t nb_cat_funcs;
+	uint32_t nb_flow_types;
+	uint32_t nb_pm_ext;
+	uint32_t nb_len;
+	uint32_t kcc_size;
+	uint32_t cts_num;
+	uint32_t kcc_banks;
+	uint32_t kcc_id_bit_size;
+	uint32_t kcc_records;
+	uint32_t km_if_count;
+	int32_t km_if_m0;
+	int32_t km_if_m1;
+
+	union {
+		struct hw_mod_cat_v18_s v18;
+		struct hw_mod_cat_v21_s v21;
+	};
+};
+
 enum debug_mode_e {
 	FLOW_BACKEND_DEBUG_MODE_NONE = 0x0000,
 	FLOW_BACKEND_DEBUG_MODE_WRITE = 0x0001
@@ -61,6 +93,25 @@ struct flow_api_backend_ops {
 
 	int (*alloc_rx_queue)(void *dev, int queue_id);
 	int (*free_rx_queue)(void *dev, int hw_queue);
+
+	/* CAT */
+	bool (*get_cat_present)(void *dev);
+	uint32_t (*get_cat_version)(void *dev);
+	int (*cat_cfn_flush)(void *dev, const struct cat_func_s *cat, int cat_func, int cnt);
+	int (*cat_kce_flush)(void *dev, const struct cat_func_s *cat, int km_if_idx, int index,
+		int cnt);
+	int (*cat_kcs_flush)(void *dev, const struct cat_func_s *cat, int km_if_idx, int cat_func,
+		int cnt);
+	int (*cat_fte_flush)(void *dev, const struct cat_func_s *cat, int km_if_idx, int index,
+		int cnt);
+	int (*cat_cte_flush)(void *dev, const struct cat_func_s *cat, int cat_func, int cnt);
+	int (*cat_cts_flush)(void *dev, const struct cat_func_s *cat, int index, int cnt);
+	int (*cat_cot_flush)(void *dev, const struct cat_func_s *cat, int cat_func, int cnt);
+	int (*cat_cct_flush)(void *dev, const struct cat_func_s *cat, int index, int cnt);
+	int (*cat_exo_flush)(void *dev, const struct cat_func_s *cat, int index, int cnt);
+	int (*cat_rck_flush)(void *dev, const struct cat_func_s *cat, int index, int cnt);
+	int (*cat_len_flush)(void *dev, const struct cat_func_s *cat, int index, int cnt);
+	int (*cat_kcc_flush)(void *dev, const struct cat_func_s *cat, int index, int cnt);
 };
 
 struct flow_api_backend_s {
diff --git a/drivers/net/ntnic/include/hw_mod_cat_v18.h b/drivers/net/ntnic/include/hw_mod_cat_v18.h
new file mode 100644
index 0000000000..7ba38207a0
--- /dev/null
+++ b/drivers/net/ntnic/include/hw_mod_cat_v18.h
@@ -0,0 +1,141 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _HW_MOD_CAT_V18_H_
+#define _HW_MOD_CAT_V18_H_
+
+#include <stdint.h>
+
+struct cat_v18_cfn_s {
+	uint32_t enable;
+	uint32_t inv;
+	/* protocol checks */
+	uint32_t ptc_inv;
+	uint32_t ptc_isl;
+	uint32_t ptc_cfp;
+	uint32_t ptc_mac;
+	uint32_t ptc_l2;
+	uint32_t ptc_vntag;
+	uint32_t ptc_vlan;
+	uint32_t ptc_mpls;
+	uint32_t ptc_l3;
+	uint32_t ptc_frag;
+	uint32_t ptc_ip_prot;
+	uint32_t ptc_l4;
+	uint32_t ptc_tunnel;
+	uint32_t ptc_tnl_l2;
+	uint32_t ptc_tnl_vlan;
+	uint32_t ptc_tnl_mpls;
+	uint32_t ptc_tnl_l3;
+	uint32_t ptc_tnl_frag;
+	uint32_t ptc_tnl_ip_prot;
+	uint32_t ptc_tnl_l4;
+	/* error checks */
+	uint32_t err_inv;
+	uint32_t err_cv;
+	uint32_t err_fcs;
+	uint32_t err_trunc;
+	uint32_t err_l3_cs;
+	uint32_t err_l4_cs;
+	/* in port */
+	uint32_t mac_port;
+	/* pattern matcher */
+	uint32_t pm_cmp[2];
+	uint32_t pm_dct;
+	uint32_t pm_ext_inv;
+	uint32_t pm_cmb;
+	uint32_t pm_and_inv;
+	uint32_t pm_or_inv;
+	uint32_t pm_inv;
+	uint32_t lc;
+	uint32_t lc_inv;
+	uint32_t km_or;
+};
+
+struct cat_v18_kce_s {
+	uint32_t enable_bm;
+};
+
+struct cat_v18_kcs_s {
+	uint32_t category;
+};
+
+struct cat_v18_fte_s {
+	uint32_t enable_bm;
+};
+
+struct cat_v18_cte_s {
+	union {
+		uint32_t enable_bm;
+		struct {
+			uint32_t col : 1;
+			uint32_t cor : 1;
+			uint32_t hsh : 1;
+			uint32_t qsl : 1;
+			uint32_t ipf : 1;
+			uint32_t slc : 1;
+			uint32_t pdb : 1;
+			uint32_t msk : 1;
+			uint32_t hst : 1;
+			uint32_t epp : 1;
+			uint32_t tpe : 1;
+		} b;
+	};
+};
+
+struct cat_v18_cts_s {
+	uint32_t cat_a;
+	uint32_t cat_b;
+};
+
+struct cat_v18_cot_s {
+	uint32_t color;
+	uint32_t km;
+};
+
+struct cat_v18_cct_s {
+	uint32_t color;
+	uint32_t km;
+};
+
+struct cat_v18_exo_s {
+	uint32_t dyn;
+	int32_t ofs;
+};
+
+struct cat_v18_rck_s {
+	uint32_t rck_data;
+};
+
+struct cat_v18_len_s {
+	uint32_t lower;
+	uint32_t upper;
+	uint32_t dyn1;
+	uint32_t dyn2;
+	uint32_t inv;
+};
+
+struct cat_v18_kcc_s {
+	uint32_t key[2];
+	uint32_t category;
+	uint32_t id;
+};
+
+struct hw_mod_cat_v18_s {
+	struct cat_v18_cfn_s *cfn;
+	struct cat_v18_kce_s *kce;
+	struct cat_v18_kcs_s *kcs;
+	struct cat_v18_fte_s *fte;
+	struct cat_v18_cte_s *cte;
+	struct cat_v18_cts_s *cts;
+	struct cat_v18_cot_s *cot;
+	struct cat_v18_cct_s *cct;
+	struct cat_v18_exo_s *exo;
+	struct cat_v18_rck_s *rck;
+	struct cat_v18_len_s *len;
+	struct cat_v18_kcc_s *kcc_cam;
+};
+
+#endif	/* _HW_MOD_CAT_V18_H_ */
diff --git a/drivers/net/ntnic/include/hw_mod_cat_v21.h b/drivers/net/ntnic/include/hw_mod_cat_v21.h
new file mode 100644
index 0000000000..7dd0038cf1
--- /dev/null
+++ b/drivers/net/ntnic/include/hw_mod_cat_v21.h
@@ -0,0 +1,91 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _HW_MOD_CAT_V21_H_
+#define _HW_MOD_CAT_V21_H_
+
+#include <stdint.h>
+
+#include "hw_mod_cat_v18.h"
+
+struct cat_v21_cfn_s {
+	uint32_t enable;
+	uint32_t inv;
+	/* protocol checks */
+	uint32_t ptc_inv;
+	uint32_t ptc_isl;
+	uint32_t ptc_cfp;
+	uint32_t ptc_mac;
+	uint32_t ptc_l2;
+	uint32_t ptc_vntag;
+	uint32_t ptc_vlan;
+	uint32_t ptc_mpls;
+	uint32_t ptc_l3;
+	uint32_t ptc_frag;
+	uint32_t ptc_ip_prot;
+	uint32_t ptc_l4;
+	uint32_t ptc_tunnel;
+	uint32_t ptc_tnl_l2;
+	uint32_t ptc_tnl_vlan;
+	uint32_t ptc_tnl_mpls;
+	uint32_t ptc_tnl_l3;
+	uint32_t ptc_tnl_frag;
+	uint32_t ptc_tnl_ip_prot;
+	uint32_t ptc_tnl_l4;
+	/* error checks */
+	uint32_t err_inv;
+	uint32_t err_cv;
+	uint32_t err_fcs;
+	uint32_t err_trunc;
+	uint32_t err_l3_cs;
+	uint32_t err_l4_cs;
+	uint32_t err_tnl_l3_cs;
+	uint32_t err_tnl_l4_cs;
+	uint32_t err_ttl_exp;
+	uint32_t err_tnl_ttl_exp;
+	/* in port */
+	uint32_t mac_port;
+	/* pattern matcher */
+	uint32_t pm_cmp[2];
+	uint32_t pm_dct;
+	uint32_t pm_ext_inv;
+	uint32_t pm_cmb;
+	uint32_t pm_and_inv;
+	uint32_t pm_or_inv;
+	uint32_t pm_inv;
+	uint32_t lc;
+	uint32_t lc_inv;
+	uint32_t km0_or;
+	uint32_t km1_or;
+};
+
+struct cat_v21_kce_s {
+	uint32_t enable_bm[2];
+};
+
+struct cat_v21_kcs_s {
+	uint32_t category[2];
+};
+
+struct cat_v21_fte_s {
+	uint32_t enable_bm[2];
+};
+
+struct hw_mod_cat_v21_s {
+	struct cat_v21_cfn_s *cfn;
+	struct cat_v21_kce_s *kce;
+	struct cat_v21_kcs_s *kcs;
+	struct cat_v21_fte_s *fte;
+	struct cat_v18_cte_s *cte;
+	struct cat_v18_cts_s *cts;
+	struct cat_v18_cot_s *cot;
+	struct cat_v18_cct_s *cct;
+	struct cat_v18_exo_s *exo;
+	struct cat_v18_rck_s *rck;
+	struct cat_v18_len_s *len;
+	struct cat_v18_kcc_s *kcc_cam;
+};
+
+#endif	/* _HW_MOD_CAT_V21_H_ */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index b771a600e4..09631fb84b 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -46,6 +46,7 @@ sources = files(
         'nthw/flow_api/flow_api.c',
         'nthw/flow_api/flow_backend/flow_backend.c',
         'nthw/flow_api/flow_filter.c',
+        'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_info.c',
         'nthw/model/nthw_fpga_model.c',
         'nthw/nthw_platform.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index f3ad3686d4..16cc24ec72 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -6,6 +6,7 @@
 #include <stdint.h>
 
 #include "flow_nthw_info.h"
+#include "flow_nthw_cat.h"
 #include "ntnic_mod_reg.h"
 #include "nthw_fpga_model.h"
 #include "hw_mod_backend.h"
@@ -21,8 +22,23 @@ static struct backend_dev_s {
 	uint8_t adapter_no;
 	enum debug_mode_e dmode;
 	struct info_nthw *p_info_nthw;
+	struct cat_nthw *p_cat_nthw;
 } be_devs[MAX_PHYS_ADAPTERS];
 
+#define CHECK_DEBUG_ON(be, mod, inst)                                                             \
+	int __debug__ = 0;                                                                        \
+	if (((be)->dmode & FLOW_BACKEND_DEBUG_MODE_WRITE) || (mod)->debug)                        \
+		do {                                                                              \
+			mod##_nthw_set_debug_mode((inst), 0xFF);                                  \
+			__debug__ = 1;                                                            \
+	} while (0)
+
+#define CHECK_DEBUG_OFF(mod, inst)                                                                \
+	do {                                                                                      \
+		if (__debug__)                                                                    \
+			mod##_nthw_set_debug_mode((inst), 0);                                     \
+	} while (0)
+
 const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, void **be_dev);
 static void bin_flow_backend_done(void *be_dev);
 
@@ -283,6 +299,427 @@ static int get_nb_hsh_toeplitz(void *be_dev)
 	return info_nthw_get_nb_hsh_toeplitz(be->p_info_nthw);
 }
 
+/*
+ * CAT
+ */
+
+static bool cat_get_present(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return be->p_cat_nthw != NULL;
+}
+
+static uint32_t cat_get_version(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return (uint32_t)((nthw_module_get_major_version(be->p_cat_nthw->m_cat) << 16) |
+			(nthw_module_get_minor_version(be->p_cat_nthw->m_cat) & 0xffff));
+}
+
+static int cat_cfn_flush(void *be_dev, const struct cat_func_s *cat, int cat_func, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+
+	CHECK_DEBUG_ON(be, cat, be->p_cat_nthw);
+
+	if (cat->ver == 18) {
+		cat_nthw_cfn_cnt(be->p_cat_nthw, 1U);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_cfn_select(be->p_cat_nthw, cat_func);
+			cat_nthw_cfn_enable(be->p_cat_nthw, cat->v18.cfn[cat_func].enable);
+			cat_nthw_cfn_inv(be->p_cat_nthw, cat->v18.cfn[cat_func].inv);
+			cat_nthw_cfn_ptc_inv(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_inv);
+			cat_nthw_cfn_ptc_isl(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_isl);
+			cat_nthw_cfn_ptc_cfp(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_cfp);
+			cat_nthw_cfn_ptc_mac(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_mac);
+			cat_nthw_cfn_ptc_l2(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_l2);
+			cat_nthw_cfn_ptc_vn_tag(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_vntag);
+			cat_nthw_cfn_ptc_vlan(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_vlan);
+			cat_nthw_cfn_ptc_mpls(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_mpls);
+			cat_nthw_cfn_ptc_l3(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_l3);
+			cat_nthw_cfn_ptc_frag(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_frag);
+			cat_nthw_cfn_ptc_ip_prot(be->p_cat_nthw,
+				cat->v18.cfn[cat_func].ptc_ip_prot);
+			cat_nthw_cfn_ptc_l4(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_l4);
+			cat_nthw_cfn_ptc_tunnel(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_tunnel);
+			cat_nthw_cfn_ptc_tnl_l2(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_tnl_l2);
+			cat_nthw_cfn_ptc_tnl_vlan(be->p_cat_nthw,
+				cat->v18.cfn[cat_func].ptc_tnl_vlan);
+			cat_nthw_cfn_ptc_tnl_mpls(be->p_cat_nthw,
+				cat->v18.cfn[cat_func].ptc_tnl_mpls);
+			cat_nthw_cfn_ptc_tnl_l3(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_tnl_l3);
+			cat_nthw_cfn_ptc_tnl_frag(be->p_cat_nthw,
+				cat->v18.cfn[cat_func].ptc_tnl_frag);
+			cat_nthw_cfn_ptc_tnl_ip_prot(be->p_cat_nthw,
+				cat->v18.cfn[cat_func].ptc_tnl_ip_prot);
+			cat_nthw_cfn_ptc_tnl_l4(be->p_cat_nthw, cat->v18.cfn[cat_func].ptc_tnl_l4);
+
+			cat_nthw_cfn_err_inv(be->p_cat_nthw, cat->v18.cfn[cat_func].err_inv);
+			cat_nthw_cfn_err_cv(be->p_cat_nthw, cat->v18.cfn[cat_func].err_cv);
+			cat_nthw_cfn_err_fcs(be->p_cat_nthw, cat->v18.cfn[cat_func].err_fcs);
+			cat_nthw_cfn_err_trunc(be->p_cat_nthw, cat->v18.cfn[cat_func].err_trunc);
+			cat_nthw_cfn_err_l3_cs(be->p_cat_nthw, cat->v18.cfn[cat_func].err_l3_cs);
+			cat_nthw_cfn_err_l4_cs(be->p_cat_nthw, cat->v18.cfn[cat_func].err_l4_cs);
+
+			cat_nthw_cfn_mac_port(be->p_cat_nthw, cat->v18.cfn[cat_func].mac_port);
+
+			cat_nthw_cfn_pm_cmp(be->p_cat_nthw, cat->v18.cfn[cat_func].pm_cmp);
+			cat_nthw_cfn_pm_dct(be->p_cat_nthw, cat->v18.cfn[cat_func].pm_dct);
+			cat_nthw_cfn_pm_ext_inv(be->p_cat_nthw, cat->v18.cfn[cat_func].pm_ext_inv);
+			cat_nthw_cfn_pm_cmb(be->p_cat_nthw, cat->v18.cfn[cat_func].pm_cmb);
+			cat_nthw_cfn_pm_and_inv(be->p_cat_nthw, cat->v18.cfn[cat_func].pm_and_inv);
+			cat_nthw_cfn_pm_or_inv(be->p_cat_nthw, cat->v18.cfn[cat_func].pm_or_inv);
+			cat_nthw_cfn_pm_inv(be->p_cat_nthw, cat->v18.cfn[cat_func].pm_inv);
+
+			cat_nthw_cfn_lc(be->p_cat_nthw, cat->v18.cfn[cat_func].lc);
+			cat_nthw_cfn_lc_inv(be->p_cat_nthw, cat->v18.cfn[cat_func].lc_inv);
+			cat_nthw_cfn_km0_or(be->p_cat_nthw, cat->v18.cfn[cat_func].km_or);
+			cat_nthw_cfn_flush(be->p_cat_nthw);
+			cat_func++;
+		}
+
+	} else if (cat->ver == 21) {
+		cat_nthw_cfn_cnt(be->p_cat_nthw, 1U);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_cfn_select(be->p_cat_nthw, cat_func);
+			cat_nthw_cfn_enable(be->p_cat_nthw, cat->v21.cfn[cat_func].enable);
+			cat_nthw_cfn_inv(be->p_cat_nthw, cat->v21.cfn[cat_func].inv);
+			cat_nthw_cfn_ptc_inv(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_inv);
+			cat_nthw_cfn_ptc_isl(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_isl);
+			cat_nthw_cfn_ptc_cfp(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_cfp);
+			cat_nthw_cfn_ptc_mac(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_mac);
+			cat_nthw_cfn_ptc_l2(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_l2);
+			cat_nthw_cfn_ptc_vn_tag(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_vntag);
+			cat_nthw_cfn_ptc_vlan(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_vlan);
+			cat_nthw_cfn_ptc_mpls(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_mpls);
+			cat_nthw_cfn_ptc_l3(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_l3);
+			cat_nthw_cfn_ptc_frag(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_frag);
+			cat_nthw_cfn_ptc_ip_prot(be->p_cat_nthw,
+				cat->v21.cfn[cat_func].ptc_ip_prot);
+			cat_nthw_cfn_ptc_l4(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_l4);
+			cat_nthw_cfn_ptc_tunnel(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_tunnel);
+			cat_nthw_cfn_ptc_tnl_l2(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_tnl_l2);
+			cat_nthw_cfn_ptc_tnl_vlan(be->p_cat_nthw,
+				cat->v21.cfn[cat_func].ptc_tnl_vlan);
+			cat_nthw_cfn_ptc_tnl_mpls(be->p_cat_nthw,
+				cat->v21.cfn[cat_func].ptc_tnl_mpls);
+			cat_nthw_cfn_ptc_tnl_l3(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_tnl_l3);
+			cat_nthw_cfn_ptc_tnl_frag(be->p_cat_nthw,
+				cat->v21.cfn[cat_func].ptc_tnl_frag);
+			cat_nthw_cfn_ptc_tnl_ip_prot(be->p_cat_nthw,
+				cat->v21.cfn[cat_func].ptc_tnl_ip_prot);
+			cat_nthw_cfn_ptc_tnl_l4(be->p_cat_nthw, cat->v21.cfn[cat_func].ptc_tnl_l4);
+
+			cat_nthw_cfn_err_inv(be->p_cat_nthw, cat->v21.cfn[cat_func].err_inv);
+			cat_nthw_cfn_err_cv(be->p_cat_nthw, cat->v21.cfn[cat_func].err_cv);
+			cat_nthw_cfn_err_fcs(be->p_cat_nthw, cat->v21.cfn[cat_func].err_fcs);
+			cat_nthw_cfn_err_trunc(be->p_cat_nthw, cat->v21.cfn[cat_func].err_trunc);
+			cat_nthw_cfn_err_l3_cs(be->p_cat_nthw, cat->v21.cfn[cat_func].err_l3_cs);
+			cat_nthw_cfn_err_l4_cs(be->p_cat_nthw, cat->v21.cfn[cat_func].err_l4_cs);
+			cat_nthw_cfn_err_tnl_l3_cs(be->p_cat_nthw,
+				cat->v21.cfn[cat_func].err_tnl_l3_cs);
+			cat_nthw_cfn_err_tnl_l4_cs(be->p_cat_nthw,
+				cat->v21.cfn[cat_func].err_tnl_l4_cs);
+			cat_nthw_cfn_err_ttl_exp(be->p_cat_nthw,
+				cat->v21.cfn[cat_func].err_ttl_exp);
+			cat_nthw_cfn_err_tnl_ttl_exp(be->p_cat_nthw,
+				cat->v21.cfn[cat_func].err_tnl_ttl_exp);
+
+			cat_nthw_cfn_mac_port(be->p_cat_nthw, cat->v21.cfn[cat_func].mac_port);
+
+			cat_nthw_cfn_pm_cmp(be->p_cat_nthw, cat->v21.cfn[cat_func].pm_cmp);
+			cat_nthw_cfn_pm_dct(be->p_cat_nthw, cat->v21.cfn[cat_func].pm_dct);
+			cat_nthw_cfn_pm_ext_inv(be->p_cat_nthw, cat->v21.cfn[cat_func].pm_ext_inv);
+			cat_nthw_cfn_pm_cmb(be->p_cat_nthw, cat->v21.cfn[cat_func].pm_cmb);
+			cat_nthw_cfn_pm_and_inv(be->p_cat_nthw, cat->v21.cfn[cat_func].pm_and_inv);
+			cat_nthw_cfn_pm_or_inv(be->p_cat_nthw, cat->v21.cfn[cat_func].pm_or_inv);
+			cat_nthw_cfn_pm_inv(be->p_cat_nthw, cat->v21.cfn[cat_func].pm_inv);
+
+			cat_nthw_cfn_lc(be->p_cat_nthw, cat->v21.cfn[cat_func].lc);
+			cat_nthw_cfn_lc_inv(be->p_cat_nthw, cat->v21.cfn[cat_func].lc_inv);
+			cat_nthw_cfn_km0_or(be->p_cat_nthw, cat->v21.cfn[cat_func].km0_or);
+
+			if (be->p_cat_nthw->m_km_if_cnt > 1)
+				cat_nthw_cfn_km1_or(be->p_cat_nthw, cat->v21.cfn[cat_func].km1_or);
+
+			cat_nthw_cfn_flush(be->p_cat_nthw);
+			cat_func++;
+		}
+	}
+
+	CHECK_DEBUG_OFF(cat, be->p_cat_nthw);
+	return 0;
+}
+
+static int cat_kce_flush(void *be_dev, const struct cat_func_s *cat, int km_if_idx, int index,
+	int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, cat, be->p_cat_nthw);
+
+	if (cat->ver == 18) {
+		cat_nthw_kce_cnt(be->p_cat_nthw, 0, 1U);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_kce_select(be->p_cat_nthw, 0, index + i);
+			cat_nthw_kce_enable(be->p_cat_nthw, 0, cat->v18.kce[index + i].enable_bm);
+			cat_nthw_kce_flush(be->p_cat_nthw, 0);
+		}
+
+	} else if (cat->ver == 21) {
+		cat_nthw_kce_cnt(be->p_cat_nthw, km_if_idx, 1U);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_kce_select(be->p_cat_nthw, km_if_idx, index + i);
+			cat_nthw_kce_enable(be->p_cat_nthw, km_if_idx,
+				cat->v21.kce[index + i].enable_bm[km_if_idx]);
+			cat_nthw_kce_flush(be->p_cat_nthw, km_if_idx);
+		}
+	}
+
+	CHECK_DEBUG_OFF(cat, be->p_cat_nthw);
+	return 0;
+}
+
+static int cat_kcs_flush(void *be_dev, const struct cat_func_s *cat, int km_if_idx, int cat_func,
+	int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, cat, be->p_cat_nthw);
+
+	if (cat->ver == 18) {
+		cat_nthw_kcs_cnt(be->p_cat_nthw, 0, 1U);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_kcs_select(be->p_cat_nthw, 0, cat_func);
+			cat_nthw_kcs_category(be->p_cat_nthw, 0, cat->v18.kcs[cat_func].category);
+			cat_nthw_kcs_flush(be->p_cat_nthw, 0);
+			cat_func++;
+		}
+
+	} else if (cat->ver == 21) {
+		cat_nthw_kcs_cnt(be->p_cat_nthw, km_if_idx, 1U);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_kcs_select(be->p_cat_nthw, km_if_idx, cat_func);
+			cat_nthw_kcs_category(be->p_cat_nthw, km_if_idx,
+				cat->v21.kcs[cat_func].category[km_if_idx]);
+			cat_nthw_kcs_flush(be->p_cat_nthw, km_if_idx);
+			cat_func++;
+		}
+	}
+
+	CHECK_DEBUG_OFF(cat, be->p_cat_nthw);
+	return 0;
+}
+
+static int cat_fte_flush(void *be_dev, const struct cat_func_s *cat, int km_if_idx, int index,
+	int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, cat, be->p_cat_nthw);
+
+	if (cat->ver == 18) {
+		cat_nthw_fte_cnt(be->p_cat_nthw, 0, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_fte_select(be->p_cat_nthw, 0, index + i);
+			cat_nthw_fte_enable(be->p_cat_nthw, 0, cat->v18.fte[index + i].enable_bm);
+			cat_nthw_fte_flush(be->p_cat_nthw, 0);
+		}
+
+	} else if (cat->ver == 21) {
+		cat_nthw_fte_cnt(be->p_cat_nthw, km_if_idx, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_fte_select(be->p_cat_nthw, km_if_idx, index + i);
+			cat_nthw_fte_enable(be->p_cat_nthw, km_if_idx,
+				cat->v21.fte[index + i].enable_bm[km_if_idx]);
+			cat_nthw_fte_flush(be->p_cat_nthw, km_if_idx);
+		}
+	}
+
+	CHECK_DEBUG_OFF(cat, be->p_cat_nthw);
+	return 0;
+}
+
+static int cat_cte_flush(void *be_dev, const struct cat_func_s *cat, int cat_func, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, cat, be->p_cat_nthw);
+
+	if (cat->ver == 18 || cat->ver == 21) {
+		cat_nthw_cte_cnt(be->p_cat_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_cte_select(be->p_cat_nthw, cat_func);
+			cat_nthw_cte_enable_col(be->p_cat_nthw, cat->v18.cte[cat_func].b.col);
+			cat_nthw_cte_enable_cor(be->p_cat_nthw, cat->v18.cte[cat_func].b.cor);
+			cat_nthw_cte_enable_hsh(be->p_cat_nthw, cat->v18.cte[cat_func].b.hsh);
+			cat_nthw_cte_enable_qsl(be->p_cat_nthw, cat->v18.cte[cat_func].b.qsl);
+			cat_nthw_cte_enable_ipf(be->p_cat_nthw, cat->v18.cte[cat_func].b.ipf);
+			cat_nthw_cte_enable_slc(be->p_cat_nthw, cat->v18.cte[cat_func].b.slc);
+			cat_nthw_cte_enable_pdb(be->p_cat_nthw, cat->v18.cte[cat_func].b.pdb);
+			cat_nthw_cte_enable_msk(be->p_cat_nthw, cat->v18.cte[cat_func].b.msk);
+			cat_nthw_cte_enable_hst(be->p_cat_nthw, cat->v18.cte[cat_func].b.hst);
+			cat_nthw_cte_enable_epp(be->p_cat_nthw, cat->v18.cte[cat_func].b.epp);
+			cat_nthw_cte_enable_tpe(be->p_cat_nthw, cat->v18.cte[cat_func].b.tpe);
+
+			cat_nthw_cte_flush(be->p_cat_nthw);
+			cat_func++;
+		}
+	}
+
+	CHECK_DEBUG_OFF(cat, be->p_cat_nthw);
+	return 0;
+}
+
+static int cat_cts_flush(void *be_dev, const struct cat_func_s *cat, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, cat, be->p_cat_nthw);
+
+	if (cat->ver == 18 || cat->ver == 21) {
+		cat_nthw_cts_cnt(be->p_cat_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_cts_select(be->p_cat_nthw, index + i);
+			cat_nthw_cts_cat_a(be->p_cat_nthw, cat->v18.cts[index + i].cat_a);
+			cat_nthw_cts_cat_b(be->p_cat_nthw, cat->v18.cts[index + i].cat_b);
+			cat_nthw_cts_flush(be->p_cat_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(cat, be->p_cat_nthw);
+	return 0;
+}
+
+static int cat_cot_flush(void *be_dev, const struct cat_func_s *cat, int cat_func, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, cat, be->p_cat_nthw);
+
+	if (cat->ver == 18 || cat->ver == 21) {
+		cat_nthw_cot_cnt(be->p_cat_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_cot_select(be->p_cat_nthw, cat_func + i);
+			cat_nthw_cot_color(be->p_cat_nthw, cat->v18.cot[cat_func + i].color);
+			cat_nthw_cot_km(be->p_cat_nthw, cat->v18.cot[cat_func + i].km);
+			cat_nthw_cot_flush(be->p_cat_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(cat, be->p_cat_nthw);
+	return 0;
+}
+
+static int cat_cct_flush(void *be_dev, const struct cat_func_s *cat, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, cat, be->p_cat_nthw);
+
+	if (cat->ver == 18 || cat->ver == 21) {
+		cat_nthw_cct_cnt(be->p_cat_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_cct_select(be->p_cat_nthw, index + i);
+			cat_nthw_cct_color(be->p_cat_nthw, cat->v18.cct[index + i].color);
+			cat_nthw_cct_km(be->p_cat_nthw, cat->v18.cct[index + i].km);
+			cat_nthw_cct_flush(be->p_cat_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(cat, be->p_cat_nthw);
+	return 0;
+}
+
+static int cat_exo_flush(void *be_dev, const struct cat_func_s *cat, int ext_index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, cat, be->p_cat_nthw);
+
+	if (cat->ver == 18 || cat->ver == 21) {
+		cat_nthw_exo_cnt(be->p_cat_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_exo_select(be->p_cat_nthw, ext_index + i);
+			cat_nthw_exo_dyn(be->p_cat_nthw, cat->v18.exo[ext_index + i].dyn);
+			cat_nthw_exo_ofs(be->p_cat_nthw, cat->v18.exo[ext_index + i].ofs);
+			cat_nthw_exo_flush(be->p_cat_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(cat, be->p_cat_nthw);
+	return 0;
+}
+
+static int cat_rck_flush(void *be_dev, const struct cat_func_s *cat, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, cat, be->p_cat_nthw);
+
+	if (cat->ver == 18 || cat->ver == 21) {
+		cat_nthw_rck_cnt(be->p_cat_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_rck_select(be->p_cat_nthw, index + i);
+			cat_nthw_rck_data(be->p_cat_nthw, cat->v18.rck[index + i].rck_data);
+			cat_nthw_rck_flush(be->p_cat_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(cat, be->p_cat_nthw);
+	return 0;
+}
+
+static int cat_len_flush(void *be_dev, const struct cat_func_s *cat, int len_index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, cat, be->p_cat_nthw);
+
+	if (cat->ver == 18 || cat->ver == 21) {
+		cat_nthw_len_cnt(be->p_cat_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_len_select(be->p_cat_nthw, len_index + i);
+			cat_nthw_len_lower(be->p_cat_nthw, cat->v18.len[len_index + i].lower);
+			cat_nthw_len_upper(be->p_cat_nthw, cat->v18.len[len_index + i].upper);
+			cat_nthw_len_dyn1(be->p_cat_nthw, cat->v18.len[len_index + i].dyn1);
+			cat_nthw_len_dyn2(be->p_cat_nthw, cat->v18.len[len_index + i].dyn2);
+			cat_nthw_len_inv(be->p_cat_nthw, cat->v18.len[len_index + i].inv);
+			cat_nthw_len_flush(be->p_cat_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(cat, be->p_cat_nthw);
+	return 0;
+}
+
+static int cat_kcc_flush(void *be_dev, const struct cat_func_s *cat, int len_index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, cat, be->p_cat_nthw);
+
+	if (cat->ver == 18 || cat->ver == 21) {
+		cat_nthw_kcc_cnt(be->p_cat_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			cat_nthw_kcc_select(be->p_cat_nthw, len_index + i);
+			cat_nthw_kcc_key(be->p_cat_nthw, cat->v18.kcc_cam[len_index + i].key);
+			cat_nthw_kcc_category(be->p_cat_nthw,
+				cat->v18.kcc_cam[len_index + i].category);
+			cat_nthw_kcc_id(be->p_cat_nthw, cat->v18.kcc_cam[len_index + i].id);
+			cat_nthw_kcc_flush(be->p_cat_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(cat, be->p_cat_nthw);
+	return 0;
+}
+
 /*
  * DBS
  */
@@ -351,6 +788,23 @@ const struct flow_api_backend_ops flow_be_iface = {
 
 	alloc_rx_queue,
 	free_rx_queue,
+
+	cat_get_present,
+	cat_get_version,
+	cat_cfn_flush,
+
+	cat_kce_flush,
+	cat_kcs_flush,
+	cat_fte_flush,
+
+	cat_cte_flush,
+	cat_cts_flush,
+	cat_cot_flush,
+	cat_cct_flush,
+	cat_exo_flush,
+	cat_rck_flush,
+	cat_len_flush,
+	cat_kcc_flush,
 };
 
 const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, void **dev)
@@ -361,6 +815,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 	info_nthw_init(pinfonthw, p_fpga, physical_adapter_no);
 	be_devs[physical_adapter_no].p_info_nthw = pinfonthw;
 
+	/* Init nthw CAT */
+	if (cat_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct cat_nthw *pcatnthw = cat_nthw_new();
+		cat_nthw_init(pcatnthw, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_cat_nthw = pcatnthw;
+
+	} else {
+		be_devs[physical_adapter_no].p_cat_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -371,6 +835,7 @@ static void bin_flow_backend_done(void *dev)
 {
 	struct backend_dev_s *be_dev = (struct backend_dev_s *)dev;
 	info_nthw_delete(be_dev->p_info_nthw);
+	cat_nthw_delete(be_dev->p_cat_nthw);
 }
 
 static const struct flow_backend_ops ops = {
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_cat.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_cat.c
new file mode 100644
index 0000000000..7d4631f813
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_cat.c
@@ -0,0 +1,872 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_cat.h"
+
+struct cat_nthw *cat_nthw_new(void)
+{
+	struct cat_nthw *p = malloc(sizeof(struct cat_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void cat_nthw_delete(struct cat_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+void cat_nthw_set_debug_mode(struct cat_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_cat, n_debug_mode);
+}
+
+int cat_nthw_init(struct cat_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_CAT, n_instance);
+
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: Cat %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_cat = p_mod;
+
+	p->m_km_if_cnt = nthw_fpga_get_product_param(p->mp_fpga, NT_CAT_KM_IF_CNT, -1);
+
+	/* CFN */
+	p->mp_cfn_ctrl = nthw_module_get_register(p->m_cat, CAT_CFN_CTRL);
+	p->mp_cfn_addr = nthw_register_get_field(p->mp_cfn_ctrl, CAT_CFN_CTRL_ADR);
+	p->mp_cfn_cnt = nthw_register_get_field(p->mp_cfn_ctrl, CAT_CFN_CTRL_CNT);
+	p->mp_cfn_data = nthw_module_get_register(p->m_cat, CAT_CFN_DATA);
+	p->mp_cfn_data_enable = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_ENABLE);
+	p->mp_cfn_data_inv = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_INV);
+	p->mp_cfn_data_ptc_inv = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_INV);
+	p->mp_cfn_data_ptc_isl = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_ISL);
+	p->mp_cfn_data_ptc_mac = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_MAC);
+	p->mp_cfn_data_ptc_l2 = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_L2);
+	p->mp_cfn_data_ptc_vn_tag =
+		nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_VNTAG);
+	p->mp_cfn_data_ptc_vlan = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_VLAN);
+	p->mp_cfn_data_ptc_mpls = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_MPLS);
+	p->mp_cfn_data_ptc_l3 = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_L3);
+	p->mp_cfn_data_ptc_frag = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_FRAG);
+	p->mp_cfn_data_ptc_ip_prot =
+		nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_IP_PROT);
+	p->mp_cfn_data_ptc_l4 = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_L4);
+	p->mp_cfn_data_ptc_tunnel =
+		nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TUNNEL);
+	p->mp_cfn_data_ptc_tnl_l2 =
+		nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_L2);
+	p->mp_cfn_data_ptc_tnl_vlan =
+		nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_VLAN);
+	p->mp_cfn_data_ptc_tnl_mpls =
+		nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_MPLS);
+	p->mp_cfn_data_ptc_tnl_l3 =
+		nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_L3);
+	p->mp_cfn_data_ptc_tnl_frag =
+		nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_FRAG);
+	p->mp_cfn_data_ptc_tnl_ip_prot =
+		nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_IP_PROT);
+	p->mp_cfn_data_ptc_tnl_l4 =
+		nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_L4);
+	p->mp_cfn_data_err_inv = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_INV);
+	p->mp_cfn_data_err_cv = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_CV);
+	p->mp_cfn_data_err_fcs = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_FCS);
+	p->mp_cfn_data_err_trunc = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_TRUNC);
+	p->mp_cfn_data_mac_port = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_MAC_PORT);
+	p->mp_cfn_data_pm_cmp = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_CMP);
+	p->mp_cfn_data_pm_dct = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_DCT);
+	p->mp_cfn_data_pm_ext_inv =
+		nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_EXT_INV);
+	p->mp_cfn_data_pm_cmb = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_CMB);
+	p->mp_cfn_data_pm_and_inv =
+		nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_AND_INV);
+	p->mp_cfn_data_pm_or_inv = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_OR_INV);
+	p->mp_cfn_data_pm_inv = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_INV);
+	p->mp_cfn_data_lc = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_LC);
+	p->mp_cfn_data_lc_inv = nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_LC_INV);
+
+	if (p->m_km_if_cnt == -1) {
+		p->mp_cfn_data_km0_or =
+			nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_KM_OR);
+
+	} else {
+		p->mp_cfn_data_km0_or =
+			nthw_register_get_field(p->mp_cfn_data, CAT_CFN_DATA_KM0_OR);
+		p->mp_cfn_data_km1_or =
+			nthw_register_query_field(p->mp_cfn_data, CAT_CFN_DATA_KM1_OR);
+	}
+
+	if (p->m_km_if_cnt < 0) {
+		/* KCE */
+		p->mp_kce_ctrl[0] = nthw_module_get_register(p->m_cat, CAT_KCE_CTRL);
+		p->mp_kce_addr[0] = nthw_register_get_field(p->mp_kce_ctrl[0], CAT_KCE_CTRL_ADR);
+		p->mp_kce_cnt[0] = nthw_register_get_field(p->mp_kce_ctrl[0], CAT_KCE_CTRL_CNT);
+		p->mp_kce_data[0] = nthw_module_get_register(p->m_cat, CAT_KCE_DATA);
+		p->mp_kce_data_enable[0] =
+			nthw_register_get_field(p->mp_kce_data[0], CAT_KCE_DATA_ENABLE);
+		/* KCS */
+		p->mp_kcs_ctrl[0] = nthw_module_get_register(p->m_cat, CAT_KCS_CTRL);
+		p->mp_kcs_addr[0] = nthw_register_get_field(p->mp_kcs_ctrl[0], CAT_KCS_CTRL_ADR);
+		p->mp_kcs_cnt[0] = nthw_register_get_field(p->mp_kcs_ctrl[0], CAT_KCS_CTRL_CNT);
+		p->mp_kcs_data[0] = nthw_module_get_register(p->m_cat, CAT_KCS_DATA);
+		p->mp_kcs_data_category[0] =
+			nthw_register_get_field(p->mp_kcs_data[0], CAT_KCS_DATA_CATEGORY);
+		/* FTE */
+		p->mp_fte_ctrl[0] = nthw_module_get_register(p->m_cat, CAT_FTE_CTRL);
+		p->mp_fte_addr[0] = nthw_register_get_field(p->mp_fte_ctrl[0], CAT_FTE_CTRL_ADR);
+		p->mp_fte_cnt[0] = nthw_register_get_field(p->mp_fte_ctrl[0], CAT_FTE_CTRL_CNT);
+		p->mp_fte_data[0] = nthw_module_get_register(p->m_cat, CAT_FTE_DATA);
+		p->mp_fte_data_enable[0] =
+			nthw_register_get_field(p->mp_fte_data[0], CAT_FTE_DATA_ENABLE);
+
+	} else {
+		/* KCE 0 */
+		p->mp_kce_ctrl[0] = nthw_module_get_register(p->m_cat, CAT_KCE0_CTRL);
+		p->mp_kce_addr[0] = nthw_register_get_field(p->mp_kce_ctrl[0], CAT_KCE0_CTRL_ADR);
+		p->mp_kce_cnt[0] = nthw_register_get_field(p->mp_kce_ctrl[0], CAT_KCE0_CTRL_CNT);
+		p->mp_kce_data[0] = nthw_module_get_register(p->m_cat, CAT_KCE0_DATA);
+		p->mp_kce_data_enable[0] =
+			nthw_register_get_field(p->mp_kce_data[0], CAT_KCE0_DATA_ENABLE);
+		/* KCS 0 */
+		p->mp_kcs_ctrl[0] = nthw_module_get_register(p->m_cat, CAT_KCS0_CTRL);
+		p->mp_kcs_addr[0] = nthw_register_get_field(p->mp_kcs_ctrl[0], CAT_KCS0_CTRL_ADR);
+		p->mp_kcs_cnt[0] = nthw_register_get_field(p->mp_kcs_ctrl[0], CAT_KCS0_CTRL_CNT);
+		p->mp_kcs_data[0] = nthw_module_get_register(p->m_cat, CAT_KCS0_DATA);
+		p->mp_kcs_data_category[0] =
+			nthw_register_get_field(p->mp_kcs_data[0], CAT_KCS0_DATA_CATEGORY);
+		/* FTE 0 */
+		p->mp_fte_ctrl[0] = nthw_module_get_register(p->m_cat, CAT_FTE0_CTRL);
+		p->mp_fte_addr[0] = nthw_register_get_field(p->mp_fte_ctrl[0], CAT_FTE0_CTRL_ADR);
+		p->mp_fte_cnt[0] = nthw_register_get_field(p->mp_fte_ctrl[0], CAT_FTE0_CTRL_CNT);
+		p->mp_fte_data[0] = nthw_module_get_register(p->m_cat, CAT_FTE0_DATA);
+		p->mp_fte_data_enable[0] =
+			nthw_register_get_field(p->mp_fte_data[0], CAT_FTE0_DATA_ENABLE);
+		/* KCE 1 */
+		p->mp_kce_ctrl[1] = nthw_module_get_register(p->m_cat, CAT_KCE1_CTRL);
+		p->mp_kce_addr[1] = nthw_register_get_field(p->mp_kce_ctrl[1], CAT_KCE1_CTRL_ADR);
+		p->mp_kce_cnt[1] = nthw_register_get_field(p->mp_kce_ctrl[1], CAT_KCE1_CTRL_CNT);
+		p->mp_kce_data[1] = nthw_module_get_register(p->m_cat, CAT_KCE1_DATA);
+		p->mp_kce_data_enable[1] =
+			nthw_register_get_field(p->mp_kce_data[1], CAT_KCE1_DATA_ENABLE);
+		/* KCS 1 */
+		p->mp_kcs_ctrl[1] = nthw_module_get_register(p->m_cat, CAT_KCS1_CTRL);
+		p->mp_kcs_addr[1] = nthw_register_get_field(p->mp_kcs_ctrl[1], CAT_KCS1_CTRL_ADR);
+		p->mp_kcs_cnt[1] = nthw_register_get_field(p->mp_kcs_ctrl[1], CAT_KCS1_CTRL_CNT);
+		p->mp_kcs_data[1] = nthw_module_get_register(p->m_cat, CAT_KCS1_DATA);
+		p->mp_kcs_data_category[1] =
+			nthw_register_get_field(p->mp_kcs_data[1], CAT_KCS1_DATA_CATEGORY);
+		/* FTE 1 */
+		p->mp_fte_ctrl[1] = nthw_module_get_register(p->m_cat, CAT_FTE1_CTRL);
+		p->mp_fte_addr[1] = nthw_register_get_field(p->mp_fte_ctrl[1], CAT_FTE1_CTRL_ADR);
+		p->mp_fte_cnt[1] = nthw_register_get_field(p->mp_fte_ctrl[1], CAT_FTE1_CTRL_CNT);
+		p->mp_fte_data[1] = nthw_module_get_register(p->m_cat, CAT_FTE1_DATA);
+		p->mp_fte_data_enable[1] =
+			nthw_register_get_field(p->mp_fte_data[1], CAT_FTE1_DATA_ENABLE);
+	}
+
+	/* CTE */
+	p->mp_cte_ctrl = nthw_module_get_register(p->m_cat, CAT_CTE_CTRL);
+	p->mp_cte_addr = nthw_register_get_field(p->mp_cte_ctrl, CAT_CTE_CTRL_ADR);
+	p->mp_cte_cnt = nthw_register_get_field(p->mp_cte_ctrl, CAT_CTE_CTRL_CNT);
+	p->mp_cte_data = nthw_module_get_register(p->m_cat, CAT_CTE_DATA);
+	p->mp_cte_data_col = nthw_register_get_field(p->mp_cte_data, CAT_CTE_DATA_COL_ENABLE);
+	p->mp_cte_data_cor = nthw_register_get_field(p->mp_cte_data, CAT_CTE_DATA_COR_ENABLE);
+	p->mp_cte_data_hsh = nthw_register_get_field(p->mp_cte_data, CAT_CTE_DATA_HSH_ENABLE);
+	p->mp_cte_data_qsl = nthw_register_get_field(p->mp_cte_data, CAT_CTE_DATA_QSL_ENABLE);
+	p->mp_cte_data_ipf = nthw_register_get_field(p->mp_cte_data, CAT_CTE_DATA_IPF_ENABLE);
+	p->mp_cte_data_slc = nthw_register_get_field(p->mp_cte_data, CAT_CTE_DATA_SLC_ENABLE);
+	p->mp_cte_data_pdb = nthw_register_get_field(p->mp_cte_data, CAT_CTE_DATA_PDB_ENABLE);
+	p->mp_cte_data_msk = nthw_register_query_field(p->mp_cte_data, CAT_CTE_DATA_MSK_ENABLE);
+	p->mp_cte_data_hst = nthw_register_query_field(p->mp_cte_data, CAT_CTE_DATA_HST_ENABLE);
+	p->mp_cte_data_epp = nthw_register_query_field(p->mp_cte_data, CAT_CTE_DATA_EPP_ENABLE);
+	p->mp_cte_data_tpe = nthw_register_query_field(p->mp_cte_data, CAT_CTE_DATA_TPE_ENABLE);
+	/* CTS */
+	p->mp_cts_ctrl = nthw_module_get_register(p->m_cat, CAT_CTS_CTRL);
+	p->mp_cts_addr = nthw_register_get_field(p->mp_cts_ctrl, CAT_CTS_CTRL_ADR);
+	p->mp_cts_cnt = nthw_register_get_field(p->mp_cts_ctrl, CAT_CTS_CTRL_CNT);
+	p->mp_cts_data = nthw_module_get_register(p->m_cat, CAT_CTS_DATA);
+	p->mp_cts_data_cat_a = nthw_register_get_field(p->mp_cts_data, CAT_CTS_DATA_CAT_A);
+	p->mp_cts_data_cat_b = nthw_register_get_field(p->mp_cts_data, CAT_CTS_DATA_CAT_B);
+	/* COT */
+	p->mp_cot_ctrl = nthw_module_get_register(p->m_cat, CAT_COT_CTRL);
+	p->mp_cot_addr = nthw_register_get_field(p->mp_cot_ctrl, CAT_COT_CTRL_ADR);
+	p->mp_cot_cnt = nthw_register_get_field(p->mp_cot_ctrl, CAT_COT_CTRL_CNT);
+	p->mp_cot_data = nthw_module_get_register(p->m_cat, CAT_COT_DATA);
+	p->mp_cot_data_color = nthw_register_get_field(p->mp_cot_data, CAT_COT_DATA_COLOR);
+	p->mp_cot_data_km = nthw_register_get_field(p->mp_cot_data, CAT_COT_DATA_KM);
+	p->mp_cot_data_nfv_sb = nthw_register_query_field(p->mp_cot_data, CAT_COT_DATA_NFV_SB);
+	/* CCT */
+	p->mp_cct_ctrl = nthw_module_get_register(p->m_cat, CAT_CCT_CTRL);
+	p->mp_cct_addr = nthw_register_get_field(p->mp_cct_ctrl, CAT_CCT_CTRL_ADR);
+	p->mp_cct_cnt = nthw_register_get_field(p->mp_cct_ctrl, CAT_CCT_CTRL_CNT);
+	p->mp_cct_data = nthw_module_get_register(p->m_cat, CAT_CCT_DATA);
+	p->mp_cct_data_color = nthw_register_get_field(p->mp_cct_data, CAT_CCT_DATA_COLOR);
+	p->mp_cct_data_km = nthw_register_get_field(p->mp_cct_data, CAT_CCT_DATA_KM);
+	/* EXO */
+	p->mp_exo_ctrl = nthw_module_get_register(p->m_cat, CAT_EXO_CTRL);
+	p->mp_exo_addr = nthw_register_get_field(p->mp_exo_ctrl, CAT_EXO_CTRL_ADR);
+	p->mp_exo_cnt = nthw_register_get_field(p->mp_exo_ctrl, CAT_EXO_CTRL_CNT);
+	p->mp_exo_data = nthw_module_get_register(p->m_cat, CAT_EXO_DATA);
+	p->mp_exo_data_dyn = nthw_register_get_field(p->mp_exo_data, CAT_EXO_DATA_DYN);
+	p->mp_exo_data_ofs = nthw_register_get_field(p->mp_exo_data, CAT_EXO_DATA_OFS);
+	/* RCK */
+	p->mp_rck_ctrl = nthw_module_get_register(p->m_cat, CAT_RCK_CTRL);
+	p->mp_rck_addr = nthw_register_get_field(p->mp_rck_ctrl, CAT_RCK_CTRL_ADR);
+	p->mp_rck_cnt = nthw_register_get_field(p->mp_rck_ctrl, CAT_RCK_CTRL_CNT);
+	p->mp_rck_data = nthw_module_get_register(p->m_cat, CAT_RCK_DATA);
+	/* LEN */
+	p->mp_len_ctrl = nthw_module_get_register(p->m_cat, CAT_LEN_CTRL);
+	p->mp_len_addr = nthw_register_get_field(p->mp_len_ctrl, CAT_LEN_CTRL_ADR);
+	p->mp_len_cnt = nthw_register_get_field(p->mp_len_ctrl, CAT_LEN_CTRL_CNT);
+	p->mp_len_data = nthw_module_get_register(p->m_cat, CAT_LEN_DATA);
+	p->mp_len_data_lower = nthw_register_get_field(p->mp_len_data, CAT_LEN_DATA_LOWER);
+	p->mp_len_data_upper = nthw_register_get_field(p->mp_len_data, CAT_LEN_DATA_UPPER);
+	p->mp_len_data_dyn1 = nthw_register_get_field(p->mp_len_data, CAT_LEN_DATA_DYN1);
+	p->mp_len_data_dyn2 = nthw_register_get_field(p->mp_len_data, CAT_LEN_DATA_DYN2);
+	p->mp_len_data_inv = nthw_register_get_field(p->mp_len_data, CAT_LEN_DATA_INV);
+
+	p->mp_cfn_data_ptc_cfp = nthw_register_query_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_CFP);
+	p->mp_cfn_data_err_l3_cs =
+		nthw_register_query_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_L3_CS);
+	p->mp_cfn_data_err_l4_cs =
+		nthw_register_query_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_L4_CS);
+	p->mp_cfn_data_err_tnl_l3_cs =
+		nthw_register_query_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_TNL_L3_CS);
+	p->mp_cfn_data_err_tnl_l4_cs =
+		nthw_register_query_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_TNL_L4_CS);
+	p->mp_cfn_data_err_ttl_exp =
+		nthw_register_query_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_TTL_EXP);
+	p->mp_cfn_data_err_tnl_ttl_exp =
+		nthw_register_query_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_TNL_TTL_EXP);
+
+	p->mp_kcc_ctrl = nthw_module_query_register(p->m_cat, CAT_KCC_CTRL);
+
+	if (p->mp_kcc_ctrl != NULL) {
+		p->mp_kcc_addr = nthw_register_query_field(p->mp_kcc_ctrl, CAT_KCC_CTRL_ADR);
+		p->mp_kcc_cnt = nthw_register_query_field(p->mp_kcc_ctrl, CAT_KCC_CTRL_CNT);
+	}
+
+	p->mp_kcc_data = nthw_module_query_register(p->m_cat, CAT_KCC_DATA);
+
+	if (p->mp_kcc_data != NULL) {
+		p->mp_kcc_data_key = nthw_register_query_field(p->mp_kcc_data, CAT_KCC_DATA_KEY);
+		p->mp_kcc_data_category =
+			nthw_register_query_field(p->mp_kcc_data, CAT_KCC_DATA_CATEGORY);
+		p->mp_kcc_data_id = nthw_register_query_field(p->mp_kcc_data, CAT_KCC_DATA_ID);
+	}
+
+	return 0;
+}
+
+/* CFN */
+void cat_nthw_cfn_select(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_addr, val);
+}
+
+void cat_nthw_cfn_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_cnt, val);
+}
+
+void cat_nthw_cfn_enable(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_enable, val);
+}
+
+void cat_nthw_cfn_inv(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_inv, val);
+}
+
+void cat_nthw_cfn_ptc_inv(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_inv, val);
+}
+
+void cat_nthw_cfn_ptc_isl(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_isl, val);
+}
+
+void cat_nthw_cfn_ptc_mac(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_mac, val);
+}
+
+void cat_nthw_cfn_ptc_l2(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_l2, val);
+}
+
+void cat_nthw_cfn_ptc_vn_tag(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_vn_tag, val);
+}
+
+void cat_nthw_cfn_ptc_vlan(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_vlan, val);
+}
+
+void cat_nthw_cfn_ptc_mpls(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_mpls, val);
+}
+
+void cat_nthw_cfn_ptc_l3(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_l3, val);
+}
+
+void cat_nthw_cfn_ptc_frag(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_frag, val);
+}
+
+void cat_nthw_cfn_ptc_ip_prot(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_ip_prot, val);
+}
+
+void cat_nthw_cfn_ptc_l4(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_l4, val);
+}
+
+void cat_nthw_cfn_ptc_tunnel(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_tunnel, val);
+}
+
+void cat_nthw_cfn_ptc_tnl_l2(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_tnl_l2, val);
+}
+
+void cat_nthw_cfn_ptc_tnl_vlan(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_tnl_vlan, val);
+}
+
+void cat_nthw_cfn_ptc_tnl_mpls(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_tnl_mpls, val);
+}
+
+void cat_nthw_cfn_ptc_tnl_l3(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_tnl_l3, val);
+}
+
+void cat_nthw_cfn_ptc_tnl_frag(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_tnl_frag, val);
+}
+
+void cat_nthw_cfn_ptc_tnl_ip_prot(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_tnl_ip_prot, val);
+}
+
+void cat_nthw_cfn_ptc_tnl_l4(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_ptc_tnl_l4, val);
+}
+
+void cat_nthw_cfn_ptc_cfp(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cfn_data_ptc_cfp);
+	nthw_field_set_val32(p->mp_cfn_data_ptc_cfp, val);
+}
+
+void cat_nthw_cfn_err_l3_cs(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cfn_data_err_l3_cs);
+	nthw_field_set_val32(p->mp_cfn_data_err_l3_cs, val);
+}
+
+void cat_nthw_cfn_err_l4_cs(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cfn_data_err_l4_cs);
+	nthw_field_set_val32(p->mp_cfn_data_err_l4_cs, val);
+}
+
+void cat_nthw_cfn_err_tnl_l3_cs(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cfn_data_err_tnl_l3_cs);
+	nthw_field_set_val32(p->mp_cfn_data_err_tnl_l3_cs, val);
+}
+
+void cat_nthw_cfn_err_tnl_l4_cs(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cfn_data_err_tnl_l4_cs);
+	nthw_field_set_val32(p->mp_cfn_data_err_tnl_l4_cs, val);
+}
+
+void cat_nthw_cfn_err_ttl_exp(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cfn_data_err_ttl_exp);
+	nthw_field_set_val32(p->mp_cfn_data_err_ttl_exp, val);
+}
+
+void cat_nthw_cfn_err_tnl_ttl_exp(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cfn_data_err_tnl_ttl_exp);
+	nthw_field_set_val32(p->mp_cfn_data_err_tnl_ttl_exp, val);
+}
+
+void cat_nthw_cfn_err_inv(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_err_inv, val);
+}
+
+void cat_nthw_cfn_err_cv(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_err_cv, val);
+}
+
+void cat_nthw_cfn_err_fcs(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_err_fcs, val);
+}
+
+void cat_nthw_cfn_err_trunc(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_err_trunc, val);
+}
+
+void cat_nthw_cfn_mac_port(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_mac_port, val);
+}
+
+void cat_nthw_cfn_pm_cmp(const struct cat_nthw *p, const uint32_t *val)
+{
+	nthw_field_set_val(p->mp_cfn_data_pm_cmp, val, p->mp_cfn_data_pm_cmp->mn_words);
+}
+
+void cat_nthw_cfn_pm_dct(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_pm_dct, val);
+}
+
+void cat_nthw_cfn_pm_ext_inv(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_pm_ext_inv, val);
+}
+
+void cat_nthw_cfn_pm_cmb(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_pm_cmb, val);
+}
+
+void cat_nthw_cfn_pm_and_inv(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_pm_and_inv, val);
+}
+
+void cat_nthw_cfn_pm_or_inv(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_pm_or_inv, val);
+}
+
+void cat_nthw_cfn_pm_inv(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_pm_inv, val);
+}
+
+void cat_nthw_cfn_lc(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_lc, val);
+}
+
+void cat_nthw_cfn_lc_inv(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_lc_inv, val);
+}
+
+void cat_nthw_cfn_km0_or(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cfn_data_km0_or, val);
+}
+
+void cat_nthw_cfn_km1_or(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cfn_data_km1_or);
+	nthw_field_set_val32(p->mp_cfn_data_km1_or, val);
+}
+
+void cat_nthw_cfn_flush(const struct cat_nthw *p)
+{
+	nthw_register_flush(p->mp_cfn_ctrl, 1);
+	nthw_register_flush(p->mp_cfn_data, 1);
+}
+
+void cat_nthw_kce_select(const struct cat_nthw *p, int index, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_kce_addr[index], val);
+}
+
+void cat_nthw_kce_cnt(const struct cat_nthw *p, int index, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_kce_cnt[index], val);
+}
+
+void cat_nthw_kce_enable(const struct cat_nthw *p, int index, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_kce_data_enable[index], val);
+}
+
+void cat_nthw_kce_flush(const struct cat_nthw *p, int index)
+{
+	nthw_register_flush(p->mp_kce_ctrl[index], 1);
+	nthw_register_flush(p->mp_kce_data[index], 1);
+}
+
+void cat_nthw_kcs_select(const struct cat_nthw *p, int index, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_kcs_addr[index], val);
+}
+
+void cat_nthw_kcs_cnt(const struct cat_nthw *p, int index, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_kcs_cnt[index], val);
+}
+
+void cat_nthw_kcs_category(const struct cat_nthw *p, int index, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_kcs_data_category[index], val);
+}
+
+void cat_nthw_kcs_flush(const struct cat_nthw *p, int index)
+{
+	nthw_register_flush(p->mp_kcs_ctrl[index], 1);
+	nthw_register_flush(p->mp_kcs_data[index], 1);
+}
+
+void cat_nthw_fte_select(const struct cat_nthw *p, int index, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_fte_addr[index], val);
+}
+
+void cat_nthw_fte_cnt(const struct cat_nthw *p, int index, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_fte_cnt[index], val);
+}
+
+void cat_nthw_fte_enable(const struct cat_nthw *p, int index, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_fte_data_enable[index], val);
+}
+
+void cat_nthw_fte_flush(const struct cat_nthw *p, int index)
+{
+	nthw_register_flush(p->mp_fte_ctrl[index], 1);
+	nthw_register_flush(p->mp_fte_data[index], 1);
+}
+
+void cat_nthw_cte_select(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cte_addr, val);
+}
+
+void cat_nthw_cte_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cte_cnt, val);
+}
+
+void cat_nthw_cte_enable_col(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cte_data_col, val);
+}
+
+void cat_nthw_cte_enable_cor(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cte_data_cor, val);
+}
+
+void cat_nthw_cte_enable_hsh(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cte_data_hsh, val);
+}
+
+void cat_nthw_cte_enable_qsl(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cte_data_qsl, val);
+}
+
+void cat_nthw_cte_enable_ipf(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cte_data_ipf, val);
+}
+
+void cat_nthw_cte_enable_slc(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cte_data_slc, val);
+}
+
+void cat_nthw_cte_enable_pdb(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cte_data_pdb, val);
+}
+
+void cat_nthw_cte_enable_msk(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cte_data_msk);
+	nthw_field_set_val32(p->mp_cte_data_msk, val);
+}
+
+void cat_nthw_cte_enable_hst(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cte_data_hst);
+	nthw_field_set_val32(p->mp_cte_data_hst, val);
+}
+
+void cat_nthw_cte_enable_epp(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cte_data_epp);
+	nthw_field_set_val32(p->mp_cte_data_epp, val);
+}
+
+void cat_nthw_cte_enable_tpe(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cte_data_tpe);
+	nthw_field_set_val32(p->mp_cte_data_tpe, val);
+}
+
+void cat_nthw_cte_flush(const struct cat_nthw *p)
+{
+	nthw_register_flush(p->mp_cte_ctrl, 1);
+	nthw_register_flush(p->mp_cte_data, 1);
+}
+
+void cat_nthw_cts_select(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cts_addr, val);
+}
+
+void cat_nthw_cts_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cts_cnt, val);
+}
+
+void cat_nthw_cts_cat_a(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cts_data_cat_a, val);
+}
+
+void cat_nthw_cts_cat_b(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cts_data_cat_b, val);
+}
+
+void cat_nthw_cts_flush(const struct cat_nthw *p)
+{
+	nthw_register_flush(p->mp_cts_ctrl, 1);
+	nthw_register_flush(p->mp_cts_data, 1);
+}
+
+void cat_nthw_cot_select(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cot_addr, val);
+}
+
+void cat_nthw_cot_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cot_cnt, val);
+}
+
+void cat_nthw_cot_color(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cot_data_color, val);
+}
+
+void cat_nthw_cot_km(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cot_data_km, val);
+}
+
+void cat_nthw_cot_flush(const struct cat_nthw *p)
+{
+	nthw_register_flush(p->mp_cot_ctrl, 1);
+	nthw_register_flush(p->mp_cot_data, 1);
+}
+
+void cat_nthw_cct_select(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cct_addr, val);
+}
+
+void cat_nthw_cct_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cct_cnt, val);
+}
+
+void cat_nthw_cct_color(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cct_data_color, val);
+}
+
+void cat_nthw_cct_km(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cct_data_km, val);
+}
+
+void cat_nthw_cct_flush(const struct cat_nthw *p)
+{
+	nthw_register_flush(p->mp_cct_ctrl, 1);
+	nthw_register_flush(p->mp_cct_data, 1);
+}
+
+void cat_nthw_exo_select(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_exo_addr, val);
+}
+
+void cat_nthw_exo_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_exo_cnt, val);
+}
+
+void cat_nthw_exo_dyn(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_exo_data_dyn, val);
+}
+
+void cat_nthw_exo_ofs(const struct cat_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_exo_data_ofs, val);
+}
+
+void cat_nthw_exo_flush(const struct cat_nthw *p)
+{
+	nthw_register_flush(p->mp_exo_ctrl, 1);
+	nthw_register_flush(p->mp_exo_data, 1);
+}
+
+void cat_nthw_rck_select(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rck_addr, val);
+}
+
+void cat_nthw_rck_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rck_cnt, val);
+}
+
+void cat_nthw_rck_data(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_register_set_val(p->mp_rck_data, &val, 1);
+	nthw_register_make_dirty(p->mp_rck_data);
+}
+
+void cat_nthw_rck_flush(const struct cat_nthw *p)
+{
+	nthw_register_flush(p->mp_rck_ctrl, 1);
+	nthw_register_flush(p->mp_rck_data, 1);
+}
+
+void cat_nthw_len_select(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_len_addr, val);
+}
+
+void cat_nthw_len_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_len_cnt, val);
+}
+
+void cat_nthw_len_lower(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_len_data_lower, val);
+}
+
+void cat_nthw_len_upper(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_len_data_upper, val);
+}
+
+void cat_nthw_len_dyn1(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_len_data_dyn1, val);
+}
+
+void cat_nthw_len_dyn2(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_len_data_dyn2, val);
+}
+
+void cat_nthw_len_inv(const struct cat_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_len_data_inv, val);
+}
+
+void cat_nthw_len_flush(const struct cat_nthw *p)
+{
+	nthw_register_flush(p->mp_len_ctrl, 1);
+	nthw_register_flush(p->mp_len_data, 1);
+}
+
+void cat_nthw_kcc_select(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_kcc_addr);
+	nthw_field_set_val32(p->mp_kcc_addr, val);
+}
+
+void cat_nthw_kcc_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_kcc_cnt);
+	nthw_field_set_val32(p->mp_kcc_cnt, val);
+}
+
+void cat_nthw_kcc_key(const struct cat_nthw *p, uint32_t *val)
+{
+	assert(p->mp_kcc_data_key);
+	nthw_field_set_val(p->mp_kcc_data_key, val, 2);
+}
+
+void cat_nthw_kcc_category(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_kcc_data_category);
+	nthw_field_set_val32(p->mp_kcc_data_category, val);
+}
+
+void cat_nthw_kcc_id(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_kcc_data_id);
+	nthw_field_set_val32(p->mp_kcc_data_id, val);
+}
+
+void cat_nthw_kcc_flush(const struct cat_nthw *p)
+{
+	assert(p->mp_kcc_ctrl);
+	assert(p->mp_kcc_data);
+	nthw_register_flush(p->mp_kcc_ctrl, 1);
+	nthw_register_flush(p->mp_kcc_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_cat.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_cat.h
new file mode 100644
index 0000000000..29f9a332f1
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_cat.h
@@ -0,0 +1,291 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_CAT_H__
+#define __FLOW_NTHW_CAT_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct cat_nthw;
+
+typedef struct cat_nthw cat_nthw_t;
+
+struct cat_nthw *cat_nthw_new(void);
+void cat_nthw_delete(struct cat_nthw *p);
+int cat_nthw_init(struct cat_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int cat_nthw_setup(struct cat_nthw *p, int n_idx, int n_idx_cnt);
+void cat_nthw_set_debug_mode(struct cat_nthw *p, unsigned int n_debug_mode);
+
+/* CFN */
+void cat_nthw_cfn_select(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_cnt(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_enable(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_inv(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_inv(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_isl(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_cfp(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_mac(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_l2(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_vn_tag(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_vlan(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_mpls(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_l3(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_frag(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_ip_prot(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_l4(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_tunnel(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_tnl_l2(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_tnl_vlan(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_tnl_mpls(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_tnl_l3(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_tnl_frag(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_tnl_ip_prot(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_ptc_tnl_l4(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_err_inv(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_err_cv(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_err_fcs(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_err_trunc(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_err_l3_cs(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_err_l4_cs(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_err_tnl_l3_cs(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_err_tnl_l4_cs(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_err_ttl_exp(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_err_tnl_ttl_exp(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_mac_port(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_pm_cmp(const struct cat_nthw *p, const uint32_t *val);
+void cat_nthw_cfn_pm_dct(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_pm_ext_inv(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_pm_cmb(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_pm_and_inv(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_pm_or_inv(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_pm_inv(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_lc(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_lc_inv(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_km0_or(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_km1_or(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cfn_flush(const struct cat_nthw *p);
+/* KCE 0/1 */
+void cat_nthw_kce_select(const struct cat_nthw *p, int index, uint32_t val);
+void cat_nthw_kce_cnt(const struct cat_nthw *p, int index, uint32_t val);
+void cat_nthw_kce_enable(const struct cat_nthw *p, int index, uint32_t val);
+void cat_nthw_kce_flush(const struct cat_nthw *p, int index);
+/* KCS 0/1 */
+void cat_nthw_kcs_select(const struct cat_nthw *p, int index, uint32_t val);
+void cat_nthw_kcs_cnt(const struct cat_nthw *p, int index, uint32_t val);
+void cat_nthw_kcs_category(const struct cat_nthw *p, int index, uint32_t val);
+void cat_nthw_kcs_flush(const struct cat_nthw *p, int index);
+/* FTE 0/1 */
+void cat_nthw_fte_select(const struct cat_nthw *p, int index, uint32_t val);
+void cat_nthw_fte_cnt(const struct cat_nthw *p, int index, uint32_t val);
+void cat_nthw_fte_enable(const struct cat_nthw *p, int index, uint32_t val);
+void cat_nthw_fte_flush(const struct cat_nthw *p, int index);
+/* CTE */
+void cat_nthw_cte_select(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_cnt(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_enable_col(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_enable_cor(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_enable_hsh(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_enable_qsl(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_enable_ipf(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_enable_slc(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_enable_pdb(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_enable_msk(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_enable_hst(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_enable_epp(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_enable_tpe(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cte_flush(const struct cat_nthw *p);
+/* CTS */
+void cat_nthw_cts_select(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cts_cnt(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cts_flush(const struct cat_nthw *p);
+void cat_nthw_cts_cat_a(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cts_cat_b(const struct cat_nthw *p, uint32_t val);
+/* COT */
+void cat_nthw_cot_select(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cot_cnt(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cot_color(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cot_km(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cot_flush(const struct cat_nthw *p);
+/* CCT */
+void cat_nthw_cct_select(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cct_cnt(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cct_color(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cct_km(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cct_flush(const struct cat_nthw *p);
+/* EXO */
+void cat_nthw_exo_select(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_exo_cnt(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_exo_dyn(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_exo_ofs(const struct cat_nthw *p, int32_t val);
+void cat_nthw_exo_flush(const struct cat_nthw *p);
+/* RCK */
+void cat_nthw_rck_select(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_rck_cnt(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_rck_data(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_rck_flush(const struct cat_nthw *p);
+/* LEN */
+void cat_nthw_len_select(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_len_cnt(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_len_lower(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_len_upper(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_len_dyn1(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_len_dyn2(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_len_inv(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_len_flush(const struct cat_nthw *p);
+/* KCC */
+void cat_nthw_kcc_select(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_kcc_cnt(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_kcc_key(const struct cat_nthw *p, uint32_t *val);
+void cat_nthw_kcc_category(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_kcc_id(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_kcc_flush(const struct cat_nthw *p);
+
+struct cat_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+	nthw_module_t *m_cat;
+	int m_km_if_cnt;
+
+	nthw_register_t *mp_cfn_ctrl;
+	nthw_field_t *mp_cfn_addr;
+	nthw_field_t *mp_cfn_cnt;
+	nthw_register_t *mp_cfn_data;
+	nthw_field_t *mp_cfn_data_enable;
+	nthw_field_t *mp_cfn_data_inv;
+	nthw_field_t *mp_cfn_data_ptc_inv;
+	nthw_field_t *mp_cfn_data_ptc_isl;
+	nthw_field_t *mp_cfn_data_ptc_cfp;
+	nthw_field_t *mp_cfn_data_ptc_mac;
+	nthw_field_t *mp_cfn_data_ptc_l2;
+	nthw_field_t *mp_cfn_data_ptc_vn_tag;
+	nthw_field_t *mp_cfn_data_ptc_vlan;
+	nthw_field_t *mp_cfn_data_ptc_mpls;
+	nthw_field_t *mp_cfn_data_ptc_l3;
+	nthw_field_t *mp_cfn_data_ptc_frag;
+	nthw_field_t *mp_cfn_data_ptc_ip_prot;
+	nthw_field_t *mp_cfn_data_ptc_l4;
+	nthw_field_t *mp_cfn_data_ptc_tunnel;
+	nthw_field_t *mp_cfn_data_ptc_tnl_l2;
+	nthw_field_t *mp_cfn_data_ptc_tnl_vlan;
+	nthw_field_t *mp_cfn_data_ptc_tnl_mpls;
+	nthw_field_t *mp_cfn_data_ptc_tnl_l3;
+	nthw_field_t *mp_cfn_data_ptc_tnl_frag;
+	nthw_field_t *mp_cfn_data_ptc_tnl_ip_prot;
+	nthw_field_t *mp_cfn_data_ptc_tnl_l4;
+	nthw_field_t *mp_cfn_data_err_inv;
+	nthw_field_t *mp_cfn_data_err_cv;
+	nthw_field_t *mp_cfn_data_err_fcs;
+	nthw_field_t *mp_cfn_data_err_trunc;
+	nthw_field_t *mp_cfn_data_err_l3_cs;
+	nthw_field_t *mp_cfn_data_err_l4_cs;
+	nthw_field_t *mp_cfn_data_err_tnl_l3_cs;
+	nthw_field_t *mp_cfn_data_err_tnl_l4_cs;
+	nthw_field_t *mp_cfn_data_err_ttl_exp;
+	nthw_field_t *mp_cfn_data_err_tnl_ttl_exp;
+	nthw_field_t *mp_cfn_data_mac_port;
+	nthw_field_t *mp_cfn_data_pm_cmp;
+	nthw_field_t *mp_cfn_data_pm_dct;
+	nthw_field_t *mp_cfn_data_pm_ext_inv;
+	nthw_field_t *mp_cfn_data_pm_cmb;
+	nthw_field_t *mp_cfn_data_pm_and_inv;
+	nthw_field_t *mp_cfn_data_pm_or_inv;
+	nthw_field_t *mp_cfn_data_pm_inv;
+	nthw_field_t *mp_cfn_data_lc;
+	nthw_field_t *mp_cfn_data_lc_inv;
+	nthw_field_t *mp_cfn_data_km0_or;
+	nthw_field_t *mp_cfn_data_km1_or;
+
+	nthw_register_t *mp_kce_ctrl[2];
+	nthw_field_t *mp_kce_addr[2];
+	nthw_field_t *mp_kce_cnt[2];
+	nthw_register_t *mp_kce_data[2];
+	nthw_field_t *mp_kce_data_enable[2];
+
+	nthw_register_t *mp_kcs_ctrl[2];
+	nthw_field_t *mp_kcs_addr[2];
+	nthw_field_t *mp_kcs_cnt[2];
+	nthw_register_t *mp_kcs_data[2];
+	nthw_field_t *mp_kcs_data_category[2];
+
+	nthw_register_t *mp_fte_ctrl[2];
+	nthw_field_t *mp_fte_addr[2];
+	nthw_field_t *mp_fte_cnt[2];
+	nthw_register_t *mp_fte_data[2];
+	nthw_field_t *mp_fte_data_enable[2];
+
+	nthw_register_t *mp_cte_ctrl;
+	nthw_field_t *mp_cte_addr;
+	nthw_field_t *mp_cte_cnt;
+	nthw_register_t *mp_cte_data;
+	nthw_field_t *mp_cte_data_col;
+	nthw_field_t *mp_cte_data_cor;
+	nthw_field_t *mp_cte_data_hsh;
+	nthw_field_t *mp_cte_data_qsl;
+	nthw_field_t *mp_cte_data_ipf;
+	nthw_field_t *mp_cte_data_slc;
+	nthw_field_t *mp_cte_data_pdb;
+	nthw_field_t *mp_cte_data_msk;
+	nthw_field_t *mp_cte_data_hst;
+	nthw_field_t *mp_cte_data_epp;
+	nthw_field_t *mp_cte_data_tpe;
+	nthw_field_t *mp_cte_data_rrb;
+
+	nthw_register_t *mp_cts_ctrl;
+	nthw_field_t *mp_cts_addr;
+	nthw_field_t *mp_cts_cnt;
+	nthw_register_t *mp_cts_data;
+	nthw_field_t *mp_cts_data_cat_a;
+	nthw_field_t *mp_cts_data_cat_b;
+
+	nthw_register_t *mp_cot_ctrl;
+	nthw_field_t *mp_cot_addr;
+	nthw_field_t *mp_cot_cnt;
+	nthw_register_t *mp_cot_data;
+	nthw_field_t *mp_cot_data_color;
+	nthw_field_t *mp_cot_data_km;
+	nthw_field_t *mp_cot_data_nfv_sb;
+
+	nthw_register_t *mp_cct_ctrl;
+	nthw_field_t *mp_cct_addr;
+	nthw_field_t *mp_cct_cnt;
+	nthw_register_t *mp_cct_data;
+	nthw_field_t *mp_cct_data_color;
+	nthw_field_t *mp_cct_data_km;
+
+	nthw_register_t *mp_exo_ctrl;
+	nthw_field_t *mp_exo_addr;
+	nthw_field_t *mp_exo_cnt;
+	nthw_register_t *mp_exo_data;
+	nthw_field_t *mp_exo_data_dyn;
+	nthw_field_t *mp_exo_data_ofs;
+
+	nthw_register_t *mp_rck_ctrl;
+	nthw_field_t *mp_rck_addr;
+	nthw_field_t *mp_rck_cnt;
+	nthw_register_t *mp_rck_data;
+
+	nthw_register_t *mp_len_ctrl;
+	nthw_field_t *mp_len_addr;
+	nthw_field_t *mp_len_cnt;
+	nthw_register_t *mp_len_data;
+	nthw_field_t *mp_len_data_lower;
+	nthw_field_t *mp_len_data_upper;
+	nthw_field_t *mp_len_data_dyn1;
+	nthw_field_t *mp_len_data_dyn2;
+	nthw_field_t *mp_len_data_inv;
+	nthw_register_t *mp_kcc_ctrl;
+	nthw_field_t *mp_kcc_addr;
+	nthw_field_t *mp_kcc_cnt;
+
+	nthw_register_t *mp_kcc_data;
+	nthw_field_t *mp_kcc_data_key;
+	nthw_field_t *mp_kcc_data_category;
+	nthw_field_t *mp_kcc_data_id;
+};
+
+#endif	/* __FLOW_NTHW_CAT_H__ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index 0b69d09cde..d4ccc5157d 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -14,6 +14,7 @@
 #define _NTHW_FPGA_MOD_DEFS_H_
 
 #define MOD_UNKNOWN (0L)/* Unknown/uninitialized - keep this as the first element */
+#define MOD_CAT (0x30b447c2UL)
 #define MOD_GFG (0xfc423807UL)
 #define MOD_GMF (0x68b1d15aUL)
 #define MOD_GPIO_PHY (0xbbe81659UL)
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index 8a55b9aeca..dad498256f 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -13,6 +13,7 @@
 #ifndef _NTHW_FPGA_REG_DEFS_
 #define _NTHW_FPGA_REG_DEFS_
 
+#include "nthw_fpga_reg_defs_cat.h"
 #include "nthw_fpga_reg_defs_gfg.h"
 #include "nthw_fpga_reg_defs_gmf.h"
 #include "nthw_fpga_reg_defs_gpio_phy.h"
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_cat.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_cat.h
new file mode 100644
index 0000000000..cafed8a4bc
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_cat.h
@@ -0,0 +1,238 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_cat.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_CAT_
+#define _NTHW_FPGA_REG_DEFS_CAT_
+
+/* CAT */
+#define NTHW_MOD_CAT (0x30b447c2UL)
+#define CAT_CCT_CTRL (0x234d3a78UL)
+#define CAT_CCT_CTRL_ADR (0x6146f230UL)
+#define CAT_CCT_CTRL_CNT (0x714e6be1UL)
+#define CAT_CCT_DATA (0x8c9cb861UL)
+#define CAT_CCT_DATA_COLOR (0x27e29b73UL)
+#define CAT_CCT_DATA_KM (0x4ac2435fUL)
+#define CAT_CFN_CTRL (0xd3383422UL)
+#define CAT_CFN_CTRL_ADR (0x209d4f53UL)
+#define CAT_CFN_CTRL_CNT (0x3095d682UL)
+#define CAT_CFN_DATA (0x7ce9b63bUL)
+#define CAT_CFN_DATA_ENABLE (0xd2ae88e2UL)
+#define CAT_CFN_DATA_ERR_CV (0x22ca6722UL)
+#define CAT_CFN_DATA_ERR_FCS (0xc45c40bfUL)
+#define CAT_CFN_DATA_ERR_INV (0xac48d40UL)
+#define CAT_CFN_DATA_ERR_L3_CS (0x55fb7895UL)
+#define CAT_CFN_DATA_ERR_L4_CS (0xc82c402cUL)
+#define CAT_CFN_DATA_ERR_TNL_L3_CS (0x51e668edUL)
+#define CAT_CFN_DATA_ERR_TNL_L4_CS (0xcc315054UL)
+#define CAT_CFN_DATA_ERR_TNL_TTL_EXP (0x948d9686UL)
+#define CAT_CFN_DATA_ERR_TRUNC (0x237fdf4fUL)
+#define CAT_CFN_DATA_ERR_TTL_EXP (0x6edc7101UL)
+#define CAT_CFN_DATA_FLM_OR (0xd82cf0b3UL)
+#define CAT_CFN_DATA_INV (0xc2e6afa4UL)
+#define CAT_CFN_DATA_KM0_OR (0xc087b29cUL)
+#define CAT_CFN_DATA_KM1_OR (0x783bd5f9UL)
+#define CAT_CFN_DATA_KM_OR (0x58fbb39eUL)
+#define CAT_CFN_DATA_LC (0x3dfcfb34UL)
+#define CAT_CFN_DATA_LC_INV (0x72af18aUL)
+#define CAT_CFN_DATA_MAC_PORT (0xcd340483UL)
+#define CAT_CFN_DATA_PM_AND_INV (0x3ae1c6afUL)
+#define CAT_CFN_DATA_PM_CMB (0xf06e8f63UL)
+#define CAT_CFN_DATA_PM_CMP (0x3d7fe2bUL)
+#define CAT_CFN_DATA_PM_DCT (0x9f760139UL)
+#define CAT_CFN_DATA_PM_EXT_INV (0x7bc194b8UL)
+#define CAT_CFN_DATA_PM_INV (0xcc0e8d0bUL)
+#define CAT_CFN_DATA_PM_OR_INV (0x7790b2fUL)
+#define CAT_CFN_DATA_PTC_CFP (0x98d6c9edUL)
+#define CAT_CFN_DATA_PTC_FRAG (0x9bb1ab3cUL)
+#define CAT_CFN_DATA_PTC_INV (0xb4fb6306UL)
+#define CAT_CFN_DATA_PTC_IP_PROT (0xfee4889bUL)
+#define CAT_CFN_DATA_PTC_ISL (0xb6f5f660UL)
+#define CAT_CFN_DATA_PTC_L2 (0xdb7388deUL)
+#define CAT_CFN_DATA_PTC_L3 (0xac74b848UL)
+#define CAT_CFN_DATA_PTC_L4 (0x32102debUL)
+#define CAT_CFN_DATA_PTC_MAC (0x59b733feUL)
+#define CAT_CFN_DATA_PTC_MPLS (0xe0405263UL)
+#define CAT_CFN_DATA_PTC_TNL_FRAG (0x76e4a788UL)
+#define CAT_CFN_DATA_PTC_TNL_IP_PROT (0x8b0734cdUL)
+#define CAT_CFN_DATA_PTC_TNL_L2 (0xec64285eUL)
+#define CAT_CFN_DATA_PTC_TNL_L3 (0x9b6318c8UL)
+#define CAT_CFN_DATA_PTC_TNL_L4 (0x5078d6bUL)
+#define CAT_CFN_DATA_PTC_TNL_MPLS (0xd155ed7UL)
+#define CAT_CFN_DATA_PTC_TNL_VLAN (0x4999c6c9UL)
+#define CAT_CFN_DATA_PTC_TUNNEL (0x2ac66873UL)
+#define CAT_CFN_DATA_PTC_VLAN (0xa4ccca7dUL)
+#define CAT_CFN_DATA_PTC_VNTAG (0x23d64f2aUL)
+#define CAT_COT_CTRL (0xe4ed500cUL)
+#define CAT_COT_CTRL_ADR (0x6b5c60f7UL)
+#define CAT_COT_CTRL_CNT (0x7b54f926UL)
+#define CAT_COT_DATA (0x4b3cd215UL)
+#define CAT_COT_DATA_COLOR (0xbd582288UL)
+#define CAT_COT_DATA_KM (0x50fea3d1UL)
+#define CAT_COT_DATA_NFV_SB (0x2219c864UL)
+#define CAT_CTE_CTRL (0x49be4906UL)
+#define CAT_CTE_CTRL_ADR (0x2ee7c9aeUL)
+#define CAT_CTE_CTRL_CNT (0x3eef507fUL)
+#define CAT_CTE_DATA (0xe66fcb1fUL)
+#define CAT_CTE_DATA_COL_ENABLE (0xa9ca226bUL)
+#define CAT_CTE_DATA_COR_ENABLE (0xc0fb0172UL)
+#define CAT_CTE_DATA_EPP_ENABLE (0xfcb9fbe8UL)
+#define CAT_CTE_DATA_HSH_ENABLE (0x9f946603UL)
+#define CAT_CTE_DATA_HST_ENABLE (0xb4804267UL)
+#define CAT_CTE_DATA_IPF_ENABLE (0x5c5123caUL)
+#define CAT_CTE_DATA_MSK_ENABLE (0xf732aaa4UL)
+#define CAT_CTE_DATA_PDB_ENABLE (0xf28c946fUL)
+#define CAT_CTE_DATA_QSL_ENABLE (0xc065c2dbUL)
+#define CAT_CTE_DATA_SLC_ENABLE (0x6ec98deaUL)
+#define CAT_CTE_DATA_TPE_ENABLE (0x8e2e71UL)
+#define CAT_CTE_DATA_TX_INS_ENABLE (0x585922e3UL)
+#define CAT_CTE_DATA_TX_RPL_ENABLE (0x468ee298UL)
+#define CAT_CTS_CTRL (0x9c31a880UL)
+#define CAT_CTS_CTRL_ADR (0x4573801UL)
+#define CAT_CTS_CTRL_CNT (0x145fa1d0UL)
+#define CAT_CTS_DATA (0x33e02a99UL)
+#define CAT_CTS_DATA_CAT_A (0xa698040aUL)
+#define CAT_CTS_DATA_CAT_B (0x3f9155b0UL)
+#define CAT_DCT_CTRL (0x29883361UL)
+#define CAT_DCT_CTRL_ADR (0x15de1bbfUL)
+#define CAT_DCT_CTRL_CNT (0x5d6826eUL)
+#define CAT_DCT_DATA (0x8659b178UL)
+#define CAT_DCT_DATA_RES (0x74489a9dUL)
+#define CAT_DCT_SEL (0xeb603410UL)
+#define CAT_DCT_SEL_LU (0x60e126beUL)
+#define CAT_EXO_CTRL (0xe9ea0993UL)
+#define CAT_EXO_CTRL_ADR (0xdce26e40UL)
+#define CAT_EXO_CTRL_CNT (0xcceaf791UL)
+#define CAT_EXO_DATA (0x463b8b8aUL)
+#define CAT_EXO_DATA_DYN (0x20ae0124UL)
+#define CAT_EXO_DATA_OFS (0x82a78c82UL)
+#define CAT_FCE_CTRL (0xa327e522UL)
+#define CAT_FCE_CTRL_ADR (0x31896ff6UL)
+#define CAT_FCE_CTRL_CNT (0x2181f627UL)
+#define CAT_FCE_DATA (0xcf6673bUL)
+#define CAT_FCE_DATA_ENABLE (0x8243e7a7UL)
+#define CAT_FCS_CTRL (0x76a804a4UL)
+#define CAT_FCS_CTRL_ADR (0x1b399e59UL)
+#define CAT_FCS_CTRL_CNT (0xb310788UL)
+#define CAT_FCS_DATA (0xd97986bdUL)
+#define CAT_FCS_DATA_CATEGORY (0x69d964f3UL)
+#define CAT_FTE0_CTRL (0x4f655742UL)
+#define CAT_FTE0_CTRL_ADR (0xa786315fUL)
+#define CAT_FTE0_CTRL_CNT (0xb78ea88eUL)
+#define CAT_FTE0_DATA (0xe0b4d55bUL)
+#define CAT_FTE0_DATA_ENABLE (0xe06dec95UL)
+#define CAT_FTE1_CTRL (0x843984e7UL)
+#define CAT_FTE1_CTRL_ADR (0x48445a61UL)
+#define CAT_FTE1_CTRL_CNT (0x584cc3b0UL)
+#define CAT_FTE1_DATA (0x2be806feUL)
+#define CAT_FTE1_DATA_ENABLE (0x3dfb3510UL)
+#define CAT_FTE_CTRL (0x15e4762UL)
+#define CAT_FTE_CTRL_ADR (0xb644bebeUL)
+#define CAT_FTE_CTRL_CNT (0xa64c276fUL)
+#define CAT_FTE_DATA (0xae8fc57bUL)
+#define CAT_FTE_DATA_ENABLE (0x813c710bUL)
+#define CAT_FTE_FLM_CTRL (0x4a63f99eUL)
+#define CAT_FTE_FLM_CTRL_ADR (0x3ed2141dUL)
+#define CAT_FTE_FLM_CTRL_CNT (0x2eda8dccUL)
+#define CAT_FTE_FLM_DATA (0xe5b27b87UL)
+#define CAT_FTE_FLM_DATA_ENABLE (0x1786f0a8UL)
+#define CAT_JOIN (0xf643707UL)
+#define CAT_JOIN_J1 (0x494d06b2UL)
+#define CAT_JOIN_J2 (0xd0445708UL)
+#define CAT_KCC (0x26068f04UL)
+#define CAT_KCC_CTRL (0xee7b13eeUL)
+#define CAT_KCC_CTRL_ADR (0xa2381e5fUL)
+#define CAT_KCC_CTRL_CNT (0xb230878eUL)
+#define CAT_KCC_DATA (0x41aa91f7UL)
+#define CAT_KCC_DATA_CATEGORY (0x3f0558aeUL)
+#define CAT_KCC_DATA_ID (0x734a5784UL)
+#define CAT_KCC_DATA_KEY (0x308cee9cUL)
+#define CAT_KCE0_CTRL (0xc8548827UL)
+#define CAT_KCE0_CTRL_ADR (0x982a5552UL)
+#define CAT_KCE0_CTRL_CNT (0x8822cc83UL)
+#define CAT_KCE0_DATA (0x67850a3eUL)
+#define CAT_KCE0_DATA_ENABLE (0x36443e99UL)
+#define CAT_KCE1_CTRL (0x3085b82UL)
+#define CAT_KCE1_CTRL_ADR (0x77e83e6cUL)
+#define CAT_KCE1_CTRL_CNT (0x67e0a7bdUL)
+#define CAT_KCE1_DATA (0xacd9d99bUL)
+#define CAT_KCE1_DATA_ENABLE (0xebd2e71cUL)
+#define CAT_KCE_CTRL (0x3822f0f3UL)
+#define CAT_KCE_CTRL_ADR (0xaf266e18UL)
+#define CAT_KCE_CTRL_CNT (0xbf2ef7c9UL)
+#define CAT_KCE_DATA (0x97f372eaUL)
+#define CAT_KCE_DATA_ENABLE (0x7e4d95abUL)
+#define CAT_KCS0_CTRL (0xcc5a21d3UL)
+#define CAT_KCS0_CTRL_ADR (0xde695bdaUL)
+#define CAT_KCS0_CTRL_CNT (0xce61c20bUL)
+#define CAT_KCS0_DATA (0x638ba3caUL)
+#define CAT_KCS0_DATA_CATEGORY (0x43dbd3eUL)
+#define CAT_KCS1_CTRL (0x706f276UL)
+#define CAT_KCS1_CTRL_ADR (0x31ab30e4UL)
+#define CAT_KCS1_CTRL_CNT (0x21a3a935UL)
+#define CAT_KCS1_DATA (0xa8d7706fUL)
+#define CAT_KCS1_DATA_CATEGORY (0xbdc666d6UL)
+#define CAT_KCS_CTRL (0xedad1175UL)
+#define CAT_KCS_CTRL_ADR (0x85969fb7UL)
+#define CAT_KCS_CTRL_CNT (0x959e0666UL)
+#define CAT_KCS_DATA (0x427c936cUL)
+#define CAT_KCS_DATA_CATEGORY (0x7b67c7e1UL)
+#define CAT_LEN_CTRL (0x3bf03c13UL)
+#define CAT_LEN_CTRL_ADR (0xcbebb623UL)
+#define CAT_LEN_CTRL_CNT (0xdbe32ff2UL)
+#define CAT_LEN_DATA (0x9421be0aUL)
+#define CAT_LEN_DATA_DYN1 (0x6b539c5dUL)
+#define CAT_LEN_DATA_DYN2 (0xf25acde7UL)
+#define CAT_LEN_DATA_INV (0x299056d4UL)
+#define CAT_LEN_DATA_LOWER (0x5f70c60fUL)
+#define CAT_LEN_DATA_UPPER (0x3fb562b0UL)
+#define CAT_RCK_CTRL (0x61dcbb83UL)
+#define CAT_RCK_CTRL_ADR (0x205e89c6UL)
+#define CAT_RCK_CTRL_CNT (0x30561017UL)
+#define CAT_RCK_DATA (0xce0d399aUL)
+#define CAT_RCK_DATA_CM0U (0xc643fdb9UL)
+#define CAT_RCK_DATA_CM1U (0xdf58ccf8UL)
+#define CAT_RCK_DATA_CM2U (0xf4759f3bUL)
+#define CAT_RCK_DATA_CM3U (0xed6eae7aUL)
+#define CAT_RCK_DATA_CM4U (0xa22f38bdUL)
+#define CAT_RCK_DATA_CM5U (0xbb3409fcUL)
+#define CAT_RCK_DATA_CM6U (0x90195a3fUL)
+#define CAT_RCK_DATA_CM7U (0x89026b7eUL)
+#define CAT_RCK_DATA_CML0 (0x78115e94UL)
+#define CAT_RCK_DATA_CML1 (0xf166e02UL)
+#define CAT_RCK_DATA_CML2 (0x961f3fb8UL)
+#define CAT_RCK_DATA_CML3 (0xe1180f2eUL)
+#define CAT_RCK_DATA_CML4 (0x7f7c9a8dUL)
+#define CAT_RCK_DATA_CML5 (0x87baa1bUL)
+#define CAT_RCK_DATA_CML6 (0x9172fba1UL)
+#define CAT_RCK_DATA_CML7 (0xe675cb37UL)
+#define CAT_RCK_DATA_SEL0 (0x261b58b3UL)
+#define CAT_RCK_DATA_SEL1 (0x511c6825UL)
+#define CAT_RCK_DATA_SEL2 (0xc815399fUL)
+#define CAT_RCK_DATA_SEL3 (0xbf120909UL)
+#define CAT_RCK_DATA_SEL4 (0x21769caaUL)
+#define CAT_RCK_DATA_SEL5 (0x5671ac3cUL)
+#define CAT_RCK_DATA_SEL6 (0xcf78fd86UL)
+#define CAT_RCK_DATA_SEL7 (0xb87fcd10UL)
+#define CAT_RCK_DATA_SEU0 (0xbd1bf1abUL)
+#define CAT_RCK_DATA_SEU1 (0xca1cc13dUL)
+#define CAT_RCK_DATA_SEU2 (0x53159087UL)
+#define CAT_RCK_DATA_SEU3 (0x2412a011UL)
+#define CAT_RCK_DATA_SEU4 (0xba7635b2UL)
+#define CAT_RCK_DATA_SEU5 (0xcd710524UL)
+#define CAT_RCK_DATA_SEU6 (0x5478549eUL)
+#define CAT_RCK_DATA_SEU7 (0x237f6408UL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_CAT_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 07/31] net/ntnic: add key match (KM) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (11 preceding siblings ...)
  2024-10-04 15:06 ` [PATCH v1 06/31] net/ntnic: add categorizer (CAT) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 08/31] net/ntnic: add flow matcher (FLM) " Serhii Iliushyk
                   ` (38 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Key Matcher module checks the values of individual fields of a packet.
It supports both exact match which is implemented with a CAM,
and wildcards which is implemented with a TCAM.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    |  28 +
 drivers/net/ntnic/include/hw_mod_km_v7.h      |  96 +++
 drivers/net/ntnic/meson.build                 |   1 +
 .../nthw/flow_api/flow_backend/flow_backend.c | 206 ++++++
 .../net/ntnic/nthw/flow_filter/flow_nthw_km.c | 610 ++++++++++++++++++
 .../net/ntnic/nthw/flow_filter/flow_nthw_km.h | 214 ++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |   1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |   1 +
 .../nthw/supported/nthw_fpga_reg_defs_km.h    | 126 ++++
 9 files changed, 1283 insertions(+)
 create mode 100644 drivers/net/ntnic/include/hw_mod_km_v7.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_km.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_km.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_km.h

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index ce2c0cf7cf..b921c06643 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -10,6 +10,7 @@
 
 #include "hw_mod_cat_v18.h"
 #include "hw_mod_cat_v21.h"
+#include "hw_mod_km_v7.h"
 
 #define MAX_PHYS_ADAPTERS 8
 
@@ -40,6 +41,23 @@ struct cat_func_s {
 	};
 };
 
+struct km_func_s {
+	COMMON_FUNC_INFO_S;
+	uint32_t nb_categories;
+	uint32_t nb_cam_banks;
+	uint32_t nb_cam_record_words;
+	uint32_t nb_cam_records;
+	uint32_t nb_tcam_banks;
+	uint32_t nb_tcam_bank_width;
+	/* not read from backend, but rather set using version */
+	uint32_t nb_km_rcp_mask_a_word_size;
+	/* --- || --- */
+	uint32_t nb_km_rcp_mask_b_word_size;
+	union {
+		struct hw_mod_km_v7_s v7;
+	};
+};
+
 enum debug_mode_e {
 	FLOW_BACKEND_DEBUG_MODE_NONE = 0x0000,
 	FLOW_BACKEND_DEBUG_MODE_WRITE = 0x0001
@@ -112,6 +130,16 @@ struct flow_api_backend_ops {
 	int (*cat_rck_flush)(void *dev, const struct cat_func_s *cat, int index, int cnt);
 	int (*cat_len_flush)(void *dev, const struct cat_func_s *cat, int index, int cnt);
 	int (*cat_kcc_flush)(void *dev, const struct cat_func_s *cat, int index, int cnt);
+
+	/* KM */
+	bool (*get_km_present)(void *dev);
+	uint32_t (*get_km_version)(void *dev);
+	int (*km_rcp_flush)(void *dev, const struct km_func_s *km, int category, int cnt);
+	int (*km_cam_flush)(void *dev, const struct km_func_s *km, int bank, int record, int cnt);
+	int (*km_tcam_flush)(void *dev, const struct km_func_s *km, int bank, int byte, int value,
+		int cnt);
+	int (*km_tci_flush)(void *dev, const struct km_func_s *km, int bank, int record, int cnt);
+	int (*km_tcq_flush)(void *dev, const struct km_func_s *km, int bank, int record, int cnt);
 };
 
 struct flow_api_backend_s {
diff --git a/drivers/net/ntnic/include/hw_mod_km_v7.h b/drivers/net/ntnic/include/hw_mod_km_v7.h
new file mode 100644
index 0000000000..dcc28c1812
--- /dev/null
+++ b/drivers/net/ntnic/include/hw_mod_km_v7.h
@@ -0,0 +1,96 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _HW_MOD_KM_V7_H_
+#define _HW_MOD_KM_V7_H_
+
+#include <stdint.h>
+
+struct km_v7_rcp_s {
+	uint32_t qw0_dyn;
+	int32_t qw0_ofs;
+	uint32_t qw0_sel_a;
+	uint32_t qw0_sel_b;
+	uint32_t qw4_dyn;
+	int32_t qw4_ofs;
+	uint32_t qw4_sel_a;
+	uint32_t qw4_sel_b;
+	uint32_t dw8_dyn;
+	int32_t dw8_ofs;
+	uint32_t dw8_sel_a;
+	uint32_t dw8_sel_b;
+	uint32_t dw10_dyn;
+	int32_t dw10_ofs;
+	uint32_t dw10_sel_a;
+	uint32_t dw10_sel_b;
+	uint32_t swx_cch;
+	uint32_t swx_sel_a;
+	uint32_t swx_sel_b;
+	uint32_t mask_d_a[12];
+	uint32_t mask_b[6];
+	uint32_t dual;
+	uint32_t paired;
+	uint32_t el_a;
+	uint32_t el_b;
+	uint32_t info_a;
+	uint32_t info_b;
+	uint32_t ftm_a;
+	uint32_t ftm_b;
+	uint32_t bank_a;
+	uint32_t bank_b;
+	uint32_t kl_a;
+	uint32_t kl_b;
+	uint32_t keyway_a;
+	uint32_t keyway_b;
+	uint32_t synergy_mode;
+	uint32_t dw0_b_dyn;
+	int32_t dw0_b_ofs;
+	uint32_t dw2_b_dyn;
+	int32_t dw2_b_ofs;
+	uint32_t sw4_b_dyn;
+	int32_t sw4_b_ofs;
+	uint32_t sw5_b_dyn;
+	int32_t sw5_b_ofs;
+};
+
+struct km_v7_cam_s {
+	uint32_t w0;
+	uint32_t w1;
+	uint32_t w2;
+	uint32_t w3;
+	uint32_t w4;
+	uint32_t w5;
+	uint32_t ft0;
+	uint32_t ft1;
+	uint32_t ft2;
+	uint32_t ft3;
+	uint32_t ft4;
+	uint32_t ft5;
+};
+
+struct km_v7_tcam_s {
+	uint32_t t[3];
+	uint32_t dirty;
+};
+
+struct km_v7_tci_s {
+	uint32_t color;
+	uint32_t ft;
+};
+
+struct km_v7_tcq_s {
+	uint32_t bank_mask;
+	uint32_t qual;
+};
+
+struct hw_mod_km_v7_s {
+	struct km_v7_rcp_s *rcp;
+	struct km_v7_cam_s *cam;
+	struct km_v7_tcam_s *tcam;
+	struct km_v7_tci_s *tci;
+	struct km_v7_tcq_s *tcq;
+};
+
+#endif	/* _HW_MOD_KM_V7_H_ */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 09631fb84b..8d297cbb61 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -48,6 +48,7 @@ sources = files(
         'nthw/flow_api/flow_filter.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_info.c',
+        'nthw/flow_filter/flow_nthw_km.c',
         'nthw/model/nthw_fpga_model.c',
         'nthw/nthw_platform.c',
         'nthw/nthw_rac.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index 16cc24ec72..c004000cc0 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -7,6 +7,7 @@
 
 #include "flow_nthw_info.h"
 #include "flow_nthw_cat.h"
+#include "flow_nthw_km.h"
 #include "ntnic_mod_reg.h"
 #include "nthw_fpga_model.h"
 #include "hw_mod_backend.h"
@@ -23,6 +24,7 @@ static struct backend_dev_s {
 	enum debug_mode_e dmode;
 	struct info_nthw *p_info_nthw;
 	struct cat_nthw *p_cat_nthw;
+	struct km_nthw *p_km_nthw;
 } be_devs[MAX_PHYS_ADAPTERS];
 
 #define CHECK_DEBUG_ON(be, mod, inst)                                                             \
@@ -720,6 +722,191 @@ static int cat_kcc_flush(void *be_dev, const struct cat_func_s *cat, int len_ind
 	return 0;
 }
 
+/*
+ * KM
+ */
+
+static bool km_get_present(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return be->p_km_nthw != NULL;
+}
+
+static uint32_t km_get_version(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return (uint32_t)((nthw_module_get_major_version(be->p_km_nthw->m_km) << 16) |
+			(nthw_module_get_minor_version(be->p_km_nthw->m_km) & 0xffff));
+}
+
+static int km_rcp_flush(void *be_dev, const struct km_func_s *km, int category, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+
+	CHECK_DEBUG_ON(be, km, be->p_km_nthw);
+
+	if (km->ver == 7) {
+		km_nthw_rcp_cnt(be->p_km_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			km_nthw_rcp_select(be->p_km_nthw, category + i);
+			km_nthw_rcp_qw0_dyn(be->p_km_nthw, km->v7.rcp[category + i].qw0_dyn);
+			km_nthw_rcp_qw0_ofs(be->p_km_nthw, km->v7.rcp[category + i].qw0_ofs);
+			km_nthw_rcp_qw0_sel_a(be->p_km_nthw, km->v7.rcp[category + i].qw0_sel_a);
+			km_nthw_rcp_qw0_sel_b(be->p_km_nthw, km->v7.rcp[category + i].qw0_sel_b);
+			km_nthw_rcp_qw4_dyn(be->p_km_nthw, km->v7.rcp[category + i].qw4_dyn);
+			km_nthw_rcp_qw4_ofs(be->p_km_nthw, km->v7.rcp[category + i].qw4_ofs);
+			km_nthw_rcp_qw4_sel_a(be->p_km_nthw, km->v7.rcp[category + i].qw4_sel_a);
+			km_nthw_rcp_qw4_sel_b(be->p_km_nthw, km->v7.rcp[category + i].qw4_sel_b);
+			km_nthw_rcp_dw8_dyn(be->p_km_nthw, km->v7.rcp[category + i].dw8_dyn);
+			km_nthw_rcp_dw8_ofs(be->p_km_nthw, km->v7.rcp[category + i].dw8_ofs);
+			km_nthw_rcp_dw8_sel_a(be->p_km_nthw, km->v7.rcp[category + i].dw8_sel_a);
+			km_nthw_rcp_dw8_sel_b(be->p_km_nthw, km->v7.rcp[category + i].dw8_sel_b);
+			km_nthw_rcp_dw10_dyn(be->p_km_nthw, km->v7.rcp[category + i].dw10_dyn);
+			km_nthw_rcp_dw10_ofs(be->p_km_nthw, km->v7.rcp[category + i].dw10_ofs);
+			km_nthw_rcp_dw10_sel_a(be->p_km_nthw, km->v7.rcp[category + i].dw10_sel_a);
+			km_nthw_rcp_dw10_sel_b(be->p_km_nthw, km->v7.rcp[category + i].dw10_sel_b);
+			km_nthw_rcp_swx_cch(be->p_km_nthw, km->v7.rcp[category + i].swx_cch);
+			km_nthw_rcp_swx_sel_a(be->p_km_nthw, km->v7.rcp[category + i].swx_sel_a);
+			km_nthw_rcp_swx_sel_b(be->p_km_nthw, km->v7.rcp[category + i].swx_sel_b);
+			km_nthw_rcp_mask_da(be->p_km_nthw, km->v7.rcp[category + i].mask_d_a);
+			km_nthw_rcp_mask_b(be->p_km_nthw, km->v7.rcp[category + i].mask_b);
+			km_nthw_rcp_dual(be->p_km_nthw, km->v7.rcp[category + i].dual);
+			km_nthw_rcp_paired(be->p_km_nthw, km->v7.rcp[category + i].paired);
+			km_nthw_rcp_el_a(be->p_km_nthw, km->v7.rcp[category + i].el_a);
+			km_nthw_rcp_el_b(be->p_km_nthw, km->v7.rcp[category + i].el_b);
+			km_nthw_rcp_info_a(be->p_km_nthw, km->v7.rcp[category + i].info_a);
+			km_nthw_rcp_info_b(be->p_km_nthw, km->v7.rcp[category + i].info_b);
+			km_nthw_rcp_ftm_a(be->p_km_nthw, km->v7.rcp[category + i].ftm_a);
+			km_nthw_rcp_ftm_b(be->p_km_nthw, km->v7.rcp[category + i].ftm_b);
+			km_nthw_rcp_bank_a(be->p_km_nthw, km->v7.rcp[category + i].bank_a);
+			km_nthw_rcp_bank_b(be->p_km_nthw, km->v7.rcp[category + i].bank_b);
+			km_nthw_rcp_kl_a(be->p_km_nthw, km->v7.rcp[category + i].kl_a);
+			km_nthw_rcp_kl_b(be->p_km_nthw, km->v7.rcp[category + i].kl_b);
+			km_nthw_rcp_keyway_a(be->p_km_nthw, km->v7.rcp[category + i].keyway_a);
+			km_nthw_rcp_keyway_b(be->p_km_nthw, km->v7.rcp[category + i].keyway_b);
+			km_nthw_rcp_synergy_mode(be->p_km_nthw,
+				km->v7.rcp[category + i].synergy_mode);
+			km_nthw_rcp_dw0_b_dyn(be->p_km_nthw, km->v7.rcp[category + i].dw0_b_dyn);
+			km_nthw_rcp_dw0_b_ofs(be->p_km_nthw, km->v7.rcp[category + i].dw0_b_ofs);
+			km_nthw_rcp_dw2_b_dyn(be->p_km_nthw, km->v7.rcp[category + i].dw2_b_dyn);
+			km_nthw_rcp_dw2_b_ofs(be->p_km_nthw, km->v7.rcp[category + i].dw2_b_ofs);
+			km_nthw_rcp_sw4_b_dyn(be->p_km_nthw, km->v7.rcp[category + i].sw4_b_dyn);
+			km_nthw_rcp_sw4_b_ofs(be->p_km_nthw, km->v7.rcp[category + i].sw4_b_ofs);
+			km_nthw_rcp_sw5_b_dyn(be->p_km_nthw, km->v7.rcp[category + i].sw5_b_dyn);
+			km_nthw_rcp_sw5_b_ofs(be->p_km_nthw, km->v7.rcp[category + i].sw5_b_ofs);
+			km_nthw_rcp_flush(be->p_km_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(km, be->p_km_nthw);
+	return 0;
+}
+
+static int km_cam_flush(void *be_dev, const struct km_func_s *km, int bank, int record, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, km, be->p_km_nthw);
+
+	if (km->ver == 7) {
+		km_nthw_cam_cnt(be->p_km_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			km_nthw_cam_select(be->p_km_nthw, (bank << 11) + record + i);
+			km_nthw_cam_w0(be->p_km_nthw, km->v7.cam[(bank << 11) + record + i].w0);
+			km_nthw_cam_w1(be->p_km_nthw, km->v7.cam[(bank << 11) + record + i].w1);
+			km_nthw_cam_w2(be->p_km_nthw, km->v7.cam[(bank << 11) + record + i].w2);
+			km_nthw_cam_w3(be->p_km_nthw, km->v7.cam[(bank << 11) + record + i].w3);
+			km_nthw_cam_w4(be->p_km_nthw, km->v7.cam[(bank << 11) + record + i].w4);
+			km_nthw_cam_w5(be->p_km_nthw, km->v7.cam[(bank << 11) + record + i].w5);
+			km_nthw_cam_ft0(be->p_km_nthw, km->v7.cam[(bank << 11) + record + i].ft0);
+			km_nthw_cam_ft1(be->p_km_nthw, km->v7.cam[(bank << 11) + record + i].ft1);
+			km_nthw_cam_ft2(be->p_km_nthw, km->v7.cam[(bank << 11) + record + i].ft2);
+			km_nthw_cam_ft3(be->p_km_nthw, km->v7.cam[(bank << 11) + record + i].ft3);
+			km_nthw_cam_ft4(be->p_km_nthw, km->v7.cam[(bank << 11) + record + i].ft4);
+			km_nthw_cam_ft5(be->p_km_nthw, km->v7.cam[(bank << 11) + record + i].ft5);
+			km_nthw_cam_flush(be->p_km_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(km, be->p_km_nthw);
+	return 0;
+}
+
+static int km_tcam_flush(void *be_dev, const struct km_func_s *km, int bank, int byte, int value,
+	int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, km, be->p_km_nthw);
+
+	if (km->ver == 7) {
+		int start_idx = bank * 4 * 256 + byte * 256 + value;
+		km_nthw_tcam_cnt(be->p_km_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			if (km->v7.tcam[start_idx + i].dirty) {
+				km_nthw_tcam_select(be->p_km_nthw, start_idx + i);
+				km_nthw_tcam_t(be->p_km_nthw, km->v7.tcam[start_idx + i].t);
+				km_nthw_tcam_flush(be->p_km_nthw);
+				km->v7.tcam[start_idx + i].dirty = 0;
+			}
+		}
+	}
+
+	CHECK_DEBUG_OFF(km, be->p_km_nthw);
+	return 0;
+}
+
+/*
+ * bank is the TCAM bank, index is the index within the bank (0..71)
+ */
+static int km_tci_flush(void *be_dev, const struct km_func_s *km, int bank, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, km, be->p_km_nthw);
+
+	if (km->ver == 7) {
+		/* TCAM bank width in version 3 = 72 */
+		km_nthw_tci_cnt(be->p_km_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			km_nthw_tci_select(be->p_km_nthw, bank * 72 + index + i);
+			km_nthw_tci_color(be->p_km_nthw, km->v7.tci[bank * 72 + index + i].color);
+			km_nthw_tci_ft(be->p_km_nthw, km->v7.tci[bank * 72 + index + i].ft);
+			km_nthw_tci_flush(be->p_km_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(km, be->p_km_nthw);
+	return 0;
+}
+
+/*
+ * bank is the TCAM bank, index is the index within the bank (0..71)
+ */
+static int km_tcq_flush(void *be_dev, const struct km_func_s *km, int bank, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, km, be->p_km_nthw);
+
+	if (km->ver == 7) {
+		/* TCAM bank width in version 3 = 72 */
+		km_nthw_tcq_cnt(be->p_km_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			/* adr = lover 4 bits = bank, upper 7 bits = index */
+			km_nthw_tcq_select(be->p_km_nthw, bank + (index << 4) + i);
+			km_nthw_tcq_bank_mask(be->p_km_nthw,
+				km->v7.tcq[bank + (index << 4) + i].bank_mask);
+			km_nthw_tcq_qual(be->p_km_nthw, km->v7.tcq[bank + (index << 4) + i].qual);
+			km_nthw_tcq_flush(be->p_km_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(km, be->p_km_nthw);
+	return 0;
+}
+
 /*
  * DBS
  */
@@ -805,6 +992,14 @@ const struct flow_api_backend_ops flow_be_iface = {
 	cat_rck_flush,
 	cat_len_flush,
 	cat_kcc_flush,
+
+	km_get_present,
+	km_get_version,
+	km_rcp_flush,
+	km_cam_flush,
+	km_tcam_flush,
+	km_tci_flush,
+	km_tcq_flush,
 };
 
 const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, void **dev)
@@ -825,6 +1020,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_cat_nthw = NULL;
 	}
 
+	/* Init nthw KM */
+	if (km_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct km_nthw *pkmnthw = km_nthw_new();
+		km_nthw_init(pkmnthw, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_km_nthw = pkmnthw;
+
+	} else {
+		be_devs[physical_adapter_no].p_km_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -836,6 +1041,7 @@ static void bin_flow_backend_done(void *dev)
 	struct backend_dev_s *be_dev = (struct backend_dev_s *)dev;
 	info_nthw_delete(be_dev->p_info_nthw);
 	cat_nthw_delete(be_dev->p_cat_nthw);
+	km_nthw_delete(be_dev->p_km_nthw);
 }
 
 static const struct flow_backend_ops ops = {
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_km.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_km.c
new file mode 100644
index 0000000000..db720bd6f8
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_km.c
@@ -0,0 +1,610 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_km.h"
+
+#define CHECK_AND_SET_VALUE(a, val)                                                               \
+	do {                                                                                      \
+		nthw_field_t *temp_a = (a);                                                       \
+		if (temp_a) {                                                                     \
+			nthw_field_set_val32(temp_a, val);                                        \
+		}                                                                                 \
+	} while (0)
+
+void km_nthw_set_debug_mode(struct km_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_km, n_debug_mode);
+}
+
+struct km_nthw *km_nthw_new(void)
+{
+	struct km_nthw *p = malloc(sizeof(struct km_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void km_nthw_delete(struct km_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int km_nthw_init(struct km_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_KM, n_instance);
+
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: Km %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_km = p_mod;
+
+	/* RCP */
+	p->mp_rcp_ctrl = nthw_module_get_register(p->m_km, KM_RCP_CTRL);
+	p->mp_rcp_addr = nthw_register_get_field(p->mp_rcp_ctrl, KM_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = nthw_register_get_field(p->mp_rcp_ctrl, KM_RCP_CTRL_CNT);
+	p->mp_rcp_data = nthw_module_get_register(p->m_km, KM_RCP_DATA);
+	p->mp_rcp_data_qw0_dyn = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW0_DYN);
+	p->mp_rcp_data_qw0_ofs = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW0_OFS);
+	p->mp_rcp_data_qw0_sel_a = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW0_SEL_A);
+	p->mp_rcp_data_qw0_sel_b = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW0_SEL_B);
+	p->mp_rcp_data_qw4_dyn = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW4_DYN);
+	p->mp_rcp_data_qw4_ofs = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW4_OFS);
+	p->mp_rcp_data_qw4_sel_a = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW4_SEL_A);
+	p->mp_rcp_data_qw4_sel_b = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW4_SEL_B);
+
+	p->mp_rcp_data_sw8_dyn = nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW8_DYN);
+	p->mp_rcp_data_dw8_dyn = nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW8_DYN);
+
+	p->mp_rcp_data_swx_ovs_sb =
+		nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SWX_OVS_SB);
+	p->mp_rcp_data_swx_cch = nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SWX_CCH);
+	p->mp_rcp_data_swx_sel_a = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_SWX_SEL_A);
+	p->mp_rcp_data_swx_sel_b = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_SWX_SEL_B);
+	p->mp_rcp_data_mask_a = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_MASK_A);
+	p->mp_rcp_data_mask_b = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_MASK_B);
+	p->mp_rcp_data_dual = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_DUAL);
+	p->mp_rcp_data_paired = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_PAIRED);
+	p->mp_rcp_data_el_a = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_EL_A);
+	p->mp_rcp_data_el_b = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_EL_B);
+	p->mp_rcp_data_info_a = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_INFO_A);
+	p->mp_rcp_data_info_b = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_INFO_B);
+	p->mp_rcp_data_ftm_a = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_FTM_A);
+	p->mp_rcp_data_ftm_b = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_FTM_B);
+	p->mp_rcp_data_bank_a = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_BANK_A);
+	p->mp_rcp_data_bank_b = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_BANK_B);
+	p->mp_rcp_data_kl_a = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_KL_A);
+	p->mp_rcp_data_kl_b = nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_KL_B);
+	p->mp_rcp_data_flow_set = nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_FLOW_SET);
+	p->mp_rcp_data_keyway_a = nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_KEYWAY_A);
+	p->mp_rcp_data_keyway_b = nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_KEYWAY_B);
+	p->mp_rcp_data_synergy_mode =
+		nthw_register_get_field(p->mp_rcp_data, KM_RCP_DATA_SYNERGY_MODE);
+
+	/* CAM */
+	p->mp_cam_ctrl = nthw_module_get_register(p->m_km, KM_CAM_CTRL);
+	p->mp_cam_addr = nthw_register_get_field(p->mp_cam_ctrl, KM_CAM_CTRL_ADR);
+	p->mp_cam_cnt = nthw_register_get_field(p->mp_cam_ctrl, KM_CAM_CTRL_CNT);
+	p->mp_cam_data = nthw_module_get_register(p->m_km, KM_CAM_DATA);
+	p->mp_cam_data_w0 = nthw_register_get_field(p->mp_cam_data, KM_CAM_DATA_W0);
+	p->mp_cam_data_w1 = nthw_register_get_field(p->mp_cam_data, KM_CAM_DATA_W1);
+	p->mp_cam_data_w2 = nthw_register_get_field(p->mp_cam_data, KM_CAM_DATA_W2);
+	p->mp_cam_data_w3 = nthw_register_get_field(p->mp_cam_data, KM_CAM_DATA_W3);
+	p->mp_cam_data_w4 = nthw_register_get_field(p->mp_cam_data, KM_CAM_DATA_W4);
+	p->mp_cam_data_w5 = nthw_register_get_field(p->mp_cam_data, KM_CAM_DATA_W5);
+	p->mp_cam_data_ft0 = nthw_register_get_field(p->mp_cam_data, KM_CAM_DATA_FT0);
+	p->mp_cam_data_ft1 = nthw_register_get_field(p->mp_cam_data, KM_CAM_DATA_FT1);
+	p->mp_cam_data_ft2 = nthw_register_get_field(p->mp_cam_data, KM_CAM_DATA_FT2);
+	p->mp_cam_data_ft3 = nthw_register_get_field(p->mp_cam_data, KM_CAM_DATA_FT3);
+	p->mp_cam_data_ft4 = nthw_register_get_field(p->mp_cam_data, KM_CAM_DATA_FT4);
+	p->mp_cam_data_ft5 = nthw_register_get_field(p->mp_cam_data, KM_CAM_DATA_FT5);
+	/* TCAM */
+	p->mp_tcam_ctrl = nthw_module_get_register(p->m_km, KM_TCAM_CTRL);
+	p->mp_tcam_addr = nthw_register_get_field(p->mp_tcam_ctrl, KM_TCAM_CTRL_ADR);
+	p->mp_tcam_cnt = nthw_register_get_field(p->mp_tcam_ctrl, KM_TCAM_CTRL_CNT);
+	p->mp_tcam_data = nthw_module_get_register(p->m_km, KM_TCAM_DATA);
+	p->mp_tcam_data_t = nthw_register_get_field(p->mp_tcam_data, KM_TCAM_DATA_T);
+	/* TCI */
+	p->mp_tci_ctrl = nthw_module_get_register(p->m_km, KM_TCI_CTRL);
+	p->mp_tci_addr = nthw_register_get_field(p->mp_tci_ctrl, KM_TCI_CTRL_ADR);
+	p->mp_tci_cnt = nthw_register_get_field(p->mp_tci_ctrl, KM_TCI_CTRL_CNT);
+	p->mp_tci_data = nthw_module_get_register(p->m_km, KM_TCI_DATA);
+	p->mp_tci_data_color = nthw_register_get_field(p->mp_tci_data, KM_TCI_DATA_COLOR);
+	p->mp_tci_data_ft = nthw_register_get_field(p->mp_tci_data, KM_TCI_DATA_FT);
+	/* TCQ */
+	p->mp_tcq_ctrl = nthw_module_get_register(p->m_km, KM_TCQ_CTRL);
+	p->mp_tcq_addr = nthw_register_get_field(p->mp_tcq_ctrl, KM_TCQ_CTRL_ADR);
+	p->mp_tcq_cnt = nthw_register_get_field(p->mp_tcq_ctrl, KM_TCQ_CTRL_CNT);
+	p->mp_tcq_data = nthw_module_get_register(p->m_km, KM_TCQ_DATA);
+	p->mp_tcq_data_bank_mask =
+		nthw_register_query_field(p->mp_tcq_data, KM_TCQ_DATA_BANK_MASK);
+	p->mp_tcq_data_qual = nthw_register_get_field(p->mp_tcq_data, KM_TCQ_DATA_QUAL);
+
+	p->mp_rcp_data_dw0_b_dyn =
+		nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW0_B_DYN);
+	p->mp_rcp_data_dw0_b_ofs =
+		nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW0_B_OFS);
+	p->mp_rcp_data_dw2_b_dyn =
+		nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW2_B_DYN);
+	p->mp_rcp_data_dw2_b_ofs =
+		nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW2_B_OFS);
+	p->mp_rcp_data_sw4_b_dyn =
+		nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW4_B_DYN);
+	p->mp_rcp_data_sw4_b_ofs =
+		nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW4_B_OFS);
+	p->mp_rcp_data_sw5_b_dyn =
+		nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW5_B_DYN);
+	p->mp_rcp_data_sw5_b_ofs =
+		nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW5_B_OFS);
+
+	if (!p->mp_rcp_data_dw0_b_dyn) {
+		/* old field defines */
+		p->mp_rcp_data_dw0_b_dyn =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_QW0_B_DYN);
+		p->mp_rcp_data_dw0_b_ofs =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_QW0_B_OFS);
+		p->mp_rcp_data_dw2_b_dyn =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_QW4_B_DYN);
+		p->mp_rcp_data_dw2_b_ofs =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_QW4_B_OFS);
+		p->mp_rcp_data_sw4_b_dyn =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW8_B_DYN);
+		p->mp_rcp_data_sw4_b_ofs =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW8_B_OFS);
+		p->mp_rcp_data_sw5_b_dyn =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW9_B_DYN);
+		p->mp_rcp_data_sw5_b_ofs =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW9_B_OFS);
+	}
+
+	/* v0.6+ */
+	if (p->mp_rcp_data_dw8_dyn) {
+		p->mp_rcp_data_dw8_ofs =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW8_OFS);
+		p->mp_rcp_data_dw8_sel_a =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW8_SEL_A);
+		p->mp_rcp_data_dw8_sel_b =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW8_SEL_B);
+		p->mp_rcp_data_dw10_dyn =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW10_DYN);
+		p->mp_rcp_data_dw10_ofs =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW10_OFS);
+		p->mp_rcp_data_dw10_sel_a =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW10_SEL_A);
+		p->mp_rcp_data_dw10_sel_b =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW10_SEL_B);
+
+	} else if (p->mp_rcp_data_sw8_dyn) {
+		p->mp_rcp_data_sw8_ofs =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW8_OFS);
+		p->mp_rcp_data_sw8_sel_a =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW8_SEL_A);
+		p->mp_rcp_data_sw8_sel_b =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW8_SEL_B);
+		p->mp_rcp_data_sw9_dyn =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW9_DYN);
+		p->mp_rcp_data_sw9_ofs =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW9_OFS);
+		p->mp_rcp_data_sw9_sel_a =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW9_SEL_A);
+		p->mp_rcp_data_sw9_sel_b =
+			nthw_register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW9_SEL_B);
+	}
+
+	return 0;
+}
+
+/* RCP */
+void km_nthw_rcp_select(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_addr, val);
+};
+
+void km_nthw_rcp_cnt(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_cnt, val);
+};
+
+void km_nthw_rcp_qw0_dyn(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw0_dyn, val);
+};
+
+void km_nthw_rcp_qw0_ofs(const struct km_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw0_ofs, val);
+};
+
+void km_nthw_rcp_qw0_sel_a(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw0_sel_a, val);
+};
+
+void km_nthw_rcp_qw0_sel_b(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw0_sel_b, val);
+};
+
+void km_nthw_rcp_qw4_dyn(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw4_dyn, val);
+};
+
+void km_nthw_rcp_qw4_ofs(const struct km_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw4_ofs, val);
+};
+
+void km_nthw_rcp_qw4_sel_a(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw4_sel_a, val);
+};
+
+void km_nthw_rcp_qw4_sel_b(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw4_sel_b, val);
+};
+
+void km_nthw_rcp_dw8_dyn(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_dw8_dyn, val);
+};
+
+void km_nthw_rcp_swx_cch(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_swx_cch, val);
+};
+
+void km_nthw_rcp_dw8_ofs(const struct km_nthw *p, int32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_dw8_ofs, val);
+};
+
+void km_nthw_rcp_dw8_sel_a(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_dw8_sel_a, val);
+};
+
+void km_nthw_rcp_dw8_sel_b(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_dw8_sel_b, val);
+};
+
+void km_nthw_rcp_dw10_dyn(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_dw10_dyn, val);
+};
+
+void km_nthw_rcp_dw10_ofs(const struct km_nthw *p, int32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_dw10_ofs, val);
+};
+
+void km_nthw_rcp_dw10_sel_a(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_dw10_sel_a, val);
+};
+
+void km_nthw_rcp_dw10_sel_b(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_dw10_sel_b, val);
+};
+
+void km_nthw_rcp_swx_sel_a(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_swx_sel_a, val);
+};
+
+void km_nthw_rcp_swx_sel_b(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_swx_sel_b, val);
+};
+
+void km_nthw_rcp_mask_b(const struct km_nthw *p, const uint32_t *val)
+{
+	nthw_field_set_val(p->mp_rcp_data_mask_b, val, p->mp_rcp_data_mask_b->mn_words);
+};
+
+void km_nthw_rcp_mask_da(const struct km_nthw *p, const uint32_t *val)
+{
+	nthw_field_set_val(p->mp_rcp_data_mask_a, val, p->mp_rcp_data_mask_a->mn_words);
+};	/* for DW8/DW10 from v6+ */
+
+void km_nthw_rcp_dual(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_dual, val);
+};
+
+void km_nthw_rcp_paired(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_paired, val);
+};
+
+void km_nthw_rcp_el_a(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_el_a, val);
+};
+
+void km_nthw_rcp_el_b(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_el_b, val);
+};
+
+void km_nthw_rcp_info_a(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_info_a, val);
+};
+
+void km_nthw_rcp_info_b(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_info_b, val);
+};
+
+void km_nthw_rcp_ftm_a(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ftm_a, val);
+};
+
+void km_nthw_rcp_ftm_b(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ftm_b, val);
+};
+
+void km_nthw_rcp_bank_a(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_bank_a, val);
+};
+
+void km_nthw_rcp_bank_b(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_bank_b, val);
+};
+
+void km_nthw_rcp_kl_a(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_kl_a, val);
+};
+
+void km_nthw_rcp_kl_b(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_kl_b, val);
+};
+
+void km_nthw_rcp_keyway_a(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_keyway_a, val);
+};
+
+void km_nthw_rcp_keyway_b(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_keyway_b, val);
+};
+
+void km_nthw_rcp_synergy_mode(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_synergy_mode, val);
+};
+
+void km_nthw_rcp_dw0_b_dyn(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_dw0_b_dyn, val);
+};
+
+void km_nthw_rcp_dw0_b_ofs(const struct km_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_dw0_b_ofs, val);
+};
+
+void km_nthw_rcp_dw2_b_dyn(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_dw2_b_dyn, val);
+};
+
+void km_nthw_rcp_dw2_b_ofs(const struct km_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_dw2_b_ofs, val);
+};
+
+void km_nthw_rcp_sw4_b_dyn(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_sw4_b_dyn, val);
+};
+
+void km_nthw_rcp_sw4_b_ofs(const struct km_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_sw4_b_ofs, val);
+};
+
+void km_nthw_rcp_sw5_b_dyn(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_sw5_b_dyn, val);
+};
+
+void km_nthw_rcp_sw5_b_ofs(const struct km_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_sw5_b_ofs, val);
+};
+
+void km_nthw_rcp_flush(const struct km_nthw *p)
+{
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+};
+
+/* CAM */
+void km_nthw_cam_select(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_addr, val);
+};
+
+void km_nthw_cam_cnt(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_cnt, val);
+};
+
+void km_nthw_cam_w0(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_data_w0, val);
+};
+
+void km_nthw_cam_w1(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_data_w1, val);
+};
+
+void km_nthw_cam_w2(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_data_w2, val);
+};
+
+void km_nthw_cam_w3(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_data_w3, val);
+};
+
+void km_nthw_cam_w4(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_data_w4, val);
+};
+
+void km_nthw_cam_w5(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_data_w5, val);
+};
+
+void km_nthw_cam_ft0(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_data_ft0, val);
+};
+
+void km_nthw_cam_ft1(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_data_ft1, val);
+};
+
+void km_nthw_cam_ft2(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_data_ft2, val);
+};
+
+void km_nthw_cam_ft3(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_data_ft3, val);
+};
+
+void km_nthw_cam_ft4(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_data_ft4, val);
+};
+
+void km_nthw_cam_ft5(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_cam_data_ft5, val);
+};
+
+void km_nthw_cam_flush(const struct km_nthw *p)
+{
+	nthw_register_flush(p->mp_cam_ctrl, 1);
+	nthw_register_flush(p->mp_cam_data, 1);
+};
+
+/* TCAM */
+void km_nthw_tcam_select(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_tcam_addr, val);
+};
+
+void km_nthw_tcam_cnt(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_tcam_cnt, val);
+};
+
+void km_nthw_tcam_t(const struct km_nthw *p, uint32_t *val)
+{
+	nthw_field_set_val(p->mp_tcam_data_t, val, 3);
+};
+
+void km_nthw_tcam_flush(const struct km_nthw *p)
+{
+	nthw_register_flush(p->mp_tcam_ctrl, 1);
+	nthw_register_flush(p->mp_tcam_data, 1);
+};
+
+/* TCI */
+void km_nthw_tci_select(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_tci_addr, val);
+};
+
+void km_nthw_tci_cnt(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_tci_cnt, val);
+};
+
+void km_nthw_tci_color(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_tci_data_color, val);
+};
+
+void km_nthw_tci_ft(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_tci_data_ft, val);
+};
+
+void km_nthw_tci_flush(const struct km_nthw *p)
+{
+	nthw_register_flush(p->mp_tci_ctrl, 1);
+	nthw_register_flush(p->mp_tci_data, 1);
+};
+
+/* TCQ */
+void km_nthw_tcq_select(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_tcq_addr, val);
+};
+
+void km_nthw_tcq_cnt(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_tcq_cnt, val);
+};
+
+void km_nthw_tcq_bank_mask(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_tcq_data_bank_mask, val);
+};
+
+void km_nthw_tcq_qual(const struct km_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_tcq_data_qual, val);
+};
+
+void km_nthw_tcq_flush(const struct km_nthw *p)
+{
+	nthw_register_flush(p->mp_tcq_ctrl, 1);
+	nthw_register_flush(p->mp_tcq_data, 1);
+};
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_km.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_km.h
new file mode 100644
index 0000000000..510aaaae98
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_km.h
@@ -0,0 +1,214 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_KM_H__
+#define __FLOW_NTHW_KM_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct km_nthw;
+
+typedef struct km_nthw km_nthw_t;
+
+struct km_nthw *km_nthw_new(void);
+void km_nthw_delete(struct km_nthw *p);
+int km_nthw_init(struct km_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int km_nthw_setup(struct km_nthw *p, int n_idx, int n_idx_cnt);
+void km_nthw_set_debug_mode(struct km_nthw *p, unsigned int n_debug_mode);
+
+/* RCP initial v3 */
+void km_nthw_rcp_select(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_cnt(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_qw0_dyn(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_qw0_ofs(const struct km_nthw *p, int32_t val);
+void km_nthw_rcp_qw0_sel_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_qw0_sel_b(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_qw4_dyn(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_qw4_ofs(const struct km_nthw *p, int32_t val);
+void km_nthw_rcp_qw4_sel_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_qw4_sel_b(const struct km_nthw *p, uint32_t val);
+/* subst in v6 */
+void km_nthw_rcp_dw8_dyn(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_dw8_ofs(const struct km_nthw *p, int32_t val);
+void km_nthw_rcp_dw8_sel_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_dw8_sel_b(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_dw10_dyn(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_dw10_ofs(const struct km_nthw *p, int32_t val);
+void km_nthw_rcp_dw10_sel_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_dw10_sel_b(const struct km_nthw *p, uint32_t val);
+
+void km_nthw_rcp_swx_cch(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_swx_sel_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_swx_sel_b(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_mask_da(const struct km_nthw *p, const uint32_t *val);
+void km_nthw_rcp_mask_b(const struct km_nthw *p, const uint32_t *val);
+void km_nthw_rcp_dual(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_paired(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_el_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_el_b(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_info_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_info_b(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_ftm_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_ftm_b(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_bank_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_bank_b(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_kl_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_kl_b(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_keyway_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_keyway_b(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_synergy_mode(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_dw0_b_dyn(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_dw0_b_ofs(const struct km_nthw *p, int32_t val);
+void km_nthw_rcp_dw2_b_dyn(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_dw2_b_ofs(const struct km_nthw *p, int32_t val);
+void km_nthw_rcp_sw4_b_dyn(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_sw4_b_ofs(const struct km_nthw *p, int32_t val);
+void km_nthw_rcp_sw5_b_dyn(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_sw5_b_ofs(const struct km_nthw *p, int32_t val);
+void km_nthw_rcp_flush(const struct km_nthw *p);
+/* CAM */
+void km_nthw_cam_select(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_cnt(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_w0(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_w1(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_w2(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_w3(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_w4(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_w5(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_ft0(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_ft1(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_ft2(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_ft3(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_ft4(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_ft5(const struct km_nthw *p, uint32_t val);
+void km_nthw_cam_flush(const struct km_nthw *p);
+/* TCAM */
+void km_nthw_tcam_select(const struct km_nthw *p, uint32_t val);
+void km_nthw_tcam_cnt(const struct km_nthw *p, uint32_t val);
+void km_nthw_tcam_t(const struct km_nthw *p, uint32_t *val);
+void km_nthw_tcam_flush(const struct km_nthw *p);
+/* TCI */
+void km_nthw_tci_select(const struct km_nthw *p, uint32_t val);
+void km_nthw_tci_cnt(const struct km_nthw *p, uint32_t val);
+void km_nthw_tci_color(const struct km_nthw *p, uint32_t val);
+void km_nthw_tci_ft(const struct km_nthw *p, uint32_t val);
+void km_nthw_tci_flush(const struct km_nthw *p);
+/* TCQ */
+void km_nthw_tcq_select(const struct km_nthw *p, uint32_t val);
+void km_nthw_tcq_cnt(const struct km_nthw *p, uint32_t val);
+void km_nthw_tcq_bank_mask(const struct km_nthw *p, uint32_t val);
+void km_nthw_tcq_qual(const struct km_nthw *p, uint32_t val);
+
+void km_nthw_tcq_flush(const struct km_nthw *p);
+
+struct km_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_km;
+
+	nthw_register_t *mp_rcp_ctrl;
+	nthw_field_t *mp_rcp_addr;
+	nthw_field_t *mp_rcp_cnt;
+	nthw_register_t *mp_rcp_data;
+	nthw_field_t *mp_rcp_data_qw0_dyn;
+	nthw_field_t *mp_rcp_data_qw0_ofs;
+	nthw_field_t *mp_rcp_data_qw0_sel_a;
+	nthw_field_t *mp_rcp_data_qw0_sel_b;
+	nthw_field_t *mp_rcp_data_qw4_dyn;
+	nthw_field_t *mp_rcp_data_qw4_ofs;
+	nthw_field_t *mp_rcp_data_qw4_sel_a;
+	nthw_field_t *mp_rcp_data_qw4_sel_b;
+	nthw_field_t *mp_rcp_data_sw8_dyn;
+	nthw_field_t *mp_rcp_data_sw8_ofs;
+	nthw_field_t *mp_rcp_data_sw8_sel_a;
+	nthw_field_t *mp_rcp_data_sw8_sel_b;
+	nthw_field_t *mp_rcp_data_sw9_dyn;
+	nthw_field_t *mp_rcp_data_sw9_ofs;
+	nthw_field_t *mp_rcp_data_sw9_sel_a;
+	nthw_field_t *mp_rcp_data_sw9_sel_b;
+
+	nthw_field_t *mp_rcp_data_dw8_dyn;	/* substituted Sw<x> from v6+ */
+	nthw_field_t *mp_rcp_data_dw8_ofs;	/* substituted Sw<x> from v6+ */
+	nthw_field_t *mp_rcp_data_dw8_sel_a;	/* substituted Sw<x> from v6+ */
+	nthw_field_t *mp_rcp_data_dw8_sel_b;	/* substituted Sw<x> from v6+ */
+	nthw_field_t *mp_rcp_data_dw10_dyn;	/* substituted Sw<x> from v6+ */
+	nthw_field_t *mp_rcp_data_dw10_ofs;	/* substituted Sw<x> from v6+ */
+	nthw_field_t *mp_rcp_data_dw10_sel_a;	/* substituted Sw<x> from v6+ */
+	nthw_field_t *mp_rcp_data_dw10_sel_b;	/* substituted Sw<x> from v6+ */
+
+	nthw_field_t *mp_rcp_data_swx_ovs_sb;
+	nthw_field_t *mp_rcp_data_swx_cch;
+	nthw_field_t *mp_rcp_data_swx_sel_a;
+	nthw_field_t *mp_rcp_data_swx_sel_b;
+	nthw_field_t *mp_rcp_data_mask_a;
+	nthw_field_t *mp_rcp_data_mask_b;
+	nthw_field_t *mp_rcp_data_dual;
+	nthw_field_t *mp_rcp_data_paired;
+	nthw_field_t *mp_rcp_data_el_a;
+	nthw_field_t *mp_rcp_data_el_b;
+	nthw_field_t *mp_rcp_data_info_a;
+	nthw_field_t *mp_rcp_data_info_b;
+	nthw_field_t *mp_rcp_data_ftm_a;
+	nthw_field_t *mp_rcp_data_ftm_b;
+	nthw_field_t *mp_rcp_data_bank_a;
+	nthw_field_t *mp_rcp_data_bank_b;
+	nthw_field_t *mp_rcp_data_kl_a;
+	nthw_field_t *mp_rcp_data_kl_b;
+	nthw_field_t *mp_rcp_data_flow_set;
+	nthw_field_t *mp_rcp_data_keyway_a;
+	nthw_field_t *mp_rcp_data_keyway_b;
+	nthw_field_t *mp_rcp_data_synergy_mode;
+	nthw_field_t *mp_rcp_data_dw0_b_dyn;
+	nthw_field_t *mp_rcp_data_dw0_b_ofs;
+	nthw_field_t *mp_rcp_data_dw2_b_dyn;
+	nthw_field_t *mp_rcp_data_dw2_b_ofs;
+	nthw_field_t *mp_rcp_data_sw4_b_dyn;
+	nthw_field_t *mp_rcp_data_sw4_b_ofs;
+	nthw_field_t *mp_rcp_data_sw5_b_dyn;
+	nthw_field_t *mp_rcp_data_sw5_b_ofs;
+
+	nthw_register_t *mp_cam_ctrl;
+	nthw_field_t *mp_cam_addr;
+	nthw_field_t *mp_cam_cnt;
+	nthw_register_t *mp_cam_data;
+	nthw_field_t *mp_cam_data_w0;
+	nthw_field_t *mp_cam_data_w1;
+	nthw_field_t *mp_cam_data_w2;
+	nthw_field_t *mp_cam_data_w3;
+	nthw_field_t *mp_cam_data_w4;
+	nthw_field_t *mp_cam_data_w5;
+	nthw_field_t *mp_cam_data_ft0;
+	nthw_field_t *mp_cam_data_ft1;
+	nthw_field_t *mp_cam_data_ft2;
+	nthw_field_t *mp_cam_data_ft3;
+	nthw_field_t *mp_cam_data_ft4;
+	nthw_field_t *mp_cam_data_ft5;
+
+	nthw_register_t *mp_tcam_ctrl;
+	nthw_field_t *mp_tcam_addr;
+	nthw_field_t *mp_tcam_cnt;
+	nthw_register_t *mp_tcam_data;
+	nthw_field_t *mp_tcam_data_t;
+
+	nthw_register_t *mp_tci_ctrl;
+	nthw_field_t *mp_tci_addr;
+	nthw_field_t *mp_tci_cnt;
+	nthw_register_t *mp_tci_data;
+	nthw_field_t *mp_tci_data_color;
+	nthw_field_t *mp_tci_data_ft;
+
+	nthw_register_t *mp_tcq_ctrl;
+	nthw_field_t *mp_tcq_addr;
+	nthw_field_t *mp_tcq_cnt;
+	nthw_register_t *mp_tcq_data;
+	nthw_field_t *mp_tcq_data_bank_mask;
+	nthw_field_t *mp_tcq_data_qual;
+};
+
+#endif	/* __FLOW_NTHW_KM_H__ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index d4ccc5157d..7d48e4012e 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -21,6 +21,7 @@
 #define MOD_HIF (0x7815363UL)
 #define MOD_I2CM (0x93bc7780UL)
 #define MOD_IIC (0x7629cddbUL)
+#define MOD_KM (0xcfbd9dbeUL)
 #define MOD_MAC_PCS (0x7abe24c7UL)
 #define MOD_PCIE3 (0xfbc48c18UL)
 #define MOD_PCI_RD_TG (0x9ad9eed2UL)
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index dad498256f..96676bf8d4 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -20,6 +20,7 @@
 #include "nthw_fpga_reg_defs_hif.h"
 #include "nthw_fpga_reg_defs_i2cm.h"
 #include "nthw_fpga_reg_defs_iic.h"
+#include "nthw_fpga_reg_defs_km.h"
 #include "nthw_fpga_reg_defs_mac_pcs.h"
 #include "nthw_fpga_reg_defs_pcie3.h"
 #include "nthw_fpga_reg_defs_pci_rd_tg.h"
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_km.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_km.h
new file mode 100644
index 0000000000..03273dced0
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_km.h
@@ -0,0 +1,126 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_km.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_KM_
+#define _NTHW_FPGA_REG_DEFS_KM_
+
+/* KM */
+#define NTHW_MOD_KM (0xcfbd9dbeUL)
+#define KM_CAM_CTRL (0x601dcc08UL)
+#define KM_CAM_CTRL_ADR (0xee5e10b0UL)
+#define KM_CAM_CTRL_CNT (0xfe568961UL)
+#define KM_CAM_DATA (0xcfcc4e11UL)
+#define KM_CAM_DATA_FT0 (0x138589ccUL)
+#define KM_CAM_DATA_FT1 (0x6482b95aUL)
+#define KM_CAM_DATA_FT2 (0xfd8be8e0UL)
+#define KM_CAM_DATA_FT3 (0x8a8cd876UL)
+#define KM_CAM_DATA_FT4 (0x14e84dd5UL)
+#define KM_CAM_DATA_FT5 (0x63ef7d43UL)
+#define KM_CAM_DATA_W0 (0xff7d6c5fUL)
+#define KM_CAM_DATA_W1 (0x887a5cc9UL)
+#define KM_CAM_DATA_W2 (0x11730d73UL)
+#define KM_CAM_DATA_W3 (0x66743de5UL)
+#define KM_CAM_DATA_W4 (0xf810a846UL)
+#define KM_CAM_DATA_W5 (0x8f1798d0UL)
+#define KM_RCP_CTRL (0xf8dbfdd1UL)
+#define KM_RCP_CTRL_ADR (0xf3df02baUL)
+#define KM_RCP_CTRL_CNT (0xe3d79b6bUL)
+#define KM_RCP_DATA (0x570a7fc8UL)
+#define KM_RCP_DATA_BANK_A (0x7fd7bd1UL)
+#define KM_RCP_DATA_BANK_B (0x9ef42a6bUL)
+#define KM_RCP_DATA_DUAL (0x428e6b23UL)
+#define KM_RCP_DATA_DW0_B_DYN (0x342bde5aUL)
+#define KM_RCP_DATA_DW0_B_OFS (0x962253fcUL)
+#define KM_RCP_DATA_DW10_DYN (0x54eccf30UL)
+#define KM_RCP_DATA_DW10_OFS (0xf6e54296UL)
+#define KM_RCP_DATA_DW10_SEL_A (0x6237e887UL)
+#define KM_RCP_DATA_DW10_SEL_B (0xfb3eb93dUL)
+#define KM_RCP_DATA_DW2_B_DYN (0xa3b4cf73UL)
+#define KM_RCP_DATA_DW2_B_OFS (0x1bd42d5UL)
+#define KM_RCP_DATA_DW8_B_DYN (0x7c4903dUL)
+#define KM_RCP_DATA_DW8_B_OFS (0xa5cd1d9bUL)
+#define KM_RCP_DATA_DW8_DYN (0x3f6b49f0UL)
+#define KM_RCP_DATA_DW8_OFS (0x9d62c456UL)
+#define KM_RCP_DATA_DW8_SEL_A (0xad16725bUL)
+#define KM_RCP_DATA_DW8_SEL_B (0x341f23e1UL)
+#define KM_RCP_DATA_EL_A (0x4335d7dbUL)
+#define KM_RCP_DATA_EL_B (0xda3c8661UL)
+#define KM_RCP_DATA_FLOW_SET (0x6b56d647UL)
+#define KM_RCP_DATA_FTM_A (0xdb75ed61UL)
+#define KM_RCP_DATA_FTM_B (0x427cbcdbUL)
+#define KM_RCP_DATA_INFO_A (0x2dd79cf0UL)
+#define KM_RCP_DATA_INFO_B (0xb4decd4aUL)
+#define KM_RCP_DATA_KEYWAY_A (0xd0e5dc89UL)
+#define KM_RCP_DATA_KEYWAY_B (0x49ec8d33UL)
+#define KM_RCP_DATA_KL_A (0xa3eaa0e8UL)
+#define KM_RCP_DATA_KL_B (0x3ae3f152UL)
+#define KM_RCP_DATA_MASK_A (0x54d84646UL)
+#define KM_RCP_DATA_MASK_B (0xcdd117fcUL)
+#define KM_RCP_DATA_PAIRED (0x7847653UL)
+#define KM_RCP_DATA_QW0_B_DYN (0xd27cd964UL)
+#define KM_RCP_DATA_QW0_B_OFS (0x707554c2UL)
+#define KM_RCP_DATA_QW0_DYN (0x3afdb158UL)
+#define KM_RCP_DATA_QW0_OFS (0x98f43cfeUL)
+#define KM_RCP_DATA_QW0_SEL_A (0x78ae3b02UL)
+#define KM_RCP_DATA_QW0_SEL_B (0xe1a76ab8UL)
+#define KM_RCP_DATA_QW4_B_DYN (0x2633fd77UL)
+#define KM_RCP_DATA_QW4_B_OFS (0x843a70d1UL)
+#define KM_RCP_DATA_QW4_DYN (0xcf7d1798UL)
+#define KM_RCP_DATA_QW4_OFS (0x6d749a3eUL)
+#define KM_RCP_DATA_QW4_SEL_A (0x8ce11f11UL)
+#define KM_RCP_DATA_QW4_SEL_B (0x15e84eabUL)
+#define KM_RCP_DATA_SW4_B_DYN (0x8c5d5f1UL)
+#define KM_RCP_DATA_SW4_B_OFS (0xaacc5857UL)
+#define KM_RCP_DATA_SW5_B_DYN (0xaeb2de45UL)
+#define KM_RCP_DATA_SW5_B_OFS (0xcbb53e3UL)
+#define KM_RCP_DATA_SW8_B_DYN (0xcf65bf85UL)
+#define KM_RCP_DATA_SW8_B_OFS (0x6d6c3223UL)
+#define KM_RCP_DATA_SW8_DYN (0x9d12ebb0UL)
+#define KM_RCP_DATA_SW8_OFS (0x3f1b6616UL)
+#define KM_RCP_DATA_SW8_SEL_A (0x65b75de3UL)
+#define KM_RCP_DATA_SW8_SEL_B (0xfcbe0c59UL)
+#define KM_RCP_DATA_SW9_B_DYN (0x6912b431UL)
+#define KM_RCP_DATA_SW9_B_OFS (0xcb1b3997UL)
+#define KM_RCP_DATA_SW9_DYN (0xa072c200UL)
+#define KM_RCP_DATA_SW9_OFS (0x27b4fa6UL)
+#define KM_RCP_DATA_SW9_SEL_A (0xc3c05657UL)
+#define KM_RCP_DATA_SW9_SEL_B (0x5ac907edUL)
+#define KM_RCP_DATA_SWX_CCH (0x5821d596UL)
+#define KM_RCP_DATA_SWX_OVS_SB (0x808773bdUL)
+#define KM_RCP_DATA_SWX_SEL_A (0xee011106UL)
+#define KM_RCP_DATA_SWX_SEL_B (0x770840bcUL)
+#define KM_RCP_DATA_SYNERGY_MODE (0x35a76c4aUL)
+#define KM_STATUS (0x2f1f9d13UL)
+#define KM_STATUS_TCQ_RDY (0x653553c4UL)
+#define KM_TCAM_CTRL (0x18fbc021UL)
+#define KM_TCAM_CTRL_ADR (0x6c84a404UL)
+#define KM_TCAM_CTRL_CNT (0x7c8c3dd5UL)
+#define KM_TCAM_DATA (0xb72a4238UL)
+#define KM_TCAM_DATA_T (0xa995a553UL)
+#define KM_TCI_CTRL (0x1a6da705UL)
+#define KM_TCI_CTRL_ADR (0xc7590d78UL)
+#define KM_TCI_CTRL_CNT (0xd75194a9UL)
+#define KM_TCI_DATA (0xb5bc251cUL)
+#define KM_TCI_DATA_COLOR (0x324017ecUL)
+#define KM_TCI_DATA_FT (0x38afba77UL)
+#define KM_TCQ_CTRL (0xf5e827f3UL)
+#define KM_TCQ_CTRL_ADR (0xf320cc64UL)
+#define KM_TCQ_CTRL_CNT (0xe32855b5UL)
+#define KM_TCQ_DATA (0x5a39a5eaUL)
+#define KM_TCQ_DATA_BANK_MASK (0x97cf4b5aUL)
+#define KM_TCQ_DATA_QUAL (0x4422cc93UL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_KM_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 08/31] net/ntnic: add flow matcher (FLM) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (12 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 07/31] net/ntnic: add key match (KM) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 09/31] net/ntnic: add IP fragmenter (IFR) " Serhii Iliushyk
                   ` (37 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Flow Matcher module is a high-performance stateful SDRAM lookup
and programming engine which supported exact match lookup
in line-rate of up to hundreds of millions of flows.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    |   40 +
 drivers/net/ntnic/include/hw_mod_flm_v25.h    |  342 +++++
 drivers/net/ntnic/meson.build                 |    1 +
 .../nthw/flow_api/flow_backend/flow_backend.c |  378 +++++
 .../ntnic/nthw/flow_filter/flow_nthw_flm.c    | 1225 +++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_flm.h    |  433 ++++++
 drivers/net/ntnic/nthw/nthw_rac.c             |  181 +++
 drivers/net/ntnic/nthw/nthw_rac.h             |    9 +
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |    1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |    1 +
 .../nthw/supported/nthw_fpga_reg_defs_flm.h   |  242 ++++
 drivers/net/ntnic/ntutil/nt_util.c            |    6 +
 drivers/net/ntnic/ntutil/nt_util.h            |    1 +
 13 files changed, 2860 insertions(+)
 create mode 100644 drivers/net/ntnic/include/hw_mod_flm_v25.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_flm.h

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index b921c06643..133a61fe9c 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -10,6 +10,7 @@
 
 #include "hw_mod_cat_v18.h"
 #include "hw_mod_cat_v21.h"
+#include "hw_mod_flm_v25.h"
 #include "hw_mod_km_v7.h"
 
 #define MAX_PHYS_ADAPTERS 8
@@ -58,6 +59,22 @@ struct km_func_s {
 	};
 };
 
+struct flm_func_s {
+	COMMON_FUNC_INFO_S;
+	uint32_t nb_categories;
+	uint32_t nb_size_mb;
+	uint32_t nb_entry_size;
+	uint32_t nb_variant;
+	uint32_t nb_prios;
+	uint32_t nb_pst_profiles;
+	uint32_t nb_scrub_profiles;
+	uint32_t nb_rpp_clock_in_ps;
+	uint32_t nb_load_aps_max;
+	union {
+		struct hw_mod_flm_v25_s v25;
+	};
+};
+
 enum debug_mode_e {
 	FLOW_BACKEND_DEBUG_MODE_NONE = 0x0000,
 	FLOW_BACKEND_DEBUG_MODE_WRITE = 0x0001
@@ -140,6 +157,29 @@ struct flow_api_backend_ops {
 		int cnt);
 	int (*km_tci_flush)(void *dev, const struct km_func_s *km, int bank, int record, int cnt);
 	int (*km_tcq_flush)(void *dev, const struct km_func_s *km, int bank, int record, int cnt);
+
+	/* FLM */
+	bool (*get_flm_present)(void *dev);
+	uint32_t (*get_flm_version)(void *dev);
+	int (*flm_control_flush)(void *dev, const struct flm_func_s *flm);
+	int (*flm_status_flush)(void *dev, const struct flm_func_s *flm);
+	int (*flm_status_update)(void *dev, const struct flm_func_s *flm);
+	int (*flm_scan_flush)(void *dev, const struct flm_func_s *flm);
+	int (*flm_load_bin_flush)(void *dev, const struct flm_func_s *flm);
+	int (*flm_prio_flush)(void *dev, const struct flm_func_s *flm);
+	int (*flm_pst_flush)(void *dev, const struct flm_func_s *flm, int index, int cnt);
+	int (*flm_rcp_flush)(void *dev, const struct flm_func_s *flm, int index, int cnt);
+	int (*flm_scrub_flush)(void *dev, const struct flm_func_s *flm, int index, int cnt);
+	int (*flm_buf_ctrl_update)(void *dev, const struct flm_func_s *flm);
+	int (*flm_stat_update)(void *dev, const struct flm_func_s *flm);
+	int (*flm_lrn_data_flush)(void *be_dev, const struct flm_func_s *flm,
+		const uint32_t *lrn_data, uint32_t records,
+		uint32_t *handled_records, uint32_t words_per_record,
+		uint32_t *inf_word_cnt, uint32_t *sta_word_cnt);
+	int (*flm_inf_sta_data_update)(void *be_dev, const struct flm_func_s *flm,
+		uint32_t *inf_data, uint32_t inf_size,
+		uint32_t *inf_word_cnt, uint32_t *sta_data,
+		uint32_t sta_size, uint32_t *sta_word_cnt);
 };
 
 struct flow_api_backend_s {
diff --git a/drivers/net/ntnic/include/hw_mod_flm_v25.h b/drivers/net/ntnic/include/hw_mod_flm_v25.h
new file mode 100644
index 0000000000..12135a652c
--- /dev/null
+++ b/drivers/net/ntnic/include/hw_mod_flm_v25.h
@@ -0,0 +1,342 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+#ifndef _HW_MOD_FLM_V25_H_
+#define _HW_MOD_FLM_V25_H_
+
+#include <stdint.h>
+
+/* SCRUB record constraints */
+#define SCRUB_T_MAX 0xEF/* MAX encoded timeout value, approx. 127 years */
+#define SCRUB_DEL                                                                                 \
+	0	/* Indicates if flow should be deleted upon timeout. If DEL=0 then the flow is \
+		 * marked as aged rather than being deleted. \
+		 */
+#define SCRUB_INF                                                                                 \
+	1	/* Indicates if a flow info record should be generated upon timeout. \
+		 * If INF=1 a flow info record will be generated even for a stateless flow. \
+		 */
+
+struct flm_v25_control_s {
+	uint32_t enable;
+	uint32_t init;
+	uint32_t lds;
+	uint32_t lfs;
+	uint32_t lis;
+	uint32_t uds;
+	uint32_t uis;
+	uint32_t rds;
+	uint32_t ris;
+	uint32_t pds;
+	uint32_t pis;
+	uint32_t crcwr;
+	uint32_t crcrd;
+	uint32_t rbl;
+	uint32_t eab;
+	uint32_t split_sdram_usage;
+};
+
+struct flm_v25_status_s {
+	uint32_t calib_success;
+	uint32_t calib_fail;
+	uint32_t initdone;
+	uint32_t idle;
+	uint32_t critical;
+	uint32_t panic;
+	uint32_t crcerr;
+	uint32_t eft_bp;
+	uint32_t cache_buf_critical;
+};
+
+struct flm_v25_load_bin_s {
+	uint32_t bin;
+};
+
+struct flm_v25_load_pps_s {
+	uint32_t pps;
+};
+
+struct flm_v25_load_lps_s {
+	uint32_t lps;
+};
+
+struct flm_v25_load_aps_s {
+	uint32_t aps;
+};
+
+struct flm_v25_prio_s {
+	uint32_t limit0;
+	uint32_t ft0;
+	uint32_t limit1;
+	uint32_t ft1;
+	uint32_t limit2;
+	uint32_t ft2;
+	uint32_t limit3;
+	uint32_t ft3;
+};
+
+struct flm_v25_pst_s {
+	uint32_t bp;
+	uint32_t pp;
+	uint32_t tp;
+};
+
+struct flm_v25_rcp_s {
+	uint32_t lookup;
+	uint32_t qw0_dyn;
+	uint32_t qw0_ofs;
+	uint32_t qw0_sel;
+	uint32_t qw4_dyn;
+	uint32_t qw4_ofs;
+	uint32_t sw8_dyn;
+	uint32_t sw8_ofs;
+	uint32_t sw8_sel;
+	uint32_t sw9_dyn;
+	uint32_t sw9_ofs;
+	uint32_t mask[10];
+	uint32_t kid;
+	uint32_t opn;
+	uint32_t ipn;
+	uint32_t byt_dyn;
+	uint32_t byt_ofs;
+	uint32_t txplm;
+	uint32_t auto_ipv4_mask;
+};
+
+struct flm_v25_buf_ctrl_s {
+	uint32_t lrn_free;
+	uint32_t inf_avail;
+	uint32_t sta_avail;
+};
+
+struct flm_v25_stat_lrn_done_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_lrn_ignore_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_lrn_fail_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_unl_done_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_unl_ignore_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_rel_done_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_rel_ignore_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_aul_done_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_aul_ignore_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_aul_fail_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_tul_done_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_flows_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_prb_done_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_prb_ignore_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_sta_done_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_inf_done_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_inf_skip_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_pck_hit_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_pck_miss_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_pck_unh_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_pck_dis_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_csh_hit_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_csh_miss_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_csh_unh_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_cuc_start_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_stat_cuc_move_s {
+	uint32_t cnt;
+};
+
+struct flm_v25_scan_s {
+	uint32_t i;
+};
+
+struct flm_v25_scrub_s {
+	uint8_t t;
+	uint8_t r;
+	uint8_t del;
+	uint8_t inf;
+};
+
+#pragma pack(1)
+struct flm_v25_lrn_data_s {
+	uint32_t sw9;	/* 31:0 (32) */
+	uint32_t sw8;	/* 63:32 (32) */
+	uint32_t qw4[4];/* 191:64 (128) */
+	uint32_t qw0[4];/* 319:192 (128) */
+	uint8_t prot;	/* 327:320 (8) */
+	uint8_t kid;	/* 335:328 (8) */
+	uint32_t nat_ip;/* 367:336 (32) */
+	uint32_t teid;	/* 399:368 (32) */
+	uint16_t nat_port;	/* 415:400 (16) */
+	uint16_t rate;	/* 431:416 (16) */
+	uint16_t size;	/* 447:432 (16) */
+	uint32_t color;	/* 479:448 (32) */
+	uint32_t adj;	/* 511:480 (32) */
+	uint32_t id;	/* 543:512 (32) */
+	uint16_t fill;	/* 559:544 (16) */
+
+	/*
+	 * Bit fields
+	 */
+	uint64_t ft : 4;/* 563:560 (4) */
+	uint64_t ft_mbr : 4;	/* 567:564 (4) */
+	uint64_t ft_miss : 4;	/* 571:568 (4) */
+	uint64_t mbr_idx1 : 28;	/* 599:572 (28) */
+	uint64_t mbr_idx2 : 28;	/* 627:600 (28) */
+	uint64_t mbr_idx3 : 28;	/* 655:628 (28) */
+	uint64_t mbr_idx4 : 28;	/* 683:656 (28) */
+	uint64_t vol_idx : 3;	/* 686:684 (3) */
+	uint64_t stat_prof : 4;	/* 690:687 (4) */
+	uint64_t prio : 2;	/* 692:691 (2) */
+	uint64_t ent : 1;	/* 693:693 (1) */
+	uint64_t op : 4;/* 697:694 (4) */
+	uint64_t dscp : 6;	/* 703:698 (6) */
+	uint64_t qfi : 6;	/* 709:704 (6) */
+	uint64_t rqi : 1;	/* 710:710 (1) */
+	uint64_t nat_en : 1;	/* 711:711 (1) */
+	uint64_t scrub_prof : 4;/* 715:712 (4) */
+	uint64_t nofi : 1;	/* 716:716 (1) */
+	uint64_t pad : 50;	/* 766:717 (50) */
+	uint64_t eor : 1;	/* 767:767 (1) */
+};
+
+struct flm_v25_inf_data_s {
+	uint64_t bytes;
+	uint64_t packets;
+	uint64_t ts;
+	uint32_t id;
+	uint64_t cause : 3;
+	uint64_t pad : 60;
+	uint64_t eor : 1;
+};
+
+struct flm_v25_sta_data_s {
+	uint32_t id;
+	uint64_t lds : 1;
+	uint64_t lfs : 1;
+	uint64_t lis : 1;
+	uint64_t uds : 1;
+	uint64_t uis : 1;
+	uint64_t rds : 1;
+	uint64_t ris : 1;
+	uint64_t pds : 1;
+	uint64_t pis : 1;
+	uint64_t pad : 54;
+	uint64_t eor : 1;
+};
+#pragma pack()
+
+struct hw_mod_flm_v25_s {
+	struct flm_v25_control_s *control;
+	struct flm_v25_status_s *status;
+	struct flm_v25_load_bin_s *load_bin;
+	struct flm_v25_load_pps_s *load_pps;
+	struct flm_v25_load_lps_s *load_lps;
+	struct flm_v25_load_aps_s *load_aps;
+	struct flm_v25_prio_s *prio;
+	struct flm_v25_pst_s *pst;
+	struct flm_v25_rcp_s *rcp;
+	struct flm_v25_buf_ctrl_s *buf_ctrl;
+	/* lrn_data is not handled by struct */
+	/* inf_data is not handled by struct */
+	/* sta_data is not handled by struct */
+	struct flm_v25_stat_lrn_done_s *lrn_done;
+	struct flm_v25_stat_lrn_ignore_s *lrn_ignore;
+	struct flm_v25_stat_lrn_fail_s *lrn_fail;
+	struct flm_v25_stat_unl_done_s *unl_done;
+	struct flm_v25_stat_unl_ignore_s *unl_ignore;
+	struct flm_v25_stat_rel_done_s *rel_done;
+	struct flm_v25_stat_rel_ignore_s *rel_ignore;
+	struct flm_v25_stat_aul_done_s *aul_done;
+	struct flm_v25_stat_aul_ignore_s *aul_ignore;
+	struct flm_v25_stat_aul_fail_s *aul_fail;
+	struct flm_v25_stat_tul_done_s *tul_done;
+	struct flm_v25_stat_flows_s *flows;
+	struct flm_v25_stat_prb_done_s *prb_done;
+	struct flm_v25_stat_prb_ignore_s *prb_ignore;
+	struct flm_v25_stat_sta_done_s *sta_done;
+	struct flm_v25_stat_inf_done_s *inf_done;
+	struct flm_v25_stat_inf_skip_s *inf_skip;
+	struct flm_v25_stat_pck_hit_s *pck_hit;
+	struct flm_v25_stat_pck_miss_s *pck_miss;
+	struct flm_v25_stat_pck_unh_s *pck_unh;
+	struct flm_v25_stat_pck_dis_s *pck_dis;
+	struct flm_v25_stat_csh_hit_s *csh_hit;
+	struct flm_v25_stat_csh_miss_s *csh_miss;
+	struct flm_v25_stat_csh_unh_s *csh_unh;
+	struct flm_v25_stat_cuc_start_s *cuc_start;
+	struct flm_v25_stat_cuc_move_s *cuc_move;
+	struct flm_v25_scan_s *scan;
+	struct flm_v25_scrub_s *scrub;
+};
+
+#endif	/* _HW_MOD_FLM_V25_H_ */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 8d297cbb61..317b696d5f 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -47,6 +47,7 @@ sources = files(
         'nthw/flow_api/flow_backend/flow_backend.c',
         'nthw/flow_api/flow_filter.c',
         'nthw/flow_filter/flow_nthw_cat.c',
+        'nthw/flow_filter/flow_nthw_flm.c',
         'nthw/flow_filter/flow_nthw_info.c',
         'nthw/flow_filter/flow_nthw_km.c',
         'nthw/model/nthw_fpga_model.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index c004000cc0..8703a4c712 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -8,6 +8,7 @@
 #include "flow_nthw_info.h"
 #include "flow_nthw_cat.h"
 #include "flow_nthw_km.h"
+#include "flow_nthw_flm.h"
 #include "ntnic_mod_reg.h"
 #include "nthw_fpga_model.h"
 #include "hw_mod_backend.h"
@@ -25,6 +26,7 @@ static struct backend_dev_s {
 	struct info_nthw *p_info_nthw;
 	struct cat_nthw *p_cat_nthw;
 	struct km_nthw *p_km_nthw;
+	struct flm_nthw *p_flm_nthw;
 } be_devs[MAX_PHYS_ADAPTERS];
 
 #define CHECK_DEBUG_ON(be, mod, inst)                                                             \
@@ -907,6 +909,355 @@ static int km_tcq_flush(void *be_dev, const struct km_func_s *km, int bank, int
 	return 0;
 }
 
+/*
+ * FLM
+ */
+
+static bool flm_get_present(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return be->p_flm_nthw != NULL;
+}
+
+static uint32_t flm_get_version(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return (uint32_t)((nthw_module_get_major_version(be->p_flm_nthw->m_flm) << 16) |
+			(nthw_module_get_minor_version(be->p_flm_nthw->m_flm) & 0xffff));
+}
+
+static int flm_control_flush(void *be_dev, const struct flm_func_s *flm)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	if (flm->ver >= 25) {
+		flm_nthw_control_enable(be->p_flm_nthw, flm->v25.control->enable);
+		flm_nthw_control_init(be->p_flm_nthw, flm->v25.control->init);
+		flm_nthw_control_lds(be->p_flm_nthw, flm->v25.control->lds);
+		flm_nthw_control_lfs(be->p_flm_nthw, flm->v25.control->lfs);
+		flm_nthw_control_lis(be->p_flm_nthw, flm->v25.control->lis);
+		flm_nthw_control_uds(be->p_flm_nthw, flm->v25.control->uds);
+		flm_nthw_control_uis(be->p_flm_nthw, flm->v25.control->uis);
+		flm_nthw_control_rds(be->p_flm_nthw, flm->v25.control->rds);
+		flm_nthw_control_ris(be->p_flm_nthw, flm->v25.control->ris);
+		flm_nthw_control_pds(be->p_flm_nthw, flm->v25.control->pds);
+		flm_nthw_control_pis(be->p_flm_nthw, flm->v25.control->pis);
+		flm_nthw_control_crcwr(be->p_flm_nthw, flm->v25.control->crcwr);
+		flm_nthw_control_crcrd(be->p_flm_nthw, flm->v25.control->crcrd);
+		flm_nthw_control_rbl(be->p_flm_nthw, flm->v25.control->rbl);
+		flm_nthw_control_eab(be->p_flm_nthw, flm->v25.control->eab);
+		flm_nthw_control_split_sdram_usage(be->p_flm_nthw,
+			flm->v25.control->split_sdram_usage);
+		flm_nthw_control_flush(be->p_flm_nthw);
+	}
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return 0;
+}
+
+static int flm_status_flush(void *be_dev, const struct flm_func_s *flm)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	if (flm->ver >= 25) {
+		/* CALIBDONE, INITDONE, IDLE, and EFT_BP is read only */
+		flm_nthw_status_critical(be->p_flm_nthw, &flm->v25.status->critical, 0);
+		flm_nthw_status_panic(be->p_flm_nthw, &flm->v25.status->panic, 0);
+		flm_nthw_status_crcerr(be->p_flm_nthw, &flm->v25.status->crcerr, 0);
+		flm_nthw_status_cache_buf_crit(be->p_flm_nthw,
+			&flm->v25.status->cache_buf_critical, 0);
+		flm_nthw_status_flush(be->p_flm_nthw);
+	}
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return 0;
+}
+
+static int flm_status_update(void *be_dev, const struct flm_func_s *flm)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	if (flm->ver >= 25) {
+		flm_nthw_status_update(be->p_flm_nthw);
+		flm_nthw_status_calib_success(be->p_flm_nthw, &flm->v25.status->calib_success, 1);
+		flm_nthw_status_calib_fail(be->p_flm_nthw, &flm->v25.status->calib_fail, 1);
+		flm_nthw_status_initdone(be->p_flm_nthw, &flm->v25.status->initdone, 1);
+		flm_nthw_status_idle(be->p_flm_nthw, &flm->v25.status->idle, 1);
+		flm_nthw_status_critical(be->p_flm_nthw, &flm->v25.status->critical, 1);
+		flm_nthw_status_panic(be->p_flm_nthw, &flm->v25.status->panic, 1);
+		flm_nthw_status_crcerr(be->p_flm_nthw, &flm->v25.status->crcerr, 1);
+		flm_nthw_status_eft_bp(be->p_flm_nthw, &flm->v25.status->eft_bp, 1);
+		flm_nthw_status_cache_buf_crit(be->p_flm_nthw,
+			&flm->v25.status->cache_buf_critical, 1);
+	}
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return 0;
+}
+
+static int flm_scan_flush(void *be_dev, const struct flm_func_s *flm)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	if (flm->ver >= 25) {
+		flm_nthw_scan_i(be->p_flm_nthw, flm->v25.scan->i);
+		flm_nthw_scan_flush(be->p_flm_nthw);
+	}
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return 0;
+}
+
+static int flm_load_bin_flush(void *be_dev, const struct flm_func_s *flm)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	if (flm->ver >= 25) {
+		flm_nthw_load_bin(be->p_flm_nthw, flm->v25.load_bin->bin);
+		flm_nthw_load_bin_flush(be->p_flm_nthw);
+	}
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return 0;
+}
+
+static int flm_prio_flush(void *be_dev, const struct flm_func_s *flm)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	if (flm->ver >= 25) {
+		flm_nthw_prio_limit0(be->p_flm_nthw, flm->v25.prio->limit0);
+		flm_nthw_prio_ft0(be->p_flm_nthw, flm->v25.prio->ft0);
+		flm_nthw_prio_limit1(be->p_flm_nthw, flm->v25.prio->limit1);
+		flm_nthw_prio_ft1(be->p_flm_nthw, flm->v25.prio->ft1);
+		flm_nthw_prio_limit2(be->p_flm_nthw, flm->v25.prio->limit2);
+		flm_nthw_prio_ft2(be->p_flm_nthw, flm->v25.prio->ft2);
+		flm_nthw_prio_limit3(be->p_flm_nthw, flm->v25.prio->limit3);
+		flm_nthw_prio_ft3(be->p_flm_nthw, flm->v25.prio->ft3);
+		flm_nthw_prio_flush(be->p_flm_nthw);
+	}
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return 0;
+}
+
+static int flm_pst_flush(void *be_dev, const struct flm_func_s *flm, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	if (flm->ver >= 25) {
+		flm_nthw_pst_cnt(be->p_flm_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			flm_nthw_pst_select(be->p_flm_nthw, index + i);
+			flm_nthw_pst_bp(be->p_flm_nthw, flm->v25.pst[index + i].bp);
+			flm_nthw_pst_pp(be->p_flm_nthw, flm->v25.pst[index + i].pp);
+			flm_nthw_pst_tp(be->p_flm_nthw, flm->v25.pst[index + i].tp);
+			flm_nthw_pst_flush(be->p_flm_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return 0;
+}
+
+static int flm_rcp_flush(void *be_dev, const struct flm_func_s *flm, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	if (flm->ver >= 25) {
+		flm_nthw_rcp_cnt(be->p_flm_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			flm_nthw_rcp_select(be->p_flm_nthw, index + i);
+			flm_nthw_rcp_lookup(be->p_flm_nthw, flm->v25.rcp[index + i].lookup);
+			flm_nthw_rcp_qw0_dyn(be->p_flm_nthw, flm->v25.rcp[index + i].qw0_dyn);
+			flm_nthw_rcp_qw0_ofs(be->p_flm_nthw, flm->v25.rcp[index + i].qw0_ofs);
+			flm_nthw_rcp_qw0_sel(be->p_flm_nthw, flm->v25.rcp[index + i].qw0_sel);
+			flm_nthw_rcp_qw4_dyn(be->p_flm_nthw, flm->v25.rcp[index + i].qw4_dyn);
+			flm_nthw_rcp_qw4_ofs(be->p_flm_nthw, flm->v25.rcp[index + i].qw4_ofs);
+			flm_nthw_rcp_sw8_dyn(be->p_flm_nthw, flm->v25.rcp[index + i].sw8_dyn);
+			flm_nthw_rcp_sw8_ofs(be->p_flm_nthw, flm->v25.rcp[index + i].sw8_ofs);
+			flm_nthw_rcp_sw8_sel(be->p_flm_nthw, flm->v25.rcp[index + i].sw8_sel);
+			flm_nthw_rcp_sw9_dyn(be->p_flm_nthw, flm->v25.rcp[index + i].sw9_dyn);
+			flm_nthw_rcp_sw9_ofs(be->p_flm_nthw, flm->v25.rcp[index + i].sw9_ofs);
+			flm_nthw_rcp_mask(be->p_flm_nthw, flm->v25.rcp[index + i].mask);
+			flm_nthw_rcp_kid(be->p_flm_nthw, flm->v25.rcp[index + i].kid);
+			flm_nthw_rcp_opn(be->p_flm_nthw, flm->v25.rcp[index + i].opn);
+			flm_nthw_rcp_ipn(be->p_flm_nthw, flm->v25.rcp[index + i].ipn);
+			flm_nthw_rcp_byt_dyn(be->p_flm_nthw, flm->v25.rcp[index + i].byt_dyn);
+			flm_nthw_rcp_byt_ofs(be->p_flm_nthw, flm->v25.rcp[index + i].byt_ofs);
+			flm_nthw_rcp_txplm(be->p_flm_nthw, flm->v25.rcp[index + i].txplm);
+			flm_nthw_rcp_auto_ipv4_mask(be->p_flm_nthw,
+				flm->v25.rcp[index + i].auto_ipv4_mask);
+			flm_nthw_rcp_flush(be->p_flm_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return 0;
+}
+
+static int flm_scrub_flush(void *be_dev, const struct flm_func_s *flm, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	if (flm->ver >= 25) {
+		flm_nthw_scrub_cnt(be->p_flm_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			flm_nthw_scrub_select(be->p_flm_nthw, index + i);
+			flm_nthw_scrub_t(be->p_flm_nthw, flm->v25.scrub[index + i].t);
+			flm_nthw_scrub_r(be->p_flm_nthw, flm->v25.scrub[index + i].r);
+			flm_nthw_scrub_del(be->p_flm_nthw, flm->v25.scrub[index + i].del);
+			flm_nthw_scrub_inf(be->p_flm_nthw, flm->v25.scrub[index + i].inf);
+			flm_nthw_scrub_flush(be->p_flm_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return 0;
+}
+
+static int flm_buf_ctrl_update(void *be_dev, const struct flm_func_s *flm)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	if (flm->ver >= 25) {
+		flm_nthw_buf_ctrl_update(be->p_flm_nthw,
+			&flm->v25.buf_ctrl->lrn_free,
+			&flm->v25.buf_ctrl->inf_avail,
+			&flm->v25.buf_ctrl->sta_avail);
+	}
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return 0;
+}
+
+static int flm_stat_update(void *be_dev, const struct flm_func_s *flm)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	if (flm->ver >= 25) {
+		flm_nthw_stat_lrn_done_update(be->p_flm_nthw);
+		flm_nthw_stat_lrn_ignore_update(be->p_flm_nthw);
+		flm_nthw_stat_lrn_fail_update(be->p_flm_nthw);
+		flm_nthw_stat_unl_done_update(be->p_flm_nthw);
+		flm_nthw_stat_unl_ignore_update(be->p_flm_nthw);
+		flm_nthw_stat_rel_done_update(be->p_flm_nthw);
+		flm_nthw_stat_rel_ignore_update(be->p_flm_nthw);
+		flm_nthw_stat_aul_done_update(be->p_flm_nthw);
+		flm_nthw_stat_aul_ignore_update(be->p_flm_nthw);
+		flm_nthw_stat_aul_fail_update(be->p_flm_nthw);
+		flm_nthw_stat_tul_done_update(be->p_flm_nthw);
+		flm_nthw_stat_flows_update(be->p_flm_nthw);
+		flm_nthw_load_lps_update(be->p_flm_nthw);
+		flm_nthw_load_aps_update(be->p_flm_nthw);
+
+		flm_nthw_stat_lrn_done_cnt(be->p_flm_nthw, &flm->v25.lrn_done->cnt, 1);
+		flm_nthw_stat_lrn_ignore_cnt(be->p_flm_nthw, &flm->v25.lrn_ignore->cnt, 1);
+		flm_nthw_stat_lrn_fail_cnt(be->p_flm_nthw, &flm->v25.lrn_fail->cnt, 1);
+		flm_nthw_stat_unl_done_cnt(be->p_flm_nthw, &flm->v25.unl_done->cnt, 1);
+		flm_nthw_stat_unl_ignore_cnt(be->p_flm_nthw, &flm->v25.unl_ignore->cnt, 1);
+		flm_nthw_stat_rel_done_cnt(be->p_flm_nthw, &flm->v25.rel_done->cnt, 1);
+		flm_nthw_stat_rel_ignore_cnt(be->p_flm_nthw, &flm->v25.rel_ignore->cnt, 1);
+		flm_nthw_stat_aul_done_cnt(be->p_flm_nthw, &flm->v25.aul_done->cnt, 1);
+		flm_nthw_stat_aul_ignore_cnt(be->p_flm_nthw, &flm->v25.aul_ignore->cnt, 1);
+		flm_nthw_stat_aul_fail_cnt(be->p_flm_nthw, &flm->v25.aul_fail->cnt, 1);
+		flm_nthw_stat_tul_done_cnt(be->p_flm_nthw, &flm->v25.tul_done->cnt, 1);
+		flm_nthw_stat_flows_cnt(be->p_flm_nthw, &flm->v25.flows->cnt, 1);
+
+		flm_nthw_stat_prb_done_update(be->p_flm_nthw);
+		flm_nthw_stat_prb_ignore_update(be->p_flm_nthw);
+		flm_nthw_stat_prb_done_cnt(be->p_flm_nthw, &flm->v25.prb_done->cnt, 1);
+		flm_nthw_stat_prb_ignore_cnt(be->p_flm_nthw, &flm->v25.prb_ignore->cnt, 1);
+
+		flm_nthw_load_lps_cnt(be->p_flm_nthw, &flm->v25.load_lps->lps, 1);
+		flm_nthw_load_aps_cnt(be->p_flm_nthw, &flm->v25.load_aps->aps, 1);
+	}
+
+	if (flm->ver >= 25) {
+		flm_nthw_stat_sta_done_update(be->p_flm_nthw);
+		flm_nthw_stat_inf_done_update(be->p_flm_nthw);
+		flm_nthw_stat_inf_skip_update(be->p_flm_nthw);
+		flm_nthw_stat_pck_hit_update(be->p_flm_nthw);
+		flm_nthw_stat_pck_miss_update(be->p_flm_nthw);
+		flm_nthw_stat_pck_unh_update(be->p_flm_nthw);
+		flm_nthw_stat_pck_dis_update(be->p_flm_nthw);
+		flm_nthw_stat_csh_hit_update(be->p_flm_nthw);
+		flm_nthw_stat_csh_miss_update(be->p_flm_nthw);
+		flm_nthw_stat_csh_unh_update(be->p_flm_nthw);
+		flm_nthw_stat_cuc_start_update(be->p_flm_nthw);
+		flm_nthw_stat_cuc_move_update(be->p_flm_nthw);
+
+		flm_nthw_stat_sta_done_cnt(be->p_flm_nthw, &flm->v25.sta_done->cnt, 1);
+		flm_nthw_stat_inf_done_cnt(be->p_flm_nthw, &flm->v25.inf_done->cnt, 1);
+		flm_nthw_stat_inf_skip_cnt(be->p_flm_nthw, &flm->v25.inf_skip->cnt, 1);
+		flm_nthw_stat_pck_hit_cnt(be->p_flm_nthw, &flm->v25.pck_hit->cnt, 1);
+		flm_nthw_stat_pck_miss_cnt(be->p_flm_nthw, &flm->v25.pck_miss->cnt, 1);
+		flm_nthw_stat_pck_unh_cnt(be->p_flm_nthw, &flm->v25.pck_unh->cnt, 1);
+		flm_nthw_stat_pck_dis_cnt(be->p_flm_nthw, &flm->v25.pck_dis->cnt, 1);
+		flm_nthw_stat_csh_hit_cnt(be->p_flm_nthw, &flm->v25.csh_hit->cnt, 1);
+		flm_nthw_stat_csh_miss_cnt(be->p_flm_nthw, &flm->v25.csh_miss->cnt, 1);
+		flm_nthw_stat_csh_unh_cnt(be->p_flm_nthw, &flm->v25.csh_unh->cnt, 1);
+		flm_nthw_stat_cuc_start_cnt(be->p_flm_nthw, &flm->v25.cuc_start->cnt, 1);
+		flm_nthw_stat_cuc_move_cnt(be->p_flm_nthw, &flm->v25.cuc_move->cnt, 1);
+	}
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return 0;
+}
+
+static int flm_lrn_data_flush(void *be_dev, const struct flm_func_s *flm, const uint32_t *lrn_data,
+	uint32_t records, uint32_t *handled_records,
+	uint32_t words_per_record, uint32_t *inf_word_cnt,
+	uint32_t *sta_word_cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	int ret = flm_nthw_lrn_data_flush(be->p_flm_nthw, lrn_data, records, words_per_record,
+			handled_records, &flm->v25.buf_ctrl->lrn_free,
+			&flm->v25.buf_ctrl->inf_avail,
+			&flm->v25.buf_ctrl->sta_avail);
+
+	*inf_word_cnt = flm->v25.buf_ctrl->inf_avail;
+	*sta_word_cnt = flm->v25.buf_ctrl->sta_avail;
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return ret;
+}
+
+static int flm_inf_sta_data_update(void *be_dev, const struct flm_func_s *flm, uint32_t *inf_data,
+	uint32_t inf_size, uint32_t *inf_word_cnt, uint32_t *sta_data,
+	uint32_t sta_size, uint32_t *sta_word_cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, flm, be->p_flm_nthw);
+
+	int ret = flm_nthw_inf_sta_data_update(be->p_flm_nthw, inf_data, inf_size, sta_data,
+			sta_size, &flm->v25.buf_ctrl->lrn_free,
+			&flm->v25.buf_ctrl->inf_avail,
+			&flm->v25.buf_ctrl->sta_avail);
+
+	*inf_word_cnt = flm->v25.buf_ctrl->inf_avail;
+	*sta_word_cnt = flm->v25.buf_ctrl->sta_avail;
+
+	CHECK_DEBUG_OFF(flm, be->p_flm_nthw);
+	return ret;
+}
+
 /*
  * DBS
  */
@@ -1000,6 +1351,22 @@ const struct flow_api_backend_ops flow_be_iface = {
 	km_tcam_flush,
 	km_tci_flush,
 	km_tcq_flush,
+
+	flm_get_present,
+	flm_get_version,
+	flm_control_flush,
+	flm_status_flush,
+	flm_status_update,
+	flm_scan_flush,
+	flm_load_bin_flush,
+	flm_prio_flush,
+	flm_pst_flush,
+	flm_rcp_flush,
+	flm_scrub_flush,
+	flm_buf_ctrl_update,
+	flm_stat_update,
+	flm_lrn_data_flush,
+	flm_inf_sta_data_update,
 };
 
 const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, void **dev)
@@ -1030,6 +1397,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_km_nthw = NULL;
 	}
 
+	/* Init nthw FLM */
+	if (flm_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct flm_nthw *pflmnthw = flm_nthw_new();
+		flm_nthw_init(pflmnthw, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_flm_nthw = pflmnthw;
+
+	} else {
+		be_devs[physical_adapter_no].p_flm_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -1042,6 +1419,7 @@ static void bin_flow_backend_done(void *dev)
 	info_nthw_delete(be_dev->p_info_nthw);
 	cat_nthw_delete(be_dev->p_cat_nthw);
 	km_nthw_delete(be_dev->p_km_nthw);
+	flm_nthw_delete(be_dev->p_flm_nthw);
 }
 
 static const struct flow_backend_ops ops = {
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.c
new file mode 100644
index 0000000000..e8ca67d691
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.c
@@ -0,0 +1,1225 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+#include "nthw_rac.h"
+
+#include "flow_nthw_flm.h"
+
+struct flm_nthw *flm_nthw_new(void)
+{
+	struct flm_nthw *p = malloc(sizeof(struct flm_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void flm_nthw_delete(struct flm_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+void flm_nthw_set_debug_mode(struct flm_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_flm, n_debug_mode);
+}
+
+int flm_nthw_init(struct flm_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_FLM, n_instance);
+
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: Flm %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_rac = p_fpga->p_fpga_info->mp_nthw_rac;
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_flm = p_mod;
+
+	p->mp_control = nthw_module_get_register(p->m_flm, FLM_CONTROL);
+	p->mp_control_enable = nthw_register_get_field(p->mp_control, FLM_CONTROL_ENABLE);
+	p->mp_control_init = nthw_register_get_field(p->mp_control, FLM_CONTROL_INIT);
+	p->mp_control_lds = nthw_register_get_field(p->mp_control, FLM_CONTROL_LDS);
+	p->mp_control_lfs = nthw_register_get_field(p->mp_control, FLM_CONTROL_LFS);
+	p->mp_control_lis = nthw_register_get_field(p->mp_control, FLM_CONTROL_LIS);
+	p->mp_control_uds = nthw_register_get_field(p->mp_control, FLM_CONTROL_UDS);
+	p->mp_control_uis = nthw_register_get_field(p->mp_control, FLM_CONTROL_UIS);
+	p->mp_control_rds = nthw_register_get_field(p->mp_control, FLM_CONTROL_RDS);
+	p->mp_control_ris = nthw_register_get_field(p->mp_control, FLM_CONTROL_RIS);
+	p->mp_control_pds = nthw_register_query_field(p->mp_control, FLM_CONTROL_PDS);
+	p->mp_control_pis = nthw_register_query_field(p->mp_control, FLM_CONTROL_PIS);
+	p->mp_control_crcwr = nthw_register_get_field(p->mp_control, FLM_CONTROL_CRCWR);
+	p->mp_control_crcrd = nthw_register_get_field(p->mp_control, FLM_CONTROL_CRCRD);
+	p->mp_control_rbl = nthw_register_get_field(p->mp_control, FLM_CONTROL_RBL);
+	p->mp_control_eab = nthw_register_get_field(p->mp_control, FLM_CONTROL_EAB);
+	p->mp_control_split_sdram_usage =
+		nthw_register_get_field(p->mp_control, FLM_CONTROL_SPLIT_SDRAM_USAGE);
+	p->mp_control_calib_recalibrate =
+		nthw_register_query_field(p->mp_control, FLM_CONTROL_CALIB_RECALIBRATE);
+
+	p->mp_status = nthw_module_get_register(p->m_flm, FLM_STATUS);
+	p->mp_status_calib_success =
+		nthw_register_get_field(p->mp_status, FLM_STATUS_CALIB_SUCCESS);
+	p->mp_status_calib_fail = nthw_register_get_field(p->mp_status, FLM_STATUS_CALIB_FAIL);
+	p->mp_status_initdone = nthw_register_get_field(p->mp_status, FLM_STATUS_INITDONE);
+	p->mp_status_idle = nthw_register_get_field(p->mp_status, FLM_STATUS_IDLE);
+	p->mp_status_critical = nthw_register_get_field(p->mp_status, FLM_STATUS_CRITICAL);
+	p->mp_status_panic = nthw_register_get_field(p->mp_status, FLM_STATUS_PANIC);
+	p->mp_status_crcerr = nthw_register_get_field(p->mp_status, FLM_STATUS_CRCERR);
+	p->mp_status_eft_bp = nthw_register_get_field(p->mp_status, FLM_STATUS_EFT_BP);
+	p->mp_status_cache_buf_critical =
+		nthw_register_get_field(p->mp_status, FLM_STATUS_CACHE_BUFFER_CRITICAL);
+
+	p->mp_scan = nthw_module_get_register(p->m_flm, FLM_SCAN);
+	p->mp_scan_i = nthw_register_get_field(p->mp_scan, FLM_SCAN_I);
+
+	p->mp_load_bin = nthw_module_get_register(p->m_flm, FLM_LOAD_BIN);
+	p->mp_load_bin_bin = nthw_register_get_field(p->mp_load_bin, FLM_LOAD_BIN_BIN);
+
+	p->mp_load_lps = nthw_module_get_register(p->m_flm, FLM_LOAD_LPS);
+	p->mp_load_lps_lps = nthw_register_get_field(p->mp_load_lps, FLM_LOAD_LPS_LPS);
+
+	p->mp_load_aps = nthw_module_get_register(p->m_flm, FLM_LOAD_APS);
+	p->mp_load_aps_aps = nthw_register_get_field(p->mp_load_aps, FLM_LOAD_APS_APS);
+
+	p->mp_prio = nthw_module_get_register(p->m_flm, FLM_PRIO);
+	p->mp_prio_limit0 = nthw_register_get_field(p->mp_prio, FLM_PRIO_LIMIT0);
+	p->mp_prio_ft0 = nthw_register_get_field(p->mp_prio, FLM_PRIO_FT0);
+	p->mp_prio_limit1 = nthw_register_get_field(p->mp_prio, FLM_PRIO_LIMIT1);
+	p->mp_prio_ft1 = nthw_register_get_field(p->mp_prio, FLM_PRIO_FT1);
+	p->mp_prio_limit2 = nthw_register_get_field(p->mp_prio, FLM_PRIO_LIMIT2);
+	p->mp_prio_ft2 = nthw_register_get_field(p->mp_prio, FLM_PRIO_FT2);
+	p->mp_prio_limit3 = nthw_register_get_field(p->mp_prio, FLM_PRIO_LIMIT3);
+	p->mp_prio_ft3 = nthw_register_get_field(p->mp_prio, FLM_PRIO_FT3);
+
+	p->mp_pst_ctrl = nthw_module_get_register(p->m_flm, FLM_PST_CTRL);
+	p->mp_pst_ctrl_adr = nthw_register_get_field(p->mp_pst_ctrl, FLM_PST_CTRL_ADR);
+	p->mp_pst_ctrl_cnt = nthw_register_get_field(p->mp_pst_ctrl, FLM_PST_CTRL_CNT);
+	p->mp_pst_data = nthw_module_get_register(p->m_flm, FLM_PST_DATA);
+	p->mp_pst_data_bp = nthw_register_get_field(p->mp_pst_data, FLM_PST_DATA_BP);
+	p->mp_pst_data_pp = nthw_register_get_field(p->mp_pst_data, FLM_PST_DATA_PP);
+	p->mp_pst_data_tp = nthw_register_get_field(p->mp_pst_data, FLM_PST_DATA_TP);
+
+	p->mp_rcp_ctrl = nthw_module_get_register(p->m_flm, FLM_RCP_CTRL);
+	p->mp_rcp_ctrl_adr = nthw_register_get_field(p->mp_rcp_ctrl, FLM_RCP_CTRL_ADR);
+	p->mp_rcp_ctrl_cnt = nthw_register_get_field(p->mp_rcp_ctrl, FLM_RCP_CTRL_CNT);
+	p->mp_rcp_data = nthw_module_get_register(p->m_flm, FLM_RCP_DATA);
+	p->mp_rcp_data_lookup = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_LOOKUP);
+	p->mp_rcp_data_qw0_dyn = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_QW0_DYN);
+	p->mp_rcp_data_qw0_ofs = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_QW0_OFS);
+	p->mp_rcp_data_qw0_sel = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_QW0_SEL);
+	p->mp_rcp_data_qw4_dyn = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_QW4_DYN);
+	p->mp_rcp_data_qw4_ofs = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_QW4_OFS);
+	p->mp_rcp_data_sw8_dyn = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_SW8_DYN);
+	p->mp_rcp_data_sw8_ofs = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_SW8_OFS);
+	p->mp_rcp_data_sw8_sel = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_SW8_SEL);
+	p->mp_rcp_data_sw9_dyn = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_SW9_DYN);
+	p->mp_rcp_data_sw9_ofs = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_SW9_OFS);
+	p->mp_rcp_data_mask = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_MASK);
+	p->mp_rcp_data_kid = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_KID);
+	p->mp_rcp_data_opn = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_OPN);
+	p->mp_rcp_data_ipn = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_IPN);
+	p->mp_rcp_data_byt_dyn = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_BYT_DYN);
+	p->mp_rcp_data_byt_ofs = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_BYT_OFS);
+	p->mp_rcp_data_txplm = nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_TXPLM);
+	p->mp_rcp_data_auto_ipv4_mask =
+		nthw_register_get_field(p->mp_rcp_data, FLM_RCP_DATA_AUTO_IPV4_MASK);
+
+	p->mp_buf_ctrl = nthw_module_get_register(p->m_flm, FLM_BUF_CTRL);
+
+	p->mp_lrn_data = nthw_module_get_register(p->m_flm, FLM_LRN_DATA);
+	p->mp_inf_data = nthw_module_get_register(p->m_flm, FLM_INF_DATA);
+	p->mp_sta_data = nthw_module_get_register(p->m_flm, FLM_STA_DATA);
+
+	p->mp_stat_lrn_done = nthw_module_get_register(p->m_flm, FLM_STAT_LRN_DONE);
+	p->mp_stat_lrn_done_cnt =
+		nthw_register_get_field(p->mp_stat_lrn_done, FLM_STAT_LRN_DONE_CNT);
+
+	p->mp_stat_lrn_ignore = nthw_module_get_register(p->m_flm, FLM_STAT_LRN_IGNORE);
+	p->mp_stat_lrn_ignore_cnt =
+		nthw_register_get_field(p->mp_stat_lrn_ignore, FLM_STAT_LRN_IGNORE_CNT);
+
+	p->mp_stat_lrn_fail = nthw_module_get_register(p->m_flm, FLM_STAT_LRN_FAIL);
+	p->mp_stat_lrn_fail_cnt =
+		nthw_register_get_field(p->mp_stat_lrn_fail, FLM_STAT_LRN_FAIL_CNT);
+
+	p->mp_stat_unl_done = nthw_module_get_register(p->m_flm, FLM_STAT_UNL_DONE);
+	p->mp_stat_unl_done_cnt =
+		nthw_register_get_field(p->mp_stat_unl_done, FLM_STAT_UNL_DONE_CNT);
+
+	p->mp_stat_unl_ignore = nthw_module_get_register(p->m_flm, FLM_STAT_UNL_IGNORE);
+	p->mp_stat_unl_ignore_cnt =
+		nthw_register_get_field(p->mp_stat_unl_ignore, FLM_STAT_UNL_IGNORE_CNT);
+
+	p->mp_stat_prb_done = nthw_module_query_register(p->m_flm, FLM_STAT_PRB_DONE);
+	p->mp_stat_prb_done_cnt =
+		nthw_register_query_field(p->mp_stat_prb_done, FLM_STAT_PRB_DONE_CNT);
+
+	p->mp_stat_prb_ignore = nthw_module_query_register(p->m_flm, FLM_STAT_PRB_IGNORE);
+	p->mp_stat_prb_ignore_cnt =
+		nthw_register_query_field(p->mp_stat_prb_ignore, FLM_STAT_PRB_IGNORE_CNT);
+
+	p->mp_stat_rel_done = nthw_module_get_register(p->m_flm, FLM_STAT_REL_DONE);
+	p->mp_stat_rel_done_cnt =
+		nthw_register_get_field(p->mp_stat_rel_done, FLM_STAT_REL_DONE_CNT);
+
+	p->mp_stat_rel_ignore = nthw_module_get_register(p->m_flm, FLM_STAT_REL_IGNORE);
+	p->mp_stat_rel_ignore_cnt =
+		nthw_register_get_field(p->mp_stat_rel_ignore, FLM_STAT_REL_IGNORE_CNT);
+
+	p->mp_stat_aul_done = nthw_module_get_register(p->m_flm, FLM_STAT_AUL_DONE);
+	p->mp_stat_aul_done_cnt =
+		nthw_register_get_field(p->mp_stat_aul_done, FLM_STAT_AUL_DONE_CNT);
+
+	p->mp_stat_aul_ignore = nthw_module_get_register(p->m_flm, FLM_STAT_AUL_IGNORE);
+	p->mp_stat_aul_ignore_cnt =
+		nthw_register_get_field(p->mp_stat_aul_ignore, FLM_STAT_AUL_IGNORE_CNT);
+
+	p->mp_stat_aul_fail = nthw_module_get_register(p->m_flm, FLM_STAT_AUL_FAIL);
+	p->mp_stat_aul_fail_cnt =
+		nthw_register_get_field(p->mp_stat_aul_fail, FLM_STAT_AUL_FAIL_CNT);
+
+	p->mp_stat_tul_done = nthw_module_get_register(p->m_flm, FLM_STAT_TUL_DONE);
+	p->mp_stat_tul_done_cnt =
+		nthw_register_get_field(p->mp_stat_tul_done, FLM_STAT_TUL_DONE_CNT);
+
+	p->mp_stat_flows = nthw_module_get_register(p->m_flm, FLM_STAT_FLOWS);
+	p->mp_stat_flows_cnt = nthw_register_get_field(p->mp_stat_flows, FLM_STAT_FLOWS_CNT);
+
+	p->mp_stat_sta_done = nthw_module_query_register(p->m_flm, FLM_STAT_STA_DONE);
+	p->mp_stat_sta_done_cnt =
+		nthw_register_query_field(p->mp_stat_sta_done, FLM_STAT_STA_DONE_CNT);
+
+	p->mp_stat_inf_done = nthw_module_query_register(p->m_flm, FLM_STAT_INF_DONE);
+	p->mp_stat_inf_done_cnt =
+		nthw_register_query_field(p->mp_stat_inf_done, FLM_STAT_INF_DONE_CNT);
+
+	p->mp_stat_inf_skip = nthw_module_query_register(p->m_flm, FLM_STAT_INF_SKIP);
+	p->mp_stat_inf_skip_cnt =
+		nthw_register_query_field(p->mp_stat_inf_skip, FLM_STAT_INF_SKIP_CNT);
+
+	p->mp_stat_pck_hit = nthw_module_query_register(p->m_flm, FLM_STAT_PCK_HIT);
+	p->mp_stat_pck_hit_cnt =
+		nthw_register_query_field(p->mp_stat_pck_hit, FLM_STAT_PCK_HIT_CNT);
+
+	p->mp_stat_pck_miss = nthw_module_query_register(p->m_flm, FLM_STAT_PCK_MISS);
+	p->mp_stat_pck_miss_cnt =
+		nthw_register_query_field(p->mp_stat_pck_miss, FLM_STAT_PCK_MISS_CNT);
+
+	p->mp_stat_pck_unh = nthw_module_query_register(p->m_flm, FLM_STAT_PCK_UNH);
+	p->mp_stat_pck_unh_cnt =
+		nthw_register_query_field(p->mp_stat_pck_unh, FLM_STAT_PCK_UNH_CNT);
+
+	p->mp_stat_pck_dis = nthw_module_query_register(p->m_flm, FLM_STAT_PCK_DIS);
+	p->mp_stat_pck_dis_cnt =
+		nthw_register_query_field(p->mp_stat_pck_dis, FLM_STAT_PCK_DIS_CNT);
+
+	p->mp_stat_csh_hit = nthw_module_query_register(p->m_flm, FLM_STAT_CSH_HIT);
+	p->mp_stat_csh_hit_cnt =
+		nthw_register_query_field(p->mp_stat_csh_hit, FLM_STAT_CSH_HIT_CNT);
+
+	p->mp_stat_csh_miss = nthw_module_query_register(p->m_flm, FLM_STAT_CSH_MISS);
+	p->mp_stat_csh_miss_cnt =
+		nthw_register_query_field(p->mp_stat_csh_miss, FLM_STAT_CSH_MISS_CNT);
+
+	p->mp_stat_csh_unh = nthw_module_query_register(p->m_flm, FLM_STAT_CSH_UNH);
+	p->mp_stat_csh_unh_cnt =
+		nthw_register_query_field(p->mp_stat_csh_unh, FLM_STAT_CSH_UNH_CNT);
+
+	p->mp_stat_cuc_start = nthw_module_query_register(p->m_flm, FLM_STAT_CUC_START);
+	p->mp_stat_cuc_start_cnt =
+		nthw_register_query_field(p->mp_stat_cuc_start, FLM_STAT_CUC_START_CNT);
+
+	p->mp_stat_cuc_move = nthw_module_query_register(p->m_flm, FLM_STAT_CUC_MOVE);
+	p->mp_stat_cuc_move_cnt =
+		nthw_register_query_field(p->mp_stat_cuc_move, FLM_STAT_CUC_MOVE_CNT);
+
+	p->mp_scrub_ctrl = nthw_module_query_register(p->m_flm, FLM_SCRUB_CTRL);
+	p->mp_scrub_ctrl_adr = nthw_register_query_field(p->mp_scrub_ctrl, FLM_SCRUB_CTRL_ADR);
+	p->mp_scrub_ctrl_cnt = nthw_register_query_field(p->mp_scrub_ctrl, FLM_SCRUB_CTRL_CNT);
+
+	p->mp_scrub_data = nthw_module_query_register(p->m_flm, FLM_SCRUB_DATA);
+	p->mp_scrub_data_t = nthw_register_query_field(p->mp_scrub_data, FLM_SCRUB_DATA_T);
+	p->mp_scrub_data_r = nthw_register_query_field(p->mp_scrub_data, FLM_SCRUB_DATA_R);
+	p->mp_scrub_data_del = nthw_register_query_field(p->mp_scrub_data, FLM_SCRUB_DATA_DEL);
+	p->mp_scrub_data_inf = nthw_register_query_field(p->mp_scrub_data, FLM_SCRUB_DATA_INF);
+
+	return 0;
+}
+
+void flm_nthw_control_enable(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_enable, val);
+}
+
+void flm_nthw_control_init(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_init, val);
+}
+
+void flm_nthw_control_lds(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_lds, val);
+}
+
+void flm_nthw_control_lfs(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_lfs, val);
+}
+
+void flm_nthw_control_lis(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_lis, val);
+}
+
+void flm_nthw_control_uds(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_uds, val);
+}
+
+void flm_nthw_control_uis(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_uis, val);
+}
+
+void flm_nthw_control_rds(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_rds, val);
+}
+
+void flm_nthw_control_ris(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_ris, val);
+}
+
+void flm_nthw_control_pds(const struct flm_nthw *p, uint32_t val)
+{
+	assert(p->mp_control_pds);
+	nthw_field_set_val32(p->mp_control_pds, val);
+}
+
+void flm_nthw_control_pis(const struct flm_nthw *p, uint32_t val)
+{
+	assert(p->mp_control_pis);
+	nthw_field_set_val32(p->mp_control_pis, val);
+}
+
+void flm_nthw_control_crcwr(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_crcwr, val);
+}
+
+void flm_nthw_control_crcrd(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_crcrd, val);
+}
+
+void flm_nthw_control_rbl(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_rbl, val);
+}
+
+void flm_nthw_control_eab(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_eab, val);
+}
+
+void flm_nthw_control_split_sdram_usage(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_control_split_sdram_usage, val);
+}
+
+void flm_nthw_control_flush(const struct flm_nthw *p)
+{
+	nthw_register_flush(p->mp_control, 1);
+}
+
+void flm_nthw_status_calib_success(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get) {
+		uint32_t w = nthw_field_get_bit_width(p->mp_status_calib_success);
+		uint32_t all_ones = (1 << w) - 1;
+		*val = nthw_field_get_val32(p->mp_status_calib_success);
+
+		if (all_ones == *val) {
+			/* Mark all calibrated */
+			*val |= 0x80000000;
+		}
+	}
+}
+
+void flm_nthw_status_calib_fail(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_status_calib_fail);
+}
+
+void flm_nthw_status_initdone(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_status_initdone);
+}
+
+void flm_nthw_status_idle(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_status_idle);
+}
+
+void flm_nthw_status_critical(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_status_critical);
+
+	else
+		nthw_field_set_val32(p->mp_status_critical, *val);
+}
+
+void flm_nthw_status_panic(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_status_panic);
+
+	else
+		nthw_field_set_val32(p->mp_status_panic, *val);
+}
+
+void flm_nthw_status_crcerr(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_status_crcerr);
+
+	else
+		nthw_field_set_val32(p->mp_status_crcerr, *val);
+}
+
+void flm_nthw_status_eft_bp(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_status_eft_bp);
+}
+
+void flm_nthw_status_cache_buf_crit(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_status_cache_buf_critical);
+
+	else
+		nthw_field_set_val32(p->mp_status_cache_buf_critical, *val);
+}
+
+void flm_nthw_status_flush(const struct flm_nthw *p)
+{
+	nthw_register_flush(p->mp_status, 1);
+}
+
+void flm_nthw_status_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_status);
+}
+
+void flm_nthw_scan_i(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_scan_i, val);
+}
+
+void flm_nthw_scan_flush(const struct flm_nthw *p)
+{
+	nthw_register_flush(p->mp_scan, 1);
+}
+
+void flm_nthw_load_bin(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_load_bin_bin, val);
+}
+
+void flm_nthw_load_bin_flush(const struct flm_nthw *p)
+{
+	nthw_register_flush(p->mp_load_bin, 1);
+}
+
+void flm_nthw_load_lps_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_load_lps);
+}
+
+void flm_nthw_load_lps_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_load_lps_lps);
+}
+
+void flm_nthw_load_aps_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_load_aps);
+}
+
+void flm_nthw_load_aps_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_load_aps_aps);
+}
+
+void flm_nthw_prio_limit0(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_prio_limit0, val);
+}
+
+void flm_nthw_prio_ft0(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_prio_ft0, val);
+}
+
+void flm_nthw_prio_limit1(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_prio_limit1, val);
+}
+
+void flm_nthw_prio_ft1(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_prio_ft1, val);
+}
+
+void flm_nthw_prio_limit2(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_prio_limit2, val);
+}
+
+void flm_nthw_prio_ft2(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_prio_ft2, val);
+}
+
+void flm_nthw_prio_limit3(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_prio_limit3, val);
+}
+
+void flm_nthw_prio_ft3(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_prio_ft3, val);
+}
+
+void flm_nthw_prio_flush(const struct flm_nthw *p)
+{
+	nthw_register_flush(p->mp_prio, 1);
+}
+
+void flm_nthw_pst_select(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_pst_ctrl_adr, val);
+}
+
+void flm_nthw_pst_cnt(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_pst_ctrl_cnt, val);
+}
+
+void flm_nthw_pst_bp(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_pst_data_bp, val);
+}
+
+void flm_nthw_pst_pp(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_pst_data_pp, val);
+}
+
+void flm_nthw_pst_tp(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_pst_data_tp, val);
+}
+
+void flm_nthw_pst_flush(const struct flm_nthw *p)
+{
+	nthw_register_flush(p->mp_pst_ctrl, 1);
+	nthw_register_flush(p->mp_pst_data, 1);
+}
+
+void flm_nthw_rcp_select(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_ctrl_adr, val);
+}
+
+void flm_nthw_rcp_cnt(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_ctrl_cnt, val);
+}
+
+void flm_nthw_rcp_lookup(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_lookup, val);
+}
+
+void flm_nthw_rcp_qw0_dyn(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw0_dyn, val);
+}
+
+void flm_nthw_rcp_qw0_ofs(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw0_ofs, val);
+}
+
+void flm_nthw_rcp_qw0_sel(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw0_sel, val);
+}
+
+void flm_nthw_rcp_qw4_dyn(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw4_dyn, val);
+}
+
+void flm_nthw_rcp_qw4_ofs(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw4_ofs, val);
+}
+
+void flm_nthw_rcp_sw8_dyn(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_sw8_dyn, val);
+}
+
+void flm_nthw_rcp_sw8_ofs(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_sw8_ofs, val);
+}
+
+void flm_nthw_rcp_sw8_sel(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_sw8_sel, val);
+}
+
+void flm_nthw_rcp_sw9_dyn(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_sw9_dyn, val);
+}
+
+void flm_nthw_rcp_sw9_ofs(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_sw9_ofs, val);
+}
+
+void flm_nthw_rcp_mask(const struct flm_nthw *p, const uint32_t *val)
+{
+	nthw_field_set_val(p->mp_rcp_data_mask, val, 10);
+}
+
+void flm_nthw_rcp_kid(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_kid, val);
+}
+
+void flm_nthw_rcp_opn(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_opn, val);
+}
+
+void flm_nthw_rcp_ipn(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ipn, val);
+}
+
+void flm_nthw_rcp_byt_dyn(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_byt_dyn, val);
+}
+
+void flm_nthw_rcp_byt_ofs(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_byt_ofs, val);
+}
+
+void flm_nthw_rcp_txplm(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_txplm, val);
+}
+
+void flm_nthw_rcp_auto_ipv4_mask(const struct flm_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_auto_ipv4_mask, val);
+}
+
+void flm_nthw_rcp_flush(const struct flm_nthw *p)
+{
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+}
+
+int flm_nthw_buf_ctrl_update(const struct flm_nthw *p, uint32_t *lrn_free, uint32_t *inf_avail,
+	uint32_t *sta_avail)
+{
+	int ret = -1;
+
+	struct nthw_rac *rac = (struct nthw_rac *)p->mp_rac;
+	uint32_t address_bufctrl = nthw_register_get_address(p->mp_buf_ctrl);
+	nthw_rab_bus_id_t bus_id = 1;
+	struct dma_buf_ptr bc_buf;
+	ret = nthw_rac_rab_dma_begin(rac);
+
+	if (ret == 0) {
+		nthw_rac_rab_read32_dma(rac, bus_id, address_bufctrl, 2, &bc_buf);
+		ret = nthw_rac_rab_dma_commit(rac);
+
+		if (ret != 0)
+			return ret;
+
+		uint32_t bc_mask = bc_buf.size - 1;
+		uint32_t bc_index = bc_buf.index;
+		*lrn_free = bc_buf.base[bc_index & bc_mask] & 0xffff;
+		*inf_avail = (bc_buf.base[bc_index & bc_mask] >> 16) & 0xffff;
+		*sta_avail = bc_buf.base[(bc_index + 1) & bc_mask] & 0xffff;
+	}
+
+	return ret;
+}
+
+int flm_nthw_lrn_data_flush(const struct flm_nthw *p, const uint32_t *data, uint32_t records,
+	uint32_t words_per_record, uint32_t *handled_records,
+	uint32_t *lrn_free, uint32_t *inf_avail, uint32_t *sta_avail)
+{
+	struct nthw_rac *rac = (struct nthw_rac *)p->mp_rac;
+	uint32_t address = nthw_register_get_address(p->mp_lrn_data);
+	uint32_t address_bufctrl = nthw_register_get_address(p->mp_buf_ctrl);
+	nthw_rab_bus_id_t bus_id = 1;
+	struct dma_buf_ptr bc_buf;
+
+	uint32_t max_records_per_write = 256 / words_per_record;
+
+	/* Check for dma overhead */
+	if ((256 % words_per_record) < (max_records_per_write + 3 + 1))
+		--max_records_per_write;
+
+	*handled_records = 0;
+	int max_tries = 10000;
+
+	while (*inf_avail == 0 && *sta_avail == 0 && records != 0 && --max_tries > 0)
+		if (nthw_rac_rab_dma_begin(rac) == 0) {
+			uint32_t dma_free = nthw_rac_rab_get_free(rac);
+
+			if (dma_free != RAB_DMA_BUF_CNT) {
+				assert(0);	/* alert developer that something is wrong */
+				return -1;
+			}
+
+			uint32_t max_writes_from_learn_free =
+				*lrn_free / (max_records_per_write * words_per_record);
+
+			/*
+			 * Not strictly needed as dma_free will always
+			 * (per design) be much larger than lrn_free
+			 */
+			uint32_t max_writes_from_dma_free = dma_free / 256;
+			uint32_t max_writes =
+				(max_writes_from_learn_free < max_writes_from_dma_free)
+				? max_writes_from_learn_free
+				: max_writes_from_dma_free;
+
+			uint32_t records_per_write = (records < max_records_per_write)
+				? records
+				: max_records_per_write;
+
+			while (records != 0 && max_writes != 0) {
+				/*
+				 * Announce the number of words to write
+				 * to LRN_DATA in next write operation
+				 */
+				uint32_t bufctrl_data[2];
+				bufctrl_data[0] = records_per_write * words_per_record;
+				bufctrl_data[1] = 0;
+				nthw_rac_rab_write32_dma(rac, bus_id, address_bufctrl, 2,
+					bufctrl_data);
+
+				/* Write data */
+				nthw_rac_rab_write32_dma(rac, bus_id, address, bufctrl_data[0],
+					data);
+
+				/* Prepare next write operation */
+				data += bufctrl_data[0];
+				records -= records_per_write;
+				*handled_records += records_per_write;
+				records_per_write = (records < max_records_per_write)
+					? records
+					: max_records_per_write;
+				--max_writes;
+			}
+
+			/* Read buf ctrl */
+			nthw_rac_rab_read32_dma(rac, bus_id, address_bufctrl, 2, &bc_buf);
+
+			if (nthw_rac_rab_dma_commit(rac) != 0)
+				return -1;
+
+			uint32_t bc_mask = bc_buf.size - 1;
+			uint32_t bc_index = bc_buf.index;
+			*lrn_free = bc_buf.base[bc_index & bc_mask] & 0xffff;
+			*inf_avail = (bc_buf.base[bc_index & bc_mask] >> 16) & 0xffff;
+			*sta_avail = bc_buf.base[(bc_index + 1) & bc_mask] & 0xffff;
+		}
+
+	return 0;
+}
+
+int flm_nthw_inf_sta_data_update(const struct flm_nthw *p, uint32_t *inf_data,
+	uint32_t inf_word_count, uint32_t *sta_data,
+	uint32_t sta_word_count, uint32_t *lrn_free, uint32_t *inf_avail,
+	uint32_t *sta_avail)
+{
+	int ret = -1;
+
+	struct nthw_rac *rac = (struct nthw_rac *)p->mp_rac;
+	uint32_t address_inf_data = nthw_register_get_address(p->mp_inf_data);
+	uint32_t address_sta_data = nthw_register_get_address(p->mp_sta_data);
+	uint32_t address_bufctrl = nthw_register_get_address(p->mp_buf_ctrl);
+	nthw_rab_bus_id_t bus_id = 1;
+	struct dma_buf_ptr inf_buf;
+	struct dma_buf_ptr sta_buf;
+	struct dma_buf_ptr bc_buf;
+	uint32_t mask;
+	uint32_t index;
+
+	ret = nthw_rac_rab_dma_begin(rac);
+
+	if (ret == 0) {
+		/* Announce the number of words to read from INF_DATA */
+		uint32_t bufctrl_data[2];
+		bufctrl_data[0] = inf_word_count << 16;
+		bufctrl_data[1] = sta_word_count;
+		nthw_rac_rab_write32_dma(rac, bus_id, address_bufctrl, 2, bufctrl_data);
+
+		if (inf_word_count > 0) {
+			nthw_rac_rab_read32_dma(rac, bus_id, address_inf_data, inf_word_count,
+				&inf_buf);
+		}
+
+		if (sta_word_count > 0) {
+			nthw_rac_rab_read32_dma(rac, bus_id, address_sta_data, sta_word_count,
+				&sta_buf);
+		}
+
+		nthw_rac_rab_read32_dma(rac, bus_id, address_bufctrl, 2, &bc_buf);
+		ret = nthw_rac_rab_dma_commit(rac);
+
+		if (ret != 0)
+			return ret;
+
+		if (inf_word_count > 0) {
+			mask = inf_buf.size - 1;
+			index = inf_buf.index;
+
+			for (uint32_t i = 0; i < inf_word_count; ++index, ++i)
+				inf_data[i] = inf_buf.base[index & mask];
+		}
+
+		if (sta_word_count > 0) {
+			mask = sta_buf.size - 1;
+			index = sta_buf.index;
+
+			for (uint32_t i = 0; i < sta_word_count; ++index, ++i)
+				sta_data[i] = sta_buf.base[index & mask];
+		}
+
+		mask = bc_buf.size - 1;
+		index = bc_buf.index;
+		*lrn_free = bc_buf.base[index & mask] & 0xffff;
+		*inf_avail = (bc_buf.base[index & mask] >> 16) & 0xffff;
+		*sta_avail = bc_buf.base[(index + 1) & mask] & 0xffff;
+	}
+
+	return ret;
+}
+
+void flm_nthw_stat_lrn_done_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_lrn_done_cnt);
+}
+
+void flm_nthw_stat_lrn_done_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_stat_lrn_done);
+}
+
+void flm_nthw_stat_lrn_ignore_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_lrn_ignore_cnt);
+}
+
+void flm_nthw_stat_lrn_ignore_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_stat_lrn_ignore);
+}
+
+void flm_nthw_stat_lrn_fail_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_lrn_fail_cnt);
+}
+
+void flm_nthw_stat_lrn_fail_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_stat_lrn_fail);
+}
+
+void flm_nthw_stat_unl_done_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_unl_done_cnt);
+}
+
+void flm_nthw_stat_unl_done_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_stat_unl_done);
+}
+
+void flm_nthw_stat_unl_ignore_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_unl_ignore_cnt);
+}
+
+void flm_nthw_stat_unl_ignore_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_stat_unl_ignore);
+}
+
+void flm_nthw_stat_prb_done_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_prb_done_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_prb_done_cnt);
+}
+
+void flm_nthw_stat_prb_done_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_prb_done);
+	nthw_register_update(p->mp_stat_prb_done);
+}
+
+void flm_nthw_stat_prb_ignore_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_prb_ignore_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_prb_ignore_cnt);
+}
+
+void flm_nthw_stat_prb_ignore_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_prb_ignore);
+	nthw_register_update(p->mp_stat_prb_ignore);
+}
+
+void flm_nthw_stat_rel_done_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_rel_done_cnt);
+}
+
+void flm_nthw_stat_rel_done_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_stat_rel_done);
+}
+
+void flm_nthw_stat_rel_ignore_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_rel_ignore_cnt);
+}
+
+void flm_nthw_stat_rel_ignore_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_stat_rel_ignore);
+}
+
+void flm_nthw_stat_aul_done_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_aul_done_cnt);
+}
+
+void flm_nthw_stat_aul_done_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_stat_aul_done);
+}
+
+void flm_nthw_stat_aul_ignore_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_aul_ignore_cnt);
+}
+
+void flm_nthw_stat_aul_ignore_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_stat_aul_ignore);
+}
+
+void flm_nthw_stat_aul_fail_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_aul_fail_cnt);
+}
+
+void flm_nthw_stat_aul_fail_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_stat_aul_fail);
+}
+
+void flm_nthw_stat_tul_done_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_tul_done_cnt);
+}
+
+void flm_nthw_stat_tul_done_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_stat_tul_done);
+}
+
+void flm_nthw_stat_flows_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_flows_cnt);
+}
+
+void flm_nthw_stat_flows_update(const struct flm_nthw *p)
+{
+	nthw_register_update(p->mp_stat_flows);
+}
+
+void flm_nthw_stat_sta_done_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_sta_done_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_sta_done_cnt);
+}
+
+void flm_nthw_stat_sta_done_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_sta_done);
+	nthw_register_update(p->mp_stat_sta_done);
+}
+
+void flm_nthw_stat_inf_done_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_inf_done_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_inf_done_cnt);
+}
+
+void flm_nthw_stat_inf_done_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_inf_done);
+	nthw_register_update(p->mp_stat_inf_done);
+}
+
+void flm_nthw_stat_inf_skip_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_inf_skip_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_inf_skip_cnt);
+}
+
+void flm_nthw_stat_inf_skip_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_inf_skip);
+	nthw_register_update(p->mp_stat_inf_skip);
+}
+
+void flm_nthw_stat_pck_hit_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_pck_hit_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_pck_hit_cnt);
+}
+
+void flm_nthw_stat_pck_hit_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_pck_hit);
+	nthw_register_update(p->mp_stat_pck_hit);
+}
+
+void flm_nthw_stat_pck_miss_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_pck_miss_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_pck_miss_cnt);
+}
+
+void flm_nthw_stat_pck_miss_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_pck_miss);
+	nthw_register_update(p->mp_stat_pck_miss);
+}
+
+void flm_nthw_stat_pck_unh_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_pck_unh_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_pck_unh_cnt);
+}
+
+void flm_nthw_stat_pck_unh_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_pck_unh);
+	nthw_register_update(p->mp_stat_pck_unh);
+}
+
+void flm_nthw_stat_pck_dis_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_pck_dis_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_pck_dis_cnt);
+}
+
+void flm_nthw_stat_pck_dis_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_pck_dis);
+	nthw_register_update(p->mp_stat_pck_dis);
+}
+
+void flm_nthw_stat_csh_hit_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_csh_hit_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_csh_hit_cnt);
+}
+
+void flm_nthw_stat_csh_hit_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_csh_hit);
+	nthw_register_update(p->mp_stat_csh_hit);
+}
+
+void flm_nthw_stat_csh_miss_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_csh_miss_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_csh_miss_cnt);
+}
+
+void flm_nthw_stat_csh_miss_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_csh_miss);
+	nthw_register_update(p->mp_stat_csh_miss);
+}
+
+void flm_nthw_stat_csh_unh_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_csh_unh_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_csh_unh_cnt);
+}
+
+void flm_nthw_stat_csh_unh_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_csh_unh);
+	nthw_register_update(p->mp_stat_csh_unh);
+}
+
+void flm_nthw_stat_cuc_start_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_cuc_start_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_cuc_start_cnt);
+}
+
+void flm_nthw_stat_cuc_start_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_cuc_start);
+	nthw_register_update(p->mp_stat_cuc_start);
+}
+
+void flm_nthw_stat_cuc_move_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	assert(p->mp_stat_cuc_move_cnt);
+
+	if (get)
+		*val = nthw_field_get_val32(p->mp_stat_cuc_move_cnt);
+}
+
+void flm_nthw_stat_cuc_move_update(const struct flm_nthw *p)
+{
+	assert(p->mp_stat_cuc_move);
+	nthw_register_update(p->mp_stat_cuc_move);
+}
+
+void flm_nthw_scrub_select(const struct flm_nthw *p, uint32_t val)
+{
+	assert(p->mp_scrub_ctrl_adr);
+	nthw_field_set_val32(p->mp_scrub_ctrl_adr, val);
+}
+
+void flm_nthw_scrub_cnt(const struct flm_nthw *p, uint32_t val)
+{
+	assert(p->mp_scrub_ctrl_cnt);
+	nthw_field_set_val32(p->mp_scrub_ctrl_cnt, val);
+}
+
+void flm_nthw_scrub_t(const struct flm_nthw *p, uint32_t val)
+{
+	assert(p->mp_scrub_data_t);
+	nthw_field_set_val32(p->mp_scrub_data_t, val);
+}
+
+void flm_nthw_scrub_r(const struct flm_nthw *p, uint32_t val)
+{
+	assert(p->mp_scrub_data_r);
+	nthw_field_set_val32(p->mp_scrub_data_r, val);
+}
+
+void flm_nthw_scrub_del(const struct flm_nthw *p, uint32_t val)
+{
+	assert(p->mp_scrub_data_del);
+	nthw_field_set_val32(p->mp_scrub_data_del, val);
+}
+
+void flm_nthw_scrub_inf(const struct flm_nthw *p, uint32_t val)
+{
+	assert(p->mp_scrub_data_inf);
+	nthw_field_set_val32(p->mp_scrub_data_inf, val);
+}
+
+void flm_nthw_scrub_flush(const struct flm_nthw *p)
+{
+	assert(p->mp_scrub_ctrl);
+	assert(p->mp_scrub_data);
+	nthw_register_flush(p->mp_scrub_ctrl, 1);
+	nthw_register_flush(p->mp_scrub_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.h
new file mode 100644
index 0000000000..5cc95ab03c
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.h
@@ -0,0 +1,433 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_FLM_H__
+#define __FLOW_NTHW_FLM_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct flm_nthw;
+
+typedef struct flm_nthw flm_nthw_t;
+
+struct flm_nthw *flm_nthw_new(void);
+void flm_nthw_delete(struct flm_nthw *p);
+int flm_nthw_init(struct flm_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+void flm_nthw_set_debug_mode(struct flm_nthw *p, unsigned int n_debug_mode);
+
+/* Control */
+void flm_nthw_control_enable(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_init(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_lds(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_lfs(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_lis(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_uds(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_uis(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_rds(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_ris(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_pds(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_pis(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_crcwr(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_crcrd(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_rbl(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_eab(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_split_sdram_usage(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_control_flush(const struct flm_nthw *p);
+
+/* Status */
+void flm_nthw_status_calib_success(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_status_calib_fail(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_status_initdone(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_status_idle(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_status_critical(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_status_panic(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_status_crcerr(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_status_eft_bp(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_status_cache_buf_crit(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_status_flush(const struct flm_nthw *p);
+void flm_nthw_status_update(const struct flm_nthw *p);
+
+/* Scan */
+void flm_nthw_scan_i(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_scan_flush(const struct flm_nthw *p);
+
+/* Load BIN */
+void flm_nthw_load_bin(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_load_bin_flush(const struct flm_nthw *p);
+
+/* Load LPS */
+void flm_nthw_load_lps_update(const struct flm_nthw *p);
+void flm_nthw_load_lps_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+
+/* Load APS */
+void flm_nthw_load_aps_update(const struct flm_nthw *p);
+void flm_nthw_load_aps_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+
+/* Prio */
+void flm_nthw_prio_limit0(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_prio_ft0(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_prio_limit1(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_prio_ft1(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_prio_limit2(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_prio_ft2(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_prio_limit3(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_prio_ft3(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_prio_flush(const struct flm_nthw *p);
+
+/* PST */
+void flm_nthw_pst_select(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_pst_cnt(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_pst_bp(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_pst_pp(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_pst_tp(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_pst_flush(const struct flm_nthw *p);
+
+/* RCP */
+void flm_nthw_rcp_select(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_cnt(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_lookup(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_qw0_dyn(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_qw0_ofs(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_qw0_sel(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_qw4_dyn(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_qw4_ofs(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_sw8_dyn(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_sw8_ofs(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_sw8_sel(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_sw9_dyn(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_sw9_ofs(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_mask(const struct flm_nthw *p, const uint32_t *val);
+void flm_nthw_rcp_kid(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_opn(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_ipn(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_byt_dyn(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_byt_ofs(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_txplm(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_auto_ipv4_mask(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_rcp_flush(const struct flm_nthw *p);
+
+/* Buf Ctrl */
+int flm_nthw_buf_ctrl_update(const struct flm_nthw *p, uint32_t *lrn_free, uint32_t *inf_avail,
+	uint32_t *sta_avail);
+
+/* Lrn Data */
+int flm_nthw_lrn_data_flush(const struct flm_nthw *p, const uint32_t *data, uint32_t records,
+	uint32_t words_per_record, uint32_t *handled_records,
+	uint32_t *lrn_free, uint32_t *inf_avail, uint32_t *sta_avail);
+
+/* Inf - Sta Data */
+int flm_nthw_inf_sta_data_update(const struct flm_nthw *p, uint32_t *inf_data,
+	uint32_t inf_word_count, uint32_t *sta_data,
+	uint32_t sta_word_count, uint32_t *lrn_free, uint32_t *inf_avail,
+	uint32_t *sta_avail);
+
+/* Stat Lrn Done */
+void flm_nthw_stat_lrn_done_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_lrn_done_update(const struct flm_nthw *p);
+
+/* Stat Lrn Ignore */
+void flm_nthw_stat_lrn_ignore_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_lrn_ignore_update(const struct flm_nthw *p);
+
+/* Stat Lrn Fail */
+void flm_nthw_stat_lrn_fail_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_lrn_fail_update(const struct flm_nthw *p);
+
+/* Stat Unl Done */
+void flm_nthw_stat_unl_done_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_unl_done_update(const struct flm_nthw *p);
+
+/* Stat Unl Ignore */
+void flm_nthw_stat_unl_ignore_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_unl_ignore_update(const struct flm_nthw *p);
+
+/* Stat Prb Done */
+void flm_nthw_stat_prb_done_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_prb_done_update(const struct flm_nthw *p);
+
+/* Stat Prb Ignore */
+void flm_nthw_stat_prb_ignore_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_prb_ignore_update(const struct flm_nthw *p);
+
+/* Stat Rel Done */
+void flm_nthw_stat_rel_done_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_rel_done_update(const struct flm_nthw *p);
+
+/* Stat Rel Ignore */
+void flm_nthw_stat_rel_ignore_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_rel_ignore_update(const struct flm_nthw *p);
+
+/* Stat Aul Done */
+void flm_nthw_stat_aul_done_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_aul_done_update(const struct flm_nthw *p);
+
+/* Stat Aul Ignore */
+void flm_nthw_stat_aul_ignore_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_aul_ignore_update(const struct flm_nthw *p);
+
+/* Stat Aul Fail */
+void flm_nthw_stat_aul_fail_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_aul_fail_update(const struct flm_nthw *p);
+
+/* Stat Tul Done */
+void flm_nthw_stat_tul_done_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_tul_done_update(const struct flm_nthw *p);
+
+/* Stat Flows */
+void flm_nthw_stat_flows_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_flows_update(const struct flm_nthw *p);
+
+/* Stat Sta Done */
+void flm_nthw_stat_sta_done_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_sta_done_update(const struct flm_nthw *p);
+
+/* Stat Inf Done */
+void flm_nthw_stat_inf_done_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_inf_done_update(const struct flm_nthw *p);
+
+/* Stat Inf Skip */
+void flm_nthw_stat_inf_skip_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_inf_skip_update(const struct flm_nthw *p);
+
+/* Stat Pck Hit */
+void flm_nthw_stat_pck_hit_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_pck_hit_update(const struct flm_nthw *p);
+
+/* Stat Pck Miss */
+void flm_nthw_stat_pck_miss_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_pck_miss_update(const struct flm_nthw *p);
+
+/* Stat Pck Unh */
+void flm_nthw_stat_pck_unh_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_pck_unh_update(const struct flm_nthw *p);
+
+/* Stat Pck Dis */
+void flm_nthw_stat_pck_dis_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_pck_dis_update(const struct flm_nthw *p);
+
+/* Stat Csh Hit */
+void flm_nthw_stat_csh_hit_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_csh_hit_update(const struct flm_nthw *p);
+
+/* Stat Csh Miss */
+void flm_nthw_stat_csh_miss_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_csh_miss_update(const struct flm_nthw *p);
+
+/* Stat Csh Unh */
+void flm_nthw_stat_csh_unh_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_csh_unh_update(const struct flm_nthw *p);
+
+/* Stat Cuc Start */
+void flm_nthw_stat_cuc_start_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_cuc_start_update(const struct flm_nthw *p);
+
+/* Stat Cuc Move */
+void flm_nthw_stat_cuc_move_cnt(const struct flm_nthw *p, uint32_t *val, int get);
+void flm_nthw_stat_cuc_move_update(const struct flm_nthw *p);
+
+/* Scrubber profile memory */
+void flm_nthw_scrub_select(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_scrub_cnt(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_scrub_t(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_scrub_r(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_scrub_del(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_scrub_inf(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_scrub_flush(const struct flm_nthw *p);
+
+struct flm_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+	void *mp_rac;
+
+	nthw_module_t *m_flm;
+
+	nthw_register_t *mp_control;
+	nthw_field_t *mp_control_enable;
+	nthw_field_t *mp_control_init;
+	nthw_field_t *mp_control_lds;
+	nthw_field_t *mp_control_lfs;
+	nthw_field_t *mp_control_lis;
+	nthw_field_t *mp_control_uds;
+	nthw_field_t *mp_control_uis;
+	nthw_field_t *mp_control_rds;
+	nthw_field_t *mp_control_ris;
+	nthw_field_t *mp_control_pds;
+	nthw_field_t *mp_control_pis;
+	nthw_field_t *mp_control_crcwr;
+	nthw_field_t *mp_control_crcrd;
+	nthw_field_t *mp_control_rbl;
+	nthw_field_t *mp_control_eab;
+	nthw_field_t *mp_control_split_sdram_usage;
+	nthw_field_t *mp_control_calib_recalibrate;
+
+	nthw_register_t *mp_status;
+	nthw_field_t *mp_status_calib_success;
+	nthw_field_t *mp_status_calib_fail;
+	nthw_field_t *mp_status_initdone;
+	nthw_field_t *mp_status_idle;
+	nthw_field_t *mp_status_critical;
+	nthw_field_t *mp_status_panic;
+	nthw_field_t *mp_status_crcerr;
+	nthw_field_t *mp_status_eft_bp;
+	nthw_field_t *mp_status_cache_buf_critical;
+
+	nthw_register_t *mp_timeout;
+	nthw_field_t *mp_timeout_t;
+
+	nthw_register_t *mp_scan;
+	nthw_field_t *mp_scan_i;
+
+	nthw_register_t *mp_load_bin;
+	nthw_field_t *mp_load_bin_bin;
+
+	nthw_register_t *mp_load_lps;
+	nthw_field_t *mp_load_lps_lps;
+
+	nthw_register_t *mp_load_aps;
+	nthw_field_t *mp_load_aps_aps;
+
+	nthw_register_t *mp_prio;
+	nthw_field_t *mp_prio_limit0;
+	nthw_field_t *mp_prio_ft0;
+	nthw_field_t *mp_prio_limit1;
+	nthw_field_t *mp_prio_ft1;
+	nthw_field_t *mp_prio_limit2;
+	nthw_field_t *mp_prio_ft2;
+	nthw_field_t *mp_prio_limit3;
+	nthw_field_t *mp_prio_ft3;
+
+	nthw_register_t *mp_pst_ctrl;
+	nthw_field_t *mp_pst_ctrl_adr;
+	nthw_field_t *mp_pst_ctrl_cnt;
+	nthw_register_t *mp_pst_data;
+	nthw_field_t *mp_pst_data_bp;
+	nthw_field_t *mp_pst_data_pp;
+	nthw_field_t *mp_pst_data_tp;
+
+	nthw_register_t *mp_rcp_ctrl;
+	nthw_field_t *mp_rcp_ctrl_adr;
+	nthw_field_t *mp_rcp_ctrl_cnt;
+	nthw_register_t *mp_rcp_data;
+	nthw_field_t *mp_rcp_data_lookup;
+	nthw_field_t *mp_rcp_data_qw0_dyn;
+	nthw_field_t *mp_rcp_data_qw0_ofs;
+	nthw_field_t *mp_rcp_data_qw0_sel;
+	nthw_field_t *mp_rcp_data_qw4_dyn;
+	nthw_field_t *mp_rcp_data_qw4_ofs;
+	nthw_field_t *mp_rcp_data_sw8_dyn;
+	nthw_field_t *mp_rcp_data_sw8_ofs;
+	nthw_field_t *mp_rcp_data_sw8_sel;
+	nthw_field_t *mp_rcp_data_sw9_dyn;
+	nthw_field_t *mp_rcp_data_sw9_ofs;
+	nthw_field_t *mp_rcp_data_mask;
+	nthw_field_t *mp_rcp_data_kid;
+	nthw_field_t *mp_rcp_data_opn;
+	nthw_field_t *mp_rcp_data_ipn;
+	nthw_field_t *mp_rcp_data_byt_dyn;
+	nthw_field_t *mp_rcp_data_byt_ofs;
+	nthw_field_t *mp_rcp_data_txplm;
+	nthw_field_t *mp_rcp_data_auto_ipv4_mask;
+
+	nthw_register_t *mp_buf_ctrl;
+	nthw_field_t *mp_buf_ctrl_lrn_free;
+	nthw_field_t *mp_buf_ctrl_inf_avail;
+	nthw_field_t *mp_buf_ctrl_sta_avail;
+
+	nthw_register_t *mp_lrn_data;
+	nthw_register_t *mp_inf_data;
+	nthw_register_t *mp_sta_data;
+
+	nthw_register_t *mp_stat_lrn_done;
+	nthw_field_t *mp_stat_lrn_done_cnt;
+
+	nthw_register_t *mp_stat_lrn_ignore;
+	nthw_field_t *mp_stat_lrn_ignore_cnt;
+
+	nthw_register_t *mp_stat_lrn_fail;
+	nthw_field_t *mp_stat_lrn_fail_cnt;
+
+	nthw_register_t *mp_stat_unl_done;
+	nthw_field_t *mp_stat_unl_done_cnt;
+
+	nthw_register_t *mp_stat_unl_ignore;
+	nthw_field_t *mp_stat_unl_ignore_cnt;
+
+	nthw_register_t *mp_stat_prb_done;
+	nthw_field_t *mp_stat_prb_done_cnt;
+
+	nthw_register_t *mp_stat_prb_ignore;
+	nthw_field_t *mp_stat_prb_ignore_cnt;
+
+	nthw_register_t *mp_stat_rel_done;
+	nthw_field_t *mp_stat_rel_done_cnt;
+
+	nthw_register_t *mp_stat_rel_ignore;
+	nthw_field_t *mp_stat_rel_ignore_cnt;
+
+	nthw_register_t *mp_stat_aul_done;
+	nthw_field_t *mp_stat_aul_done_cnt;
+
+	nthw_register_t *mp_stat_aul_ignore;
+	nthw_field_t *mp_stat_aul_ignore_cnt;
+
+	nthw_register_t *mp_stat_aul_fail;
+	nthw_field_t *mp_stat_aul_fail_cnt;
+
+	nthw_register_t *mp_stat_tul_done;
+	nthw_field_t *mp_stat_tul_done_cnt;
+
+	nthw_register_t *mp_stat_flows;
+	nthw_field_t *mp_stat_flows_cnt;
+
+	nthw_register_t *mp_stat_sta_done;
+	nthw_field_t *mp_stat_sta_done_cnt;
+
+	nthw_register_t *mp_stat_inf_done;
+	nthw_field_t *mp_stat_inf_done_cnt;
+
+	nthw_register_t *mp_stat_inf_skip;
+	nthw_field_t *mp_stat_inf_skip_cnt;
+
+	nthw_register_t *mp_stat_pck_hit;
+	nthw_field_t *mp_stat_pck_hit_cnt;
+
+	nthw_register_t *mp_stat_pck_miss;
+	nthw_field_t *mp_stat_pck_miss_cnt;
+
+	nthw_register_t *mp_stat_pck_unh;
+	nthw_field_t *mp_stat_pck_unh_cnt;
+
+	nthw_register_t *mp_stat_pck_dis;
+	nthw_field_t *mp_stat_pck_dis_cnt;
+
+	nthw_register_t *mp_stat_csh_hit;
+	nthw_field_t *mp_stat_csh_hit_cnt;
+
+	nthw_register_t *mp_stat_csh_miss;
+	nthw_field_t *mp_stat_csh_miss_cnt;
+
+	nthw_register_t *mp_stat_csh_unh;
+	nthw_field_t *mp_stat_csh_unh_cnt;
+
+	nthw_register_t *mp_stat_cuc_start;
+	nthw_field_t *mp_stat_cuc_start_cnt;
+
+	nthw_register_t *mp_stat_cuc_move;
+	nthw_field_t *mp_stat_cuc_move_cnt;
+
+	nthw_register_t *mp_scrub_ctrl;
+	nthw_field_t *mp_scrub_ctrl_adr;
+	nthw_field_t *mp_scrub_ctrl_cnt;
+
+	nthw_register_t *mp_scrub_data;
+	nthw_field_t *mp_scrub_data_t;
+	nthw_field_t *mp_scrub_data_r;
+	nthw_field_t *mp_scrub_data_del;
+	nthw_field_t *mp_scrub_data_inf;
+};
+
+#endif	/* __FLOW_NTHW_FLM_H__ */
diff --git a/drivers/net/ntnic/nthw/nthw_rac.c b/drivers/net/ntnic/nthw/nthw_rac.c
index 2aef0c148f..8be6f7623e 100644
--- a/drivers/net/ntnic/nthw/nthw_rac.c
+++ b/drivers/net/ntnic/nthw/nthw_rac.c
@@ -12,6 +12,7 @@
 
 #include <pthread.h>
 
+#define RAB_DMA_WAIT (1000000)
 
 #define RAB_READ (0x01)
 #define RAB_WRITE (0x02)
@@ -386,6 +387,186 @@ void nthw_rac_bar0_write32(const struct fpga_info_s *p_fpga_info, uint32_t reg_a
 		dst_addr[i] = p_data[i];
 }
 
+int nthw_rac_rab_dma_begin(nthw_rac_t *p)
+{
+	const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info;
+	const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str;
+
+	pthread_mutex_lock(&p->m_mutex);
+
+	if (p->m_dma_active) {
+		pthread_mutex_unlock(&p->m_mutex);
+		NT_LOG(ERR, NTHW,
+			"%s: DMA begin requested, but a DMA transaction is already active\n",
+			p_adapter_id_str);
+		return -1;
+	}
+
+	p->m_dma_active = true;
+
+	return 0;
+}
+
+static void nthw_rac_rab_dma_activate(nthw_rac_t *p)
+{
+	const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info;
+	const uint32_t completion = RAB_COMPLETION << RAB_OPR_LO;
+
+	/* Write completion word */
+	p->m_dma_in_buf[p->m_dma_in_ptr_wr] = completion;
+	p->m_dma_in_ptr_wr = (uint16_t)((p->m_dma_in_ptr_wr + 1) & (RAB_DMA_BUF_CNT - 1));
+
+	/* Clear output completion word */
+	p->m_dma_out_buf[p->m_dma_out_ptr_rd] = 0;
+
+	/* Update DMA pointer and start transfer */
+	nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_DMA_IB_WR_ADDR,
+		(uint32_t)(p->m_dma_in_ptr_wr * sizeof(uint32_t)));
+}
+
+static int nthw_rac_rab_dma_wait(nthw_rac_t *p)
+{
+	const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info;
+	const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str;
+	const uint32_t completion = RAB_COMPLETION << RAB_OPR_LO;
+	uint32_t i;
+
+	for (i = 0; i < RAB_DMA_WAIT; i++) {
+		nt_os_wait_usec_poll(1);
+
+		if ((p->m_dma_out_buf[p->m_dma_out_ptr_rd] & completion) == completion)
+			break;
+	}
+
+	if (i == RAB_DMA_WAIT) {
+		NT_LOG(ERR, NTHW, "%s: RAB: Unexpected value of completion (0x%08X)\n",
+			p_adapter_id_str, p->m_dma_out_buf[p->m_dma_out_ptr_rd]);
+		return -1;
+	}
+
+	p->m_dma_out_ptr_rd = (uint16_t)((p->m_dma_out_ptr_rd + 1) & (RAB_DMA_BUF_CNT - 1));
+	p->m_in_free = RAB_DMA_BUF_CNT;
+
+	return 0;
+}
+
+int nthw_rac_rab_dma_commit(nthw_rac_t *p)
+{
+	int ret;
+
+	if (!p->m_dma_active) {
+		/* Expecting mutex not to be locked! */
+		assert(0);      /* alert developer that something is wrong */
+		return -1;
+	}
+
+	nthw_rac_rab_dma_activate(p);
+	ret = nthw_rac_rab_dma_wait(p);
+
+	p->m_dma_active = false;
+
+	pthread_mutex_unlock(&p->m_mutex);
+
+	return ret;
+}
+
+uint32_t nthw_rac_rab_get_free(nthw_rac_t *p)
+{
+	if (!p->m_dma_active) {
+		/* Expecting mutex not to be locked! */
+		assert(0);      /* alert developer that something is wrong */
+		return -1;
+	}
+
+	return p->m_in_free;
+}
+
+int nthw_rac_rab_write32_dma(nthw_rac_t *p, nthw_rab_bus_id_t bus_id, uint32_t address,
+	uint32_t word_cnt, const uint32_t *p_data)
+{
+	const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info;
+	const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str;
+
+	if (word_cnt == 0 || word_cnt > 256) {
+		NT_LOG(ERR, NTHW,
+			"%s: Failed rab dma write length check - bus: %d addr: 0x%08X wordcount: %d - inBufFree: 0x%08X\n",
+			p_adapter_id_str, bus_id, address, word_cnt, p->m_in_free);
+		assert(0);      /* alert developer that something is wrong */
+		return -1;
+	}
+
+	if (p->m_in_free < (word_cnt + 3)) {
+		/*
+		 * No more memory available.
+		 * nthw_rac_rab_dma_commit() needs to be called to start and finish pending
+		 * transfers.
+		 */
+		return -1;
+	}
+
+	p->m_in_free -= (word_cnt + 1);
+
+	/* Write the command word */
+	p->m_dma_in_buf[p->m_dma_in_ptr_wr] = (RAB_WRITE << RAB_OPR_LO) |
+		((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) | (bus_id << RAB_BUSID_LO) |
+		address;
+	p->m_dma_in_ptr_wr = (uint16_t)((p->m_dma_in_ptr_wr + 1) & (RAB_DMA_BUF_CNT - 1));
+
+	for (uint32_t i = 0; i < word_cnt; i++) {
+		p->m_dma_in_buf[p->m_dma_in_ptr_wr] = p_data[i];
+		p->m_dma_in_ptr_wr = (uint16_t)((p->m_dma_in_ptr_wr + 1) & (RAB_DMA_BUF_CNT - 1));
+	}
+
+	return 0;
+}
+
+int nthw_rac_rab_read32_dma(nthw_rac_t *p, nthw_rab_bus_id_t bus_id, uint32_t address,
+	uint32_t word_cnt, struct dma_buf_ptr *buf_ptr)
+{
+	const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info;
+	const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str;
+
+	if (word_cnt == 0 || word_cnt > 256) {
+		NT_LOG(ERR, NTHW,
+			"%s: Failed rab dma read length check - bus: %d addr: 0x%08X wordcount: %d - inBufFree: 0x%08X\n",
+			p_adapter_id_str, bus_id, address, word_cnt, p->m_in_free);
+		assert(0);      /* alert developer that something is wrong */
+		return -1;
+	}
+
+	if ((word_cnt + 3) > RAB_DMA_BUF_CNT) {
+		NT_LOG(ERR, NTHW,
+			"%s: Failed rab dma read length check - bus: %d addr: 0x%08X wordcount: %d",
+			p_adapter_id_str, bus_id, address, word_cnt);
+		return -1;
+	}
+
+	if (p->m_in_free < 3) {
+		/*
+		 * No more memory available.
+		 * nthw_rac_rab_dma_commit() needs to be called to start and finish pending
+		 * transfers.
+		 */
+		return -1;
+	}
+
+	p->m_in_free -= 1;
+
+	/* Write the command word */
+	p->m_dma_in_buf[p->m_dma_in_ptr_wr] = (RAB_READ << RAB_OPR_LO) |
+		((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) | (bus_id << RAB_BUSID_LO) |
+		address;
+	p->m_dma_in_ptr_wr = (uint16_t)((p->m_dma_in_ptr_wr + 1) & (RAB_DMA_BUF_CNT - 1));
+
+	buf_ptr->index = p->m_dma_out_ptr_rd;
+	buf_ptr->size = RAB_DMA_BUF_CNT;
+	buf_ptr->base = p->m_dma_out_buf;
+	p->m_dma_out_ptr_rd =
+		(uint16_t)((p->m_dma_out_ptr_rd + word_cnt) & (RAB_DMA_BUF_CNT - 1U));
+
+	return 0;
+}
+
 int nthw_rac_rab_write32(nthw_rac_t *p, bool trc, nthw_rab_bus_id_t bus_id, uint32_t address,
 	uint32_t word_cnt, const uint32_t *p_data)
 {
diff --git a/drivers/net/ntnic/nthw/nthw_rac.h b/drivers/net/ntnic/nthw/nthw_rac.h
index c16ff77189..c64dac9da9 100644
--- a/drivers/net/ntnic/nthw/nthw_rac.h
+++ b/drivers/net/ntnic/nthw/nthw_rac.h
@@ -140,11 +140,20 @@ int nthw_rac_rab_reset(nthw_rac_t *p);
 
 int nthw_rac_rab_write32(nthw_rac_t *p, bool trc, nthw_rab_bus_id_t bus_id, uint32_t address,
 	uint32_t word_cnt, const uint32_t *p_data);
+int nthw_rac_rab_write32_dma(nthw_rac_t *p, nthw_rab_bus_id_t bus_id, uint32_t address,
+	uint32_t word_cnt, const uint32_t *p_data);
 int nthw_rac_rab_read32(nthw_rac_t *p, bool trc, nthw_rab_bus_id_t bus_id, uint32_t address,
 	uint32_t word_cnt, uint32_t *p_data);
+int nthw_rac_rab_read32_dma(nthw_rac_t *p, nthw_rab_bus_id_t bus_id, uint32_t address,
+	uint32_t word_cnt, struct dma_buf_ptr *buf_ptr);
+
+uint32_t nthw_rac_rab_get_free(nthw_rac_t *p);
 
 int nthw_rac_rab_flush(nthw_rac_t *p);
 
+int nthw_rac_rab_dma_begin(nthw_rac_t *p);
+int nthw_rac_rab_dma_commit(nthw_rac_t *p);
+
 void nthw_rac_bar0_read32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr,
 	uint32_t word_cnt, uint32_t *p_data);
 void nthw_rac_bar0_write32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr,
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index 7d48e4012e..01254f7f5d 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -15,6 +15,7 @@
 
 #define MOD_UNKNOWN (0L)/* Unknown/uninitialized - keep this as the first element */
 #define MOD_CAT (0x30b447c2UL)
+#define MOD_FLM (0xe7ba53a4UL)
 #define MOD_GFG (0xfc423807UL)
 #define MOD_GMF (0x68b1d15aUL)
 #define MOD_GPIO_PHY (0xbbe81659UL)
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index 96676bf8d4..0c153e21ed 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -14,6 +14,7 @@
 #define _NTHW_FPGA_REG_DEFS_
 
 #include "nthw_fpga_reg_defs_cat.h"
+#include "nthw_fpga_reg_defs_flm.h"
 #include "nthw_fpga_reg_defs_gfg.h"
 #include "nthw_fpga_reg_defs_gmf.h"
 #include "nthw_fpga_reg_defs_gpio_phy.h"
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_flm.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_flm.h
new file mode 100644
index 0000000000..1f8678779e
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_flm.h
@@ -0,0 +1,242 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_flm.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_FLM_
+#define _NTHW_FPGA_REG_DEFS_FLM_
+
+/* FLM */
+#define NTHW_MOD_FLM (0xe7ba53a4UL)
+#define FLM_BUF_CTRL (0x2d7ba0b7UL)
+#define FLM_BUF_CTRL_INF_AVAIL (0x55993c46UL)
+#define FLM_BUF_CTRL_LRN_FREE (0x60b97a24UL)
+#define FLM_BUF_CTRL_STA_AVAIL (0x44abe7c4UL)
+#define FLM_CONTROL (0xdbb393a2UL)
+#define FLM_CONTROL_CALIB_RECALIBRATE (0xd787824aUL)
+#define FLM_CONTROL_CRCRD (0x35ba7f13UL)
+#define FLM_CONTROL_CRCWR (0xbc193e07UL)
+#define FLM_CONTROL_EAB (0xa09637c2UL)
+#define FLM_CONTROL_ENABLE (0x5d80d95eUL)
+#define FLM_CONTROL_INIT (0x69b06e85UL)
+#define FLM_CONTROL_LDS (0xb880d8faUL)
+#define FLM_CONTROL_LFS (0x8ab6ba78UL)
+#define FLM_CONTROL_LIS (0xd2ea6b7UL)
+#define FLM_CONTROL_PDS (0xadbc82eeUL)
+#define FLM_CONTROL_PIS (0x1812fca3UL)
+#define FLM_CONTROL_RBL (0x756afcf3UL)
+#define FLM_CONTROL_RDS (0xae385680UL)
+#define FLM_CONTROL_RIS (0x1b9628cdUL)
+#define FLM_CONTROL_SPLIT_SDRAM_USAGE (0x71e7a8a4UL)
+#define FLM_CONTROL_UDS (0xab774005UL)
+#define FLM_CONTROL_UIS (0x1ed93e48UL)
+#define FLM_CONTROL_WPD (0x58ec6f9UL)
+#define FLM_INF_DATA (0xba19f6ccUL)
+#define FLM_INF_DATA_BYTES (0x480dab67UL)
+#define FLM_INF_DATA_BYT_A (0xb9920f4UL)
+#define FLM_INF_DATA_BYT_B (0x9290714eUL)
+#define FLM_INF_DATA_CAUSE (0x94e9716UL)
+#define FLM_INF_DATA_EOR (0xd81a867eUL)
+#define FLM_INF_DATA_ID (0x23a04258UL)
+#define FLM_INF_DATA_PACKETS (0x33a4ab9eUL)
+#define FLM_INF_DATA_PCK_A (0x3967b7a0UL)
+#define FLM_INF_DATA_PCK_B (0xa06ee61aUL)
+#define FLM_INF_DATA_RTX_A (0x900996cfUL)
+#define FLM_INF_DATA_RTX_B (0x900c775UL)
+#define FLM_INF_DATA_TCP_A (0xdc945df1UL)
+#define FLM_INF_DATA_TCP_B (0x459d0c4bUL)
+#define FLM_INF_DATA_TS (0x5f1fab83UL)
+#define FLM_LOAD_APS (0x4e7601e5UL)
+#define FLM_LOAD_APS_APS (0x504ad426UL)
+#define FLM_LOAD_BIN (0xb4367a7dUL)
+#define FLM_LOAD_BIN_BIN (0x274bb543UL)
+#define FLM_LOAD_LPS (0x46ae92b6UL)
+#define FLM_LOAD_LPS_LPS (0x394526b5UL)
+#define FLM_LRN_CTRL (0x11050e66UL)
+#define FLM_LRN_CTRL_FREE (0x4193813dUL)
+#define FLM_LRN_DATA (0xbed48c7fUL)
+#define FLM_LRN_DATA_ADJ (0x130ed7UL)
+#define FLM_LRN_DATA_COLOR (0x33d0a7f2UL)
+#define FLM_LRN_DATA_DSCP (0x5eab148eUL)
+#define FLM_LRN_DATA_ENT (0x7fa73e2UL)
+#define FLM_LRN_DATA_EOR (0xf782e796UL)
+#define FLM_LRN_DATA_FILL (0x768aba23UL)
+#define FLM_LRN_DATA_FT (0x4e9221cfUL)
+#define FLM_LRN_DATA_FT_MBR (0x48f095acUL)
+#define FLM_LRN_DATA_FT_MISS (0xea062e35UL)
+#define FLM_LRN_DATA_GFI (0xafa1415dUL)
+#define FLM_LRN_DATA_ID (0xd4bd2d64UL)
+#define FLM_LRN_DATA_KID (0x5f92d84bUL)
+#define FLM_LRN_DATA_MBR_ID1 (0x9931440eUL)
+#define FLM_LRN_DATA_MBR_ID2 (0x3815b4UL)
+#define FLM_LRN_DATA_MBR_ID3 (0x773f2522UL)
+#define FLM_LRN_DATA_MBR_ID4 (0xe95bb081UL)
+#define FLM_LRN_DATA_NAT_EN (0x9f4035a4UL)
+#define FLM_LRN_DATA_NAT_IP (0xc9fa47cbUL)
+#define FLM_LRN_DATA_NAT_PORT (0x5f8f57d0UL)
+#define FLM_LRN_DATA_NOFI (0x3d36f27bUL)
+#define FLM_LRN_DATA_OP (0x983d5e9fUL)
+#define FLM_LRN_DATA_PRIO (0xf7f55b0eUL)
+#define FLM_LRN_DATA_PROT (0x2bca3564UL)
+#define FLM_LRN_DATA_QFI (0xb70a9e9fUL)
+#define FLM_LRN_DATA_QW0 (0xcd0a7417UL)
+#define FLM_LRN_DATA_QW4 (0xca67b00eUL)
+#define FLM_LRN_DATA_RATE (0x5c250baeUL)
+#define FLM_LRN_DATA_RQI (0xb0cfa450UL)
+#define FLM_LRN_DATA_SCRUB_PROF (0xc3730f6bUL)
+#define FLM_LRN_DATA_SIZE (0x740910fdUL)
+#define FLM_LRN_DATA_STAT_PROF (0xded894eaUL)
+#define FLM_LRN_DATA_SW8 (0xc055284bUL)
+#define FLM_LRN_DATA_SW9 (0xb75218ddUL)
+#define FLM_LRN_DATA_TAU (0xea8196fcUL)
+#define FLM_LRN_DATA_TEID (0xf62ca024UL)
+#define FLM_LRN_DATA_TTL (0xb95fd828UL)
+#define FLM_LRN_DATA_VOL_IDX (0xabc86ffbUL)
+#define FLM_PRIO (0x5ed7bcbeUL)
+#define FLM_PRIO_FT0 (0x9ef34f69UL)
+#define FLM_PRIO_FT1 (0xe9f47fffUL)
+#define FLM_PRIO_FT2 (0x70fd2e45UL)
+#define FLM_PRIO_FT3 (0x7fa1ed3UL)
+#define FLM_PRIO_LIMIT0 (0xcce9cfe8UL)
+#define FLM_PRIO_LIMIT1 (0xbbeeff7eUL)
+#define FLM_PRIO_LIMIT2 (0x22e7aec4UL)
+#define FLM_PRIO_LIMIT3 (0x55e09e52UL)
+#define FLM_PST_CTRL (0x3e2b004bUL)
+#define FLM_PST_CTRL_ADR (0xfa8565c1UL)
+#define FLM_PST_CTRL_CNT (0xea8dfc10UL)
+#define FLM_PST_DATA (0x91fa8252UL)
+#define FLM_PST_DATA_BP (0x5f53d50fUL)
+#define FLM_PST_DATA_PP (0x27a7a5dcUL)
+#define FLM_PST_DATA_TP (0x43cb60d8UL)
+#define FLM_RCP_CTRL (0x8041d9eeUL)
+#define FLM_RCP_CTRL_ADR (0xb1a39fefUL)
+#define FLM_RCP_CTRL_CNT (0xa1ab063eUL)
+#define FLM_RCP_DATA (0x2f905bf7UL)
+#define FLM_RCP_DATA_A (0xec41ba43UL)
+#define FLM_RCP_DATA_AUTO_IPV4_MASK (0xa7818261UL)
+#define FLM_RCP_DATA_B (0x7548ebf9UL)
+#define FLM_RCP_DATA_BYT_DYN (0x28334583UL)
+#define FLM_RCP_DATA_BYT_OFS (0x8a3ac825UL)
+#define FLM_RCP_DATA_IPN (0x94f5d891UL)
+#define FLM_RCP_DATA_ITF (0xfe4295a7UL)
+#define FLM_RCP_DATA_KID (0xeca44cf9UL)
+#define FLM_RCP_DATA_LOOKUP (0x5d0f2e84UL)
+#define FLM_RCP_DATA_MASK (0xd97a1393UL)
+#define FLM_RCP_DATA_OPN (0x9078a423UL)
+#define FLM_RCP_DATA_QW0_DYN (0x28bd732dUL)
+#define FLM_RCP_DATA_QW0_OFS (0x8ab4fe8bUL)
+#define FLM_RCP_DATA_QW0_SEL (0x39adfaa9UL)
+#define FLM_RCP_DATA_QW4_DYN (0xdd3dd5edUL)
+#define FLM_RCP_DATA_QW4_OFS (0x7f34584bUL)
+#define FLM_RCP_DATA_SW8_DYN (0x8f5229c5UL)
+#define FLM_RCP_DATA_SW8_OFS (0x2d5ba463UL)
+#define FLM_RCP_DATA_SW8_SEL (0x9e42a041UL)
+#define FLM_RCP_DATA_SW9_DYN (0xb2320075UL)
+#define FLM_RCP_DATA_SW9_OFS (0x103b8dd3UL)
+#define FLM_RCP_DATA_TXPLM (0xbe56af35UL)
+#define FLM_SCAN (0xee586089UL)
+#define FLM_SCAN_I (0xe22d4ee5UL)
+#define FLM_SCRUB (0x690c7a66UL)
+#define FLM_SCRUB_I (0xc6a9dfe8UL)
+#define FLM_SCRUB_CTRL (0xc647074aUL)
+#define FLM_SCRUB_CTRL_ADR (0x3d584aa4UL)
+#define FLM_SCRUB_CTRL_CNT (0x2d50d375UL)
+#define FLM_SCRUB_DATA (0x69968553UL)
+#define FLM_SCRUB_DATA_DEL (0xc96d19b1UL)
+#define FLM_SCRUB_DATA_INF (0xc294ba37UL)
+#define FLM_SCRUB_DATA_R (0xc3ff3ba5UL)
+#define FLM_SCRUB_DATA_T (0x2a9c9e90UL)
+#define FLM_STAT (0xa532c06UL)
+#define FLM_STAT_I (0x215c23d1UL)
+#define FLM_STATUS (0x10f57a96UL)
+#define FLM_STATUS_CACHE_BUFFER_CRITICAL (0x39f44c00UL)
+#define FLM_STATUS_CALIB_FAIL (0xb59e2af6UL)
+#define FLM_STATUS_CALIB_SUCCESS (0x9c031e4fUL)
+#define FLM_STATUS_CRCERR (0xcd852b33UL)
+#define FLM_STATUS_CRITICAL (0xe9e1b478UL)
+#define FLM_STATUS_EFT_BP (0xf60fc391UL)
+#define FLM_STATUS_EFT_EVICT_BP (0xf4dd216fUL)
+#define FLM_STATUS_IDLE (0xd02fd0e7UL)
+#define FLM_STATUS_INITDONE (0xdd6bdbd8UL)
+#define FLM_STATUS_PANIC (0xf676390fUL)
+#define FLM_STAT_AUL_DONE (0x747800bbUL)
+#define FLM_STAT_AUL_DONE_CNT (0x6b744caeUL)
+#define FLM_STAT_AUL_FAIL (0xe272cb59UL)
+#define FLM_STAT_AUL_FAIL_CNT (0x697b6247UL)
+#define FLM_STAT_AUL_IGNORE (0x49aa46f4UL)
+#define FLM_STAT_AUL_IGNORE_CNT (0x37721e3bUL)
+#define FLM_STAT_CSH_HIT (0xd0dca28cUL)
+#define FLM_STAT_CSH_HIT_CNT (0xc7a41ba4UL)
+#define FLM_STAT_CSH_MISS (0xbc219a9fUL)
+#define FLM_STAT_CSH_MISS_CNT (0x4a66e57eUL)
+#define FLM_STAT_CSH_UNH (0x9f625827UL)
+#define FLM_STAT_CSH_UNH_CNT (0x79b8ac91UL)
+#define FLM_STAT_CUC_MOVE (0x381862c0UL)
+#define FLM_STAT_CUC_MOVE_CNT (0x868e1261UL)
+#define FLM_STAT_CUC_START (0x617a68acUL)
+#define FLM_STAT_CUC_START_CNT (0xbf953f79UL)
+#define FLM_STAT_FLOWS (0x3072544fUL)
+#define FLM_STAT_FLOWS_CNT (0x829b2631UL)
+#define FLM_STAT_INF_DONE (0x63dff05cUL)
+#define FLM_STAT_INF_DONE_CNT (0xf78de916UL)
+#define FLM_STAT_INF_SKIP (0x8b84458aUL)
+#define FLM_STAT_INF_SKIP_CNT (0xc0b9dd7dUL)
+#define FLM_STAT_LRN_DONE (0x67128aefUL)
+#define FLM_STAT_LRN_DONE_CNT (0xd81588feUL)
+#define FLM_STAT_LRN_FAIL (0xf118410dUL)
+#define FLM_STAT_LRN_FAIL_CNT (0xda1aa617UL)
+#define FLM_STAT_LRN_IGNORE (0x9a10a7f0UL)
+#define FLM_STAT_LRN_IGNORE_CNT (0x11c0f6a7UL)
+#define FLM_STAT_PCK_DIS (0x55e23053UL)
+#define FLM_STAT_PCK_DIS_CNT (0x9b13b227UL)
+#define FLM_STAT_PCK_HIT (0xc29c5c94UL)
+#define FLM_STAT_PCK_HIT_CNT (0xee930443UL)
+#define FLM_STAT_PCK_MISS (0xaf5f4237UL)
+#define FLM_STAT_PCK_MISS_CNT (0x7421a5baUL)
+#define FLM_STAT_PCK_UNH (0x8d22a63fUL)
+#define FLM_STAT_PCK_UNH_CNT (0x508fb376UL)
+#define FLM_STAT_PRB_DONE (0x3bc46ef0UL)
+#define FLM_STAT_PRB_DONE_CNT (0xcb3bc80dUL)
+#define FLM_STAT_PRB_IGNORE (0xf02dd3d9UL)
+#define FLM_STAT_PRB_IGNORE_CNT (0x588d1667UL)
+#define FLM_STAT_REL_DONE (0xe192aabdUL)
+#define FLM_STAT_REL_DONE_CNT (0xbe04b769UL)
+#define FLM_STAT_REL_IGNORE (0x29f33e6eUL)
+#define FLM_STAT_REL_IGNORE_CNT (0x99a6a156UL)
+#define FLM_STAT_STA_DONE (0x500f2e87UL)
+#define FLM_STAT_STA_DONE_CNT (0xbf276bbdUL)
+#define FLM_STAT_TUL_DONE (0x40233ff4UL)
+#define FLM_STAT_TUL_DONE_CNT (0xffcfd642UL)
+#define FLM_STAT_UNL_DONE (0xe950f75eUL)
+#define FLM_STAT_UNL_DONE_CNT (0xe9bdd9a2UL)
+#define FLM_STAT_UNL_IGNORE (0x497abbcaUL)
+#define FLM_STAT_UNL_IGNORE_CNT (0x1ba2b435UL)
+#define FLM_STA_DATA (0x89c92817UL)
+#define FLM_STA_DATA_EOR (0x90b004d5UL)
+#define FLM_STA_DATA_ID (0x3b14a2ffUL)
+#define FLM_STA_DATA_LDS (0xb92d607UL)
+#define FLM_STA_DATA_LFS (0x39a4b485UL)
+#define FLM_STA_DATA_LIS (0xbe3ca84aUL)
+#define FLM_STA_DATA_PDS (0x1eae8c13UL)
+#define FLM_STA_DATA_PIS (0xab00f25eUL)
+#define FLM_STA_DATA_RDS (0x1d2a587dUL)
+#define FLM_STA_DATA_RIS (0xa8842630UL)
+#define FLM_STA_DATA_UDS (0x18654ef8UL)
+#define FLM_STA_DATA_UIS (0xadcb30b5UL)
+#define FLM_TRSWIN (0xff97af47UL)
+#define FLM_TRSWIN_S (0x41ed83b1UL)
+#define FLM_TRTWIN (0x624097feUL)
+#define FLM_TRTWIN_T (0xc28c26aaUL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_FLM_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
diff --git a/drivers/net/ntnic/ntutil/nt_util.c b/drivers/net/ntnic/ntutil/nt_util.c
index a69a8e10c1..72aabad090 100644
--- a/drivers/net/ntnic/ntutil/nt_util.c
+++ b/drivers/net/ntnic/ntutil/nt_util.c
@@ -23,6 +23,12 @@ void nt_os_wait_usec(int val)
 	rte_delay_us_sleep(val);
 }
 
+/* spins in a waiting loop calling pause asm instruction uses RDTSC - precise wait */
+void nt_os_wait_usec_poll(int val)
+{
+	rte_delay_us(val);
+}
+
 uint64_t nt_os_get_time_monotonic_counter(void)
 {
 	return rte_get_timer_cycles();
diff --git a/drivers/net/ntnic/ntutil/nt_util.h b/drivers/net/ntnic/ntutil/nt_util.h
index 540cd615f2..d82e6d3248 100644
--- a/drivers/net/ntnic/ntutil/nt_util.h
+++ b/drivers/net/ntnic/ntutil/nt_util.h
@@ -22,6 +22,7 @@
 
 uint64_t nt_os_get_time_monotonic_counter(void);
 void nt_os_wait_usec(int val);
+void nt_os_wait_usec_poll(int val);
 
 static inline int min(int a, int b)
 {
-- 
2.45.0


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

* [PATCH v1 09/31] net/ntnic: add IP fragmenter (IFR) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (13 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 08/31] net/ntnic: add flow matcher (FLM) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 10/31] net/ntnic: add hasher (HSH) " Serhii Iliushyk
                   ` (36 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The IP Fragmenter module can fragment outgoing packets
based on a programmable MTU.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/meson.build                 |  1 +
 .../nthw/flow_api/flow_backend/flow_backend.c | 12 ++++
 .../ntnic/nthw/flow_filter/flow_nthw_ifr.c    | 68 +++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_ifr.h    | 43 ++++++++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |  1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |  1 +
 .../nthw/supported/nthw_fpga_reg_defs_ifr.h   | 42 ++++++++++++
 7 files changed, 168 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_ifr.h

diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 317b696d5f..1ca34d8b47 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -48,6 +48,7 @@ sources = files(
         'nthw/flow_api/flow_filter.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_flm.c',
+        'nthw/flow_filter/flow_nthw_ifr.c',
         'nthw/flow_filter/flow_nthw_info.c',
         'nthw/flow_filter/flow_nthw_km.c',
         'nthw/model/nthw_fpga_model.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index 8703a4c712..5d2c09d52a 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -6,6 +6,7 @@
 #include <stdint.h>
 
 #include "flow_nthw_info.h"
+#include "flow_nthw_ifr.h"
 #include "flow_nthw_cat.h"
 #include "flow_nthw_km.h"
 #include "flow_nthw_flm.h"
@@ -27,6 +28,7 @@ static struct backend_dev_s {
 	struct cat_nthw *p_cat_nthw;
 	struct km_nthw *p_km_nthw;
 	struct flm_nthw *p_flm_nthw;
+	struct ifr_nthw *p_ifr_nthw;    /* TPE module */
 } be_devs[MAX_PHYS_ADAPTERS];
 
 #define CHECK_DEBUG_ON(be, mod, inst)                                                             \
@@ -1407,6 +1409,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_flm_nthw = NULL;
 	}
 
+	/* Init nthw IFR */
+	if (ifr_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct ifr_nthw *ifrnthw = ifr_nthw_new();
+		ifr_nthw_init(ifrnthw, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_ifr_nthw = ifrnthw;
+
+	} else {
+		be_devs[physical_adapter_no].p_ifr_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.c
new file mode 100644
index 0000000000..849c599e32
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.c
@@ -0,0 +1,68 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_ifr.h"
+
+struct ifr_nthw *ifr_nthw_new(void)
+{
+	struct ifr_nthw *p = malloc(sizeof(struct ifr_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+int ifr_nthw_init(struct ifr_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_IFR, n_instance);
+
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: Ifr %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_ifr = nthw_fpga_query_module(p_fpga, MOD_IFR, n_instance);
+
+	p->mp_rcp_ctrl = nthw_module_get_register(p->m_ifr, IFR_RCP_CTRL);
+	p->mp_rcp_addr = nthw_register_get_field(p->mp_rcp_ctrl, IFR_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = nthw_register_get_field(p->mp_rcp_ctrl, IFR_RCP_CTRL_CNT);
+
+	p->mp_rcp_data = nthw_module_get_register(p->m_ifr, IFR_RCP_DATA);
+	p->mp_rcp_data_ipv4_en = nthw_register_query_field(p->mp_rcp_data, IFR_RCP_DATA_IPV4_EN);
+	p->mp_rcp_data_ipv6_en = nthw_register_query_field(p->mp_rcp_data, IFR_RCP_DATA_IPV6_EN);
+	p->mp_rcp_data_mtu = nthw_register_get_field(p->mp_rcp_data, IFR_RCP_DATA_MTU);
+	p->mp_rcp_data_ipv4_df_drop =
+		nthw_register_query_field(p->mp_rcp_data, IFR_RCP_DATA_IPV4_DF_DROP);
+	p->mp_rcp_data_ipv6_drop =
+		nthw_register_query_field(p->mp_rcp_data, IFR_RCP_DATA_IPV6_DROP);
+
+	p->mp_df_buf_ctrl = nthw_module_get_register(p->m_ifr, IFR_DF_BUF_CTRL);
+	p->mp_df_buf_ctrl_available =
+		nthw_register_get_field(p->mp_df_buf_ctrl, IFR_DF_BUF_CTRL_AVAILABLE);
+	p->mp_df_buf_ctrl_mtu_profile =
+		nthw_register_get_field(p->mp_df_buf_ctrl, IFR_DF_BUF_CTRL_MTU_PROFILE);
+
+	p->mp_df_buf_data = nthw_module_get_register(p->m_ifr, IFR_DF_BUF_DATA);
+	p->mp_df_buf_data_fifo_dat =
+		nthw_register_get_field(p->mp_df_buf_data, IFR_DF_BUF_DATA_FIFO_DAT);
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.h
new file mode 100644
index 0000000000..439aafbfbc
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.h
@@ -0,0 +1,43 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_IFR_H__
+#define __FLOW_NTHW_IFR_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct ifr_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_ifr;
+
+	nthw_register_t *mp_rcp_ctrl;
+	nthw_field_t *mp_rcp_addr;
+	nthw_field_t *mp_rcp_cnt;
+
+	nthw_register_t *mp_rcp_data;
+	nthw_field_t *mp_rcp_data_ipv4_en;
+	nthw_field_t *mp_rcp_data_ipv6_en;
+	nthw_field_t *mp_rcp_data_mtu;
+	nthw_field_t *mp_rcp_data_ipv4_df_drop;
+	nthw_field_t *mp_rcp_data_ipv6_drop;
+
+	nthw_register_t *mp_df_buf_ctrl;
+	nthw_field_t *mp_df_buf_ctrl_available;
+	nthw_field_t *mp_df_buf_ctrl_mtu_profile;
+
+	nthw_register_t *mp_df_buf_data;
+	nthw_field_t *mp_df_buf_data_fifo_dat;
+};
+
+struct ifr_nthw *ifr_nthw_new(void);
+int ifr_nthw_init(struct ifr_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int ifr_nthw_setup(struct ifr_nthw *p, int n_idx, int n_idx_cnt);
+
+#endif	/* __FLOW_NTHW_IFR_H__ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index 01254f7f5d..6b2b5334da 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -21,6 +21,7 @@
 #define MOD_GPIO_PHY (0xbbe81659UL)
 #define MOD_HIF (0x7815363UL)
 #define MOD_I2CM (0x93bc7780UL)
+#define MOD_IFR (0x9b01f1e6UL)
 #define MOD_IIC (0x7629cddbUL)
 #define MOD_KM (0xcfbd9dbeUL)
 #define MOD_MAC_PCS (0x7abe24c7UL)
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index 0c153e21ed..38b222363e 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -20,6 +20,7 @@
 #include "nthw_fpga_reg_defs_gpio_phy.h"
 #include "nthw_fpga_reg_defs_hif.h"
 #include "nthw_fpga_reg_defs_i2cm.h"
+#include "nthw_fpga_reg_defs_ifr.h"
 #include "nthw_fpga_reg_defs_iic.h"
 #include "nthw_fpga_reg_defs_km.h"
 #include "nthw_fpga_reg_defs_mac_pcs.h"
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_ifr.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_ifr.h
new file mode 100644
index 0000000000..5636e94e07
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_ifr.h
@@ -0,0 +1,42 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_ifr.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_IFR_
+#define _NTHW_FPGA_REG_DEFS_IFR_
+
+/* IFR */
+#define NTHW_MOD_IFR (0x9b01f1e6UL)
+#define IFR_COUNTERS_CTRL (0x92ba13e6UL)
+#define IFR_COUNTERS_CTRL_ADR (0xecdeeda8UL)
+#define IFR_COUNTERS_CTRL_CNT (0xfcd67479UL)
+#define IFR_COUNTERS_DATA (0x3d6b91ffUL)
+#define IFR_COUNTERS_DATA_DROP (0x3ee57cc0UL)
+#define IFR_DF_BUF_CTRL (0xf60805e4UL)
+#define IFR_DF_BUF_CTRL_AVAILABLE (0x158f09c3UL)
+#define IFR_DF_BUF_CTRL_MTU_PROFILE (0x7cb4bc5aUL)
+#define IFR_DF_BUF_DATA (0x59d987fdUL)
+#define IFR_DF_BUF_DATA_FIFO_DAT (0xdbfdf650UL)
+#define IFR_RCP_CTRL (0xc6dfc47eUL)
+#define IFR_RCP_CTRL_ADR (0x68600d59UL)
+#define IFR_RCP_CTRL_CNT (0x78689488UL)
+#define IFR_RCP_DATA (0x690e4667UL)
+#define IFR_RCP_DATA_IPV4_DF_DROP (0xbfd1ca18UL)
+#define IFR_RCP_DATA_IPV4_EN (0xb48ee13aUL)
+#define IFR_RCP_DATA_IPV6_DROP (0x4fbf34a2UL)
+#define IFR_RCP_DATA_IPV6_EN (0x1e8729b1UL)
+#define IFR_RCP_DATA_MTU (0xa436ee13UL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_IFR_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 10/31] net/ntnic: add hasher (HSH) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (14 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 09/31] net/ntnic: add IP fragmenter (IFR) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 11/31] net/ntnic: add queue select (QSL) " Serhii Iliushyk
                   ` (35 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Hasher module calculates a configurable hash value
to be used internally by the FPGA.
The module support both Toeplitz and NT-hash.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    |  16 ++
 drivers/net/ntnic/include/hw_mod_hsh_v5.h     |  46 ++++
 drivers/net/ntnic/meson.build                 |   1 +
 .../nthw/flow_api/flow_backend/flow_backend.c |  80 ++++++
 .../ntnic/nthw/flow_filter/flow_nthw_hsh.c    | 260 ++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_hsh.h    |  87 ++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |   1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |   1 +
 .../nthw/supported/nthw_fpga_reg_defs_hsh.h   |  50 ++++
 9 files changed, 542 insertions(+)
 create mode 100644 drivers/net/ntnic/include/hw_mod_hsh_v5.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_hsh.h

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 133a61fe9c..a4c3336e13 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -12,6 +12,7 @@
 #include "hw_mod_cat_v21.h"
 #include "hw_mod_flm_v25.h"
 #include "hw_mod_km_v7.h"
+#include "hw_mod_hsh_v5.h"
 
 #define MAX_PHYS_ADAPTERS 8
 
@@ -75,6 +76,16 @@ struct flm_func_s {
 	};
 };
 
+struct hsh_func_s {
+	COMMON_FUNC_INFO_S;
+	uint32_t nb_rcp;/* number of HSH recipes supported by FPGA */
+	/* indication if Toeplitz is supported by FPGA, i.e. 0 - unsupported, 1 - supported */
+	uint32_t toeplitz;
+	union {
+		struct hw_mod_hsh_v5_s v5;
+	};
+};
+
 enum debug_mode_e {
 	FLOW_BACKEND_DEBUG_MODE_NONE = 0x0000,
 	FLOW_BACKEND_DEBUG_MODE_WRITE = 0x0001
@@ -180,6 +191,11 @@ struct flow_api_backend_ops {
 		uint32_t *inf_data, uint32_t inf_size,
 		uint32_t *inf_word_cnt, uint32_t *sta_data,
 		uint32_t sta_size, uint32_t *sta_word_cnt);
+
+	/* HSH */
+	bool (*get_hsh_present)(void *dev);
+	uint32_t (*get_hsh_version)(void *dev);
+	int (*hsh_rcp_flush)(void *dev, const struct hsh_func_s *hsh, int category, int cnt);
 };
 
 struct flow_api_backend_s {
diff --git a/drivers/net/ntnic/include/hw_mod_hsh_v5.h b/drivers/net/ntnic/include/hw_mod_hsh_v5.h
new file mode 100644
index 0000000000..cdab15e6c2
--- /dev/null
+++ b/drivers/net/ntnic/include/hw_mod_hsh_v5.h
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _HW_MOD_HSH_V5_H_
+#define _HW_MOD_HSH_V5_H_
+
+#include <stdint.h>
+
+#define HSH_RCP_MAC_PORT_MASK_SIZE 4
+#define HSH_RCP_WORD_MASK_SIZE 10
+/* Toeplitz hash key size in 32-bit words, e.g. 10 words means 320 bits, i.e. 40 Bytes */
+#define HSH_RCP_KEY_SIZE 10
+
+struct hsh_v5_rcp_s {
+	uint32_t load_dist_type;
+	uint32_t mac_port_mask[HSH_RCP_MAC_PORT_MASK_SIZE];
+	uint32_t sort;
+	uint32_t qw0_pe;
+	int32_t qw0_ofs;
+	uint32_t qw4_pe;
+	int32_t qw4_ofs;
+	uint32_t w8_pe;
+	int32_t w8_ofs;
+	uint32_t w8_sort;
+	uint32_t w9_pe;
+	int32_t w9_ofs;
+	uint32_t w9_sort;
+	uint32_t w9_p;
+	uint32_t p_mask;
+	uint32_t word_mask[HSH_RCP_WORD_MASK_SIZE];
+	uint32_t seed;
+	uint32_t tnl_p;
+	uint32_t hsh_valid;
+	uint32_t hsh_type;
+	uint32_t toeplitz;	/* Toeplitz enabled / disabled */
+	uint32_t k[HSH_RCP_KEY_SIZE];	/* Toeplitz hash key */
+	uint32_t auto_ipv4_mask;
+};
+
+struct hw_mod_hsh_v5_s {
+	struct hsh_v5_rcp_s *rcp;
+};
+
+#endif	/* _HW_MOD_HSH_V5_H_ */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 1ca34d8b47..de6777f4d3 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -48,6 +48,7 @@ sources = files(
         'nthw/flow_api/flow_filter.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_flm.c',
+        'nthw/flow_filter/flow_nthw_hsh.c',
         'nthw/flow_filter/flow_nthw_ifr.c',
         'nthw/flow_filter/flow_nthw_info.c',
         'nthw/flow_filter/flow_nthw_km.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index 5d2c09d52a..86a7da2334 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -10,6 +10,7 @@
 #include "flow_nthw_cat.h"
 #include "flow_nthw_km.h"
 #include "flow_nthw_flm.h"
+#include "flow_nthw_hsh.h"
 #include "ntnic_mod_reg.h"
 #include "nthw_fpga_model.h"
 #include "hw_mod_backend.h"
@@ -28,6 +29,7 @@ static struct backend_dev_s {
 	struct cat_nthw *p_cat_nthw;
 	struct km_nthw *p_km_nthw;
 	struct flm_nthw *p_flm_nthw;
+	struct hsh_nthw *p_hsh_nthw;
 	struct ifr_nthw *p_ifr_nthw;    /* TPE module */
 } be_devs[MAX_PHYS_ADAPTERS];
 
@@ -1260,6 +1262,69 @@ static int flm_inf_sta_data_update(void *be_dev, const struct flm_func_s *flm, u
 	return ret;
 }
 
+/*
+ * HSH
+ */
+
+static bool hsh_get_present(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return be->p_hsh_nthw != NULL;
+}
+
+static uint32_t hsh_get_version(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return (uint32_t)((nthw_module_get_major_version(be->p_hsh_nthw->m_hsh) << 16) |
+			(nthw_module_get_minor_version(be->p_hsh_nthw->m_hsh) & 0xffff));
+}
+
+static int hsh_rcp_flush(void *be_dev, const struct hsh_func_s *hsh, int category, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, hsh, be->p_hsh_nthw);
+
+	if (hsh->ver == 5) {
+		hsh_nthw_rcp_cnt(be->p_hsh_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			hsh_nthw_rcp_select(be->p_hsh_nthw, category + i);
+			hsh_nthw_rcp_load_dist_type(be->p_hsh_nthw,
+				hsh->v5.rcp[category + i].load_dist_type);
+			hsh_nthw_rcp_mac_port_mask(be->p_hsh_nthw,
+				hsh->v5.rcp[category + i].mac_port_mask);
+			hsh_nthw_rcp_sort(be->p_hsh_nthw, hsh->v5.rcp[category + i].sort);
+			hsh_nthw_rcp_qw0_pe(be->p_hsh_nthw, hsh->v5.rcp[category + i].qw0_pe);
+			hsh_nthw_rcp_qw0_ofs(be->p_hsh_nthw, hsh->v5.rcp[category + i].qw0_ofs);
+			hsh_nthw_rcp_qw4_pe(be->p_hsh_nthw, hsh->v5.rcp[category + i].qw4_pe);
+			hsh_nthw_rcp_qw4_ofs(be->p_hsh_nthw, hsh->v5.rcp[category + i].qw4_ofs);
+			hsh_nthw_rcp_w8_pe(be->p_hsh_nthw, hsh->v5.rcp[category + i].w8_pe);
+			hsh_nthw_rcp_w8_ofs(be->p_hsh_nthw, hsh->v5.rcp[category + i].w8_ofs);
+			hsh_nthw_rcp_w8_sort(be->p_hsh_nthw, hsh->v5.rcp[category + i].w8_sort);
+			hsh_nthw_rcp_w9_pe(be->p_hsh_nthw, hsh->v5.rcp[category + i].w9_pe);
+			hsh_nthw_rcp_w9_ofs(be->p_hsh_nthw, hsh->v5.rcp[category + i].w9_ofs);
+			hsh_nthw_rcp_w9_sort(be->p_hsh_nthw, hsh->v5.rcp[category + i].w9_sort);
+			hsh_nthw_rcp_w9_p(be->p_hsh_nthw, hsh->v5.rcp[category + i].w9_p);
+			hsh_nthw_rcp_p_mask(be->p_hsh_nthw, hsh->v5.rcp[category + i].p_mask);
+			hsh_nthw_rcp_word_mask(be->p_hsh_nthw,
+				hsh->v5.rcp[category + i].word_mask);
+			hsh_nthw_rcp_seed(be->p_hsh_nthw, hsh->v5.rcp[category + i].seed);
+			hsh_nthw_rcp_tnl_p(be->p_hsh_nthw, hsh->v5.rcp[category + i].tnl_p);
+			hsh_nthw_rcp_hsh_valid(be->p_hsh_nthw,
+				hsh->v5.rcp[category + i].hsh_valid);
+			hsh_nthw_rcp_hsh_type(be->p_hsh_nthw, hsh->v5.rcp[category + i].hsh_type);
+			hsh_nthw_rcp_toeplitz(be->p_hsh_nthw, hsh->v5.rcp[category + i].toeplitz);
+			hsh_nthw_rcp_k(be->p_hsh_nthw, hsh->v5.rcp[category + i].k);
+			hsh_nthw_rcp_auto_ipv4_mask(be->p_hsh_nthw,
+				hsh->v5.rcp[category + i].auto_ipv4_mask);
+			hsh_nthw_rcp_flush(be->p_hsh_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(hsh, be->p_hsh_nthw);
+	return 0;
+}
+
 /*
  * DBS
  */
@@ -1369,6 +1434,10 @@ const struct flow_api_backend_ops flow_be_iface = {
 	flm_stat_update,
 	flm_lrn_data_flush,
 	flm_inf_sta_data_update,
+
+	hsh_get_present,
+	hsh_get_version,
+	hsh_rcp_flush,
 };
 
 const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, void **dev)
@@ -1419,6 +1488,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_ifr_nthw = NULL;
 	}
 
+	/* Init nthw HSH */
+	if (hsh_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct hsh_nthw *phshnthw = hsh_nthw_new();
+		hsh_nthw_init(phshnthw, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_hsh_nthw = phshnthw;
+
+	} else {
+		be_devs[physical_adapter_no].p_hsh_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -1432,6 +1511,7 @@ static void bin_flow_backend_done(void *dev)
 	cat_nthw_delete(be_dev->p_cat_nthw);
 	km_nthw_delete(be_dev->p_km_nthw);
 	flm_nthw_delete(be_dev->p_flm_nthw);
+	hsh_nthw_delete(be_dev->p_hsh_nthw);
 }
 
 static const struct flow_backend_ops ops = {
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.c
new file mode 100644
index 0000000000..c878c4e54b
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.c
@@ -0,0 +1,260 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_hsh.h"
+
+void hsh_nthw_set_debug_mode(struct hsh_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_hsh, n_debug_mode);
+}
+
+struct hsh_nthw *hsh_nthw_new(void)
+{
+	struct hsh_nthw *p = malloc(sizeof(struct hsh_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void hsh_nthw_delete(struct hsh_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int hsh_nthw_init(struct hsh_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_HSH, n_instance);
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: Hsh %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_hsh = p_mod;
+
+	/* RCP */
+	p->mp_rcp_ctrl = nthw_module_get_register(p->m_hsh, HSH_RCP_CTRL);
+	p->mp_rcp_addr = nthw_register_get_field(p->mp_rcp_ctrl, HSH_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = nthw_register_get_field(p->mp_rcp_ctrl, HSH_RCP_CTRL_CNT);
+	p->mp_rcp_data = nthw_module_get_register(p->m_hsh, HSH_RCP_DATA);
+	p->mp_rcp_data_load_dist_type =
+		nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_LOAD_DIST_TYPE);
+	p->mp_rcp_data_mac_port_mask =
+		nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_MAC_PORT_MASK);
+	p->mp_rcp_data_sort = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_SORT);
+	p->mp_rcp_data_qw0_pe = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_QW0_PE);
+	p->mp_rcp_data_qw0_ofs = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_QW0_OFS);
+	p->mp_rcp_data_qw4_pe = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_QW4_PE);
+	p->mp_rcp_data_qw4_ofs = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_QW4_OFS);
+	p->mp_rcp_data_w8_pe = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W8_PE);
+	p->mp_rcp_data_w8_ofs = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W8_OFS);
+	p->mp_rcp_data_w8_sort = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W8_SORT);
+	p->mp_rcp_data_w9_pe = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W9_PE);
+	p->mp_rcp_data_w9_ofs = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W9_OFS);
+	p->mp_rcp_data_w9_sort = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W9_SORT);
+	p->mp_rcp_data_w9_p = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W9_P);
+	p->mp_rcp_data_p_mask = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_P_MASK);
+	p->mp_rcp_data_word_mask = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_WORD_MASK);
+	p->mp_rcp_data_seed = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_SEED);
+	p->mp_rcp_data_tnl_p = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_TNL_P);
+	p->mp_rcp_data_hsh_valid = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_HSH_VALID);
+	p->mp_rcp_data_hsh_type = nthw_register_get_field(p->mp_rcp_data, HSH_RCP_DATA_HSH_TYPE);
+	p->mp_rcp_data_toeplitz = nthw_register_query_field(p->mp_rcp_data, HSH_RCP_DATA_TOEPLITZ);
+	p->mp_rcp_data_k = nthw_register_query_field(p->mp_rcp_data, HSH_RCP_DATA_K);
+	p->mp_rcp_data_auto_ipv4_mask =
+		nthw_register_query_field(p->mp_rcp_data, HSH_RCP_DATA_AUTO_IPV4_MASK);
+
+	/* Init */
+	uint32_t val[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+	nthw_field_set_val32(p->mp_rcp_addr, 0);
+	nthw_field_set_val32(p->mp_rcp_cnt, 1);
+
+	nthw_field_set_val32(p->mp_rcp_data_load_dist_type, 0);
+	nthw_field_set_val(p->mp_rcp_data_mac_port_mask, val,
+		p->mp_rcp_data_mac_port_mask->mn_words);
+	nthw_field_set_val32(p->mp_rcp_data_sort, 0);
+	nthw_field_set_val32(p->mp_rcp_data_qw0_pe, 0);
+	nthw_field_set_val32(p->mp_rcp_data_qw0_ofs, 0);
+	nthw_field_set_val32(p->mp_rcp_data_qw4_pe, 0);
+	nthw_field_set_val32(p->mp_rcp_data_qw4_ofs, 0);
+	nthw_field_set_val32(p->mp_rcp_data_w8_pe, 0);
+	nthw_field_set_val32(p->mp_rcp_data_w8_ofs, 0);
+	nthw_field_set_val32(p->mp_rcp_data_w8_sort, 0);
+	nthw_field_set_val32(p->mp_rcp_data_w9_pe, 0);
+	nthw_field_set_val32(p->mp_rcp_data_w9_ofs, 0);
+	nthw_field_set_val32(p->mp_rcp_data_w9_sort, 0);
+	nthw_field_set_val32(p->mp_rcp_data_w9_p, 0);
+	nthw_field_set_val(p->mp_rcp_data_word_mask, val, 10);
+	nthw_field_set_val32(p->mp_rcp_data_seed, 0);
+	nthw_field_set_val32(p->mp_rcp_data_tnl_p, 0);
+	nthw_field_set_val32(p->mp_rcp_data_hsh_valid, 0);
+	nthw_field_set_val32(p->mp_rcp_data_hsh_type, 31);
+
+	if (p->mp_rcp_data_toeplitz)
+		nthw_field_set_val32(p->mp_rcp_data_toeplitz, 0);
+
+	if (p->mp_rcp_data_k)
+		nthw_field_set_val(p->mp_rcp_data_k, val, 10);
+
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+
+	return 0;
+}
+
+void hsh_nthw_rcp_select(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_addr, val);
+}
+
+void hsh_nthw_rcp_cnt(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void hsh_nthw_rcp_load_dist_type(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_load_dist_type, val);
+}
+
+void hsh_nthw_rcp_mac_port_mask(const struct hsh_nthw *p, uint32_t *val)
+{
+	nthw_field_set_val(p->mp_rcp_data_mac_port_mask, val,
+		p->mp_rcp_data_mac_port_mask->mn_words);
+}
+
+void hsh_nthw_rcp_sort(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_sort, val);
+}
+
+void hsh_nthw_rcp_qw0_pe(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw0_pe, val);
+}
+
+void hsh_nthw_rcp_qw0_ofs(const struct hsh_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw0_ofs, val);
+}
+
+void hsh_nthw_rcp_qw4_pe(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw4_pe, val);
+}
+
+void hsh_nthw_rcp_qw4_ofs(const struct hsh_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_qw4_ofs, val);
+}
+
+void hsh_nthw_rcp_w8_pe(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_w8_pe, val);
+}
+
+void hsh_nthw_rcp_w8_ofs(const struct hsh_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_w8_ofs, val);
+}
+
+void hsh_nthw_rcp_w8_sort(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_w8_sort, val);
+}
+
+void hsh_nthw_rcp_w9_pe(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_w9_pe, val);
+}
+
+void hsh_nthw_rcp_w9_ofs(const struct hsh_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_w9_ofs, val);
+}
+
+void hsh_nthw_rcp_w9_sort(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_w9_sort, val);
+}
+
+void hsh_nthw_rcp_w9_p(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_w9_p, val);
+}
+
+void hsh_nthw_rcp_p_mask(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_p_mask, val);
+}
+
+void hsh_nthw_rcp_word_mask(const struct hsh_nthw *p, uint32_t *val)
+{
+	nthw_field_set_val(p->mp_rcp_data_word_mask, val, 10);
+}
+
+void hsh_nthw_rcp_seed(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_seed, val);
+}
+
+void hsh_nthw_rcp_tnl_p(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_tnl_p, val);
+}
+
+void hsh_nthw_rcp_hsh_valid(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_hsh_valid, val);
+}
+
+void hsh_nthw_rcp_hsh_type(const struct hsh_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_hsh_type, val);
+}
+
+void hsh_nthw_rcp_toeplitz(const struct hsh_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_toeplitz)
+		nthw_field_set_val32(p->mp_rcp_data_toeplitz, val);
+}
+
+void hsh_nthw_rcp_k(const struct hsh_nthw *p, uint32_t *val)
+{
+	if (p->mp_rcp_data_k)
+		nthw_field_set_val(p->mp_rcp_data_k, val, 10);
+}
+
+void hsh_nthw_rcp_auto_ipv4_mask(const struct hsh_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_auto_ipv4_mask)
+		nthw_field_set_val32(p->mp_rcp_data_auto_ipv4_mask, val);
+}
+
+void hsh_nthw_rcp_flush(const struct hsh_nthw *p)
+{
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.h
new file mode 100644
index 0000000000..70626122e3
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.h
@@ -0,0 +1,87 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_HSH_H__
+#define __FLOW_NTHW_HSH_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct hsh_nthw;
+
+typedef struct hsh_nthw hsh_nthw_t;
+
+struct hsh_nthw *hsh_nthw_new(void);
+void hsh_nthw_delete(struct hsh_nthw *p);
+int hsh_nthw_init(struct hsh_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int hsh_nthw_setup(struct hsh_nthw *p, int n_idx, int n_idx_cnt);
+void hsh_nthw_set_debug_mode(struct hsh_nthw *p, unsigned int n_debug_mode);
+
+/* RCP */
+void hsh_nthw_rcp_select(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_cnt(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_load_dist_type(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_mac_port_mask(const struct hsh_nthw *p, uint32_t *val);
+void hsh_nthw_rcp_sort(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_qw0_pe(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_qw0_ofs(const struct hsh_nthw *p, int32_t val);
+void hsh_nthw_rcp_qw4_pe(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_qw4_ofs(const struct hsh_nthw *p, int32_t val);
+void hsh_nthw_rcp_w8_pe(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_w8_ofs(const struct hsh_nthw *p, int32_t val);
+void hsh_nthw_rcp_w8_sort(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_w9_pe(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_w9_ofs(const struct hsh_nthw *p, int32_t val);
+void hsh_nthw_rcp_w9_sort(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_w9_p(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_p_mask(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_word_mask(const struct hsh_nthw *p, uint32_t *val);
+void hsh_nthw_rcp_seed(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_tnl_p(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_hsh_valid(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_hsh_type(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_toeplitz(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_k(const struct hsh_nthw *p, uint32_t *val);
+void hsh_nthw_rcp_auto_ipv4_mask(const struct hsh_nthw *p, uint32_t val);
+void hsh_nthw_rcp_flush(const struct hsh_nthw *p);
+
+struct hsh_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_hsh;
+
+	nthw_register_t *mp_rcp_ctrl;
+	nthw_field_t *mp_rcp_addr;
+	nthw_field_t *mp_rcp_cnt;
+	nthw_register_t *mp_rcp_data;
+	nthw_field_t *mp_rcp_data_load_dist_type;
+	nthw_field_t *mp_rcp_data_mac_port_mask;
+	nthw_field_t *mp_rcp_data_sort;
+	nthw_field_t *mp_rcp_data_qw0_pe;
+	nthw_field_t *mp_rcp_data_qw0_ofs;
+	nthw_field_t *mp_rcp_data_qw4_pe;
+	nthw_field_t *mp_rcp_data_qw4_ofs;
+	nthw_field_t *mp_rcp_data_w8_pe;
+	nthw_field_t *mp_rcp_data_w8_ofs;
+	nthw_field_t *mp_rcp_data_w8_sort;
+	nthw_field_t *mp_rcp_data_w9_pe;
+	nthw_field_t *mp_rcp_data_w9_ofs;
+	nthw_field_t *mp_rcp_data_w9_sort;
+	nthw_field_t *mp_rcp_data_w9_p;
+	nthw_field_t *mp_rcp_data_p_mask;
+	nthw_field_t *mp_rcp_data_word_mask;
+	nthw_field_t *mp_rcp_data_seed;
+	nthw_field_t *mp_rcp_data_tnl_p;
+	nthw_field_t *mp_rcp_data_hsh_valid;
+	nthw_field_t *mp_rcp_data_hsh_type;
+	nthw_field_t *mp_rcp_data_toeplitz;
+	nthw_field_t *mp_rcp_data_k;
+	nthw_field_t *mp_rcp_data_auto_ipv4_mask;
+};
+
+#endif	/* __FLOW_NTHW_HSH_H__ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index 6b2b5334da..a929a98b52 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -20,6 +20,7 @@
 #define MOD_GMF (0x68b1d15aUL)
 #define MOD_GPIO_PHY (0xbbe81659UL)
 #define MOD_HIF (0x7815363UL)
+#define MOD_HSH (0x501484bfUL)
 #define MOD_I2CM (0x93bc7780UL)
 #define MOD_IFR (0x9b01f1e6UL)
 #define MOD_IIC (0x7629cddbUL)
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index 38b222363e..9155cc4435 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -19,6 +19,7 @@
 #include "nthw_fpga_reg_defs_gmf.h"
 #include "nthw_fpga_reg_defs_gpio_phy.h"
 #include "nthw_fpga_reg_defs_hif.h"
+#include "nthw_fpga_reg_defs_hsh.h"
 #include "nthw_fpga_reg_defs_i2cm.h"
 #include "nthw_fpga_reg_defs_ifr.h"
 #include "nthw_fpga_reg_defs_iic.h"
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_hsh.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_hsh.h
new file mode 100644
index 0000000000..fb95a514de
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_hsh.h
@@ -0,0 +1,50 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_hsh.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_HSH_
+#define _NTHW_FPGA_REG_DEFS_HSH_
+
+/* HSH */
+#define NTHW_MOD_HSH (0x501484bfUL)
+#define HSH_RCP_CTRL (0xb257f1b9UL)
+#define HSH_RCP_CTRL_ADR (0x5685bfbUL)
+#define HSH_RCP_CTRL_CNT (0x1560c22aUL)
+#define HSH_RCP_DATA (0x1d8673a0UL)
+#define HSH_RCP_DATA_AUTO_IPV4_MASK (0xa0d4de3bUL)
+#define HSH_RCP_DATA_HSH_TYPE (0x14cd0865UL)
+#define HSH_RCP_DATA_HSH_VALID (0xc89b0bd3UL)
+#define HSH_RCP_DATA_K (0xccdb0222UL)
+#define HSH_RCP_DATA_LOAD_DIST_TYPE (0x152a0a87UL)
+#define HSH_RCP_DATA_MAC_PORT_MASK (0x5160b288UL)
+#define HSH_RCP_DATA_P_MASK (0x8a555abbUL)
+#define HSH_RCP_DATA_QW0_OFS (0x276b79cfUL)
+#define HSH_RCP_DATA_QW0_PE (0x32014a20UL)
+#define HSH_RCP_DATA_QW4_OFS (0xd2ebdf0fUL)
+#define HSH_RCP_DATA_QW4_PE (0xbd63dd77UL)
+#define HSH_RCP_DATA_SEED (0xf8fc2c1cUL)
+#define HSH_RCP_DATA_SORT (0xed5f3d38UL)
+#define HSH_RCP_DATA_TNL_P (0x6e56b51eUL)
+#define HSH_RCP_DATA_TOEPLITZ (0xc1864a45UL)
+#define HSH_RCP_DATA_W8_OFS (0x68150d02UL)
+#define HSH_RCP_DATA_W8_PE (0x9387d583UL)
+#define HSH_RCP_DATA_W8_SORT (0x5c67eca8UL)
+#define HSH_RCP_DATA_W9_OFS (0x557524b2UL)
+#define HSH_RCP_DATA_W9_P (0x808204d9UL)
+#define HSH_RCP_DATA_W9_PE (0x2b3bb2e6UL)
+#define HSH_RCP_DATA_W9_SORT (0x973b3f0dUL)
+#define HSH_RCP_DATA_WORD_MASK (0x55c53a1fUL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_HSH_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 11/31] net/ntnic: add queue select (QSL) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (15 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 10/31] net/ntnic: add hasher (HSH) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 12/31] net/ntnic: add slicer (SLC LR) " Serhii Iliushyk
                   ` (34 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Queue Selector module directs packets to a given destination
which includes host queues, physical ports, exceptions paths, and discard.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    |  18 ++
 drivers/net/ntnic/include/hw_mod_qsl_v7.h     |  48 +++
 drivers/net/ntnic/meson.build                 |   1 +
 .../nthw/flow_api/flow_backend/flow_backend.c | 129 ++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_qsl.c    | 295 ++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_qsl.h    | 113 +++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |   1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |   1 +
 .../nthw/supported/nthw_fpga_reg_defs_qsl.h   |  66 ++++
 9 files changed, 672 insertions(+)
 create mode 100644 drivers/net/ntnic/include/hw_mod_qsl_v7.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_qsl.h

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index a4c3336e13..84f2ed6c6a 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -12,6 +12,7 @@
 #include "hw_mod_cat_v21.h"
 #include "hw_mod_flm_v25.h"
 #include "hw_mod_km_v7.h"
+#include "hw_mod_qsl_v7.h"
 #include "hw_mod_hsh_v5.h"
 
 #define MAX_PHYS_ADAPTERS 8
@@ -86,6 +87,15 @@ struct hsh_func_s {
 	};
 };
 
+struct qsl_func_s {
+	COMMON_FUNC_INFO_S;
+	uint32_t nb_rcp_categories;
+	uint32_t nb_qst_entries;
+	union {
+		struct hw_mod_qsl_v7_s v7;
+	};
+};
+
 enum debug_mode_e {
 	FLOW_BACKEND_DEBUG_MODE_NONE = 0x0000,
 	FLOW_BACKEND_DEBUG_MODE_WRITE = 0x0001
@@ -196,6 +206,14 @@ struct flow_api_backend_ops {
 	bool (*get_hsh_present)(void *dev);
 	uint32_t (*get_hsh_version)(void *dev);
 	int (*hsh_rcp_flush)(void *dev, const struct hsh_func_s *hsh, int category, int cnt);
+
+	/* QSL */
+	bool (*get_qsl_present)(void *dev);
+	uint32_t (*get_qsl_version)(void *dev);
+	int (*qsl_rcp_flush)(void *dev, const struct qsl_func_s *qsl, int category, int cnt);
+	int (*qsl_qst_flush)(void *dev, const struct qsl_func_s *qsl, int entry, int cnt);
+	int (*qsl_qen_flush)(void *dev, const struct qsl_func_s *qsl, int entry, int cnt);
+	int (*qsl_unmq_flush)(void *dev, const struct qsl_func_s *qsl, int entry, int cnt);
 };
 
 struct flow_api_backend_s {
diff --git a/drivers/net/ntnic/include/hw_mod_qsl_v7.h b/drivers/net/ntnic/include/hw_mod_qsl_v7.h
new file mode 100644
index 0000000000..6f6f230638
--- /dev/null
+++ b/drivers/net/ntnic/include/hw_mod_qsl_v7.h
@@ -0,0 +1,48 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _HW_MOD_QSL_V7_H_
+#define _HW_MOD_QSL_V7_H_
+
+#include <stdint.h>
+
+struct qsl_v7_rcp_s {
+	uint32_t discard;
+	uint32_t drop;
+	uint32_t tbl_lo;
+	uint32_t tbl_hi;
+	uint32_t tbl_idx;
+	uint32_t tbl_msk;
+	uint32_t lr;
+	uint32_t tsa;
+	uint32_t vli;
+};
+
+struct qsl_v7_qst_s {
+	uint32_t queue;
+	uint32_t en;
+	uint32_t tx_port;
+	uint32_t lre;
+	uint32_t tci;
+	uint32_t ven;
+};
+
+struct qsl_v7_qen_s {
+	uint32_t en;
+};
+
+struct qsl_v7_unmq_s {
+	uint32_t dest_queue;
+	uint32_t en;
+};
+
+struct hw_mod_qsl_v7_s {
+	struct qsl_v7_rcp_s *rcp;
+	struct qsl_v7_qst_s *qst;
+	struct qsl_v7_qen_s *qen;
+	struct qsl_v7_unmq_s *unmq;
+};
+
+#endif	/* _HW_MOD_QSL_V7_H_ */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index de6777f4d3..c7c5cd997f 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -52,6 +52,7 @@ sources = files(
         'nthw/flow_filter/flow_nthw_ifr.c',
         'nthw/flow_filter/flow_nthw_info.c',
         'nthw/flow_filter/flow_nthw_km.c',
+        'nthw/flow_filter/flow_nthw_qsl.c',
         'nthw/model/nthw_fpga_model.c',
         'nthw/nthw_platform.c',
         'nthw/nthw_rac.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index 86a7da2334..a2422f8b31 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -11,6 +11,7 @@
 #include "flow_nthw_km.h"
 #include "flow_nthw_flm.h"
 #include "flow_nthw_hsh.h"
+#include "flow_nthw_qsl.h"
 #include "ntnic_mod_reg.h"
 #include "nthw_fpga_model.h"
 #include "hw_mod_backend.h"
@@ -30,6 +31,7 @@ static struct backend_dev_s {
 	struct km_nthw *p_km_nthw;
 	struct flm_nthw *p_flm_nthw;
 	struct hsh_nthw *p_hsh_nthw;
+	struct qsl_nthw *p_qsl_nthw;
 	struct ifr_nthw *p_ifr_nthw;    /* TPE module */
 } be_devs[MAX_PHYS_ADAPTERS];
 
@@ -1325,6 +1327,115 @@ static int hsh_rcp_flush(void *be_dev, const struct hsh_func_s *hsh, int categor
 	return 0;
 }
 
+/*
+ * QSL
+ */
+
+static bool qsl_get_present(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return be->p_qsl_nthw != NULL;
+}
+
+static uint32_t qsl_get_version(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return (uint32_t)((nthw_module_get_major_version(be->p_qsl_nthw->m_qsl) << 16) |
+			(nthw_module_get_minor_version(be->p_qsl_nthw->m_qsl) & 0xffff));
+}
+
+static int qsl_rcp_flush(void *be_dev, const struct qsl_func_s *qsl, int category, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, qsl, be->p_qsl_nthw);
+
+	if (qsl->ver == 7) {
+		qsl_nthw_rcp_cnt(be->p_qsl_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			qsl_nthw_rcp_select(be->p_qsl_nthw, category + i);
+			qsl_nthw_rcp_discard(be->p_qsl_nthw, qsl->v7.rcp[category + i].discard);
+			qsl_nthw_rcp_drop(be->p_qsl_nthw, qsl->v7.rcp[category + i].drop);
+			qsl_nthw_rcp_tbl_lo(be->p_qsl_nthw, qsl->v7.rcp[category + i].tbl_lo);
+			qsl_nthw_rcp_tbl_hi(be->p_qsl_nthw, qsl->v7.rcp[category + i].tbl_hi);
+			qsl_nthw_rcp_tbl_idx(be->p_qsl_nthw, qsl->v7.rcp[category + i].tbl_idx);
+			qsl_nthw_rcp_tbl_msk(be->p_qsl_nthw, qsl->v7.rcp[category + i].tbl_msk);
+			qsl_nthw_rcp_lr(be->p_qsl_nthw, qsl->v7.rcp[category + i].lr);
+			qsl_nthw_rcp_tsa(be->p_qsl_nthw, qsl->v7.rcp[category + i].tsa);
+			qsl_nthw_rcp_vli(be->p_qsl_nthw, qsl->v7.rcp[category + i].vli);
+			qsl_nthw_rcp_flush(be->p_qsl_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(qsl, be->p_qsl_nthw);
+	return 0;
+}
+
+static int qsl_qst_flush(void *be_dev, const struct qsl_func_s *qsl, int entry, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, qsl, be->p_qsl_nthw);
+
+	if (qsl->ver == 7) {
+		qsl_nthw_qst_cnt(be->p_qsl_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			qsl_nthw_qst_select(be->p_qsl_nthw, entry + i);
+			qsl_nthw_qst_queue(be->p_qsl_nthw, qsl->v7.qst[entry + i].queue);
+			qsl_nthw_qst_en(be->p_qsl_nthw, qsl->v7.qst[entry + i].en);
+
+			qsl_nthw_qst_tx_port(be->p_qsl_nthw, qsl->v7.qst[entry + i].tx_port);
+			qsl_nthw_qst_lre(be->p_qsl_nthw, qsl->v7.qst[entry + i].lre);
+			qsl_nthw_qst_tci(be->p_qsl_nthw, qsl->v7.qst[entry + i].tci);
+			qsl_nthw_qst_ven(be->p_qsl_nthw, qsl->v7.qst[entry + i].ven);
+			qsl_nthw_qst_flush(be->p_qsl_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(qsl, be->p_qsl_nthw);
+	return 0;
+}
+
+static int qsl_qen_flush(void *be_dev, const struct qsl_func_s *qsl, int entry, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, qsl, be->p_qsl_nthw);
+
+	if (qsl->ver == 7) {
+		qsl_nthw_qen_cnt(be->p_qsl_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			qsl_nthw_qen_select(be->p_qsl_nthw, entry + i);
+			qsl_nthw_qen_en(be->p_qsl_nthw, qsl->v7.qen[entry + i].en);
+			qsl_nthw_qen_flush(be->p_qsl_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(qsl, be->p_qsl_nthw);
+	return 0;
+}
+
+static int qsl_unmq_flush(void *be_dev, const struct qsl_func_s *qsl, int entry, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, qsl, be->p_qsl_nthw);
+
+	if (qsl->ver == 7) {
+		qsl_nthw_unmq_cnt(be->p_qsl_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			qsl_nthw_unmq_select(be->p_qsl_nthw, entry + i);
+			qsl_nthw_unmq_dest_queue(be->p_qsl_nthw,
+				qsl->v7.unmq[entry + i].dest_queue);
+			qsl_nthw_unmq_en(be->p_qsl_nthw, qsl->v7.unmq[entry + i].en);
+			qsl_nthw_unmq_flush(be->p_qsl_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(qsl, be->p_qsl_nthw);
+	return 0;
+}
+
 /*
  * DBS
  */
@@ -1438,6 +1549,13 @@ const struct flow_api_backend_ops flow_be_iface = {
 	hsh_get_present,
 	hsh_get_version,
 	hsh_rcp_flush,
+
+	qsl_get_present,
+	qsl_get_version,
+	qsl_rcp_flush,
+	qsl_qst_flush,
+	qsl_qen_flush,
+	qsl_unmq_flush,
 };
 
 const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, void **dev)
@@ -1498,6 +1616,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_hsh_nthw = NULL;
 	}
 
+	/* Init nthw QSL */
+	if (qsl_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct qsl_nthw *pqslnthw = qsl_nthw_new();
+		qsl_nthw_init(pqslnthw, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_qsl_nthw = pqslnthw;
+
+	} else {
+		be_devs[physical_adapter_no].p_qsl_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -1512,6 +1640,7 @@ static void bin_flow_backend_done(void *dev)
 	km_nthw_delete(be_dev->p_km_nthw);
 	flm_nthw_delete(be_dev->p_flm_nthw);
 	hsh_nthw_delete(be_dev->p_hsh_nthw);
+	qsl_nthw_delete(be_dev->p_qsl_nthw);
 }
 
 static const struct flow_backend_ops ops = {
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.c
new file mode 100644
index 0000000000..0ba1d904f2
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.c
@@ -0,0 +1,295 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_qsl.h"
+
+void qsl_nthw_set_debug_mode(struct qsl_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_qsl, n_debug_mode);
+}
+
+struct qsl_nthw *qsl_nthw_new(void)
+{
+	struct qsl_nthw *p = malloc(sizeof(struct qsl_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void qsl_nthw_delete(struct qsl_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int qsl_nthw_init(struct qsl_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_QSL, n_instance);
+
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: QSL %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_qsl = p_mod;
+
+	/* RCP */
+	p->mp_rcp_ctrl = nthw_module_get_register(p->m_qsl, QSL_RCP_CTRL);
+	p->mp_rcp_addr = nthw_register_get_field(p->mp_rcp_ctrl, QSL_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = nthw_register_get_field(p->mp_rcp_ctrl, QSL_RCP_CTRL_CNT);
+	p->mp_rcp_data = nthw_module_get_register(p->m_qsl, QSL_RCP_DATA);
+	p->mp_rcp_data_discard = nthw_register_get_field(p->mp_rcp_data, QSL_RCP_DATA_DISCARD);
+	p->mp_rcp_data_drop = nthw_register_get_field(p->mp_rcp_data, QSL_RCP_DATA_DROP);
+	p->mp_rcp_data_tbl_lo = nthw_register_get_field(p->mp_rcp_data, QSL_RCP_DATA_TBL_LO);
+	p->mp_rcp_data_tbl_hi = nthw_register_get_field(p->mp_rcp_data, QSL_RCP_DATA_TBL_HI);
+	p->mp_rcp_data_tbl_idx = nthw_register_get_field(p->mp_rcp_data, QSL_RCP_DATA_TBL_IDX);
+	p->mp_rcp_data_tbl_msk = nthw_register_get_field(p->mp_rcp_data, QSL_RCP_DATA_TBL_MSK);
+	p->mp_rcp_data_cao = nthw_register_query_field(p->mp_rcp_data, QSL_RCP_DATA_CAO);
+	p->mp_rcp_data_lr = nthw_register_query_field(p->mp_rcp_data, QSL_RCP_DATA_LR);
+	p->mp_rcp_data_tsa = nthw_register_query_field(p->mp_rcp_data, QSL_RCP_DATA_TSA);
+	p->mp_rcp_data_vli = nthw_register_query_field(p->mp_rcp_data, QSL_RCP_DATA_VLI);
+
+	/* QST */
+	p->mp_qst_ctrl = nthw_module_get_register(p->m_qsl, QSL_QST_CTRL);
+	p->mp_qst_addr = nthw_register_get_field(p->mp_qst_ctrl, QSL_QST_CTRL_ADR);
+	p->mp_qst_cnt = nthw_register_get_field(p->mp_qst_ctrl, QSL_QST_CTRL_CNT);
+	p->mp_qst_data = nthw_module_get_register(p->m_qsl, QSL_QST_DATA);
+	p->mp_qst_data_queue = nthw_register_get_field(p->mp_qst_data, QSL_QST_DATA_QUEUE);
+	p->mp_qst_data_en = nthw_register_query_field(p->mp_qst_data, QSL_QST_DATA_EN);
+	p->mp_qst_data_tx_port = nthw_register_query_field(p->mp_qst_data, QSL_QST_DATA_TX_PORT);
+	p->mp_qst_data_lre = nthw_register_query_field(p->mp_qst_data, QSL_QST_DATA_LRE);
+	p->mp_qst_data_tci = nthw_register_query_field(p->mp_qst_data, QSL_QST_DATA_TCI);
+	p->mp_qst_data_ven = nthw_register_query_field(p->mp_qst_data, QSL_QST_DATA_VEN);
+	/* QEN */
+	p->mp_qen_ctrl = nthw_module_get_register(p->m_qsl, QSL_QEN_CTRL);
+	p->mp_qen_addr = nthw_register_get_field(p->mp_qen_ctrl, QSL_QEN_CTRL_ADR);
+	p->mp_qen_cnt = nthw_register_get_field(p->mp_qen_ctrl, QSL_QEN_CTRL_CNT);
+	p->mp_qen_data = nthw_module_get_register(p->m_qsl, QSL_QEN_DATA);
+	p->mp_qen_data_en = nthw_register_get_field(p->mp_qen_data, QSL_QEN_DATA_EN);
+	/* UNMQ */
+	p->mp_unmq_ctrl = nthw_module_get_register(p->m_qsl, QSL_UNMQ_CTRL);
+	p->mp_unmq_addr = nthw_register_get_field(p->mp_unmq_ctrl, QSL_UNMQ_CTRL_ADR);
+	p->mp_unmq_cnt = nthw_register_get_field(p->mp_unmq_ctrl, QSL_UNMQ_CTRL_CNT);
+	p->mp_unmq_data = nthw_module_get_register(p->m_qsl, QSL_UNMQ_DATA);
+	p->mp_unmq_data_dest_queue =
+		nthw_register_get_field(p->mp_unmq_data, QSL_UNMQ_DATA_DEST_QUEUE);
+	p->mp_unmq_data_en = nthw_register_get_field(p->mp_unmq_data, QSL_UNMQ_DATA_EN);
+
+	if (!p->mp_qst_data_en) {
+		/* changed name from EN to QEN in v0.7 */
+		p->mp_qst_data_en = nthw_register_get_field(p->mp_qst_data, QSL_QST_DATA_QEN);
+	}
+
+	/* LTX - not there anymore from v0.7+ */
+	p->mp_ltx_ctrl = nthw_module_query_register(p->m_qsl, QSL_LTX_CTRL);
+
+	if (p->mp_ltx_ctrl) {
+		p->mp_ltx_addr = nthw_register_get_field(p->mp_ltx_ctrl, QSL_LTX_CTRL_ADR);
+		p->mp_ltx_cnt = nthw_register_get_field(p->mp_ltx_ctrl, QSL_LTX_CTRL_CNT);
+
+	} else {
+		p->mp_ltx_addr = NULL;
+		p->mp_ltx_cnt = NULL;
+	}
+
+	p->mp_ltx_data = nthw_module_query_register(p->m_qsl, QSL_LTX_DATA);
+
+	if (p->mp_ltx_data) {
+		p->mp_ltx_data_lr = nthw_register_get_field(p->mp_ltx_data, QSL_LTX_DATA_LR);
+		p->mp_ltx_data_tx_port =
+			nthw_register_get_field(p->mp_ltx_data, QSL_LTX_DATA_TX_PORT);
+		p->mp_ltx_data_tsa = nthw_register_get_field(p->mp_ltx_data, QSL_LTX_DATA_TSA);
+
+	} else {
+		p->mp_ltx_data_lr = NULL;
+		p->mp_ltx_data_tx_port = NULL;
+		p->mp_ltx_data_tsa = NULL;
+	}
+
+	return 0;
+}
+
+/* RCP */
+void qsl_nthw_rcp_select(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_addr, val);
+};
+
+void qsl_nthw_rcp_cnt(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void qsl_nthw_rcp_discard(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_discard, val);
+}
+
+void qsl_nthw_rcp_drop(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_drop, val);
+}
+
+void qsl_nthw_rcp_tbl_lo(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_tbl_lo, val);
+}
+void qsl_nthw_rcp_tbl_hi(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_tbl_hi, val);
+}
+void qsl_nthw_rcp_tbl_idx(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_tbl_idx, val);
+}
+
+void qsl_nthw_rcp_tbl_msk(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_tbl_msk, val);
+}
+
+void qsl_nthw_rcp_lr(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_lr)
+		nthw_field_set_val32(p->mp_rcp_data_lr, val);
+}
+
+void qsl_nthw_rcp_tsa(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_tsa)
+		nthw_field_set_val32(p->mp_rcp_data_tsa, val);
+}
+
+void qsl_nthw_rcp_vli(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_vli)
+		nthw_field_set_val32(p->mp_rcp_data_vli, val);
+}
+
+void qsl_nthw_rcp_flush(const struct qsl_nthw *p)
+{
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+}
+
+/* QST */
+void qsl_nthw_qst_select(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_qst_addr, val);
+}
+
+void qsl_nthw_qst_cnt(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_qst_cnt, val);
+}
+
+void qsl_nthw_qst_queue(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_qst_data_queue, val);
+}
+
+void qsl_nthw_qst_en(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_qst_data_en, val);
+}
+
+void qsl_nthw_qst_tx_port(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_qst_data_tx_port)
+		nthw_field_set_val32(p->mp_qst_data_tx_port, val);
+}
+
+void qsl_nthw_qst_lre(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_qst_data_lre)
+		nthw_field_set_val32(p->mp_qst_data_lre, val);
+}
+
+void qsl_nthw_qst_tci(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_qst_data_tci)
+		nthw_field_set_val32(p->mp_qst_data_tci, val);
+}
+
+void qsl_nthw_qst_ven(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_qst_data_ven)
+		nthw_field_set_val32(p->mp_qst_data_ven, val);
+}
+
+void qsl_nthw_qst_flush(const struct qsl_nthw *p)
+{
+	nthw_register_flush(p->mp_qst_ctrl, 1);
+	nthw_register_flush(p->mp_qst_data, 1);
+}
+
+/* QEN */
+void qsl_nthw_qen_select(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_qen_addr, val);
+}
+
+void qsl_nthw_qen_cnt(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_qen_cnt, val);
+}
+
+void qsl_nthw_qen_en(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_qen_data_en, val);
+}
+
+void qsl_nthw_qen_flush(const struct qsl_nthw *p)
+{
+	nthw_register_flush(p->mp_qen_ctrl, 1);
+	nthw_register_flush(p->mp_qen_data, 1);
+}
+
+/* UNMQ */
+void qsl_nthw_unmq_select(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_unmq_addr, val);
+}
+
+void qsl_nthw_unmq_cnt(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_unmq_cnt, val);
+}
+
+void qsl_nthw_unmq_dest_queue(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_unmq_data_dest_queue, val);
+}
+
+void qsl_nthw_unmq_en(const struct qsl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_unmq_data_en, val);
+}
+
+void qsl_nthw_unmq_flush(const struct qsl_nthw *p)
+{
+	nthw_register_flush(p->mp_unmq_ctrl, 1);
+	nthw_register_flush(p->mp_unmq_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.h
new file mode 100644
index 0000000000..1bbcd1cea6
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.h
@@ -0,0 +1,113 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_QSL_H__
+#define __FLOW_NTHW_QSL_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct qsl_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_qsl;
+
+	nthw_register_t *mp_rcp_ctrl;
+	nthw_field_t *mp_rcp_addr;
+	nthw_field_t *mp_rcp_cnt;
+	nthw_register_t *mp_rcp_data;
+	nthw_field_t *mp_rcp_data_discard;
+	nthw_field_t *mp_rcp_data_drop;
+	nthw_field_t *mp_rcp_data_tbl_lo;
+	nthw_field_t *mp_rcp_data_tbl_hi;
+	nthw_field_t *mp_rcp_data_tbl_idx;
+	nthw_field_t *mp_rcp_data_tbl_msk;
+	nthw_field_t *mp_rcp_data_cao;
+	nthw_field_t *mp_rcp_data_lr;
+	nthw_field_t *mp_rcp_data_tsa;
+	nthw_field_t *mp_rcp_data_vli;
+
+	nthw_register_t *mp_ltx_ctrl;
+	nthw_field_t *mp_ltx_addr;
+	nthw_field_t *mp_ltx_cnt;
+	nthw_register_t *mp_ltx_data;
+	nthw_field_t *mp_ltx_data_lr;
+	nthw_field_t *mp_ltx_data_tx_port;
+	nthw_field_t *mp_ltx_data_tsa;
+
+	nthw_register_t *mp_qst_ctrl;
+	nthw_field_t *mp_qst_addr;
+	nthw_field_t *mp_qst_cnt;
+	nthw_register_t *mp_qst_data;
+	nthw_field_t *mp_qst_data_queue;
+	nthw_field_t *mp_qst_data_en;
+	nthw_field_t *mp_qst_data_tx_port;
+	nthw_field_t *mp_qst_data_lre;
+	nthw_field_t *mp_qst_data_tci;
+	nthw_field_t *mp_qst_data_ven;
+
+	nthw_register_t *mp_qen_ctrl;
+	nthw_field_t *mp_qen_addr;
+	nthw_field_t *mp_qen_cnt;
+	nthw_register_t *mp_qen_data;
+	nthw_field_t *mp_qen_data_en;
+
+	nthw_register_t *mp_unmq_ctrl;
+	nthw_field_t *mp_unmq_addr;
+	nthw_field_t *mp_unmq_cnt;
+	nthw_register_t *mp_unmq_data;
+	nthw_field_t *mp_unmq_data_dest_queue;
+	nthw_field_t *mp_unmq_data_en;
+};
+
+typedef struct qsl_nthw qsl_nthw_t;
+
+struct qsl_nthw *qsl_nthw_new(void);
+void qsl_nthw_delete(struct qsl_nthw *p);
+int qsl_nthw_init(struct qsl_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+void qsl_nthw_set_debug_mode(struct qsl_nthw *p, unsigned int n_debug_mode);
+
+/* RCP */
+void qsl_nthw_rcp_select(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_rcp_cnt(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_rcp_discard(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_rcp_drop(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_rcp_tbl_lo(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_rcp_tbl_hi(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_rcp_tbl_idx(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_rcp_tbl_msk(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_rcp_lr(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_rcp_tsa(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_rcp_vli(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_rcp_flush(const struct qsl_nthw *p);
+
+/* QST */
+void qsl_nthw_qst_select(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_qst_cnt(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_qst_queue(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_qst_en(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_qst_tx_port(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_qst_lre(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_qst_tci(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_qst_ven(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_qst_flush(const struct qsl_nthw *p);
+
+/* QEN */
+void qsl_nthw_qen_select(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_qen_cnt(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_qen_en(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_qen_flush(const struct qsl_nthw *p);
+
+/* UNMQ */
+void qsl_nthw_unmq_select(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_unmq_cnt(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_unmq_dest_queue(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_unmq_en(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_unmq_flush(const struct qsl_nthw *p);
+
+#endif	/* __FLOW_NTHW_QSL_H__ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index a929a98b52..b159da7597 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -29,6 +29,7 @@
 #define MOD_PCIE3 (0xfbc48c18UL)
 #define MOD_PCI_RD_TG (0x9ad9eed2UL)
 #define MOD_PCI_WR_TG (0x274b69e1UL)
+#define MOD_QSL (0x448ed859UL)
 #define MOD_RAC (0xae830b42UL)
 #define MOD_RST9563 (0x385d6d1dUL)
 #define MOD_SDC (0xd2369530UL)
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index 9155cc4435..7b99a7fbdb 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -28,6 +28,7 @@
 #include "nthw_fpga_reg_defs_pcie3.h"
 #include "nthw_fpga_reg_defs_pci_rd_tg.h"
 #include "nthw_fpga_reg_defs_pci_wr_tg.h"
+#include "nthw_fpga_reg_defs_qsl.h"
 #include "nthw_fpga_reg_defs_rac.h"
 #include "nthw_fpga_reg_defs_rst9563.h"
 #include "nthw_fpga_reg_defs_sdc.h"
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_qsl.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_qsl.h
new file mode 100644
index 0000000000..6a15ddc00e
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_qsl.h
@@ -0,0 +1,66 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_qsl.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_QSL_
+#define _NTHW_FPGA_REG_DEFS_QSL_
+
+/* QSL */
+#define NTHW_MOD_QSL (0x448ed859UL)
+#define QSL_LTX_CTRL (0xd16859aUL)
+#define QSL_LTX_CTRL_ADR (0x56ab4bfeUL)
+#define QSL_LTX_CTRL_CNT (0x46a3d22fUL)
+#define QSL_LTX_DATA (0xa2c70783UL)
+#define QSL_LTX_DATA_LR (0xbd09e686UL)
+#define QSL_LTX_DATA_TSA (0xdc9172f1UL)
+#define QSL_LTX_DATA_TX_PORT (0x4e838100UL)
+#define QSL_QEN_CTRL (0xfe8ed79cUL)
+#define QSL_QEN_CTRL_ADR (0x81d44d48UL)
+#define QSL_QEN_CTRL_CNT (0x91dcd499UL)
+#define QSL_QEN_DATA (0x515f5585UL)
+#define QSL_QEN_DATA_EN (0xa1e5961UL)
+#define QSL_QST_CTRL (0x58cd5f95UL)
+#define QSL_QST_CTRL_ADR (0xf71b52e1UL)
+#define QSL_QST_CTRL_CNT (0xe713cb30UL)
+#define QSL_QST_DATA (0xf71cdd8cUL)
+#define QSL_QST_DATA_EN (0x19406021UL)
+#define QSL_QST_DATA_LRE (0x71626c7eUL)
+#define QSL_QST_DATA_QEN (0xf7cd0143UL)
+#define QSL_QST_DATA_QUEUE (0x70bc6d12UL)
+#define QSL_QST_DATA_TCI (0x3938f18dUL)
+#define QSL_QST_DATA_TX_PORT (0x101a63f0UL)
+#define QSL_QST_DATA_VEN (0xf28217c6UL)
+#define QSL_RCP_CTRL (0x2a0d86aeUL)
+#define QSL_RCP_CTRL_ADR (0x2798e4a0UL)
+#define QSL_RCP_CTRL_CNT (0x37907d71UL)
+#define QSL_RCP_DATA (0x85dc04b7UL)
+#define QSL_RCP_DATA_CAO (0x2b87358eUL)
+#define QSL_RCP_DATA_DISCARD (0x5b3da2b8UL)
+#define QSL_RCP_DATA_DROP (0x30f5b2fbUL)
+#define QSL_RCP_DATA_LR (0x3f2331c2UL)
+#define QSL_RCP_DATA_TBL_HI (0xde81892fUL)
+#define QSL_RCP_DATA_TBL_IDX (0xa8d19ee1UL)
+#define QSL_RCP_DATA_TBL_LO (0x538ee91eUL)
+#define QSL_RCP_DATA_TBL_MSK (0x2ee5f375UL)
+#define QSL_RCP_DATA_TSA (0xada2ddafUL)
+#define QSL_RCP_DATA_VLI (0x6da78f6dUL)
+#define QSL_UNMQ_CTRL (0xe759d3f1UL)
+#define QSL_UNMQ_CTRL_ADR (0xe5833152UL)
+#define QSL_UNMQ_CTRL_CNT (0xf58ba883UL)
+#define QSL_UNMQ_DATA (0x488851e8UL)
+#define QSL_UNMQ_DATA_DEST_QUEUE (0xef8ce959UL)
+#define QSL_UNMQ_DATA_EN (0x36ca8378UL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_QSL_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 12/31] net/ntnic: add slicer (SLC LR) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (16 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 11/31] net/ntnic: add queue select (QSL) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 13/31] net/ntnic: add packet descriptor builder (PDB) " Serhii Iliushyk
                   ` (33 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Slicer for Local Retransmit module can cut of the head a packet
before the packet leaves the FPGA RX pipeline.
This is used when the TX pipeline is configured
to add a new head in the packet.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    |  14 ++
 drivers/net/ntnic/include/hw_mod_slc_lr_v2.h  |  25 ++++
 drivers/net/ntnic/meson.build                 |   1 +
 .../nthw/flow_api/flow_backend/flow_backend.c |  66 +++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_slc_lr.c | 126 ++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_slc_lr.h |  54 ++++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |   1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |   2 +
 .../nthw/supported/nthw_fpga_reg_defs_slc.h   |  34 +++++
 .../supported/nthw_fpga_reg_defs_slc_lr.h     |  23 ++++
 10 files changed, 346 insertions(+)
 create mode 100644 drivers/net/ntnic/include/hw_mod_slc_lr_v2.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc_lr.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc_lr.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_slc.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_slc_lr.h

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 84f2ed6c6a..309365f30d 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -13,6 +13,7 @@
 #include "hw_mod_flm_v25.h"
 #include "hw_mod_km_v7.h"
 #include "hw_mod_qsl_v7.h"
+#include "hw_mod_slc_lr_v2.h"
 #include "hw_mod_hsh_v5.h"
 
 #define MAX_PHYS_ADAPTERS 8
@@ -96,6 +97,13 @@ struct qsl_func_s {
 	};
 };
 
+struct slc_lr_func_s {
+	COMMON_FUNC_INFO_S;
+	union {
+		struct hw_mod_slc_lr_v2_s v2;
+	};
+};
+
 enum debug_mode_e {
 	FLOW_BACKEND_DEBUG_MODE_NONE = 0x0000,
 	FLOW_BACKEND_DEBUG_MODE_WRITE = 0x0001
@@ -214,6 +222,12 @@ struct flow_api_backend_ops {
 	int (*qsl_qst_flush)(void *dev, const struct qsl_func_s *qsl, int entry, int cnt);
 	int (*qsl_qen_flush)(void *dev, const struct qsl_func_s *qsl, int entry, int cnt);
 	int (*qsl_unmq_flush)(void *dev, const struct qsl_func_s *qsl, int entry, int cnt);
+
+	/* SLC LR */
+	bool (*get_slc_lr_present)(void *dev);
+	uint32_t (*get_slc_lr_version)(void *dev);
+	int (*slc_lr_rcp_flush)(void *dev, const struct slc_lr_func_s *slc_lr, int category,
+		int cnt);
 };
 
 struct flow_api_backend_s {
diff --git a/drivers/net/ntnic/include/hw_mod_slc_lr_v2.h b/drivers/net/ntnic/include/hw_mod_slc_lr_v2.h
new file mode 100644
index 0000000000..718a3cff27
--- /dev/null
+++ b/drivers/net/ntnic/include/hw_mod_slc_lr_v2.h
@@ -0,0 +1,25 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _HW_MOD_SLC_LR_V2_H_
+#define _HW_MOD_SLC_LR_V2_H_
+
+#include <stdint.h>
+
+struct slc_lr_v2_rcp_s {
+	uint32_t head_slc_en;
+	uint32_t head_dyn;
+	int32_t head_ofs;
+	uint32_t tail_slc_en;
+	uint32_t tail_dyn;
+	int32_t tail_ofs;
+	uint32_t pcap;
+};
+
+struct hw_mod_slc_lr_v2_s {
+	struct slc_lr_v2_rcp_s *rcp;
+};
+
+#endif	/* _HW_MOD_SLC_V2_H_ */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index c7c5cd997f..2c303f6980 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -53,6 +53,7 @@ sources = files(
         'nthw/flow_filter/flow_nthw_info.c',
         'nthw/flow_filter/flow_nthw_km.c',
         'nthw/flow_filter/flow_nthw_qsl.c',
+        'nthw/flow_filter/flow_nthw_slc_lr.c',
         'nthw/model/nthw_fpga_model.c',
         'nthw/nthw_platform.c',
         'nthw/nthw_rac.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index a2422f8b31..6188d900bb 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -12,6 +12,7 @@
 #include "flow_nthw_flm.h"
 #include "flow_nthw_hsh.h"
 #include "flow_nthw_qsl.h"
+#include "flow_nthw_slc_lr.h"
 #include "ntnic_mod_reg.h"
 #include "nthw_fpga_model.h"
 #include "hw_mod_backend.h"
@@ -32,6 +33,7 @@ static struct backend_dev_s {
 	struct flm_nthw *p_flm_nthw;
 	struct hsh_nthw *p_hsh_nthw;
 	struct qsl_nthw *p_qsl_nthw;
+	struct slc_lr_nthw *p_slc_lr_nthw;
 	struct ifr_nthw *p_ifr_nthw;    /* TPE module */
 } be_devs[MAX_PHYS_ADAPTERS];
 
@@ -1436,6 +1438,55 @@ static int qsl_unmq_flush(void *be_dev, const struct qsl_func_s *qsl, int entry,
 	return 0;
 }
 
+/*
+ * SLC LR
+ */
+
+static bool slc_lr_get_present(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return be->p_slc_lr_nthw != NULL;
+}
+
+static uint32_t slc_lr_get_version(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return (uint32_t)((nthw_module_get_major_version(be->p_slc_lr_nthw->m_slc_lr) << 16) |
+			(nthw_module_get_minor_version(be->p_slc_lr_nthw->m_slc_lr) & 0xffff));
+}
+
+static int slc_lr_rcp_flush(void *be_dev, const struct slc_lr_func_s *slc_lr, int category,
+	int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, slc_lr, be->p_slc_lr_nthw);
+
+	if (slc_lr->ver == 2) {
+		slc_lr_nthw_rcp_cnt(be->p_slc_lr_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			slc_lr_nthw_rcp_select(be->p_slc_lr_nthw, category + i);
+			slc_lr_nthw_rcp_head_slc_en(be->p_slc_lr_nthw,
+				slc_lr->v2.rcp[category + i].head_slc_en);
+			slc_lr_nthw_rcp_head_dyn(be->p_slc_lr_nthw,
+				slc_lr->v2.rcp[category + i].head_dyn);
+			slc_lr_nthw_rcp_head_ofs(be->p_slc_lr_nthw,
+				slc_lr->v2.rcp[category + i].head_ofs);
+			slc_lr_nthw_rcp_tail_slc_en(be->p_slc_lr_nthw,
+				slc_lr->v2.rcp[category + i].tail_slc_en);
+			slc_lr_nthw_rcp_tail_dyn(be->p_slc_lr_nthw,
+				slc_lr->v2.rcp[category + i].tail_dyn);
+			slc_lr_nthw_rcp_tail_ofs(be->p_slc_lr_nthw,
+				slc_lr->v2.rcp[category + i].tail_ofs);
+			slc_lr_nthw_rcp_pcap(be->p_slc_lr_nthw, slc_lr->v2.rcp[category + i].pcap);
+			slc_lr_nthw_rcp_flush(be->p_slc_lr_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(slc_lr, be->p_slc_lr_nthw);
+	return 0;
+}
+
 /*
  * DBS
  */
@@ -1556,6 +1607,10 @@ const struct flow_api_backend_ops flow_be_iface = {
 	qsl_qst_flush,
 	qsl_qen_flush,
 	qsl_unmq_flush,
+
+	slc_lr_get_present,
+	slc_lr_get_version,
+	slc_lr_rcp_flush,
 };
 
 const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, void **dev)
@@ -1626,6 +1681,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_qsl_nthw = NULL;
 	}
 
+	/* Init nthw SLC LR */
+	if (slc_lr_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct slc_lr_nthw *pslclrnthw = slc_lr_nthw_new();
+		slc_lr_nthw_init(pslclrnthw, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_slc_lr_nthw = pslclrnthw;
+
+	} else {
+		be_devs[physical_adapter_no].p_slc_lr_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -1641,6 +1706,7 @@ static void bin_flow_backend_done(void *dev)
 	flm_nthw_delete(be_dev->p_flm_nthw);
 	hsh_nthw_delete(be_dev->p_hsh_nthw);
 	qsl_nthw_delete(be_dev->p_qsl_nthw);
+	slc_lr_nthw_delete(be_dev->p_slc_lr_nthw);
 }
 
 static const struct flow_backend_ops ops = {
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc_lr.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc_lr.c
new file mode 100644
index 0000000000..5961df7735
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc_lr.c
@@ -0,0 +1,126 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_slc_lr.h"
+
+void slc_lr_nthw_set_debug_mode(struct slc_lr_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_slc_lr, n_debug_mode);
+}
+
+struct slc_lr_nthw *slc_lr_nthw_new(void)
+{
+	struct slc_lr_nthw *p = malloc(sizeof(struct slc_lr_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void slc_lr_nthw_delete(struct slc_lr_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int slc_lr_nthw_init(struct slc_lr_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_SLC_LR, n_instance);
+
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: Slc %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_slc_lr = nthw_fpga_query_module(p_fpga, MOD_SLC_LR, n_instance);
+
+	/* RCP */
+	p->mp_rcp_ctrl = nthw_module_get_register(p->m_slc_lr, SLC_RCP_CTRL);
+	p->mp_rcp_addr = nthw_register_get_field(p->mp_rcp_ctrl, SLC_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = nthw_register_get_field(p->mp_rcp_ctrl, SLC_RCP_CTRL_CNT);
+	p->mp_rcp_data = nthw_module_get_register(p->m_slc_lr, SLC_RCP_DATA);
+	p->mp_rcp_data_head_slc_en =
+		nthw_register_get_field(p->mp_rcp_data, SLC_RCP_DATA_HEAD_SLC_EN);
+	p->mp_rcp_data_head_dyn = nthw_register_get_field(p->mp_rcp_data, SLC_RCP_DATA_HEAD_DYN);
+	p->mp_rcp_data_head_ofs = nthw_register_get_field(p->mp_rcp_data, SLC_RCP_DATA_HEAD_OFS);
+	p->mp_rcp_data_tail_slc_en =
+		nthw_register_get_field(p->mp_rcp_data, SLC_RCP_DATA_TAIL_SLC_EN);
+	p->mp_rcp_data_tail_dyn = nthw_register_get_field(p->mp_rcp_data, SLC_RCP_DATA_TAIL_DYN);
+	p->mp_rcp_data_tail_ofs = nthw_register_get_field(p->mp_rcp_data, SLC_RCP_DATA_TAIL_OFS);
+	p->mp_rcp_data_pcap = nthw_register_get_field(p->mp_rcp_data, SLC_RCP_DATA_PCAP);
+
+	return 0;
+}
+
+/* RCP */
+void slc_lr_nthw_rcp_select(const struct slc_lr_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_addr, val);
+}
+
+void slc_lr_nthw_rcp_cnt(const struct slc_lr_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void slc_lr_nthw_rcp_head_slc_en(const struct slc_lr_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_head_slc_en, val);
+}
+
+void slc_lr_nthw_rcp_head_dyn(const struct slc_lr_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_head_dyn, val);
+}
+
+void slc_lr_nthw_rcp_head_ofs(const struct slc_lr_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_head_ofs, val);
+}
+
+void slc_lr_nthw_rcp_tail_slc_en(const struct slc_lr_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_tail_slc_en, val);
+}
+
+void slc_lr_nthw_rcp_tail_dyn(const struct slc_lr_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_tail_dyn, val);
+}
+
+void slc_lr_nthw_rcp_tail_ofs(const struct slc_lr_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_tail_ofs, val);
+}
+
+void slc_lr_nthw_rcp_pcap(const struct slc_lr_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_pcap, val);
+}
+
+void slc_lr_nthw_rcp_flush(const struct slc_lr_nthw *p)
+{
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc_lr.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc_lr.h
new file mode 100644
index 0000000000..2eed32c022
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc_lr.h
@@ -0,0 +1,54 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_SLC_LR_H__
+#define __FLOW_NTHW_SLC_LR_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct slc_lr_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_slc_lr;
+
+	nthw_register_t *mp_rcp_ctrl;
+	nthw_field_t *mp_rcp_addr;
+	nthw_field_t *mp_rcp_cnt;
+	nthw_register_t *mp_rcp_data;
+
+	nthw_field_t *mp_rcp_data_head_slc_en;
+	nthw_field_t *mp_rcp_data_head_dyn;
+	nthw_field_t *mp_rcp_data_head_ofs;
+	nthw_field_t *mp_rcp_data_tail_slc_en;
+	nthw_field_t *mp_rcp_data_tail_dyn;
+	nthw_field_t *mp_rcp_data_tail_ofs;
+	nthw_field_t *mp_rcp_data_pcap;
+};
+
+typedef struct slc_lr_nthw slc_lr_nthw_t;
+
+struct slc_lr_nthw *slc_lr_nthw_new(void);
+void slc_lr_nthw_delete(struct slc_lr_nthw *p);
+int slc_lr_nthw_init(struct slc_lr_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int slc_lr_nthw_setup(struct slc_lr_nthw *p, int n_idx, int n_idx_cnt);
+void slc_lr_nthw_set_debug_mode(struct slc_lr_nthw *p, unsigned int n_debug_mode);
+
+/* RCP */
+void slc_lr_nthw_rcp_select(const struct slc_lr_nthw *p, uint32_t val);
+void slc_lr_nthw_rcp_cnt(const struct slc_lr_nthw *p, uint32_t val);
+void slc_lr_nthw_rcp_head_slc_en(const struct slc_lr_nthw *p, uint32_t val);
+void slc_lr_nthw_rcp_head_dyn(const struct slc_lr_nthw *p, uint32_t val);
+void slc_lr_nthw_rcp_head_ofs(const struct slc_lr_nthw *p, int32_t val);
+void slc_lr_nthw_rcp_tail_slc_en(const struct slc_lr_nthw *p, uint32_t val);
+void slc_lr_nthw_rcp_tail_dyn(const struct slc_lr_nthw *p, uint32_t val);
+void slc_lr_nthw_rcp_tail_ofs(const struct slc_lr_nthw *p, int32_t val);
+void slc_lr_nthw_rcp_pcap(const struct slc_lr_nthw *p, uint32_t val);
+void slc_lr_nthw_rcp_flush(const struct slc_lr_nthw *p);
+
+#endif	/* __FLOW_NTHW_SLC_LR_H__ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index b159da7597..22682b6a5f 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -33,6 +33,7 @@
 #define MOD_RAC (0xae830b42UL)
 #define MOD_RST9563 (0x385d6d1dUL)
 #define MOD_SDC (0xd2369530UL)
+#define MOD_SLC_LR (0x969fc50bUL)
 #define MOD_IDX_COUNT (14)
 
 /* aliases - only aliases go below this point */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index 7b99a7fbdb..f775a4b33a 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -32,6 +32,8 @@
 #include "nthw_fpga_reg_defs_rac.h"
 #include "nthw_fpga_reg_defs_rst9563.h"
 #include "nthw_fpga_reg_defs_sdc.h"
+#include "nthw_fpga_reg_defs_slc.h"
+#include "nthw_fpga_reg_defs_slc_lr.h"
 
 /* aliases */
 
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_slc.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_slc.h
new file mode 100644
index 0000000000..11a8ef79a1
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_slc.h
@@ -0,0 +1,34 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_slc.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_SLC_
+#define _NTHW_FPGA_REG_DEFS_SLC_
+
+/* SLC */
+#define NTHW_MOD_SLC (0x1aef1f38UL)
+#define SLC_RCP_CTRL (0xa3373b1UL)
+#define SLC_RCP_CTRL_ADR (0xe64629e7UL)
+#define SLC_RCP_CTRL_CNT (0xf64eb036UL)
+#define SLC_RCP_DATA (0xa5e2f1a8UL)
+#define SLC_RCP_DATA_HEAD_DYN (0x86b55a78UL)
+#define SLC_RCP_DATA_HEAD_OFS (0x24bcd7deUL)
+#define SLC_RCP_DATA_HEAD_SLC_EN (0x61cf5ef7UL)
+#define SLC_RCP_DATA_PCAP (0x84909c04UL)
+#define SLC_RCP_DATA_TAIL_DYN (0x85cd93a3UL)
+#define SLC_RCP_DATA_TAIL_OFS (0x27c41e05UL)
+#define SLC_RCP_DATA_TAIL_SLC_EN (0xa4f5112cUL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_SLC_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_slc_lr.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_slc_lr.h
new file mode 100644
index 0000000000..ef1f358cb3
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_slc_lr.h
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_slc_lr.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_SLC_LR_
+#define _NTHW_FPGA_REG_DEFS_SLC_LR_
+
+/* SLC_LR */
+#define NTHW_MOD_SLC_LR (0x969fc50bUL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_SLC_LR_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 13/31] net/ntnic: add packet descriptor builder (PDB) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (17 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 12/31] net/ntnic: add slicer (SLC LR) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 14/31] net/ntnic: add header field update (HFU) " Serhii Iliushyk
                   ` (32 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Packet Description Builder module creates packet meta-data
for example virtio-net headers.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    |  16 ++
 drivers/net/ntnic/include/hw_mod_pdb_v9.h     |  42 ++++
 drivers/net/ntnic/meson.build                 |   1 +
 .../nthw/flow_api/flow_backend/flow_backend.c |  93 ++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_pdb.c    | 210 ++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_pdb.h    |  85 +++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |   1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |   1 +
 .../nthw/supported/nthw_fpga_reg_defs_pdb.h   |  48 ++++
 9 files changed, 497 insertions(+)
 create mode 100644 drivers/net/ntnic/include/hw_mod_pdb_v9.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_pdb.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_pdb.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_pdb.h

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 309365f30d..3ea2fefc53 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -13,6 +13,7 @@
 #include "hw_mod_flm_v25.h"
 #include "hw_mod_km_v7.h"
 #include "hw_mod_qsl_v7.h"
+#include "hw_mod_pdb_v9.h"
 #include "hw_mod_slc_lr_v2.h"
 #include "hw_mod_hsh_v5.h"
 
@@ -104,6 +105,15 @@ struct slc_lr_func_s {
 	};
 };
 
+struct pdb_func_s {
+	COMMON_FUNC_INFO_S;
+	uint32_t nb_pdb_rcp_categories;
+
+	union {
+		struct hw_mod_pdb_v9_s v9;
+	};
+};
+
 enum debug_mode_e {
 	FLOW_BACKEND_DEBUG_MODE_NONE = 0x0000,
 	FLOW_BACKEND_DEBUG_MODE_WRITE = 0x0001
@@ -228,6 +238,12 @@ struct flow_api_backend_ops {
 	uint32_t (*get_slc_lr_version)(void *dev);
 	int (*slc_lr_rcp_flush)(void *dev, const struct slc_lr_func_s *slc_lr, int category,
 		int cnt);
+
+	/* PDB */
+	bool (*get_pdb_present)(void *dev);
+	uint32_t (*get_pdb_version)(void *dev);
+	int (*pdb_rcp_flush)(void *dev, const struct pdb_func_s *pdb, int category, int cnt);
+	int (*pdb_config_flush)(void *dev, const struct pdb_func_s *pdb);
 };
 
 struct flow_api_backend_s {
diff --git a/drivers/net/ntnic/include/hw_mod_pdb_v9.h b/drivers/net/ntnic/include/hw_mod_pdb_v9.h
new file mode 100644
index 0000000000..b155ee6d1e
--- /dev/null
+++ b/drivers/net/ntnic/include/hw_mod_pdb_v9.h
@@ -0,0 +1,42 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _HW_MOD_PDB_V9_H_
+#define _HW_MOD_PDB_V9_H_
+
+#include <stdint.h>
+
+struct pdb_v9_rcp_s {
+	uint32_t descriptor;
+	uint32_t desc_len;
+	uint32_t tx_port;
+	uint32_t tx_ignore;
+	uint32_t tx_now;
+	uint32_t crc_overwrite;
+	uint32_t align;
+	uint32_t ofs0_dyn;
+	int32_t ofs0_rel;
+	uint32_t ofs1_dyn;
+	int32_t ofs1_rel;
+	uint32_t ofs2_dyn;
+	int32_t ofs2_rel;
+	uint32_t ip_prot_tnl;
+	uint32_t ppc_hsh;
+	uint32_t duplicate_en;
+	uint32_t duplicate_bit;
+	uint32_t pcap_keep_fcs;	/* only field added to v9 cmp to v7/8 */
+};
+
+struct pdb_v9_config_s {
+	uint32_t ts_format;
+	uint32_t port_ofs;
+};
+
+struct hw_mod_pdb_v9_s {
+	struct pdb_v9_rcp_s *rcp;
+	struct pdb_v9_config_s *config;
+};
+
+#endif	/* _HW_MOD_PDB_V9_H_ */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 2c303f6980..35f7feb7be 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -52,6 +52,7 @@ sources = files(
         'nthw/flow_filter/flow_nthw_ifr.c',
         'nthw/flow_filter/flow_nthw_info.c',
         'nthw/flow_filter/flow_nthw_km.c',
+        'nthw/flow_filter/flow_nthw_pdb.c',
         'nthw/flow_filter/flow_nthw_qsl.c',
         'nthw/flow_filter/flow_nthw_slc_lr.c',
         'nthw/model/nthw_fpga_model.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index 6188d900bb..e3c4c5b7cb 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -13,6 +13,7 @@
 #include "flow_nthw_hsh.h"
 #include "flow_nthw_qsl.h"
 #include "flow_nthw_slc_lr.h"
+#include "flow_nthw_pdb.h"
 #include "ntnic_mod_reg.h"
 #include "nthw_fpga_model.h"
 #include "hw_mod_backend.h"
@@ -34,6 +35,7 @@ static struct backend_dev_s {
 	struct hsh_nthw *p_hsh_nthw;
 	struct qsl_nthw *p_qsl_nthw;
 	struct slc_lr_nthw *p_slc_lr_nthw;
+	struct pdb_nthw *p_pdb_nthw;
 	struct ifr_nthw *p_ifr_nthw;    /* TPE module */
 } be_devs[MAX_PHYS_ADAPTERS];
 
@@ -1487,6 +1489,81 @@ static int slc_lr_rcp_flush(void *be_dev, const struct slc_lr_func_s *slc_lr, in
 	return 0;
 }
 
+/*
+ * PDB
+ */
+
+static bool pdb_get_present(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return be->p_pdb_nthw != NULL;
+}
+
+static uint32_t pdb_get_version(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return (uint32_t)((nthw_module_get_major_version(be->p_pdb_nthw->m_pdb) << 16) |
+			(nthw_module_get_minor_version(be->p_pdb_nthw->m_pdb) & 0xffff));
+}
+
+static int pdb_rcp_flush(void *be_dev, const struct pdb_func_s *pdb, int category, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, pdb, be->p_pdb_nthw);
+
+	if (pdb->ver == 9) {
+		pdb_nthw_rcp_cnt(be->p_pdb_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			pdb_nthw_rcp_select(be->p_pdb_nthw, category + i);
+			pdb_nthw_rcp_descriptor(be->p_pdb_nthw,
+				pdb->v9.rcp[category + i].descriptor);
+			pdb_nthw_rcp_desc_len(be->p_pdb_nthw, pdb->v9.rcp[category + i].desc_len);
+			pdb_nthw_rcp_tx_port(be->p_pdb_nthw, pdb->v9.rcp[category + i].tx_port);
+			pdb_nthw_rcp_tx_ignore(be->p_pdb_nthw,
+				pdb->v9.rcp[category + i].tx_ignore);
+			pdb_nthw_rcp_tx_now(be->p_pdb_nthw, pdb->v9.rcp[category + i].tx_now);
+			pdb_nthw_rcp_crc_overwrite(be->p_pdb_nthw,
+				pdb->v9.rcp[category + i].crc_overwrite);
+			pdb_nthw_rcp_align(be->p_pdb_nthw, pdb->v9.rcp[category + i].align);
+			pdb_nthw_rcp_ofs0_dyn(be->p_pdb_nthw, pdb->v9.rcp[category + i].ofs0_dyn);
+			pdb_nthw_rcp_ofs0_rel(be->p_pdb_nthw, pdb->v9.rcp[category + i].ofs0_rel);
+			pdb_nthw_rcp_ofs1_dyn(be->p_pdb_nthw, pdb->v9.rcp[category + i].ofs1_dyn);
+			pdb_nthw_rcp_ofs1_rel(be->p_pdb_nthw, pdb->v9.rcp[category + i].ofs1_rel);
+			pdb_nthw_rcp_ofs2_dyn(be->p_pdb_nthw, pdb->v9.rcp[category + i].ofs2_dyn);
+			pdb_nthw_rcp_ofs2_rel(be->p_pdb_nthw, pdb->v9.rcp[category + i].ofs2_rel);
+			pdb_nthw_rcp_ip_prot_tnl(be->p_pdb_nthw,
+				pdb->v9.rcp[category + i].ip_prot_tnl);
+			pdb_nthw_rcp_ppc_hsh(be->p_pdb_nthw, pdb->v9.rcp[category + i].ppc_hsh);
+			pdb_nthw_rcp_duplicate_en(be->p_pdb_nthw,
+				pdb->v9.rcp[category + i].duplicate_en);
+			pdb_nthw_rcp_duplicate_bit(be->p_pdb_nthw,
+				pdb->v9.rcp[category + i].duplicate_bit);
+			pdb_nthw_rcp_duplicate_bit(be->p_pdb_nthw,
+				pdb->v9.rcp[category + i].pcap_keep_fcs);
+			pdb_nthw_rcp_flush(be->p_pdb_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(pdb, be->p_pdb_nthw);
+	return 0;
+}
+
+static int pdb_config_flush(void *be_dev, const struct pdb_func_s *pdb)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, pdb, be->p_pdb_nthw);
+
+	if (pdb->ver == 9) {
+		pdb_nthw_config_ts_format(be->p_pdb_nthw, pdb->v9.config->ts_format);
+		pdb_nthw_config_port_ofs(be->p_pdb_nthw, pdb->v9.config->port_ofs);
+		pdb_nthw_config_flush(be->p_pdb_nthw);
+	}
+
+	CHECK_DEBUG_OFF(pdb, be->p_pdb_nthw);
+	return 0;
+}
+
 /*
  * DBS
  */
@@ -1611,6 +1688,11 @@ const struct flow_api_backend_ops flow_be_iface = {
 	slc_lr_get_present,
 	slc_lr_get_version,
 	slc_lr_rcp_flush,
+
+	pdb_get_present,
+	pdb_get_version,
+	pdb_rcp_flush,
+	pdb_config_flush,
 };
 
 const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, void **dev)
@@ -1691,6 +1773,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_slc_lr_nthw = NULL;
 	}
 
+	/* Init nthw PDB */
+	if (pdb_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct pdb_nthw *ppdbnthw = pdb_nthw_new();
+		pdb_nthw_init(ppdbnthw, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_pdb_nthw = ppdbnthw;
+
+	} else {
+		be_devs[physical_adapter_no].p_pdb_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -1707,6 +1799,7 @@ static void bin_flow_backend_done(void *dev)
 	hsh_nthw_delete(be_dev->p_hsh_nthw);
 	qsl_nthw_delete(be_dev->p_qsl_nthw);
 	slc_lr_nthw_delete(be_dev->p_slc_lr_nthw);
+	pdb_nthw_delete(be_dev->p_pdb_nthw);
 }
 
 static const struct flow_backend_ops ops = {
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_pdb.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_pdb.c
new file mode 100644
index 0000000000..8ea10d8571
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_pdb.c
@@ -0,0 +1,210 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_pdb.h"
+
+void pdb_nthw_set_debug_mode(struct pdb_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_pdb, n_debug_mode);
+}
+
+struct pdb_nthw *pdb_nthw_new(void)
+{
+	struct pdb_nthw *p = malloc(sizeof(struct pdb_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void pdb_nthw_delete(struct pdb_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int pdb_nthw_init(struct pdb_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_PDB, n_instance);
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: Pdb %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_pdb = p_mod;
+
+	/* RCP */
+	p->mp_rcp_ctrl = nthw_module_get_register(p->m_pdb, PDB_RCP_CTRL);
+	p->mp_rcp_addr = nthw_register_get_field(p->mp_rcp_ctrl, PDB_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = nthw_register_get_field(p->mp_rcp_ctrl, PDB_RCP_CTRL_CNT);
+	p->mp_rcp_data = nthw_module_get_register(p->m_pdb, PDB_RCP_DATA);
+	p->mp_rcp_data_descriptor =
+		nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_DESCRIPTOR);
+	p->mp_rcp_data_desc_len = nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_DESC_LEN);
+	p->mp_rcp_data_tx_port = nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_TX_PORT);
+	p->mp_rcp_data_tx_ignore = nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_TX_IGNORE);
+	p->mp_rcp_data_tx_now = nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_TX_NOW);
+	p->mp_rcp_data_crc_overwrite =
+		nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_CRC_OVERWRITE);
+	p->mp_rcp_data_align = nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_ALIGN);
+	p->mp_rcp_data_ofs0_dyn = nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_OFS0_DYN);
+	p->mp_rcp_data_ofs0_rel = nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_OFS0_REL);
+	p->mp_rcp_data_ofs1_dyn = nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_OFS1_DYN);
+	p->mp_rcp_data_ofs1_rel = nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_OFS1_REL);
+	p->mp_rcp_data_ofs2_dyn = nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_OFS2_DYN);
+	p->mp_rcp_data_ofs2_rel = nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_OFS2_REL);
+	p->mp_rcp_data_ip_prot_tnl =
+		nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_IP_PROT_TNL);
+	p->mp_rcp_data_ppc_hsh = nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_PPC_HSH);
+	p->mp_rcp_data_duplicate_en =
+		nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_DUPLICATE_EN);
+	p->mp_rcp_data_duplicate_bit =
+		nthw_register_get_field(p->mp_rcp_data, PDB_RCP_DATA_DUPLICATE_BIT);
+	p->mp_rcp_data_pcap_keep_fcs =
+		nthw_register_query_field(p->mp_rcp_data, PDB_RCP_DATA_PCAP_KEEP_FCS);
+	/* CONFIG */
+	p->mp_config = nthw_module_get_register(p->m_pdb, PDB_CONFIG);
+	p->mp_config_ts_format = nthw_register_get_field(p->mp_config, PDB_CONFIG_TS_FORMAT);
+	p->mp_config_port_ofs = nthw_register_get_field(p->mp_config, PDB_CONFIG_PORT_OFS);
+
+	return 0;
+}
+
+/* RCP */
+void pdb_nthw_rcp_select(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_addr, val);
+}
+
+void pdb_nthw_rcp_cnt(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void pdb_nthw_rcp_descriptor(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_descriptor, val);
+}
+
+void pdb_nthw_rcp_desc_len(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_desc_len, val);
+}
+
+void pdb_nthw_rcp_tx_port(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_tx_port, val);
+}
+
+void pdb_nthw_rcp_tx_ignore(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_tx_ignore, val);
+}
+
+void pdb_nthw_rcp_tx_now(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_tx_now, val);
+}
+
+void pdb_nthw_rcp_crc_overwrite(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_crc_overwrite, val);
+}
+
+void pdb_nthw_rcp_align(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_align, val);
+}
+
+void pdb_nthw_rcp_ofs0_dyn(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ofs0_dyn, val);
+}
+
+void pdb_nthw_rcp_ofs0_rel(const struct pdb_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ofs0_rel, val);
+}
+
+void pdb_nthw_rcp_ofs1_dyn(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ofs1_dyn, val);
+}
+
+void pdb_nthw_rcp_ofs1_rel(const struct pdb_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ofs1_rel, val);
+}
+
+void pdb_nthw_rcp_ofs2_dyn(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ofs2_dyn, val);
+}
+
+void pdb_nthw_rcp_ofs2_rel(const struct pdb_nthw *p, int32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ofs2_rel, val);
+}
+
+void pdb_nthw_rcp_ip_prot_tnl(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ip_prot_tnl, val);
+}
+
+void pdb_nthw_rcp_ppc_hsh(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ppc_hsh, val);
+}
+
+void pdb_nthw_rcp_duplicate_en(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_duplicate_en, val);
+}
+
+void pdb_nthw_rcp_duplicate_bit(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_duplicate_bit, val);
+}
+
+void pdb_nthw_rcp_flush(const struct pdb_nthw *p)
+{
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+}
+
+/* CONFIG */
+void pdb_nthw_config_ts_format(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_config_ts_format, val);
+}
+
+void pdb_nthw_config_port_ofs(const struct pdb_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_config_port_ofs, val);
+}
+
+void pdb_nthw_config_flush(const struct pdb_nthw *p)
+{
+	nthw_register_flush(p->mp_config, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_pdb.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_pdb.h
new file mode 100644
index 0000000000..aafe12d3e0
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_pdb.h
@@ -0,0 +1,85 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_PDB_H__
+#define __FLOW_NTHW_PDB_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct pdb_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_pdb;
+
+	nthw_register_t *mp_rcp_ctrl;
+	nthw_field_t *mp_rcp_addr;
+	nthw_field_t *mp_rcp_cnt;
+	nthw_register_t *mp_rcp_data;
+	nthw_field_t *mp_rcp_data_descriptor;
+	nthw_field_t *mp_rcp_data_desc_len;
+	nthw_field_t *mp_rcp_data_tx_port;
+	nthw_field_t *mp_rcp_data_tx_ignore;
+	nthw_field_t *mp_rcp_data_tx_now;
+	nthw_field_t *mp_rcp_data_crc_overwrite;
+	nthw_field_t *mp_rcp_data_align;
+	nthw_field_t *mp_rcp_data_ofs0_dyn;
+	nthw_field_t *mp_rcp_data_ofs0_rel;
+	nthw_field_t *mp_rcp_data_ofs1_dyn;
+	nthw_field_t *mp_rcp_data_ofs1_rel;
+	nthw_field_t *mp_rcp_data_ofs2_dyn;
+	nthw_field_t *mp_rcp_data_ofs2_rel;
+	nthw_field_t *mp_rcp_data_ip_prot_tnl;
+	nthw_field_t *mp_rcp_data_ppc_hsh;
+	nthw_field_t *mp_rcp_data_duplicate_en;
+	nthw_field_t *mp_rcp_data_duplicate_bit;
+	nthw_field_t *mp_rcp_data_pcap_keep_fcs;
+
+	nthw_register_t *mp_config;
+	nthw_field_t *mp_config_ts_format;
+	nthw_field_t *mp_config_port_ofs;
+};
+
+typedef struct pdb_nthw pdb_nthw_t;
+
+struct pdb_nthw *pdb_nthw_new(void);
+void pdb_nthw_delete(struct pdb_nthw *p);
+int pdb_nthw_init(struct pdb_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int pdb_nthw_setup(struct pdb_nthw *p, int n_idx, int n_idx_cnt);
+void pdb_nthw_set_debug_mode(struct pdb_nthw *p, unsigned int n_debug_mode);
+
+/* RCP */
+void pdb_nthw_rcp_select(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_cnt(const struct pdb_nthw *p, uint32_t val);
+
+void pdb_nthw_rcp_descriptor(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_desc_len(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_tx_port(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_tx_ignore(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_tx_now(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_crc_overwrite(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_align(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_ofs0_dyn(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_ofs0_rel(const struct pdb_nthw *p, int32_t val);
+void pdb_nthw_rcp_ofs1_dyn(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_ofs1_rel(const struct pdb_nthw *p, int32_t val);
+void pdb_nthw_rcp_ofs2_dyn(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_ofs2_rel(const struct pdb_nthw *p, int32_t val);
+void pdb_nthw_rcp_ip_prot_tnl(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_ppc_hsh(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_duplicate_en(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_duplicate_bit(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_rcp_flush(const struct pdb_nthw *p);
+
+/* CONFIG */
+void pdb_nthw_config_ts_format(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_config_port_ofs(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_config_port_ofs(const struct pdb_nthw *p, uint32_t val);
+void pdb_nthw_config_flush(const struct pdb_nthw *p);
+
+#endif	/* __FLOW_NTHW_PDB_H__ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index 22682b6a5f..65c482f7c8 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -29,6 +29,7 @@
 #define MOD_PCIE3 (0xfbc48c18UL)
 #define MOD_PCI_RD_TG (0x9ad9eed2UL)
 #define MOD_PCI_WR_TG (0x274b69e1UL)
+#define MOD_PDB (0xa7771bffUL)
 #define MOD_QSL (0x448ed859UL)
 #define MOD_RAC (0xae830b42UL)
 #define MOD_RST9563 (0x385d6d1dUL)
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index f775a4b33a..ccb57fdd47 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -28,6 +28,7 @@
 #include "nthw_fpga_reg_defs_pcie3.h"
 #include "nthw_fpga_reg_defs_pci_rd_tg.h"
 #include "nthw_fpga_reg_defs_pci_wr_tg.h"
+#include "nthw_fpga_reg_defs_pdb.h"
 #include "nthw_fpga_reg_defs_qsl.h"
 #include "nthw_fpga_reg_defs_rac.h"
 #include "nthw_fpga_reg_defs_rst9563.h"
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_pdb.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_pdb.h
new file mode 100644
index 0000000000..98887ffccb
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_pdb.h
@@ -0,0 +1,48 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_pdb.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_PDB_
+#define _NTHW_FPGA_REG_DEFS_PDB_
+
+/* PDB */
+#define NTHW_MOD_PDB (0xa7771bffUL)
+#define PDB_CONFIG (0xf73771edUL)
+#define PDB_CONFIG_PORT_OFS (0xb5b30335UL)
+#define PDB_CONFIG_TS_FORMAT (0x7013d8aUL)
+#define PDB_RCP_CTRL (0x28ac2b3aUL)
+#define PDB_RCP_CTRL_ADR (0x9d08b0e4UL)
+#define PDB_RCP_CTRL_CNT (0x8d002935UL)
+#define PDB_RCP_DATA (0x877da923UL)
+#define PDB_RCP_DATA_ALIGN (0xe802afb8UL)
+#define PDB_RCP_DATA_CRC_OVERWRITE (0x4847dc0aUL)
+#define PDB_RCP_DATA_DESCRIPTOR (0x46cb76faUL)
+#define PDB_RCP_DATA_DESC_LEN (0xf467e85bUL)
+#define PDB_RCP_DATA_DUPLICATE_BIT (0xaeb59507UL)
+#define PDB_RCP_DATA_DUPLICATE_EN (0xbab03efeUL)
+#define PDB_RCP_DATA_IP_PROT_TNL (0xec892325UL)
+#define PDB_RCP_DATA_OFS0_DYN (0xcef3786aUL)
+#define PDB_RCP_DATA_OFS0_REL (0xde219bd9UL)
+#define PDB_RCP_DATA_OFS1_DYN (0xf39351daUL)
+#define PDB_RCP_DATA_OFS1_REL (0xe341b269UL)
+#define PDB_RCP_DATA_OFS2_DYN (0xb4332b0aUL)
+#define PDB_RCP_DATA_OFS2_REL (0xa4e1c8b9UL)
+#define PDB_RCP_DATA_PCAP_KEEP_FCS (0x90bc735eUL)
+#define PDB_RCP_DATA_PPC_HSH (0xac10e9f8UL)
+#define PDB_RCP_DATA_TX_IGNORE (0x14c556dcUL)
+#define PDB_RCP_DATA_TX_NOW (0x479cb22cUL)
+#define PDB_RCP_DATA_TX_PORT (0x412a5ed8UL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_PDB_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 14/31] net/ntnic: add header field update (HFU) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (18 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 13/31] net/ntnic: add packet descriptor builder (PDB) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 15/31] net/ntnic: add RPP local retransmit (RPP LR) " Serhii Iliushyk
                   ` (31 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Header Field Update module updates protocol fields
if the packets have been changed,
for example length fields and next protocol fields.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/meson.build                 |  1 +
 .../nthw/flow_api/flow_backend/flow_backend.c | 13 +++
 .../ntnic/nthw/flow_filter/flow_nthw_hfu.c    | 99 +++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_hfu.h    | 54 ++++++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |  1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |  1 +
 .../nthw/supported/nthw_fpga_reg_defs_hfu.h   | 49 +++++++++
 7 files changed, 218 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_hfu.h

diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 35f7feb7be..552cbc30bf 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -48,6 +48,7 @@ sources = files(
         'nthw/flow_api/flow_filter.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_flm.c',
+        'nthw/flow_filter/flow_nthw_hfu.c',
         'nthw/flow_filter/flow_nthw_hsh.c',
         'nthw/flow_filter/flow_nthw_ifr.c',
         'nthw/flow_filter/flow_nthw_info.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index e3c4c5b7cb..feb3355de3 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -10,6 +10,7 @@
 #include "flow_nthw_cat.h"
 #include "flow_nthw_km.h"
 #include "flow_nthw_flm.h"
+#include "flow_nthw_hfu.h"
 #include "flow_nthw_hsh.h"
 #include "flow_nthw_qsl.h"
 #include "flow_nthw_slc_lr.h"
@@ -36,6 +37,7 @@ static struct backend_dev_s {
 	struct qsl_nthw *p_qsl_nthw;
 	struct slc_lr_nthw *p_slc_lr_nthw;
 	struct pdb_nthw *p_pdb_nthw;
+	struct hfu_nthw *p_hfu_nthw;    /* TPE module */
 	struct ifr_nthw *p_ifr_nthw;    /* TPE module */
 } be_devs[MAX_PHYS_ADAPTERS];
 
@@ -1783,6 +1785,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_pdb_nthw = NULL;
 	}
 
+	/* Init nthw HFU */
+	if (hfu_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct hfu_nthw *ptr = hfu_nthw_new();
+		hfu_nthw_init(ptr, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_hfu_nthw = ptr;
+
+	} else {
+		be_devs[physical_adapter_no].p_hfu_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -1800,6 +1812,7 @@ static void bin_flow_backend_done(void *dev)
 	qsl_nthw_delete(be_dev->p_qsl_nthw);
 	slc_lr_nthw_delete(be_dev->p_slc_lr_nthw);
 	pdb_nthw_delete(be_dev->p_pdb_nthw);
+	hfu_nthw_delete(be_dev->p_hfu_nthw);
 }
 
 static const struct flow_backend_ops ops = {
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.c
new file mode 100644
index 0000000000..36d181df02
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.c
@@ -0,0 +1,99 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_hfu.h"
+
+struct hfu_nthw *hfu_nthw_new(void)
+{
+	struct hfu_nthw *p = malloc(sizeof(struct hfu_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void hfu_nthw_delete(struct hfu_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int hfu_nthw_init(struct hfu_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_HFU, n_instance);
+
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: Hfu %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_hfu = nthw_fpga_query_module(p_fpga, MOD_HFU, n_instance);
+
+	p->mp_rcp_ctrl = nthw_module_get_register(p->m_hfu, HFU_RCP_CTRL);
+	p->mp_rcp_addr = nthw_register_get_field(p->mp_rcp_ctrl, HFU_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = nthw_register_get_field(p->mp_rcp_ctrl, HFU_RCP_CTRL_CNT);
+
+	p->mp_rcp_data = nthw_module_get_register(p->m_hfu, HFU_RCP_DATA);
+	p->mp_rcp_data_len_a_wr = nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_WR);
+	p->mp_rcp_data_len_a_ol4len =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_OL4LEN);
+	p->mp_rcp_data_len_a_pos_dyn =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_POS_DYN);
+	p->mp_rcp_data_len_a_pos_ofs =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_POS_OFS);
+	p->mp_rcp_data_len_a_add_dyn =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_ADD_DYN);
+	p->mp_rcp_data_len_a_add_ofs =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_ADD_OFS);
+	p->mp_rcp_data_len_a_sub_dyn =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_SUB_DYN);
+	p->mp_rcp_data_len_b_wr = nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_B_WR);
+	p->mp_rcp_data_len_b_pos_dyn =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_B_POS_DYN);
+	p->mp_rcp_data_len_b_pos_ofs =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_B_POS_OFS);
+	p->mp_rcp_data_len_b_add_dyn =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_B_ADD_DYN);
+	p->mp_rcp_data_len_b_add_ofs =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_B_ADD_OFS);
+	p->mp_rcp_data_len_b_sub_dyn =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_B_SUB_DYN);
+	p->mp_rcp_data_len_c_wr = nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_C_WR);
+	p->mp_rcp_data_len_c_pos_dyn =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_C_POS_DYN);
+	p->mp_rcp_data_len_c_pos_ofs =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_C_POS_OFS);
+	p->mp_rcp_data_len_c_add_dyn =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_C_ADD_DYN);
+	p->mp_rcp_data_len_c_add_ofs =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_C_ADD_OFS);
+	p->mp_rcp_data_len_c_sub_dyn =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_C_SUB_DYN);
+	p->mp_rcp_data_ttl_wr = nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_TTL_WR);
+	p->mp_rcp_data_ttl_pos_dyn =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_TTL_POS_DYN);
+	p->mp_rcp_data_ttl_pos_ofs =
+		nthw_register_get_field(p->mp_rcp_data, HFU_RCP_DATA_TTL_POS_OFS);
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.h
new file mode 100644
index 0000000000..7a59066b92
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.h
@@ -0,0 +1,54 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_HFU_H__
+#define __FLOW_NTHW_HFU_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct hfu_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_hfu;
+
+	nthw_register_t *mp_rcp_ctrl;
+	nthw_field_t *mp_rcp_addr;
+	nthw_field_t *mp_rcp_cnt;
+
+	nthw_register_t *mp_rcp_data;
+	nthw_field_t *mp_rcp_data_len_a_wr;
+	nthw_field_t *mp_rcp_data_len_a_ol4len;
+	nthw_field_t *mp_rcp_data_len_a_pos_dyn;
+	nthw_field_t *mp_rcp_data_len_a_pos_ofs;
+	nthw_field_t *mp_rcp_data_len_a_add_dyn;
+	nthw_field_t *mp_rcp_data_len_a_add_ofs;
+	nthw_field_t *mp_rcp_data_len_a_sub_dyn;
+	nthw_field_t *mp_rcp_data_len_b_wr;
+	nthw_field_t *mp_rcp_data_len_b_pos_dyn;
+	nthw_field_t *mp_rcp_data_len_b_pos_ofs;
+	nthw_field_t *mp_rcp_data_len_b_add_dyn;
+	nthw_field_t *mp_rcp_data_len_b_add_ofs;
+	nthw_field_t *mp_rcp_data_len_b_sub_dyn;
+	nthw_field_t *mp_rcp_data_len_c_wr;
+	nthw_field_t *mp_rcp_data_len_c_pos_dyn;
+	nthw_field_t *mp_rcp_data_len_c_pos_ofs;
+	nthw_field_t *mp_rcp_data_len_c_add_dyn;
+	nthw_field_t *mp_rcp_data_len_c_add_ofs;
+	nthw_field_t *mp_rcp_data_len_c_sub_dyn;
+	nthw_field_t *mp_rcp_data_ttl_wr;
+	nthw_field_t *mp_rcp_data_ttl_pos_dyn;
+	nthw_field_t *mp_rcp_data_ttl_pos_ofs;
+};
+
+struct hfu_nthw *hfu_nthw_new(void);
+void hfu_nthw_delete(struct hfu_nthw *p);
+int hfu_nthw_init(struct hfu_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int hfu_nthw_setup(struct hfu_nthw *p, int n_idx, int n_idx_cnt);
+
+#endif	/* __FLOW_NTHW_HFU_H__ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index 65c482f7c8..2d53dfdf98 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -19,6 +19,7 @@
 #define MOD_GFG (0xfc423807UL)
 #define MOD_GMF (0x68b1d15aUL)
 #define MOD_GPIO_PHY (0xbbe81659UL)
+#define MOD_HFU (0x4a70e72UL)
 #define MOD_HIF (0x7815363UL)
 #define MOD_HSH (0x501484bfUL)
 #define MOD_I2CM (0x93bc7780UL)
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index ccb57fdd47..c49913036e 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -18,6 +18,7 @@
 #include "nthw_fpga_reg_defs_gfg.h"
 #include "nthw_fpga_reg_defs_gmf.h"
 #include "nthw_fpga_reg_defs_gpio_phy.h"
+#include "nthw_fpga_reg_defs_hfu.h"
 #include "nthw_fpga_reg_defs_hif.h"
 #include "nthw_fpga_reg_defs_hsh.h"
 #include "nthw_fpga_reg_defs_i2cm.h"
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_hfu.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_hfu.h
new file mode 100644
index 0000000000..1334e55ef3
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_hfu.h
@@ -0,0 +1,49 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_hfu.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_HFU_
+#define _NTHW_FPGA_REG_DEFS_HFU_
+
+/* HFU */
+#define NTHW_MOD_HFU (0x4a70e72UL)
+#define HFU_RCP_CTRL (0xbfa69368UL)
+#define HFU_RCP_CTRL_ADR (0xa3c53608UL)
+#define HFU_RCP_CTRL_CNT (0xb3cdafd9UL)
+#define HFU_RCP_DATA (0x10771171UL)
+#define HFU_RCP_DATA_LEN_A_ADD_DYN (0xf48e5cadUL)
+#define HFU_RCP_DATA_LEN_A_ADD_OFS (0x5687d10bUL)
+#define HFU_RCP_DATA_LEN_A_OL4LEN (0xb06eaffcUL)
+#define HFU_RCP_DATA_LEN_A_POS_DYN (0x8d207086UL)
+#define HFU_RCP_DATA_LEN_A_POS_OFS (0x2f29fd20UL)
+#define HFU_RCP_DATA_LEN_A_SUB_DYN (0x4305f5d4UL)
+#define HFU_RCP_DATA_LEN_A_WR (0x22d5466UL)
+#define HFU_RCP_DATA_LEN_B_ADD_DYN (0xcd036068UL)
+#define HFU_RCP_DATA_LEN_B_ADD_OFS (0x6f0aedceUL)
+#define HFU_RCP_DATA_LEN_B_POS_DYN (0xb4ad4c43UL)
+#define HFU_RCP_DATA_LEN_B_POS_OFS (0x16a4c1e5UL)
+#define HFU_RCP_DATA_LEN_B_SUB_DYN (0x7a88c911UL)
+#define HFU_RCP_DATA_LEN_B_WR (0x1098fb88UL)
+#define HFU_RCP_DATA_LEN_C_ADD_DYN (0xda78742bUL)
+#define HFU_RCP_DATA_LEN_C_ADD_OFS (0x7871f98dUL)
+#define HFU_RCP_DATA_LEN_C_POS_DYN (0xa3d65800UL)
+#define HFU_RCP_DATA_LEN_C_POS_OFS (0x1dfd5a6UL)
+#define HFU_RCP_DATA_LEN_C_SUB_DYN (0x6df3dd52UL)
+#define HFU_RCP_DATA_LEN_C_WR (0xa8249cedUL)
+#define HFU_RCP_DATA_TTL_POS_DYN (0x92a70913UL)
+#define HFU_RCP_DATA_TTL_POS_OFS (0x30ae84b5UL)
+#define HFU_RCP_DATA_TTL_WR (0x7a1aaf7UL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_HFU_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 15/31] net/ntnic: add RPP local retransmit (RPP LR) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (19 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 14/31] net/ntnic: add header field update (HFU) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 16/31] net/ntnic: add copier (Tx CPY) " Serhii Iliushyk
                   ` (30 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The RX Packet Process for Local Retransmit module can add bytes
in the FPGA TX pipeline, which is needed when the packet increases in size.
Note, this makes room for packet expansion,
but the actual expansion is done by the modules.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/meson.build                 |  1 +
 .../nthw/flow_api/flow_backend/flow_backend.c | 13 ++++
 .../ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c | 76 +++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h | 44 +++++++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |  1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |  1 +
 .../supported/nthw_fpga_reg_defs_rpp_lr.h     | 37 +++++++++
 7 files changed, 173 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rpp_lr.h

diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 552cbc30bf..2dfb0d0627 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -55,6 +55,7 @@ sources = files(
         'nthw/flow_filter/flow_nthw_km.c',
         'nthw/flow_filter/flow_nthw_pdb.c',
         'nthw/flow_filter/flow_nthw_qsl.c',
+        'nthw/flow_filter/flow_nthw_rpp_lr.c',
         'nthw/flow_filter/flow_nthw_slc_lr.c',
         'nthw/model/nthw_fpga_model.c',
         'nthw/nthw_platform.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index feb3355de3..e2abbf0368 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -15,6 +15,7 @@
 #include "flow_nthw_qsl.h"
 #include "flow_nthw_slc_lr.h"
 #include "flow_nthw_pdb.h"
+#include "flow_nthw_rpp_lr.h"
 #include "ntnic_mod_reg.h"
 #include "nthw_fpga_model.h"
 #include "hw_mod_backend.h"
@@ -38,6 +39,7 @@ static struct backend_dev_s {
 	struct slc_lr_nthw *p_slc_lr_nthw;
 	struct pdb_nthw *p_pdb_nthw;
 	struct hfu_nthw *p_hfu_nthw;    /* TPE module */
+	struct rpp_lr_nthw *p_rpp_lr_nthw;      /* TPE module */
 	struct ifr_nthw *p_ifr_nthw;    /* TPE module */
 } be_devs[MAX_PHYS_ADAPTERS];
 
@@ -1795,6 +1797,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_hfu_nthw = NULL;
 	}
 
+	/* Init nthw RPP_LR */
+	if (rpp_lr_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct rpp_lr_nthw *ptr = rpp_lr_nthw_new();
+		rpp_lr_nthw_init(ptr, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_rpp_lr_nthw = ptr;
+
+	} else {
+		be_devs[physical_adapter_no].p_rpp_lr_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -1813,6 +1825,7 @@ static void bin_flow_backend_done(void *dev)
 	slc_lr_nthw_delete(be_dev->p_slc_lr_nthw);
 	pdb_nthw_delete(be_dev->p_pdb_nthw);
 	hfu_nthw_delete(be_dev->p_hfu_nthw);
+	rpp_lr_nthw_delete(be_dev->p_rpp_lr_nthw);
 }
 
 static const struct flow_backend_ops ops = {
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c
new file mode 100644
index 0000000000..84bbcbdc4f
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c
@@ -0,0 +1,76 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_rpp_lr.h"
+
+struct rpp_lr_nthw *rpp_lr_nthw_new(void)
+{
+	struct rpp_lr_nthw *p = malloc(sizeof(struct rpp_lr_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void rpp_lr_nthw_delete(struct rpp_lr_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int rpp_lr_nthw_init(struct rpp_lr_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_RPP_LR, n_instance);
+
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: RppLr %d: no such instance\n", p_adapter_id_str,
+			n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_rpp_lr = nthw_fpga_query_module(p_fpga, MOD_RPP_LR, n_instance);
+
+	p->mp_rcp_ctrl = nthw_module_get_register(p->m_rpp_lr, RPP_LR_RCP_CTRL);
+	p->mp_rcp_addr = nthw_register_get_field(p->mp_rcp_ctrl, RPP_LR_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = nthw_register_get_field(p->mp_rcp_ctrl, RPP_LR_RCP_CTRL_CNT);
+	p->mp_rcp_data = nthw_module_get_register(p->m_rpp_lr, RPP_LR_RCP_DATA);
+	p->mp_rcp_data_exp = nthw_register_get_field(p->mp_rcp_data, RPP_LR_RCP_DATA_EXP);
+
+	p->mp_ifr_rcp_ctrl = nthw_module_query_register(p->m_rpp_lr, RPP_LR_IFR_RCP_CTRL);
+	p->mp_ifr_rcp_addr =
+		nthw_register_query_field(p->mp_ifr_rcp_ctrl, RPP_LR_IFR_RCP_CTRL_ADR);
+	p->mp_ifr_rcp_cnt = nthw_register_query_field(p->mp_ifr_rcp_ctrl, RPP_LR_IFR_RCP_CTRL_CNT);
+	p->mp_ifr_rcp_data = nthw_module_query_register(p->m_rpp_lr, RPP_LR_IFR_RCP_DATA);
+	p->mp_ifr_rcp_data_ipv4_en =
+		nthw_register_query_field(p->mp_ifr_rcp_data, RPP_LR_IFR_RCP_DATA_IPV4_EN);
+	p->mp_ifr_rcp_data_ipv6_en =
+		nthw_register_query_field(p->mp_ifr_rcp_data, RPP_LR_IFR_RCP_DATA_IPV6_EN);
+	p->mp_ifr_rcp_data_mtu =
+		nthw_register_query_field(p->mp_ifr_rcp_data, RPP_LR_IFR_RCP_DATA_MTU);
+	p->mp_ifr_rcp_data_ipv4_df_drop =
+		nthw_register_query_field(p->mp_ifr_rcp_data, RPP_LR_IFR_RCP_DATA_IPV4_DF_DROP);
+	p->mp_ifr_rcp_data_ipv6_drop =
+		nthw_register_query_field(p->mp_ifr_rcp_data, RPP_LR_IFR_RCP_DATA_IPV6_DROP);
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h
new file mode 100644
index 0000000000..509e46fc48
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h
@@ -0,0 +1,44 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_RPP_LR_H__
+#define __FLOW_NTHW_RPP_LR_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct rpp_lr_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_rpp_lr;
+
+	nthw_register_t *mp_rcp_ctrl;
+	nthw_field_t *mp_rcp_addr;
+	nthw_field_t *mp_rcp_cnt;
+
+	nthw_register_t *mp_rcp_data;
+	nthw_field_t *mp_rcp_data_exp;
+
+	nthw_register_t *mp_ifr_rcp_ctrl;
+	nthw_field_t *mp_ifr_rcp_addr;
+	nthw_field_t *mp_ifr_rcp_cnt;
+
+	nthw_register_t *mp_ifr_rcp_data;
+	nthw_field_t *mp_ifr_rcp_data_ipv4_en;
+	nthw_field_t *mp_ifr_rcp_data_ipv6_en;
+	nthw_field_t *mp_ifr_rcp_data_mtu;
+	nthw_field_t *mp_ifr_rcp_data_ipv4_df_drop;
+	nthw_field_t *mp_ifr_rcp_data_ipv6_drop;
+};
+
+struct rpp_lr_nthw *rpp_lr_nthw_new(void);
+void rpp_lr_nthw_delete(struct rpp_lr_nthw *p);
+int rpp_lr_nthw_init(struct rpp_lr_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int rpp_lr_nthw_setup(struct rpp_lr_nthw *p, int n_idx, int n_idx_cnt);
+
+#endif	/* __FLOW_NTHW_RPP_LR_H__ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index 2d53dfdf98..f1d055a36e 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -33,6 +33,7 @@
 #define MOD_PDB (0xa7771bffUL)
 #define MOD_QSL (0x448ed859UL)
 #define MOD_RAC (0xae830b42UL)
+#define MOD_RPP_LR (0xba7f945cUL)
 #define MOD_RST9563 (0x385d6d1dUL)
 #define MOD_SDC (0xd2369530UL)
 #define MOD_SLC_LR (0x969fc50bUL)
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index c49913036e..c39901ce39 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -32,6 +32,7 @@
 #include "nthw_fpga_reg_defs_pdb.h"
 #include "nthw_fpga_reg_defs_qsl.h"
 #include "nthw_fpga_reg_defs_rac.h"
+#include "nthw_fpga_reg_defs_rpp_lr.h"
 #include "nthw_fpga_reg_defs_rst9563.h"
 #include "nthw_fpga_reg_defs_sdc.h"
 #include "nthw_fpga_reg_defs_slc.h"
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rpp_lr.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rpp_lr.h
new file mode 100644
index 0000000000..f84cdf5939
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rpp_lr.h
@@ -0,0 +1,37 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_rpp_lr.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_RPP_LR_
+#define _NTHW_FPGA_REG_DEFS_RPP_LR_
+
+/* RPP_LR */
+#define NTHW_MOD_RPP_LR (0xba7f945cUL)
+#define RPP_LR_IFR_RCP_CTRL (0xce88594UL)
+#define RPP_LR_IFR_RCP_CTRL_ADR (0x4b4cc068UL)
+#define RPP_LR_IFR_RCP_CTRL_CNT (0x5b4459b9UL)
+#define RPP_LR_IFR_RCP_DATA (0xa339078dUL)
+#define RPP_LR_IFR_RCP_DATA_IPV4_DF_DROP (0xee1d681fUL)
+#define RPP_LR_IFR_RCP_DATA_IPV4_EN (0xfe386131UL)
+#define RPP_LR_IFR_RCP_DATA_IPV6_DROP (0x41f324ffUL)
+#define RPP_LR_IFR_RCP_DATA_IPV6_EN (0x5431a9baUL)
+#define RPP_LR_IFR_RCP_DATA_MTU (0x871a2322UL)
+#define RPP_LR_RCP_CTRL (0xf3395d47UL)
+#define RPP_LR_RCP_CTRL_ADR (0x4916a944UL)
+#define RPP_LR_RCP_CTRL_CNT (0x591e3095UL)
+#define RPP_LR_RCP_DATA (0x5ce8df5eUL)
+#define RPP_LR_RCP_DATA_EXP (0x578ca035UL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_RPP_LR_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 16/31] net/ntnic: add copier (Tx CPY) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (20 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 15/31] net/ntnic: add RPP local retransmit (RPP LR) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 17/31] net/ntnic: add checksum update (CSU) " Serhii Iliushyk
                   ` (29 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The TX Copy module writes data to packet fields based on the lookup
performed by the FLM module.
This is used for NAT and can support other actions
based on the RTE action MODIFY_FIELD.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/meson.build                 |   1 +
 .../nthw/flow_api/flow_backend/flow_backend.c |  13 +
 .../ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c | 339 ++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h |  49 +++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |   1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |   2 +
 .../nthw/supported/nthw_fpga_reg_defs_cpy.h   | 113 ++++++
 .../supported/nthw_fpga_reg_defs_tx_cpy.h     |  23 ++
 8 files changed, 541 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_cpy.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_cpy.h

diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 2dfb0d0627..3c00203e34 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -57,6 +57,7 @@ sources = files(
         'nthw/flow_filter/flow_nthw_qsl.c',
         'nthw/flow_filter/flow_nthw_rpp_lr.c',
         'nthw/flow_filter/flow_nthw_slc_lr.c',
+        'nthw/flow_filter/flow_nthw_tx_cpy.c',
         'nthw/model/nthw_fpga_model.c',
         'nthw/nthw_platform.c',
         'nthw/nthw_rac.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index e2abbf0368..af1e8ce3a4 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -16,6 +16,7 @@
 #include "flow_nthw_slc_lr.h"
 #include "flow_nthw_pdb.h"
 #include "flow_nthw_rpp_lr.h"
+#include "flow_nthw_tx_cpy.h"
 #include "ntnic_mod_reg.h"
 #include "nthw_fpga_model.h"
 #include "hw_mod_backend.h"
@@ -40,6 +41,7 @@ static struct backend_dev_s {
 	struct pdb_nthw *p_pdb_nthw;
 	struct hfu_nthw *p_hfu_nthw;    /* TPE module */
 	struct rpp_lr_nthw *p_rpp_lr_nthw;      /* TPE module */
+	struct tx_cpy_nthw *p_tx_cpy_nthw;      /* TPE module */
 	struct ifr_nthw *p_ifr_nthw;    /* TPE module */
 } be_devs[MAX_PHYS_ADAPTERS];
 
@@ -1807,6 +1809,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_rpp_lr_nthw = NULL;
 	}
 
+	/* Init nthw TX_CPY */
+	if (tx_cpy_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct tx_cpy_nthw *ptr = tx_cpy_nthw_new();
+		tx_cpy_nthw_init(ptr, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_tx_cpy_nthw = ptr;
+
+	} else {
+		be_devs[physical_adapter_no].p_tx_cpy_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -1826,6 +1838,7 @@ static void bin_flow_backend_done(void *dev)
 	pdb_nthw_delete(be_dev->p_pdb_nthw);
 	hfu_nthw_delete(be_dev->p_hfu_nthw);
 	rpp_lr_nthw_delete(be_dev->p_rpp_lr_nthw);
+	tx_cpy_nthw_delete(be_dev->p_tx_cpy_nthw);
 }
 
 static const struct flow_backend_ops ops = {
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c
new file mode 100644
index 0000000000..197baae334
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c
@@ -0,0 +1,339 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_tx_cpy.h"
+
+struct tx_cpy_nthw *tx_cpy_nthw_new(void)
+{
+	struct tx_cpy_nthw *p = malloc(sizeof(struct tx_cpy_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void tx_cpy_nthw_delete(struct tx_cpy_nthw *p)
+{
+	if (p) {
+		free(p->m_writers);
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int tx_cpy_nthw_init(struct tx_cpy_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_TX_CPY, n_instance);
+
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: TxCpy %d: no such instance\n", p_adapter_id_str,
+			n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_tx_cpy = nthw_fpga_query_module(p_fpga, MOD_TX_CPY, n_instance);
+
+	const int writers_cnt = nthw_fpga_get_product_param(p->mp_fpga, NT_TX_CPY_WRITERS, 0);
+
+	if (writers_cnt < 1)
+		return -1;
+
+	p->m_writers_cnt = (unsigned int)writers_cnt;
+	p->m_writers = calloc(p->m_writers_cnt, sizeof(struct tx_cpy_writers_s));
+
+	if (p->m_writers == NULL)
+		return -1;
+
+	const int variant = nthw_fpga_get_product_param(p->mp_fpga, NT_TX_CPY_VARIANT, 0);
+
+	switch (p->m_writers_cnt) {
+	default:
+	case 6:
+		p->m_writers[5].mp_writer_ctrl =
+			nthw_module_get_register(p->m_tx_cpy, CPY_WRITER5_CTRL);
+		p->m_writers[5].mp_writer_ctrl_addr =
+			nthw_register_get_field(p->m_writers[5].mp_writer_ctrl,
+				CPY_WRITER5_CTRL_ADR);
+		p->m_writers[5].mp_writer_ctrl_cnt =
+			nthw_register_get_field(p->m_writers[5].mp_writer_ctrl,
+				CPY_WRITER5_CTRL_CNT);
+		p->m_writers[5].mp_writer_data =
+			nthw_module_get_register(p->m_tx_cpy, CPY_WRITER5_DATA);
+		p->m_writers[5].mp_writer_data_reader_select =
+			nthw_register_get_field(p->m_writers[5].mp_writer_data,
+				CPY_WRITER5_DATA_READER_SELECT);
+		p->m_writers[5].mp_writer_data_dyn =
+			nthw_register_get_field(p->m_writers[5].mp_writer_data,
+				CPY_WRITER5_DATA_DYN);
+		p->m_writers[5].mp_writer_data_ofs =
+			nthw_register_get_field(p->m_writers[5].mp_writer_data,
+				CPY_WRITER5_DATA_OFS);
+		p->m_writers[5].mp_writer_data_len =
+			nthw_register_get_field(p->m_writers[5].mp_writer_data,
+				CPY_WRITER5_DATA_LEN);
+
+		if (variant != 0) {
+			p->m_writers[5].mp_writer_data_mask_pointer =
+				nthw_register_get_field(p->m_writers[5].mp_writer_data,
+					CPY_WRITER5_DATA_MASK_POINTER);
+			p->m_writers[5].mp_writer_mask_ctrl =
+				nthw_module_get_register(p->m_tx_cpy, CPY_WRITER5_MASK_CTRL);
+			p->m_writers[5].mp_writer_mask_ctrl_addr =
+				nthw_register_get_field(p->m_writers[5].mp_writer_mask_ctrl,
+					CPY_WRITER5_MASK_CTRL_ADR);
+			p->m_writers[5].mp_writer_mask_ctrl_cnt =
+				nthw_register_get_field(p->m_writers[5].mp_writer_mask_ctrl,
+					CPY_WRITER5_MASK_CTRL_CNT);
+			p->m_writers[5].mp_writer_mask_data =
+				nthw_module_get_register(p->m_tx_cpy, CPY_WRITER5_MASK_DATA);
+			p->m_writers[5].mp_writer_mask_data_byte_mask =
+				nthw_register_get_field(p->m_writers[5].mp_writer_mask_data,
+					CPY_WRITER5_MASK_DATA_BYTE_MASK);
+		}
+
+	/* Fallthrough */
+	case 5:
+		p->m_writers[4].mp_writer_ctrl =
+			nthw_module_get_register(p->m_tx_cpy, CPY_WRITER4_CTRL);
+		p->m_writers[4].mp_writer_ctrl_addr =
+			nthw_register_get_field(p->m_writers[4].mp_writer_ctrl,
+				CPY_WRITER4_CTRL_ADR);
+		p->m_writers[4].mp_writer_ctrl_cnt =
+			nthw_register_get_field(p->m_writers[4].mp_writer_ctrl,
+				CPY_WRITER4_CTRL_CNT);
+		p->m_writers[4].mp_writer_data =
+			nthw_module_get_register(p->m_tx_cpy, CPY_WRITER4_DATA);
+		p->m_writers[4].mp_writer_data_reader_select =
+			nthw_register_get_field(p->m_writers[4].mp_writer_data,
+				CPY_WRITER4_DATA_READER_SELECT);
+		p->m_writers[4].mp_writer_data_dyn =
+			nthw_register_get_field(p->m_writers[4].mp_writer_data,
+				CPY_WRITER4_DATA_DYN);
+		p->m_writers[4].mp_writer_data_ofs =
+			nthw_register_get_field(p->m_writers[4].mp_writer_data,
+				CPY_WRITER4_DATA_OFS);
+		p->m_writers[4].mp_writer_data_len =
+			nthw_register_get_field(p->m_writers[4].mp_writer_data,
+				CPY_WRITER4_DATA_LEN);
+
+		if (variant != 0) {
+			p->m_writers[4].mp_writer_data_mask_pointer =
+				nthw_register_get_field(p->m_writers[4].mp_writer_data,
+					CPY_WRITER4_DATA_MASK_POINTER);
+			p->m_writers[4].mp_writer_mask_ctrl =
+				nthw_module_get_register(p->m_tx_cpy, CPY_WRITER4_MASK_CTRL);
+			p->m_writers[4].mp_writer_mask_ctrl_addr =
+				nthw_register_get_field(p->m_writers[4].mp_writer_mask_ctrl,
+					CPY_WRITER4_MASK_CTRL_ADR);
+			p->m_writers[4].mp_writer_mask_ctrl_cnt =
+				nthw_register_get_field(p->m_writers[4].mp_writer_mask_ctrl,
+					CPY_WRITER4_MASK_CTRL_CNT);
+			p->m_writers[4].mp_writer_mask_data =
+				nthw_module_get_register(p->m_tx_cpy, CPY_WRITER4_MASK_DATA);
+			p->m_writers[4].mp_writer_mask_data_byte_mask =
+				nthw_register_get_field(p->m_writers[4].mp_writer_mask_data,
+					CPY_WRITER4_MASK_DATA_BYTE_MASK);
+		}
+
+	/* Fallthrough */
+	case 4:
+		p->m_writers[3].mp_writer_ctrl =
+			nthw_module_get_register(p->m_tx_cpy, CPY_WRITER3_CTRL);
+		p->m_writers[3].mp_writer_ctrl_addr =
+			nthw_register_get_field(p->m_writers[3].mp_writer_ctrl,
+				CPY_WRITER3_CTRL_ADR);
+		p->m_writers[3].mp_writer_ctrl_cnt =
+			nthw_register_get_field(p->m_writers[3].mp_writer_ctrl,
+				CPY_WRITER3_CTRL_CNT);
+		p->m_writers[3].mp_writer_data =
+			nthw_module_get_register(p->m_tx_cpy, CPY_WRITER3_DATA);
+		p->m_writers[3].mp_writer_data_reader_select =
+			nthw_register_get_field(p->m_writers[3].mp_writer_data,
+				CPY_WRITER3_DATA_READER_SELECT);
+		p->m_writers[3].mp_writer_data_dyn =
+			nthw_register_get_field(p->m_writers[3].mp_writer_data,
+				CPY_WRITER3_DATA_DYN);
+		p->m_writers[3].mp_writer_data_ofs =
+			nthw_register_get_field(p->m_writers[3].mp_writer_data,
+				CPY_WRITER3_DATA_OFS);
+		p->m_writers[3].mp_writer_data_len =
+			nthw_register_get_field(p->m_writers[3].mp_writer_data,
+				CPY_WRITER3_DATA_LEN);
+
+		if (variant != 0) {
+			p->m_writers[3].mp_writer_data_mask_pointer =
+				nthw_register_get_field(p->m_writers[3].mp_writer_data,
+					CPY_WRITER3_DATA_MASK_POINTER);
+			p->m_writers[3].mp_writer_mask_ctrl =
+				nthw_module_get_register(p->m_tx_cpy, CPY_WRITER3_MASK_CTRL);
+			p->m_writers[3].mp_writer_mask_ctrl_addr =
+				nthw_register_get_field(p->m_writers[3].mp_writer_mask_ctrl,
+					CPY_WRITER3_MASK_CTRL_ADR);
+			p->m_writers[3].mp_writer_mask_ctrl_cnt =
+				nthw_register_get_field(p->m_writers[3].mp_writer_mask_ctrl,
+					CPY_WRITER3_MASK_CTRL_CNT);
+			p->m_writers[3].mp_writer_mask_data =
+				nthw_module_get_register(p->m_tx_cpy, CPY_WRITER3_MASK_DATA);
+			p->m_writers[3].mp_writer_mask_data_byte_mask =
+				nthw_register_get_field(p->m_writers[3].mp_writer_mask_data,
+					CPY_WRITER3_MASK_DATA_BYTE_MASK);
+		}
+
+	/* Fallthrough */
+	case 3:
+		p->m_writers[2].mp_writer_ctrl =
+			nthw_module_get_register(p->m_tx_cpy, CPY_WRITER2_CTRL);
+		p->m_writers[2].mp_writer_ctrl_addr =
+			nthw_register_get_field(p->m_writers[2].mp_writer_ctrl,
+				CPY_WRITER2_CTRL_ADR);
+		p->m_writers[2].mp_writer_ctrl_cnt =
+			nthw_register_get_field(p->m_writers[2].mp_writer_ctrl,
+				CPY_WRITER2_CTRL_CNT);
+		p->m_writers[2].mp_writer_data =
+			nthw_module_get_register(p->m_tx_cpy, CPY_WRITER2_DATA);
+		p->m_writers[2].mp_writer_data_reader_select =
+			nthw_register_get_field(p->m_writers[2].mp_writer_data,
+				CPY_WRITER2_DATA_READER_SELECT);
+		p->m_writers[2].mp_writer_data_dyn =
+			nthw_register_get_field(p->m_writers[2].mp_writer_data,
+				CPY_WRITER2_DATA_DYN);
+		p->m_writers[2].mp_writer_data_ofs =
+			nthw_register_get_field(p->m_writers[2].mp_writer_data,
+				CPY_WRITER2_DATA_OFS);
+		p->m_writers[2].mp_writer_data_len =
+			nthw_register_get_field(p->m_writers[2].mp_writer_data,
+				CPY_WRITER2_DATA_LEN);
+
+		if (variant != 0) {
+			p->m_writers[2].mp_writer_data_mask_pointer =
+				nthw_register_get_field(p->m_writers[2].mp_writer_data,
+					CPY_WRITER2_DATA_MASK_POINTER);
+			p->m_writers[2].mp_writer_mask_ctrl =
+				nthw_module_get_register(p->m_tx_cpy, CPY_WRITER2_MASK_CTRL);
+			p->m_writers[2].mp_writer_mask_ctrl_addr =
+				nthw_register_get_field(p->m_writers[2].mp_writer_mask_ctrl,
+					CPY_WRITER2_MASK_CTRL_ADR);
+			p->m_writers[2].mp_writer_mask_ctrl_cnt =
+				nthw_register_get_field(p->m_writers[2].mp_writer_mask_ctrl,
+					CPY_WRITER2_MASK_CTRL_CNT);
+			p->m_writers[2].mp_writer_mask_data =
+				nthw_module_get_register(p->m_tx_cpy, CPY_WRITER2_MASK_DATA);
+			p->m_writers[2].mp_writer_mask_data_byte_mask =
+				nthw_register_get_field(p->m_writers[2].mp_writer_mask_data,
+					CPY_WRITER2_MASK_DATA_BYTE_MASK);
+		}
+
+	/* Fallthrough */
+	case 2:
+		p->m_writers[1].mp_writer_ctrl =
+			nthw_module_get_register(p->m_tx_cpy, CPY_WRITER1_CTRL);
+		p->m_writers[1].mp_writer_ctrl_addr =
+			nthw_register_get_field(p->m_writers[1].mp_writer_ctrl,
+				CPY_WRITER1_CTRL_ADR);
+		p->m_writers[1].mp_writer_ctrl_cnt =
+			nthw_register_get_field(p->m_writers[1].mp_writer_ctrl,
+				CPY_WRITER1_CTRL_CNT);
+		p->m_writers[1].mp_writer_data =
+			nthw_module_get_register(p->m_tx_cpy, CPY_WRITER1_DATA);
+		p->m_writers[1].mp_writer_data_reader_select =
+			nthw_register_get_field(p->m_writers[1].mp_writer_data,
+				CPY_WRITER1_DATA_READER_SELECT);
+		p->m_writers[1].mp_writer_data_dyn =
+			nthw_register_get_field(p->m_writers[1].mp_writer_data,
+				CPY_WRITER1_DATA_DYN);
+		p->m_writers[1].mp_writer_data_ofs =
+			nthw_register_get_field(p->m_writers[1].mp_writer_data,
+				CPY_WRITER1_DATA_OFS);
+		p->m_writers[1].mp_writer_data_len =
+			nthw_register_get_field(p->m_writers[1].mp_writer_data,
+				CPY_WRITER1_DATA_LEN);
+
+		if (variant != 0) {
+			p->m_writers[1].mp_writer_data_mask_pointer =
+				nthw_register_get_field(p->m_writers[1].mp_writer_data,
+					CPY_WRITER1_DATA_MASK_POINTER);
+			p->m_writers[1].mp_writer_mask_ctrl =
+				nthw_module_get_register(p->m_tx_cpy, CPY_WRITER1_MASK_CTRL);
+			p->m_writers[1].mp_writer_mask_ctrl_addr =
+				nthw_register_get_field(p->m_writers[1].mp_writer_mask_ctrl,
+					CPY_WRITER1_MASK_CTRL_ADR);
+			p->m_writers[1].mp_writer_mask_ctrl_cnt =
+				nthw_register_get_field(p->m_writers[1].mp_writer_mask_ctrl,
+					CPY_WRITER1_MASK_CTRL_CNT);
+			p->m_writers[1].mp_writer_mask_data =
+				nthw_module_get_register(p->m_tx_cpy, CPY_WRITER1_MASK_DATA);
+			p->m_writers[1].mp_writer_mask_data_byte_mask =
+				nthw_register_get_field(p->m_writers[1].mp_writer_mask_data,
+					CPY_WRITER1_MASK_DATA_BYTE_MASK);
+		}
+
+	/* Fallthrough */
+	case 1:
+		p->m_writers[0].mp_writer_ctrl =
+			nthw_module_get_register(p->m_tx_cpy, CPY_WRITER0_CTRL);
+		p->m_writers[0].mp_writer_ctrl_addr =
+			nthw_register_get_field(p->m_writers[0].mp_writer_ctrl,
+				CPY_WRITER0_CTRL_ADR);
+		p->m_writers[0].mp_writer_ctrl_cnt =
+			nthw_register_get_field(p->m_writers[0].mp_writer_ctrl,
+				CPY_WRITER0_CTRL_CNT);
+		p->m_writers[0].mp_writer_data =
+			nthw_module_get_register(p->m_tx_cpy, CPY_WRITER0_DATA);
+		p->m_writers[0].mp_writer_data_reader_select =
+			nthw_register_get_field(p->m_writers[0].mp_writer_data,
+				CPY_WRITER0_DATA_READER_SELECT);
+		p->m_writers[0].mp_writer_data_dyn =
+			nthw_register_get_field(p->m_writers[0].mp_writer_data,
+				CPY_WRITER0_DATA_DYN);
+		p->m_writers[0].mp_writer_data_ofs =
+			nthw_register_get_field(p->m_writers[0].mp_writer_data,
+				CPY_WRITER0_DATA_OFS);
+		p->m_writers[0].mp_writer_data_len =
+			nthw_register_get_field(p->m_writers[0].mp_writer_data,
+				CPY_WRITER0_DATA_LEN);
+
+		if (variant != 0) {
+			p->m_writers[0].mp_writer_data_mask_pointer =
+				nthw_register_get_field(p->m_writers[0].mp_writer_data,
+					CPY_WRITER0_DATA_MASK_POINTER);
+			p->m_writers[0].mp_writer_mask_ctrl =
+				nthw_module_get_register(p->m_tx_cpy, CPY_WRITER0_MASK_CTRL);
+			p->m_writers[0].mp_writer_mask_ctrl_addr =
+				nthw_register_get_field(p->m_writers[0].mp_writer_mask_ctrl,
+					CPY_WRITER0_MASK_CTRL_ADR);
+			p->m_writers[0].mp_writer_mask_ctrl_cnt =
+				nthw_register_get_field(p->m_writers[0].mp_writer_mask_ctrl,
+					CPY_WRITER0_MASK_CTRL_CNT);
+			p->m_writers[0].mp_writer_mask_data =
+				nthw_module_get_register(p->m_tx_cpy, CPY_WRITER0_MASK_DATA);
+			p->m_writers[0].mp_writer_mask_data_byte_mask =
+				nthw_register_get_field(p->m_writers[0].mp_writer_mask_data,
+					CPY_WRITER0_MASK_DATA_BYTE_MASK);
+		}
+
+		break;
+
+	case 0:
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h
new file mode 100644
index 0000000000..801b47b0bb
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h
@@ -0,0 +1,49 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_TX_CPY_H__
+#define __FLOW_NTHW_TX_CPY_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct tx_cpy_writers_s {
+	nthw_register_t *mp_writer_ctrl;
+	nthw_field_t *mp_writer_ctrl_addr;
+	nthw_field_t *mp_writer_ctrl_cnt;
+
+	nthw_register_t *mp_writer_data;
+	nthw_field_t *mp_writer_data_reader_select;
+	nthw_field_t *mp_writer_data_dyn;
+	nthw_field_t *mp_writer_data_ofs;
+	nthw_field_t *mp_writer_data_len;
+	nthw_field_t *mp_writer_data_mask_pointer;
+
+	nthw_register_t *mp_writer_mask_ctrl;
+	nthw_field_t *mp_writer_mask_ctrl_addr;
+	nthw_field_t *mp_writer_mask_ctrl_cnt;
+
+	nthw_register_t *mp_writer_mask_data;
+	nthw_field_t *mp_writer_mask_data_byte_mask;
+};
+
+struct tx_cpy_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_tx_cpy;
+
+	unsigned int m_writers_cnt;
+	struct tx_cpy_writers_s *m_writers;
+};
+
+struct tx_cpy_nthw *tx_cpy_nthw_new(void);
+void tx_cpy_nthw_delete(struct tx_cpy_nthw *p);
+int tx_cpy_nthw_init(struct tx_cpy_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int tx_cpy_nthw_setup(struct tx_cpy_nthw *p, int n_idx, int n_idx_cnt);
+
+#endif	/* __FLOW_NTHW_TX_CPY_H__ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index f1d055a36e..d93d9d3816 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -37,6 +37,7 @@
 #define MOD_RST9563 (0x385d6d1dUL)
 #define MOD_SDC (0xd2369530UL)
 #define MOD_SLC_LR (0x969fc50bUL)
+#define MOD_TX_CPY (0x60acf217UL)
 #define MOD_IDX_COUNT (14)
 
 /* aliases - only aliases go below this point */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index c39901ce39..d58d10c438 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -14,6 +14,7 @@
 #define _NTHW_FPGA_REG_DEFS_
 
 #include "nthw_fpga_reg_defs_cat.h"
+#include "nthw_fpga_reg_defs_cpy.h"
 #include "nthw_fpga_reg_defs_flm.h"
 #include "nthw_fpga_reg_defs_gfg.h"
 #include "nthw_fpga_reg_defs_gmf.h"
@@ -37,6 +38,7 @@
 #include "nthw_fpga_reg_defs_sdc.h"
 #include "nthw_fpga_reg_defs_slc.h"
 #include "nthw_fpga_reg_defs_slc_lr.h"
+#include "nthw_fpga_reg_defs_tx_cpy.h"
 
 /* aliases */
 
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_cpy.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_cpy.h
new file mode 100644
index 0000000000..55fd5704b9
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_cpy.h
@@ -0,0 +1,113 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_cpy.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_CPY_
+#define _NTHW_FPGA_REG_DEFS_CPY_
+
+/* CPY */
+#define NTHW_MOD_CPY (0x1ddc186fUL)
+#define CPY_PACKET_READER0_CTRL (0x59359b7UL)
+#define CPY_PACKET_READER0_CTRL_ADR (0xc84f1475UL)
+#define CPY_PACKET_READER0_CTRL_CNT (0xd8478da4UL)
+#define CPY_PACKET_READER0_DATA (0xaa42dbaeUL)
+#define CPY_PACKET_READER0_DATA_DYN (0x34037b11UL)
+#define CPY_PACKET_READER0_DATA_OFS (0x960af6b7UL)
+#define CPY_WRITER0_CTRL (0xe9b3268eUL)
+#define CPY_WRITER0_CTRL_ADR (0x26f906c2UL)
+#define CPY_WRITER0_CTRL_CNT (0x36f19f13UL)
+#define CPY_WRITER0_DATA (0x4662a497UL)
+#define CPY_WRITER0_DATA_DYN (0xdab569a6UL)
+#define CPY_WRITER0_DATA_LEN (0x32d16543UL)
+#define CPY_WRITER0_DATA_MASK_POINTER (0x64db2b2dUL)
+#define CPY_WRITER0_DATA_OFS (0x78bce400UL)
+#define CPY_WRITER0_DATA_READER_SELECT (0x63a38cf9UL)
+#define CPY_WRITER0_MASK_CTRL (0xed52c5f9UL)
+#define CPY_WRITER0_MASK_CTRL_ADR (0x3bbdf6aaUL)
+#define CPY_WRITER0_MASK_CTRL_CNT (0x2bb56f7bUL)
+#define CPY_WRITER0_MASK_DATA (0x428347e0UL)
+#define CPY_WRITER0_MASK_DATA_BYTE_MASK (0xd1d0e256UL)
+#define CPY_WRITER1_CTRL (0x22eff52bUL)
+#define CPY_WRITER1_CTRL_ADR (0xc93b6dfcUL)
+#define CPY_WRITER1_CTRL_CNT (0xd933f42dUL)
+#define CPY_WRITER1_DATA (0x8d3e7732UL)
+#define CPY_WRITER1_DATA_DYN (0x35770298UL)
+#define CPY_WRITER1_DATA_LEN (0xdd130e7dUL)
+#define CPY_WRITER1_DATA_MASK_POINTER (0xb339ab75UL)
+#define CPY_WRITER1_DATA_OFS (0x977e8f3eUL)
+#define CPY_WRITER1_DATA_READER_SELECT (0x6c4b7bfUL)
+#define CPY_WRITER1_MASK_CTRL (0x2cdc1a39UL)
+#define CPY_WRITER1_MASK_CTRL_ADR (0x82462d42UL)
+#define CPY_WRITER1_MASK_CTRL_CNT (0x924eb493UL)
+#define CPY_WRITER1_MASK_DATA (0x830d9820UL)
+#define CPY_WRITER1_MASK_DATA_BYTE_MASK (0x4e0a61c8UL)
+#define CPY_WRITER2_CTRL (0xa47b8785UL)
+#define CPY_WRITER2_CTRL_ADR (0x220cd6ffUL)
+#define CPY_WRITER2_CTRL_CNT (0x32044f2eUL)
+#define CPY_WRITER2_DATA (0xbaa059cUL)
+#define CPY_WRITER2_DATA_DYN (0xde40b99bUL)
+#define CPY_WRITER2_DATA_LEN (0x3624b57eUL)
+#define CPY_WRITER2_DATA_MASK_POINTER (0x106f2ddcUL)
+#define CPY_WRITER2_DATA_OFS (0x7c49343dUL)
+#define CPY_WRITER2_DATA_READER_SELECT (0xa96dfa75UL)
+#define CPY_WRITER2_MASK_CTRL (0xb53e7c38UL)
+#define CPY_WRITER2_MASK_CTRL_ADR (0x933b473bUL)
+#define CPY_WRITER2_MASK_CTRL_CNT (0x8333deeaUL)
+#define CPY_WRITER2_MASK_DATA (0x1aeffe21UL)
+#define CPY_WRITER2_MASK_DATA_BYTE_MASK (0x3514e32bUL)
+#define CPY_WRITER3_CTRL (0x6f275420UL)
+#define CPY_WRITER3_CTRL_ADR (0xcdcebdc1UL)
+#define CPY_WRITER3_CTRL_CNT (0xddc62410UL)
+#define CPY_WRITER3_DATA (0xc0f6d639UL)
+#define CPY_WRITER3_DATA_DYN (0x3182d2a5UL)
+#define CPY_WRITER3_DATA_LEN (0xd9e6de40UL)
+#define CPY_WRITER3_DATA_MASK_POINTER (0xc78dad84UL)
+#define CPY_WRITER3_DATA_OFS (0x938b5f03UL)
+#define CPY_WRITER3_DATA_READER_SELECT (0xcc0ac133UL)
+#define CPY_WRITER3_MASK_CTRL (0x74b0a3f8UL)
+#define CPY_WRITER3_MASK_CTRL_ADR (0x2ac09cd3UL)
+#define CPY_WRITER3_MASK_CTRL_CNT (0x3ac80502UL)
+#define CPY_WRITER3_MASK_DATA (0xdb6121e1UL)
+#define CPY_WRITER3_MASK_DATA_BYTE_MASK (0xaace60b5UL)
+#define CPY_WRITER4_CTRL (0x72226498UL)
+#define CPY_WRITER4_CTRL_ADR (0x2f12a6b8UL)
+#define CPY_WRITER4_CTRL_CNT (0x3f1a3f69UL)
+#define CPY_WRITER4_DATA (0xddf3e681UL)
+#define CPY_WRITER4_DATA_DYN (0xd35ec9dcUL)
+#define CPY_WRITER4_DATA_LEN (0x3b3ac539UL)
+#define CPY_WRITER4_DATA_MASK_POINTER (0x8db326cfUL)
+#define CPY_WRITER4_DATA_OFS (0x7157447aUL)
+#define CPY_WRITER4_DATA_READER_SELECT (0x2d4e67a0UL)
+#define CPY_WRITER4_MASK_CTRL (0x5d8bb67bUL)
+#define CPY_WRITER4_MASK_CTRL_ADR (0xb1c193c9UL)
+#define CPY_WRITER4_MASK_CTRL_CNT (0xa1c90a18UL)
+#define CPY_WRITER4_MASK_DATA (0xf25a3462UL)
+#define CPY_WRITER4_MASK_DATA_BYTE_MASK (0xc329e6edUL)
+#define CPY_WRITER5_CTRL (0xb97eb73dUL)
+#define CPY_WRITER5_CTRL_ADR (0xc0d0cd86UL)
+#define CPY_WRITER5_CTRL_CNT (0xd0d85457UL)
+#define CPY_WRITER5_DATA (0x16af3524UL)
+#define CPY_WRITER5_DATA_DYN (0x3c9ca2e2UL)
+#define CPY_WRITER5_DATA_LEN (0xd4f8ae07UL)
+#define CPY_WRITER5_DATA_MASK_POINTER (0x5a51a697UL)
+#define CPY_WRITER5_DATA_OFS (0x9e952f44UL)
+#define CPY_WRITER5_DATA_READER_SELECT (0x48295ce6UL)
+#define CPY_WRITER5_MASK_CTRL (0x9c0569bbUL)
+#define CPY_WRITER5_MASK_CTRL_ADR (0x83a4821UL)
+#define CPY_WRITER5_MASK_CTRL_CNT (0x1832d1f0UL)
+#define CPY_WRITER5_MASK_DATA (0x33d4eba2UL)
+#define CPY_WRITER5_MASK_DATA_BYTE_MASK (0x5cf36573UL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_CPY_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_cpy.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_cpy.h
new file mode 100644
index 0000000000..1fb71bf483
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_cpy.h
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_tx_cpy.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_TX_CPY_
+#define _NTHW_FPGA_REG_DEFS_TX_CPY_
+
+/* TX_CPY */
+#define NTHW_MOD_TX_CPY (0x60acf217UL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_TX_CPY_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 17/31] net/ntnic: add checksum update (CSU) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (21 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 16/31] net/ntnic: add copier (Tx CPY) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 18/31] net/ntnic: add insert (Tx INS) " Serhii Iliushyk
                   ` (28 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Checksum Update module updates the checksums of packets
that has been modified in any way.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/meson.build                 |  1 +
 .../nthw/flow_api/flow_backend/flow_backend.c | 13 ++++
 .../ntnic/nthw/flow_filter/flow_nthw_csu.c    | 62 +++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_csu.h    | 35 +++++++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |  1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |  1 +
 .../nthw/supported/nthw_fpga_reg_defs_csu.h   | 31 ++++++++++
 7 files changed, 144 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_csu.h

diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 3c00203e34..cc5e6fe100 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -47,6 +47,7 @@ sources = files(
         'nthw/flow_api/flow_backend/flow_backend.c',
         'nthw/flow_api/flow_filter.c',
         'nthw/flow_filter/flow_nthw_cat.c',
+        'nthw/flow_filter/flow_nthw_csu.c',
         'nthw/flow_filter/flow_nthw_flm.c',
         'nthw/flow_filter/flow_nthw_hfu.c',
         'nthw/flow_filter/flow_nthw_hsh.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index af1e8ce3a4..c12a3204bc 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -8,6 +8,7 @@
 #include "flow_nthw_info.h"
 #include "flow_nthw_ifr.h"
 #include "flow_nthw_cat.h"
+#include "flow_nthw_csu.h"
 #include "flow_nthw_km.h"
 #include "flow_nthw_flm.h"
 #include "flow_nthw_hfu.h"
@@ -42,6 +43,7 @@ static struct backend_dev_s {
 	struct hfu_nthw *p_hfu_nthw;    /* TPE module */
 	struct rpp_lr_nthw *p_rpp_lr_nthw;      /* TPE module */
 	struct tx_cpy_nthw *p_tx_cpy_nthw;      /* TPE module */
+	struct csu_nthw *p_csu_nthw;    /* TPE module */
 	struct ifr_nthw *p_ifr_nthw;    /* TPE module */
 } be_devs[MAX_PHYS_ADAPTERS];
 
@@ -1819,6 +1821,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_tx_cpy_nthw = NULL;
 	}
 
+	/* Init nthw CSU */
+	if (csu_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct csu_nthw *ptr = csu_nthw_new();
+		csu_nthw_init(ptr, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_csu_nthw = ptr;
+
+	} else {
+		be_devs[physical_adapter_no].p_csu_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -1836,6 +1848,7 @@ static void bin_flow_backend_done(void *dev)
 	qsl_nthw_delete(be_dev->p_qsl_nthw);
 	slc_lr_nthw_delete(be_dev->p_slc_lr_nthw);
 	pdb_nthw_delete(be_dev->p_pdb_nthw);
+	csu_nthw_delete(be_dev->p_csu_nthw);
 	hfu_nthw_delete(be_dev->p_hfu_nthw);
 	rpp_lr_nthw_delete(be_dev->p_rpp_lr_nthw);
 	tx_cpy_nthw_delete(be_dev->p_tx_cpy_nthw);
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.c
new file mode 100644
index 0000000000..21efc62eda
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.c
@@ -0,0 +1,62 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_csu.h"
+
+struct csu_nthw *csu_nthw_new(void)
+{
+	struct csu_nthw *p = malloc(sizeof(struct csu_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void csu_nthw_delete(struct csu_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int csu_nthw_init(struct csu_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_CSU, n_instance);
+
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: Csu %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_csu = p_mod;
+
+	p->mp_rcp_ctrl = nthw_module_get_register(p->m_csu, CSU_RCP_CTRL);
+	p->mp_rcp_ctrl_adr = nthw_register_get_field(p->mp_rcp_ctrl, CSU_RCP_CTRL_ADR);
+	p->mp_rcp_ctrl_cnt = nthw_register_get_field(p->mp_rcp_ctrl, CSU_RCP_CTRL_CNT);
+	p->mp_rcp_data = nthw_module_get_register(p->m_csu, CSU_RCP_DATA);
+	p->mp_rcp_data_ol3_cmd = nthw_register_get_field(p->mp_rcp_data, CSU_RCP_DATA_OL3_CMD);
+	p->mp_rcp_data_ol4_cmd = nthw_register_get_field(p->mp_rcp_data, CSU_RCP_DATA_OL4_CMD);
+	p->mp_rcp_data_il3_cmd = nthw_register_get_field(p->mp_rcp_data, CSU_RCP_DATA_IL3_CMD);
+	p->mp_rcp_data_il4_cmd = nthw_register_get_field(p->mp_rcp_data, CSU_RCP_DATA_IL4_CMD);
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.h
new file mode 100644
index 0000000000..e5986a1a9b
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.h
@@ -0,0 +1,35 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _FLOW_NTHW_CSU_H_
+#define _FLOW_NTHW_CSU_H_
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct csu_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_csu;
+
+	nthw_register_t *mp_rcp_ctrl;
+	nthw_field_t *mp_rcp_ctrl_adr;
+	nthw_field_t *mp_rcp_ctrl_cnt;
+	nthw_register_t *mp_rcp_data;
+	nthw_field_t *mp_rcp_data_ol3_cmd;
+	nthw_field_t *mp_rcp_data_ol4_cmd;
+	nthw_field_t *mp_rcp_data_il3_cmd;
+	nthw_field_t *mp_rcp_data_il4_cmd;
+};
+
+struct csu_nthw *csu_nthw_new(void);
+void csu_nthw_delete(struct csu_nthw *p);
+int csu_nthw_init(struct csu_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int csu_nthw_setup(struct csu_nthw *p, int n_idx, int n_idx_cnt);
+
+#endif	/* _FLOW_NTHW_CSU_H_ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index d93d9d3816..14e031dc69 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -15,6 +15,7 @@
 
 #define MOD_UNKNOWN (0L)/* Unknown/uninitialized - keep this as the first element */
 #define MOD_CAT (0x30b447c2UL)
+#define MOD_CSU (0x3f470787UL)
 #define MOD_FLM (0xe7ba53a4UL)
 #define MOD_GFG (0xfc423807UL)
 #define MOD_GMF (0x68b1d15aUL)
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index d58d10c438..6eebab65a2 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -15,6 +15,7 @@
 
 #include "nthw_fpga_reg_defs_cat.h"
 #include "nthw_fpga_reg_defs_cpy.h"
+#include "nthw_fpga_reg_defs_csu.h"
 #include "nthw_fpga_reg_defs_flm.h"
 #include "nthw_fpga_reg_defs_gfg.h"
 #include "nthw_fpga_reg_defs_gmf.h"
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_csu.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_csu.h
new file mode 100644
index 0000000000..a67f1c392e
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_csu.h
@@ -0,0 +1,31 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_csu.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_CSU_
+#define _NTHW_FPGA_REG_DEFS_CSU_
+
+/* CSU */
+#define NTHW_MOD_CSU (0x3f470787UL)
+#define CSU_RCP_CTRL (0x11955fefUL)
+#define CSU_RCP_CTRL_ADR (0x8efb3c71UL)
+#define CSU_RCP_CTRL_CNT (0x9ef3a5a0UL)
+#define CSU_RCP_DATA (0xbe44ddf6UL)
+#define CSU_RCP_DATA_IL3_CMD (0xdbac8e0dUL)
+#define CSU_RCP_DATA_IL4_CMD (0x698c521dUL)
+#define CSU_RCP_DATA_OL3_CMD (0xb87cbb37UL)
+#define CSU_RCP_DATA_OL4_CMD (0xa5c6727UL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_CSU_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 18/31] net/ntnic: add insert (Tx INS) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (22 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 17/31] net/ntnic: add checksum update (CSU) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 19/31] net/ntnic: add replacer (Tx RPL) " Serhii Iliushyk
                   ` (27 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

he TX Inserter module injects zeros into an offset of a packet,
effectively expanding the packet.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/meson.build                 |  1 +
 .../nthw/flow_api/flow_backend/flow_backend.c | 13 ++++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_ins.c | 62 +++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_ins.h | 35 +++++++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |  1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |  2 +
 .../nthw/supported/nthw_fpga_reg_defs_ins.h   | 30 +++++++++
 .../supported/nthw_fpga_reg_defs_tx_ins.h     | 23 +++++++
 8 files changed, 167 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_ins.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_ins.h

diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index cc5e6fe100..7e0900f0eb 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -59,6 +59,7 @@ sources = files(
         'nthw/flow_filter/flow_nthw_rpp_lr.c',
         'nthw/flow_filter/flow_nthw_slc_lr.c',
         'nthw/flow_filter/flow_nthw_tx_cpy.c',
+        'nthw/flow_filter/flow_nthw_tx_ins.c',
         'nthw/model/nthw_fpga_model.c',
         'nthw/nthw_platform.c',
         'nthw/nthw_rac.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index c12a3204bc..1b4c6d6b4d 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -18,6 +18,7 @@
 #include "flow_nthw_pdb.h"
 #include "flow_nthw_rpp_lr.h"
 #include "flow_nthw_tx_cpy.h"
+#include "flow_nthw_tx_ins.h"
 #include "ntnic_mod_reg.h"
 #include "nthw_fpga_model.h"
 #include "hw_mod_backend.h"
@@ -43,6 +44,7 @@ static struct backend_dev_s {
 	struct hfu_nthw *p_hfu_nthw;    /* TPE module */
 	struct rpp_lr_nthw *p_rpp_lr_nthw;      /* TPE module */
 	struct tx_cpy_nthw *p_tx_cpy_nthw;      /* TPE module */
+	struct tx_ins_nthw *p_tx_ins_nthw;      /* TPE module */
 	struct csu_nthw *p_csu_nthw;    /* TPE module */
 	struct ifr_nthw *p_ifr_nthw;    /* TPE module */
 } be_devs[MAX_PHYS_ADAPTERS];
@@ -1831,6 +1833,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_csu_nthw = NULL;
 	}
 
+	/* Init nthw TX_INS */
+	if (tx_ins_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct tx_ins_nthw *ptr = tx_ins_nthw_new();
+		tx_ins_nthw_init(ptr, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_tx_ins_nthw = ptr;
+
+	} else {
+		be_devs[physical_adapter_no].p_tx_ins_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -1852,6 +1864,7 @@ static void bin_flow_backend_done(void *dev)
 	hfu_nthw_delete(be_dev->p_hfu_nthw);
 	rpp_lr_nthw_delete(be_dev->p_rpp_lr_nthw);
 	tx_cpy_nthw_delete(be_dev->p_tx_cpy_nthw);
+	tx_ins_nthw_delete(be_dev->p_tx_ins_nthw);
 }
 
 static const struct flow_backend_ops ops = {
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.c
new file mode 100644
index 0000000000..5d9867981e
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.c
@@ -0,0 +1,62 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_tx_ins.h"
+
+struct tx_ins_nthw *tx_ins_nthw_new(void)
+{
+	struct tx_ins_nthw *p = malloc(sizeof(struct tx_ins_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void tx_ins_nthw_delete(struct tx_ins_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int tx_ins_nthw_init(struct tx_ins_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_TX_INS, n_instance);
+
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: TxIns %d: no such instance\n", p_adapter_id_str,
+			n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_tx_ins = nthw_fpga_query_module(p_fpga, MOD_TX_INS, n_instance);
+
+	p->mp_rcp_ctrl = nthw_module_get_register(p->m_tx_ins, INS_RCP_CTRL);
+	p->mp_rcp_addr = nthw_register_get_field(p->mp_rcp_ctrl, INS_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = nthw_register_get_field(p->mp_rcp_ctrl, INS_RCP_CTRL_CNT);
+	p->mp_rcp_data = nthw_module_get_register(p->m_tx_ins, INS_RCP_DATA);
+	p->mp_rcp_data_dyn = nthw_register_get_field(p->mp_rcp_data, INS_RCP_DATA_DYN);
+	p->mp_rcp_data_ofs = nthw_register_get_field(p->mp_rcp_data, INS_RCP_DATA_OFS);
+	p->mp_rcp_data_len = nthw_register_get_field(p->mp_rcp_data, INS_RCP_DATA_LEN);
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.h
new file mode 100644
index 0000000000..4e7c4133da
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.h
@@ -0,0 +1,35 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_TX_INS_H__
+#define __FLOW_NTHW_TX_INS_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct tx_ins_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_tx_ins;
+
+	nthw_register_t *mp_rcp_ctrl;
+	nthw_field_t *mp_rcp_addr;
+	nthw_field_t *mp_rcp_cnt;
+
+	nthw_register_t *mp_rcp_data;
+	nthw_field_t *mp_rcp_data_dyn;
+	nthw_field_t *mp_rcp_data_ofs;
+	nthw_field_t *mp_rcp_data_len;
+};
+
+struct tx_ins_nthw *tx_ins_nthw_new(void);
+void tx_ins_nthw_delete(struct tx_ins_nthw *p);
+int tx_ins_nthw_init(struct tx_ins_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int tx_ins_nthw_setup(struct tx_ins_nthw *p, int n_idx, int n_idx_cnt);
+
+#endif	/* __FLOW_NTHW_TX_INS_H__ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index 14e031dc69..0d5385a313 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -39,6 +39,7 @@
 #define MOD_SDC (0xd2369530UL)
 #define MOD_SLC_LR (0x969fc50bUL)
 #define MOD_TX_CPY (0x60acf217UL)
+#define MOD_TX_INS (0x59afa100UL)
 #define MOD_IDX_COUNT (14)
 
 /* aliases - only aliases go below this point */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index 6eebab65a2..605196e30e 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -26,6 +26,7 @@
 #include "nthw_fpga_reg_defs_i2cm.h"
 #include "nthw_fpga_reg_defs_ifr.h"
 #include "nthw_fpga_reg_defs_iic.h"
+#include "nthw_fpga_reg_defs_ins.h"
 #include "nthw_fpga_reg_defs_km.h"
 #include "nthw_fpga_reg_defs_mac_pcs.h"
 #include "nthw_fpga_reg_defs_pcie3.h"
@@ -40,6 +41,7 @@
 #include "nthw_fpga_reg_defs_slc.h"
 #include "nthw_fpga_reg_defs_slc_lr.h"
 #include "nthw_fpga_reg_defs_tx_cpy.h"
+#include "nthw_fpga_reg_defs_tx_ins.h"
 
 /* aliases */
 
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_ins.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_ins.h
new file mode 100644
index 0000000000..8aaef2a8f6
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_ins.h
@@ -0,0 +1,30 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_ins.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_INS_
+#define _NTHW_FPGA_REG_DEFS_INS_
+
+/* INS */
+#define NTHW_MOD_INS (0x24df4b78UL)
+#define INS_RCP_CTRL (0x93de4e05UL)
+#define INS_RCP_CTRL_ADR (0x3ae620a8UL)
+#define INS_RCP_CTRL_CNT (0x2aeeb979UL)
+#define INS_RCP_DATA (0x3c0fcc1cUL)
+#define INS_RCP_DATA_DYN (0xc6aa4fccUL)
+#define INS_RCP_DATA_LEN (0x2ece4329UL)
+#define INS_RCP_DATA_OFS (0x64a3c26aUL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_INS_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_ins.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_ins.h
new file mode 100644
index 0000000000..26635bd0a2
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_ins.h
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_tx_ins.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_TX_INS_
+#define _NTHW_FPGA_REG_DEFS_TX_INS_
+
+/* TX_INS */
+#define NTHW_MOD_TX_INS (0x59afa100UL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_TX_INS_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 19/31] net/ntnic: add replacer (Tx RPL) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (23 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 18/31] net/ntnic: add insert (Tx INS) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 20/31] net/ntnic: add Tx Packet Editor (TPE) " Serhii Iliushyk
                   ` (26 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The TX Replacer module can replace a range of bytes in a packet.
The replacing data is stored in a table in the module
and will often contain tunnel data.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/meson.build                 |  1 +
 .../nthw/flow_api/flow_backend/flow_backend.c | 13 ++++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c | 78 +++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h | 52 +++++++++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |  1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |  2 +
 .../nthw/supported/nthw_fpga_reg_defs_rpl.h   | 43 ++++++++++
 .../supported/nthw_fpga_reg_defs_tx_rpl.h     | 23 ++++++
 8 files changed, 213 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rpl.h
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_rpl.h

diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 7e0900f0eb..e236b82b36 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -60,6 +60,7 @@ sources = files(
         'nthw/flow_filter/flow_nthw_slc_lr.c',
         'nthw/flow_filter/flow_nthw_tx_cpy.c',
         'nthw/flow_filter/flow_nthw_tx_ins.c',
+        'nthw/flow_filter/flow_nthw_tx_rpl.c',
         'nthw/model/nthw_fpga_model.c',
         'nthw/nthw_platform.c',
         'nthw/nthw_rac.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index 1b4c6d6b4d..f093bfb8bb 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -19,6 +19,7 @@
 #include "flow_nthw_rpp_lr.h"
 #include "flow_nthw_tx_cpy.h"
 #include "flow_nthw_tx_ins.h"
+#include "flow_nthw_tx_rpl.h"
 #include "ntnic_mod_reg.h"
 #include "nthw_fpga_model.h"
 #include "hw_mod_backend.h"
@@ -45,6 +46,7 @@ static struct backend_dev_s {
 	struct rpp_lr_nthw *p_rpp_lr_nthw;      /* TPE module */
 	struct tx_cpy_nthw *p_tx_cpy_nthw;      /* TPE module */
 	struct tx_ins_nthw *p_tx_ins_nthw;      /* TPE module */
+	struct tx_rpl_nthw *p_tx_rpl_nthw;      /* TPE module */
 	struct csu_nthw *p_csu_nthw;    /* TPE module */
 	struct ifr_nthw *p_ifr_nthw;    /* TPE module */
 } be_devs[MAX_PHYS_ADAPTERS];
@@ -1843,6 +1845,16 @@ const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, vo
 		be_devs[physical_adapter_no].p_tx_ins_nthw = NULL;
 	}
 
+	/* Init nthw TX_RPL */
+	if (tx_rpl_nthw_init(NULL, p_fpga, physical_adapter_no) == 0) {
+		struct tx_rpl_nthw *ptr = tx_rpl_nthw_new();
+		tx_rpl_nthw_init(ptr, p_fpga, physical_adapter_no);
+		be_devs[physical_adapter_no].p_tx_rpl_nthw = ptr;
+
+	} else {
+		be_devs[physical_adapter_no].p_tx_rpl_nthw = NULL;
+	}
+
 	be_devs[physical_adapter_no].adapter_no = physical_adapter_no;
 	*dev = (void *)&be_devs[physical_adapter_no];
 
@@ -1865,6 +1877,7 @@ static void bin_flow_backend_done(void *dev)
 	rpp_lr_nthw_delete(be_dev->p_rpp_lr_nthw);
 	tx_cpy_nthw_delete(be_dev->p_tx_cpy_nthw);
 	tx_ins_nthw_delete(be_dev->p_tx_ins_nthw);
+	tx_rpl_nthw_delete(be_dev->p_tx_rpl_nthw);
 }
 
 static const struct flow_backend_ops ops = {
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c
new file mode 100644
index 0000000000..65fc1a9c5e
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c
@@ -0,0 +1,78 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_tx_rpl.h"
+
+struct tx_rpl_nthw *tx_rpl_nthw_new(void)
+{
+	struct tx_rpl_nthw *p = malloc(sizeof(struct tx_rpl_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void tx_rpl_nthw_delete(struct tx_rpl_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int tx_rpl_nthw_init(struct tx_rpl_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_TX_RPL, n_instance);
+
+	assert(n_instance >= 0 && n_instance < 256);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: TxRpl %d: no such instance\n", p_adapter_id_str,
+			n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->m_physical_adapter_no = (uint8_t)n_instance;
+	p->m_tx_rpl = nthw_fpga_query_module(p_fpga, MOD_TX_RPL, n_instance);
+
+	p->mp_rcp_ctrl = nthw_module_get_register(p->m_tx_rpl, RPL_RCP_CTRL);
+	p->mp_rcp_ctrl_addr = nthw_register_get_field(p->mp_rcp_ctrl, RPL_RCP_CTRL_ADR);
+	p->mp_rcp_ctrl_cnt = nthw_register_get_field(p->mp_rcp_ctrl, RPL_RCP_CTRL_CNT);
+	p->mp_rcp_data = nthw_module_get_register(p->m_tx_rpl, RPL_RCP_DATA);
+	p->mp_rcp_data_dyn = nthw_register_get_field(p->mp_rcp_data, RPL_RCP_DATA_DYN);
+	p->mp_rcp_data_ofs = nthw_register_get_field(p->mp_rcp_data, RPL_RCP_DATA_OFS);
+	p->mp_rcp_data_len = nthw_register_get_field(p->mp_rcp_data, RPL_RCP_DATA_LEN);
+	p->mp_rcp_data_rpl_ptr = nthw_register_get_field(p->mp_rcp_data, RPL_RCP_DATA_RPL_PTR);
+	p->mp_rcp_data_ext_prio = nthw_register_get_field(p->mp_rcp_data, RPL_RCP_DATA_EXT_PRIO);
+	p->mp_rcp_data_eth_type_wr =
+		nthw_register_query_field(p->mp_rcp_data, RPL_RCP_DATA_ETH_TYPE_WR);
+
+	p->mp_ext_ctrl = nthw_module_get_register(p->m_tx_rpl, RPL_EXT_CTRL);
+	p->mp_ext_ctrl_addr = nthw_register_get_field(p->mp_ext_ctrl, RPL_EXT_CTRL_ADR);
+	p->mp_ext_ctrl_cnt = nthw_register_get_field(p->mp_ext_ctrl, RPL_EXT_CTRL_CNT);
+	p->mp_ext_data = nthw_module_get_register(p->m_tx_rpl, RPL_EXT_DATA);
+	p->mp_ext_data_rpl_ptr = nthw_register_get_field(p->mp_ext_data, RPL_EXT_DATA_RPL_PTR);
+
+	p->mp_rpl_ctrl = nthw_module_get_register(p->m_tx_rpl, RPL_RPL_CTRL);
+	p->mp_rpl_ctrl_addr = nthw_register_get_field(p->mp_rpl_ctrl, RPL_RPL_CTRL_ADR);
+	p->mp_rpl_ctrl_cnt = nthw_register_get_field(p->mp_rpl_ctrl, RPL_RPL_CTRL_CNT);
+	p->mp_rpl_data = nthw_module_get_register(p->m_tx_rpl, RPL_RPL_DATA);
+	p->mp_rpl_data_value = nthw_register_get_field(p->mp_rpl_data, RPL_RPL_DATA_VALUE);
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h
new file mode 100644
index 0000000000..7425021692
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h
@@ -0,0 +1,52 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_TX_RPL_H__
+#define __FLOW_NTHW_TX_RPL_H__
+
+#include <stdint.h>
+
+#include "nthw_fpga_model.h"
+
+struct tx_rpl_nthw {
+	uint8_t m_physical_adapter_no;
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_tx_rpl;
+
+	nthw_register_t *mp_rcp_ctrl;
+	nthw_field_t *mp_rcp_ctrl_addr;
+	nthw_field_t *mp_rcp_ctrl_cnt;
+
+	nthw_register_t *mp_rcp_data;
+	nthw_field_t *mp_rcp_data_dyn;
+	nthw_field_t *mp_rcp_data_ofs;
+	nthw_field_t *mp_rcp_data_len;
+	nthw_field_t *mp_rcp_data_rpl_ptr;
+	nthw_field_t *mp_rcp_data_ext_prio;
+	nthw_field_t *mp_rcp_data_eth_type_wr;
+
+	nthw_register_t *mp_ext_ctrl;
+	nthw_field_t *mp_ext_ctrl_addr;
+	nthw_field_t *mp_ext_ctrl_cnt;
+
+	nthw_register_t *mp_ext_data;
+	nthw_field_t *mp_ext_data_rpl_ptr;
+
+	nthw_register_t *mp_rpl_ctrl;
+	nthw_field_t *mp_rpl_ctrl_addr;
+	nthw_field_t *mp_rpl_ctrl_cnt;
+
+	nthw_register_t *mp_rpl_data;
+	nthw_field_t *mp_rpl_data_value;
+};
+
+struct tx_rpl_nthw *tx_rpl_nthw_new(void);
+void tx_rpl_nthw_delete(struct tx_rpl_nthw *p);
+int tx_rpl_nthw_init(struct tx_rpl_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int tx_rpl_nthw_setup(struct tx_rpl_nthw *p, int n_idx, int n_idx_cnt);
+
+#endif	/* __FLOW_NTHW_TX_RPL_H__ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index 0d5385a313..51b2d99c01 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -40,6 +40,7 @@
 #define MOD_SLC_LR (0x969fc50bUL)
 #define MOD_TX_CPY (0x60acf217UL)
 #define MOD_TX_INS (0x59afa100UL)
+#define MOD_TX_RPL (0x1095dfbbUL)
 #define MOD_IDX_COUNT (14)
 
 /* aliases - only aliases go below this point */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index 605196e30e..8fa41eb7ea 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -35,6 +35,7 @@
 #include "nthw_fpga_reg_defs_pdb.h"
 #include "nthw_fpga_reg_defs_qsl.h"
 #include "nthw_fpga_reg_defs_rac.h"
+#include "nthw_fpga_reg_defs_rpl.h"
 #include "nthw_fpga_reg_defs_rpp_lr.h"
 #include "nthw_fpga_reg_defs_rst9563.h"
 #include "nthw_fpga_reg_defs_sdc.h"
@@ -42,6 +43,7 @@
 #include "nthw_fpga_reg_defs_slc_lr.h"
 #include "nthw_fpga_reg_defs_tx_cpy.h"
 #include "nthw_fpga_reg_defs_tx_ins.h"
+#include "nthw_fpga_reg_defs_tx_rpl.h"
 
 /* aliases */
 
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rpl.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rpl.h
new file mode 100644
index 0000000000..a163ffc45e
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rpl.h
@@ -0,0 +1,43 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_rpl.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_RPL_
+#define _NTHW_FPGA_REG_DEFS_RPL_
+
+/* RPL */
+#define NTHW_MOD_RPL (0x6de535c3UL)
+#define RPL_EXT_CTRL (0x4c47804fUL)
+#define RPL_EXT_CTRL_ADR (0xe391ddadUL)
+#define RPL_EXT_CTRL_CNT (0xf399447cUL)
+#define RPL_EXT_DATA (0xe3960256UL)
+#define RPL_EXT_DATA_RPL_PTR (0xa8e4d0d9UL)
+#define RPL_RCP_CTRL (0xc471325fUL)
+#define RPL_RCP_CTRL_ADR (0x1f2d3a2bUL)
+#define RPL_RCP_CTRL_CNT (0xf25a3faUL)
+#define RPL_RCP_DATA (0x6ba0b046UL)
+#define RPL_RCP_DATA_DYN (0xe361554fUL)
+#define RPL_RCP_DATA_ETH_TYPE_WR (0xfc7f05c1UL)
+#define RPL_RCP_DATA_EXT_PRIO (0xcd2ae9d1UL)
+#define RPL_RCP_DATA_LEN (0xb0559aaUL)
+#define RPL_RCP_DATA_OFS (0x4168d8e9UL)
+#define RPL_RCP_DATA_RPL_PTR (0x3000a098UL)
+#define RPL_RPL_CTRL (0xe65376ecUL)
+#define RPL_RPL_CTRL_ADR (0x15abf987UL)
+#define RPL_RPL_CTRL_CNT (0x5a36056UL)
+#define RPL_RPL_DATA (0x4982f4f5UL)
+#define RPL_RPL_DATA_VALUE (0x60951eb4UL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_RPL_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_rpl.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_rpl.h
new file mode 100644
index 0000000000..8c46079cd5
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_tx_rpl.h
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_tx_rpl.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_TX_RPL_
+#define _NTHW_FPGA_REG_DEFS_TX_RPL_
+
+/* TX_RPL */
+#define NTHW_MOD_TX_RPL (0x1095dfbbUL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_TX_RPL_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 20/31] net/ntnic: add Tx Packet Editor (TPE) flow module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (24 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 19/31] net/ntnic: add replacer (Tx RPL) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 21/31] net/ntnic: add base init and deinit of the NT flow API Serhii Iliushyk
                   ` (25 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev; +Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit

The TX Packet Editor is a software abstraction module,
that keeps track of the handful of FPGA modules
that are used to edit packets in the TX pipeline.

Signed-off-by: Serhii Iliushyk <sil-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    |  27 ++
 drivers/net/ntnic/include/hw_mod_tpe_v3.h     | 126 ++++++
 .../nthw/flow_api/flow_backend/flow_backend.c | 364 ++++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_csu.c    |  79 ++++
 .../ntnic/nthw/flow_filter/flow_nthw_csu.h    |   9 +
 .../ntnic/nthw/flow_filter/flow_nthw_hfu.c    | 131 +++++++
 .../ntnic/nthw/flow_filter/flow_nthw_hfu.h    |  30 ++
 .../ntnic/nthw/flow_filter/flow_nthw_ifr.c    |  55 +++
 .../ntnic/nthw/flow_filter/flow_nthw_ifr.h    |  11 +
 .../ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c |  81 ++++
 .../ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h |  17 +
 .../ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c |  49 +++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h |  10 +
 .../ntnic/nthw/flow_filter/flow_nthw_tx_ins.c |  36 ++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_ins.h |   9 +
 .../ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c |  94 +++++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h |  22 ++
 17 files changed, 1150 insertions(+)
 create mode 100644 drivers/net/ntnic/include/hw_mod_tpe_v3.h

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 3ea2fefc53..29c33306d1 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -16,6 +16,7 @@
 #include "hw_mod_pdb_v9.h"
 #include "hw_mod_slc_lr_v2.h"
 #include "hw_mod_hsh_v5.h"
+#include "hw_mod_tpe_v3.h"
 
 #define MAX_PHYS_ADAPTERS 8
 
@@ -114,6 +115,18 @@ struct pdb_func_s {
 	};
 };
 
+struct tpe_func_s {
+	COMMON_FUNC_INFO_S;
+	uint32_t nb_rcp_categories;
+	uint32_t nb_ifr_categories;
+	uint32_t nb_cpy_writers;
+	uint32_t nb_rpl_depth;
+	uint32_t nb_rpl_ext_categories;
+	union {
+		struct hw_mod_tpe_v3_s v3;
+	};
+};
+
 enum debug_mode_e {
 	FLOW_BACKEND_DEBUG_MODE_NONE = 0x0000,
 	FLOW_BACKEND_DEBUG_MODE_WRITE = 0x0001
@@ -244,6 +257,20 @@ struct flow_api_backend_ops {
 	uint32_t (*get_pdb_version)(void *dev);
 	int (*pdb_rcp_flush)(void *dev, const struct pdb_func_s *pdb, int category, int cnt);
 	int (*pdb_config_flush)(void *dev, const struct pdb_func_s *pdb);
+
+	/* TPE */
+	bool (*get_tpe_present)(void *dev);
+	uint32_t (*get_tpe_version)(void *dev);
+	int (*tpe_rpp_rcp_flush)(void *dev, const struct tpe_func_s *tpe, int index, int cnt);
+	int (*tpe_rpp_ifr_rcp_flush)(void *dev, const struct tpe_func_s *tpe, int index, int cnt);
+	int (*tpe_ifr_rcp_flush)(void *dev, const struct tpe_func_s *tpe, int index, int cnt);
+	int (*tpe_ins_rcp_flush)(void *dev, const struct tpe_func_s *tpe, int index, int cnt);
+	int (*tpe_rpl_rcp_flush)(void *dev, const struct tpe_func_s *tpe, int index, int cnt);
+	int (*tpe_rpl_ext_flush)(void *dev, const struct tpe_func_s *tpe, int index, int cnt);
+	int (*tpe_rpl_rpl_flush)(void *dev, const struct tpe_func_s *tpe, int index, int cnt);
+	int (*tpe_cpy_rcp_flush)(void *dev, const struct tpe_func_s *tpe, int index, int cnt);
+	int (*tpe_hfu_rcp_flush)(void *dev, const struct tpe_func_s *tpe, int index, int cnt);
+	int (*tpe_csu_rcp_flush)(void *dev, const struct tpe_func_s *tpe, int index, int cnt);
 };
 
 struct flow_api_backend_s {
diff --git a/drivers/net/ntnic/include/hw_mod_tpe_v3.h b/drivers/net/ntnic/include/hw_mod_tpe_v3.h
new file mode 100644
index 0000000000..87710d8b35
--- /dev/null
+++ b/drivers/net/ntnic/include/hw_mod_tpe_v3.h
@@ -0,0 +1,126 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _HW_MOD_TPE_V3_H_
+#define _HW_MOD_TPE_V3_H_
+
+#include <stdint.h>
+
+struct tpe_v1_rpp_v0_rcp_s {
+	uint32_t exp;
+};
+
+struct tpe_v1_ins_v1_rcp_s {
+	uint32_t dyn;
+	uint32_t ofs;
+	uint32_t len;
+};
+
+struct tpe_v3_rpl_v4_rcp_s {
+	uint32_t dyn;
+	uint32_t ofs;
+	uint32_t len;
+	uint32_t rpl_ptr;
+	uint32_t ext_prio;
+	uint32_t eth_type_wr;
+};
+
+struct tpe_v1_rpl_v2_ext_s {
+	uint32_t rpl_ptr;
+	uint32_t meta_rpl_len;	/* SW only */
+};
+
+struct tpe_v1_rpl_v2_rpl_s {
+	uint32_t value[4];
+};
+
+struct tpe_v1_cpy_v1_rcp_s {
+	uint32_t reader_select;
+	uint32_t dyn;
+	uint32_t ofs;
+	uint32_t len;
+};
+
+struct tpe_v1_hfu_v1_rcp_s {
+	uint32_t len_a_wr;
+	uint32_t len_a_outer_l4_len;
+	uint32_t len_a_pos_dyn;
+	uint32_t len_a_pos_ofs;
+	uint32_t len_a_add_dyn;
+	uint32_t len_a_add_ofs;
+	uint32_t len_a_sub_dyn;
+
+	uint32_t len_b_wr;
+	uint32_t len_b_pos_dyn;
+	uint32_t len_b_pos_ofs;
+	uint32_t len_b_add_dyn;
+	uint32_t len_b_add_ofs;
+	uint32_t len_b_sub_dyn;
+
+	uint32_t len_c_wr;
+	uint32_t len_c_pos_dyn;
+	uint32_t len_c_pos_ofs;
+	uint32_t len_c_add_dyn;
+	uint32_t len_c_add_ofs;
+	uint32_t len_c_sub_dyn;
+
+	uint32_t ttl_wr;
+	uint32_t ttl_pos_dyn;
+	uint32_t ttl_pos_ofs;
+
+	uint32_t cs_inf;
+	uint32_t l3_prt;
+	uint32_t l3_frag;
+	uint32_t tunnel;
+	uint32_t l4_prt;
+	uint32_t outer_l3_ofs;
+	uint32_t outer_l4_ofs;
+	uint32_t inner_l3_ofs;
+	uint32_t inner_l4_ofs;
+};
+
+struct tpe_v1_csu_v0_rcp_s {
+	uint32_t ol3_cmd;
+	uint32_t ol4_cmd;
+	uint32_t il3_cmd;
+	uint32_t il4_cmd;
+};
+
+struct tpe_v2_rpp_v1_ifr_rcp_s {
+	uint32_t ipv4_en;
+	uint32_t ipv4_df_drop;
+	uint32_t ipv6_en;
+	uint32_t ipv6_drop;
+	uint32_t mtu;
+};
+
+struct tpe_v2_ifr_v1_rcp_s {
+	uint32_t ipv4_en;
+	uint32_t ipv4_df_drop;
+	uint32_t ipv6_en;
+	uint32_t ipv6_drop;
+	uint32_t mtu;
+};
+
+struct hw_mod_tpe_v3_s {
+	struct tpe_v1_rpp_v0_rcp_s *rpp_rcp;
+
+	struct tpe_v1_ins_v1_rcp_s *ins_rcp;
+
+	struct tpe_v3_rpl_v4_rcp_s *rpl_rcp;
+	struct tpe_v1_rpl_v2_ext_s *rpl_ext;
+	struct tpe_v1_rpl_v2_rpl_s *rpl_rpl;
+
+	struct tpe_v1_cpy_v1_rcp_s *cpy_rcp;
+
+	struct tpe_v1_hfu_v1_rcp_s *hfu_rcp;
+
+	struct tpe_v1_csu_v0_rcp_s *csu_rcp;
+
+	struct tpe_v2_rpp_v1_ifr_rcp_s *rpp_ifr_rcp;
+	struct tpe_v2_ifr_v1_rcp_s *ifr_rcp;
+};
+
+#endif	/* _HW_MOD_TPE_V3_H_ */
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
index f093bfb8bb..ff359e1713 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_backend/flow_backend.c
@@ -1576,6 +1576,357 @@ static int pdb_config_flush(void *be_dev, const struct pdb_func_s *pdb)
 	return 0;
 }
 
+/*
+ * TPE
+ */
+
+static bool tpe_get_present(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	return be->p_csu_nthw != NULL && be->p_hfu_nthw != NULL && be->p_rpp_lr_nthw != NULL &&
+		be->p_tx_cpy_nthw != NULL && be->p_tx_ins_nthw != NULL &&
+		be->p_tx_rpl_nthw != NULL;
+}
+
+static uint32_t tpe_get_version(void *be_dev)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+
+	const uint32_t csu_version =
+		(uint32_t)((nthw_module_get_major_version(be->p_csu_nthw->m_csu) << 16) |
+			(nthw_module_get_minor_version(be->p_csu_nthw->m_csu) & 0xffff));
+
+	const uint32_t hfu_version =
+		(uint32_t)((nthw_module_get_major_version(be->p_hfu_nthw->m_hfu) << 16) |
+			(nthw_module_get_minor_version(be->p_hfu_nthw->m_hfu) & 0xffff));
+
+	const uint32_t rpp_lr_version =
+		(uint32_t)((nthw_module_get_major_version(be->p_rpp_lr_nthw->m_rpp_lr) << 16) |
+			(nthw_module_get_minor_version(be->p_rpp_lr_nthw->m_rpp_lr) & 0xffff));
+
+	const uint32_t tx_cpy_version =
+		(uint32_t)((nthw_module_get_major_version(be->p_tx_cpy_nthw->m_tx_cpy) << 16) |
+			(nthw_module_get_minor_version(be->p_tx_cpy_nthw->m_tx_cpy) & 0xffff));
+
+	const uint32_t tx_ins_version =
+		(uint32_t)((nthw_module_get_major_version(be->p_tx_ins_nthw->m_tx_ins) << 16) |
+			(nthw_module_get_minor_version(be->p_tx_ins_nthw->m_tx_ins) & 0xffff));
+
+	const uint32_t tx_rpl_version =
+		(uint32_t)((nthw_module_get_major_version(be->p_tx_rpl_nthw->m_tx_rpl) << 16) |
+			(nthw_module_get_minor_version(be->p_tx_rpl_nthw->m_tx_rpl) & 0xffff));
+
+	/*
+	 * we have to support 9563-55-28 and 9563-55-30
+	 * so check for INS ver 0.1 and RPL ver 0.2 or for INS ver 0.2 and RPL ver 0.4
+	 */
+	if (csu_version == 0 && hfu_version == 2 && rpp_lr_version >= 1 && tx_cpy_version == 2 &&
+		((tx_ins_version == 1 && tx_rpl_version == 2) ||
+			(tx_ins_version == 2 && tx_rpl_version == 4))) {
+		return 3;
+	}
+
+	if (csu_version == 0 && hfu_version == 2 && rpp_lr_version >= 1 && tx_cpy_version == 4 &&
+		((tx_ins_version == 1 && tx_rpl_version == 2) ||
+			(tx_ins_version == 2 && tx_rpl_version == 4))) {
+		return 3;
+	}
+
+	assert(false);
+	return 0;
+}
+
+static int tpe_rpp_rcp_flush(void *be_dev, const struct tpe_func_s *rpp_lr, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, rpp_lr, be->p_rpp_lr_nthw);
+
+	if (rpp_lr->ver >= 1) {
+		rpp_lr_nthw_rcp_cnt(be->p_rpp_lr_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			rpp_lr_nthw_rcp_select(be->p_rpp_lr_nthw, index + i);
+			rpp_lr_nthw_rcp_exp(be->p_rpp_lr_nthw, rpp_lr->v3.rpp_rcp[index + i].exp);
+			rpp_lr_nthw_rcp_flush(be->p_rpp_lr_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(rpp_lr, be->p_rpp_lr_nthw);
+	return 0;
+}
+
+static int tpe_rpp_ifr_rcp_flush(void *be_dev, const struct tpe_func_s *rpp_lr, int index, int cnt)
+{
+	int res = 0;
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, rpp_lr, be->p_rpp_lr_nthw);
+
+	if (rpp_lr->ver >= 2) {
+		rpp_lr_nthw_ifr_rcp_cnt(be->p_rpp_lr_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			rpp_lr_nthw_ifr_rcp_select(be->p_rpp_lr_nthw, index + i);
+			rpp_lr_nthw_ifr_rcp_ipv4_en(be->p_rpp_lr_nthw,
+				rpp_lr->v3.rpp_ifr_rcp[index + i].ipv4_en);
+			rpp_lr_nthw_ifr_rcp_ipv4_df_drop(be->p_rpp_lr_nthw,
+				rpp_lr->v3.rpp_ifr_rcp[index + i]
+				.ipv4_df_drop);
+			rpp_lr_nthw_ifr_rcp_ipv6_en(be->p_rpp_lr_nthw,
+				rpp_lr->v3.rpp_ifr_rcp[index + i].ipv6_en);
+			rpp_lr_nthw_ifr_rcp_ipv6_drop(be->p_rpp_lr_nthw,
+				rpp_lr->v3.rpp_ifr_rcp[index + i].ipv6_drop);
+			rpp_lr_nthw_ifr_rcp_mtu(be->p_rpp_lr_nthw,
+				rpp_lr->v3.rpp_ifr_rcp[index + i].mtu);
+			rpp_lr_nthw_ifr_rcp_flush(be->p_rpp_lr_nthw);
+		}
+
+	} else {
+		res = -1;
+	}
+
+	CHECK_DEBUG_OFF(rpp_lr, be->p_rpp_lr_nthw);
+	return res;
+}
+
+static int tpe_ifr_rcp_flush(void *be_dev, const struct tpe_func_s *ifr, int index, int cnt)
+{
+	int res = 0;
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, ifr, be->p_ifr_nthw);
+
+	if (ifr->ver >= 2) {
+		ifr_nthw_rcp_cnt(be->p_ifr_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			ifr_nthw_rcp_select(be->p_ifr_nthw, index + i);
+			ifr_nthw_rcp_ipv4_en(be->p_ifr_nthw, ifr->v3.ifr_rcp[index + i].ipv4_en);
+			ifr_nthw_rcp_ipv4_df_drop(be->p_ifr_nthw,
+				ifr->v3.ifr_rcp[index + i].ipv4_df_drop);
+			ifr_nthw_rcp_ipv6_en(be->p_ifr_nthw, ifr->v3.ifr_rcp[index + i].ipv6_en);
+			ifr_nthw_rcp_ipv6_drop(be->p_ifr_nthw,
+				ifr->v3.ifr_rcp[index + i].ipv6_drop);
+			ifr_nthw_rcp_mtu(be->p_ifr_nthw, ifr->v3.ifr_rcp[index + i].mtu);
+			ifr_nthw_rcp_flush(be->p_ifr_nthw);
+		}
+
+	} else {
+		res = -1;
+	}
+
+	CHECK_DEBUG_OFF(ifr, be->p_ifr_nthw);
+	return res;
+}
+
+static int tpe_ins_rcp_flush(void *be_dev, const struct tpe_func_s *tx_ins, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, tx_ins, be->p_tx_ins_nthw);
+
+	if (tx_ins->ver >= 1) {
+		tx_ins_nthw_rcp_cnt(be->p_tx_ins_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			tx_ins_nthw_rcp_select(be->p_tx_ins_nthw, index + i);
+			tx_ins_nthw_rcp_dyn(be->p_tx_ins_nthw, tx_ins->v3.ins_rcp[index + i].dyn);
+			tx_ins_nthw_rcp_ofs(be->p_tx_ins_nthw, tx_ins->v3.ins_rcp[index + i].ofs);
+			tx_ins_nthw_rcp_len(be->p_tx_ins_nthw, tx_ins->v3.ins_rcp[index + i].len);
+			tx_ins_nthw_rcp_flush(be->p_tx_ins_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(tx_ins, be->p_tx_ins_nthw);
+	return 0;
+}
+
+static int tpe_rpl_rcp_flush(void *be_dev, const struct tpe_func_s *tx_rpl, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, tx_rpl, be->p_tx_rpl_nthw);
+
+	if (tx_rpl->ver >= 1) {
+		tx_rpl_nthw_rcp_cnt(be->p_tx_rpl_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			tx_rpl_nthw_rcp_select(be->p_tx_rpl_nthw, index + i);
+			tx_rpl_nthw_rcp_dyn(be->p_tx_rpl_nthw, tx_rpl->v3.rpl_rcp[index + i].dyn);
+			tx_rpl_nthw_rcp_ofs(be->p_tx_rpl_nthw, tx_rpl->v3.rpl_rcp[index + i].ofs);
+			tx_rpl_nthw_rcp_len(be->p_tx_rpl_nthw, tx_rpl->v3.rpl_rcp[index + i].len);
+			tx_rpl_nthw_rcp_rpl_ptr(be->p_tx_rpl_nthw,
+				tx_rpl->v3.rpl_rcp[index + i].rpl_ptr);
+			tx_rpl_nthw_rcp_ext_prio(be->p_tx_rpl_nthw,
+				tx_rpl->v3.rpl_rcp[index + i].ext_prio);
+
+			if (tx_rpl->ver >= 3) {
+				tx_rpl_nthw_rcp_eth_type_wr(be->p_tx_rpl_nthw,
+					tx_rpl->v3.rpl_rcp[index + i]
+					.eth_type_wr);
+			}
+
+			tx_rpl_nthw_rcp_flush(be->p_tx_rpl_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(tx_rpl, be->p_tx_rpl_nthw);
+	return 0;
+}
+
+static int tpe_rpl_ext_flush(void *be_dev, const struct tpe_func_s *tx_rpl, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, tx_rpl, be->p_tx_rpl_nthw);
+
+	if (tx_rpl->ver >= 1) {
+		tx_rpl_nthw_ext_cnt(be->p_tx_rpl_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			tx_rpl_nthw_ext_select(be->p_tx_rpl_nthw, index + i);
+			tx_rpl_nthw_ext_rpl_ptr(be->p_tx_rpl_nthw,
+				tx_rpl->v3.rpl_ext[index + i].rpl_ptr);
+			tx_rpl_nthw_ext_flush(be->p_tx_rpl_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(tx_rpl, be->p_tx_rpl_nthw);
+	return 0;
+}
+
+static int tpe_rpl_rpl_flush(void *be_dev, const struct tpe_func_s *tx_rpl, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, tx_rpl, be->p_tx_rpl_nthw);
+
+	if (tx_rpl->ver >= 1) {
+		tx_rpl_nthw_rpl_cnt(be->p_tx_rpl_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			tx_rpl_nthw_rpl_select(be->p_tx_rpl_nthw, index + i);
+			tx_rpl_nthw_rpl_value(be->p_tx_rpl_nthw,
+				tx_rpl->v3.rpl_rpl[index + i].value);
+			tx_rpl_nthw_rpl_flush(be->p_tx_rpl_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(tx_rpl, be->p_tx_rpl_nthw);
+	return 0;
+}
+
+static int tpe_cpy_rcp_flush(void *be_dev, const struct tpe_func_s *tx_cpy, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	unsigned int wr_index = -1;
+
+	CHECK_DEBUG_ON(be, tx_cpy, be->p_tx_cpy_nthw);
+
+	if (tx_cpy->ver >= 1) {
+		for (int i = 0; i < cnt; i++) {
+			if (wr_index != (index + i) / tx_cpy->nb_rcp_categories) {
+				wr_index = (index + i) / tx_cpy->nb_rcp_categories;
+				tx_cpy_nthw_writer_cnt(be->p_tx_cpy_nthw, wr_index, 1);
+			}
+
+			tx_cpy_nthw_writer_select(be->p_tx_cpy_nthw, wr_index,
+				(index + i) % tx_cpy->nb_rcp_categories);
+			tx_cpy_nthw_writer_reader_select(be->p_tx_cpy_nthw, wr_index,
+				tx_cpy->v3.cpy_rcp[index + i]
+				.reader_select);
+			tx_cpy_nthw_writer_dyn(be->p_tx_cpy_nthw, wr_index,
+				tx_cpy->v3.cpy_rcp[index + i].dyn);
+			tx_cpy_nthw_writer_ofs(be->p_tx_cpy_nthw, wr_index,
+				tx_cpy->v3.cpy_rcp[index + i].ofs);
+			tx_cpy_nthw_writer_len(be->p_tx_cpy_nthw, wr_index,
+				tx_cpy->v3.cpy_rcp[index + i].len);
+			tx_cpy_nthw_writer_flush(be->p_tx_cpy_nthw, wr_index);
+		}
+	}
+
+	CHECK_DEBUG_OFF(tx_cpy, be->p_tx_cpy_nthw);
+	return 0;
+}
+
+static int tpe_hfu_rcp_flush(void *be_dev, const struct tpe_func_s *hfu, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, hfu, be->p_hfu_nthw);
+
+	if (hfu->ver >= 1) {
+		hfu_nthw_rcp_cnt(be->p_hfu_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			hfu_nthw_rcp_select(be->p_hfu_nthw, index + i);
+			hfu_nthw_rcp_len_a_wr(be->p_hfu_nthw, hfu->v3.hfu_rcp[index + i].len_a_wr);
+			hfu_nthw_rcp_len_a_ol4len(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_a_outer_l4_len);
+			hfu_nthw_rcp_len_a_pos_dyn(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_a_pos_dyn);
+			hfu_nthw_rcp_len_a_pos_ofs(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_a_pos_ofs);
+			hfu_nthw_rcp_len_a_add_dyn(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_a_add_dyn);
+			hfu_nthw_rcp_len_a_add_ofs(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_a_add_ofs);
+			hfu_nthw_rcp_len_a_sub_dyn(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_a_sub_dyn);
+			hfu_nthw_rcp_len_b_wr(be->p_hfu_nthw, hfu->v3.hfu_rcp[index + i].len_b_wr);
+			hfu_nthw_rcp_len_b_pos_dyn(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_b_pos_dyn);
+			hfu_nthw_rcp_len_b_pos_ofs(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_b_pos_ofs);
+			hfu_nthw_rcp_len_b_add_dyn(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_b_add_dyn);
+			hfu_nthw_rcp_len_b_add_ofs(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_b_add_ofs);
+			hfu_nthw_rcp_len_b_sub_dyn(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_b_sub_dyn);
+			hfu_nthw_rcp_len_c_wr(be->p_hfu_nthw, hfu->v3.hfu_rcp[index + i].len_c_wr);
+			hfu_nthw_rcp_len_c_pos_dyn(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_c_pos_dyn);
+			hfu_nthw_rcp_len_c_pos_ofs(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_c_pos_ofs);
+			hfu_nthw_rcp_len_c_add_dyn(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_c_add_dyn);
+			hfu_nthw_rcp_len_c_add_ofs(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_c_add_ofs);
+			hfu_nthw_rcp_len_c_sub_dyn(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].len_c_sub_dyn);
+			hfu_nthw_rcp_ttl_wr(be->p_hfu_nthw, hfu->v3.hfu_rcp[index + i].ttl_wr);
+			hfu_nthw_rcp_ttl_pos_dyn(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].ttl_pos_dyn);
+			hfu_nthw_rcp_ttl_pos_ofs(be->p_hfu_nthw,
+				hfu->v3.hfu_rcp[index + i].ttl_pos_ofs);
+			hfu_nthw_rcp_flush(be->p_hfu_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(hfu, be->p_hfu_nthw);
+	return 0;
+}
+
+static int tpe_csu_rcp_flush(void *be_dev, const struct tpe_func_s *csu, int index, int cnt)
+{
+	struct backend_dev_s *be = (struct backend_dev_s *)be_dev;
+	CHECK_DEBUG_ON(be, csu, be->p_csu_nthw);
+
+	if (csu->ver >= 1) {
+		csu_nthw_rcp_cnt(be->p_csu_nthw, 1);
+
+		for (int i = 0; i < cnt; i++) {
+			csu_nthw_rcp_select(be->p_csu_nthw, index + i);
+			csu_nthw_rcp_outer_l3_cmd(be->p_csu_nthw,
+				csu->v3.csu_rcp[index + i].ol3_cmd);
+			csu_nthw_rcp_outer_l4_cmd(be->p_csu_nthw,
+				csu->v3.csu_rcp[index + i].ol4_cmd);
+			csu_nthw_rcp_inner_l3_cmd(be->p_csu_nthw,
+				csu->v3.csu_rcp[index + i].il3_cmd);
+			csu_nthw_rcp_inner_l4_cmd(be->p_csu_nthw,
+				csu->v3.csu_rcp[index + i].il4_cmd);
+			csu_nthw_rcp_flush(be->p_csu_nthw);
+		}
+	}
+
+	CHECK_DEBUG_OFF(csu, be->p_csu_nthw);
+	return 0;
+}
+
 /*
  * DBS
  */
@@ -1705,6 +2056,19 @@ const struct flow_api_backend_ops flow_be_iface = {
 	pdb_get_version,
 	pdb_rcp_flush,
 	pdb_config_flush,
+
+	tpe_get_present,
+	tpe_get_version,
+	tpe_rpp_rcp_flush,
+	tpe_rpp_ifr_rcp_flush,
+	tpe_ifr_rcp_flush,
+	tpe_ins_rcp_flush,
+	tpe_rpl_rcp_flush,
+	tpe_rpl_ext_flush,
+	tpe_rpl_rpl_flush,
+	tpe_cpy_rcp_flush,
+	tpe_hfu_rcp_flush,
+	tpe_csu_rcp_flush,
 };
 
 const struct flow_api_backend_ops *bin_flow_backend_init(nthw_fpga_t *p_fpga, void **dev)
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.c
index 21efc62eda..f92f322d07 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.c
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.c
@@ -12,6 +12,11 @@
 
 #include "flow_nthw_csu.h"
 
+void csu_nthw_set_debug_mode(struct csu_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_csu, n_debug_mode);
+}
+
 struct csu_nthw *csu_nthw_new(void)
 {
 	struct csu_nthw *p = malloc(sizeof(struct csu_nthw));
@@ -60,3 +65,77 @@ int csu_nthw_init(struct csu_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
 
 	return 0;
 }
+
+void csu_nthw_rcp_select(const struct csu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_ctrl_adr, val);
+}
+
+void csu_nthw_rcp_cnt(const struct csu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_ctrl_cnt, val);
+}
+
+void csu_nthw_rcp_outer_l3_cmd(const struct csu_nthw *p, uint32_t val)
+{
+	/*
+	 * Select L3 calc method for outer layer3.
+	 * 0: Do not touch checksum field.
+	 * 1: Check, but do not touch checksum field.
+	 * 2: Insert checksum header value for BAD checksum.
+	 * 3: Insert checksum header value for GOOD checksum.
+	 */
+	nthw_field_set_val32(p->mp_rcp_data_ol3_cmd, val);
+}
+
+void csu_nthw_rcp_outer_l4_cmd(const struct csu_nthw *p, uint32_t val)
+{
+	/*
+	 * Select L4 calc method for outer layer4.
+	 * 0: Do not touch checksum field.
+	 * 1: Check, but do not touch checksum field.
+	 * 2: Insert checksum header value for BAD checksum.
+	 * 3: Insert checksum header value for GOOD checksum.
+	 * 4: Set UDP checksum value of ZERO for both IPv4/IPv6, set good checksum for TCP.
+	 * 5: Set UDP checksum value of ZERO for IPv4, set good checksum for TCP.
+	 * 6: Set UDP checksum value of ZERO for outer tunnel when tunnel is IPv4/IPv6 and UDP,
+	 * otherwise GOOD checksum. 7: Set UDP checksum value of ZERO for outer tunnel when tunnel
+	 * is IPv4 and UDP, otherwise GOOD checksum.
+	 */
+	nthw_field_set_val32(p->mp_rcp_data_ol4_cmd, val);
+}
+
+void csu_nthw_rcp_inner_l3_cmd(const struct csu_nthw *p, uint32_t val)
+{
+	/*
+	 * Select L3 calc method for inner layer3 (tunneled).
+	 * 0: Do not touch checksum field.
+	 * 1: Check, but do not touch checksum field.
+	 * 2: Insert checksum header value for BAD checksum.
+	 * 3: Insert checksum header value for GOOD checksum.
+	 */
+	nthw_field_set_val32(p->mp_rcp_data_il3_cmd, val);
+}
+
+void csu_nthw_rcp_inner_l4_cmd(const struct csu_nthw *p, uint32_t val)
+{
+	/*
+	 * Select L4 calc method for inner layer4 (tunneled).
+	 * 0: Do not touch checksum field.
+	 * 1: Check, but do not touch checksum field.
+	 * 2: Insert checksum header value for BAD checksum.
+	 * 3: Insert checksum header value for GOOD checksum.
+	 * 4: Set UDP checksum value of ZERO for both IPv4/IPv6, set good checksum for TCP.
+	 * 5: Set UDP checksum value of ZERO for IPv4, set good checksum for TCP.
+	 * 6: Set UDP checksum value of ZERO for outer tunnel when tunnel is IPv4/IPv6 and UDP,
+	 * otherwise GOOD checksum. 7: Set UDP checksum value of ZERO for outer tunnel when tunnel
+	 * is IPv4 and UDP, otherwise GOOD checksum.
+	 */
+	nthw_field_set_val32(p->mp_rcp_data_il4_cmd, val);
+}
+
+void csu_nthw_rcp_flush(const struct csu_nthw *p)
+{
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.h
index e5986a1a9b..91a0926318 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.h
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.h
@@ -31,5 +31,14 @@ void csu_nthw_delete(struct csu_nthw *p);
 int csu_nthw_init(struct csu_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
 
 int csu_nthw_setup(struct csu_nthw *p, int n_idx, int n_idx_cnt);
+void csu_nthw_set_debug_mode(struct csu_nthw *p, unsigned int n_debug_mode);
+
+void csu_nthw_rcp_select(const struct csu_nthw *p, uint32_t val);
+void csu_nthw_rcp_cnt(const struct csu_nthw *p, uint32_t val);
+void csu_nthw_rcp_outer_l3_cmd(const struct csu_nthw *p, uint32_t val);
+void csu_nthw_rcp_outer_l4_cmd(const struct csu_nthw *p, uint32_t val);
+void csu_nthw_rcp_inner_l3_cmd(const struct csu_nthw *p, uint32_t val);
+void csu_nthw_rcp_inner_l4_cmd(const struct csu_nthw *p, uint32_t val);
+void csu_nthw_rcp_flush(const struct csu_nthw *p);
 
 #endif	/* _FLOW_NTHW_CSU_H_ */
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.c
index 36d181df02..fcb4003aed 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.c
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.c
@@ -12,6 +12,11 @@
 
 #include "flow_nthw_hfu.h"
 
+void hfu_nthw_set_debug_mode(struct hfu_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_hfu, n_debug_mode);
+}
+
 struct hfu_nthw *hfu_nthw_new(void)
 {
 	struct hfu_nthw *p = malloc(sizeof(struct hfu_nthw));
@@ -97,3 +102,129 @@ int hfu_nthw_init(struct hfu_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
 
 	return 0;
 }
+
+void hfu_nthw_rcp_select(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_addr, val);
+}
+
+void hfu_nthw_rcp_cnt(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void hfu_nthw_rcp_len_a_wr(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_a_wr, val);
+}
+
+void hfu_nthw_rcp_len_a_ol4len(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_a_ol4len, val);
+}
+
+void hfu_nthw_rcp_len_a_pos_dyn(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_a_pos_dyn, val);
+}
+
+void hfu_nthw_rcp_len_a_pos_ofs(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_a_pos_ofs, val);
+}
+
+void hfu_nthw_rcp_len_a_add_dyn(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_a_add_dyn, val);
+}
+
+void hfu_nthw_rcp_len_a_add_ofs(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_a_add_ofs, val);
+}
+
+void hfu_nthw_rcp_len_a_sub_dyn(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_a_sub_dyn, val);
+}
+
+void hfu_nthw_rcp_len_b_wr(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_b_wr, val);
+}
+
+void hfu_nthw_rcp_len_b_pos_dyn(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_b_pos_dyn, val);
+}
+
+void hfu_nthw_rcp_len_b_pos_ofs(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_b_pos_ofs, val);
+}
+
+void hfu_nthw_rcp_len_b_add_dyn(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_b_add_dyn, val);
+}
+
+void hfu_nthw_rcp_len_b_add_ofs(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_b_add_ofs, val);
+}
+
+void hfu_nthw_rcp_len_b_sub_dyn(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_b_sub_dyn, val);
+}
+
+void hfu_nthw_rcp_len_c_wr(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_c_wr, val);
+}
+
+void hfu_nthw_rcp_len_c_pos_dyn(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_c_pos_dyn, val);
+}
+
+void hfu_nthw_rcp_len_c_pos_ofs(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_c_pos_ofs, val);
+}
+
+void hfu_nthw_rcp_len_c_add_dyn(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_c_add_dyn, val);
+}
+
+void hfu_nthw_rcp_len_c_add_ofs(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_c_add_ofs, val);
+}
+
+void hfu_nthw_rcp_len_c_sub_dyn(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len_c_sub_dyn, val);
+}
+
+void hfu_nthw_rcp_ttl_wr(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ttl_wr, val);
+}
+
+void hfu_nthw_rcp_ttl_pos_dyn(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ttl_pos_dyn, val);
+}
+
+void hfu_nthw_rcp_ttl_pos_ofs(const struct hfu_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ttl_pos_ofs, val);
+}
+
+void hfu_nthw_rcp_flush(const struct hfu_nthw *p)
+{
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.h
index 7a59066b92..77002a639e 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.h
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.h
@@ -50,5 +50,35 @@ void hfu_nthw_delete(struct hfu_nthw *p);
 int hfu_nthw_init(struct hfu_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
 
 int hfu_nthw_setup(struct hfu_nthw *p, int n_idx, int n_idx_cnt);
+void hfu_nthw_set_debug_mode(struct hfu_nthw *p, unsigned int n_debug_mode);
+
+/* RCP */
+void hfu_nthw_rcp_select(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_cnt(const struct hfu_nthw *p, uint32_t val);
+
+void hfu_nthw_rcp_len_a_wr(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_a_ol4len(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_a_pos_dyn(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_a_pos_ofs(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_a_add_dyn(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_a_add_ofs(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_a_sub_dyn(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_b_wr(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_b_pos_dyn(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_b_pos_ofs(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_b_add_dyn(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_b_add_ofs(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_b_sub_dyn(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_c_wr(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_c_pos_dyn(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_c_pos_ofs(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_c_add_dyn(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_c_add_ofs(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_len_c_sub_dyn(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_ttl_wr(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_ttl_pos_dyn(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_ttl_pos_ofs(const struct hfu_nthw *p, uint32_t val);
+
+void hfu_nthw_rcp_flush(const struct hfu_nthw *p);
 
 #endif	/* __FLOW_NTHW_HFU_H__ */
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.c
index 849c599e32..e6bb4329da 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.c
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.c
@@ -12,6 +12,11 @@
 
 #include "flow_nthw_ifr.h"
 
+void ifr_nthw_set_debug_mode(struct ifr_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_ifr, n_debug_mode);
+}
+
 struct ifr_nthw *ifr_nthw_new(void)
 {
 	struct ifr_nthw *p = malloc(sizeof(struct ifr_nthw));
@@ -66,3 +71,53 @@ int ifr_nthw_init(struct ifr_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
 
 	return 0;
 }
+
+void ifr_nthw_rcp_select(const struct ifr_nthw *p, uint32_t val)
+{
+	assert(p->mp_rcp_addr);
+	nthw_field_set_val32(p->mp_rcp_addr, val);
+}
+
+void ifr_nthw_rcp_cnt(const struct ifr_nthw *p, uint32_t val)
+{
+	assert(p->mp_rcp_cnt);
+	nthw_field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void ifr_nthw_rcp_ipv4_en(const struct ifr_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_ipv4_en)
+		nthw_field_set_val32(p->mp_rcp_data_ipv4_en, val);
+}
+
+void ifr_nthw_rcp_ipv4_df_drop(const struct ifr_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_ipv4_df_drop)
+		nthw_field_set_val32(p->mp_rcp_data_ipv4_df_drop, val);
+}
+
+void ifr_nthw_rcp_ipv6_en(const struct ifr_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_ipv6_en)
+		nthw_field_set_val32(p->mp_rcp_data_ipv6_en, val);
+}
+
+void ifr_nthw_rcp_ipv6_drop(const struct ifr_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_ipv6_drop)
+		nthw_field_set_val32(p->mp_rcp_data_ipv6_drop, val);
+}
+
+void ifr_nthw_rcp_mtu(const struct ifr_nthw *p, uint32_t val)
+{
+	assert(p->mp_rcp_data_mtu);
+	nthw_field_set_val32(p->mp_rcp_data_mtu, val);
+}
+
+void ifr_nthw_rcp_flush(const struct ifr_nthw *p)
+{
+	assert(p->mp_rcp_ctrl);
+	assert(p->mp_rcp_data);
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.h
index 439aafbfbc..6751a599aa 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.h
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.h
@@ -39,5 +39,16 @@ struct ifr_nthw *ifr_nthw_new(void);
 int ifr_nthw_init(struct ifr_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
 
 int ifr_nthw_setup(struct ifr_nthw *p, int n_idx, int n_idx_cnt);
+void ifr_nthw_set_debug_mode(struct ifr_nthw *p, unsigned int n_debug_mode);
+
+/* IFR */
+void ifr_nthw_rcp_select(const struct ifr_nthw *p, uint32_t val);
+void ifr_nthw_rcp_cnt(const struct ifr_nthw *p, uint32_t val);
+void ifr_nthw_rcp_ipv4_en(const struct ifr_nthw *p, uint32_t val);
+void ifr_nthw_rcp_ipv4_df_drop(const struct ifr_nthw *p, uint32_t val);
+void ifr_nthw_rcp_ipv6_en(const struct ifr_nthw *p, uint32_t val);
+void ifr_nthw_rcp_ipv6_drop(const struct ifr_nthw *p, uint32_t val);
+void ifr_nthw_rcp_mtu(const struct ifr_nthw *p, uint32_t val);
+void ifr_nthw_rcp_flush(const struct ifr_nthw *p);
 
 #endif	/* __FLOW_NTHW_IFR_H__ */
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c
index 84bbcbdc4f..6cdc2dea37 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c
@@ -12,6 +12,11 @@
 
 #include "flow_nthw_rpp_lr.h"
 
+void rpp_lr_nthw_set_debug_mode(struct rpp_lr_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_rpp_lr, n_debug_mode);
+}
+
 struct rpp_lr_nthw *rpp_lr_nthw_new(void)
 {
 	struct rpp_lr_nthw *p = malloc(sizeof(struct rpp_lr_nthw));
@@ -74,3 +79,79 @@ int rpp_lr_nthw_init(struct rpp_lr_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
 
 	return 0;
 }
+
+void rpp_lr_nthw_rcp_select(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	assert(p->mp_rcp_addr);
+	nthw_field_set_val32(p->mp_rcp_addr, val);
+}
+
+void rpp_lr_nthw_rcp_cnt(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	assert(p->mp_rcp_cnt);
+	nthw_field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void rpp_lr_nthw_rcp_exp(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	assert(p->mp_rcp_data_exp);
+	nthw_field_set_val32(p->mp_rcp_data_exp, val);
+}
+
+void rpp_lr_nthw_rcp_flush(const struct rpp_lr_nthw *p)
+{
+	assert(p->mp_rcp_ctrl);
+	assert(p->mp_rcp_data);
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+}
+
+void rpp_lr_nthw_ifr_rcp_select(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	assert(p->mp_ifr_rcp_addr);
+	nthw_field_set_val32(p->mp_ifr_rcp_addr, val);
+}
+
+void rpp_lr_nthw_ifr_rcp_cnt(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	assert(p->mp_ifr_rcp_cnt);
+	nthw_field_set_val32(p->mp_ifr_rcp_cnt, val);
+}
+
+void rpp_lr_nthw_ifr_rcp_ipv4_en(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	if (p->mp_ifr_rcp_data_ipv4_en)
+		nthw_field_set_val32(p->mp_ifr_rcp_data_ipv4_en, val);
+}
+
+void rpp_lr_nthw_ifr_rcp_ipv4_df_drop(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	if (p->mp_ifr_rcp_data_ipv4_df_drop)
+		nthw_field_set_val32(p->mp_ifr_rcp_data_ipv4_df_drop, val);
+}
+
+void rpp_lr_nthw_ifr_rcp_ipv6_en(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	if (p->mp_ifr_rcp_data_ipv6_en)
+		nthw_field_set_val32(p->mp_ifr_rcp_data_ipv6_en, val);
+}
+
+void rpp_lr_nthw_ifr_rcp_ipv6_drop(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	if (p->mp_ifr_rcp_data_ipv6_drop)
+		nthw_field_set_val32(p->mp_ifr_rcp_data_ipv6_drop, val);
+}
+
+void rpp_lr_nthw_ifr_rcp_mtu(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	assert(p->mp_ifr_rcp_data_mtu);
+	nthw_field_set_val32(p->mp_ifr_rcp_data_mtu, val);
+}
+
+void rpp_lr_nthw_ifr_rcp_flush(const struct rpp_lr_nthw *p)
+{
+	assert(p->mp_ifr_rcp_ctrl);
+	assert(p->mp_ifr_rcp_data);
+	nthw_register_flush(p->mp_ifr_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_ifr_rcp_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h
index 509e46fc48..bdb2e5fa54 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h
@@ -40,5 +40,22 @@ void rpp_lr_nthw_delete(struct rpp_lr_nthw *p);
 int rpp_lr_nthw_init(struct rpp_lr_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
 
 int rpp_lr_nthw_setup(struct rpp_lr_nthw *p, int n_idx, int n_idx_cnt);
+void rpp_lr_nthw_set_debug_mode(struct rpp_lr_nthw *p, unsigned int n_debug_mode);
+
+/* RCP */
+void rpp_lr_nthw_rcp_select(const struct rpp_lr_nthw *p, uint32_t val);
+void rpp_lr_nthw_rcp_cnt(const struct rpp_lr_nthw *p, uint32_t val);
+void rpp_lr_nthw_rcp_exp(const struct rpp_lr_nthw *p, uint32_t val);
+void rpp_lr_nthw_rcp_flush(const struct rpp_lr_nthw *p);
+
+/* RCP IFR */
+void rpp_lr_nthw_ifr_rcp_select(const struct rpp_lr_nthw *p, uint32_t val);
+void rpp_lr_nthw_ifr_rcp_cnt(const struct rpp_lr_nthw *p, uint32_t val);
+void rpp_lr_nthw_ifr_rcp_ipv4_en(const struct rpp_lr_nthw *p, uint32_t val);
+void rpp_lr_nthw_ifr_rcp_ipv4_df_drop(const struct rpp_lr_nthw *p, uint32_t val);
+void rpp_lr_nthw_ifr_rcp_ipv6_en(const struct rpp_lr_nthw *p, uint32_t val);
+void rpp_lr_nthw_ifr_rcp_ipv6_drop(const struct rpp_lr_nthw *p, uint32_t val);
+void rpp_lr_nthw_ifr_rcp_mtu(const struct rpp_lr_nthw *p, uint32_t val);
+void rpp_lr_nthw_ifr_rcp_flush(const struct rpp_lr_nthw *p);
 
 #endif	/* __FLOW_NTHW_RPP_LR_H__ */
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c
index 197baae334..9ba8b97701 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c
@@ -12,6 +12,11 @@
 
 #include "flow_nthw_tx_cpy.h"
 
+void tx_cpy_nthw_set_debug_mode(struct tx_cpy_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_tx_cpy, n_debug_mode);
+}
+
 struct tx_cpy_nthw *tx_cpy_nthw_new(void)
 {
 	struct tx_cpy_nthw *p = malloc(sizeof(struct tx_cpy_nthw));
@@ -337,3 +342,47 @@ int tx_cpy_nthw_init(struct tx_cpy_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
 
 	return 0;
 }
+
+void tx_cpy_nthw_writer_select(const struct tx_cpy_nthw *p, unsigned int index, uint32_t val)
+{
+	assert(index < p->m_writers_cnt);
+	nthw_field_set_val32(p->m_writers[index].mp_writer_ctrl_addr, val);
+}
+
+void tx_cpy_nthw_writer_cnt(const struct tx_cpy_nthw *p, unsigned int index, uint32_t val)
+{
+	assert(index < p->m_writers_cnt);
+	nthw_field_set_val32(p->m_writers[index].mp_writer_ctrl_cnt, val);
+}
+
+void tx_cpy_nthw_writer_reader_select(const struct tx_cpy_nthw *p, unsigned int index,
+	uint32_t val)
+{
+	assert(index < p->m_writers_cnt);
+	nthw_field_set_val32(p->m_writers[index].mp_writer_data_reader_select, val);
+}
+
+void tx_cpy_nthw_writer_dyn(const struct tx_cpy_nthw *p, unsigned int index, uint32_t val)
+{
+	assert(index < p->m_writers_cnt);
+	nthw_field_set_val32(p->m_writers[index].mp_writer_data_dyn, val);
+}
+
+void tx_cpy_nthw_writer_ofs(const struct tx_cpy_nthw *p, unsigned int index, uint32_t val)
+{
+	assert(index < p->m_writers_cnt);
+	nthw_field_set_val32(p->m_writers[index].mp_writer_data_ofs, val);
+}
+
+void tx_cpy_nthw_writer_len(const struct tx_cpy_nthw *p, unsigned int index, uint32_t val)
+{
+	assert(index < p->m_writers_cnt);
+	nthw_field_set_val32(p->m_writers[index].mp_writer_data_len, val);
+}
+
+void tx_cpy_nthw_writer_flush(const struct tx_cpy_nthw *p, unsigned int index)
+{
+	assert(index < p->m_writers_cnt);
+	nthw_register_flush(p->m_writers[index].mp_writer_ctrl, 1);
+	nthw_register_flush(p->m_writers[index].mp_writer_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h
index 801b47b0bb..c1094c09a9 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h
@@ -45,5 +45,15 @@ void tx_cpy_nthw_delete(struct tx_cpy_nthw *p);
 int tx_cpy_nthw_init(struct tx_cpy_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
 
 int tx_cpy_nthw_setup(struct tx_cpy_nthw *p, int n_idx, int n_idx_cnt);
+void tx_cpy_nthw_set_debug_mode(struct tx_cpy_nthw *p, unsigned int n_debug_mode);
+
+void tx_cpy_nthw_writer_select(const struct tx_cpy_nthw *p, unsigned int index, uint32_t val);
+void tx_cpy_nthw_writer_cnt(const struct tx_cpy_nthw *p, unsigned int index, uint32_t val);
+void tx_cpy_nthw_writer_reader_select(const struct tx_cpy_nthw *p, unsigned int index,
+	uint32_t val);
+void tx_cpy_nthw_writer_dyn(const struct tx_cpy_nthw *p, unsigned int index, uint32_t val);
+void tx_cpy_nthw_writer_ofs(const struct tx_cpy_nthw *p, unsigned int index, uint32_t val);
+void tx_cpy_nthw_writer_len(const struct tx_cpy_nthw *p, unsigned int index, uint32_t val);
+void tx_cpy_nthw_writer_flush(const struct tx_cpy_nthw *p, unsigned int index);
 
 #endif	/* __FLOW_NTHW_TX_CPY_H__ */
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.c
index 5d9867981e..d27752444c 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.c
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.c
@@ -12,6 +12,11 @@
 
 #include "flow_nthw_tx_ins.h"
 
+void tx_ins_nthw_set_debug_mode(struct tx_ins_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_tx_ins, n_debug_mode);
+}
+
 struct tx_ins_nthw *tx_ins_nthw_new(void)
 {
 	struct tx_ins_nthw *p = malloc(sizeof(struct tx_ins_nthw));
@@ -60,3 +65,34 @@ int tx_ins_nthw_init(struct tx_ins_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
 
 	return 0;
 }
+
+void tx_ins_nthw_rcp_select(const struct tx_ins_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_addr, val);
+}
+
+void tx_ins_nthw_rcp_cnt(const struct tx_ins_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void tx_ins_nthw_rcp_dyn(const struct tx_ins_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_dyn, val);
+}
+
+void tx_ins_nthw_rcp_ofs(const struct tx_ins_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ofs, val);
+}
+
+void tx_ins_nthw_rcp_len(const struct tx_ins_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len, val);
+}
+
+void tx_ins_nthw_rcp_flush(const struct tx_ins_nthw *p)
+{
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.h
index 4e7c4133da..b87b9dcac3 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.h
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.h
@@ -31,5 +31,14 @@ void tx_ins_nthw_delete(struct tx_ins_nthw *p);
 int tx_ins_nthw_init(struct tx_ins_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
 
 int tx_ins_nthw_setup(struct tx_ins_nthw *p, int n_idx, int n_idx_cnt);
+void tx_ins_nthw_set_debug_mode(struct tx_ins_nthw *p, unsigned int n_debug_mode);
+
+/* RCP */
+void tx_ins_nthw_rcp_select(const struct tx_ins_nthw *p, uint32_t val);
+void tx_ins_nthw_rcp_cnt(const struct tx_ins_nthw *p, uint32_t val);
+void tx_ins_nthw_rcp_dyn(const struct tx_ins_nthw *p, uint32_t val);
+void tx_ins_nthw_rcp_ofs(const struct tx_ins_nthw *p, uint32_t val);
+void tx_ins_nthw_rcp_len(const struct tx_ins_nthw *p, uint32_t val);
+void tx_ins_nthw_rcp_flush(const struct tx_ins_nthw *p);
 
 #endif	/* __FLOW_NTHW_TX_INS_H__ */
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c
index 65fc1a9c5e..a3a7554f16 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c
@@ -12,6 +12,11 @@
 
 #include "flow_nthw_tx_rpl.h"
 
+void tx_rpl_nthw_set_debug_mode(struct tx_rpl_nthw *p, unsigned int n_debug_mode)
+{
+	nthw_module_set_debug_mode(p->m_tx_rpl, n_debug_mode);
+}
+
 struct tx_rpl_nthw *tx_rpl_nthw_new(void)
 {
 	struct tx_rpl_nthw *p = malloc(sizeof(struct tx_rpl_nthw));
@@ -76,3 +81,92 @@ int tx_rpl_nthw_init(struct tx_rpl_nthw *p, nthw_fpga_t *p_fpga, int n_instance)
 
 	return 0;
 }
+
+void tx_rpl_nthw_rcp_select(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_ctrl_addr, val);
+}
+
+void tx_rpl_nthw_rcp_cnt(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_ctrl_cnt, val);
+}
+
+void tx_rpl_nthw_rcp_dyn(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_dyn, val);
+}
+
+void tx_rpl_nthw_rcp_ofs(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ofs, val);
+}
+
+void tx_rpl_nthw_rcp_len(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_len, val);
+}
+
+void tx_rpl_nthw_rcp_rpl_ptr(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_rpl_ptr, val);
+}
+
+void tx_rpl_nthw_rcp_ext_prio(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rcp_data_ext_prio, val);
+}
+
+void tx_rpl_nthw_rcp_eth_type_wr(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	assert(p->mp_rcp_data_eth_type_wr);
+	nthw_field_set_val32(p->mp_rcp_data_eth_type_wr, val);
+}
+
+void tx_rpl_nthw_rcp_flush(const struct tx_rpl_nthw *p)
+{
+	nthw_register_flush(p->mp_rcp_ctrl, 1);
+	nthw_register_flush(p->mp_rcp_data, 1);
+}
+
+void tx_rpl_nthw_ext_select(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_ext_ctrl_addr, val);
+}
+
+void tx_rpl_nthw_ext_cnt(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_ext_ctrl_cnt, val);
+}
+
+void tx_rpl_nthw_ext_rpl_ptr(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_ext_data_rpl_ptr, val);
+}
+
+void tx_rpl_nthw_ext_flush(const struct tx_rpl_nthw *p)
+{
+	nthw_register_flush(p->mp_ext_ctrl, 1);
+	nthw_register_flush(p->mp_ext_data, 1);
+}
+
+void tx_rpl_nthw_rpl_select(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rpl_ctrl_addr, val);
+}
+
+void tx_rpl_nthw_rpl_cnt(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	nthw_field_set_val32(p->mp_rpl_ctrl_cnt, val);
+}
+
+void tx_rpl_nthw_rpl_value(const struct tx_rpl_nthw *p, const uint32_t *val)
+{
+	nthw_field_set_val(p->mp_rpl_data_value, val, 4);
+}
+
+void tx_rpl_nthw_rpl_flush(const struct tx_rpl_nthw *p)
+{
+	nthw_register_flush(p->mp_rpl_ctrl, 1);
+	nthw_register_flush(p->mp_rpl_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h
index 7425021692..f743b418f0 100644
--- a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h
@@ -48,5 +48,27 @@ void tx_rpl_nthw_delete(struct tx_rpl_nthw *p);
 int tx_rpl_nthw_init(struct tx_rpl_nthw *p, nthw_fpga_t *p_fpga, int n_instance);
 
 int tx_rpl_nthw_setup(struct tx_rpl_nthw *p, int n_idx, int n_idx_cnt);
+void tx_rpl_nthw_set_debug_mode(struct tx_rpl_nthw *p, unsigned int n_debug_mode);
+
+/* RCP */
+void tx_rpl_nthw_rcp_select(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_rcp_cnt(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_rcp_dyn(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_rcp_ofs(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_rcp_len(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_rcp_rpl_ptr(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_rcp_ext_prio(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_rcp_eth_type_wr(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_rcp_flush(const struct tx_rpl_nthw *p);
+
+void tx_rpl_nthw_ext_select(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_ext_cnt(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_ext_rpl_ptr(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_ext_flush(const struct tx_rpl_nthw *p);
+
+void tx_rpl_nthw_rpl_select(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_rpl_cnt(const struct tx_rpl_nthw *p, uint32_t val);
+void tx_rpl_nthw_rpl_value(const struct tx_rpl_nthw *p, const uint32_t *val);
+void tx_rpl_nthw_rpl_flush(const struct tx_rpl_nthw *p);
 
 #endif	/* __FLOW_NTHW_TX_RPL_H__ */
-- 
2.45.0


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

* [PATCH v1 21/31] net/ntnic: add base init and deinit of the NT flow API
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (25 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 20/31] net/ntnic: add Tx Packet Editor (TPE) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 22/31] net/ntnic: add base init and deinit the NT flow backend Serhii Iliushyk
                   ` (24 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

Add basic API for initialization resources required by flow filter API

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/flow_api.h          |  82 ++++++
 drivers/net/ntnic/include/flow_api_engine.h   |  43 +++
 drivers/net/ntnic/include/hw_mod_backend.h    |   3 +
 .../ntnic/include/stream_binary_flow_api.h    |  22 ++
 drivers/net/ntnic/meson.build                 |   2 +
 drivers/net/ntnic/nthw/flow_api/flow_api.c    | 245 ++++++++++++++++++
 .../ntnic/nthw/flow_api/flow_api_nic_setup.h  |   6 +
 drivers/net/ntnic/nthw/flow_api/flow_filter.c |  17 +-
 drivers/net/ntnic/nthw/flow_api/flow_kcc.c    |  19 ++
 drivers/net/ntnic/nthw/flow_api/flow_km.c     |  19 ++
 10 files changed, 453 insertions(+), 5 deletions(-)
 create mode 100644 drivers/net/ntnic/include/flow_api_engine.h
 create mode 100644 drivers/net/ntnic/include/stream_binary_flow_api.h
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_kcc.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_km.c

diff --git a/drivers/net/ntnic/include/flow_api.h b/drivers/net/ntnic/include/flow_api.h
index 6a2277c2ca..bad1f72868 100644
--- a/drivers/net/ntnic/include/flow_api.h
+++ b/drivers/net/ntnic/include/flow_api.h
@@ -6,14 +6,96 @@
 #ifndef _FLOW_API_H_
 #define _FLOW_API_H_
 
+#include <pthread.h>
+
 #include "ntlog.h"
 
+#include "flow_api_engine.h"
 #include "hw_mod_backend.h"
+#include "stream_binary_flow_api.h"
+
+/*
+ * Flow NIC and Eth port device management
+ */
+
+struct hw_mod_resource_s {
+	uint8_t *alloc_bm;      /* allocation bitmap */
+	uint32_t *ref;  /* reference counter for each resource element */
+	uint32_t resource_count;/* number of total available entries */
+};
+
+/*
+ * Device Management API
+ */
+int flow_delete_eth_dev(struct flow_eth_dev *eth_dev);
+
+struct flow_eth_dev {
+	/* NIC that owns this port device */
+	struct flow_nic_dev *ndev;
+	/* NIC port id */
+	uint8_t port;
+
+	/* 0th for exception */
+	struct flow_queue_id_s rx_queue[FLOW_MAX_QUEUES + 1];
+
+	/* VSWITCH has exceptions sent on queue 0 per design */
+	int num_queues;
+
+	struct flow_eth_dev *next;
+};
 
 /* registered NIC backends */
 struct flow_nic_dev {
+	struct hw_mod_resource_s res[RES_COUNT];/* raw NIC resource allocation table */
+	void *km_res_handle;
+	void *kcc_res_handle;
+
+	uint32_t flow_unique_id_counter;
+	/* linked list of all flows created on this NIC */
+	struct flow_handle *flow_base;
+
 	/* NIC backend API */
 	struct flow_api_backend_s be;
+	/* linked list of created eth-port devices on this NIC */
+	struct flow_eth_dev *eth_base;
+	pthread_mutex_t mtx;
+
+	/* next NIC linked list */
+	struct flow_nic_dev *next;
 };
 
+/*
+ * Resources
+ */
+
+extern const char *dbg_res_descr[];
+
+#define flow_nic_unset_bit(arr, x)                                                                \
+	do {                                                                                      \
+		size_t _temp_x = (x);                                                             \
+		arr[_temp_x / 8] &= (uint8_t)(~(1 << (_temp_x % 8)));                             \
+	} while (0)
+
+#define flow_nic_is_bit_set(arr, x)                                                               \
+	({                                                                                        \
+		size_t _temp_x = (x);                                                             \
+		(arr[_temp_x / 8] & (uint8_t)(1 << (_temp_x % 8)));                               \
+	})
+
+#define flow_nic_mark_resource_unused(_ndev, res_type, index)                                     \
+	do {                                                                                      \
+		typeof(res_type) _temp_res_type = (res_type);                                 \
+		size_t _temp_index = (index);                                                     \
+		NT_LOG(DBG, FILTER, "mark resource unused: %s idx %zu\n",                         \
+		       dbg_res_descr[_temp_res_type], _temp_index);                               \
+		flow_nic_unset_bit((_ndev)->res[_temp_res_type].alloc_bm, _temp_index);           \
+	} while (0)
+
+#define flow_nic_is_resource_used(_ndev, res_type, index)                                         \
+	(!!flow_nic_is_bit_set((_ndev)->res[res_type].alloc_bm, index))
+
+void flow_nic_free_resource(struct flow_nic_dev *ndev, enum res_type_e res_type, int idx);
+
+int flow_nic_deref_resource(struct flow_nic_dev *ndev, enum res_type_e res_type, int index);
+
 #endif
diff --git a/drivers/net/ntnic/include/flow_api_engine.h b/drivers/net/ntnic/include/flow_api_engine.h
new file mode 100644
index 0000000000..724b68c3e8
--- /dev/null
+++ b/drivers/net/ntnic/include/flow_api_engine.h
@@ -0,0 +1,43 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _FLOW_API_ENGINE_H_
+#define _FLOW_API_ENGINE_H_
+
+/*
+ * Resource management
+ * These are free resources in FPGA
+ * Other FPGA memory lists are linked to one of these
+ * and will implicitly follow them
+ */
+enum res_type_e {
+	RES_QUEUE,
+	RES_CAT_CFN,
+	RES_CAT_COT,
+	RES_CAT_EXO,
+	RES_CAT_LEN,
+	RES_KM_FLOW_TYPE,
+	RES_KM_CATEGORY,
+	RES_HSH_RCP,
+	RES_PDB_RCP,
+	RES_QSL_RCP,
+	RES_QSL_QST,
+	RES_SLC_LR_RCP,
+
+	RES_FLM_FLOW_TYPE,
+	RES_FLM_RCP,
+	RES_TPE_RCP,
+	RES_TPE_EXT,
+	RES_TPE_RPL,
+	RES_SCRUB_RCP,
+	RES_COUNT,
+	RES_INVALID
+};
+
+void km_free_ndev_resource_management(void **handle);
+
+void kcc_free_ndev_resource_management(void **handle);
+
+#endif  /* _FLOW_API_ENGINE_H_ */
diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 29c33306d1..3c6c15c896 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -8,6 +8,8 @@
 
 #include <stdbool.h>
 
+#include "ntlog.h"
+
 #include "hw_mod_cat_v18.h"
 #include "hw_mod_cat_v21.h"
 #include "hw_mod_flm_v25.h"
@@ -275,6 +277,7 @@ struct flow_api_backend_ops {
 
 struct flow_api_backend_s {
 	void *be_dev;
+	const struct flow_api_backend_ops *iface;
 };
 
 #endif  /* _HW_MOD_BACKEND_H_ */
diff --git a/drivers/net/ntnic/include/stream_binary_flow_api.h b/drivers/net/ntnic/include/stream_binary_flow_api.h
new file mode 100644
index 0000000000..10529b8843
--- /dev/null
+++ b/drivers/net/ntnic/include/stream_binary_flow_api.h
@@ -0,0 +1,22 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _STREAM_BINARY_FLOW_API_H_
+#define _STREAM_BINARY_FLOW_API_H_
+
+/*
+ * Flow frontend for binary programming interface
+ */
+
+#define FLOW_MAX_QUEUES 128
+
+struct flow_queue_id_s {
+	int id;
+	int hw_id;
+};
+
+struct flow_eth_dev;             /* port device */
+
+#endif  /* _STREAM_BINARY_FLOW_API_H_ */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index e236b82b36..15549e1c94 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -46,6 +46,8 @@ sources = files(
         'nthw/flow_api/flow_api.c',
         'nthw/flow_api/flow_backend/flow_backend.c',
         'nthw/flow_api/flow_filter.c',
+        'nthw/flow_api/flow_kcc.c',
+        'nthw/flow_api/flow_km.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_csu.c',
         'nthw/flow_filter/flow_nthw_flm.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
index 9671a20e0b..92b8d083e0 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -3,11 +3,256 @@
  * Copyright(c) 2023 Napatech A/S
  */
 
+#include "flow_api_engine.h"
 #include "flow_api_nic_setup.h"
 #include "ntnic_mod_reg.h"
 
 #include "flow_filter.h"
 
+const char *dbg_res_descr[] = {
+	/* RES_QUEUE */ "RES_QUEUE",
+	/* RES_CAT_CFN */ "RES_CAT_CFN",
+	/* RES_CAT_COT */ "RES_CAT_COT",
+	/* RES_CAT_EXO */ "RES_CAT_EXO",
+	/* RES_CAT_LEN */ "RES_CAT_LEN",
+	/* RES_KM_FLOW_TYPE */ "RES_KM_FLOW_TYPE",
+	/* RES_KM_CATEGORY */ "RES_KM_CATEGORY",
+	/* RES_HSH_RCP */ "RES_HSH_RCP",
+	/* RES_PDB_RCP */ "RES_PDB_RCP",
+	/* RES_QSL_RCP */ "RES_QSL_RCP",
+	/* RES_QSL_LTX */ "RES_QSL_LTX",
+	/* RES_QSL_QST */ "RES_QSL_QST",
+	/* RES_SLC_LR_RCP */ "RES_SLC_LR_RCP",
+	/* RES_FLM_FLOW_TYPE */ "RES_FLM_FLOW_TYPE",
+	/* RES_FLM_RCP */ "RES_FLM_RCP",
+	/* RES_TPE_RCP */ "RES_TPE_RCP",
+	/* RES_TPE_EXT */ "RES_TPE_EXT",
+	/* RES_TPE_RPL */ "RES_TPE_RPL",
+	/* RES_COUNT */ "RES_COUNT",
+	/* RES_INVALID */ "RES_INVALID"
+};
+
+static struct flow_nic_dev *dev_base;
+static pthread_mutex_t base_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+void flow_nic_free_resource(struct flow_nic_dev *ndev, enum res_type_e res_type, int idx)
+{
+	flow_nic_mark_resource_unused(ndev, res_type, idx);
+}
+
+int flow_nic_deref_resource(struct flow_nic_dev *ndev, enum res_type_e res_type, int index)
+{
+	NT_LOG(DBG, FILTER, "De-reference resource %s idx %i (before ref cnt %i)\n",
+		dbg_res_descr[res_type], index, ndev->res[res_type].ref[index]);
+	assert(flow_nic_is_resource_used(ndev, res_type, index));
+	assert(ndev->res[res_type].ref[index]);
+	/* deref */
+	ndev->res[res_type].ref[index]--;
+
+	if (!ndev->res[res_type].ref[index])
+		flow_nic_free_resource(ndev, res_type, index);
+
+	return !!ndev->res[res_type].ref[index];/* if 0 resource has been freed */
+}
+
+/*
+ * Device Management API
+ */
+
+static int nic_remove_eth_port_dev(struct flow_nic_dev *ndev, struct flow_eth_dev *eth_dev)
+{
+	struct flow_eth_dev *dev = ndev->eth_base, *prev = NULL;
+
+	while (dev) {
+		if (dev == eth_dev) {
+			if (prev)
+				prev->next = dev->next;
+
+			else
+				ndev->eth_base = dev->next;
+
+			return 0;
+		}
+
+		prev = dev;
+		dev = dev->next;
+	}
+
+	return -1;
+}
+
+static void flow_ndev_reset(struct flow_nic_dev *ndev)
+{
+	/* Delete all eth-port devices created on this NIC device */
+	while (ndev->eth_base)
+		flow_delete_eth_dev(ndev->eth_base);
+
+	km_free_ndev_resource_management(&ndev->km_res_handle);
+	kcc_free_ndev_resource_management(&ndev->kcc_res_handle);
+
+	ndev->flow_unique_id_counter = 0;
+
+#ifdef FLOW_DEBUG
+	/*
+	 * free all resources default allocated, initially for this NIC DEV
+	 * Is not really needed since the bitmap will be freed in a sec. Therefore
+	 * only in debug mode
+	 */
+
+	/* Check if all resources has been released */
+	NT_LOG(DBG, FILTER, "Delete NIC DEV Adaptor %i\n", ndev->adapter_no);
+
+	for (unsigned int i = 0; i < RES_COUNT; i++) {
+		int err = 0;
+#if defined(FLOW_DEBUG)
+		NT_LOG(DBG, FILTER, "RES state for: %s\n", dbg_res_descr[i]);
+#endif
+
+		for (unsigned int ii = 0; ii < ndev->res[i].resource_count; ii++) {
+			int ref = ndev->res[i].ref[ii];
+			int used = flow_nic_is_resource_used(ndev, i, ii);
+
+			if (ref || used) {
+				NT_LOG(DBG, FILTER, "  [%i]: ref cnt %i, used %i\n", ii, ref,
+					used);
+				err = 1;
+			}
+		}
+
+		if (err)
+			NT_LOG(DBG, FILTER, "ERROR - some resources not freed\n");
+	}
+
+#endif
+}
+
+int flow_delete_eth_dev(struct flow_eth_dev *eth_dev)
+{
+	struct flow_nic_dev *ndev = eth_dev->ndev;
+
+	if (!ndev) {
+		/* Error invalid nic device */
+		return -1;
+	}
+
+	NT_LOG(DBG, FILTER, "Delete eth-port device %p, port %i\n", eth_dev, eth_dev->port);
+
+#ifdef FLOW_DEBUG
+	ndev->be.iface->set_debug_mode(ndev->be.be_dev, FLOW_BACKEND_DEBUG_MODE_WRITE);
+#endif
+
+	/* delete all created flows from this device */
+	pthread_mutex_lock(&ndev->mtx);
+
+#ifdef FLOW_DEBUG
+	ndev->be.iface->set_debug_mode(ndev->be.be_dev, FLOW_BACKEND_DEBUG_MODE_NONE);
+#endif
+
+#ifndef SCATTER_GATHER
+
+	/* free rx queues */
+	for (int i = 0; i < eth_dev->num_queues; i++) {
+		ndev->be.iface->free_rx_queue(ndev->be.be_dev, eth_dev->rx_queue[i].hw_id);
+		flow_nic_deref_resource(ndev, RES_QUEUE, eth_dev->rx_queue[i].id);
+	}
+
+#endif
+
+	/* take eth_dev out of ndev list */
+	if (nic_remove_eth_port_dev(ndev, eth_dev) != 0)
+		NT_LOG(ERR, FILTER, "ERROR : eth_dev %p not found\n", eth_dev);
+
+	pthread_mutex_unlock(&ndev->mtx);
+
+	/* free eth_dev */
+	free(eth_dev);
+
+	return 0;
+}
+
+/*
+ * Flow API NIC Setup
+ * Flow backend creation function - register and initialize common backend API to FPA modules
+ */
+
+static void done_resource_elements(struct flow_nic_dev *ndev, enum res_type_e res_type)
+{
+	assert(ndev);
+
+	if (ndev->res[res_type].alloc_bm)
+		free(ndev->res[res_type].alloc_bm);
+}
+
+static int list_remove_flow_nic(struct flow_nic_dev *ndev)
+{
+	pthread_mutex_lock(&base_mtx);
+	struct flow_nic_dev *nic_dev = dev_base, *prev = NULL;
+
+	while (nic_dev) {
+		if (nic_dev == ndev) {
+			if (prev)
+				prev->next = nic_dev->next;
+
+			else
+				dev_base = nic_dev->next;
+
+			pthread_mutex_unlock(&base_mtx);
+			return 0;
+		}
+
+		prev = nic_dev;
+		nic_dev = nic_dev->next;
+	}
+
+	pthread_mutex_unlock(&base_mtx);
+	return -1;
+}
+
+struct flow_nic_dev *flow_api_create(uint8_t adapter_no, const struct flow_api_backend_ops *be_if,
+	void *be_dev)
+{
+	(void)adapter_no;
+
+	if (!be_if || be_if->version != 1) {
+		NT_LOG(DBG, FILTER, "ERR: %s\n", __func__);
+		return NULL;
+	}
+
+	struct flow_nic_dev *ndev = calloc(1, sizeof(struct flow_nic_dev));
+
+	if (!ndev) {
+		NT_LOG(ERR, FILTER, "ERROR: calloc failed\n");
+		return NULL;
+	}
+
+	/*
+	 * To dump module initialization writes use
+	 * FLOW_BACKEND_DEBUG_MODE_WRITE
+	 * then remember to set it ...NONE afterwards again
+	 */
+	be_if->set_debug_mode(be_dev, FLOW_BACKEND_DEBUG_MODE_NONE);
+
+	return ndev;
+}
+
+int flow_api_done(struct flow_nic_dev *ndev)
+{
+	NT_LOG(DBG, FILTER, "FLOW API DONE\n");
+
+	if (ndev) {
+		flow_ndev_reset(ndev);
+
+		/* delete resource management allocations for this ndev */
+		for (int i = 0; i < RES_COUNT; i++)
+			done_resource_elements(ndev, i);
+
+		list_remove_flow_nic(ndev);
+		free(ndev);
+	}
+
+	return 0;
+}
+
 void *flow_api_get_be_dev(struct flow_nic_dev *ndev)
 {
 	if (!ndev) {
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h b/drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h
index da083f050a..eeb070c569 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api_nic_setup.h
@@ -9,6 +9,12 @@
 #include "hw_mod_backend.h"
 #include "flow_api.h"
 
+/*
+ * Flow capable NIC backend - creating flow api instance for adapter nr (backend)
+ */
+struct flow_nic_dev *flow_api_create(uint8_t adapter_no, const struct flow_api_backend_ops *be_if,
+	void *be_dev);
+int flow_api_done(struct flow_nic_dev *dev);
 void *flow_api_get_be_dev(struct flow_nic_dev *dev);
 
 #endif  /* __FLOW_API_NIC_SETUP_H__ */
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_filter.c b/drivers/net/ntnic/nthw/flow_api/flow_filter.c
index e822ba7df9..69e5972f5d 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_filter.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_filter.c
@@ -9,10 +9,8 @@
 
 int flow_filter_init(nthw_fpga_t *p_fpga, struct flow_nic_dev **p_flow_device, int adapter_no)
 {
-	(void)p_flow_device;
-	(void)adapter_no;
-
 	void *be_dev = NULL;
+	struct flow_nic_dev *flow_nic;
 
 	const struct flow_backend_ops *flow_backend_ops = get_flow_backend_ops();
 
@@ -22,8 +20,17 @@ int flow_filter_init(nthw_fpga_t *p_fpga, struct flow_nic_dev **p_flow_device, i
 	}
 
 	NT_LOG(DBG, FILTER, "Initializing flow filter api\n");
-	flow_backend_ops->bin_flow_backend_init(p_fpga, &be_dev);
+	const struct flow_api_backend_ops *iface =
+		flow_backend_ops->bin_flow_backend_init(p_fpga, &be_dev);
+
+	flow_nic = flow_api_create((uint8_t)adapter_no, iface, be_dev);
+
+	if (!flow_nic) {
+		*p_flow_device = NULL;
+		return -1;
+	}
 
+	*p_flow_device = flow_nic;
 	return 0;
 }
 
@@ -31,7 +38,7 @@ int flow_filter_done(struct flow_nic_dev *dev)
 {
 	void *be_dev = flow_api_get_be_dev(dev);
 
-	int res = 0;
+	int res = flow_api_done(dev);
 
 	if (be_dev) {
 		const struct flow_backend_ops *flow_backend_ops = get_flow_backend_ops();
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_kcc.c b/drivers/net/ntnic/nthw/flow_api/flow_kcc.c
new file mode 100644
index 0000000000..dc5e5474c1
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/flow_kcc.c
@@ -0,0 +1,19 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+
+#include "hw_mod_backend.h"
+#include "flow_api_engine.h"
+
+void kcc_free_ndev_resource_management(void **handle)
+{
+	if (*handle) {
+		free(*handle);
+		NT_LOG(DBG, FILTER, "Free NIC DEV KCC-CAM record manager\n");
+	}
+
+	*handle = NULL;
+}
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_km.c b/drivers/net/ntnic/nthw/flow_api/flow_km.c
new file mode 100644
index 0000000000..1ba7ed7da2
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/flow_km.c
@@ -0,0 +1,19 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdlib.h>
+
+#include "hw_mod_backend.h"
+#include "flow_api_engine.h"
+
+void km_free_ndev_resource_management(void **handle)
+{
+	if (*handle) {
+		free(*handle);
+		NT_LOG(DBG, FILTER, "Free NIC DEV CAM and TCAM record manager\n");
+	}
+
+	*handle = NULL;
+}
-- 
2.45.0


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

* [PATCH v1 22/31] net/ntnic: add base init and deinit the NT flow backend
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (26 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 21/31] net/ntnic: add base init and deinit of the NT flow API Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 23/31] net/ntnic: add categorizer (CAT) FPGA module Serhii Iliushyk
                   ` (23 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

Add basic implementation of the NT flow backend  API

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/flow_api.h          |  3 +
 drivers/net/ntnic/include/flow_api_engine.h   |  5 ++
 drivers/net/ntnic/include/hw_mod_backend.h    | 12 ++++
 drivers/net/ntnic/meson.build                 |  1 +
 drivers/net/ntnic/nthw/flow_api/flow_api.c    | 64 +++++++++++++++++++
 .../nthw/flow_api/hw_mod/hw_mod_backend.c     | 28 ++++++++
 6 files changed, 113 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c

diff --git a/drivers/net/ntnic/include/flow_api.h b/drivers/net/ntnic/include/flow_api.h
index bad1f72868..b5194ffa8d 100644
--- a/drivers/net/ntnic/include/flow_api.h
+++ b/drivers/net/ntnic/include/flow_api.h
@@ -46,6 +46,9 @@ struct flow_eth_dev {
 
 /* registered NIC backends */
 struct flow_nic_dev {
+	uint8_t adapter_no;     /* physical adapter no in the host system */
+	uint16_t ports; /* number of in-ports addressable on this NIC */
+
 	struct hw_mod_resource_s res[RES_COUNT];/* raw NIC resource allocation table */
 	void *km_res_handle;
 	void *kcc_res_handle;
diff --git a/drivers/net/ntnic/include/flow_api_engine.h b/drivers/net/ntnic/include/flow_api_engine.h
index 724b68c3e8..db5e6fe09d 100644
--- a/drivers/net/ntnic/include/flow_api_engine.h
+++ b/drivers/net/ntnic/include/flow_api_engine.h
@@ -6,6 +6,11 @@
 #ifndef _FLOW_API_ENGINE_H_
 #define _FLOW_API_ENGINE_H_
 
+/*
+ * Resource management
+ */
+#define BIT_CONTAINER_8_ALIGN(x) (((x) + 7) / 8)
+
 /*
  * Resource management
  * These are free resources in FPGA
diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 3c6c15c896..f47153cbb6 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -278,6 +278,18 @@ struct flow_api_backend_ops {
 struct flow_api_backend_s {
 	void *be_dev;
 	const struct flow_api_backend_ops *iface;
+
+	/* NIC attributes */
+	unsigned int num_phy_ports;
+	unsigned int num_rx_ports;
+
+	/* flow filter resource capacities */
+	unsigned int max_categories;
+	unsigned int max_queues;
 };
 
+int flow_api_backend_init(struct flow_api_backend_s *dev, const struct flow_api_backend_ops *iface,
+	void *be_dev);
+int flow_api_backend_done(struct flow_api_backend_s *dev);
+
 #endif  /* _HW_MOD_BACKEND_H_ */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 15549e1c94..57d1ded2a7 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -48,6 +48,7 @@ sources = files(
         'nthw/flow_api/flow_filter.c',
         'nthw/flow_api/flow_kcc.c',
         'nthw/flow_api/flow_km.c',
+        'nthw/flow_api/hw_mod/hw_mod_backend.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_csu.c',
         'nthw/flow_filter/flow_nthw_flm.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
index 92b8d083e0..4bab8983c9 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -175,6 +175,24 @@ int flow_delete_eth_dev(struct flow_eth_dev *eth_dev)
  * Flow backend creation function - register and initialize common backend API to FPA modules
  */
 
+static int init_resource_elements(struct flow_nic_dev *ndev, enum res_type_e res_type,
+	uint32_t count)
+{
+	assert(ndev->res[res_type].alloc_bm == NULL);
+	/* allocate bitmap and ref counter */
+	ndev->res[res_type].alloc_bm =
+		calloc(1, BIT_CONTAINER_8_ALIGN(count) + count * sizeof(uint32_t));
+
+	if (ndev->res[res_type].alloc_bm) {
+		ndev->res[res_type].ref =
+			(uint32_t *)&ndev->res[res_type].alloc_bm[BIT_CONTAINER_8_ALIGN(count)];
+		ndev->res[res_type].resource_count = count;
+		return 0;
+	}
+
+	return -1;
+}
+
 static void done_resource_elements(struct flow_nic_dev *ndev, enum res_type_e res_type)
 {
 	assert(ndev);
@@ -183,6 +201,14 @@ static void done_resource_elements(struct flow_nic_dev *ndev, enum res_type_e re
 		free(ndev->res[res_type].alloc_bm);
 }
 
+static void list_insert_flow_nic(struct flow_nic_dev *ndev)
+{
+	pthread_mutex_lock(&base_mtx);
+	ndev->next = dev_base;
+	dev_base = ndev;
+	pthread_mutex_unlock(&base_mtx);
+}
+
 static int list_remove_flow_nic(struct flow_nic_dev *ndev)
 {
 	pthread_mutex_lock(&base_mtx);
@@ -232,7 +258,44 @@ struct flow_nic_dev *flow_api_create(uint8_t adapter_no, const struct flow_api_b
 	 */
 	be_if->set_debug_mode(be_dev, FLOW_BACKEND_DEBUG_MODE_NONE);
 
+	if (flow_api_backend_init(&ndev->be, be_if, be_dev) != 0)
+		goto err_exit;
+
+	ndev->adapter_no = adapter_no;
+
+	ndev->ports = (uint16_t)((ndev->be.num_rx_ports > 256) ? 256 : ndev->be.num_rx_ports);
+
+	/*
+	 * Free resources in NIC must be managed by this module
+	 * Get resource sizes and create resource manager elements
+	 */
+	if (init_resource_elements(ndev, RES_QUEUE, ndev->be.max_queues))
+		goto err_exit;
+
+	if (init_resource_elements(ndev, RES_CAT_COT, ndev->be.max_categories))
+		goto err_exit;
+
+	if (init_resource_elements(ndev, RES_SLC_LR_RCP, ndev->be.max_categories))
+		goto err_exit;
+
+	/* may need IPF, COR */
+
+	/* check all defined has been initialized */
+	for (int i = 0; i < RES_COUNT; i++)
+		assert(ndev->res[i].alloc_bm);
+
+	pthread_mutex_init(&ndev->mtx, NULL);
+	list_insert_flow_nic(ndev);
+
 	return ndev;
+
+err_exit:
+
+	if (ndev)
+		flow_api_done(ndev);
+
+	NT_LOG(DBG, FILTER, "ERR: %s\n", __func__);
+	return NULL;
 }
 
 int flow_api_done(struct flow_nic_dev *ndev)
@@ -246,6 +309,7 @@ int flow_api_done(struct flow_nic_dev *ndev)
 		for (int i = 0; i < RES_COUNT; i++)
 			done_resource_elements(ndev, i);
 
+		flow_api_backend_done(&ndev->be);
 		list_remove_flow_nic(ndev);
 		free(ndev);
 	}
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
new file mode 100644
index 0000000000..5966dc6e8c
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
@@ -0,0 +1,28 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "hw_mod_backend.h"
+
+int flow_api_backend_init(struct flow_api_backend_s *dev,
+	const struct flow_api_backend_ops *iface,
+	void *be_dev)
+{
+	assert(dev);
+	dev->iface = iface;
+	dev->be_dev = be_dev;
+	dev->num_phy_ports = iface->get_nb_phy_port(be_dev);
+	dev->num_rx_ports = iface->get_nb_rx_port(be_dev);
+	dev->max_categories = iface->get_nb_categories(be_dev);
+	dev->max_queues = iface->get_nb_queues(be_dev);
+
+	return 0;
+}
+
+int flow_api_backend_done(struct flow_api_backend_s *dev)
+{
+	(void)dev;
+
+	return 0;
+}
-- 
2.45.0


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

* [PATCH v1 23/31] net/ntnic: add categorizer (CAT) FPGA module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (27 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 22/31] net/ntnic: add base init and deinit the NT flow backend Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 24/31] net/ntnic: add key match (KM) " Serhii Iliushyk
                   ` (22 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Categorizer module’s main purpose is to is select the behavior
of other modules in the FPGA pipeline depending on a protocol check.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    | 205 ++++
 drivers/net/ntnic/meson.build                 |   1 +
 drivers/net/ntnic/nthw/flow_api/flow_api.c    |  15 +
 .../nthw/flow_api/hw_mod/hw_mod_backend.c     | 109 +-
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c   | 985 ++++++++++++++++++
 .../supported/nthw_fpga_9563_055_049_0000.c   | 264 ++++-
 6 files changed, 1577 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index f47153cbb6..20b10faf5e 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -22,12 +22,116 @@
 
 #define MAX_PHYS_ADAPTERS 8
 
+#define VER_MAJOR(ver) (((ver) >> 16) & 0xffff)
+#define VER_MINOR(ver) ((ver) & 0xffff)
+
+struct flow_api_backend_s;
+struct common_func_s;
+
+void *callocate_mod(struct common_func_s *mod, int sets, ...);
+void zero_module_cache(struct common_func_s *mod);
+
+#define ALL_ENTRIES -1000
+
+#define INDEX_TOO_LARGE (NT_LOG(INF, FILTER, "ERROR:%s: Index too large\n", __func__), -2)
+
+#define WORD_OFF_TOO_LARGE (NT_LOG(INF, FILTER, "ERROR:%s: Word offset too large\n", __func__), -3)
+
+#define UNSUP_FIELD                                                                               \
+	(NT_LOG(INF, FILTER, "ERROR:%s: Unsupported field in NIC module\n", __func__), -5)
+
+#define UNSUP_VER                                                                                 \
+	(NT_LOG(INF, FILTER, "ERROR:%s: Unsupported NIC module: %s ver %i.%i\n", __func__, _MOD_, \
+		VER_MAJOR(_VER_), VER_MINOR(_VER_)),                                              \
+	 -4)
+
+#define COUNT_ERROR(_RESOURCE_)                                                                   \
+	(NT_LOG(INF, FILTER,                                                                      \
+		"ERROR:%s: Insufficient resource [ %s ] : NIC module: %s ver %i.%i\n", __func__,  \
+		#_RESOURCE_, _MOD_, VER_MAJOR(_VER_), VER_MINOR(_VER_)),                          \
+	 -4)
+
+#define NOT_FOUND 0xffffffff
+
+enum {
+	EXTRA_INDEXES
+};
+
+#define GET(cached_val, val) ({ *(val) = *(cached_val); })
+
+#define SET(cached_val, val) ({ *(cached_val) = *(val); })
+
+#define GET_SET(cached_val, val)                                                                  \
+	do {                                                                                      \
+		uint32_t *temp_val = (val);                                                       \
+		typeof(cached_val) *temp_cached_val = &(cached_val);                          \
+		if (get)                                                                          \
+			GET(temp_cached_val, temp_val);                                           \
+		else                                                                              \
+			SET(temp_cached_val, temp_val);                                           \
+	} while (0)
+
+#define GET_SIGNED(cached_val, val) ({ *(val) = (uint32_t)(*(cached_val)); })
+
+#define SET_SIGNED(cached_val, val) ({ *(cached_val) = (int32_t)(*(val)); })
+
+#define GET_SET_SIGNED(cached_val, val)                                                           \
+	do {                                                                                      \
+		uint32_t *temp_val = (val);                                                       \
+		typeof(cached_val) *temp_cached_val = &(cached_val);                          \
+		if (get)                                                                          \
+			GET_SIGNED(temp_cached_val, temp_val);                                    \
+		else                                                                              \
+			SET_SIGNED(temp_cached_val, temp_val);                                    \
+	} while (0)
+
+#define FIND_EQUAL_INDEX(be_module_reg, type, idx, start, nb_elements)                            \
+	do {                                                                                      \
+		typeof(be_module_reg) *temp_be_module =                                       \
+			(typeof(be_module_reg) *)be_module_reg;                               \
+		typeof(idx) tmp_idx = (idx);                                                  \
+		typeof(nb_elements) tmp_nb_elements = (nb_elements);                          \
+		unsigned int start_idx = (unsigned int)(start);                                   \
+		*value = NOT_FOUND;                                                               \
+		for (unsigned int i = start_idx; i < tmp_nb_elements; i++) {                      \
+			if ((unsigned int)(tmp_idx) == i)                                         \
+				continue;                                                         \
+			if (memcmp(&temp_be_module[tmp_idx], &temp_be_module[i], sizeof(type)) == \
+			    0) {                                                                  \
+				*value = i;                                                       \
+				break;                                                            \
+			}                                                                         \
+		}                                                                                 \
+	} while (0)
+
+#define DO_COMPARE_INDEXS(be_module_reg, type, idx, cmp_idx)                                      \
+	do {                                                                                      \
+		typeof(be_module_reg) *temp_be_module = &(be_module_reg);                     \
+		typeof(idx) tmp_idx = (idx);                                                  \
+		typeof(cmp_idx) tmp_cmp_idx = (cmp_idx);                                      \
+		if ((unsigned int)(tmp_idx) != (unsigned int)(tmp_cmp_idx)) {                     \
+			(void)memcmp(temp_be_module + tmp_idx, &temp_be_module[tmp_cmp_idx],      \
+				     sizeof(type));                                               \
+		}                                                                                 \
+	} while (0)
+
+enum km_flm_if_select_e {
+	KM_FLM_IF_FIRST = 0,
+	KM_FLM_IF_SECOND = 1
+};
+
+#define FIELD_START_INDEX 100
+
 #define COMMON_FUNC_INFO_S                                                                        \
 	int ver;                                                                                  \
 	void *base;                                                                               \
 	unsigned int alloced_size;                                                                \
 	int debug
 
+struct common_func_s {
+	COMMON_FUNC_INFO_S;
+};
+
 struct cat_func_s {
 	COMMON_FUNC_INFO_S;
 	uint32_t nb_cat_funcs;
@@ -48,6 +152,104 @@ struct cat_func_s {
 		struct hw_mod_cat_v21_s v21;
 	};
 };
+enum hw_cat_e {
+	/*
+	 * functions initial CAT v18
+	 */
+	/* 00 */ HW_CAT_CFN_SET_ALL_DEFAULTS = 0,
+	/* 01 */ HW_CAT_CFN_PRESET_ALL,
+	/* 02 */ HW_CAT_CFN_COMPARE,
+	/* 03 */ HW_CAT_CFN_FIND,
+	/* 04 */ HW_CAT_CFN_COPY_FROM,
+	/* 05 */ HW_CAT_COT_PRESET_ALL,
+	/* 06 */ HW_CAT_COT_COMPARE,
+	/* 07 */ HW_CAT_COT_FIND,
+	/* 08 */ HW_CAT_COT_COPY_FROM,
+	/* fields */
+	/* 00 */ HW_CAT_CFN_ENABLE = FIELD_START_INDEX,
+	/* 01 */ HW_CAT_CFN_INV,
+	/* 02 */ HW_CAT_CFN_PTC_INV,
+	/* 03 */ HW_CAT_CFN_PTC_ISL,
+	/* 04 */ HW_CAT_CFN_PTC_CFP,
+	/* 05 */ HW_CAT_CFN_PTC_MAC,
+	/* 06 */ HW_CAT_CFN_PTC_L2,
+	/* 07 */ HW_CAT_CFN_PTC_VNTAG,
+	/* 08 */ HW_CAT_CFN_PTC_VLAN,
+	/* 09 */ HW_CAT_CFN_PTC_MPLS,
+	/* 10 */ HW_CAT_CFN_PTC_L3,
+	/* 11 */ HW_CAT_CFN_PTC_FRAG,
+	/* 12 */ HW_CAT_CFN_PTC_IP_PROT,
+	/* 13 */ HW_CAT_CFN_PTC_L4,
+	/* 14 */ HW_CAT_CFN_PTC_TUNNEL,
+	/* 15 */ HW_CAT_CFN_PTC_TNL_L2,
+	/* 16 */ HW_CAT_CFN_PTC_TNL_VLAN,
+	/* 17 */ HW_CAT_CFN_PTC_TNL_MPLS,
+	/* 18 */ HW_CAT_CFN_PTC_TNL_L3,
+	/* 19 */ HW_CAT_CFN_PTC_TNL_FRAG,
+	/* 20 */ HW_CAT_CFN_PTC_TNL_IP_PROT,
+	/* 21 */ HW_CAT_CFN_PTC_TNL_L4,
+	/* 22 */ HW_CAT_CFN_ERR_INV,
+	/* 23 */ HW_CAT_CFN_ERR_CV,
+	/* 24 */ HW_CAT_CFN_ERR_FCS,
+	/* 25 */ HW_CAT_CFN_ERR_TRUNC,
+	/* 26 */ HW_CAT_CFN_ERR_L3_CS,
+	/* 27 */ HW_CAT_CFN_ERR_L4_CS,
+	/* 28 */ HW_CAT_CFN_MAC_PORT,
+	/* 29 */ HW_CAT_CFN_PM_CMP,
+	/* 30 */ HW_CAT_CFN_PM_DCT,
+	/* 31 */ HW_CAT_CFN_PM_EXT_INV,
+	/* 32 */ HW_CAT_CFN_PM_CMB,
+	/* 33 */ HW_CAT_CFN_PM_AND_INV,
+	/* 34 */ HW_CAT_CFN_PM_OR_INV,
+	/* 35 */ HW_CAT_CFN_PM_INV,
+	/* 36 */ HW_CAT_CFN_LC,
+	/* 37 */ HW_CAT_CFN_LC_INV,
+	/* 38 */ HW_CAT_CFN_KM0_OR,
+	/* 39 */ HW_CAT_CFN_KM1_OR,
+	/* 40 */ HW_CAT_KCE_ENABLE_BM,
+	/* 41 */ HW_CAT_KCS_CATEGORY,
+	/* 42 */ HW_CAT_FTE_ENABLE_BM,
+	/* 43 */ HW_CAT_CTE_ENABLE_BM,
+	/* 44 */ HW_CAT_CTS_CAT_A,
+	/* 45 */ HW_CAT_CTS_CAT_B,
+	/* 46 */ HW_CAT_COT_COLOR,
+	/* 47 */ HW_CAT_COT_KM,
+	/* 48 */ HW_CAT_CCT_COLOR,
+	/* 49 */ HW_CAT_CCT_KM,
+	/* 50 */ HW_CAT_KCC_KEY,
+	/* 51 */ HW_CAT_KCC_CATEGORY,
+	/* 52 */ HW_CAT_KCC_ID,
+	/* 53 */ HW_CAT_EXO_DYN,
+	/* 54 */ HW_CAT_EXO_OFS,
+	/* 55 */ HW_CAT_RCK_DATA,
+	/* 56 */ HW_CAT_LEN_LOWER,
+	/* 57 */ HW_CAT_LEN_UPPER,
+	/* 58 */ HW_CAT_LEN_DYN1,
+	/* 59 */ HW_CAT_LEN_DYN2,
+	/* 60 */ HW_CAT_LEN_INV,
+	/* 61 */ HW_CAT_CFN_ERR_TNL_L3_CS,
+	/* 62 */ HW_CAT_CFN_ERR_TNL_L4_CS,
+	/* 63 */ HW_CAT_CFN_ERR_TTL_EXP,
+	/* 64 */ HW_CAT_CFN_ERR_TNL_TTL_EXP,
+};
+
+bool hw_mod_cat_present(struct flow_api_backend_s *be);
+int hw_mod_cat_alloc(struct flow_api_backend_s *be);
+void hw_mod_cat_free(struct flow_api_backend_s *be);
+int hw_mod_cat_reset(struct flow_api_backend_s *be);
+int hw_mod_cat_cfn_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_cfn_set(struct flow_api_backend_s *be, enum hw_cat_e field, int index, int word_off,
+	uint32_t value);
+
+int hw_mod_cat_cte_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_cts_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_cot_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_cct_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_kcc_flush(struct flow_api_backend_s *be, int start_idx, int count);
+
+int hw_mod_cat_exo_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_rck_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_len_flush(struct flow_api_backend_s *be, int start_idx, int count);
 
 struct km_func_s {
 	COMMON_FUNC_INFO_S;
@@ -279,6 +481,9 @@ struct flow_api_backend_s {
 	void *be_dev;
 	const struct flow_api_backend_ops *iface;
 
+	/* flow filter FPGA modules */
+	struct cat_func_s cat;
+
 	/* NIC attributes */
 	unsigned int num_phy_ports;
 	unsigned int num_rx_ports;
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 57d1ded2a7..3d394f9bad 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -49,6 +49,7 @@ sources = files(
         'nthw/flow_api/flow_kcc.c',
         'nthw/flow_api/flow_km.c',
         'nthw/flow_api/hw_mod/hw_mod_backend.c',
+        'nthw/flow_api/hw_mod/hw_mod_cat.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_csu.c',
         'nthw/flow_filter/flow_nthw_flm.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
index 4bab8983c9..3b1d7c5850 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -272,12 +272,27 @@ struct flow_nic_dev *flow_api_create(uint8_t adapter_no, const struct flow_api_b
 	if (init_resource_elements(ndev, RES_QUEUE, ndev->be.max_queues))
 		goto err_exit;
 
+	if (init_resource_elements(ndev, RES_CAT_CFN, ndev->be.cat.nb_cat_funcs))
+		goto err_exit;
+
 	if (init_resource_elements(ndev, RES_CAT_COT, ndev->be.max_categories))
 		goto err_exit;
 
+	if (init_resource_elements(ndev, RES_CAT_EXO, ndev->be.cat.nb_pm_ext))
+		goto err_exit;
+
+	if (init_resource_elements(ndev, RES_CAT_LEN, ndev->be.cat.nb_len))
+		goto err_exit;
+
+	if (init_resource_elements(ndev, RES_KM_FLOW_TYPE, ndev->be.cat.nb_flow_types))
+		goto err_exit;
+
 	if (init_resource_elements(ndev, RES_SLC_LR_RCP, ndev->be.max_categories))
 		goto err_exit;
 
+	if (init_resource_elements(ndev, RES_FLM_FLOW_TYPE, ndev->be.cat.nb_flow_types))
+		goto err_exit;
+
 	/* may need IPF, COR */
 
 	/* check all defined has been initialized */
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
index 5966dc6e8c..33fb4df126 100644
--- a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
@@ -5,6 +5,79 @@
 
 #include "hw_mod_backend.h"
 
+#include <stdlib.h>
+#include <string.h>
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+static const struct {
+	const char *name;
+	int (*allocate)(struct flow_api_backend_s *be);
+	void (*free)(struct flow_api_backend_s *be);
+	int (*reset)(struct flow_api_backend_s *be);
+	bool (*present)(struct flow_api_backend_s *be);
+} module[] = {
+	{ "CAT", hw_mod_cat_alloc, hw_mod_cat_free, hw_mod_cat_reset, hw_mod_cat_present },
+};
+#define MOD_COUNT (ARRAY_SIZE(module))
+
+void *callocate_mod(struct common_func_s *mod, int sets, ...)
+{
+#define MAX_SETS 38
+	void *base = NULL;
+	void **plist[MAX_SETS];
+	int len[MAX_SETS];
+	int offs[MAX_SETS];
+	unsigned int total_bytes = 0;
+	int cnt, elem_size;
+
+	assert(sets <= MAX_SETS);
+	assert(sets > 0);
+
+	va_list args;
+	va_start(args, sets);
+
+	for (int i = 0; i < sets; i++) {
+		plist[i] = va_arg(args, void *);
+		cnt = va_arg(args, int);
+		elem_size = va_arg(args, int);
+		offs[i] = EXTRA_INDEXES * elem_size;
+		len[i] = offs[i] + cnt * elem_size;
+		total_bytes += len[i];
+	}
+
+	if (total_bytes > 0) {
+		base = calloc(1, total_bytes);
+
+		if (base) {
+			char *p_b = (char *)base;
+
+			for (int i = 0; i < sets; i++) {
+				*plist[i] = (void *)((char *)p_b + offs[i]);
+				p_b += len[i];
+			}
+
+		} else {
+			NT_LOG(ERR, FILTER, "ERROR: module memory allocation failed\n");
+		}
+
+	} else {
+		NT_LOG(ERR, FILTER, "ERROR: module request to allocate 0 bytes of memory\n");
+	}
+
+	va_end(args);
+
+	mod->base = base;
+	mod->alloced_size = total_bytes;
+
+	return base;
+}
+
+void zero_module_cache(struct common_func_s *mod)
+{
+	memset(mod->base, 0, mod->alloced_size);
+}
+
 int flow_api_backend_init(struct flow_api_backend_s *dev,
 	const struct flow_api_backend_ops *iface,
 	void *be_dev)
@@ -17,12 +90,46 @@ int flow_api_backend_init(struct flow_api_backend_s *dev,
 	dev->max_categories = iface->get_nb_categories(be_dev);
 	dev->max_queues = iface->get_nb_queues(be_dev);
 
+	NT_LOG(DBG,
+		FILTER,
+		"*************** FLOW REGISTER MODULES AND INITIALIZE - SET ALL TO DEFAULT *****************\n");
+
+	/*
+	 * Create Cache and SW, version independent, NIC module representation
+	 */
+	for (unsigned int mod = 0; mod < MOD_COUNT; mod++) {
+		if (!module[mod].present(dev))
+			continue;
+
+		if (module[mod].allocate(dev) == 0 && module[mod].reset(dev) == 0) {
+			/* OK */
+			continue;
+		}
+
+		NT_LOG(ERR,
+			FILTER,
+			"ERROR: Initialization of NIC module failed : [ %s ]\n",
+			module[mod].name);
+		flow_api_backend_done(dev);
+		NT_LOG(ERR,
+			FILTER,
+			"*************** Failed to create Binary Flow API *******************\n");
+		NT_LOG(ERR,
+			FILTER,
+			"******** ERROR ERROR: Binary Flow API will not be available ********\n");
+		NT_LOG(ERR,
+			FILTER,
+			"********************************************************************\n");
+		return -1;
+	}
+
 	return 0;
 }
 
 int flow_api_backend_done(struct flow_api_backend_s *dev)
 {
-	(void)dev;
+	for (unsigned int mod = 0; mod < MOD_COUNT; mod++)
+		module[mod].free(dev);
 
 	return 0;
 }
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c
new file mode 100644
index 0000000000..0c1f37db2b
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c
@@ -0,0 +1,985 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hw_mod_backend.h"
+
+#define _MOD_ "CAT"
+#define _VER_ be->cat.ver
+
+static int hw_mod_cat_kce_flush(struct flow_api_backend_s *be, enum km_flm_if_select_e if_num,
+	int km_if_id, int start_idx, int count);
+static int hw_mod_cat_kcs_flush(struct flow_api_backend_s *be, enum km_flm_if_select_e if_num,
+	int km_if_id, int start_idx, int count);
+static int hw_mod_cat_fte_flush(struct flow_api_backend_s *be, enum km_flm_if_select_e if_num,
+	int km_if_id, int start_idx, int count);
+
+bool hw_mod_cat_present(struct flow_api_backend_s *be)
+{
+	return be->iface->get_cat_present(be->be_dev);
+}
+
+int hw_mod_cat_alloc(struct flow_api_backend_s *be)
+{
+	_VER_ = be->iface->get_cat_version(be->be_dev);
+	NT_LOG(DBG, FILTER, "CAT MODULE VERSION  %i.%i\n", VER_MAJOR(_VER_), VER_MINOR(_VER_));
+
+	int nb = be->iface->get_nb_cat_funcs(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(cat_funcs);
+
+	be->cat.nb_cat_funcs = (uint32_t)nb;
+
+	nb = be->iface->get_nb_km_flow_types(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(km_flow_types);
+
+	be->cat.nb_flow_types = (uint32_t)nb;
+
+	nb = be->iface->get_nb_pm_ext(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(pm_ext);
+
+	be->cat.nb_pm_ext = (uint32_t)nb;
+
+	nb = be->iface->get_nb_len(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(len);
+
+	be->cat.nb_len = (uint32_t)nb;
+
+	nb = be->iface->get_kcc_size(be->be_dev);
+
+	if (nb < 0)
+		return COUNT_ERROR(kcc_size);
+
+	be->cat.kcc_size = (uint32_t)nb;
+
+	nb = be->iface->get_kcc_banks(be->be_dev);
+
+	if (nb < 0)
+		return COUNT_ERROR(kcc_banks);
+
+	be->cat.kcc_banks = (uint32_t)nb;
+
+	nb = be->iface->get_nb_cat_km_if_cnt(be->be_dev);
+
+	if (nb < 0)
+		return COUNT_ERROR(km_if_count);
+
+	be->cat.km_if_count = (uint32_t)nb;
+
+	int idx = be->iface->get_nb_cat_km_if_m0(be->be_dev);
+	be->cat.km_if_m0 = idx;
+
+	idx = be->iface->get_nb_cat_km_if_m1(be->be_dev);
+	be->cat.km_if_m1 = idx;
+
+	if (be->cat.kcc_banks)
+		be->cat.kcc_records = be->cat.kcc_size / be->cat.kcc_banks;
+
+	else
+		be->cat.kcc_records = 0;
+
+	be->cat.kcc_id_bit_size = 10;
+
+	switch (_VER_) {
+	case 18:
+		be->cat.cts_num = 11;
+
+		if (!callocate_mod((struct common_func_s *)&be->cat, 12, &be->cat.v18.cfn,
+				be->cat.nb_cat_funcs, sizeof(struct cat_v18_cfn_s),
+				&be->cat.v18.kce, (be->cat.nb_cat_funcs / 8),
+				sizeof(struct cat_v18_kce_s), &be->cat.v18.kcs,
+				be->cat.nb_cat_funcs, sizeof(struct cat_v18_kcs_s),
+				&be->cat.v18.fte,
+				(be->cat.nb_cat_funcs / 8) * be->cat.nb_flow_types * 2,
+				sizeof(struct cat_v18_fte_s),
+
+				&be->cat.v18.cte, be->cat.nb_cat_funcs,
+				sizeof(struct cat_v18_cte_s), &be->cat.v18.cts,
+				be->cat.nb_cat_funcs * ((be->cat.cts_num + 1) / 2),
+				sizeof(struct cat_v18_cts_s), &be->cat.v18.cot,
+				be->max_categories, sizeof(struct cat_v18_cot_s),
+
+				&be->cat.v18.cct, be->max_categories * 4,
+				sizeof(struct cat_v18_cct_s), &be->cat.v18.exo,
+				be->cat.nb_pm_ext, sizeof(struct cat_v18_exo_s),
+				&be->cat.v18.rck, be->cat.nb_pm_ext * 64,
+				sizeof(struct cat_v18_rck_s), &be->cat.v18.len, be->cat.nb_len,
+				sizeof(struct cat_v18_len_s), &be->cat.v18.kcc_cam,
+				be->cat.kcc_size, sizeof(struct cat_v18_kcc_s)))
+			return -1;
+
+		break;
+
+	/* end case 18 */
+	case 21:
+		be->cat.cts_num = 11;
+
+		if (!callocate_mod((struct common_func_s *)&be->cat, 12, &be->cat.v21.cfn,
+				be->cat.nb_cat_funcs, sizeof(struct cat_v21_cfn_s),
+				&be->cat.v21.kce, (be->cat.nb_cat_funcs / 8),
+				sizeof(struct cat_v21_kce_s), &be->cat.v21.kcs,
+				be->cat.nb_cat_funcs, sizeof(struct cat_v21_kcs_s),
+				&be->cat.v21.fte,
+				(be->cat.nb_cat_funcs / 8) * be->cat.nb_flow_types * 4,
+				sizeof(struct cat_v21_fte_s),
+
+				&be->cat.v21.cte, be->cat.nb_cat_funcs,
+				sizeof(struct cat_v18_cte_s), &be->cat.v21.cts,
+				be->cat.nb_cat_funcs * ((be->cat.cts_num + 1) / 2),
+				sizeof(struct cat_v18_cts_s), &be->cat.v21.cot,
+				be->max_categories, sizeof(struct cat_v18_cot_s),
+
+				&be->cat.v21.cct, be->max_categories * 4,
+				sizeof(struct cat_v18_cct_s), &be->cat.v21.exo,
+				be->cat.nb_pm_ext, sizeof(struct cat_v18_exo_s),
+				&be->cat.v21.rck, be->cat.nb_pm_ext * 64,
+				sizeof(struct cat_v18_rck_s), &be->cat.v21.len, be->cat.nb_len,
+				sizeof(struct cat_v18_len_s), &be->cat.v21.kcc_cam,
+				be->cat.kcc_size, sizeof(struct cat_v18_kcc_s)))
+			return -1;
+
+		break;
+
+	/* end case 21 */
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+void hw_mod_cat_free(struct flow_api_backend_s *be)
+{
+	if (be->cat.base) {
+		free(be->cat.base);
+		be->cat.base = NULL;
+	}
+}
+
+static int cfn_reset(struct flow_api_backend_s *be, int i)
+{
+	int err = hw_mod_cat_cfn_set(be, HW_CAT_CFN_PRESET_ALL, i, 0, 0);
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_ISL, i, 0,
+		0xffffffff);	/* accept both ISL or not ISL */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_CFP, i, 0,
+		0xffffffff);	/* accept both CFP or not CFP */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_MAC, i, 0, 0xffffffff);	/* accept all MACs */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_L2, i, 0, 0xffffffff);	/* accept all L2 prot */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_VNTAG, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_VLAN, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_MPLS, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_L3, i, 0, 0xffffffff);	/* accept all L3 prot */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_FRAG, i, 0, 0xffffffff);	/* accept all fragments */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_IP_PROT, i, 0,
+		0xffffffff);	/* IP prot check disabled */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_L4, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TUNNEL, i, 0, 0xffffffff);/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_L2, i, 0, 0xffffffff);/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_VLAN, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_MPLS, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_L3, i, 0, 0xffffffff);/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_FRAG, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_IP_PROT, i, 0,
+		0xffffffff);	/* inner IP prot check disabled */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_L4, i, 0, 0xffffffff);/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_CV, i, 0, 3);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_FCS, i, 0, 3);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TRUNC, i, 0,
+		0xffffffff);	/* accept all truncations */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_L3_CS, i, 0, 3);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_L4_CS, i, 0, 3);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PM_OR_INV, i, 0, 1);
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_LC_INV, i, 0, 1);
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_KM0_OR, i, 0, 0xffffffff);	/* or all */
+
+	if (_VER_ >= 21) {
+		hw_mod_cat_cfn_set(be, HW_CAT_CFN_KM1_OR, i, 0, 0xffffffff);	/* or all */
+		hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TNL_L3_CS, i, 0, 0xffffffff);	/* or all */
+		hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TNL_L4_CS, i, 0, 0xffffffff);	/* or all */
+		hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TTL_EXP, i, 0, 0xffffffff);	/* or all */
+		hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TNL_TTL_EXP, i, 0, 0xffffffff);	/* or all */
+	}
+
+	return err;
+}
+
+int hw_mod_cat_reset(struct flow_api_backend_s *be)
+{
+	/* Zero entire cache area */
+	zero_module_cache((struct common_func_s *)(&be->cat));
+
+	NT_LOG(DBG, FILTER, "INIT CAT CFN\n");
+
+	if (hw_mod_cat_cfn_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	if (_VER_ <= 18) {
+		NT_LOG(DBG, FILTER, "INIT CAT KCE\n");
+
+		if (hw_mod_cat_kce_flush(be, KM_FLM_IF_FIRST, 0, 0, ALL_ENTRIES))
+			return -1;
+
+		NT_LOG(DBG, FILTER, "INIT CAT KCS\n");
+
+		if (hw_mod_cat_kcs_flush(be, KM_FLM_IF_FIRST, 0, 0, ALL_ENTRIES))
+			return -1;
+
+		NT_LOG(DBG, FILTER, "INIT CAT FTE\n");
+
+		if (hw_mod_cat_fte_flush(be, KM_FLM_IF_FIRST, 0, 0, ALL_ENTRIES))
+			return -1;
+
+	} else {
+		NT_LOG(DBG, FILTER, "INIT CAT KCE 0\n");
+
+		if (hw_mod_cat_kce_flush(be, KM_FLM_IF_FIRST, be->cat.km_if_m0, 0, ALL_ENTRIES))
+			return -1;
+
+		NT_LOG(DBG, FILTER, "INIT CAT KCS 0\n");
+
+		if (hw_mod_cat_kcs_flush(be, KM_FLM_IF_FIRST, be->cat.km_if_m0, 0, ALL_ENTRIES))
+			return -1;
+
+		NT_LOG(DBG, FILTER, "INIT CAT FTE 0\n");
+
+		if (hw_mod_cat_fte_flush(be, KM_FLM_IF_FIRST, be->cat.km_if_m0, 0, ALL_ENTRIES))
+			return -1;
+
+		if (be->cat.km_if_count > 1) {
+			NT_LOG(DBG, FILTER, "INIT CAT KCE 1\n");
+
+			if (hw_mod_cat_kce_flush(be, KM_FLM_IF_SECOND, be->cat.km_if_m1, 0,
+					ALL_ENTRIES))
+				return -1;
+
+			NT_LOG(DBG, FILTER, "INIT CAT KCS 1\n");
+
+			if (hw_mod_cat_kcs_flush(be, KM_FLM_IF_SECOND, be->cat.km_if_m1, 0,
+					ALL_ENTRIES))
+				return -1;
+
+			NT_LOG(DBG, FILTER, "INIT CAT FTE 1\n");
+
+			if (hw_mod_cat_fte_flush(be, KM_FLM_IF_SECOND, be->cat.km_if_m1, 0,
+					ALL_ENTRIES))
+				return -1;
+		}
+	}
+
+	NT_LOG(DBG, FILTER, "INIT CAT CTE\n");
+
+	if (hw_mod_cat_cte_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	NT_LOG(DBG, FILTER, "INIT CAT CTS\n");
+
+	if (hw_mod_cat_cts_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	NT_LOG(DBG, FILTER, "INIT CAT COT\n");
+
+	if (hw_mod_cat_cot_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	NT_LOG(DBG, FILTER, "INIT CAT CCT\n");
+
+	if (hw_mod_cat_cct_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	NT_LOG(DBG, FILTER, "INIT CAT EXO\n");
+
+	if (hw_mod_cat_exo_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	NT_LOG(DBG, FILTER, "INIT CAT RCK\n");
+
+	if (hw_mod_cat_rck_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	NT_LOG(DBG, FILTER, "INIT CAT LEN\n");
+
+	if (hw_mod_cat_len_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	if (be->cat.kcc_size) {
+		NT_LOG(DBG, FILTER, "INIT CAT KCC\n");
+
+		if (hw_mod_cat_kcc_flush(be, 0, ALL_ENTRIES))
+			return -1;
+	}
+
+	return 0;
+}
+
+int hw_mod_cat_cfn_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	switch (count) {
+	case ALL_ENTRIES:
+		if (start_idx != 0)
+			return INDEX_TOO_LARGE;
+
+		return be->iface->cat_cfn_flush(be->be_dev, &be->cat, start_idx,
+				be->cat.nb_cat_funcs);
+
+	default:
+		if ((unsigned int)(start_idx + count) > be->cat.nb_cat_funcs)
+			return INDEX_TOO_LARGE;
+
+		return be->iface->cat_cfn_flush(be->be_dev, &be->cat, start_idx, count);
+	}
+}
+
+static int hw_mod_cat_cfn_mod(struct flow_api_backend_s *be, enum hw_cat_e field, int index,
+	int word_off, uint32_t *value, int get)
+{
+	if ((unsigned int)index >= be->cat.nb_cat_funcs)
+		return INDEX_TOO_LARGE;
+
+	switch (_VER_) {
+	case 18:
+		switch (field) {
+		case HW_CAT_CFN_SET_ALL_DEFAULTS:
+			if (get)
+				return UNSUP_FIELD;
+
+			return cfn_reset(be, index);
+
+		case HW_CAT_CFN_PRESET_ALL:
+			if (get)
+				return UNSUP_FIELD;
+
+			memset(&be->cat.v18.cfn[index], (uint8_t)*value,
+				sizeof(struct cat_v18_cfn_s));
+			break;
+
+		case HW_CAT_CFN_COMPARE:
+			if (!get)
+				return UNSUP_FIELD;
+
+			if ((unsigned int)word_off >= be->cat.nb_cat_funcs)
+				return INDEX_TOO_LARGE;
+
+			DO_COMPARE_INDEXS(be->cat.v18.cfn, struct cat_v18_cfn_s, index, word_off);
+			break;
+
+		case HW_CAT_CFN_FIND:
+			if (!get)
+				return UNSUP_FIELD;
+
+			if ((unsigned int)word_off >= be->cat.nb_cat_funcs)
+				return INDEX_TOO_LARGE;
+
+			FIND_EQUAL_INDEX(be->cat.v18.cfn, struct cat_v18_cfn_s, index, word_off,
+				be->cat.nb_cat_funcs);
+			break;
+
+		case HW_CAT_CFN_ENABLE:
+			GET_SET(be->cat.v18.cfn[index].enable, value);
+			break;
+
+		case HW_CAT_CFN_INV:
+			GET_SET(be->cat.v18.cfn[index].inv, value);
+			break;
+
+		case HW_CAT_CFN_PTC_INV:
+			GET_SET(be->cat.v18.cfn[index].ptc_inv, value);
+			break;
+
+		case HW_CAT_CFN_PTC_ISL:
+			GET_SET(be->cat.v18.cfn[index].ptc_isl, value);
+			break;
+
+		case HW_CAT_CFN_PTC_CFP:
+			GET_SET(be->cat.v18.cfn[index].ptc_cfp, value);
+			break;
+
+		case HW_CAT_CFN_PTC_MAC:
+			GET_SET(be->cat.v18.cfn[index].ptc_mac, value);
+			break;
+
+		case HW_CAT_CFN_PTC_L2:
+			GET_SET(be->cat.v18.cfn[index].ptc_l2, value);
+			break;
+
+		case HW_CAT_CFN_PTC_VNTAG:
+			GET_SET(be->cat.v18.cfn[index].ptc_vntag, value);
+			break;
+
+		case HW_CAT_CFN_PTC_VLAN:
+			GET_SET(be->cat.v18.cfn[index].ptc_vlan, value);
+			break;
+
+		case HW_CAT_CFN_PTC_MPLS:
+			GET_SET(be->cat.v18.cfn[index].ptc_mpls, value);
+			break;
+
+		case HW_CAT_CFN_PTC_L3:
+			GET_SET(be->cat.v18.cfn[index].ptc_l3, value);
+			break;
+
+		case HW_CAT_CFN_PTC_FRAG:
+			GET_SET(be->cat.v18.cfn[index].ptc_frag, value);
+			break;
+
+		case HW_CAT_CFN_PTC_IP_PROT:
+			GET_SET(be->cat.v18.cfn[index].ptc_ip_prot, value);
+			break;
+
+		case HW_CAT_CFN_PTC_L4:
+			GET_SET(be->cat.v18.cfn[index].ptc_l4, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TUNNEL:
+			GET_SET(be->cat.v18.cfn[index].ptc_tunnel, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_L2:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_l2, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_VLAN:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_vlan, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_MPLS:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_mpls, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_L3:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_l3, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_FRAG:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_frag, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_IP_PROT:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_ip_prot, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_L4:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_l4, value);
+			break;
+
+		case HW_CAT_CFN_ERR_INV:
+			GET_SET(be->cat.v18.cfn[index].err_inv, value);
+			break;
+
+		case HW_CAT_CFN_ERR_CV:
+			GET_SET(be->cat.v18.cfn[index].err_cv, value);
+			break;
+
+		case HW_CAT_CFN_ERR_FCS:
+			GET_SET(be->cat.v18.cfn[index].err_fcs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_TRUNC:
+			GET_SET(be->cat.v18.cfn[index].err_trunc, value);
+			break;
+
+		case HW_CAT_CFN_ERR_L3_CS:
+			GET_SET(be->cat.v18.cfn[index].err_l3_cs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_L4_CS:
+			GET_SET(be->cat.v18.cfn[index].err_l4_cs, value);
+			break;
+
+		case HW_CAT_CFN_MAC_PORT:
+			GET_SET(be->cat.v18.cfn[index].mac_port, value);
+			break;
+
+		case HW_CAT_CFN_PM_CMP:
+			if (word_off > 1)
+				return WORD_OFF_TOO_LARGE;
+
+			GET_SET(be->cat.v18.cfn[index].pm_cmp[word_off], value);
+			break;
+
+		case HW_CAT_CFN_PM_DCT:
+			GET_SET(be->cat.v18.cfn[index].pm_dct, value);
+			break;
+
+		case HW_CAT_CFN_PM_EXT_INV:
+			GET_SET(be->cat.v18.cfn[index].pm_ext_inv, value);
+			break;
+
+		case HW_CAT_CFN_PM_CMB:
+			GET_SET(be->cat.v18.cfn[index].pm_cmb, value);
+			break;
+
+		case HW_CAT_CFN_PM_AND_INV:
+			GET_SET(be->cat.v18.cfn[index].pm_and_inv, value);
+			break;
+
+		case HW_CAT_CFN_PM_OR_INV:
+			GET_SET(be->cat.v18.cfn[index].pm_or_inv, value);
+			break;
+
+		case HW_CAT_CFN_PM_INV:
+			GET_SET(be->cat.v18.cfn[index].pm_inv, value);
+			break;
+
+		case HW_CAT_CFN_LC:
+			GET_SET(be->cat.v18.cfn[index].lc, value);
+			break;
+
+		case HW_CAT_CFN_LC_INV:
+			GET_SET(be->cat.v18.cfn[index].lc_inv, value);
+			break;
+
+		case HW_CAT_CFN_KM0_OR:
+			GET_SET(be->cat.v18.cfn[index].km_or, value);
+			break;
+
+		default:
+			return UNSUP_FIELD;
+		}
+
+		break;
+
+	/* end case 18 */
+	case 21:
+		switch (field) {
+		case HW_CAT_CFN_SET_ALL_DEFAULTS:
+			if (get)
+				return UNSUP_FIELD;
+
+			return cfn_reset(be, index);
+
+		case HW_CAT_CFN_PRESET_ALL:
+			if (get)
+				return UNSUP_FIELD;
+
+			memset(&be->cat.v21.cfn[index], (uint8_t)*value,
+				sizeof(struct cat_v21_cfn_s));
+			break;
+
+		case HW_CAT_CFN_COMPARE:
+			if (!get)
+				return UNSUP_FIELD;
+
+			if ((unsigned int)word_off >= be->cat.nb_cat_funcs)
+				return INDEX_TOO_LARGE;
+
+			DO_COMPARE_INDEXS(be->cat.v21.cfn, struct cat_v21_cfn_s, index, word_off);
+			break;
+
+		case HW_CAT_CFN_FIND:
+			if (!get)
+				return UNSUP_FIELD;
+
+			if ((unsigned int)word_off >= be->cat.nb_cat_funcs)
+				return INDEX_TOO_LARGE;
+
+			FIND_EQUAL_INDEX(be->cat.v21.cfn, struct cat_v21_cfn_s, index, word_off,
+				be->cat.nb_cat_funcs);
+			break;
+
+		case HW_CAT_CFN_COPY_FROM:
+			if (get)
+				return UNSUP_FIELD;
+
+			memcpy(&be->cat.v21.cfn[index], &be->cat.v21.cfn[*value],
+				sizeof(struct cat_v21_cfn_s));
+			break;
+
+		case HW_CAT_CFN_ENABLE:
+			GET_SET(be->cat.v21.cfn[index].enable, value);
+			break;
+
+		case HW_CAT_CFN_INV:
+			GET_SET(be->cat.v21.cfn[index].inv, value);
+			break;
+
+		case HW_CAT_CFN_PTC_INV:
+			GET_SET(be->cat.v21.cfn[index].ptc_inv, value);
+			break;
+
+		case HW_CAT_CFN_PTC_ISL:
+			GET_SET(be->cat.v21.cfn[index].ptc_isl, value);
+			break;
+
+		case HW_CAT_CFN_PTC_CFP:
+			GET_SET(be->cat.v21.cfn[index].ptc_cfp, value);
+			break;
+
+		case HW_CAT_CFN_PTC_MAC:
+			GET_SET(be->cat.v21.cfn[index].ptc_mac, value);
+			break;
+
+		case HW_CAT_CFN_PTC_L2:
+			GET_SET(be->cat.v21.cfn[index].ptc_l2, value);
+			break;
+
+		case HW_CAT_CFN_PTC_VNTAG:
+			GET_SET(be->cat.v21.cfn[index].ptc_vntag, value);
+			break;
+
+		case HW_CAT_CFN_PTC_VLAN:
+			GET_SET(be->cat.v21.cfn[index].ptc_vlan, value);
+			break;
+
+		case HW_CAT_CFN_PTC_MPLS:
+			GET_SET(be->cat.v21.cfn[index].ptc_mpls, value);
+			break;
+
+		case HW_CAT_CFN_PTC_L3:
+			GET_SET(be->cat.v21.cfn[index].ptc_l3, value);
+			break;
+
+		case HW_CAT_CFN_PTC_FRAG:
+			GET_SET(be->cat.v21.cfn[index].ptc_frag, value);
+			break;
+
+		case HW_CAT_CFN_PTC_IP_PROT:
+			GET_SET(be->cat.v21.cfn[index].ptc_ip_prot, value);
+			break;
+
+		case HW_CAT_CFN_PTC_L4:
+			GET_SET(be->cat.v21.cfn[index].ptc_l4, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TUNNEL:
+			GET_SET(be->cat.v21.cfn[index].ptc_tunnel, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_L2:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_l2, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_VLAN:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_vlan, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_MPLS:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_mpls, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_L3:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_l3, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_FRAG:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_frag, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_IP_PROT:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_ip_prot, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_L4:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_l4, value);
+			break;
+
+		case HW_CAT_CFN_ERR_INV:
+			GET_SET(be->cat.v21.cfn[index].err_inv, value);
+			break;
+
+		case HW_CAT_CFN_ERR_CV:
+			GET_SET(be->cat.v21.cfn[index].err_cv, value);
+			break;
+
+		case HW_CAT_CFN_ERR_FCS:
+			GET_SET(be->cat.v21.cfn[index].err_fcs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_TRUNC:
+			GET_SET(be->cat.v21.cfn[index].err_trunc, value);
+			break;
+
+		case HW_CAT_CFN_ERR_L3_CS:
+			GET_SET(be->cat.v21.cfn[index].err_l3_cs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_L4_CS:
+			GET_SET(be->cat.v21.cfn[index].err_l4_cs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_TNL_L3_CS:
+			GET_SET(be->cat.v21.cfn[index].err_tnl_l3_cs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_TNL_L4_CS:
+			GET_SET(be->cat.v21.cfn[index].err_tnl_l4_cs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_TTL_EXP:
+			GET_SET(be->cat.v21.cfn[index].err_ttl_exp, value);
+			break;
+
+		case HW_CAT_CFN_ERR_TNL_TTL_EXP:
+			GET_SET(be->cat.v21.cfn[index].err_tnl_ttl_exp, value);
+			break;
+
+		case HW_CAT_CFN_MAC_PORT:
+			GET_SET(be->cat.v21.cfn[index].mac_port, value);
+			break;
+
+		case HW_CAT_CFN_PM_CMP:
+			if (word_off > 1)
+				return WORD_OFF_TOO_LARGE;
+
+			GET_SET(be->cat.v21.cfn[index].pm_cmp[word_off], value);
+			break;
+
+		case HW_CAT_CFN_PM_DCT:
+			GET_SET(be->cat.v21.cfn[index].pm_dct, value);
+			break;
+
+		case HW_CAT_CFN_PM_EXT_INV:
+			GET_SET(be->cat.v21.cfn[index].pm_ext_inv, value);
+			break;
+
+		case HW_CAT_CFN_PM_CMB:
+			GET_SET(be->cat.v21.cfn[index].pm_cmb, value);
+			break;
+
+		case HW_CAT_CFN_PM_AND_INV:
+			GET_SET(be->cat.v21.cfn[index].pm_and_inv, value);
+			break;
+
+		case HW_CAT_CFN_PM_OR_INV:
+			GET_SET(be->cat.v21.cfn[index].pm_or_inv, value);
+			break;
+
+		case HW_CAT_CFN_PM_INV:
+			GET_SET(be->cat.v21.cfn[index].pm_inv, value);
+			break;
+
+		case HW_CAT_CFN_LC:
+			GET_SET(be->cat.v21.cfn[index].lc, value);
+			break;
+
+		case HW_CAT_CFN_LC_INV:
+			GET_SET(be->cat.v21.cfn[index].lc_inv, value);
+			break;
+
+		case HW_CAT_CFN_KM0_OR:
+			GET_SET(be->cat.v21.cfn[index].km0_or, value);
+			break;
+
+		case HW_CAT_CFN_KM1_OR:
+			GET_SET(be->cat.v21.cfn[index].km1_or, value);
+			break;
+
+		default:
+			return UNSUP_FIELD;
+		}
+
+		break;
+
+	/* end case 21 */
+
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+int hw_mod_cat_cfn_set(struct flow_api_backend_s *be, enum hw_cat_e field, int index, int word_off,
+	uint32_t value)
+{
+	return hw_mod_cat_cfn_mod(be, field, index, word_off, &value, 0);
+}
+
+static inline int find_km_flm_module_interface_index(struct flow_api_backend_s *be,
+	enum km_flm_if_select_e if_num, int km_if_id)
+{
+	int km_if_idx;
+
+	if (_VER_ == 18) {
+		km_if_idx = 0;
+
+	} else {
+		if (if_num == KM_FLM_IF_SECOND)
+			if (be->cat.km_if_m1 == km_if_id)
+				km_if_idx = 1;
+
+			else
+				return UNSUP_FIELD;
+
+		else if (be->cat.km_if_m0 == km_if_id)
+			km_if_idx = 0;
+
+		else if (be->cat.km_if_m1 == km_if_id)
+			km_if_idx = 1;
+
+		else
+			return UNSUP_FIELD;
+	}
+
+	return km_if_idx;
+}
+
+/*
+ * KCE
+ */
+
+static int hw_mod_cat_kce_flush(struct flow_api_backend_s *be, enum km_flm_if_select_e if_num,
+	int km_if_id, int start_idx, int count)
+{
+	/* writes 8 bits - one for each cfn - at a time */
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_cat_funcs / 8;
+
+	if ((unsigned int)(start_idx + count) > (be->cat.nb_cat_funcs / 8))
+		return INDEX_TOO_LARGE;
+
+	/* find KM module */
+	int km_if_idx = find_km_flm_module_interface_index(be, if_num, km_if_id);
+
+	if (km_if_idx < 0)
+		return km_if_idx;
+
+	return be->iface->cat_kce_flush(be->be_dev, &be->cat, km_if_idx, start_idx, count);
+}
+
+/*
+ * KCS
+ */
+static int hw_mod_cat_kcs_flush(struct flow_api_backend_s *be, enum km_flm_if_select_e if_num,
+	int km_if_id, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_cat_funcs;
+
+	if ((unsigned int)(start_idx + count) > be->cat.nb_cat_funcs)
+		return INDEX_TOO_LARGE;
+
+	/* find KM module */
+	int km_if_idx = find_km_flm_module_interface_index(be, if_num, km_if_id);
+
+	if (km_if_idx < 0)
+		return km_if_idx;
+
+	return be->iface->cat_kcs_flush(be->be_dev, &be->cat, km_if_idx, start_idx, count);
+}
+
+/*
+ * FTE
+ */
+static int hw_mod_cat_fte_flush(struct flow_api_backend_s *be, enum km_flm_if_select_e if_num,
+	int km_if_id, int start_idx, int count)
+{
+	const uint32_t key_cnt = (_VER_ >= 20) ? 4 : 2;
+
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_cat_funcs / 8 * be->cat.nb_flow_types * key_cnt;
+
+	if ((unsigned int)(start_idx + count) >
+		(be->cat.nb_cat_funcs / 8 * be->cat.nb_flow_types * key_cnt)) {
+		return INDEX_TOO_LARGE;
+	}
+
+	/* find KM module */
+	int km_if_idx = find_km_flm_module_interface_index(be, if_num, km_if_id);
+
+	if (km_if_idx < 0)
+		return km_if_idx;
+
+	return be->iface->cat_fte_flush(be->be_dev, &be->cat, km_if_idx, start_idx, count);
+}
+
+int hw_mod_cat_cte_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_cat_funcs;
+
+	if ((unsigned int)(start_idx + count) > be->cat.nb_cat_funcs)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_cte_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_cts_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	int addr_size = (_VER_ < 15) ? 8 : ((be->cat.cts_num + 1) / 2);
+
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_cat_funcs * addr_size;
+
+	if ((unsigned int)(start_idx + count) > (be->cat.nb_cat_funcs * addr_size))
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_cts_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_cot_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->max_categories;
+
+	if ((unsigned int)(start_idx + count) > be->max_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_cot_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_cct_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_cat_funcs * 4;
+
+	if ((unsigned int)(start_idx + count) > be->cat.nb_cat_funcs * 4)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_cct_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_kcc_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.kcc_size;
+
+	if ((unsigned int)(start_idx + count) > be->cat.kcc_size)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_kcc_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_exo_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_pm_ext;
+
+	if ((unsigned int)(start_idx + count) > be->cat.nb_pm_ext)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_exo_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_rck_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_pm_ext * 64;
+
+	if ((unsigned int)(start_idx + count) > (be->cat.nb_pm_ext * 64))
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_rck_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_len_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_len;
+
+	if ((unsigned int)(start_idx + count) > be->cat.nb_len)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_len_flush(be->be_dev, &be->cat, start_idx, count);
+}
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
index cbebcff541..4efd5aa2f8 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
@@ -9,6 +9,267 @@
 
 #include "nthw_register.h"
 
+static nthw_fpga_field_init_s cat_cct_ctrl_fields[] = {
+	{ CAT_CCT_CTRL_ADR, 8, 0, 0x0000 },
+	{ CAT_CCT_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cct_data_fields[] = {
+	{ CAT_CCT_DATA_COLOR, 32, 0, 0x0000 },
+	{ CAT_CCT_DATA_KM, 4, 32, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cfn_ctrl_fields[] = {
+	{ CAT_CFN_CTRL_ADR, 6, 0, 0x0000 },
+	{ CAT_CFN_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cfn_data_fields[] = {
+	{ CAT_CFN_DATA_ENABLE, 1, 0, 0x0000 },
+	{ CAT_CFN_DATA_ERR_CV, 2, 99, 0x0000 },
+	{ CAT_CFN_DATA_ERR_FCS, 2, 101, 0x0000 },
+	{ CAT_CFN_DATA_ERR_INV, 1, 98, 0x0000 },
+	{ CAT_CFN_DATA_ERR_L3_CS, 2, 105, 0x0000 },
+	{ CAT_CFN_DATA_ERR_L4_CS, 2, 107, 0x0000 },
+	{ CAT_CFN_DATA_ERR_TNL_L3_CS, 2, 109, 0x0000 },
+	{ CAT_CFN_DATA_ERR_TNL_L4_CS, 2, 111, 0x0000 },
+	{ CAT_CFN_DATA_ERR_TNL_TTL_EXP, 2, 115, 0x0000 },
+	{ CAT_CFN_DATA_ERR_TRUNC, 2, 103, 0x0000 },
+	{ CAT_CFN_DATA_ERR_TTL_EXP, 2, 113, 0x0000 },
+	{ CAT_CFN_DATA_INV, 1, 1, 0x0000 },
+	{ CAT_CFN_DATA_KM0_OR, 3, 173, 0x0000 },
+	{ CAT_CFN_DATA_KM1_OR, 3, 176, 0x0000 },
+	{ CAT_CFN_DATA_LC, 8, 164, 0x0000 },
+	{ CAT_CFN_DATA_LC_INV, 1, 172, 0x0000 },
+	{ CAT_CFN_DATA_MAC_PORT, 2, 117, 0x0000 },
+	{ CAT_CFN_DATA_PM_AND_INV, 1, 161, 0x0000 },
+	{ CAT_CFN_DATA_PM_CMB, 4, 157, 0x0000 },
+	{ CAT_CFN_DATA_PM_CMP, 32, 119, 0x0000 },
+	{ CAT_CFN_DATA_PM_DCT, 2, 151, 0x0000 },
+	{ CAT_CFN_DATA_PM_EXT_INV, 4, 153, 0x0000 },
+	{ CAT_CFN_DATA_PM_INV, 1, 163, 0x0000 },
+	{ CAT_CFN_DATA_PM_OR_INV, 1, 162, 0x0000 },
+	{ CAT_CFN_DATA_PTC_CFP, 2, 5, 0x0000 },
+	{ CAT_CFN_DATA_PTC_FRAG, 4, 36, 0x0000 },
+	{ CAT_CFN_DATA_PTC_INV, 1, 2, 0x0000 },
+	{ CAT_CFN_DATA_PTC_IP_PROT, 8, 40, 0x0000 },
+	{ CAT_CFN_DATA_PTC_ISL, 2, 3, 0x0000 },
+	{ CAT_CFN_DATA_PTC_L2, 7, 12, 0x0000 },
+	{ CAT_CFN_DATA_PTC_L3, 3, 33, 0x0000 },
+	{ CAT_CFN_DATA_PTC_L4, 5, 48, 0x0000 },
+	{ CAT_CFN_DATA_PTC_MAC, 5, 7, 0x0000 },
+	{ CAT_CFN_DATA_PTC_MPLS, 8, 25, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_FRAG, 4, 81, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_IP_PROT, 8, 85, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_L2, 2, 64, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_L3, 3, 78, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_L4, 5, 93, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_MPLS, 8, 70, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_VLAN, 4, 66, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TUNNEL, 11, 53, 0x0000 },
+	{ CAT_CFN_DATA_PTC_VLAN, 4, 21, 0x0000 },
+	{ CAT_CFN_DATA_PTC_VNTAG, 2, 19, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cot_ctrl_fields[] = {
+	{ CAT_COT_CTRL_ADR, 6, 0, 0x0000 },
+	{ CAT_COT_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cot_data_fields[] = {
+	{ CAT_COT_DATA_COLOR, 32, 0, 0x0000 },
+	{ CAT_COT_DATA_KM, 4, 32, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cte_ctrl_fields[] = {
+	{ CAT_CTE_CTRL_ADR, 6, 0, 0x0000 },
+	{ CAT_CTE_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cte_data_fields[] = {
+	{ CAT_CTE_DATA_COL_ENABLE, 1, 0, 0x0000 }, { CAT_CTE_DATA_COR_ENABLE, 1, 1, 0x0000 },
+	{ CAT_CTE_DATA_EPP_ENABLE, 1, 9, 0x0000 }, { CAT_CTE_DATA_HSH_ENABLE, 1, 2, 0x0000 },
+	{ CAT_CTE_DATA_HST_ENABLE, 1, 8, 0x0000 }, { CAT_CTE_DATA_IPF_ENABLE, 1, 4, 0x0000 },
+	{ CAT_CTE_DATA_MSK_ENABLE, 1, 7, 0x0000 }, { CAT_CTE_DATA_PDB_ENABLE, 1, 6, 0x0000 },
+	{ CAT_CTE_DATA_QSL_ENABLE, 1, 3, 0x0000 }, { CAT_CTE_DATA_SLC_ENABLE, 1, 5, 0x0000 },
+	{ CAT_CTE_DATA_TPE_ENABLE, 1, 10, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cts_ctrl_fields[] = {
+	{ CAT_CTS_CTRL_ADR, 9, 0, 0x0000 },
+	{ CAT_CTS_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cts_data_fields[] = {
+	{ CAT_CTS_DATA_CAT_A, 6, 0, 0x0000 },
+	{ CAT_CTS_DATA_CAT_B, 6, 6, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_dct_ctrl_fields[] = {
+	{ CAT_DCT_CTRL_ADR, 13, 0, 0x0000 },
+	{ CAT_DCT_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_dct_data_fields[] = {
+	{ CAT_DCT_DATA_RES, 16, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_dct_sel_fields[] = {
+	{ CAT_DCT_SEL_LU, 2, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_exo_ctrl_fields[] = {
+	{ CAT_EXO_CTRL_ADR, 2, 0, 0x0000 },
+	{ CAT_EXO_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_exo_data_fields[] = {
+	{ CAT_EXO_DATA_DYN, 5, 0, 0x0000 },
+	{ CAT_EXO_DATA_OFS, 11, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_fte0_ctrl_fields[] = {
+	{ CAT_FTE0_CTRL_ADR, 9, 0, 0x0000 },
+	{ CAT_FTE0_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_fte0_data_fields[] = {
+	{ CAT_FTE0_DATA_ENABLE, 8, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_fte1_ctrl_fields[] = {
+	{ CAT_FTE1_CTRL_ADR, 9, 0, 0x0000 },
+	{ CAT_FTE1_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_fte1_data_fields[] = {
+	{ CAT_FTE1_DATA_ENABLE, 8, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_join_fields[] = {
+	{ CAT_JOIN_J1, 2, 0, 0x0000 },
+	{ CAT_JOIN_J2, 1, 8, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kcc_ctrl_fields[] = {
+	{ CAT_KCC_CTRL_ADR, 11, 0, 0x0000 },
+	{ CAT_KCC_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kcc_data_fields[] = {
+	{ CAT_KCC_DATA_CATEGORY, 8, 64, 0x0000 },
+	{ CAT_KCC_DATA_ID, 12, 72, 0x0000 },
+	{ CAT_KCC_DATA_KEY, 64, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kce0_ctrl_fields[] = {
+	{ CAT_KCE0_CTRL_ADR, 3, 0, 0x0000 },
+	{ CAT_KCE0_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kce0_data_fields[] = {
+	{ CAT_KCE0_DATA_ENABLE, 8, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kce1_ctrl_fields[] = {
+	{ CAT_KCE1_CTRL_ADR, 3, 0, 0x0000 },
+	{ CAT_KCE1_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kce1_data_fields[] = {
+	{ CAT_KCE1_DATA_ENABLE, 8, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kcs0_ctrl_fields[] = {
+	{ CAT_KCS0_CTRL_ADR, 6, 0, 0x0000 },
+	{ CAT_KCS0_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kcs0_data_fields[] = {
+	{ CAT_KCS0_DATA_CATEGORY, 6, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kcs1_ctrl_fields[] = {
+	{ CAT_KCS1_CTRL_ADR, 6, 0, 0x0000 },
+	{ CAT_KCS1_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kcs1_data_fields[] = {
+	{ CAT_KCS1_DATA_CATEGORY, 6, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_len_ctrl_fields[] = {
+	{ CAT_LEN_CTRL_ADR, 3, 0, 0x0000 },
+	{ CAT_LEN_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_len_data_fields[] = {
+	{ CAT_LEN_DATA_DYN1, 5, 28, 0x0000 }, { CAT_LEN_DATA_DYN2, 5, 33, 0x0000 },
+	{ CAT_LEN_DATA_INV, 1, 38, 0x0000 }, { CAT_LEN_DATA_LOWER, 14, 0, 0x0000 },
+	{ CAT_LEN_DATA_UPPER, 14, 14, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_rck_ctrl_fields[] = {
+	{ CAT_RCK_CTRL_ADR, 8, 0, 0x0000 },
+	{ CAT_RCK_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_rck_data_fields[] = {
+	{ CAT_RCK_DATA_CM0U, 1, 1, 0x0000 }, { CAT_RCK_DATA_CM1U, 1, 5, 0x0000 },
+	{ CAT_RCK_DATA_CM2U, 1, 9, 0x0000 }, { CAT_RCK_DATA_CM3U, 1, 13, 0x0000 },
+	{ CAT_RCK_DATA_CM4U, 1, 17, 0x0000 }, { CAT_RCK_DATA_CM5U, 1, 21, 0x0000 },
+	{ CAT_RCK_DATA_CM6U, 1, 25, 0x0000 }, { CAT_RCK_DATA_CM7U, 1, 29, 0x0000 },
+	{ CAT_RCK_DATA_CML0, 1, 0, 0x0000 }, { CAT_RCK_DATA_CML1, 1, 4, 0x0000 },
+	{ CAT_RCK_DATA_CML2, 1, 8, 0x0000 }, { CAT_RCK_DATA_CML3, 1, 12, 0x0000 },
+	{ CAT_RCK_DATA_CML4, 1, 16, 0x0000 }, { CAT_RCK_DATA_CML5, 1, 20, 0x0000 },
+	{ CAT_RCK_DATA_CML6, 1, 24, 0x0000 }, { CAT_RCK_DATA_CML7, 1, 28, 0x0000 },
+	{ CAT_RCK_DATA_SEL0, 1, 2, 0x0000 }, { CAT_RCK_DATA_SEL1, 1, 6, 0x0000 },
+	{ CAT_RCK_DATA_SEL2, 1, 10, 0x0000 }, { CAT_RCK_DATA_SEL3, 1, 14, 0x0000 },
+	{ CAT_RCK_DATA_SEL4, 1, 18, 0x0000 }, { CAT_RCK_DATA_SEL5, 1, 22, 0x0000 },
+	{ CAT_RCK_DATA_SEL6, 1, 26, 0x0000 }, { CAT_RCK_DATA_SEL7, 1, 30, 0x0000 },
+	{ CAT_RCK_DATA_SEU0, 1, 3, 0x0000 }, { CAT_RCK_DATA_SEU1, 1, 7, 0x0000 },
+	{ CAT_RCK_DATA_SEU2, 1, 11, 0x0000 }, { CAT_RCK_DATA_SEU3, 1, 15, 0x0000 },
+	{ CAT_RCK_DATA_SEU4, 1, 19, 0x0000 }, { CAT_RCK_DATA_SEU5, 1, 23, 0x0000 },
+	{ CAT_RCK_DATA_SEU6, 1, 27, 0x0000 }, { CAT_RCK_DATA_SEU7, 1, 31, 0x0000 },
+};
+
+static nthw_fpga_register_init_s cat_registers[] = {
+	{ CAT_CCT_CTRL, 30, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cct_ctrl_fields },
+	{ CAT_CCT_DATA, 31, 36, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cct_data_fields },
+	{ CAT_CFN_CTRL, 10, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cfn_ctrl_fields },
+	{ CAT_CFN_DATA, 11, 179, NTHW_FPGA_REG_TYPE_WO, 0, 44, cat_cfn_data_fields },
+	{ CAT_COT_CTRL, 28, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cot_ctrl_fields },
+	{ CAT_COT_DATA, 29, 36, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cot_data_fields },
+	{ CAT_CTE_CTRL, 24, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cte_ctrl_fields },
+	{ CAT_CTE_DATA, 25, 11, NTHW_FPGA_REG_TYPE_WO, 0, 11, cat_cte_data_fields },
+	{ CAT_CTS_CTRL, 26, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cts_ctrl_fields },
+	{ CAT_CTS_DATA, 27, 12, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cts_data_fields },
+	{ CAT_DCT_CTRL, 6, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_dct_ctrl_fields },
+	{ CAT_DCT_DATA, 7, 16, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_dct_data_fields },
+	{ CAT_DCT_SEL, 4, 2, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_dct_sel_fields },
+	{ CAT_EXO_CTRL, 0, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_exo_ctrl_fields },
+	{ CAT_EXO_DATA, 1, 27, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_exo_data_fields },
+	{ CAT_FTE0_CTRL, 16, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_fte0_ctrl_fields },
+	{ CAT_FTE0_DATA, 17, 8, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_fte0_data_fields },
+	{ CAT_FTE1_CTRL, 22, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_fte1_ctrl_fields },
+	{ CAT_FTE1_DATA, 23, 8, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_fte1_data_fields },
+	{ CAT_JOIN, 5, 9, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_join_fields },
+	{ CAT_KCC_CTRL, 32, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_kcc_ctrl_fields },
+	{ CAT_KCC_DATA, 33, 84, NTHW_FPGA_REG_TYPE_WO, 0, 3, cat_kcc_data_fields },
+	{ CAT_KCE0_CTRL, 12, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_kce0_ctrl_fields },
+	{ CAT_KCE0_DATA, 13, 8, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_kce0_data_fields },
+	{ CAT_KCE1_CTRL, 18, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_kce1_ctrl_fields },
+	{ CAT_KCE1_DATA, 19, 8, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_kce1_data_fields },
+	{ CAT_KCS0_CTRL, 14, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_kcs0_ctrl_fields },
+	{ CAT_KCS0_DATA, 15, 6, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_kcs0_data_fields },
+	{ CAT_KCS1_CTRL, 20, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_kcs1_ctrl_fields },
+	{ CAT_KCS1_DATA, 21, 6, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_kcs1_data_fields },
+	{ CAT_LEN_CTRL, 8, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_len_ctrl_fields },
+	{ CAT_LEN_DATA, 9, 39, NTHW_FPGA_REG_TYPE_WO, 0, 5, cat_len_data_fields },
+	{ CAT_RCK_CTRL, 2, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_rck_ctrl_fields },
+	{ CAT_RCK_DATA, 3, 32, NTHW_FPGA_REG_TYPE_WO, 0, 32, cat_rck_data_fields },
+};
+
 static nthw_fpga_field_init_s gfg_burstsize0_fields[] = {
 	{ GFG_BURSTSIZE0_VAL, 24, 0, 0 },
 };
@@ -1037,6 +1298,7 @@ static nthw_fpga_register_init_s rst9563_registers[] = {
 };
 
 static nthw_fpga_module_init_s fpga_modules[] = {
+	{ MOD_CAT, 0, MOD_CAT, 0, 21, NTHW_FPGA_BUS_TYPE_RAB1, 768, 34, cat_registers },
 	{ MOD_GFG, 0, MOD_GFG, 1, 1, NTHW_FPGA_BUS_TYPE_RAB2, 8704, 10, gfg_registers },
 	{ MOD_GMF, 0, MOD_GMF, 2, 5, NTHW_FPGA_BUS_TYPE_RAB2, 9216, 12, gmf_registers },
 	{ MOD_GMF, 1, MOD_GMF, 2, 5, NTHW_FPGA_BUS_TYPE_RAB2, 9728, 12, gmf_registers },
@@ -1226,5 +1488,5 @@ static nthw_fpga_prod_param_s product_parameters[] = {
 };
 
 nthw_fpga_prod_init_s nthw_fpga_9563_055_049_0000 = {
-	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 15, fpga_modules,
+	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 16, fpga_modules,
 };
-- 
2.45.0


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

* [PATCH v1 24/31] net/ntnic: add key match (KM) FPGA module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (28 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 23/31] net/ntnic: add categorizer (CAT) FPGA module Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 25/31] net/ntnic: add flow matcher (FLM) " Serhii Iliushyk
                   ` (21 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Key Matcher module checks the values of individual fields of a packet.
It supports both exact match which is implemented with a CAM,
and wildcards which is implemented with a TCAM.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    |  85 ++++++
 drivers/net/ntnic/meson.build                 |   1 +
 drivers/net/ntnic/nthw/flow_api/flow_api.c    |   3 +
 .../nthw/flow_api/hw_mod/hw_mod_backend.c     |   1 +
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_km.c    | 278 ++++++++++++++++++
 .../supported/nthw_fpga_9563_055_049_0000.c   |  94 +++++-
 6 files changed, 461 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km.c

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 20b10faf5e..f40b33a888 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -32,6 +32,7 @@ void *callocate_mod(struct common_func_s *mod, int sets, ...);
 void zero_module_cache(struct common_func_s *mod);
 
 #define ALL_ENTRIES -1000
+#define ALL_BANK_ENTRIES -1001
 
 #define INDEX_TOO_LARGE (NT_LOG(INF, FILTER, "ERROR:%s: Index too large\n", __func__), -2)
 
@@ -267,6 +268,89 @@ struct km_func_s {
 		struct hw_mod_km_v7_s v7;
 	};
 };
+enum hw_km_e {
+	/* functions */
+	HW_KM_RCP_PRESET_ALL = 0,
+	HW_KM_CAM_PRESET_ALL,
+	/* to sync and reset hw with cache - force write all entries in a bank */
+	HW_KM_TCAM_BANK_RESET,
+	/* fields */
+	HW_KM_RCP_QW0_DYN = FIELD_START_INDEX,
+	HW_KM_RCP_QW0_OFS,
+	HW_KM_RCP_QW0_SEL_A,
+	HW_KM_RCP_QW0_SEL_B,
+	HW_KM_RCP_QW4_DYN,
+	HW_KM_RCP_QW4_OFS,
+	HW_KM_RCP_QW4_SEL_A,
+	HW_KM_RCP_QW4_SEL_B,
+	HW_KM_RCP_DW8_DYN,
+	HW_KM_RCP_DW8_OFS,
+	HW_KM_RCP_DW8_SEL_A,
+	HW_KM_RCP_DW8_SEL_B,
+	HW_KM_RCP_DW10_DYN,
+	HW_KM_RCP_DW10_OFS,
+	HW_KM_RCP_DW10_SEL_A,
+	HW_KM_RCP_DW10_SEL_B,
+	HW_KM_RCP_SWX_CCH,
+	HW_KM_RCP_SWX_SEL_A,
+	HW_KM_RCP_SWX_SEL_B,
+	HW_KM_RCP_MASK_A,
+	HW_KM_RCP_MASK_B,
+	HW_KM_RCP_DUAL,
+	HW_KM_RCP_PAIRED,
+	HW_KM_RCP_EL_A,
+	HW_KM_RCP_EL_B,
+	HW_KM_RCP_INFO_A,
+	HW_KM_RCP_INFO_B,
+	HW_KM_RCP_FTM_A,
+	HW_KM_RCP_FTM_B,
+	HW_KM_RCP_BANK_A,
+	HW_KM_RCP_BANK_B,
+	HW_KM_RCP_KL_A,
+	HW_KM_RCP_KL_B,
+	HW_KM_RCP_KEYWAY_A,
+	HW_KM_RCP_KEYWAY_B,
+	HW_KM_RCP_SYNERGY_MODE,
+	HW_KM_RCP_DW0_B_DYN,
+	HW_KM_RCP_DW0_B_OFS,
+	HW_KM_RCP_DW2_B_DYN,
+	HW_KM_RCP_DW2_B_OFS,
+	HW_KM_RCP_SW4_B_DYN,
+	HW_KM_RCP_SW4_B_OFS,
+	HW_KM_RCP_SW5_B_DYN,
+	HW_KM_RCP_SW5_B_OFS,
+	HW_KM_CAM_W0,
+	HW_KM_CAM_W1,
+	HW_KM_CAM_W2,
+	HW_KM_CAM_W3,
+	HW_KM_CAM_W4,
+	HW_KM_CAM_W5,
+	HW_KM_CAM_FT0,
+	HW_KM_CAM_FT1,
+	HW_KM_CAM_FT2,
+	HW_KM_CAM_FT3,
+	HW_KM_CAM_FT4,
+	HW_KM_CAM_FT5,
+	HW_KM_TCAM_T,
+	HW_KM_TCI_COLOR,
+	HW_KM_TCI_FT,
+	HW_KM_TCQ_BANK_MASK,
+	HW_KM_TCQ_QUAL
+};
+bool hw_mod_km_present(struct flow_api_backend_s *be);
+int hw_mod_km_alloc(struct flow_api_backend_s *be);
+void hw_mod_km_free(struct flow_api_backend_s *be);
+int hw_mod_km_reset(struct flow_api_backend_s *be);
+int hw_mod_km_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_km_cam_flush(struct flow_api_backend_s *be, int start_bank, int start_record,
+	int count);
+int hw_mod_km_tcam_flush(struct flow_api_backend_s *be, int start_bank, int count);
+int hw_mod_km_tcam_set(struct flow_api_backend_s *be, enum hw_km_e field, int bank, int byte,
+	int byte_val, uint32_t *value_set);
+int hw_mod_km_tci_flush(struct flow_api_backend_s *be, int start_bank, int start_record,
+	int count);
+int hw_mod_km_tcq_flush(struct flow_api_backend_s *be, int start_bank, int start_record,
+	int count);
 
 struct flm_func_s {
 	COMMON_FUNC_INFO_S;
@@ -483,6 +567,7 @@ struct flow_api_backend_s {
 
 	/* flow filter FPGA modules */
 	struct cat_func_s cat;
+	struct km_func_s km;
 
 	/* NIC attributes */
 	unsigned int num_phy_ports;
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 3d394f9bad..e37bb96331 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -50,6 +50,7 @@ sources = files(
         'nthw/flow_api/flow_km.c',
         'nthw/flow_api/hw_mod/hw_mod_backend.c',
         'nthw/flow_api/hw_mod/hw_mod_cat.c',
+        'nthw/flow_api/hw_mod/hw_mod_km.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_csu.c',
         'nthw/flow_filter/flow_nthw_flm.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
index 3b1d7c5850..c85838519b 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -287,6 +287,9 @@ struct flow_nic_dev *flow_api_create(uint8_t adapter_no, const struct flow_api_b
 	if (init_resource_elements(ndev, RES_KM_FLOW_TYPE, ndev->be.cat.nb_flow_types))
 		goto err_exit;
 
+	if (init_resource_elements(ndev, RES_KM_CATEGORY, ndev->be.km.nb_categories))
+		goto err_exit;
+
 	if (init_resource_elements(ndev, RES_SLC_LR_RCP, ndev->be.max_categories))
 		goto err_exit;
 
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
index 33fb4df126..9d5572f4b2 100644
--- a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
@@ -18,6 +18,7 @@ static const struct {
 	bool (*present)(struct flow_api_backend_s *be);
 } module[] = {
 	{ "CAT", hw_mod_cat_alloc, hw_mod_cat_free, hw_mod_cat_reset, hw_mod_cat_present },
+	{ "KM", hw_mod_km_alloc, hw_mod_km_free, hw_mod_km_reset, hw_mod_km_present },
 };
 #define MOD_COUNT (ARRAY_SIZE(module))
 
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km.c
new file mode 100644
index 0000000000..680fcd0af9
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_km.c
@@ -0,0 +1,278 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hw_mod_backend.h"
+
+#define _MOD_ "KM"
+#define _VER_ be->km.ver
+
+#define KM_TCQ_ENTRIES 2048
+#define KM_RCP_MASK_A_SIZE 11
+#define KM_RCP_MASK_D_A_SIZE 12	/* Mask for double size word extractors for DW8/DW10 */
+#define KM_RCP_MASK_B_SIZE 6
+
+bool hw_mod_km_present(struct flow_api_backend_s *be)
+{
+	return be->iface->get_km_present(be->be_dev);
+}
+
+int hw_mod_km_alloc(struct flow_api_backend_s *be)
+{
+	int nb;
+	_VER_ = be->iface->get_km_version(be->be_dev);
+	NT_LOG(DBG, FILTER, "KM  MODULE VERSION  %i.%i\n", VER_MAJOR(_VER_), VER_MINOR(_VER_));
+
+	nb = be->iface->get_nb_km_categories(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(km_categories);
+
+	be->km.nb_categories = (uint32_t)nb;
+
+	nb = be->iface->get_nb_km_cam_banks(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(cam_banks);
+
+	be->km.nb_cam_banks = (uint32_t)nb;
+
+	nb = be->iface->get_nb_km_cam_records(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(cam_records);
+
+	be->km.nb_cam_records = (uint32_t)nb;
+
+	nb = be->iface->get_nb_km_cam_record_words(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(cam_record_words);
+
+	be->km.nb_cam_record_words = (uint32_t)nb;
+
+	nb = be->iface->get_nb_km_tcam_banks(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(tcam_banks);
+
+	be->km.nb_tcam_banks = (uint32_t)nb;
+
+	nb = be->iface->get_nb_km_tcam_bank_width(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(tcam_bank_width);
+
+	be->km.nb_tcam_bank_width = (uint32_t)nb;
+
+	switch (_VER_) {
+	case 7:
+		be->km.nb_km_rcp_mask_a_word_size = 12;
+		be->km.nb_km_rcp_mask_b_word_size = 6;
+
+		if (!callocate_mod((struct common_func_s *)&be->km, 5, &be->km.v7.rcp,
+				be->km.nb_categories, sizeof(struct km_v7_rcp_s),
+				&be->km.v7.cam, be->km.nb_cam_banks * be->km.nb_cam_records,
+				sizeof(struct km_v7_cam_s), &be->km.v7.tcam,
+				be->km.nb_tcam_banks * 4 * 256, sizeof(struct km_v7_tcam_s),
+				&be->km.v7.tci,
+				be->km.nb_tcam_banks * be->km.nb_tcam_bank_width,
+				sizeof(struct km_v7_tci_s), &be->km.v7.tcq, KM_TCQ_ENTRIES,
+				sizeof(struct km_v7_tcq_s)))
+			return -1;
+
+		break;
+
+	/* end case 7 */
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+void hw_mod_km_free(struct flow_api_backend_s *be)
+{
+	if (be->km.base) {
+		free(be->km.base);
+		be->km.base = NULL;
+	}
+}
+
+int hw_mod_km_reset(struct flow_api_backend_s *be)
+{
+	uint32_t tcam_v_set[3] = { 0x00000000, 0x00000000, 0x00000000 };
+
+	/* Zero entire cache area */
+	zero_module_cache((struct common_func_s *)(&be->km));
+
+	NT_LOG(DBG, FILTER, "INIT KM RCP\n");
+	hw_mod_km_rcp_flush(be, 0, ALL_ENTRIES);
+
+	/* init CAM - all zero */
+	NT_LOG(DBG, FILTER, "INIT KM CAM\n");
+	hw_mod_km_cam_flush(be, 0, 0, ALL_ENTRIES);
+
+	/* init TCAM - all zero */
+	NT_LOG(DBG, FILTER, "INIT KM TCAM\n");
+
+	for (unsigned int i = 0; i < be->km.nb_tcam_banks; i++) {
+		/* TCAM entries are cache controlled,
+		 * thus need to hard reset initially to sync cache with HW
+		 */
+		hw_mod_km_tcam_set(be, HW_KM_TCAM_BANK_RESET, i, 0, 0, tcam_v_set);
+	}
+
+	hw_mod_km_tcam_flush(be, 0, ALL_ENTRIES);
+
+	/* init TCI - all zero */
+	NT_LOG(DBG, FILTER, "INIT KM TCI\n");
+	hw_mod_km_tci_flush(be, 0, 0, ALL_ENTRIES);
+
+	NT_LOG(DBG, FILTER, "INIT KM TCQ\n");
+
+	for (unsigned int i = 0; i < be->km.nb_tcam_bank_width; i++)
+		hw_mod_km_tcq_flush(be, 0, i, be->km.nb_tcam_banks);
+
+	return 0;
+}
+
+int hw_mod_km_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->km.nb_categories;
+
+	if ((unsigned int)(start_idx + count) > be->km.nb_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->km_rcp_flush(be->be_dev, &be->km, start_idx, count);
+}
+
+int hw_mod_km_cam_flush(struct flow_api_backend_s *be, int start_bank, int start_record, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->km.nb_cam_records * be->km.nb_cam_banks;
+
+	unsigned int end = start_bank * be->km.nb_cam_records + start_record + count;
+
+	if (end > (be->km.nb_cam_banks * be->km.nb_cam_records))
+		return INDEX_TOO_LARGE;
+
+	return be->iface->km_cam_flush(be->be_dev, &be->km, start_bank, start_record, count);
+}
+
+int hw_mod_km_tcam_flush(struct flow_api_backend_s *be, int start_bank, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->km.nb_tcam_banks * 4 * 256;
+
+	else if (count == ALL_BANK_ENTRIES)
+		count = 4 * 256;
+
+	unsigned int end = start_bank * 4 * 256 + count;
+
+	if (end > (be->km.nb_tcam_banks * 4 * 256))
+		return INDEX_TOO_LARGE;
+
+	return be->iface->km_tcam_flush(be->be_dev, &be->km, start_bank, 0, 0, count);
+}
+
+static int hw_mod_km_tcam_mod(struct flow_api_backend_s *be, enum hw_km_e field, int bank,
+	int byte, int byte_val, uint32_t *value_set, int get)
+{
+	unsigned int start_index = bank * 4 * 256 + (int)byte * 256 + byte_val;
+
+	if (start_index >= (be->km.nb_tcam_banks * 4 * 256))
+		return INDEX_TOO_LARGE;
+
+	switch (_VER_) {
+	case 7:
+		switch (field) {
+		case HW_KM_TCAM_BANK_RESET:
+			if (get)
+				return UNSUP_FIELD;
+
+			{
+				int start_idx = bank * 4 * 256;
+
+				for (int i = 0; i < 4 * 256; i++) {
+					be->km.v7.tcam[start_idx + i].t[0] = value_set[0];
+					be->km.v7.tcam[start_idx + i].t[1] = value_set[1];
+					be->km.v7.tcam[start_idx + i].t[2] = value_set[2];
+					be->km.v7.tcam[start_idx + i].dirty = 1;
+				}
+			}
+			break;
+
+		case HW_KM_TCAM_T: {
+			int index = bank * 4 * 256 + byte * 256 + byte_val;
+
+			if (get) {
+				value_set[0] = be->km.v7.tcam[index].t[0];
+				value_set[1] = be->km.v7.tcam[index].t[1];
+				value_set[2] = be->km.v7.tcam[index].t[2];
+
+			} else {
+				/* only change if any bits has to be changed */
+				if (be->km.v7.tcam[index].t[0] != value_set[0] ||
+					be->km.v7.tcam[index].t[1] != value_set[1] ||
+					be->km.v7.tcam[index].t[2] != value_set[2]) {
+					be->km.v7.tcam[index].t[0] = value_set[0];
+					be->km.v7.tcam[index].t[1] = value_set[1];
+					be->km.v7.tcam[index].t[2] = value_set[2];
+					be->km.v7.tcam[index].dirty = 1;
+				}
+			}
+		}
+		break;
+
+		default:
+			return UNSUP_FIELD;
+		}
+
+		break;
+
+	/* end case 7 */
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+int hw_mod_km_tcam_set(struct flow_api_backend_s *be, enum hw_km_e field, int bank, int byte,
+	int byte_val, uint32_t *value_set)
+{
+	return hw_mod_km_tcam_mod(be, field, bank, byte, byte_val, value_set, 0);
+}
+
+int hw_mod_km_tci_flush(struct flow_api_backend_s *be, int start_bank, int start_record, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->km.nb_tcam_banks * be->km.nb_tcam_bank_width;
+
+	unsigned int end = (int)start_bank * be->km.nb_tcam_bank_width + start_record + count;
+
+	if (end > (be->km.nb_tcam_banks * be->km.nb_tcam_bank_width))
+		return INDEX_TOO_LARGE;
+
+	return be->iface->km_tci_flush(be->be_dev, &be->km, start_bank, start_record, count);
+}
+
+int hw_mod_km_tcq_flush(struct flow_api_backend_s *be, int start_bank, int start_record, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->km.nb_tcam_banks * be->km.nb_tcam_bank_width;
+
+	unsigned int end = (int)start_bank * be->km.nb_tcam_bank_width + start_record + count;
+
+	if (end > (be->km.nb_tcam_banks * be->km.nb_tcam_bank_width))
+		return INDEX_TOO_LARGE;
+
+	return be->iface->km_tcq_flush(be->be_dev, &be->km, start_bank, start_record, count);
+}
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
index 4efd5aa2f8..a003334a23 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
@@ -667,6 +667,97 @@ static nthw_fpga_register_init_s iic_registers[] = {
 	{ IIC_TX_FIFO_OCY, 69, 4, NTHW_FPGA_REG_TYPE_RO, 0, 1, iic_tx_fifo_ocy_fields },
 };
 
+static nthw_fpga_field_init_s km_cam_ctrl_fields[] = {
+	{ KM_CAM_CTRL_ADR, 13, 0, 0x0000 },
+	{ KM_CAM_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s km_cam_data_fields[] = {
+	{ KM_CAM_DATA_FT0, 4, 192, 0x0000 }, { KM_CAM_DATA_FT1, 4, 196, 0x0000 },
+	{ KM_CAM_DATA_FT2, 4, 200, 0x0000 }, { KM_CAM_DATA_FT3, 4, 204, 0x0000 },
+	{ KM_CAM_DATA_FT4, 4, 208, 0x0000 }, { KM_CAM_DATA_FT5, 4, 212, 0x0000 },
+	{ KM_CAM_DATA_W0, 32, 0, 0x0000 }, { KM_CAM_DATA_W1, 32, 32, 0x0000 },
+	{ KM_CAM_DATA_W2, 32, 64, 0x0000 }, { KM_CAM_DATA_W3, 32, 96, 0x0000 },
+	{ KM_CAM_DATA_W4, 32, 128, 0x0000 }, { KM_CAM_DATA_W5, 32, 160, 0x0000 },
+};
+
+static nthw_fpga_field_init_s km_rcp_ctrl_fields[] = {
+	{ KM_RCP_CTRL_ADR, 5, 0, 0x0000 },
+	{ KM_RCP_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s km_rcp_data_fields[] = {
+	{ KM_RCP_DATA_BANK_A, 12, 694, 0x0000 }, { KM_RCP_DATA_BANK_B, 12, 706, 0x0000 },
+	{ KM_RCP_DATA_DUAL, 1, 651, 0x0000 }, { KM_RCP_DATA_DW0_B_DYN, 5, 729, 0x0000 },
+	{ KM_RCP_DATA_DW0_B_OFS, 8, 734, 0x0000 }, { KM_RCP_DATA_DW10_DYN, 5, 55, 0x0000 },
+	{ KM_RCP_DATA_DW10_OFS, 8, 60, 0x0000 }, { KM_RCP_DATA_DW10_SEL_A, 2, 68, 0x0000 },
+	{ KM_RCP_DATA_DW10_SEL_B, 2, 70, 0x0000 }, { KM_RCP_DATA_DW2_B_DYN, 5, 742, 0x0000 },
+	{ KM_RCP_DATA_DW2_B_OFS, 8, 747, 0x0000 }, { KM_RCP_DATA_DW8_DYN, 5, 36, 0x0000 },
+	{ KM_RCP_DATA_DW8_OFS, 8, 41, 0x0000 }, { KM_RCP_DATA_DW8_SEL_A, 3, 49, 0x0000 },
+	{ KM_RCP_DATA_DW8_SEL_B, 3, 52, 0x0000 }, { KM_RCP_DATA_EL_A, 4, 653, 0x0000 },
+	{ KM_RCP_DATA_EL_B, 3, 657, 0x0000 }, { KM_RCP_DATA_FTM_A, 16, 662, 0x0000 },
+	{ KM_RCP_DATA_FTM_B, 16, 678, 0x0000 }, { KM_RCP_DATA_INFO_A, 1, 660, 0x0000 },
+	{ KM_RCP_DATA_INFO_B, 1, 661, 0x0000 }, { KM_RCP_DATA_KEYWAY_A, 1, 725, 0x0000 },
+	{ KM_RCP_DATA_KEYWAY_B, 1, 726, 0x0000 }, { KM_RCP_DATA_KL_A, 4, 718, 0x0000 },
+	{ KM_RCP_DATA_KL_B, 3, 722, 0x0000 }, { KM_RCP_DATA_MASK_A, 384, 75, 0x0000 },
+	{ KM_RCP_DATA_MASK_B, 192, 459, 0x0000 }, { KM_RCP_DATA_PAIRED, 1, 652, 0x0000 },
+	{ KM_RCP_DATA_QW0_DYN, 5, 0, 0x0000 }, { KM_RCP_DATA_QW0_OFS, 8, 5, 0x0000 },
+	{ KM_RCP_DATA_QW0_SEL_A, 3, 13, 0x0000 }, { KM_RCP_DATA_QW0_SEL_B, 3, 16, 0x0000 },
+	{ KM_RCP_DATA_QW4_DYN, 5, 19, 0x0000 }, { KM_RCP_DATA_QW4_OFS, 8, 24, 0x0000 },
+	{ KM_RCP_DATA_QW4_SEL_A, 2, 32, 0x0000 }, { KM_RCP_DATA_QW4_SEL_B, 2, 34, 0x0000 },
+	{ KM_RCP_DATA_SW4_B_DYN, 5, 755, 0x0000 }, { KM_RCP_DATA_SW4_B_OFS, 8, 760, 0x0000 },
+	{ KM_RCP_DATA_SW5_B_DYN, 5, 768, 0x0000 }, { KM_RCP_DATA_SW5_B_OFS, 8, 773, 0x0000 },
+	{ KM_RCP_DATA_SWX_CCH, 1, 72, 0x0000 }, { KM_RCP_DATA_SWX_SEL_A, 1, 73, 0x0000 },
+	{ KM_RCP_DATA_SWX_SEL_B, 1, 74, 0x0000 }, { KM_RCP_DATA_SYNERGY_MODE, 2, 727, 0x0000 },
+};
+
+static nthw_fpga_field_init_s km_status_fields[] = {
+	{ KM_STATUS_TCQ_RDY, 1, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s km_tcam_ctrl_fields[] = {
+	{ KM_TCAM_CTRL_ADR, 14, 0, 0x0000 },
+	{ KM_TCAM_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s km_tcam_data_fields[] = {
+	{ KM_TCAM_DATA_T, 72, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s km_tci_ctrl_fields[] = {
+	{ KM_TCI_CTRL_ADR, 10, 0, 0x0000 },
+	{ KM_TCI_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s km_tci_data_fields[] = {
+	{ KM_TCI_DATA_COLOR, 32, 0, 0x0000 },
+	{ KM_TCI_DATA_FT, 4, 32, 0x0000 },
+};
+
+static nthw_fpga_field_init_s km_tcq_ctrl_fields[] = {
+	{ KM_TCQ_CTRL_ADR, 7, 0, 0x0000 },
+	{ KM_TCQ_CTRL_CNT, 5, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s km_tcq_data_fields[] = {
+	{ KM_TCQ_DATA_BANK_MASK, 12, 0, 0x0000 },
+	{ KM_TCQ_DATA_QUAL, 3, 12, 0x0000 },
+};
+
+static nthw_fpga_register_init_s km_registers[] = {
+	{ KM_CAM_CTRL, 2, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, km_cam_ctrl_fields },
+	{ KM_CAM_DATA, 3, 216, NTHW_FPGA_REG_TYPE_WO, 0, 12, km_cam_data_fields },
+	{ KM_RCP_CTRL, 0, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, km_rcp_ctrl_fields },
+	{ KM_RCP_DATA, 1, 781, NTHW_FPGA_REG_TYPE_WO, 0, 44, km_rcp_data_fields },
+	{ KM_STATUS, 10, 1, NTHW_FPGA_REG_TYPE_RO, 0, 1, km_status_fields },
+	{ KM_TCAM_CTRL, 4, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, km_tcam_ctrl_fields },
+	{ KM_TCAM_DATA, 5, 72, NTHW_FPGA_REG_TYPE_WO, 0, 1, km_tcam_data_fields },
+	{ KM_TCI_CTRL, 6, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, km_tci_ctrl_fields },
+	{ KM_TCI_DATA, 7, 36, NTHW_FPGA_REG_TYPE_WO, 0, 2, km_tci_data_fields },
+	{ KM_TCQ_CTRL, 8, 21, NTHW_FPGA_REG_TYPE_WO, 0, 2, km_tcq_ctrl_fields },
+	{ KM_TCQ_DATA, 9, 15, NTHW_FPGA_REG_TYPE_WO, 0, 2, km_tcq_data_fields },
+};
+
 static nthw_fpga_field_init_s mac_pcs_bad_code_fields[] = {
 	{ MAC_PCS_BAD_CODE_CODE_ERR, 16, 0, 0x0000 },
 };
@@ -1311,6 +1402,7 @@ static nthw_fpga_module_init_s fpga_modules[] = {
 	{ MOD_IIC, 1, MOD_IIC, 0, 1, NTHW_FPGA_BUS_TYPE_RAB0, 896, 22, iic_registers },
 	{ MOD_IIC, 2, MOD_IIC, 0, 1, NTHW_FPGA_BUS_TYPE_RAB0, 24832, 22, iic_registers },
 	{ MOD_IIC, 3, MOD_IIC, 0, 1, NTHW_FPGA_BUS_TYPE_RAB0, 24960, 22, iic_registers },
+	{ MOD_KM, 0, MOD_KM, 0, 7, NTHW_FPGA_BUS_TYPE_RAB1, 1024, 11, km_registers },
 	{
 		MOD_MAC_PCS, 0, MOD_MAC_PCS, 0, 2, NTHW_FPGA_BUS_TYPE_RAB2, 10240, 44,
 		mac_pcs_registers
@@ -1488,5 +1580,5 @@ static nthw_fpga_prod_param_s product_parameters[] = {
 };
 
 nthw_fpga_prod_init_s nthw_fpga_9563_055_049_0000 = {
-	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 16, fpga_modules,
+	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 17, fpga_modules,
 };
-- 
2.45.0


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

* [PATCH v1 25/31] net/ntnic: add flow matcher (FLM) FPGA module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (29 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 24/31] net/ntnic: add key match (KM) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 26/31] net/ntnic: add hasher (HSH) " Serhii Iliushyk
                   ` (20 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Flow Matcher module is a high-performance stateful SDRAM lookup
and programming engine which supported exact match lookup
in line-rate of up to hundreds of millions of flows.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    | 117 +++++++
 drivers/net/ntnic/meson.build                 |   1 +
 drivers/net/ntnic/nthw/flow_api/flow_api.c    |   6 +
 .../nthw/flow_api/hw_mod/hw_mod_backend.c     |   1 +
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_flm.c   | 300 ++++++++++++++++++
 5 files changed, 425 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm.c

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index f40b33a888..3933d4bf53 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -367,6 +367,122 @@ struct flm_func_s {
 		struct hw_mod_flm_v25_s v25;
 	};
 };
+enum hw_flm_e {
+	/* functions */
+	HW_FLM_CONTROL_PRESET_ALL = 0,
+	HW_FLM_RCP_PRESET_ALL,
+	HW_FLM_FLOW_LRN_DATA,
+	HW_FLM_FLOW_INF_STA_DATA,
+	/* Control fields */
+	HW_FLM_CONTROL_ENABLE = FIELD_START_INDEX,
+	HW_FLM_CONTROL_INIT,
+	HW_FLM_CONTROL_LDS,
+	HW_FLM_CONTROL_LFS,
+	HW_FLM_CONTROL_LIS,
+	HW_FLM_CONTROL_UDS,
+	HW_FLM_CONTROL_UIS,
+	HW_FLM_CONTROL_RDS,
+	HW_FLM_CONTROL_RIS,
+	HW_FLM_CONTROL_PDS,
+	HW_FLM_CONTROL_PIS,
+	HW_FLM_CONTROL_CRCWR,
+	HW_FLM_CONTROL_CRCRD,
+	HW_FLM_CONTROL_RBL,
+	HW_FLM_CONTROL_EAB,
+	HW_FLM_CONTROL_SPLIT_SDRAM_USAGE,
+	HW_FLM_STATUS_CALIB_SUCCESS,
+	HW_FLM_STATUS_CALIB_FAIL,
+	HW_FLM_STATUS_INITDONE,
+	HW_FLM_STATUS_IDLE,
+	HW_FLM_STATUS_CRITICAL,
+	HW_FLM_STATUS_PANIC,
+	HW_FLM_STATUS_CRCERR,
+	HW_FLM_STATUS_EFT_BP,
+	HW_FLM_STATUS_CACHE_BUFFER_CRITICAL,
+	HW_FLM_LOAD_BIN,
+	HW_FLM_LOAD_LPS,
+	HW_FLM_LOAD_APS,
+	HW_FLM_PRIO_LIMIT0,
+	HW_FLM_PRIO_FT0,
+	HW_FLM_PRIO_LIMIT1,
+	HW_FLM_PRIO_FT1,
+	HW_FLM_PRIO_LIMIT2,
+	HW_FLM_PRIO_FT2,
+	HW_FLM_PRIO_LIMIT3,
+	HW_FLM_PRIO_FT3,
+	HW_FLM_PST_PRESET_ALL,
+	HW_FLM_PST_BP,
+	HW_FLM_PST_PP,
+	HW_FLM_PST_TP,
+	HW_FLM_RCP_LOOKUP,
+	HW_FLM_RCP_QW0_DYN,
+	HW_FLM_RCP_QW0_OFS,
+	HW_FLM_RCP_QW0_SEL,
+	HW_FLM_RCP_QW4_DYN,
+	HW_FLM_RCP_QW4_OFS,
+	HW_FLM_RCP_SW8_DYN,
+	HW_FLM_RCP_SW8_OFS,
+	HW_FLM_RCP_SW8_SEL,
+	HW_FLM_RCP_SW9_DYN,
+	HW_FLM_RCP_SW9_OFS,
+	HW_FLM_RCP_MASK,
+	HW_FLM_RCP_KID,
+	HW_FLM_RCP_OPN,
+	HW_FLM_RCP_IPN,
+	HW_FLM_RCP_BYT_DYN,
+	HW_FLM_RCP_BYT_OFS,
+	HW_FLM_RCP_TXPLM,
+	HW_FLM_RCP_AUTO_IPV4_MASK,
+	HW_FLM_BUF_CTRL_LRN_FREE,
+	HW_FLM_BUF_CTRL_INF_AVAIL,
+	HW_FLM_BUF_CTRL_STA_AVAIL,
+	HW_FLM_STAT_LRN_DONE,
+	HW_FLM_STAT_LRN_IGNORE,
+	HW_FLM_STAT_LRN_FAIL,
+	HW_FLM_STAT_UNL_DONE,
+	HW_FLM_STAT_UNL_IGNORE,
+	HW_FLM_STAT_REL_DONE,
+	HW_FLM_STAT_REL_IGNORE,
+	HW_FLM_STAT_PRB_DONE,
+	HW_FLM_STAT_PRB_IGNORE,
+	HW_FLM_STAT_AUL_DONE,
+	HW_FLM_STAT_AUL_IGNORE,
+	HW_FLM_STAT_AUL_FAIL,
+	HW_FLM_STAT_TUL_DONE,
+	HW_FLM_STAT_FLOWS,
+	HW_FLM_STAT_STA_DONE,	/* module ver 0.20 */
+	HW_FLM_STAT_INF_DONE,	/* module ver 0.20 */
+	HW_FLM_STAT_INF_SKIP,	/* module ver 0.20 */
+	HW_FLM_STAT_PCK_HIT,	/* module ver 0.20 */
+	HW_FLM_STAT_PCK_MISS,	/* module ver 0.20 */
+	HW_FLM_STAT_PCK_UNH,	/* module ver 0.20 */
+	HW_FLM_STAT_PCK_DIS,	/* module ver 0.20 */
+	HW_FLM_STAT_CSH_HIT,	/* module ver 0.20 */
+	HW_FLM_STAT_CSH_MISS,	/* module ver 0.20 */
+	HW_FLM_STAT_CSH_UNH,	/* module ver 0.20 */
+	HW_FLM_STAT_CUC_START,	/* module ver 0.20 */
+	HW_FLM_STAT_CUC_MOVE,	/* module ver 0.20 */
+	HW_FLM_SCAN_I,	/* module ver 0.22 */
+	HW_FLM_SCRUB_PRESET_ALL,
+	HW_FLM_SCRUB_T,	/* module ver 0.22 */
+	HW_FLM_SCRUB_R,	/* module ver 0.24 */
+	HW_FLM_SCRUB_DEL,	/* module ver 0.24 */
+	HW_FLM_SCRUB_INF,	/* module ver 0.24 */
+};
+
+bool hw_mod_flm_present(struct flow_api_backend_s *be);
+int hw_mod_flm_alloc(struct flow_api_backend_s *be);
+void hw_mod_flm_free(struct flow_api_backend_s *be);
+int hw_mod_flm_reset(struct flow_api_backend_s *be);
+
+int hw_mod_flm_control_flush(struct flow_api_backend_s *be);
+int hw_mod_flm_control_set(struct flow_api_backend_s *be, enum hw_flm_e field, uint32_t value);
+
+int hw_mod_flm_scan_flush(struct flow_api_backend_s *be);
+
+int hw_mod_flm_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
+
+int hw_mod_flm_scrub_flush(struct flow_api_backend_s *be, int start_idx, int count);
 
 struct hsh_func_s {
 	COMMON_FUNC_INFO_S;
@@ -568,6 +684,7 @@ struct flow_api_backend_s {
 	/* flow filter FPGA modules */
 	struct cat_func_s cat;
 	struct km_func_s km;
+	struct flm_func_s flm;
 
 	/* NIC attributes */
 	unsigned int num_phy_ports;
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index e37bb96331..9af7e3d813 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -50,6 +50,7 @@ sources = files(
         'nthw/flow_api/flow_km.c',
         'nthw/flow_api/hw_mod/hw_mod_backend.c',
         'nthw/flow_api/hw_mod/hw_mod_cat.c',
+        'nthw/flow_api/hw_mod/hw_mod_flm.c',
         'nthw/flow_api/hw_mod/hw_mod_km.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_csu.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
index c85838519b..d39bdc9936 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -296,6 +296,12 @@ struct flow_nic_dev *flow_api_create(uint8_t adapter_no, const struct flow_api_b
 	if (init_resource_elements(ndev, RES_FLM_FLOW_TYPE, ndev->be.cat.nb_flow_types))
 		goto err_exit;
 
+	if (init_resource_elements(ndev, RES_FLM_RCP, ndev->be.flm.nb_categories))
+		goto err_exit;
+
+	if (init_resource_elements(ndev, RES_SCRUB_RCP, ndev->be.flm.nb_scrub_profiles))
+		goto err_exit;
+
 	/* may need IPF, COR */
 
 	/* check all defined has been initialized */
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
index 9d5572f4b2..fe66493336 100644
--- a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
@@ -19,6 +19,7 @@ static const struct {
 } module[] = {
 	{ "CAT", hw_mod_cat_alloc, hw_mod_cat_free, hw_mod_cat_reset, hw_mod_cat_present },
 	{ "KM", hw_mod_km_alloc, hw_mod_km_free, hw_mod_km_reset, hw_mod_km_present },
+	{ "FLM", hw_mod_flm_alloc, hw_mod_flm_free, hw_mod_flm_reset, hw_mod_flm_present },
 };
 #define MOD_COUNT (ARRAY_SIZE(module))
 
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm.c
new file mode 100644
index 0000000000..c52467b575
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_flm.c
@@ -0,0 +1,300 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hw_mod_backend.h"
+
+#define _MOD_ "FLM"
+#define _VER_ be->flm.ver
+
+bool hw_mod_flm_present(struct flow_api_backend_s *be)
+{
+	return be->iface->get_flm_present(be->be_dev);
+}
+
+int hw_mod_flm_alloc(struct flow_api_backend_s *be)
+{
+	int nb;
+	_VER_ = be->iface->get_flm_version(be->be_dev);
+	NT_LOG(DBG, FILTER, "FLM MODULE VERSION  %i.%i\n", VER_MAJOR(_VER_), VER_MINOR(_VER_));
+
+	nb = be->iface->get_nb_flm_categories(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(flm_categories);
+
+	be->flm.nb_categories = (uint32_t)nb;
+
+	nb = be->iface->get_nb_flm_size_mb(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(flm_size_mb);
+
+	be->flm.nb_size_mb = (uint32_t)nb;
+
+	nb = be->iface->get_nb_flm_entry_size(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(flm_entry_size);
+
+	be->flm.nb_entry_size = (uint32_t)nb;
+
+	nb = be->iface->get_nb_flm_variant(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(flm_variant);
+
+	be->flm.nb_variant = (uint32_t)nb;
+
+	nb = be->iface->get_nb_flm_prios(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(flm_prios);
+
+	be->flm.nb_prios = (uint32_t)nb;
+
+	nb = be->iface->get_nb_flm_pst_profiles(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(flm_pst_profiles);
+
+	be->flm.nb_pst_profiles = (uint32_t)nb;
+
+	if (_VER_ >= 22) {
+		nb = be->iface->get_nb_flm_scrub_profiles(be->be_dev);
+
+		if (nb <= 0)
+			return COUNT_ERROR(flm_scrub_profiles);
+
+		be->flm.nb_scrub_profiles = (uint32_t)nb;
+	}
+
+	nb = be->iface->get_nb_rpp_per_ps(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(flm_rpp_clock);
+
+	be->flm.nb_rpp_clock_in_ps = (uint32_t)nb;
+
+	nb = be->iface->get_nb_flm_load_aps_max(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(flm_load_aps_max);
+
+	be->flm.nb_load_aps_max = (uint32_t)nb;
+
+	switch (_VER_) {
+	case 25:
+		if (!callocate_mod((struct common_func_s *)&be->flm, 38, &be->flm.v25.control, 1,
+				sizeof(struct flm_v25_control_s), &be->flm.v25.status, 1,
+				sizeof(struct flm_v25_status_s), &be->flm.v25.load_bin, 1,
+				sizeof(struct flm_v25_load_bin_s), &be->flm.v25.load_pps, 1,
+				sizeof(struct flm_v25_load_pps_s), &be->flm.v25.load_lps, 1,
+				sizeof(struct flm_v25_load_lps_s), &be->flm.v25.load_aps, 1,
+				sizeof(struct flm_v25_load_aps_s), &be->flm.v25.prio, 1,
+				sizeof(struct flm_v25_prio_s), &be->flm.v25.pst,
+				be->flm.nb_pst_profiles, sizeof(struct flm_v25_pst_s),
+				&be->flm.v25.rcp, be->flm.nb_categories,
+				sizeof(struct flm_v25_rcp_s),
+				&be->flm.v25.buf_ctrl, 1, sizeof(struct flm_v25_buf_ctrl_s),
+				&be->flm.v25.lrn_done, 1, sizeof(struct flm_v25_stat_lrn_done_s),
+				&be->flm.v25.lrn_ignore, 1,
+				sizeof(struct flm_v25_stat_lrn_ignore_s),
+				&be->flm.v25.lrn_fail, 1, sizeof(struct flm_v25_stat_lrn_fail_s),
+				&be->flm.v25.unl_done, 1, sizeof(struct flm_v25_stat_unl_done_s),
+				&be->flm.v25.unl_ignore, 1,
+				sizeof(struct flm_v25_stat_unl_ignore_s),
+				&be->flm.v25.rel_done, 1, sizeof(struct flm_v25_stat_rel_done_s),
+				&be->flm.v25.rel_ignore, 1,
+				sizeof(struct flm_v25_stat_rel_ignore_s),
+				&be->flm.v25.aul_done, 1, sizeof(struct flm_v25_stat_aul_done_s),
+				&be->flm.v25.aul_ignore, 1,
+				sizeof(struct flm_v25_stat_aul_ignore_s),
+				&be->flm.v25.aul_fail, 1, sizeof(struct flm_v25_stat_aul_fail_s),
+				&be->flm.v25.tul_done, 1, sizeof(struct flm_v25_stat_tul_done_s),
+				&be->flm.v25.flows, 1, sizeof(struct flm_v25_stat_flows_s),
+				&be->flm.v25.prb_done, 1, sizeof(struct flm_v25_stat_prb_done_s),
+				&be->flm.v25.prb_ignore, 1,
+				sizeof(struct flm_v25_stat_prb_ignore_s),
+				&be->flm.v25.sta_done, 1, sizeof(struct flm_v25_stat_sta_done_s),
+				&be->flm.v25.inf_done, 1, sizeof(struct flm_v25_stat_inf_done_s),
+				&be->flm.v25.inf_skip, 1, sizeof(struct flm_v25_stat_inf_skip_s),
+				&be->flm.v25.pck_hit, 1, sizeof(struct flm_v25_stat_pck_hit_s),
+				&be->flm.v25.pck_miss, 1, sizeof(struct flm_v25_stat_pck_miss_s),
+				&be->flm.v25.pck_unh, 1, sizeof(struct flm_v25_stat_pck_unh_s),
+				&be->flm.v25.pck_dis, 1, sizeof(struct flm_v25_stat_pck_dis_s),
+				&be->flm.v25.csh_hit, 1, sizeof(struct flm_v25_stat_csh_hit_s),
+				&be->flm.v25.csh_miss, 1, sizeof(struct flm_v25_stat_csh_miss_s),
+				&be->flm.v25.csh_unh, 1, sizeof(struct flm_v25_stat_csh_unh_s),
+				&be->flm.v25.cuc_start, 1, sizeof(struct flm_v25_stat_cuc_start_s),
+				&be->flm.v25.cuc_move, 1, sizeof(struct flm_v25_stat_cuc_move_s),
+				&be->flm.v25.scan, 1, sizeof(struct flm_v25_scan_s),
+				&be->flm.v25.scrub, be->flm.nb_scrub_profiles,
+				sizeof(struct flm_v25_scrub_s)))
+			return -1;
+
+		break;
+
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+void hw_mod_flm_free(struct flow_api_backend_s *be)
+{
+	if (be->flm.base) {
+		free(be->flm.base);
+		be->flm.base = NULL;
+	}
+}
+
+int hw_mod_flm_reset(struct flow_api_backend_s *be)
+{
+	/* Zero entire cache area */
+	zero_module_cache((struct common_func_s *)(&be->flm));
+
+	NT_LOG(DBG, FILTER, "INIT FLM\n");
+	hw_mod_flm_control_set(be, HW_FLM_CONTROL_SPLIT_SDRAM_USAGE, 0x10);
+
+	hw_mod_flm_control_flush(be);
+	hw_mod_flm_scrub_flush(be, 0, ALL_ENTRIES);
+	hw_mod_flm_scan_flush(be);
+	hw_mod_flm_rcp_flush(be, 0, ALL_ENTRIES);
+
+	return 0;
+}
+
+int hw_mod_flm_control_flush(struct flow_api_backend_s *be)
+{
+	return be->iface->flm_control_flush(be->be_dev, &be->flm);
+}
+
+static int hw_mod_flm_control_mod(struct flow_api_backend_s *be, enum hw_flm_e field,
+	uint32_t *value, int get)
+{
+	switch (_VER_) {
+	case 25:
+		switch (field) {
+		case HW_FLM_CONTROL_PRESET_ALL:
+			if (get)
+				return UNSUP_FIELD;
+
+			memset(be->flm.v25.control, (uint8_t)*value,
+				sizeof(struct flm_v25_control_s));
+			break;
+
+		case HW_FLM_CONTROL_ENABLE:
+			GET_SET(be->flm.v25.control->enable, value);
+			break;
+
+		case HW_FLM_CONTROL_INIT:
+			GET_SET(be->flm.v25.control->init, value);
+			break;
+
+		case HW_FLM_CONTROL_LDS:
+			GET_SET(be->flm.v25.control->lds, value);
+			break;
+
+		case HW_FLM_CONTROL_LFS:
+			GET_SET(be->flm.v25.control->lfs, value);
+			break;
+
+		case HW_FLM_CONTROL_LIS:
+			GET_SET(be->flm.v25.control->lis, value);
+			break;
+
+		case HW_FLM_CONTROL_UDS:
+			GET_SET(be->flm.v25.control->uds, value);
+			break;
+
+		case HW_FLM_CONTROL_UIS:
+			GET_SET(be->flm.v25.control->uis, value);
+			break;
+
+		case HW_FLM_CONTROL_RDS:
+			GET_SET(be->flm.v25.control->rds, value);
+			break;
+
+		case HW_FLM_CONTROL_RIS:
+			GET_SET(be->flm.v25.control->ris, value);
+			break;
+
+		case HW_FLM_CONTROL_PDS:
+			GET_SET(be->flm.v25.control->pds, value);
+			break;
+
+		case HW_FLM_CONTROL_PIS:
+			GET_SET(be->flm.v25.control->pis, value);
+			break;
+
+		case HW_FLM_CONTROL_CRCWR:
+			GET_SET(be->flm.v25.control->crcwr, value);
+			break;
+
+		case HW_FLM_CONTROL_CRCRD:
+			GET_SET(be->flm.v25.control->crcrd, value);
+			break;
+
+		case HW_FLM_CONTROL_RBL:
+			GET_SET(be->flm.v25.control->rbl, value);
+			break;
+
+		case HW_FLM_CONTROL_EAB:
+			GET_SET(be->flm.v25.control->eab, value);
+			break;
+
+		case HW_FLM_CONTROL_SPLIT_SDRAM_USAGE:
+			GET_SET(be->flm.v25.control->split_sdram_usage, value);
+			break;
+
+		default:
+			return UNSUP_FIELD;
+		}
+
+		break;
+
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+int hw_mod_flm_control_set(struct flow_api_backend_s *be, enum hw_flm_e field, uint32_t value)
+{
+	return hw_mod_flm_control_mod(be, field, &value, 0);
+}
+
+int hw_mod_flm_scan_flush(struct flow_api_backend_s *be)
+{
+	return be->iface->flm_scan_flush(be->be_dev, &be->flm);
+}
+
+int hw_mod_flm_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->flm.nb_categories;
+
+	if ((unsigned int)(start_idx + count) > be->flm.nb_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->flm_rcp_flush(be->be_dev, &be->flm, start_idx, count);
+}
+
+int hw_mod_flm_scrub_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->flm.nb_scrub_profiles;
+
+	if ((unsigned int)(start_idx + count) > be->flm.nb_scrub_profiles)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->flm_scrub_flush(be->be_dev, &be->flm, start_idx, count);
+}
-- 
2.45.0


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

* [PATCH v1 26/31] net/ntnic: add hasher (HSH) FPGA module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (30 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 25/31] net/ntnic: add flow matcher (FLM) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 27/31] net/ntnic: add queue select (QSL) " Serhii Iliushyk
                   ` (19 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Hasher module calculates a configurable hash value
to be used internally by the FPGA.
The module support both Toeplitz and NT-hash.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    | 36 ++++++++
 drivers/net/ntnic/meson.build                 |  1 +
 drivers/net/ntnic/nthw/flow_api/flow_api.c    |  3 +
 .../nthw/flow_api/hw_mod/hw_mod_backend.c     |  1 +
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_hsh.c   | 84 +++++++++++++++++++
 .../supported/nthw_fpga_9563_055_049_0000.c   | 39 ++++++++-
 6 files changed, 163 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh.c

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 3933d4bf53..6bf651272f 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -493,6 +493,41 @@ struct hsh_func_s {
 		struct hw_mod_hsh_v5_s v5;
 	};
 };
+enum hw_hsh_e {
+	/* functions */
+	HW_HSH_RCP_PRESET_ALL = 0,
+	HW_HSH_RCP_COMPARE,
+	HW_HSH_RCP_FIND,
+	/* fields */
+	HW_HSH_RCP_LOAD_DIST_TYPE = FIELD_START_INDEX,
+	HW_HSH_RCP_MAC_PORT_MASK,
+	HW_HSH_RCP_SORT,
+	HW_HSH_RCP_QW0_PE,
+	HW_HSH_RCP_QW0_OFS,
+	HW_HSH_RCP_QW4_PE,
+	HW_HSH_RCP_QW4_OFS,
+	HW_HSH_RCP_W8_PE,
+	HW_HSH_RCP_W8_OFS,
+	HW_HSH_RCP_W8_SORT,
+	HW_HSH_RCP_W9_PE,
+	HW_HSH_RCP_W9_OFS,
+	HW_HSH_RCP_W9_SORT,
+	HW_HSH_RCP_W9_P,
+	HW_HSH_RCP_P_MASK,
+	HW_HSH_RCP_WORD_MASK,
+	HW_HSH_RCP_SEED,
+	HW_HSH_RCP_TNL_P,
+	HW_HSH_RCP_HSH_VALID,
+	HW_HSH_RCP_HSH_TYPE,
+	HW_HSH_RCP_TOEPLITZ,
+	HW_HSH_RCP_K,
+	HW_HSH_RCP_AUTO_IPV4_MASK
+};
+bool hw_mod_hsh_present(struct flow_api_backend_s *be);
+int hw_mod_hsh_alloc(struct flow_api_backend_s *be);
+void hw_mod_hsh_free(struct flow_api_backend_s *be);
+int hw_mod_hsh_reset(struct flow_api_backend_s *be);
+int hw_mod_hsh_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
 
 struct qsl_func_s {
 	COMMON_FUNC_INFO_S;
@@ -685,6 +720,7 @@ struct flow_api_backend_s {
 	struct cat_func_s cat;
 	struct km_func_s km;
 	struct flm_func_s flm;
+	struct hsh_func_s hsh;
 
 	/* NIC attributes */
 	unsigned int num_phy_ports;
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 9af7e3d813..18aafc57f0 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -51,6 +51,7 @@ sources = files(
         'nthw/flow_api/hw_mod/hw_mod_backend.c',
         'nthw/flow_api/hw_mod/hw_mod_cat.c',
         'nthw/flow_api/hw_mod/hw_mod_flm.c',
+        'nthw/flow_api/hw_mod/hw_mod_hsh.c',
         'nthw/flow_api/hw_mod/hw_mod_km.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_csu.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
index d39bdc9936..b43c8fef1a 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -290,6 +290,9 @@ struct flow_nic_dev *flow_api_create(uint8_t adapter_no, const struct flow_api_b
 	if (init_resource_elements(ndev, RES_KM_CATEGORY, ndev->be.km.nb_categories))
 		goto err_exit;
 
+	if (init_resource_elements(ndev, RES_HSH_RCP, ndev->be.hsh.nb_rcp))
+		goto err_exit;
+
 	if (init_resource_elements(ndev, RES_SLC_LR_RCP, ndev->be.max_categories))
 		goto err_exit;
 
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
index fe66493336..3ccc14c4ce 100644
--- a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
@@ -20,6 +20,7 @@ static const struct {
 	{ "CAT", hw_mod_cat_alloc, hw_mod_cat_free, hw_mod_cat_reset, hw_mod_cat_present },
 	{ "KM", hw_mod_km_alloc, hw_mod_km_free, hw_mod_km_reset, hw_mod_km_present },
 	{ "FLM", hw_mod_flm_alloc, hw_mod_flm_free, hw_mod_flm_reset, hw_mod_flm_present },
+	{ "HSH", hw_mod_hsh_alloc, hw_mod_hsh_free, hw_mod_hsh_reset, hw_mod_hsh_present },
 };
 #define MOD_COUNT (ARRAY_SIZE(module))
 
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh.c
new file mode 100644
index 0000000000..77dfbb5374
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_hsh.c
@@ -0,0 +1,84 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hw_mod_backend.h"
+
+#define _MOD_ "HSH"
+#define _VER_ be->hsh.ver
+
+bool hw_mod_hsh_present(struct flow_api_backend_s *be)
+{
+	return be->iface->get_hsh_present(be->be_dev);
+}
+
+int hw_mod_hsh_alloc(struct flow_api_backend_s *be)
+{
+	int nb;
+	_VER_ = be->iface->get_hsh_version(be->be_dev);
+	NT_LOG(DBG, FILTER, "HSH MODULE VERSION  %i.%i\n", VER_MAJOR(_VER_), VER_MINOR(_VER_));
+
+	/* detect number of HSH categories supported by FPGA */
+	nb = be->iface->get_nb_hsh_categories(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(hsh_categories);
+
+	be->hsh.nb_rcp = (uint32_t)nb;
+
+	/* detect if Toeplitz hashing function is supported by FPGA */
+	nb = be->iface->get_nb_hsh_toeplitz(be->be_dev);
+
+	if (nb < 0)
+		return COUNT_ERROR(hsh_toeplitz);
+
+	be->hsh.toeplitz = (uint32_t)nb;
+
+	switch (_VER_) {
+	case 5:
+		if (!callocate_mod((struct common_func_s *)&be->hsh, 1, &be->hsh.v5.rcp,
+				be->hsh.nb_rcp, sizeof(struct hsh_v5_rcp_s)))
+			return -1;
+
+		break;
+
+	/* end case 5 */
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+void hw_mod_hsh_free(struct flow_api_backend_s *be)
+{
+	if (be->hsh.base) {
+		free(be->hsh.base);
+		be->hsh.base = NULL;
+	}
+}
+
+int hw_mod_hsh_reset(struct flow_api_backend_s *be)
+{
+	/* Zero entire cache area */
+	zero_module_cache((struct common_func_s *)(&be->hsh));
+
+	NT_LOG(DBG, FILTER, "INIT HSH RCP\n");
+	return hw_mod_hsh_rcp_flush(be, 0, be->hsh.nb_rcp);
+}
+
+int hw_mod_hsh_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->hsh.nb_rcp;
+
+	if ((start_idx + count) > (int)be->hsh.nb_rcp)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->hsh_rcp_flush(be->be_dev, &be->hsh, start_idx, count);
+}
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
index a003334a23..4317da8094 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
@@ -544,6 +544,42 @@ static nthw_fpga_register_init_s hif_registers[] = {
 	{ HIF_UUID3, 176, 32, NTHW_FPGA_REG_TYPE_RO, 462142918, 1, hif_uuid3_fields },
 };
 
+static nthw_fpga_field_init_s hsh_rcp_ctrl_fields[] = {
+	{ HSH_RCP_CTRL_ADR, 4, 0, 0x0000 },
+	{ HSH_RCP_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s hsh_rcp_data_fields[] = {
+	{ HSH_RCP_DATA_AUTO_IPV4_MASK, 1, 742, 0x0000 },
+	{ HSH_RCP_DATA_HSH_TYPE, 5, 416, 0x0000 },
+	{ HSH_RCP_DATA_HSH_VALID, 1, 415, 0x0000 },
+	{ HSH_RCP_DATA_K, 320, 422, 0x0000 },
+	{ HSH_RCP_DATA_LOAD_DIST_TYPE, 2, 0, 0x0000 },
+	{ HSH_RCP_DATA_MAC_PORT_MASK, 2, 2, 0x0000 },
+	{ HSH_RCP_DATA_P_MASK, 1, 61, 0x0000 },
+	{ HSH_RCP_DATA_QW0_OFS, 8, 11, 0x0000 },
+	{ HSH_RCP_DATA_QW0_PE, 5, 6, 0x0000 },
+	{ HSH_RCP_DATA_QW4_OFS, 8, 24, 0x0000 },
+	{ HSH_RCP_DATA_QW4_PE, 5, 19, 0x0000 },
+	{ HSH_RCP_DATA_SEED, 32, 382, 0x0000 },
+	{ HSH_RCP_DATA_SORT, 2, 4, 0x0000 },
+	{ HSH_RCP_DATA_TNL_P, 1, 414, 0x0000 },
+	{ HSH_RCP_DATA_TOEPLITZ, 1, 421, 0x0000 },
+	{ HSH_RCP_DATA_W8_OFS, 8, 37, 0x0000 },
+	{ HSH_RCP_DATA_W8_PE, 5, 32, 0x0000 },
+	{ HSH_RCP_DATA_W8_SORT, 1, 45, 0x0000 },
+	{ HSH_RCP_DATA_W9_OFS, 8, 51, 0x0000 },
+	{ HSH_RCP_DATA_W9_P, 1, 60, 0x0000 },
+	{ HSH_RCP_DATA_W9_PE, 5, 46, 0x0000 },
+	{ HSH_RCP_DATA_W9_SORT, 1, 59, 0x0000 },
+	{ HSH_RCP_DATA_WORD_MASK, 320, 62, 0x0000 },
+};
+
+static nthw_fpga_register_init_s hsh_registers[] = {
+	{ HSH_RCP_CTRL, 0, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, hsh_rcp_ctrl_fields },
+	{ HSH_RCP_DATA, 1, 743, NTHW_FPGA_REG_TYPE_WO, 0, 23, hsh_rcp_data_fields },
+};
+
 static nthw_fpga_field_init_s iic_adr_fields[] = {
 	{ IIC_ADR_SLV_ADR, 7, 1, 0 },
 };
@@ -1398,6 +1434,7 @@ static nthw_fpga_module_init_s fpga_modules[] = {
 		gpio_phy_registers
 	},
 	{ MOD_HIF, 0, MOD_HIF, 0, 0, NTHW_FPGA_BUS_TYPE_PCI, 0, 18, hif_registers },
+	{ MOD_HSH, 0, MOD_HSH, 0, 5, NTHW_FPGA_BUS_TYPE_RAB1, 1536, 2, hsh_registers },
 	{ MOD_IIC, 0, MOD_IIC, 0, 1, NTHW_FPGA_BUS_TYPE_RAB0, 768, 22, iic_registers },
 	{ MOD_IIC, 1, MOD_IIC, 0, 1, NTHW_FPGA_BUS_TYPE_RAB0, 896, 22, iic_registers },
 	{ MOD_IIC, 2, MOD_IIC, 0, 1, NTHW_FPGA_BUS_TYPE_RAB0, 24832, 22, iic_registers },
@@ -1580,5 +1617,5 @@ static nthw_fpga_prod_param_s product_parameters[] = {
 };
 
 nthw_fpga_prod_init_s nthw_fpga_9563_055_049_0000 = {
-	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 17, fpga_modules,
+	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 18, fpga_modules,
 };
-- 
2.45.0


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

* [PATCH v1 27/31] net/ntnic: add queue select (QSL) FPGA module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (31 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 26/31] net/ntnic: add hasher (HSH) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 28/31] net/ntnic: add slicer (SLC LR) " Serhii Iliushyk
                   ` (18 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Queue Selector module directs packets to a given destination
which includes host queues, physical ports, exceptions paths, and discard.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    |  37 ++++
 drivers/net/ntnic/meson.build                 |   1 +
 drivers/net/ntnic/nthw/flow_api/flow_api.c    |  14 ++
 .../nthw/flow_api/hw_mod/hw_mod_backend.c     |   1 +
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_qsl.c   | 170 ++++++++++++++++++
 .../supported/nthw_fpga_9563_055_049_0000.c   |  57 +++++-
 6 files changed, 279 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl.c

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 6bf651272f..13e0d1731e 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -537,6 +537,42 @@ struct qsl_func_s {
 		struct hw_mod_qsl_v7_s v7;
 	};
 };
+enum hw_qsl_e {
+	/* functions */
+	HW_QSL_RCP_PRESET_ALL = 0,
+	HW_QSL_RCP_COMPARE,
+	HW_QSL_RCP_FIND,
+	HW_QSL_QST_PRESET_ALL,
+	/* fields */
+	HW_QSL_RCP_DISCARD = FIELD_START_INDEX,
+	HW_QSL_RCP_DROP,
+	HW_QSL_RCP_TBL_LO,
+	HW_QSL_RCP_TBL_HI,
+	HW_QSL_RCP_TBL_IDX,
+	HW_QSL_RCP_TBL_MSK,
+	HW_QSL_RCP_LR,
+	HW_QSL_RCP_TSA,
+	HW_QSL_RCP_VLI,
+	HW_QSL_QST_QUEUE,
+	HW_QSL_QST_EN,	/* Alias: HW_QSL_QST_QEN */
+	HW_QSL_QST_TX_PORT,
+	HW_QSL_QST_LRE,
+	HW_QSL_QST_TCI,
+	HW_QSL_QST_VEN,
+	HW_QSL_QEN_EN,
+	HW_QSL_UNMQ_DEST_QUEUE,
+	HW_QSL_UNMQ_EN,
+};
+bool hw_mod_qsl_present(struct flow_api_backend_s *be);
+int hw_mod_qsl_alloc(struct flow_api_backend_s *be);
+void hw_mod_qsl_free(struct flow_api_backend_s *be);
+int hw_mod_qsl_reset(struct flow_api_backend_s *be);
+int hw_mod_qsl_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_qsl_qst_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_qsl_qen_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_qsl_unmq_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_qsl_unmq_set(struct flow_api_backend_s *be, enum hw_qsl_e field, uint32_t index,
+	uint32_t value);
 
 struct slc_lr_func_s {
 	COMMON_FUNC_INFO_S;
@@ -721,6 +757,7 @@ struct flow_api_backend_s {
 	struct km_func_s km;
 	struct flm_func_s flm;
 	struct hsh_func_s hsh;
+	struct qsl_func_s qsl;
 
 	/* NIC attributes */
 	unsigned int num_phy_ports;
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 18aafc57f0..02981ef987 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -53,6 +53,7 @@ sources = files(
         'nthw/flow_api/hw_mod/hw_mod_flm.c',
         'nthw/flow_api/hw_mod/hw_mod_hsh.c',
         'nthw/flow_api/hw_mod/hw_mod_km.c',
+        'nthw/flow_api/hw_mod/hw_mod_qsl.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_csu.c',
         'nthw/flow_filter/flow_nthw_flm.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
index b43c8fef1a..5d6571310c 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -144,6 +144,14 @@ int flow_delete_eth_dev(struct flow_eth_dev *eth_dev)
 	/* delete all created flows from this device */
 	pthread_mutex_lock(&ndev->mtx);
 
+	/*
+	 * remove unmatched queue if setup in QSL
+	 * remove exception queue setting in QSL UNM
+	 */
+	hw_mod_qsl_unmq_set(&ndev->be, HW_QSL_UNMQ_DEST_QUEUE, eth_dev->port, 0);
+	hw_mod_qsl_unmq_set(&ndev->be, HW_QSL_UNMQ_EN, eth_dev->port, 0);
+	hw_mod_qsl_unmq_flush(&ndev->be, eth_dev->port, 1);
+
 #ifdef FLOW_DEBUG
 	ndev->be.iface->set_debug_mode(ndev->be.be_dev, FLOW_BACKEND_DEBUG_MODE_NONE);
 #endif
@@ -293,6 +301,12 @@ struct flow_nic_dev *flow_api_create(uint8_t adapter_no, const struct flow_api_b
 	if (init_resource_elements(ndev, RES_HSH_RCP, ndev->be.hsh.nb_rcp))
 		goto err_exit;
 
+	if (init_resource_elements(ndev, RES_QSL_RCP, ndev->be.qsl.nb_rcp_categories))
+		goto err_exit;
+
+	if (init_resource_elements(ndev, RES_QSL_QST, ndev->be.qsl.nb_qst_entries))
+		goto err_exit;
+
 	if (init_resource_elements(ndev, RES_SLC_LR_RCP, ndev->be.max_categories))
 		goto err_exit;
 
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
index 3ccc14c4ce..4f16235a67 100644
--- a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
@@ -21,6 +21,7 @@ static const struct {
 	{ "KM", hw_mod_km_alloc, hw_mod_km_free, hw_mod_km_reset, hw_mod_km_present },
 	{ "FLM", hw_mod_flm_alloc, hw_mod_flm_free, hw_mod_flm_reset, hw_mod_flm_present },
 	{ "HSH", hw_mod_hsh_alloc, hw_mod_hsh_free, hw_mod_hsh_reset, hw_mod_hsh_present },
+	{ "QSL", hw_mod_qsl_alloc, hw_mod_qsl_free, hw_mod_qsl_reset, hw_mod_qsl_present },
 };
 #define MOD_COUNT (ARRAY_SIZE(module))
 
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl.c
new file mode 100644
index 0000000000..f69717cf84
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_qsl.c
@@ -0,0 +1,170 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hw_mod_backend.h"
+
+#define _MOD_ "QSL"
+#define _VER_ be->qsl.ver
+
+#define QSL_QEN_ENTRIES 32
+#define QSL_QNMQ_ENTRIES 256
+
+bool hw_mod_qsl_present(struct flow_api_backend_s *be)
+{
+	return be->iface->get_qsl_present(be->be_dev);
+}
+
+int hw_mod_qsl_alloc(struct flow_api_backend_s *be)
+{
+	int nb;
+	_VER_ = be->iface->get_qsl_version(be->be_dev);
+	NT_LOG(DBG, FILTER, "QSL MODULE VERSION  %i.%i\n", VER_MAJOR(_VER_), VER_MINOR(_VER_));
+
+	nb = be->iface->get_nb_qsl_categories(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(qsl_categories);
+
+	be->qsl.nb_rcp_categories = (uint32_t)nb;
+
+	nb = be->iface->get_nb_qsl_qst_entries(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(qsl_qst_entries);
+
+	be->qsl.nb_qst_entries = (uint32_t)nb;
+
+	switch (_VER_) {
+	case 7:
+		if (!callocate_mod((struct common_func_s *)&be->qsl, 4, &be->qsl.v7.rcp,
+				be->qsl.nb_rcp_categories, sizeof(struct qsl_v7_rcp_s),
+				&be->qsl.v7.qst, be->qsl.nb_qst_entries,
+				sizeof(struct qsl_v7_qst_s), &be->qsl.v7.qen, QSL_QEN_ENTRIES,
+				sizeof(struct qsl_v7_qen_s), &be->qsl.v7.unmq, QSL_QNMQ_ENTRIES,
+				sizeof(struct qsl_v7_unmq_s)))
+			return -1;
+
+		break;
+
+	/* end case 7 */
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+void hw_mod_qsl_free(struct flow_api_backend_s *be)
+{
+	if (be->qsl.base) {
+		free(be->qsl.base);
+		be->qsl.base = NULL;
+	}
+}
+
+int hw_mod_qsl_reset(struct flow_api_backend_s *be)
+{
+	/* Zero entire cache area */
+	zero_module_cache((struct common_func_s *)(&be->qsl));
+
+	NT_LOG(DBG, FILTER, "INIT QSL RCP\n");
+	hw_mod_qsl_rcp_flush(be, 0, ALL_ENTRIES);
+
+	NT_LOG(DBG, FILTER, "INIT QSL QST\n");
+	hw_mod_qsl_qst_flush(be, 0, ALL_ENTRIES);
+
+	NT_LOG(DBG, FILTER, "INIT QSL QEN\n");
+	hw_mod_qsl_qen_flush(be, 0, ALL_ENTRIES);
+
+	NT_LOG(DBG, FILTER, "INIT QSL UNMQ\n");
+	be->iface->qsl_unmq_flush(be->be_dev, &be->qsl, 0, 256);
+
+	return 0;
+}
+
+int hw_mod_qsl_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->qsl.nb_rcp_categories;
+
+	if ((unsigned int)(start_idx + count) > be->qsl.nb_rcp_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->qsl_rcp_flush(be->be_dev, &be->qsl, start_idx, count);
+}
+
+int hw_mod_qsl_qst_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->qsl.nb_qst_entries;
+
+	if ((unsigned int)(start_idx + count) > be->qsl.nb_qst_entries)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->qsl_qst_flush(be->be_dev, &be->qsl, start_idx, count);
+}
+
+int hw_mod_qsl_qen_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = QSL_QEN_ENTRIES;
+
+	if ((start_idx + count) > QSL_QEN_ENTRIES)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->qsl_qen_flush(be->be_dev, &be->qsl, start_idx, count);
+}
+
+int hw_mod_qsl_unmq_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = QSL_QNMQ_ENTRIES;
+
+	if ((start_idx + count) > QSL_QNMQ_ENTRIES)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->qsl_unmq_flush(be->be_dev, &be->qsl, start_idx, count);
+}
+
+static int hw_mod_qsl_unmq_mod(struct flow_api_backend_s *be, enum hw_qsl_e field, uint32_t index,
+	uint32_t *value, int get)
+{
+	if (index >= QSL_QNMQ_ENTRIES)
+		return INDEX_TOO_LARGE;
+
+	switch (_VER_) {
+	case 7:
+		switch (field) {
+		case HW_QSL_UNMQ_DEST_QUEUE:
+			GET_SET(be->qsl.v7.unmq[index].dest_queue, value);
+			break;
+
+		case HW_QSL_UNMQ_EN:
+			GET_SET(be->qsl.v7.unmq[index].en, value);
+			break;
+
+		default:
+			return UNSUP_FIELD;
+		}
+
+		break;
+
+	/* end case 7 */
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+int hw_mod_qsl_unmq_set(struct flow_api_backend_s *be, enum hw_qsl_e field, uint32_t index,
+	uint32_t value)
+{
+	return hw_mod_qsl_unmq_mod(be, field, index, &value, 0);
+}
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
index 4317da8094..7eeb210b80 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
@@ -1297,6 +1297,60 @@ static nthw_fpga_register_init_s pci_wr_tg_registers[] = {
 	{ PCI_WR_TG_TG_WR_RUN, 4, 16, NTHW_FPGA_REG_TYPE_WO, 0, 1, pci_wr_tg_tg_wr_run_fields },
 };
 
+static nthw_fpga_field_init_s qsl_qen_ctrl_fields[] = {
+	{ QSL_QEN_CTRL_ADR, 5, 0, 0x0000 },
+	{ QSL_QEN_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s qsl_qen_data_fields[] = {
+	{ QSL_QEN_DATA_EN, 4, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s qsl_qst_ctrl_fields[] = {
+	{ QSL_QST_CTRL_ADR, 12, 0, 0x0000 },
+	{ QSL_QST_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s qsl_qst_data_fields[] = {
+	{ QSL_QST_DATA_LRE, 1, 9, 0x0000 }, { QSL_QST_DATA_QEN, 1, 7, 0x0000 },
+	{ QSL_QST_DATA_QUEUE, 7, 0, 0x0000 }, { QSL_QST_DATA_TCI, 16, 10, 0x0000 },
+	{ QSL_QST_DATA_TX_PORT, 1, 8, 0x0000 }, { QSL_QST_DATA_VEN, 1, 26, 0x0000 },
+};
+
+static nthw_fpga_field_init_s qsl_rcp_ctrl_fields[] = {
+	{ QSL_RCP_CTRL_ADR, 5, 0, 0x0000 },
+	{ QSL_RCP_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s qsl_rcp_data_fields[] = {
+	{ QSL_RCP_DATA_DISCARD, 1, 0, 0x0000 }, { QSL_RCP_DATA_DROP, 2, 1, 0x0000 },
+	{ QSL_RCP_DATA_LR, 2, 51, 0x0000 }, { QSL_RCP_DATA_TBL_HI, 12, 15, 0x0000 },
+	{ QSL_RCP_DATA_TBL_IDX, 12, 27, 0x0000 }, { QSL_RCP_DATA_TBL_LO, 12, 3, 0x0000 },
+	{ QSL_RCP_DATA_TBL_MSK, 12, 39, 0x0000 }, { QSL_RCP_DATA_TSA, 1, 53, 0x0000 },
+	{ QSL_RCP_DATA_VLI, 2, 54, 0x0000 },
+};
+
+static nthw_fpga_field_init_s qsl_unmq_ctrl_fields[] = {
+	{ QSL_UNMQ_CTRL_ADR, 1, 0, 0x0000 },
+	{ QSL_UNMQ_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s qsl_unmq_data_fields[] = {
+	{ QSL_UNMQ_DATA_DEST_QUEUE, 7, 0, 0x0000 },
+	{ QSL_UNMQ_DATA_EN, 1, 7, 0x0000 },
+};
+
+static nthw_fpga_register_init_s qsl_registers[] = {
+	{ QSL_QEN_CTRL, 4, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, qsl_qen_ctrl_fields },
+	{ QSL_QEN_DATA, 5, 4, NTHW_FPGA_REG_TYPE_WO, 0, 1, qsl_qen_data_fields },
+	{ QSL_QST_CTRL, 2, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, qsl_qst_ctrl_fields },
+	{ QSL_QST_DATA, 3, 27, NTHW_FPGA_REG_TYPE_WO, 0, 6, qsl_qst_data_fields },
+	{ QSL_RCP_CTRL, 0, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, qsl_rcp_ctrl_fields },
+	{ QSL_RCP_DATA, 1, 56, NTHW_FPGA_REG_TYPE_WO, 0, 9, qsl_rcp_data_fields },
+	{ QSL_UNMQ_CTRL, 6, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, qsl_unmq_ctrl_fields },
+	{ QSL_UNMQ_DATA, 7, 8, NTHW_FPGA_REG_TYPE_WO, 0, 2, qsl_unmq_data_fields },
+};
+
 static nthw_fpga_field_init_s rac_dbg_ctrl_fields[] = {
 	{ RAC_DBG_CTRL_C, 32, 0, 0x0000 },
 };
@@ -1456,6 +1510,7 @@ static nthw_fpga_module_init_s fpga_modules[] = {
 		MOD_PCI_WR_TG, 0, MOD_PCI_WR_TG, 0, 1, NTHW_FPGA_BUS_TYPE_RAB0, 2304, 7,
 		pci_wr_tg_registers
 	},
+	{ MOD_QSL, 0, MOD_QSL, 0, 7, NTHW_FPGA_BUS_TYPE_RAB1, 1792, 8, qsl_registers },
 	{ MOD_RAC, 0, MOD_RAC, 3, 0, NTHW_FPGA_BUS_TYPE_PCI, 8192, 14, rac_registers },
 	{ MOD_RST9563, 0, MOD_RST9563, 0, 5, NTHW_FPGA_BUS_TYPE_RAB0, 1024, 5, rst9563_registers },
 };
@@ -1617,5 +1672,5 @@ static nthw_fpga_prod_param_s product_parameters[] = {
 };
 
 nthw_fpga_prod_init_s nthw_fpga_9563_055_049_0000 = {
-	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 18, fpga_modules,
+	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 19, fpga_modules,
 };
-- 
2.45.0


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

* [PATCH v1 28/31] net/ntnic: add slicer (SLC LR) FPGA module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (32 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 27/31] net/ntnic: add queue select (QSL) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 29/31] net/ntnic: add packet descriptor builder (PDB) " Serhii Iliushyk
                   ` (17 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Slicer for Local Retransmit module can cut of the head a packet
before the packet leaves the FPGA RX pipeline.
This is used when the TX pipeline is configured
to add a new head in the packet.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    | 21 ++++++
 drivers/net/ntnic/meson.build                 |  1 +
 .../nthw/flow_api/hw_mod/hw_mod_backend.c     |  4 ++
 .../nthw/flow_api/hw_mod/hw_mod_slc_lr.c      | 65 +++++++++++++++++++
 4 files changed, 91 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr.c

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 13e0d1731e..b28192e682 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -7,6 +7,7 @@
 #define _HW_MOD_BACKEND_H_
 
 #include <stdbool.h>
+#include <string.h>
 
 #include "ntlog.h"
 
@@ -580,6 +581,25 @@ struct slc_lr_func_s {
 		struct hw_mod_slc_lr_v2_s v2;
 	};
 };
+enum hw_slc_lr_e {
+	/* functions */
+	HW_SLC_LR_RCP_PRESET_ALL = 0,
+	HW_SLC_LR_RCP_COMPARE,
+	HW_SLC_LR_RCP_FIND,
+	/* fields */
+	HW_SLC_LR_RCP_HEAD_SLC_EN = FIELD_START_INDEX,
+	HW_SLC_LR_RCP_HEAD_DYN,
+	HW_SLC_LR_RCP_HEAD_OFS,
+	HW_SLC_LR_RCP_TAIL_SLC_EN,
+	HW_SLC_LR_RCP_TAIL_DYN,
+	HW_SLC_LR_RCP_TAIL_OFS,
+	HW_SLC_LR_RCP_PCAP
+};
+bool hw_mod_slc_lr_present(struct flow_api_backend_s *be);
+int hw_mod_slc_lr_alloc(struct flow_api_backend_s *be);
+void hw_mod_slc_lr_free(struct flow_api_backend_s *be);
+int hw_mod_slc_lr_reset(struct flow_api_backend_s *be);
+int hw_mod_slc_lr_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
 
 struct pdb_func_s {
 	COMMON_FUNC_INFO_S;
@@ -758,6 +778,7 @@ struct flow_api_backend_s {
 	struct flm_func_s flm;
 	struct hsh_func_s hsh;
 	struct qsl_func_s qsl;
+	struct slc_lr_func_s slc_lr;
 
 	/* NIC attributes */
 	unsigned int num_phy_ports;
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 02981ef987..4caee8ac41 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -54,6 +54,7 @@ sources = files(
         'nthw/flow_api/hw_mod/hw_mod_hsh.c',
         'nthw/flow_api/hw_mod/hw_mod_km.c',
         'nthw/flow_api/hw_mod/hw_mod_qsl.c',
+        'nthw/flow_api/hw_mod/hw_mod_slc_lr.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_csu.c',
         'nthw/flow_filter/flow_nthw_flm.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
index 4f16235a67..6b0ea2a4a6 100644
--- a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
@@ -22,6 +22,10 @@ static const struct {
 	{ "FLM", hw_mod_flm_alloc, hw_mod_flm_free, hw_mod_flm_reset, hw_mod_flm_present },
 	{ "HSH", hw_mod_hsh_alloc, hw_mod_hsh_free, hw_mod_hsh_reset, hw_mod_hsh_present },
 	{ "QSL", hw_mod_qsl_alloc, hw_mod_qsl_free, hw_mod_qsl_reset, hw_mod_qsl_present },
+	{
+		"SLC LR", hw_mod_slc_lr_alloc, hw_mod_slc_lr_free, hw_mod_slc_lr_reset,
+		hw_mod_slc_lr_present
+	},
 };
 #define MOD_COUNT (ARRAY_SIZE(module))
 
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr.c
new file mode 100644
index 0000000000..d95352ec67
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_slc_lr.c
@@ -0,0 +1,65 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "hw_mod_backend.h"
+
+#define _MOD_ "SLC_LR"
+#define _VER_ be->slc_lr.ver
+
+bool hw_mod_slc_lr_present(struct flow_api_backend_s *be)
+{
+	return be->iface->get_slc_lr_present(be->be_dev);
+}
+
+int hw_mod_slc_lr_alloc(struct flow_api_backend_s *be)
+{
+	_VER_ = be->iface->get_slc_lr_version(be->be_dev);
+	NT_LOG(DBG, FILTER, "SLC LR MODULE VERSION  %i.%i\n", VER_MAJOR(_VER_), VER_MINOR(_VER_));
+
+	switch (_VER_) {
+	case 2:
+		if (!callocate_mod((struct common_func_s *)&be->slc_lr, 1, &be->slc_lr.v2.rcp,
+				be->max_categories, sizeof(struct slc_lr_v2_rcp_s)))
+			return -1;
+
+		break;
+
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+void hw_mod_slc_lr_free(struct flow_api_backend_s *be)
+{
+	if (be->slc_lr.base) {
+		free(be->slc_lr.base);
+		be->slc_lr.base = NULL;
+	}
+}
+
+int hw_mod_slc_lr_reset(struct flow_api_backend_s *be)
+{
+	/* Zero entire cache area */
+	zero_module_cache((struct common_func_s *)(&be->slc_lr));
+
+	NT_LOG(DBG, FILTER, "INIT SLC LR RCP\n");
+	return hw_mod_slc_lr_rcp_flush(be, 0, be->max_categories);
+}
+
+int hw_mod_slc_lr_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->max_categories;
+
+	if ((unsigned int)(start_idx + count) > be->max_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->slc_lr_rcp_flush(be->be_dev, &be->slc_lr, start_idx, count);
+}
-- 
2.45.0


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

* [PATCH v1 29/31] net/ntnic: add packet descriptor builder (PDB) FPGA module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (33 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 28/31] net/ntnic: add slicer (SLC LR) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 30/31] net/ntnic: add Tx Packet Editor (TPE) " Serhii Iliushyk
                   ` (16 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Packet Description Builder module creates packet meta-data
for example virtio-net headers.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    | 34 ++++++++
 drivers/net/ntnic/meson.build                 |  1 +
 drivers/net/ntnic/nthw/flow_api/flow_api.c    |  3 +
 .../nthw/flow_api/hw_mod/hw_mod_backend.c     |  1 +
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_pdb.c   | 86 +++++++++++++++++++
 .../supported/nthw_fpga_9563_055_049_0000.c   | 40 ++++++++-
 6 files changed, 164 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb.c

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index b28192e682..9644639131 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -609,6 +609,39 @@ struct pdb_func_s {
 		struct hw_mod_pdb_v9_s v9;
 	};
 };
+enum hw_pdb_e {
+	/* functions */
+	HW_PDB_RCP_PRESET_ALL = 0,
+	HW_PDB_RCP_COMPARE,
+	HW_PDB_RCP_FIND,
+	/* fields */
+	HW_PDB_RCP_DESCRIPTOR = FIELD_START_INDEX,
+	HW_PDB_RCP_DESC_LEN,
+	HW_PDB_RCP_TX_PORT,
+	HW_PDB_RCP_TX_IGNORE,
+	HW_PDB_RCP_TX_NOW,
+	HW_PDB_RCP_CRC_OVERWRITE,
+	HW_PDB_RCP_ALIGN,
+	HW_PDB_RCP_OFS0_DYN,
+	HW_PDB_RCP_OFS0_REL,
+	HW_PDB_RCP_OFS1_DYN,
+	HW_PDB_RCP_OFS1_REL,
+	HW_PDB_RCP_OFS2_DYN,
+	HW_PDB_RCP_OFS2_REL,
+	HW_PDB_RCP_IP_PROT_TNL,
+	HW_PDB_RCP_PPC_HSH,
+	HW_PDB_RCP_DUPLICATE_EN,
+	HW_PDB_RCP_DUPLICATE_BIT,
+	HW_PDB_RCP_PCAP_KEEP_FCS,
+	HW_PDB_CONFIG_TS_FORMAT,
+	HW_PDB_CONFIG_PORT_OFS,
+};
+bool hw_mod_pdb_present(struct flow_api_backend_s *be);
+int hw_mod_pdb_alloc(struct flow_api_backend_s *be);
+void hw_mod_pdb_free(struct flow_api_backend_s *be);
+int hw_mod_pdb_reset(struct flow_api_backend_s *be);
+int hw_mod_pdb_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_pdb_config_flush(struct flow_api_backend_s *be);
 
 struct tpe_func_s {
 	COMMON_FUNC_INFO_S;
@@ -779,6 +812,7 @@ struct flow_api_backend_s {
 	struct hsh_func_s hsh;
 	struct qsl_func_s qsl;
 	struct slc_lr_func_s slc_lr;
+	struct pdb_func_s pdb;
 
 	/* NIC attributes */
 	unsigned int num_phy_ports;
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 4caee8ac41..0415e5a5b2 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -53,6 +53,7 @@ sources = files(
         'nthw/flow_api/hw_mod/hw_mod_flm.c',
         'nthw/flow_api/hw_mod/hw_mod_hsh.c',
         'nthw/flow_api/hw_mod/hw_mod_km.c',
+        'nthw/flow_api/hw_mod/hw_mod_pdb.c',
         'nthw/flow_api/hw_mod/hw_mod_qsl.c',
         'nthw/flow_api/hw_mod/hw_mod_slc_lr.c',
         'nthw/flow_filter/flow_nthw_cat.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
index 5d6571310c..03946fb52f 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -301,6 +301,9 @@ struct flow_nic_dev *flow_api_create(uint8_t adapter_no, const struct flow_api_b
 	if (init_resource_elements(ndev, RES_HSH_RCP, ndev->be.hsh.nb_rcp))
 		goto err_exit;
 
+	if (init_resource_elements(ndev, RES_PDB_RCP, ndev->be.pdb.nb_pdb_rcp_categories))
+		goto err_exit;
+
 	if (init_resource_elements(ndev, RES_QSL_RCP, ndev->be.qsl.nb_rcp_categories))
 		goto err_exit;
 
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
index 6b0ea2a4a6..118e49f539 100644
--- a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
@@ -26,6 +26,7 @@ static const struct {
 		"SLC LR", hw_mod_slc_lr_alloc, hw_mod_slc_lr_free, hw_mod_slc_lr_reset,
 		hw_mod_slc_lr_present
 	},
+	{ "PDB", hw_mod_pdb_alloc, hw_mod_pdb_free, hw_mod_pdb_reset, hw_mod_pdb_present },
 };
 #define MOD_COUNT (ARRAY_SIZE(module))
 
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb.c
new file mode 100644
index 0000000000..13f0972e07
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_pdb.c
@@ -0,0 +1,86 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hw_mod_backend.h"
+
+#define _MOD_ "PDB"
+#define _VER_ be->pdb.ver
+
+bool hw_mod_pdb_present(struct flow_api_backend_s *be)
+{
+	return be->iface->get_pdb_present(be->be_dev);
+}
+
+int hw_mod_pdb_alloc(struct flow_api_backend_s *be)
+{
+	int nb;
+	_VER_ = be->iface->get_pdb_version(be->be_dev);
+	NT_LOG(DBG, FILTER, "PDB MODULE VERSION  %i.%i\n", VER_MAJOR(_VER_), VER_MINOR(_VER_));
+
+	nb = be->iface->get_nb_pdb_categories(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(pdb_categories);
+
+	be->pdb.nb_pdb_rcp_categories = (uint32_t)nb;
+
+	switch (_VER_) {
+	case 9:
+		if (!callocate_mod((struct common_func_s *)&be->pdb, 2, &be->pdb.v9.rcp,
+				be->pdb.nb_pdb_rcp_categories, sizeof(struct pdb_v9_rcp_s),
+				&be->pdb.v9.config, 1, sizeof(struct pdb_v9_config_s)))
+			return -1;
+
+		break;
+
+	/* end case 9 */
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+void hw_mod_pdb_free(struct flow_api_backend_s *be)
+{
+	if (be->pdb.base) {
+		free(be->pdb.base);
+		be->pdb.base = NULL;
+	}
+}
+
+int hw_mod_pdb_reset(struct flow_api_backend_s *be)
+{
+	int err = 0;
+	/* Zero entire cache area */
+	zero_module_cache((struct common_func_s *)(&be->hsh));
+
+	NT_LOG(DBG, FILTER, "INIT PDB RCP\n");
+	err |= hw_mod_pdb_rcp_flush(be, 0, ALL_ENTRIES);
+
+	NT_LOG(DBG, FILTER, "INIT PDB CONFIG\n");
+	err |= hw_mod_pdb_config_flush(be);
+	return err;
+}
+
+int hw_mod_pdb_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->pdb.nb_pdb_rcp_categories;
+
+	if ((unsigned int)(start_idx + count) > be->pdb.nb_pdb_rcp_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->pdb_rcp_flush(be->be_dev, &be->pdb, start_idx, count);
+}
+
+int hw_mod_pdb_config_flush(struct flow_api_backend_s *be)
+{
+	return be->iface->pdb_config_flush(be->be_dev, &be->pdb);
+}
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
index 7eeb210b80..9f821abf55 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
@@ -1297,6 +1297,43 @@ static nthw_fpga_register_init_s pci_wr_tg_registers[] = {
 	{ PCI_WR_TG_TG_WR_RUN, 4, 16, NTHW_FPGA_REG_TYPE_WO, 0, 1, pci_wr_tg_tg_wr_run_fields },
 };
 
+static nthw_fpga_field_init_s pdb_config_fields[] = {
+	{ PDB_CONFIG_PORT_OFS, 6, 3, 0 },
+	{ PDB_CONFIG_TS_FORMAT, 3, 0, 0 },
+};
+
+static nthw_fpga_field_init_s pdb_rcp_ctrl_fields[] = {
+	{ PDB_RCP_CTRL_ADR, 4, 0, 0x0000 },
+	{ PDB_RCP_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s pdb_rcp_data_fields[] = {
+	{ PDB_RCP_DATA_ALIGN, 1, 17, 0x0000 },
+	{ PDB_RCP_DATA_CRC_OVERWRITE, 1, 16, 0x0000 },
+	{ PDB_RCP_DATA_DESCRIPTOR, 4, 0, 0x0000 },
+	{ PDB_RCP_DATA_DESC_LEN, 5, 4, 0 },
+	{ PDB_RCP_DATA_DUPLICATE_BIT, 5, 61, 0x0000 },
+	{ PDB_RCP_DATA_DUPLICATE_EN, 1, 60, 0x0000 },
+	{ PDB_RCP_DATA_IP_PROT_TNL, 1, 57, 0x0000 },
+	{ PDB_RCP_DATA_OFS0_DYN, 5, 18, 0x0000 },
+	{ PDB_RCP_DATA_OFS0_REL, 8, 23, 0x0000 },
+	{ PDB_RCP_DATA_OFS1_DYN, 5, 31, 0x0000 },
+	{ PDB_RCP_DATA_OFS1_REL, 8, 36, 0x0000 },
+	{ PDB_RCP_DATA_OFS2_DYN, 5, 44, 0x0000 },
+	{ PDB_RCP_DATA_OFS2_REL, 8, 49, 0x0000 },
+	{ PDB_RCP_DATA_PCAP_KEEP_FCS, 1, 66, 0x0000 },
+	{ PDB_RCP_DATA_PPC_HSH, 2, 58, 0x0000 },
+	{ PDB_RCP_DATA_TX_IGNORE, 1, 14, 0x0000 },
+	{ PDB_RCP_DATA_TX_NOW, 1, 15, 0x0000 },
+	{ PDB_RCP_DATA_TX_PORT, 5, 9, 0x0000 },
+};
+
+static nthw_fpga_register_init_s pdb_registers[] = {
+	{ PDB_CONFIG, 2, 10, NTHW_FPGA_REG_TYPE_WO, 0, 2, pdb_config_fields },
+	{ PDB_RCP_CTRL, 0, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, pdb_rcp_ctrl_fields },
+	{ PDB_RCP_DATA, 1, 67, NTHW_FPGA_REG_TYPE_WO, 0, 18, pdb_rcp_data_fields },
+};
+
 static nthw_fpga_field_init_s qsl_qen_ctrl_fields[] = {
 	{ QSL_QEN_CTRL_ADR, 5, 0, 0x0000 },
 	{ QSL_QEN_CTRL_CNT, 16, 16, 0x0000 },
@@ -1510,6 +1547,7 @@ static nthw_fpga_module_init_s fpga_modules[] = {
 		MOD_PCI_WR_TG, 0, MOD_PCI_WR_TG, 0, 1, NTHW_FPGA_BUS_TYPE_RAB0, 2304, 7,
 		pci_wr_tg_registers
 	},
+	{ MOD_PDB, 0, MOD_PDB, 0, 9, NTHW_FPGA_BUS_TYPE_RAB1, 2560, 3, pdb_registers },
 	{ MOD_QSL, 0, MOD_QSL, 0, 7, NTHW_FPGA_BUS_TYPE_RAB1, 1792, 8, qsl_registers },
 	{ MOD_RAC, 0, MOD_RAC, 3, 0, NTHW_FPGA_BUS_TYPE_PCI, 8192, 14, rac_registers },
 	{ MOD_RST9563, 0, MOD_RST9563, 0, 5, NTHW_FPGA_BUS_TYPE_RAB0, 1024, 5, rst9563_registers },
@@ -1672,5 +1710,5 @@ static nthw_fpga_prod_param_s product_parameters[] = {
 };
 
 nthw_fpga_prod_init_s nthw_fpga_9563_055_049_0000 = {
-	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 19, fpga_modules,
+	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 20, fpga_modules,
 };
-- 
2.45.0


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

* [PATCH v1 30/31] net/ntnic: add Tx Packet Editor (TPE) FPGA module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (34 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 29/31] net/ntnic: add packet descriptor builder (PDB) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 31/31] net/ntnic: add receive MAC converter (RMC) core module Serhii Iliushyk
                   ` (15 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The TX Packet Editor is a software abstraction module,
that keeps track of the handful of FPGA modules
that are used to edit packets in the TX pipeline.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    |  80 +++++
 drivers/net/ntnic/meson.build                 |   1 +
 drivers/net/ntnic/nthw/flow_api/flow_api.c    |   9 +
 .../nthw/flow_api/hw_mod/hw_mod_backend.c     |   1 +
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_tpe.c   | 277 ++++++++++++++++++
 5 files changed, 368 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe.c

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 9644639131..cfd5150e59 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -654,6 +654,85 @@ struct tpe_func_s {
 		struct hw_mod_tpe_v3_s v3;
 	};
 };
+enum hw_tpe_e {
+	/* functions */
+	HW_TPE_PRESET_ALL = 0,
+	HW_TPE_FIND,
+	HW_TPE_COMPARE,
+	/* Control fields */
+	HW_TPE_RPP_RCP_EXP = FIELD_START_INDEX,
+	HW_TPE_IFR_RCP_IPV4_EN,
+	HW_TPE_IFR_RCP_IPV4_DF_DROP,
+	HW_TPE_IFR_RCP_IPV6_EN,
+	HW_TPE_IFR_RCP_IPV6_DROP,
+	HW_TPE_IFR_RCP_MTU,
+	HW_TPE_INS_RCP_DYN,
+	HW_TPE_INS_RCP_OFS,
+	HW_TPE_INS_RCP_LEN,
+	HW_TPE_RPL_RCP_DYN,
+	HW_TPE_RPL_RCP_OFS,
+	HW_TPE_RPL_RCP_LEN,
+	HW_TPE_RPL_RCP_RPL_PTR,
+	HW_TPE_RPL_RCP_EXT_PRIO,
+	HW_TPE_RPL_RCP_ETH_TYPE_WR,
+	HW_TPE_RPL_EXT_RPL_PTR,
+	HW_TPE_RPL_EXT_META_RPL_LEN,	/* SW only */
+	HW_TPE_RPL_RPL_VALUE,
+	HW_TPE_CPY_RCP_READER_SELECT,
+	HW_TPE_CPY_RCP_DYN,
+	HW_TPE_CPY_RCP_OFS,
+	HW_TPE_CPY_RCP_LEN,
+	HW_TPE_HFU_RCP_LEN_A_WR,
+	HW_TPE_HFU_RCP_LEN_A_OUTER_L4_LEN,
+	HW_TPE_HFU_RCP_LEN_A_POS_DYN,
+	HW_TPE_HFU_RCP_LEN_A_POS_OFS,
+	HW_TPE_HFU_RCP_LEN_A_ADD_DYN,
+	HW_TPE_HFU_RCP_LEN_A_ADD_OFS,
+	HW_TPE_HFU_RCP_LEN_A_SUB_DYN,
+	HW_TPE_HFU_RCP_LEN_B_WR,
+	HW_TPE_HFU_RCP_LEN_B_POS_DYN,
+	HW_TPE_HFU_RCP_LEN_B_POS_OFS,
+	HW_TPE_HFU_RCP_LEN_B_ADD_DYN,
+	HW_TPE_HFU_RCP_LEN_B_ADD_OFS,
+	HW_TPE_HFU_RCP_LEN_B_SUB_DYN,
+	HW_TPE_HFU_RCP_LEN_C_WR,
+	HW_TPE_HFU_RCP_LEN_C_POS_DYN,
+	HW_TPE_HFU_RCP_LEN_C_POS_OFS,
+	HW_TPE_HFU_RCP_LEN_C_ADD_DYN,
+	HW_TPE_HFU_RCP_LEN_C_ADD_OFS,
+	HW_TPE_HFU_RCP_LEN_C_SUB_DYN,
+	HW_TPE_HFU_RCP_TTL_WR,
+	HW_TPE_HFU_RCP_TTL_POS_DYN,
+	HW_TPE_HFU_RCP_TTL_POS_OFS,
+	HW_TPE_CSU_RCP_OUTER_L3_CMD,
+	HW_TPE_CSU_RCP_OUTER_L4_CMD,
+	HW_TPE_CSU_RCP_INNER_L3_CMD,
+	HW_TPE_CSU_RCP_INNER_L4_CMD,
+};
+bool hw_mod_tpe_present(struct flow_api_backend_s *be);
+int hw_mod_tpe_alloc(struct flow_api_backend_s *be);
+void hw_mod_tpe_free(struct flow_api_backend_s *be);
+int hw_mod_tpe_reset(struct flow_api_backend_s *be);
+
+int hw_mod_tpe_rpp_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
+
+int hw_mod_tpe_rpp_ifr_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
+
+int hw_mod_tpe_ifr_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
+
+int hw_mod_tpe_ins_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
+
+int hw_mod_tpe_rpl_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
+
+int hw_mod_tpe_rpl_ext_flush(struct flow_api_backend_s *be, int start_idx, int count);
+
+int hw_mod_tpe_rpl_rpl_flush(struct flow_api_backend_s *be, int start_idx, int count);
+
+int hw_mod_tpe_cpy_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
+
+int hw_mod_tpe_hfu_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
+
+int hw_mod_tpe_csu_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count);
 
 enum debug_mode_e {
 	FLOW_BACKEND_DEBUG_MODE_NONE = 0x0000,
@@ -813,6 +892,7 @@ struct flow_api_backend_s {
 	struct qsl_func_s qsl;
 	struct slc_lr_func_s slc_lr;
 	struct pdb_func_s pdb;
+	struct tpe_func_s tpe;
 
 	/* NIC attributes */
 	unsigned int num_phy_ports;
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 0415e5a5b2..e2eff3cf1e 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -56,6 +56,7 @@ sources = files(
         'nthw/flow_api/hw_mod/hw_mod_pdb.c',
         'nthw/flow_api/hw_mod/hw_mod_qsl.c',
         'nthw/flow_api/hw_mod/hw_mod_slc_lr.c',
+        'nthw/flow_api/hw_mod/hw_mod_tpe.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_csu.c',
         'nthw/flow_filter/flow_nthw_flm.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
index 03946fb52f..9d47aed061 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -319,6 +319,15 @@ struct flow_nic_dev *flow_api_create(uint8_t adapter_no, const struct flow_api_b
 	if (init_resource_elements(ndev, RES_FLM_RCP, ndev->be.flm.nb_categories))
 		goto err_exit;
 
+	if (init_resource_elements(ndev, RES_TPE_RCP, ndev->be.tpe.nb_rcp_categories))
+		goto err_exit;
+
+	if (init_resource_elements(ndev, RES_TPE_EXT, ndev->be.tpe.nb_rpl_ext_categories))
+		goto err_exit;
+
+	if (init_resource_elements(ndev, RES_TPE_RPL, ndev->be.tpe.nb_rpl_depth))
+		goto err_exit;
+
 	if (init_resource_elements(ndev, RES_SCRUB_RCP, ndev->be.flm.nb_scrub_profiles))
 		goto err_exit;
 
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
index 118e49f539..13e98ea9ba 100644
--- a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
@@ -27,6 +27,7 @@ static const struct {
 		hw_mod_slc_lr_present
 	},
 	{ "PDB", hw_mod_pdb_alloc, hw_mod_pdb_free, hw_mod_pdb_reset, hw_mod_pdb_present },
+	{ "TPE", hw_mod_tpe_alloc, hw_mod_tpe_free, hw_mod_tpe_reset, hw_mod_tpe_present },
 };
 #define MOD_COUNT (ARRAY_SIZE(module))
 
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe.c
new file mode 100644
index 0000000000..180deefd72
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_tpe.c
@@ -0,0 +1,277 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "hw_mod_backend.h"
+
+#define _MOD_ "TPE"
+#define _VER_ be->tpe.ver
+
+bool hw_mod_tpe_present(struct flow_api_backend_s *be)
+{
+	return be->iface->get_tpe_present(be->be_dev);
+}
+
+int hw_mod_tpe_alloc(struct flow_api_backend_s *be)
+{
+	int nb;
+	_VER_ = be->iface->get_tpe_version(be->be_dev);
+	NT_LOG(DBG, FILTER, _MOD_ " MODULE VERSION %i.%i\n", VER_MAJOR(_VER_), VER_MINOR(_VER_));
+
+	nb = be->iface->get_nb_tpe_categories(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(tpe_categories);
+
+	be->tpe.nb_rcp_categories = (uint32_t)nb;
+
+	nb = be->iface->get_nb_tpe_ifr_categories(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(tpe_ifr_categories);
+
+	be->tpe.nb_ifr_categories = (uint32_t)nb;
+
+	nb = be->iface->get_nb_tx_cpy_writers(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(tx_cpy_writers);
+
+	be->tpe.nb_cpy_writers = (uint32_t)nb;
+
+	nb = be->iface->get_nb_tx_rpl_depth(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(tx_rpl_depth);
+
+	be->tpe.nb_rpl_depth = (uint32_t)nb;
+
+	nb = be->iface->get_nb_tx_rpl_ext_categories(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(tx_rpl_ext_categories);
+
+	be->tpe.nb_rpl_ext_categories = (uint32_t)nb;
+
+	switch (_VER_) {
+	case 3:
+		if (!callocate_mod((struct common_func_s *)&be->tpe, 10, &be->tpe.v3.rpp_rcp,
+				be->tpe.nb_rcp_categories, sizeof(struct tpe_v1_rpp_v0_rcp_s),
+				&be->tpe.v3.rpp_ifr_rcp, be->tpe.nb_ifr_categories,
+				sizeof(struct tpe_v2_rpp_v1_ifr_rcp_s), &be->tpe.v3.ifr_rcp,
+				be->tpe.nb_ifr_categories, sizeof(struct tpe_v2_ifr_v1_rcp_s),
+
+				&be->tpe.v3.ins_rcp, be->tpe.nb_rcp_categories,
+				sizeof(struct tpe_v1_ins_v1_rcp_s),
+
+				&be->tpe.v3.rpl_rcp, be->tpe.nb_rcp_categories,
+				sizeof(struct tpe_v3_rpl_v4_rcp_s), &be->tpe.v3.rpl_ext,
+				be->tpe.nb_rpl_ext_categories,
+				sizeof(struct tpe_v1_rpl_v2_ext_s), &be->tpe.v3.rpl_rpl,
+				be->tpe.nb_rpl_depth, sizeof(struct tpe_v1_rpl_v2_rpl_s),
+
+				&be->tpe.v3.cpy_rcp,
+				be->tpe.nb_cpy_writers * be->tpe.nb_rcp_categories,
+				sizeof(struct tpe_v1_cpy_v1_rcp_s),
+
+				&be->tpe.v3.hfu_rcp, be->tpe.nb_rcp_categories,
+				sizeof(struct tpe_v1_hfu_v1_rcp_s),
+
+				&be->tpe.v3.csu_rcp, be->tpe.nb_rcp_categories,
+				sizeof(struct tpe_v1_csu_v0_rcp_s)))
+			return -1;
+
+		break;
+
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+void hw_mod_tpe_free(struct flow_api_backend_s *be)
+{
+	if (be->tpe.base) {
+		free(be->tpe.base);
+		be->tpe.base = NULL;
+	}
+}
+
+int hw_mod_tpe_reset(struct flow_api_backend_s *be)
+{
+	int err = 0;
+
+	/* Zero entire cache area */
+	zero_module_cache((struct common_func_s *)(&be->tpe));
+
+	NT_LOG(DBG, FILTER, "INIT TPE\n");
+	err |= hw_mod_tpe_rpp_rcp_flush(be, 0, ALL_ENTRIES);
+	err |= hw_mod_tpe_ins_rcp_flush(be, 0, ALL_ENTRIES);
+	err |= hw_mod_tpe_rpl_rcp_flush(be, 0, ALL_ENTRIES);
+	err |= hw_mod_tpe_rpl_ext_flush(be, 0, ALL_ENTRIES);
+	err |= hw_mod_tpe_rpl_rpl_flush(be, 0, ALL_ENTRIES);
+	err |= hw_mod_tpe_cpy_rcp_flush(be, 0, ALL_ENTRIES);
+	err |= hw_mod_tpe_hfu_rcp_flush(be, 0, ALL_ENTRIES);
+	err |= hw_mod_tpe_csu_rcp_flush(be, 0, ALL_ENTRIES);
+	err |= hw_mod_tpe_rpp_ifr_rcp_flush(be, 0, ALL_ENTRIES);
+	err |= hw_mod_tpe_ifr_rcp_flush(be, 0, ALL_ENTRIES);
+
+	return err;
+}
+
+/*
+ * RPP_IFR_RCP
+ */
+
+int hw_mod_tpe_rpp_ifr_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->tpe.nb_ifr_categories;
+
+	if ((unsigned int)(start_idx + count) > be->tpe.nb_ifr_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->tpe_rpp_ifr_rcp_flush(be->be_dev, &be->tpe, start_idx, count);
+}
+
+/*
+ * RPP_RCP
+ */
+
+int hw_mod_tpe_rpp_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->tpe.nb_rcp_categories;
+
+	if ((unsigned int)(start_idx + count) > be->tpe.nb_rcp_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->tpe_rpp_rcp_flush(be->be_dev, &be->tpe, start_idx, count);
+}
+
+/*
+ * IFR_RCP
+ */
+
+int hw_mod_tpe_ifr_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->tpe.nb_ifr_categories;
+
+	if ((unsigned int)(start_idx + count) > be->tpe.nb_ifr_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->tpe_ifr_rcp_flush(be->be_dev, &be->tpe, start_idx, count);
+}
+
+/*
+ * INS_RCP
+ */
+
+int hw_mod_tpe_ins_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->tpe.nb_rcp_categories;
+
+	if ((unsigned int)(start_idx + count) > be->tpe.nb_rcp_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->tpe_ins_rcp_flush(be->be_dev, &be->tpe, start_idx, count);
+}
+
+/*
+ * RPL_RCP
+ */
+
+int hw_mod_tpe_rpl_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->tpe.nb_rcp_categories;
+
+	if ((unsigned int)(start_idx + count) > be->tpe.nb_rcp_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->tpe_rpl_rcp_flush(be->be_dev, &be->tpe, start_idx, count);
+}
+
+/*
+ * RPL_EXT
+ */
+
+int hw_mod_tpe_rpl_ext_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->tpe.nb_rpl_ext_categories;
+
+	if ((unsigned int)(start_idx + count) > be->tpe.nb_rpl_ext_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->tpe_rpl_ext_flush(be->be_dev, &be->tpe, start_idx, count);
+}
+
+/*
+ * RPL_RPL
+ */
+
+int hw_mod_tpe_rpl_rpl_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->tpe.nb_rpl_depth;
+
+	if ((unsigned int)(start_idx + count) > be->tpe.nb_rpl_depth)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->tpe_rpl_rpl_flush(be->be_dev, &be->tpe, start_idx, count);
+}
+
+/*
+ * CPY_RCP
+ */
+
+int hw_mod_tpe_cpy_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	const uint32_t cpy_size = be->tpe.nb_cpy_writers * be->tpe.nb_rcp_categories;
+
+	if (count == ALL_ENTRIES)
+		count = cpy_size;
+
+	if ((unsigned int)(start_idx + count) > cpy_size)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->tpe_cpy_rcp_flush(be->be_dev, &be->tpe, start_idx, count);
+}
+
+/*
+ * HFU_RCP
+ */
+
+int hw_mod_tpe_hfu_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->tpe.nb_rcp_categories;
+
+	if ((unsigned int)(start_idx + count) > be->tpe.nb_rcp_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->tpe_hfu_rcp_flush(be->be_dev, &be->tpe, start_idx, count);
+}
+
+/*
+ * CSU_RCP
+ */
+
+int hw_mod_tpe_csu_rcp_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->tpe.nb_rcp_categories;
+
+	if ((unsigned int)(start_idx + count) > be->tpe.nb_rcp_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->tpe_csu_rcp_flush(be->be_dev, &be->tpe, start_idx, count);
+}
-- 
2.45.0


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

* [PATCH v1 31/31] net/ntnic: add receive MAC converter (RMC) core module
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (35 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 30/31] net/ntnic: add Tx Packet Editor (TPE) " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 00/14] Enable virtual queues Serhii Iliushyk
                   ` (14 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The RX MAC Converter module is part of the control mechanism
of the physical ports.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/adapter/nt4ga_adapter.c     | 14 +++
 drivers/net/ntnic/include/nt4ga_adapter.h     |  1 +
 drivers/net/ntnic/include/ntnic_stat.h        | 11 +++
 drivers/net/ntnic/meson.build                 |  1 +
 .../net/ntnic/nthw/core/include/nthw_rmc.h    | 49 ++++++++++
 drivers/net/ntnic/nthw/core/nthw_rmc.c        | 90 +++++++++++++++++++
 .../supported/nthw_fpga_9563_055_049_0000.c   | 29 +++++-
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |  1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |  1 +
 .../nthw/supported/nthw_fpga_reg_defs_rmc.h   | 36 ++++++++
 10 files changed, 232 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ntnic/include/ntnic_stat.h
 create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_rmc.h
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_rmc.c
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rmc.h

diff --git a/drivers/net/ntnic/adapter/nt4ga_adapter.c b/drivers/net/ntnic/adapter/nt4ga_adapter.c
index fd90f31abd..5d9db3450d 100644
--- a/drivers/net/ntnic/adapter/nt4ga_adapter.c
+++ b/drivers/net/ntnic/adapter/nt4ga_adapter.c
@@ -212,6 +212,20 @@ static int nt4ga_adapter_init(struct adapter_info_s *p_adapter_info)
 		}
 	}
 
+	nthw_rmc_t *p_nthw_rmc = nthw_rmc_new();
+	if (p_nthw_rmc == NULL) {
+		NT_LOG(ERR, NTNIC, "Failed to allocate memory for RMC module\n");
+		return -1;
+	}
+
+	res = nthw_rmc_init(p_nthw_rmc, p_fpga, 0);
+	if (res) {
+		NT_LOG(ERR, NTNIC, "Failed to initialize RMC module\n");
+		return -1;
+	}
+
+	nthw_rmc_unblock(p_nthw_rmc, false);
+
 	return 0;
 }
 
diff --git a/drivers/net/ntnic/include/nt4ga_adapter.h b/drivers/net/ntnic/include/nt4ga_adapter.h
index 93218fd45b..809135f130 100644
--- a/drivers/net/ntnic/include/nt4ga_adapter.h
+++ b/drivers/net/ntnic/include/nt4ga_adapter.h
@@ -27,6 +27,7 @@ typedef struct hw_info_s {
  * Services provided by the adapter module
  */
 #include "nt4ga_filter.h"
+#include "ntnic_stat.h"
 
 typedef struct adapter_info_s {
 	struct nt4ga_filter_s nt4ga_filter;
diff --git a/drivers/net/ntnic/include/ntnic_stat.h b/drivers/net/ntnic/include/ntnic_stat.h
new file mode 100644
index 0000000000..148088fe1d
--- /dev/null
+++ b/drivers/net/ntnic/include/ntnic_stat.h
@@ -0,0 +1,11 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef NTNIC_STAT_H_
+#define NTNIC_STAT_H_
+
+#include "nthw_rmc.h"
+
+#endif  /* NTNIC_STAT_H_ */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index e2eff3cf1e..66d2770da7 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -41,6 +41,7 @@ sources = files(
         'nthw/core/nthw_iic.c',
         'nthw/core/nthw_mac_pcs.c',
         'nthw/core/nthw_pcie3.c',
+        'nthw/core/nthw_rmc.c',
         'nthw/core/nthw_sdc.c',
         'nthw/core/nthw_si5340.c',
         'nthw/flow_api/flow_api.c',
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_rmc.h b/drivers/net/ntnic/nthw/core/include/nthw_rmc.h
new file mode 100644
index 0000000000..65fbd8cda0
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/include/nthw_rmc.h
@@ -0,0 +1,49 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef NTHW_RMC_H_
+#define NTHW_RMC_H_
+
+#include "nthw_fpga_model.h"
+
+struct nthw_rmc {
+	nthw_fpga_t *mp_fpga;
+	nthw_module_t *mp_mod_rmc;
+	int mn_instance;
+
+	int mn_ports;
+	int mn_nims;
+
+	bool mb_administrative_block;
+
+	/* RMC CTRL register */
+	nthw_register_t *mp_reg_ctrl;
+	nthw_field_t *mp_fld_ctrl_block_stat_drop;
+	nthw_field_t *mp_fld_ctrl_block_keep_alive;
+	nthw_field_t *mp_fld_ctrl_block_mac_port;
+
+	/* RMC Status register */
+	nthw_register_t *mp_reg_status;
+	nthw_field_t *mp_fld_sf_ram_of;
+	nthw_field_t *mp_fld_descr_fifo_of;
+
+	/* RMC DBG register */
+	nthw_register_t *mp_reg_dbg;
+	nthw_field_t *mp_fld_dbg_merge;
+
+	/* RMC MAC_IF register */
+	nthw_register_t *mp_reg_mac_if;
+	nthw_field_t *mp_fld_mac_if_err;
+};
+
+typedef struct nthw_rmc nthw_rmc_t;
+typedef struct nthw_rmc nthw_rmc;
+
+nthw_rmc_t *nthw_rmc_new(void);
+int nthw_rmc_init(nthw_rmc_t *p, nthw_fpga_t *p_fpga, int n_instance);
+
+void nthw_rmc_unblock(nthw_rmc_t *p, bool b_is_slave);
+
+#endif	/* NTHW_RMC_H_ */
diff --git a/drivers/net/ntnic/nthw/core/nthw_rmc.c b/drivers/net/ntnic/nthw/core/nthw_rmc.c
new file mode 100644
index 0000000000..9604825be0
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_rmc.c
@@ -0,0 +1,90 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_rmc.h"
+
+nthw_rmc_t *nthw_rmc_new(void)
+{
+	nthw_rmc_t *p = malloc(sizeof(nthw_rmc_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_rmc_t));
+
+	return p;
+}
+
+int nthw_rmc_init(nthw_rmc_t *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_RMC, n_instance);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: RMC %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_instance = n_instance;
+	p->mp_mod_rmc = p_mod;
+
+	/* Params */
+	p->mn_ports =
+		nthw_fpga_get_product_param(p_fpga, NT_RX_PORTS,
+			nthw_fpga_get_product_param(p_fpga, NT_PORTS, 0));
+	p->mn_nims = nthw_fpga_get_product_param(p_fpga, NT_NIMS, 0);
+	p->mb_administrative_block = false;
+
+	NT_LOG(DBG, NTHW, "%s: RMC %d\n", p_adapter_id_str, p->mn_instance);
+
+	p->mp_reg_ctrl = nthw_module_get_register(p->mp_mod_rmc, RMC_CTRL);
+
+	p->mp_fld_ctrl_block_stat_drop =
+		nthw_register_get_field(p->mp_reg_ctrl, RMC_CTRL_BLOCK_STATT);
+	p->mp_fld_ctrl_block_keep_alive =
+		nthw_register_get_field(p->mp_reg_ctrl, RMC_CTRL_BLOCK_KEEPA);
+	p->mp_fld_ctrl_block_mac_port =
+		nthw_register_get_field(p->mp_reg_ctrl, RMC_CTRL_BLOCK_MAC_PORT);
+
+	p->mp_reg_status = nthw_module_query_register(p->mp_mod_rmc, RMC_STATUS);
+
+	if (p->mp_reg_status) {
+		p->mp_fld_sf_ram_of =
+			nthw_register_get_field(p->mp_reg_status, RMC_STATUS_SF_RAM_OF);
+		p->mp_fld_descr_fifo_of =
+			nthw_register_get_field(p->mp_reg_status, RMC_STATUS_DESCR_FIFO_OF);
+	}
+
+	p->mp_reg_dbg = nthw_module_query_register(p->mp_mod_rmc, RMC_DBG);
+
+	if (p->mp_reg_dbg)
+		p->mp_fld_dbg_merge = nthw_register_get_field(p->mp_reg_dbg, RMC_DBG_MERGE);
+
+	p->mp_reg_mac_if = nthw_module_query_register(p->mp_mod_rmc, RMC_MAC_IF);
+
+	if (p->mp_reg_mac_if)
+		p->mp_fld_mac_if_err = nthw_register_get_field(p->mp_reg_mac_if, RMC_MAC_IF_ERR);
+
+	return 0;
+}
+
+void nthw_rmc_unblock(nthw_rmc_t *p, bool b_is_slave)
+{
+	uint32_t n_block_mask = ~0U << (b_is_slave ? p->mn_nims : p->mn_ports);
+
+	/* BLOCK_STATT(0)=0 BLOCK_KEEPA(1)=0 BLOCK_MAC_PORT(8:11)=0 */
+	if (!p->mb_administrative_block) {
+		nthw_field_clr_flush(p->mp_fld_ctrl_block_stat_drop);
+		nthw_field_clr_flush(p->mp_fld_ctrl_block_keep_alive);
+		nthw_field_set_val_flush32(p->mp_fld_ctrl_block_mac_port, n_block_mask);
+	}
+}
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
index 9f821abf55..98b857158e 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
@@ -1468,6 +1468,32 @@ static nthw_fpga_register_init_s rac_registers[] = {
 	{ RAC_RAB_OB_DATA, 4168, 32, NTHW_FPGA_REG_TYPE_RC1, 0, 1, rac_rab_ob_data_fields },
 };
 
+static nthw_fpga_field_init_s rmc_ctrl_fields[] = {
+	{ RMC_CTRL_BLOCK_KEEPA, 1, 1, 1 }, { RMC_CTRL_BLOCK_MAC_PORT, 2, 8, 3 },
+	{ RMC_CTRL_BLOCK_RPP_SLICE, 8, 10, 0 }, { RMC_CTRL_BLOCK_STATT, 1, 0, 1 },
+	{ RMC_CTRL_LAG_PHY_ODD_EVEN, 1, 24, 0 },
+};
+
+static nthw_fpga_field_init_s rmc_dbg_fields[] = {
+	{ RMC_DBG_MERGE, 31, 0, 0 },
+};
+
+static nthw_fpga_field_init_s rmc_mac_if_fields[] = {
+	{ RMC_MAC_IF_ERR, 31, 0, 0 },
+};
+
+static nthw_fpga_field_init_s rmc_status_fields[] = {
+	{ RMC_STATUS_DESCR_FIFO_OF, 1, 16, 0 },
+	{ RMC_STATUS_SF_RAM_OF, 1, 0, 0 },
+};
+
+static nthw_fpga_register_init_s rmc_registers[] = {
+	{ RMC_CTRL, 0, 25, NTHW_FPGA_REG_TYPE_RW, 771, 5, rmc_ctrl_fields },
+	{ RMC_DBG, 2, 31, NTHW_FPGA_REG_TYPE_RO, 0, 1, rmc_dbg_fields },
+	{ RMC_MAC_IF, 3, 31, NTHW_FPGA_REG_TYPE_RO, 0, 1, rmc_mac_if_fields },
+	{ RMC_STATUS, 1, 17, NTHW_FPGA_REG_TYPE_RO, 0, 2, rmc_status_fields },
+};
+
 static nthw_fpga_field_init_s rst9563_ctrl_fields[] = {
 	{ RST9563_CTRL_PTP_MMCM_CLKSEL, 1, 2, 1 },
 	{ RST9563_CTRL_TS_CLKSEL, 1, 1, 1 },
@@ -1550,6 +1576,7 @@ static nthw_fpga_module_init_s fpga_modules[] = {
 	{ MOD_PDB, 0, MOD_PDB, 0, 9, NTHW_FPGA_BUS_TYPE_RAB1, 2560, 3, pdb_registers },
 	{ MOD_QSL, 0, MOD_QSL, 0, 7, NTHW_FPGA_BUS_TYPE_RAB1, 1792, 8, qsl_registers },
 	{ MOD_RAC, 0, MOD_RAC, 3, 0, NTHW_FPGA_BUS_TYPE_PCI, 8192, 14, rac_registers },
+	{ MOD_RMC, 0, MOD_RMC, 1, 3, NTHW_FPGA_BUS_TYPE_RAB0, 12288, 4, rmc_registers },
 	{ MOD_RST9563, 0, MOD_RST9563, 0, 5, NTHW_FPGA_BUS_TYPE_RAB0, 1024, 5, rst9563_registers },
 };
 
@@ -1710,5 +1737,5 @@ static nthw_fpga_prod_param_s product_parameters[] = {
 };
 
 nthw_fpga_prod_init_s nthw_fpga_9563_055_049_0000 = {
-	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 20, fpga_modules,
+	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 21, fpga_modules,
 };
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index 51b2d99c01..5d6aac122c 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -34,6 +34,7 @@
 #define MOD_PDB (0xa7771bffUL)
 #define MOD_QSL (0x448ed859UL)
 #define MOD_RAC (0xae830b42UL)
+#define MOD_RMC (0x236444eUL)
 #define MOD_RPP_LR (0xba7f945cUL)
 #define MOD_RST9563 (0x385d6d1dUL)
 #define MOD_SDC (0xd2369530UL)
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index 8fa41eb7ea..45f9794958 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -35,6 +35,7 @@
 #include "nthw_fpga_reg_defs_pdb.h"
 #include "nthw_fpga_reg_defs_qsl.h"
 #include "nthw_fpga_reg_defs_rac.h"
+#include "nthw_fpga_reg_defs_rmc.h"
 #include "nthw_fpga_reg_defs_rpl.h"
 #include "nthw_fpga_reg_defs_rpp_lr.h"
 #include "nthw_fpga_reg_defs_rst9563.h"
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rmc.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rmc.h
new file mode 100644
index 0000000000..07a1c8f890
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_rmc.h
@@ -0,0 +1,36 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_rmc.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_RMC_
+#define _NTHW_FPGA_REG_DEFS_RMC_
+
+/* RMC */
+#define NTHW_MOD_RMC (0x236444eUL)
+#define RMC_CTRL (0x4c45f748UL)
+#define RMC_CTRL_BLOCK_KEEPA (0x5e036c8UL)
+#define RMC_CTRL_BLOCK_MAC_PORT (0x582a6486UL)
+#define RMC_CTRL_BLOCK_RPP_SLICE (0x58c719cUL)
+#define RMC_CTRL_BLOCK_STATT (0xb36d5342UL)
+#define RMC_CTRL_LAG_PHY_ODD_EVEN (0xf4613c9UL)
+#define RMC_DBG (0x578721f2UL)
+#define RMC_DBG_MERGE (0xebfd6f00UL)
+#define RMC_MAC_IF (0x806bb8b0UL)
+#define RMC_MAC_IF_ERR (0xa79e974aUL)
+#define RMC_STATUS (0x3c415d75UL)
+#define RMC_STATUS_DESCR_FIFO_OF (0x7be968baUL)
+#define RMC_STATUS_SF_RAM_OF (0x1832173dUL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_RMC_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 00/14] Enable virtual queues
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (36 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 31/31] net/ntnic: add receive MAC converter (RMC) core module Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 01/14] net/ntnic: add basic queue operations Serhii Iliushyk
                   ` (13 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev; +Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit

*** BLURB HERE ***

Danylo Vodopianov (13):
  net/ntnic: add basic queue operations
  net/ntnic: enhance Ethernet device configuration
  net/ntnic: add scatter-gather HW deallocation
  net/ntnic: add queue setup operations
  net/ntnic: add packet handler for virtio queues
  net/ntnic: add init for virt queues in the DBS
  net/ntnic: add split-queue support
  net/ntnic: add functions for availability monitor management
  net/ntnic: used writer data handling functions
  net/ntnic: add descriptor reader data handling functions
  net/ntnic: virtqueue setup managed packed-ring was added
  net/ntnic: add functions for releasing virt queues
  net/ntnic: add functions for retrieving and managing packets

Serhii Iliushyk (1):
  net/ntnic: update FPGA registeris related to DBS

 doc/guides/nics/features/ntnic.ini            |    1 +
 doc/guides/nics/ntnic.rst                     |   44 +
 drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c | 1428 +++++++++++++++++
 drivers/net/ntnic/include/ntnic_dbs.h         |  313 ++++
 drivers/net/ntnic/include/ntnic_virt_queue.h  |  146 ++
 drivers/net/ntnic/include/ntos_drv.h          |   70 +
 drivers/net/ntnic/meson.build                 |    2 +
 drivers/net/ntnic/nthw/dbs/nthw_dbs.c         | 1157 +++++++++++++
 drivers/net/ntnic/nthw/nthw_drv.h             |    3 +
 .../supported/nthw_fpga_9563_055_049_0000.c   |  184 ++-
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |    1 +
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |    1 +
 .../nthw/supported/nthw_fpga_reg_defs_dbs.h   |  144 ++
 drivers/net/ntnic/ntnic_ethdev.c              | 1063 ++++++++++++
 drivers/net/ntnic/ntnic_mod_reg.c             |   14 +
 drivers/net/ntnic/ntnic_mod_reg.h             |   95 ++
 drivers/net/ntnic/ntutil/nt_util.c            |   10 +
 drivers/net/ntnic/ntutil/nt_util.h            |    2 +
 18 files changed, 4677 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
 create mode 100644 drivers/net/ntnic/include/ntnic_dbs.h
 create mode 100644 drivers/net/ntnic/include/ntnic_virt_queue.h
 create mode 100644 drivers/net/ntnic/nthw/dbs/nthw_dbs.c
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h

-- 
2.45.0


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

* [PATCH v1 01/14] net/ntnic: add basic queue operations
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (37 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 00/14] Enable virtual queues Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 02/14] net/ntnic: enhance Ethernet device configuration Serhii Iliushyk
                   ` (12 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

Adds support for queue configure, start, stop, release.
The internal macro and functions of ntnic were also added and
initialized.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 doc/guides/nics/features/ntnic.ini   |   1 +
 drivers/net/ntnic/include/ntos_drv.h |  34 +++++
 drivers/net/ntnic/ntnic_ethdev.c     | 208 +++++++++++++++++++++++++++
 drivers/net/ntnic/ntutil/nt_util.c   |  10 ++
 drivers/net/ntnic/ntutil/nt_util.h   |   2 +
 5 files changed, 255 insertions(+)

diff --git a/doc/guides/nics/features/ntnic.ini b/doc/guides/nics/features/ntnic.ini
index b6d92c7ee1..8b9b87bdfe 100644
--- a/doc/guides/nics/features/ntnic.ini
+++ b/doc/guides/nics/features/ntnic.ini
@@ -7,6 +7,7 @@
 FW version           = Y
 Speed capabilities   = Y
 Link status          = Y
+Queue start/stop     = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
 Linux                = Y
diff --git a/drivers/net/ntnic/include/ntos_drv.h b/drivers/net/ntnic/include/ntos_drv.h
index 67baf9fe0c..a77e6a0247 100644
--- a/drivers/net/ntnic/include/ntos_drv.h
+++ b/drivers/net/ntnic/include/ntos_drv.h
@@ -13,6 +13,7 @@
 
 #include <rte_ether.h>
 
+#include "stream_binary_flow_api.h"
 #include "nthw_drv.h"
 
 #define NUM_MAC_ADDRS_PER_PORT (16U)
@@ -21,6 +22,32 @@
 #define NUM_ADAPTER_MAX (8)
 #define NUM_ADAPTER_PORTS_MAX (128)
 
+
+/* Max RSS queues */
+#define MAX_QUEUES       125
+
+/* Structs: */
+struct __rte_cache_aligned ntnic_rx_queue {
+	struct flow_queue_id_s queue;    /* queue info - user id and hw queue index */
+	struct rte_mempool *mb_pool; /* mbuf memory pool */
+	uint16_t buf_size; /* Size of data area in mbuf */
+	int  enabled;  /* Enabling/disabling of this queue */
+
+	nt_meta_port_type_t type;
+	uint32_t port;     /* Rx port for this queue */
+	enum fpga_info_profile profile;  /* Inline / Capture */
+
+};
+
+struct __rte_cache_aligned ntnic_tx_queue {
+	struct flow_queue_id_s queue; /* queue info - user id and hw queue index */
+	nt_meta_port_type_t type;
+
+	uint32_t port;     /* Tx port for this queue */
+	int  enabled;  /* Enabling/disabling of this queue */
+	enum fpga_info_profile profile;  /* Inline / Capture */
+};
+
 struct pmd_internals {
 	const struct rte_pci_device *pci_dev;
 	char name[20];
@@ -30,7 +57,14 @@ struct pmd_internals {
 	unsigned int nb_tx_queues;
 	/* Offset of the VF from the PF */
 	uint8_t vf_offset;
+	uint32_t port;
 	nt_meta_port_type_t type;
+	struct flow_queue_id_s vpq[MAX_QUEUES];
+	unsigned int           vpq_nb_vq;
+	/* Array of Rx queues */
+	struct ntnic_rx_queue  rxq_scg[MAX_QUEUES];
+	/* Array of Tx queues */
+	struct ntnic_tx_queue  txq_scg[MAX_QUEUES];
 	struct drv_s *p_drv;
 	/* Ethernet (MAC) addresses. Element number zero denotes default address. */
 	struct rte_ether_addr eth_addrs[NUM_MAC_ADDRS_PER_PORT];
diff --git a/drivers/net/ntnic/ntnic_ethdev.c b/drivers/net/ntnic/ntnic_ethdev.c
index 5af18a3b27..967e989575 100644
--- a/drivers/net/ntnic/ntnic_ethdev.c
+++ b/drivers/net/ntnic/ntnic_ethdev.c
@@ -3,12 +3,17 @@
  * Copyright(c) 2023 Napatech A/S
  */
 
+#include <stdint.h>
+
 #include <rte_eal.h>
 #include <rte_dev.h>
 #include <rte_vfio.h>
 #include <rte_ethdev.h>
 #include <rte_bus_pci.h>
 #include <ethdev_pci.h>
+#include <rte_kvargs.h>
+
+#include <sys/queue.h>
 
 #include "ntlog.h"
 #include "ntdrv_4ga.h"
@@ -24,6 +29,23 @@
 
 #define EXCEPTION_PATH_HID 0
 
+#define MAX_TOTAL_QUEUES       128
+
+/* Max RSS queues */
+#define MAX_QUEUES 125
+
+#define ETH_DEV_NTNIC_HELP_ARG "help"
+#define ETH_DEV_NTHW_RXQUEUES_ARG "rxqs"
+#define ETH_DEV_NTHW_TXQUEUES_ARG "txqs"
+
+static const char *const valid_arguments[] = {
+	ETH_DEV_NTNIC_HELP_ARG,
+	ETH_DEV_NTHW_RXQUEUES_ARG,
+	ETH_DEV_NTHW_TXQUEUES_ARG,
+	NULL,
+};
+
+
 static const struct rte_pci_id nthw_pci_id_map[] = {
 	{ RTE_PCI_DEVICE(NT_HW_PCI_VENDOR_ID, NT_HW_PCI_DEVICE_ID_NT200A02) },
 	{
@@ -161,6 +183,58 @@ eth_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *dev_info
 	return 0;
 }
 
+static void eth_tx_queue_release(struct rte_eth_dev *eth_dev, uint16_t queue_id)
+{
+	(void)eth_dev;
+	(void)queue_id;
+}
+
+static void eth_rx_queue_release(struct rte_eth_dev *eth_dev, uint16_t queue_id)
+{
+	(void)eth_dev;
+	(void)queue_id;
+}
+
+static int num_queues_alloced;
+
+/* Returns num queue starting at returned queue num or -1 on fail */
+static int allocate_queue(int num)
+{
+	int next_free = num_queues_alloced;
+	NT_LOG_DBGX(DBG, NTNIC, "num_queues_alloced=%u, New queues=%u, Max queues=%u\n",
+		num_queues_alloced, num, MAX_TOTAL_QUEUES);
+
+	if (num_queues_alloced + num > MAX_TOTAL_QUEUES)
+		return -1;
+
+	num_queues_alloced += num;
+	return next_free;
+}
+
+static int eth_rx_queue_start(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id)
+{
+	eth_dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+}
+
+static int eth_rx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id)
+{
+	eth_dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
+static int eth_tx_queue_start(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id)
+{
+	eth_dev->data->tx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
+	return 0;
+}
+
+static int eth_tx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id)
+{
+	eth_dev->data->tx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
+	return 0;
+}
+
 static int
 eth_mac_addr_add(struct rte_eth_dev *eth_dev,
 	struct rte_ether_addr *mac_addr,
@@ -247,6 +321,15 @@ eth_dev_start(struct rte_eth_dev *eth_dev)
 
 	NT_LOG_DBGX(DBG, NTNIC, "Port %u\n", internals->n_intf_no);
 
+	/* Start queues */
+	uint q;
+
+	for (q = 0; q < internals->nb_rx_queues; q++)
+		eth_rx_queue_start(eth_dev, q);
+
+	for (q = 0; q < internals->nb_tx_queues; q++)
+		eth_tx_queue_start(eth_dev, q);
+
 	if (internals->type == PORT_TYPE_VIRTUAL || internals->type == PORT_TYPE_OVERRIDE) {
 		eth_dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
 
@@ -296,6 +379,16 @@ eth_dev_stop(struct rte_eth_dev *eth_dev)
 
 	NT_LOG_DBGX(DBG, NTNIC, "Port %u\n", internals->n_intf_no);
 
+	if (internals->type != PORT_TYPE_VIRTUAL) {
+		uint q;
+
+		for (q = 0; q < internals->nb_rx_queues; q++)
+			eth_rx_queue_stop(eth_dev, q);
+
+		for (q = 0; q < internals->nb_tx_queues; q++)
+			eth_tx_queue_stop(eth_dev, q);
+	}
+
 	eth_dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
 	return 0;
 }
@@ -438,6 +531,12 @@ static const struct eth_dev_ops nthw_eth_dev_ops = {
 	.link_update = eth_link_update,
 	.dev_infos_get = eth_dev_infos_get,
 	.fw_version_get = eth_fw_version_get,
+	.rx_queue_start = eth_rx_queue_start,
+	.rx_queue_stop = eth_rx_queue_stop,
+	.rx_queue_release = eth_rx_queue_release,
+	.tx_queue_start = eth_tx_queue_start,
+	.tx_queue_stop = eth_tx_queue_stop,
+	.tx_queue_release = eth_tx_queue_release,
 	.mac_addr_add = eth_mac_addr_add,
 	.mac_addr_set = eth_mac_addr_set,
 	.set_mc_addr_list = eth_set_mc_addr_list,
@@ -462,6 +561,7 @@ nthw_pci_dev_init(struct rte_pci_device *pci_dev)
 		return -1;
 	}
 
+	int res;
 	struct drv_s *p_drv;
 	ntdrv_4ga_t *p_nt_drv;
 	hw_info_t *p_hw_info;
@@ -469,6 +569,7 @@ nthw_pci_dev_init(struct rte_pci_device *pci_dev)
 	uint32_t n_port_mask = -1;	/* All ports enabled by default */
 	uint32_t nb_rx_queues = 1;
 	uint32_t nb_tx_queues = 1;
+	struct flow_queue_id_s queue_ids[MAX_QUEUES];
 	int n_phy_ports;
 	struct port_link_speed pls_mbps[NUM_ADAPTER_PORTS_MAX] = { 0 };
 	int num_port_speeds = 0;
@@ -476,6 +577,81 @@ nthw_pci_dev_init(struct rte_pci_device *pci_dev)
 		pci_dev->addr.function, pci_dev->addr.bus, pci_dev->addr.devid,
 		pci_dev->addr.function);
 
+	/*
+	 * Process options/arguments
+	 */
+	if (pci_dev->device.devargs && pci_dev->device.devargs->args) {
+		int kvargs_count;
+		struct rte_kvargs *kvlist =
+			rte_kvargs_parse(pci_dev->device.devargs->args, valid_arguments);
+
+		if (kvlist == NULL)
+			return -1;
+
+		/*
+		 * Argument: help
+		 * NOTE: this argument/option check should be the first as it will stop
+		 * execution after producing its output
+		 */
+		{
+			if (rte_kvargs_get(kvlist, ETH_DEV_NTNIC_HELP_ARG)) {
+				size_t i;
+
+				for (i = 0; i < RTE_DIM(valid_arguments); i++)
+					if (valid_arguments[i] == NULL)
+						break;
+
+				exit(0);
+			}
+		}
+
+		/*
+		 * rxq option/argument
+		 * The number of rxq (hostbuffers) allocated in memory.
+		 * Default is 32 RX Hostbuffers
+		 */
+		kvargs_count = rte_kvargs_count(kvlist, ETH_DEV_NTHW_RXQUEUES_ARG);
+
+		if (kvargs_count != 0) {
+			assert(kvargs_count == 1);
+			res = rte_kvargs_process(kvlist, ETH_DEV_NTHW_RXQUEUES_ARG, &string_to_u32,
+					&nb_rx_queues);
+
+			if (res < 0) {
+				NT_LOG_DBGX(ERR, NTNIC,
+					"problem with command line arguments: res=%d\n",
+					res);
+				return -1;
+			}
+
+			NT_LOG_DBGX(DBG, NTNIC, "devargs: %s=%u\n",
+				ETH_DEV_NTHW_RXQUEUES_ARG, nb_rx_queues);
+		}
+
+		/*
+		 * txq option/argument
+		 * The number of txq (hostbuffers) allocated in memory.
+		 * Default is 32 TX Hostbuffers
+		 */
+		kvargs_count = rte_kvargs_count(kvlist, ETH_DEV_NTHW_TXQUEUES_ARG);
+
+		if (kvargs_count != 0) {
+			assert(kvargs_count == 1);
+			res = rte_kvargs_process(kvlist, ETH_DEV_NTHW_TXQUEUES_ARG, &string_to_u32,
+					&nb_tx_queues);
+
+			if (res < 0) {
+				NT_LOG_DBGX(ERR, NTNIC,
+					"problem with command line arguments: res=%d\n",
+					res);
+				return -1;
+			}
+
+			NT_LOG_DBGX(DBG, NTNIC, "devargs: %s=%u\n",
+				ETH_DEV_NTHW_TXQUEUES_ARG, nb_tx_queues);
+		}
+	}
+
 
 	/* alloc */
 	p_drv = rte_zmalloc_socket(pci_dev->name, sizeof(struct drv_s), RTE_CACHE_LINE_SIZE,
@@ -581,6 +757,7 @@ nthw_pci_dev_init(struct rte_pci_device *pci_dev)
 		struct pmd_internals *internals = NULL;
 		struct rte_eth_dev *eth_dev = NULL;
 		char name[32];
+		int i;
 
 		if ((1 << n_intf_no) & ~n_port_mask) {
 			NT_LOG_DBGX(DBG, NTNIC,
@@ -608,6 +785,10 @@ nthw_pci_dev_init(struct rte_pci_device *pci_dev)
 		internals->nb_rx_queues = nb_rx_queues;
 		internals->nb_tx_queues = nb_tx_queues;
 
+		/* Not used queue index as dest port in bypass - use 0x80 + port nr */
+		for (i = 0; i < MAX_QUEUES; i++)
+			internals->vpq[i].hw_id = -1;
+
 
 		/* Setup queue_ids */
 		if (nb_rx_queues > 1) {
@@ -622,6 +803,33 @@ nthw_pci_dev_init(struct rte_pci_device *pci_dev)
 				internals->n_intf_no, nb_tx_queues);
 		}
 
+		int max_num_queues = (nb_rx_queues > nb_tx_queues) ? nb_rx_queues : nb_tx_queues;
+		int start_queue = allocate_queue(max_num_queues);
+
+		if (start_queue < 0)
+			return -1;
+
+		for (i = 0; i < (int)max_num_queues; i++) {
+			queue_ids[i].id = i;
+			queue_ids[i].hw_id = start_queue + i;
+
+			internals->rxq_scg[i].queue = queue_ids[i];
+			/* use same index in Rx and Tx rings */
+			internals->txq_scg[i].queue = queue_ids[i];
+			internals->rxq_scg[i].enabled = 0;
+			internals->txq_scg[i].type = internals->type;
+			internals->rxq_scg[i].type = internals->type;
+			internals->rxq_scg[i].port = internals->port;
+		}
+
+		/* no tx queues - tx data goes out on phy */
+		internals->vpq_nb_vq = 0;
+
+		for (i = 0; i < (int)nb_tx_queues; i++) {
+			internals->txq_scg[i].port = internals->port;
+			internals->txq_scg[i].enabled = 0;
+		}
+
 		/* Set MAC address (but only if the MAC address is permitted) */
 		if (n_intf_no < fpga_info->nthw_hw_info.vpd_info.mn_mac_addr_count) {
 			const uint64_t mac =
diff --git a/drivers/net/ntnic/ntutil/nt_util.c b/drivers/net/ntnic/ntutil/nt_util.c
index 72aabad090..7ee95d0642 100644
--- a/drivers/net/ntnic/ntutil/nt_util.c
+++ b/drivers/net/ntnic/ntutil/nt_util.c
@@ -234,3 +234,13 @@ int nt_link_duplex_to_eth_duplex(enum nt_link_duplex_e nt_link_duplex)
 
 	return eth_link_duplex;
 }
+
+int string_to_u32(const char *key_str __rte_unused, const char *value_str, void *extra_args)
+{
+	if (!value_str || !extra_args)
+		return -1;
+
+	const uint32_t value = strtol(value_str, NULL, 0);
+	*(uint32_t *)extra_args = value;
+	return 0;
+}
diff --git a/drivers/net/ntnic/ntutil/nt_util.h b/drivers/net/ntnic/ntutil/nt_util.h
index d82e6d3248..64947f5fbf 100644
--- a/drivers/net/ntnic/ntutil/nt_util.h
+++ b/drivers/net/ntnic/ntutil/nt_util.h
@@ -57,4 +57,6 @@ uint32_t nt_link_speed_capa_to_eth_speed_capa(int nt_link_speed_capa);
 nt_link_speed_t convert_link_speed(int link_speed_mbps);
 int nt_link_duplex_to_eth_duplex(enum nt_link_duplex_e nt_link_duplex);
 
+int string_to_u32(const char *key_str __rte_unused, const char *value_str, void *extra_args);
+
 #endif	/* NTOSS_SYSTEM_NT_UTIL_H */
-- 
2.45.0


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

* [PATCH v1 02/14] net/ntnic: enhance Ethernet device configuration
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (38 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 01/14] net/ntnic: add basic queue operations Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 03/14] net/ntnic: add scatter-gather HW deallocation Serhii Iliushyk
                   ` (11 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

Added eth_dev_close function to handle closing of Ethernet devices.
It releases managed RX/TX virtual queues.

Initialized scatter-gather queue system.

Defined constants and macros for hardware RX/TX descriptors and
packet buffer sizes.

Defined structures for RX and TX packet headers including
fields for packet length, descriptors, and color types.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 drivers/net/ntnic/include/ntnic_dbs.h        | 19 ++++
 drivers/net/ntnic/include/ntnic_virt_queue.h | 22 +++++
 drivers/net/ntnic/include/ntos_drv.h         | 15 ++++
 drivers/net/ntnic/nthw/nthw_drv.h            |  1 +
 drivers/net/ntnic/ntnic_ethdev.c             | 67 ++++++++++++++
 drivers/net/ntnic/ntnic_mod_reg.c            |  5 ++
 drivers/net/ntnic/ntnic_mod_reg.h            | 93 ++++++++++++++++++++
 7 files changed, 222 insertions(+)
 create mode 100644 drivers/net/ntnic/include/ntnic_dbs.h
 create mode 100644 drivers/net/ntnic/include/ntnic_virt_queue.h

diff --git a/drivers/net/ntnic/include/ntnic_dbs.h b/drivers/net/ntnic/include/ntnic_dbs.h
new file mode 100644
index 0000000000..551c6ade43
--- /dev/null
+++ b/drivers/net/ntnic/include/ntnic_dbs.h
@@ -0,0 +1,19 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _NTNIC_DBS_H_
+#define _NTNIC_DBS_H_
+
+#include "nthw_fpga_model.h"
+
+/*
+ * Struct for implementation of memory bank shadows
+ */
+
+struct nthw_dbs_s;
+
+typedef struct nthw_dbs_s nthw_dbs_t;
+
+#endif	/* _NTNIC_DBS_H_ */
diff --git a/drivers/net/ntnic/include/ntnic_virt_queue.h b/drivers/net/ntnic/include/ntnic_virt_queue.h
new file mode 100644
index 0000000000..422ac3b950
--- /dev/null
+++ b/drivers/net/ntnic/include/ntnic_virt_queue.h
@@ -0,0 +1,22 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NTOSS_VIRT_QUEUE_H__
+#define __NTOSS_VIRT_QUEUE_H__
+
+#include <stdint.h>
+#include <stdalign.h>
+
+#include <rte_memory.h>
+
+struct nthw_virt_queue;
+
+struct nthw_virtq_desc_buf;
+
+struct nthw_cvirtq_desc;
+
+struct nthw_received_packets;
+
+#endif /* __NTOSS_VIRT_QUEUE_H__ */
diff --git a/drivers/net/ntnic/include/ntos_drv.h b/drivers/net/ntnic/include/ntos_drv.h
index a77e6a0247..191686a07a 100644
--- a/drivers/net/ntnic/include/ntos_drv.h
+++ b/drivers/net/ntnic/include/ntos_drv.h
@@ -27,12 +27,25 @@
 #define MAX_QUEUES       125
 
 /* Structs: */
+struct nthw_memory_descriptor {
+	void *virt_addr;
+	uint32_t len;
+};
+
+struct hwq_s {
+	int vf_num;
+	struct nthw_memory_descriptor virt_queues_ctrl;
+	struct nthw_memory_descriptor *pkt_buffers;
+};
+
 struct __rte_cache_aligned ntnic_rx_queue {
 	struct flow_queue_id_s queue;    /* queue info - user id and hw queue index */
 	struct rte_mempool *mb_pool; /* mbuf memory pool */
 	uint16_t buf_size; /* Size of data area in mbuf */
 	int  enabled;  /* Enabling/disabling of this queue */
 
+	struct hwq_s           hwq;
+	struct nthw_virt_queue *vq;
 	nt_meta_port_type_t type;
 	uint32_t port;     /* Rx port for this queue */
 	enum fpga_info_profile profile;  /* Inline / Capture */
@@ -41,6 +54,8 @@ struct __rte_cache_aligned ntnic_rx_queue {
 
 struct __rte_cache_aligned ntnic_tx_queue {
 	struct flow_queue_id_s queue; /* queue info - user id and hw queue index */
+	struct hwq_s hwq;
+	struct nthw_virt_queue *vq;
 	nt_meta_port_type_t type;
 
 	uint32_t port;     /* Tx port for this queue */
diff --git a/drivers/net/ntnic/nthw/nthw_drv.h b/drivers/net/ntnic/nthw/nthw_drv.h
index 41500f49dd..eaa2b19015 100644
--- a/drivers/net/ntnic/nthw/nthw_drv.h
+++ b/drivers/net/ntnic/nthw/nthw_drv.h
@@ -7,6 +7,7 @@
 #define __NTHW_DRV_H__
 
 #include "nthw_core.h"
+#include "ntnic_dbs.h"
 
 typedef enum nt_meta_port_type_e {
 	PORT_TYPE_PHYSICAL,
diff --git a/drivers/net/ntnic/ntnic_ethdev.c b/drivers/net/ntnic/ntnic_ethdev.c
index 967e989575..79b5ae4d60 100644
--- a/drivers/net/ntnic/ntnic_ethdev.c
+++ b/drivers/net/ntnic/ntnic_ethdev.c
@@ -53,6 +53,8 @@ static const struct rte_pci_id nthw_pci_id_map[] = {
 	},	/* sentinel */
 };
 
+static const struct sg_ops_s *sg_ops;
+
 static rte_spinlock_t hwlock = RTE_SPINLOCK_INITIALIZER;
 
 /*
@@ -183,6 +185,14 @@ eth_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *dev_info
 	return 0;
 }
 
+static void release_hw_virtio_queues(struct hwq_s *hwq)
+{
+	if (!hwq || hwq->vf_num == 0)
+		return;
+
+	hwq->vf_num = 0;
+}
+
 static void eth_tx_queue_release(struct rte_eth_dev *eth_dev, uint16_t queue_id)
 {
 	(void)eth_dev;
@@ -474,6 +484,21 @@ eth_dev_close(struct rte_eth_dev *eth_dev)
 	struct pmd_internals *internals = (struct pmd_internals *)eth_dev->data->dev_private;
 	struct drv_s *p_drv = internals->p_drv;
 
+	if (internals->type != PORT_TYPE_VIRTUAL) {
+		struct ntnic_rx_queue *rx_q = internals->rxq_scg;
+		struct ntnic_tx_queue *tx_q = internals->txq_scg;
+
+		uint q;
+
+		if (sg_ops != NULL) {
+			for (q = 0; q < internals->nb_rx_queues; q++)
+				sg_ops->nthw_release_mngd_rx_virt_queue(rx_q[q].vq);
+
+			for (q = 0; q < internals->nb_tx_queues; q++)
+				sg_ops->nthw_release_mngd_tx_virt_queue(tx_q[q].vq);
+		}
+	}
+
 	internals->p_drv = NULL;
 
 	if (p_drv) {
@@ -728,6 +753,28 @@ nthw_pci_dev_init(struct rte_pci_device *pci_dev)
 		return -1;
 	}
 
+	/* Initialize the queue system */
+	if (err == 0) {
+		sg_ops = get_sg_ops();
+
+		if (sg_ops != NULL) {
+			err = sg_ops->nthw_virt_queue_init(fpga_info);
+
+			if (err != 0) {
+				NT_LOG(ERR, NTNIC,
+					"%s: Cannot initialize scatter-gather queues\n",
+					p_nt_drv->adapter_info.mp_adapter_id_str);
+
+			} else {
+				NT_LOG(DBG, NTNIC, "%s: Initialized scatter-gather queues\n",
+					p_nt_drv->adapter_info.mp_adapter_id_str);
+			}
+
+		} else {
+			NT_LOG_DBGX(DBG, NTNIC, "SG module is not initialized\n");
+		}
+	}
+
 	/* Start ctrl, monitor, stat thread only for primary process. */
 	if (err == 0) {
 		/* mp_adapter_id_str is initialized after nt4ga_adapter_init(p_nt_drv) */
@@ -891,6 +938,26 @@ nthw_pci_dev_deinit(struct rte_eth_dev *eth_dev __rte_unused)
 	ntdrv_4ga_t *p_ntdrv = &internals->p_drv->ntdrv;
 	fpga_info_t *fpga_info = &p_ntdrv->adapter_info.fpga_info;
 	const int n_phy_ports = fpga_info->n_phy_ports;
+
+	/* let running threads end Rx and Tx activity */
+	if (sg_ops != NULL) {
+		nt_os_wait_usec(1 * 1000 * 1000);
+
+		while (internals) {
+			for (i = internals->nb_tx_queues - 1; i >= 0; i--) {
+				sg_ops->nthw_release_mngd_tx_virt_queue(internals->txq_scg[i].vq);
+				release_hw_virtio_queues(&internals->txq_scg[i].hwq);
+			}
+
+			for (i = internals->nb_rx_queues - 1; i >= 0; i--) {
+				sg_ops->nthw_release_mngd_rx_virt_queue(internals->rxq_scg[i].vq);
+				release_hw_virtio_queues(&internals->rxq_scg[i].hwq);
+			}
+
+			internals = internals->next;
+		}
+	}
+
 	for (i = 0; i < n_phy_ports; i++) {
 		sprintf(name, "ntnic%d", i);
 		eth_dev = rte_eth_dev_allocated(name);
diff --git a/drivers/net/ntnic/ntnic_mod_reg.c b/drivers/net/ntnic/ntnic_mod_reg.c
index ff9afbeb7c..8fe5193027 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.c
+++ b/drivers/net/ntnic/ntnic_mod_reg.c
@@ -5,6 +5,11 @@
 
 #include "ntnic_mod_reg.h"
 
+const struct sg_ops_s *get_sg_ops(void)
+{
+	return NULL;
+}
+
 static struct link_ops_s *link_100g_ops;
 
 void register_100g_link_ops(struct link_ops_s *ops)
diff --git a/drivers/net/ntnic/ntnic_mod_reg.h b/drivers/net/ntnic/ntnic_mod_reg.h
index 602f5de77d..e9dff51935 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.h
+++ b/drivers/net/ntnic/ntnic_mod_reg.h
@@ -13,6 +13,99 @@
 #include "nthw_drv.h"
 #include "nt4ga_adapter.h"
 #include "ntnic_nthw_fpga_rst_nt200a0x.h"
+#include "ntnic_virt_queue.h"
+
+/* sg ops section */
+struct sg_ops_s {
+	/* Setup a virtQueue for a VM */
+	struct nthw_virt_queue *(*nthw_setup_rx_virt_queue)(nthw_dbs_t *p_nthw_dbs,
+		uint32_t index,
+		uint16_t start_idx,
+		uint16_t start_ptr,
+		void *avail_struct_phys_addr,
+		void *used_struct_phys_addr,
+		void *desc_struct_phys_addr,
+		uint16_t queue_size,
+		uint32_t host_id,
+		uint32_t header,
+		uint32_t vq_type,
+		int irq_vector);
+	struct nthw_virt_queue *(*nthw_setup_tx_virt_queue)(nthw_dbs_t *p_nthw_dbs,
+		uint32_t index,
+		uint16_t start_idx,
+		uint16_t start_ptr,
+		void *avail_struct_phys_addr,
+		void *used_struct_phys_addr,
+		void *desc_struct_phys_addr,
+		uint16_t queue_size,
+		uint32_t host_id,
+		uint32_t port,
+		uint32_t virtual_port,
+		uint32_t header,
+		uint32_t vq_type,
+		int irq_vector,
+		uint32_t in_order);
+	struct nthw_virt_queue *(*nthw_setup_mngd_rx_virt_queue)(nthw_dbs_t *p_nthw_dbs,
+		uint32_t index,
+		uint32_t queue_size,
+		uint32_t host_id,
+		uint32_t header,
+		/*
+		 * Memory that can be used
+		 * for virtQueue structs
+		 */
+		struct nthw_memory_descriptor *p_virt_struct_area,
+		/*
+		 * Memory that can be used for packet
+		 * buffers - Array must have queue_size
+		 * entries
+		 */
+		struct nthw_memory_descriptor *p_packet_buffers,
+		uint32_t vq_type,
+		int irq_vector);
+	int (*nthw_release_mngd_rx_virt_queue)(struct nthw_virt_queue *rxvq);
+	struct nthw_virt_queue *(*nthw_setup_mngd_tx_virt_queue)(nthw_dbs_t *p_nthw_dbs,
+		uint32_t index,
+		uint32_t queue_size,
+		uint32_t host_id,
+		uint32_t port,
+		uint32_t virtual_port,
+		uint32_t header,
+		/*
+		 * Memory that can be used
+		 * for virtQueue structs
+		 */
+		struct nthw_memory_descriptor *p_virt_struct_area,
+		/*
+		 * Memory that can be used for packet
+		 * buffers - Array must have queue_size
+		 * entries
+		 */
+		struct nthw_memory_descriptor *p_packet_buffers,
+		uint32_t vq_type,
+		int irq_vector,
+		uint32_t in_order);
+	int (*nthw_release_mngd_tx_virt_queue)(struct nthw_virt_queue *txvq);
+	/*
+	 * These functions handles both Split and Packed including merged buffers (jumbo)
+	 */
+	uint16_t (*nthw_get_rx_packets)(struct nthw_virt_queue *rxvq,
+		uint16_t n,
+		struct nthw_received_packets *rp,
+		uint16_t *nb_pkts);
+	void (*nthw_release_rx_packets)(struct nthw_virt_queue *rxvq, uint16_t n);
+	uint16_t (*nthw_get_tx_packets)(struct nthw_virt_queue *txvq,
+		uint16_t n,
+		uint16_t *first_idx,
+		struct nthw_cvirtq_desc *cvq,
+		struct nthw_memory_descriptor **p_virt_addr);
+	void (*nthw_release_tx_packets)(struct nthw_virt_queue *txvq,
+		uint16_t n,
+		uint16_t n_segs[]);
+	int (*nthw_virt_queue_init)(struct fpga_info_s *p_fpga_info);
+};
+
+const struct sg_ops_s *get_sg_ops(void);
 
 struct link_ops_s {
 	int (*link_init)(struct adapter_info_s *p_adapter_info, nthw_fpga_t *p_fpga);
-- 
2.45.0


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

* [PATCH v1 03/14] net/ntnic: add scatter-gather HW deallocation
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (39 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 02/14] net/ntnic: enhance Ethernet device configuration Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 04/14] net/ntnic: add queue setup operations Serhii Iliushyk
                   ` (10 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

Deallocates memory for hardware Virtio queues and unmaps
VFIO resources.

Updated eth_tx_queue_release and eth_rx_queue_release. Released
hardware Virtio queues for TX and RX.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 drivers/net/ntnic/include/ntos_drv.h |  1 +
 drivers/net/ntnic/ntnic_ethdev.c     | 32 ++++++++++++++++++++++++----
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ntnic/include/ntos_drv.h b/drivers/net/ntnic/include/ntos_drv.h
index 191686a07a..233d585303 100644
--- a/drivers/net/ntnic/include/ntos_drv.h
+++ b/drivers/net/ntnic/include/ntos_drv.h
@@ -28,6 +28,7 @@
 
 /* Structs: */
 struct nthw_memory_descriptor {
+	void *phys_addr;
 	void *virt_addr;
 	uint32_t len;
 };
diff --git a/drivers/net/ntnic/ntnic_ethdev.c b/drivers/net/ntnic/ntnic_ethdev.c
index 79b5ae4d60..78a689d444 100644
--- a/drivers/net/ntnic/ntnic_ethdev.c
+++ b/drivers/net/ntnic/ntnic_ethdev.c
@@ -34,6 +34,8 @@
 /* Max RSS queues */
 #define MAX_QUEUES 125
 
+#define ONE_G_SIZE  0x40000000
+
 #define ETH_DEV_NTNIC_HELP_ARG "help"
 #define ETH_DEV_NTHW_RXQUEUES_ARG "rxqs"
 #define ETH_DEV_NTHW_TXQUEUES_ARG "txqs"
@@ -193,16 +195,38 @@ static void release_hw_virtio_queues(struct hwq_s *hwq)
 	hwq->vf_num = 0;
 }
 
+static int deallocate_hw_virtio_queues(struct hwq_s *hwq)
+{
+	int vf_num = hwq->vf_num;
+
+	void *virt = hwq->virt_queues_ctrl.virt_addr;
+
+	int res = nt_vfio_dma_unmap(vf_num, hwq->virt_queues_ctrl.virt_addr,
+			(uint64_t)hwq->virt_queues_ctrl.phys_addr, ONE_G_SIZE);
+
+	if (res != 0) {
+		NT_LOG(ERR, NTNIC, "VFIO UNMMAP FAILED! res %i, vf_num %i\n", res, vf_num);
+		return -1;
+	}
+
+	release_hw_virtio_queues(hwq);
+	rte_free(hwq->pkt_buffers);
+	rte_free(virt);
+	return 0;
+}
+
 static void eth_tx_queue_release(struct rte_eth_dev *eth_dev, uint16_t queue_id)
 {
-	(void)eth_dev;
-	(void)queue_id;
+	struct pmd_internals *internals = (struct pmd_internals *)eth_dev->data->dev_private;
+	struct ntnic_tx_queue *tx_q = &internals->txq_scg[queue_id];
+	deallocate_hw_virtio_queues(&tx_q->hwq);
 }
 
 static void eth_rx_queue_release(struct rte_eth_dev *eth_dev, uint16_t queue_id)
 {
-	(void)eth_dev;
-	(void)queue_id;
+	struct pmd_internals *internals = (struct pmd_internals *)eth_dev->data->dev_private;
+	struct ntnic_rx_queue *rx_q = &internals->rxq_scg[queue_id];
+	deallocate_hw_virtio_queues(&rx_q->hwq);
 }
 
 static int num_queues_alloced;
-- 
2.45.0


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

* [PATCH v1 04/14] net/ntnic: add queue setup operations
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (40 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 03/14] net/ntnic: add scatter-gather HW deallocation Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 05/14] net/ntnic: add packet handler for virtio queues Serhii Iliushyk
                   ` (9 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

Added TX and RX queue setup. Handles memory allocation
and hardware Virtio queue setup.

Allocates and configures memory for hardware Virtio queues,
including handling IOMMU and VFIO mappings.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 drivers/net/ntnic/include/ntnic_virt_queue.h |   3 +-
 drivers/net/ntnic/include/ntos_drv.h         |   6 +
 drivers/net/ntnic/nthw/nthw_drv.h            |   2 +
 drivers/net/ntnic/ntnic_ethdev.c             | 323 +++++++++++++++++++
 4 files changed, 333 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ntnic/include/ntnic_virt_queue.h b/drivers/net/ntnic/include/ntnic_virt_queue.h
index 422ac3b950..821b23af6c 100644
--- a/drivers/net/ntnic/include/ntnic_virt_queue.h
+++ b/drivers/net/ntnic/include/ntnic_virt_queue.h
@@ -13,7 +13,8 @@
 
 struct nthw_virt_queue;
 
-struct nthw_virtq_desc_buf;
+#define SPLIT_RING        0
+#define IN_ORDER          1
 
 struct nthw_cvirtq_desc;
 
diff --git a/drivers/net/ntnic/include/ntos_drv.h b/drivers/net/ntnic/include/ntos_drv.h
index 233d585303..933b012e07 100644
--- a/drivers/net/ntnic/include/ntos_drv.h
+++ b/drivers/net/ntnic/include/ntos_drv.h
@@ -47,6 +47,7 @@ struct __rte_cache_aligned ntnic_rx_queue {
 
 	struct hwq_s           hwq;
 	struct nthw_virt_queue *vq;
+	int nb_hw_rx_descr;
 	nt_meta_port_type_t type;
 	uint32_t port;     /* Rx port for this queue */
 	enum fpga_info_profile profile;  /* Inline / Capture */
@@ -57,7 +58,12 @@ struct __rte_cache_aligned ntnic_tx_queue {
 	struct flow_queue_id_s queue; /* queue info - user id and hw queue index */
 	struct hwq_s hwq;
 	struct nthw_virt_queue *vq;
+	int nb_hw_tx_descr;
+	/* Used for bypass in NTDVIO0 header on  Tx - pre calculated */
+	int target_id;
 	nt_meta_port_type_t type;
+	/* only used for exception tx queue from OVS SW switching */
+	int rss_target_id;
 
 	uint32_t port;     /* Tx port for this queue */
 	int  enabled;  /* Enabling/disabling of this queue */
diff --git a/drivers/net/ntnic/nthw/nthw_drv.h b/drivers/net/ntnic/nthw/nthw_drv.h
index eaa2b19015..69e0360f5f 100644
--- a/drivers/net/ntnic/nthw/nthw_drv.h
+++ b/drivers/net/ntnic/nthw/nthw_drv.h
@@ -71,6 +71,8 @@ typedef struct fpga_info_s {
 	struct nthw_pcie3 *mp_nthw_pcie3;
 	struct nthw_tsm *mp_nthw_tsm;
 
+	nthw_dbs_t *mp_nthw_dbs;
+
 	uint8_t *bar0_addr;	/* Needed for register read/write */
 	size_t bar0_size;
 
diff --git a/drivers/net/ntnic/ntnic_ethdev.c b/drivers/net/ntnic/ntnic_ethdev.c
index 78a689d444..57827d73d5 100644
--- a/drivers/net/ntnic/ntnic_ethdev.c
+++ b/drivers/net/ntnic/ntnic_ethdev.c
@@ -31,10 +31,16 @@
 
 #define MAX_TOTAL_QUEUES       128
 
+#define SG_NB_HW_RX_DESCRIPTORS 1024
+#define SG_NB_HW_TX_DESCRIPTORS 1024
+#define SG_HW_RX_PKT_BUFFER_SIZE (1024 << 1)
+#define SG_HW_TX_PKT_BUFFER_SIZE (1024 << 1)
+
 /* Max RSS queues */
 #define MAX_QUEUES 125
 
 #define ONE_G_SIZE  0x40000000
+#define ONE_G_MASK  (ONE_G_SIZE - 1)
 
 #define ETH_DEV_NTNIC_HELP_ARG "help"
 #define ETH_DEV_NTHW_RXQUEUES_ARG "rxqs"
@@ -187,6 +193,157 @@ eth_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *dev_info
 	return 0;
 }
 
+static int allocate_hw_virtio_queues(struct rte_eth_dev *eth_dev, int vf_num, struct hwq_s *hwq,
+	int num_descr, int buf_size)
+{
+	int i, res;
+	uint32_t size;
+	uint64_t iova_addr;
+
+	NT_LOG(DBG, NTNIC, "***** Configure IOMMU for HW queues on VF %i *****\n", vf_num);
+
+	/* Just allocate 1MB to hold all combined descr rings */
+	uint64_t tot_alloc_size = 0x100000 + buf_size * num_descr;
+
+	void *virt =
+		rte_malloc_socket("VirtQDescr", tot_alloc_size, nt_util_align_size(tot_alloc_size),
+			eth_dev->data->numa_node);
+
+	if (!virt)
+		return -1;
+
+	uint64_t gp_offset = (uint64_t)virt & ONE_G_MASK;
+	rte_iova_t hpa = rte_malloc_virt2iova(virt);
+
+	NT_LOG(DBG, NTNIC, "Allocated virtio descr rings : virt "
+		"%p [0x%" PRIX64 "],hpa %" PRIX64 " [0x%" PRIX64 "]\n",
+		virt, gp_offset, hpa, hpa & ONE_G_MASK);
+
+	/*
+	 * Same offset on both HPA and IOVA
+	 * Make sure 1G boundary is never crossed
+	 */
+	if (((hpa & ONE_G_MASK) != gp_offset) ||
+		(((uint64_t)virt + tot_alloc_size) & ~ONE_G_MASK) !=
+		((uint64_t)virt & ~ONE_G_MASK)) {
+		NT_LOG(ERR, NTNIC, "*********************************************************\n");
+		NT_LOG(ERR, NTNIC, "ERROR, no optimal IOMMU mapping available hpa: %016" PRIX64
+			"(%016" PRIX64 "), gp_offset: %016" PRIX64 " size: %" PRIu64 "\n",
+			hpa, hpa & ONE_G_MASK, gp_offset, tot_alloc_size);
+		NT_LOG(ERR, NTNIC, "*********************************************************\n");
+
+		rte_free(virt);
+
+		/* Just allocate 1MB to hold all combined descr rings */
+		size = 0x100000;
+		void *virt = rte_malloc_socket("VirtQDescr", size, 4096, eth_dev->data->numa_node);
+
+		if (!virt)
+			return -1;
+
+		res = nt_vfio_dma_map(vf_num, virt, &iova_addr, size);
+
+		NT_LOG(DBG, NTNIC, "VFIO MMAP res %i, vf_num %i\n", res, vf_num);
+
+		if (res != 0)
+			return -1;
+
+		hwq->vf_num = vf_num;
+		hwq->virt_queues_ctrl.virt_addr = virt;
+		hwq->virt_queues_ctrl.phys_addr = (void *)iova_addr;
+		hwq->virt_queues_ctrl.len = size;
+
+		NT_LOG(DBG, NTNIC,
+			"Allocated for virtio descr rings combined 1MB : %p, IOVA %016" PRIX64 "\n",
+			virt, iova_addr);
+
+		size = num_descr * sizeof(struct nthw_memory_descriptor);
+		hwq->pkt_buffers =
+			rte_zmalloc_socket("rx_pkt_buffers", size, 64, eth_dev->data->numa_node);
+
+		if (!hwq->pkt_buffers) {
+			NT_LOG(ERR, NTNIC,
+				"Failed to allocated buffer array for hw-queue %p, total size %i, elements %i\n",
+				hwq->pkt_buffers, size, num_descr);
+			rte_free(virt);
+			return -1;
+		}
+
+		size = buf_size * num_descr;
+		void *virt_addr =
+			rte_malloc_socket("pkt_buffer_pkts", size, 4096, eth_dev->data->numa_node);
+
+		if (!virt_addr) {
+			NT_LOG(ERR, NTNIC,
+				"Failed allocate packet buffers for hw-queue %p, buf size %i, elements %i\n",
+				hwq->pkt_buffers, buf_size, num_descr);
+			rte_free(hwq->pkt_buffers);
+			rte_free(virt);
+			return -1;
+		}
+
+		res = nt_vfio_dma_map(vf_num, virt_addr, &iova_addr, size);
+
+		NT_LOG(DBG, NTNIC,
+			"VFIO MMAP res %i, virt %p, iova %016" PRIX64 ", vf_num %i, num pkt bufs %i, tot size %i\n",
+			res, virt_addr, iova_addr, vf_num, num_descr, size);
+
+		if (res != 0)
+			return -1;
+
+		for (i = 0; i < num_descr; i++) {
+			hwq->pkt_buffers[i].virt_addr =
+				(void *)((char *)virt_addr + ((uint64_t)(i) * buf_size));
+			hwq->pkt_buffers[i].phys_addr =
+				(void *)(iova_addr + ((uint64_t)(i) * buf_size));
+			hwq->pkt_buffers[i].len = buf_size;
+		}
+
+		return 0;
+	}	/* End of: no optimal IOMMU mapping available */
+
+	res = nt_vfio_dma_map(vf_num, virt, &iova_addr, ONE_G_SIZE);
+
+	if (res != 0) {
+		NT_LOG(ERR, NTNIC, "VFIO MMAP FAILED! res %i, vf_num %i\n", res, vf_num);
+		return -1;
+	}
+
+	hwq->vf_num = vf_num;
+	hwq->virt_queues_ctrl.virt_addr = virt;
+	hwq->virt_queues_ctrl.phys_addr = (void *)(iova_addr);
+	hwq->virt_queues_ctrl.len = 0x100000;
+	iova_addr += 0x100000;
+
+	NT_LOG(DBG, NTNIC,
+		"VFIO MMAP: virt_addr=%p phys_addr=%p size=%" PRIX32 " hpa=%" PRIX64 "\n",
+		hwq->virt_queues_ctrl.virt_addr, hwq->virt_queues_ctrl.phys_addr,
+		hwq->virt_queues_ctrl.len, rte_malloc_virt2iova(hwq->virt_queues_ctrl.virt_addr));
+
+	size = num_descr * sizeof(struct nthw_memory_descriptor);
+	hwq->pkt_buffers =
+		rte_zmalloc_socket("rx_pkt_buffers", size, 64, eth_dev->data->numa_node);
+
+	if (!hwq->pkt_buffers) {
+		NT_LOG(ERR, NTNIC,
+			"Failed to allocated buffer array for hw-queue %p, total size %i, elements %i\n",
+			hwq->pkt_buffers, size, num_descr);
+		rte_free(virt);
+		return -1;
+	}
+
+	void *virt_addr = (void *)((uint64_t)virt + 0x100000);
+
+	for (i = 0; i < num_descr; i++) {
+		hwq->pkt_buffers[i].virt_addr =
+			(void *)((char *)virt_addr + ((uint64_t)(i) * buf_size));
+		hwq->pkt_buffers[i].phys_addr = (void *)(iova_addr + ((uint64_t)(i) * buf_size));
+		hwq->pkt_buffers[i].len = buf_size;
+	}
+
+	return 0;
+}
+
 static void release_hw_virtio_queues(struct hwq_s *hwq)
 {
 	if (!hwq || hwq->vf_num == 0)
@@ -245,6 +402,170 @@ static int allocate_queue(int num)
 	return next_free;
 }
 
+static int eth_rx_scg_queue_setup(struct rte_eth_dev *eth_dev,
+	uint16_t rx_queue_id,
+	uint16_t nb_rx_desc __rte_unused,
+	unsigned int socket_id __rte_unused,
+	const struct rte_eth_rxconf *rx_conf __rte_unused,
+	struct rte_mempool *mb_pool)
+{
+	NT_LOG_DBGX(DBG, NTNIC, "\n");
+	struct rte_pktmbuf_pool_private *mbp_priv;
+	struct pmd_internals *internals = (struct pmd_internals *)eth_dev->data->dev_private;
+	struct ntnic_rx_queue *rx_q = &internals->rxq_scg[rx_queue_id];
+	struct drv_s *p_drv = internals->p_drv;
+	struct ntdrv_4ga_s *p_nt_drv = &p_drv->ntdrv;
+
+	if (sg_ops == NULL) {
+		NT_LOG_DBGX(DBG, NTNIC, "SG module is not initialized\n");
+		return 0;
+	}
+
+	if (internals->type == PORT_TYPE_OVERRIDE) {
+		rx_q->mb_pool = mb_pool;
+		eth_dev->data->rx_queues[rx_queue_id] = rx_q;
+		mbp_priv = rte_mempool_get_priv(rx_q->mb_pool);
+		rx_q->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size - RTE_PKTMBUF_HEADROOM);
+		rx_q->enabled = 1;
+		return 0;
+	}
+
+	NT_LOG(DBG, NTNIC, "(%i) NTNIC RX OVS-SW queue setup: queue id %i, hw queue index %i\n",
+		internals->port, rx_queue_id, rx_q->queue.hw_id);
+
+	rx_q->mb_pool = mb_pool;
+
+	eth_dev->data->rx_queues[rx_queue_id] = rx_q;
+
+	mbp_priv = rte_mempool_get_priv(rx_q->mb_pool);
+	rx_q->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size - RTE_PKTMBUF_HEADROOM);
+	rx_q->enabled = 1;
+
+	if (allocate_hw_virtio_queues(eth_dev, EXCEPTION_PATH_HID, &rx_q->hwq,
+			SG_NB_HW_RX_DESCRIPTORS, SG_HW_RX_PKT_BUFFER_SIZE) < 0)
+		return -1;
+
+	rx_q->nb_hw_rx_descr = SG_NB_HW_RX_DESCRIPTORS;
+
+	rx_q->profile = p_drv->ntdrv.adapter_info.fpga_info.profile;
+
+	rx_q->vq =
+		sg_ops->nthw_setup_mngd_rx_virt_queue(p_nt_drv->adapter_info.fpga_info.mp_nthw_dbs,
+			rx_q->queue.hw_id,	/* index */
+			rx_q->nb_hw_rx_descr,
+			EXCEPTION_PATH_HID,	/* host_id */
+			1,	/* header NT DVIO header for exception path */
+			&rx_q->hwq.virt_queues_ctrl,
+			rx_q->hwq.pkt_buffers,
+			SPLIT_RING,
+			-1);
+
+	NT_LOG(DBG, NTNIC, "(%i) NTNIC RX OVS-SW queues successfully setup\n", internals->port);
+
+	return 0;
+}
+
+static int eth_tx_scg_queue_setup(struct rte_eth_dev *eth_dev,
+	uint16_t tx_queue_id,
+	uint16_t nb_tx_desc __rte_unused,
+	unsigned int socket_id __rte_unused,
+	const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	const struct port_ops *port_ops = get_port_ops();
+
+	if (port_ops == NULL) {
+		NT_LOG_DBGX(ERR, NTNIC, "Link management module uninitialized\n");
+		return -1;
+	}
+
+	NT_LOG_DBGX(DBG, NTNIC, "\n");
+	struct pmd_internals *internals = (struct pmd_internals *)eth_dev->data->dev_private;
+	struct drv_s *p_drv = internals->p_drv;
+	struct ntdrv_4ga_s *p_nt_drv = &p_drv->ntdrv;
+	struct ntnic_tx_queue *tx_q = &internals->txq_scg[tx_queue_id];
+
+	if (internals->type == PORT_TYPE_OVERRIDE) {
+		eth_dev->data->tx_queues[tx_queue_id] = tx_q;
+		return 0;
+	}
+
+	if (sg_ops == NULL) {
+		NT_LOG_DBGX(DBG, NTNIC, "SG module is not initialized\n");
+		return 0;
+	}
+
+	NT_LOG(DBG, NTNIC, "(%i) NTNIC TX OVS-SW queue setup: queue id %i, hw queue index %i\n",
+		tx_q->port, tx_queue_id, tx_q->queue.hw_id);
+
+	if (tx_queue_id > internals->nb_tx_queues) {
+		NT_LOG(ERR, NTNIC, "Error invalid tx queue id\n");
+		return -1;
+	}
+
+	eth_dev->data->tx_queues[tx_queue_id] = tx_q;
+
+	/* Calculate target ID for HW  - to be used in NTDVIO0 header bypass_port */
+	if (tx_q->rss_target_id >= 0) {
+		/* bypass to a multiqueue port - qsl-hsh index */
+		tx_q->target_id = tx_q->rss_target_id + 0x90;
+
+	} else if (internals->vpq[tx_queue_id].hw_id > -1) {
+		/* virtual port - queue index */
+		tx_q->target_id = internals->vpq[tx_queue_id].hw_id;
+
+	} else {
+		/* Phy port - phy port identifier */
+		/* output/bypass to MAC */
+		tx_q->target_id = (int)(tx_q->port + 0x80);
+	}
+
+	if (allocate_hw_virtio_queues(eth_dev, EXCEPTION_PATH_HID, &tx_q->hwq,
+			SG_NB_HW_TX_DESCRIPTORS, SG_HW_TX_PKT_BUFFER_SIZE) < 0) {
+		return -1;
+	}
+
+	tx_q->nb_hw_tx_descr = SG_NB_HW_TX_DESCRIPTORS;
+
+	tx_q->profile = p_drv->ntdrv.adapter_info.fpga_info.profile;
+
+	uint32_t port, header;
+	port = tx_q->port;	/* transmit port */
+	header = 0;	/* header type VirtIO-Net */
+
+	tx_q->vq =
+		sg_ops->nthw_setup_mngd_tx_virt_queue(p_nt_drv->adapter_info.fpga_info.mp_nthw_dbs,
+			tx_q->queue.hw_id,	/* index */
+			tx_q->nb_hw_tx_descr,	/* queue size */
+			EXCEPTION_PATH_HID,	/* host_id always VF4 */
+			port,
+			/*
+			 * in_port - in vswitch mode has
+			 * to move tx port from OVS excep.
+			 * away from VM tx port,
+			 * because of QoS is matched by port id!
+			 */
+			tx_q->port + 128,
+			header,
+			&tx_q->hwq.virt_queues_ctrl,
+			tx_q->hwq.pkt_buffers,
+			SPLIT_RING,
+			-1,
+			IN_ORDER);
+
+	tx_q->enabled = 1;
+
+	NT_LOG(DBG, NTNIC, "(%i) NTNIC TX OVS-SW queues successfully setup\n", internals->port);
+
+	if (internals->type == PORT_TYPE_PHYSICAL) {
+		struct adapter_info_s *p_adapter_info = &internals->p_drv->ntdrv.adapter_info;
+		NT_LOG(DBG, NTNIC, "Port %i is ready for data. Enable port\n",
+			internals->n_intf_no);
+		port_ops->set_adm_state(p_adapter_info, internals->n_intf_no, true);
+	}
+
+	return 0;
+}
+
 static int eth_rx_queue_start(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id)
 {
 	eth_dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
@@ -580,9 +901,11 @@ static const struct eth_dev_ops nthw_eth_dev_ops = {
 	.link_update = eth_link_update,
 	.dev_infos_get = eth_dev_infos_get,
 	.fw_version_get = eth_fw_version_get,
+	.rx_queue_setup = eth_rx_scg_queue_setup,
 	.rx_queue_start = eth_rx_queue_start,
 	.rx_queue_stop = eth_rx_queue_stop,
 	.rx_queue_release = eth_rx_queue_release,
+	.tx_queue_setup = eth_tx_scg_queue_setup,
 	.tx_queue_start = eth_tx_queue_start,
 	.tx_queue_stop = eth_tx_queue_stop,
 	.tx_queue_release = eth_tx_queue_release,
-- 
2.45.0


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

* [PATCH v1 05/14] net/ntnic: add packet handler for virtio queues
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (41 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 04/14] net/ntnic: add queue setup operations Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 06/14] net/ntnic: add init for virt queues in the DBS Serhii Iliushyk
                   ` (8 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

Added functionality to handles the copying of segmented queue data
into a rte_mbuf and vice versa.

Added functionality to manages packet transmission for a
specified TX and RX queues.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 drivers/net/ntnic/include/ntnic_virt_queue.h |  87 +++-
 drivers/net/ntnic/include/ntos_drv.h         |  14 +
 drivers/net/ntnic/ntnic_ethdev.c             | 441 +++++++++++++++++++
 3 files changed, 540 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ntnic/include/ntnic_virt_queue.h b/drivers/net/ntnic/include/ntnic_virt_queue.h
index 821b23af6c..f8842819e4 100644
--- a/drivers/net/ntnic/include/ntnic_virt_queue.h
+++ b/drivers/net/ntnic/include/ntnic_virt_queue.h
@@ -14,10 +14,93 @@
 struct nthw_virt_queue;
 
 #define SPLIT_RING        0
+#define PACKED_RING       1
 #define IN_ORDER          1
 
-struct nthw_cvirtq_desc;
+/*
+ * SPLIT : This marks a buffer as continuing via the next field.
+ * PACKED: This marks a buffer as continuing. (packed does not have a next field, so must be
+ * contiguous) In Used descriptors it must be ignored
+ */
+#define VIRTQ_DESC_F_NEXT 1
+
+/*
+ * Split Ring virtq Descriptor
+ */
+struct __rte_aligned(8) virtq_desc {
+	/* Address (guest-physical). */
+	uint64_t addr;
+	/* Length. */
+	uint32_t len;
+	/* The flags as indicated above. */
+	uint16_t flags;
+	/* Next field if flags & NEXT */
+	uint16_t next;
+};
+
+/* descr phys address must be 16 byte aligned */
+struct __rte_aligned(16) pvirtq_desc {
+	/* Buffer Address. */
+	uint64_t addr;
+	/* Buffer Length. */
+	uint32_t len;
+	/* Buffer ID. */
+	uint16_t id;
+	/* The flags depending on descriptor type. */
+	uint16_t flags;
+};
+
+/*
+ * Common virtq descr
+ */
+#define vq_set_next(vq, index, nxt) \
+do { \
+	struct nthw_cvirtq_desc *temp_vq = (vq); \
+	if (temp_vq->vq_type == SPLIT_RING) \
+		temp_vq->s[index].next = nxt; \
+} while (0)
+
+#define vq_add_flags(vq, index, flgs) \
+do { \
+	struct nthw_cvirtq_desc *temp_vq = (vq); \
+	uint16_t tmp_index = (index); \
+	typeof(flgs) tmp_flgs = (flgs); \
+	if (temp_vq->vq_type == SPLIT_RING) \
+		temp_vq->s[tmp_index].flags |= tmp_flgs; \
+	else if (temp_vq->vq_type == PACKED_RING) \
+		temp_vq->p[tmp_index].flags |= tmp_flgs; \
+} while (0)
+
+#define vq_set_flags(vq, index, flgs) \
+do { \
+	struct nthw_cvirtq_desc *temp_vq = (vq); \
+	uint32_t temp_flags = (flgs); \
+	uint32_t temp_index = (index); \
+	if ((temp_vq)->vq_type == SPLIT_RING) \
+		(temp_vq)->s[temp_index].flags = temp_flags; \
+	else if ((temp_vq)->vq_type == PACKED_RING) \
+		(temp_vq)->p[temp_index].flags = temp_flags; \
+} while (0)
+
+struct nthw_virtq_desc_buf {
+	/* Address (guest-physical). */
+	alignas(16) uint64_t addr;
+	/* Length. */
+	uint32_t len;
+};
+
+struct nthw_cvirtq_desc {
+	union {
+		struct nthw_virtq_desc_buf *b;  /* buffer part as is common */
+		struct virtq_desc     *s;  /* SPLIT */
+		struct pvirtq_desc    *p;  /* PACKED */
+	};
+	uint16_t vq_type;
+};
 
-struct nthw_received_packets;
+struct nthw_received_packets {
+	void *addr;
+	uint32_t len;
+};
 
 #endif /* __NTOSS_VIRT_QUEUE_H__ */
diff --git a/drivers/net/ntnic/include/ntos_drv.h b/drivers/net/ntnic/include/ntos_drv.h
index 933b012e07..d51d1e3677 100644
--- a/drivers/net/ntnic/include/ntos_drv.h
+++ b/drivers/net/ntnic/include/ntos_drv.h
@@ -27,6 +27,20 @@
 #define MAX_QUEUES       125
 
 /* Structs: */
+#define SG_HDR_SIZE    12
+
+struct _pkt_hdr_rx {
+	uint32_t cap_len:14;
+	uint32_t fid:10;
+	uint32_t ofs1:8;
+	uint32_t ip_prot:8;
+	uint32_t port:13;
+	uint32_t descr:8;
+	uint32_t descr_12b:1;
+	uint32_t color_type:2;
+	uint32_t color:32;
+};
+
 struct nthw_memory_descriptor {
 	void *phys_addr;
 	void *virt_addr;
diff --git a/drivers/net/ntnic/ntnic_ethdev.c b/drivers/net/ntnic/ntnic_ethdev.c
index 57827d73d5..b0ec41e2bb 100644
--- a/drivers/net/ntnic/ntnic_ethdev.c
+++ b/drivers/net/ntnic/ntnic_ethdev.c
@@ -39,9 +39,29 @@
 /* Max RSS queues */
 #define MAX_QUEUES 125
 
+#define NUM_VQ_SEGS(_data_size_)                                                                  \
+	({                                                                                        \
+		size_t _size = (_data_size_);                                                     \
+		size_t _segment_count = ((_size + SG_HDR_SIZE) > SG_HW_TX_PKT_BUFFER_SIZE)        \
+			? (((_size + SG_HDR_SIZE) + SG_HW_TX_PKT_BUFFER_SIZE - 1) /               \
+			   SG_HW_TX_PKT_BUFFER_SIZE)                                              \
+			: 1;                                                                      \
+		_segment_count;                                                                   \
+	})
+
+#define VIRTQ_DESCR_IDX(_tx_pkt_idx_)                                                             \
+	(((_tx_pkt_idx_) + first_vq_descr_idx) % SG_NB_HW_TX_DESCRIPTORS)
+
+#define VIRTQ_DESCR_IDX_NEXT(_vq_descr_idx_) (((_vq_descr_idx_) + 1) % SG_NB_HW_TX_DESCRIPTORS)
+
 #define ONE_G_SIZE  0x40000000
 #define ONE_G_MASK  (ONE_G_SIZE - 1)
 
+#define MAX_RX_PACKETS   128
+#define MAX_TX_PACKETS   128
+
+int kill_pmd;
+
 #define ETH_DEV_NTNIC_HELP_ARG "help"
 #define ETH_DEV_NTHW_RXQUEUES_ARG "rxqs"
 #define ETH_DEV_NTHW_TXQUEUES_ARG "txqs"
@@ -193,6 +213,423 @@ eth_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *dev_info
 	return 0;
 }
 
+static __rte_always_inline int copy_virtqueue_to_mbuf(struct rte_mbuf *mbuf,
+	struct rte_mempool *mb_pool,
+	struct nthw_received_packets *hw_recv,
+	int max_segs,
+	uint16_t data_len)
+{
+	int src_pkt = 0;
+	/*
+	 * 1. virtqueue packets may be segmented
+	 * 2. the mbuf size may be too small and may need to be segmented
+	 */
+	char *data = (char *)hw_recv->addr + SG_HDR_SIZE;
+	char *dst = (char *)mbuf->buf_addr + RTE_PKTMBUF_HEADROOM;
+
+	/* set packet length */
+	mbuf->pkt_len = data_len - SG_HDR_SIZE;
+
+	int remain = mbuf->pkt_len;
+	/* First cpy_size is without header */
+	int cpy_size = (data_len > SG_HW_RX_PKT_BUFFER_SIZE)
+		? SG_HW_RX_PKT_BUFFER_SIZE - SG_HDR_SIZE
+		: remain;
+
+	struct rte_mbuf *m = mbuf;	/* if mbuf segmentation is needed */
+
+	while (++src_pkt <= max_segs) {
+		/* keep track of space in dst */
+		int cpto_size = rte_pktmbuf_tailroom(m);
+
+		if (cpy_size > cpto_size) {
+			int new_cpy_size = cpto_size;
+
+			rte_memcpy((void *)dst, (void *)data, new_cpy_size);
+			m->data_len += new_cpy_size;
+			remain -= new_cpy_size;
+			cpy_size -= new_cpy_size;
+
+			data += new_cpy_size;
+
+			/*
+			 * loop if remaining data from this virtqueue seg
+			 * cannot fit in one extra mbuf
+			 */
+			do {
+				m->next = rte_pktmbuf_alloc(mb_pool);
+
+				if (unlikely(!m->next))
+					return -1;
+
+				m = m->next;
+
+				/* Headroom is not needed in chained mbufs */
+				rte_pktmbuf_prepend(m, rte_pktmbuf_headroom(m));
+				dst = (char *)m->buf_addr;
+				m->data_len = 0;
+				m->pkt_len = 0;
+
+				cpto_size = rte_pktmbuf_tailroom(m);
+
+				int actual_cpy_size =
+					(cpy_size > cpto_size) ? cpto_size : cpy_size;
+
+				rte_memcpy((void *)dst, (void *)data, actual_cpy_size);
+				m->pkt_len += actual_cpy_size;
+				m->data_len += actual_cpy_size;
+
+				remain -= actual_cpy_size;
+				cpy_size -= actual_cpy_size;
+
+				data += actual_cpy_size;
+
+				mbuf->nb_segs++;
+
+			} while (cpy_size && remain);
+
+		} else {
+			/* all data from this virtqueue segment can fit in current mbuf */
+			rte_memcpy((void *)dst, (void *)data, cpy_size);
+			m->data_len += cpy_size;
+
+			if (mbuf->nb_segs > 1)
+				m->pkt_len += cpy_size;
+
+			remain -= cpy_size;
+		}
+
+		/* packet complete - all data from current virtqueue packet has been copied */
+		if (remain == 0)
+			break;
+
+		/* increment dst to data end */
+		dst = rte_pktmbuf_mtod_offset(m, char *, m->data_len);
+		/* prepare for next virtqueue segment */
+		data = (char *)hw_recv[src_pkt].addr;	/* following packets are full data */
+
+		cpy_size = (remain > SG_HW_RX_PKT_BUFFER_SIZE) ? SG_HW_RX_PKT_BUFFER_SIZE : remain;
+	};
+
+	if (src_pkt > max_segs) {
+		NT_LOG(ERR, NTNIC,
+			"Did not receive correct number of segment for a whole packet");
+		return -1;
+	}
+
+	return src_pkt;
+}
+
+static uint16_t eth_dev_rx_scg(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	unsigned int i;
+	struct rte_mbuf *mbuf;
+	struct ntnic_rx_queue *rx_q = queue;
+	uint16_t num_rx = 0;
+
+	struct nthw_received_packets hw_recv[MAX_RX_PACKETS];
+
+	if (kill_pmd)
+		return 0;
+
+	if (unlikely(nb_pkts == 0))
+		return 0;
+
+	if (nb_pkts > MAX_RX_PACKETS)
+		nb_pkts = MAX_RX_PACKETS;
+
+	uint16_t whole_pkts = 0;
+	uint16_t hw_recv_pkt_segs = 0;
+
+	if (sg_ops != NULL) {
+		hw_recv_pkt_segs =
+			sg_ops->nthw_get_rx_packets(rx_q->vq, nb_pkts, hw_recv, &whole_pkts);
+
+		if (!hw_recv_pkt_segs)
+			return 0;
+	}
+
+	nb_pkts = whole_pkts;
+
+	int src_pkt = 0;/* from 0 to hw_recv_pkt_segs */
+
+	for (i = 0; i < nb_pkts; i++) {
+		bufs[i] = rte_pktmbuf_alloc(rx_q->mb_pool);
+
+		if (!bufs[i]) {
+			NT_LOG(ERR, NTNIC, "ERROR - no more buffers mbuf in mempool\n");
+			goto err_exit;
+		}
+
+		mbuf = bufs[i];
+
+		struct _pkt_hdr_rx *phdr = (struct _pkt_hdr_rx *)hw_recv[src_pkt].addr;
+
+		if (phdr->cap_len < SG_HDR_SIZE) {
+			NT_LOG(ERR, NTNIC,
+				"Pkt len of zero received. No header!! - dropping packets\n");
+			rte_pktmbuf_free(mbuf);
+			goto err_exit;
+		}
+
+		{
+			if (phdr->cap_len <= SG_HW_RX_PKT_BUFFER_SIZE &&
+				(phdr->cap_len - SG_HDR_SIZE) <= rte_pktmbuf_tailroom(mbuf)) {
+				mbuf->data_len = phdr->cap_len - SG_HDR_SIZE;
+				rte_memcpy(rte_pktmbuf_mtod(mbuf, char *),
+					(char *)hw_recv[src_pkt].addr + SG_HDR_SIZE,
+					mbuf->data_len);
+
+				mbuf->pkt_len = mbuf->data_len;
+				src_pkt++;
+
+			} else {
+				int cpy_segs = copy_virtqueue_to_mbuf(mbuf, rx_q->mb_pool,
+						&hw_recv[src_pkt],
+						hw_recv_pkt_segs - src_pkt,
+						phdr->cap_len);
+
+				if (cpy_segs < 0) {
+					/* Error */
+					rte_pktmbuf_free(mbuf);
+					goto err_exit;
+				}
+
+				src_pkt += cpy_segs;
+			}
+
+			num_rx++;
+
+			mbuf->ol_flags &= ~(RTE_MBUF_F_RX_FDIR_ID | RTE_MBUF_F_RX_FDIR);
+			mbuf->port = (uint16_t)-1;
+		}
+	}
+
+err_exit:
+
+	if (sg_ops != NULL)
+		sg_ops->nthw_release_rx_packets(rx_q->vq, hw_recv_pkt_segs);
+
+	return num_rx;
+}
+
+static int copy_mbuf_to_virtqueue(struct nthw_cvirtq_desc *cvq_desc,
+	uint16_t vq_descr_idx,
+	struct nthw_memory_descriptor *vq_bufs,
+	int max_segs,
+	struct rte_mbuf *mbuf)
+{
+	/*
+	 * 1. mbuf packet may be segmented
+	 * 2. the virtqueue buffer size may be too small and may need to be segmented
+	 */
+
+	char *data = rte_pktmbuf_mtod(mbuf, char *);
+	char *dst = (char *)vq_bufs[vq_descr_idx].virt_addr + SG_HDR_SIZE;
+
+	int remain = mbuf->pkt_len;
+	int cpy_size = mbuf->data_len;
+
+	struct rte_mbuf *m = mbuf;
+	int cpto_size = SG_HW_TX_PKT_BUFFER_SIZE - SG_HDR_SIZE;
+
+	cvq_desc->b[vq_descr_idx].len = SG_HDR_SIZE;
+
+	int cur_seg_num = 0;	/* start from 0 */
+
+	while (m) {
+		/* Can all data in current src segment be in current dest segment */
+		if (cpy_size > cpto_size) {
+			int new_cpy_size = cpto_size;
+
+			rte_memcpy((void *)dst, (void *)data, new_cpy_size);
+
+			cvq_desc->b[vq_descr_idx].len += new_cpy_size;
+
+			remain -= new_cpy_size;
+			cpy_size -= new_cpy_size;
+
+			data += new_cpy_size;
+
+			/*
+			 * Loop if remaining data from this virtqueue seg cannot fit in one extra
+			 * mbuf
+			 */
+			do {
+				vq_add_flags(cvq_desc, vq_descr_idx, VIRTQ_DESC_F_NEXT);
+
+				int next_vq_descr_idx = VIRTQ_DESCR_IDX_NEXT(vq_descr_idx);
+
+				vq_set_next(cvq_desc, vq_descr_idx, next_vq_descr_idx);
+
+				vq_descr_idx = next_vq_descr_idx;
+
+				vq_set_flags(cvq_desc, vq_descr_idx, 0);
+				vq_set_next(cvq_desc, vq_descr_idx, 0);
+
+				if (++cur_seg_num > max_segs)
+					break;
+
+				dst = (char *)vq_bufs[vq_descr_idx].virt_addr;
+				cpto_size = SG_HW_TX_PKT_BUFFER_SIZE;
+
+				int actual_cpy_size =
+					(cpy_size > cpto_size) ? cpto_size : cpy_size;
+				rte_memcpy((void *)dst, (void *)data, actual_cpy_size);
+
+				cvq_desc->b[vq_descr_idx].len = actual_cpy_size;
+
+				remain -= actual_cpy_size;
+				cpy_size -= actual_cpy_size;
+				cpto_size -= actual_cpy_size;
+
+				data += actual_cpy_size;
+
+			} while (cpy_size && remain);
+
+		} else {
+			/* All data from this segment can fit in current virtqueue buffer */
+			rte_memcpy((void *)dst, (void *)data, cpy_size);
+
+			cvq_desc->b[vq_descr_idx].len += cpy_size;
+
+			remain -= cpy_size;
+			cpto_size -= cpy_size;
+		}
+
+		/* Packet complete - all segments from current mbuf has been copied */
+		if (remain == 0)
+			break;
+
+		/* increment dst to data end */
+		dst = (char *)vq_bufs[vq_descr_idx].virt_addr + cvq_desc->b[vq_descr_idx].len;
+
+		m = m->next;
+
+		if (!m) {
+			NT_LOG(ERR, NTNIC, "ERROR: invalid packet size\n");
+			break;
+		}
+
+		/* Prepare for next mbuf segment */
+		data = rte_pktmbuf_mtod(m, char *);
+		cpy_size = m->data_len;
+	};
+
+	cur_seg_num++;
+
+	if (cur_seg_num > max_segs) {
+		NT_LOG(ERR, NTNIC,
+			"Did not receive correct number of segment for a whole packet");
+		return -1;
+	}
+
+	return cur_seg_num;
+}
+
+static uint16_t eth_dev_tx_scg(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	uint16_t pkt;
+	uint16_t first_vq_descr_idx = 0;
+
+	struct nthw_cvirtq_desc cvq_desc;
+
+	struct nthw_memory_descriptor *vq_bufs;
+
+	struct ntnic_tx_queue *tx_q = queue;
+
+	int nb_segs = 0, i;
+	int pkts_sent = 0;
+	uint16_t nb_segs_arr[MAX_TX_PACKETS];
+
+	if (kill_pmd)
+		return 0;
+
+	if (nb_pkts > MAX_TX_PACKETS)
+		nb_pkts = MAX_TX_PACKETS;
+
+	/*
+	 * count all segments needed to contain all packets in vq buffers
+	 */
+	for (i = 0; i < nb_pkts; i++) {
+		/* build the num segments array for segmentation control and release function */
+		int vq_segs = NUM_VQ_SEGS(bufs[i]->pkt_len);
+		nb_segs_arr[i] = vq_segs;
+		nb_segs += vq_segs;
+	}
+
+	if (!nb_segs)
+		goto exit_out;
+
+	if (sg_ops == NULL)
+		goto exit_out;
+
+	int got_nb_segs = sg_ops->nthw_get_tx_packets(tx_q->vq, nb_segs, &first_vq_descr_idx,
+			&cvq_desc /*&vq_descr,*/, &vq_bufs);
+
+	if (!got_nb_segs)
+		goto exit_out;
+
+	/*
+	 * we may get less vq buffers than we have asked for
+	 * calculate last whole packet that can fit into what
+	 * we have got
+	 */
+	while (got_nb_segs < nb_segs) {
+		if (!--nb_pkts)
+			goto exit_out;
+
+		nb_segs -= NUM_VQ_SEGS(bufs[nb_pkts]->pkt_len);
+
+		if (nb_segs <= 0)
+			goto exit_out;
+	}
+
+	/*
+	 * nb_pkts & nb_segs, got it all, ready to copy
+	 */
+	int seg_idx = 0;
+	int last_seg_idx = seg_idx;
+
+	for (pkt = 0; pkt < nb_pkts; ++pkt) {
+		uint16_t vq_descr_idx = VIRTQ_DESCR_IDX(seg_idx);
+
+		vq_set_flags(&cvq_desc, vq_descr_idx, 0);
+		vq_set_next(&cvq_desc, vq_descr_idx, 0);
+
+		if (bufs[pkt]->nb_segs == 1 && nb_segs_arr[pkt] == 1) {
+			rte_memcpy((void *)((char *)vq_bufs[vq_descr_idx].virt_addr + SG_HDR_SIZE),
+				rte_pktmbuf_mtod(bufs[pkt], void *), bufs[pkt]->pkt_len);
+
+			cvq_desc.b[vq_descr_idx].len = bufs[pkt]->pkt_len + SG_HDR_SIZE;
+
+			seg_idx++;
+
+		} else {
+			int cpy_segs = copy_mbuf_to_virtqueue(&cvq_desc, vq_descr_idx, vq_bufs,
+					nb_segs - last_seg_idx, bufs[pkt]);
+
+			if (cpy_segs < 0)
+				break;
+
+			seg_idx += cpy_segs;
+		}
+
+		last_seg_idx = seg_idx;
+		rte_pktmbuf_free(bufs[pkt]);
+		pkts_sent++;
+	}
+
+exit_out:
+
+	if (sg_ops != NULL) {
+		if (pkts_sent)
+			sg_ops->nthw_release_tx_packets(tx_q->vq, pkts_sent, nb_segs_arr);
+	}
+
+	return pkts_sent;
+}
+
 static int allocate_hw_virtio_queues(struct rte_eth_dev *eth_dev, int vf_num, struct hwq_s *hwq,
 	int num_descr, int buf_size)
 {
@@ -1252,6 +1689,10 @@ nthw_pci_dev_init(struct rte_pci_device *pci_dev)
 		rte_memcpy(&eth_dev->data->mac_addrs[0],
 					&internals->eth_addrs[0], RTE_ETHER_ADDR_LEN);
 
+		NT_LOG_DBGX(DBG, NTNIC, "Setting up RX functions for SCG\n");
+		eth_dev->rx_pkt_burst = eth_dev_rx_scg;
+		eth_dev->tx_pkt_burst = eth_dev_tx_scg;
+		eth_dev->tx_pkt_prepare = NULL;
 
 		struct rte_eth_link pmd_link;
 		pmd_link.link_speed = RTE_ETH_SPEED_NUM_NONE;
-- 
2.45.0


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

* [PATCH v1 06/14] net/ntnic: add init for virt queues in the DBS
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (42 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 05/14] net/ntnic: add packet handler for virtio queues Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 07/14] net/ntnic: add split-queue support Serhii Iliushyk
                   ` (7 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

DBS (DVIO Buffer System) module controls the scatter-gather buffer system
that let's the host CPU interact with packets.

Macros and Definitions: Defined constants for queue management and
polling speeds.

Data Structures: Added structures and arrays for RX and TX
queue management.

Procedures: Implemented initialization routines for setting up
queues and configuring Direct Buffer Storage (DBS) in FPGA.

Main Initialization: Allocates DBS modules, resets, and configures
RX and TX queues.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c | 154 ++++++++++++++++++
 drivers/net/ntnic/include/ntnic_dbs.h         |  71 +++++++-
 drivers/net/ntnic/meson.build                 |   2 +
 drivers/net/ntnic/nthw/dbs/nthw_dbs.c         | 135 +++++++++++++++
 .../ntnic/nthw/supported/nthw_fpga_mod_defs.h |   1 +
 drivers/net/ntnic/ntnic_mod_reg.c             |  11 +-
 drivers/net/ntnic/ntnic_mod_reg.h             |   2 +
 7 files changed, 374 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
 create mode 100644 drivers/net/ntnic/nthw/dbs/nthw_dbs.c

diff --git a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
new file mode 100644
index 0000000000..fc1dab6c5f
--- /dev/null
+++ b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
@@ -0,0 +1,154 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <unistd.h>
+
+#include "ntos_drv.h"
+#include "ntnic_virt_queue.h"
+#include "ntnic_mod_reg.h"
+#include "ntlog.h"
+
+#define MAX_VIRT_QUEUES 128
+
+#define LAST_QUEUE 127
+#define DISABLE 0
+#define ENABLE 1
+#define RX_AM_DISABLE DISABLE
+#define RX_AM_ENABLE ENABLE
+#define RX_UW_DISABLE DISABLE
+#define RX_UW_ENABLE ENABLE
+#define RX_Q_DISABLE DISABLE
+#define RX_Q_ENABLE ENABLE
+#define RX_AM_POLL_SPEED 5
+#define RX_UW_POLL_SPEED 9
+#define INIT_QUEUE 1
+
+#define TX_AM_DISABLE DISABLE
+#define TX_AM_ENABLE ENABLE
+#define TX_UW_DISABLE DISABLE
+#define TX_UW_ENABLE ENABLE
+#define TX_Q_DISABLE DISABLE
+#define TX_Q_ENABLE ENABLE
+#define TX_AM_POLL_SPEED 5
+#define TX_UW_POLL_SPEED 8
+
+enum nthw_virt_queue_usage {
+	NTHW_VIRTQ_UNUSED = 0
+};
+
+struct nthw_virt_queue {
+	enum nthw_virt_queue_usage usage;
+};
+
+static struct nthw_virt_queue rxvq[MAX_VIRT_QUEUES];
+static struct nthw_virt_queue txvq[MAX_VIRT_QUEUES];
+
+static void dbs_init_rx_queue(nthw_dbs_t *p_nthw_dbs, uint32_t queue, uint32_t start_idx,
+	uint32_t start_ptr)
+{
+	uint32_t busy;
+	uint32_t init;
+	uint32_t dummy;
+
+	do {
+		get_rx_init(p_nthw_dbs, &init, &dummy, &busy);
+	} while (busy != 0);
+
+	set_rx_init(p_nthw_dbs, start_idx, start_ptr, INIT_QUEUE, queue);
+
+	do {
+		get_rx_init(p_nthw_dbs, &init, &dummy, &busy);
+	} while (busy != 0);
+}
+
+static void dbs_init_tx_queue(nthw_dbs_t *p_nthw_dbs, uint32_t queue, uint32_t start_idx,
+	uint32_t start_ptr)
+{
+	uint32_t busy;
+	uint32_t init;
+	uint32_t dummy;
+
+	do {
+		get_tx_init(p_nthw_dbs, &init, &dummy, &busy);
+	} while (busy != 0);
+
+	set_tx_init(p_nthw_dbs, start_idx, start_ptr, INIT_QUEUE, queue);
+
+	do {
+		get_tx_init(p_nthw_dbs, &init, &dummy, &busy);
+	} while (busy != 0);
+}
+
+static int nthw_virt_queue_init(struct fpga_info_s *p_fpga_info)
+{
+	assert(p_fpga_info);
+
+	nthw_fpga_t *const p_fpga = p_fpga_info->mp_fpga;
+	nthw_dbs_t *p_nthw_dbs;
+	int res = 0;
+	uint32_t i;
+
+	p_fpga_info->mp_nthw_dbs = NULL;
+
+	p_nthw_dbs = nthw_dbs_new();
+
+	if (p_nthw_dbs == NULL)
+		return -1;
+
+	res = dbs_init(NULL, p_fpga, 0);/* Check that DBS exists in FPGA */
+
+	if (res) {
+		free(p_nthw_dbs);
+		return res;
+	}
+
+	res = dbs_init(p_nthw_dbs, p_fpga, 0);	/* Create DBS module */
+
+	if (res) {
+		free(p_nthw_dbs);
+		return res;
+	}
+
+	p_fpga_info->mp_nthw_dbs = p_nthw_dbs;
+
+	for (i = 0; i < MAX_VIRT_QUEUES; ++i) {
+		rxvq[i].usage = NTHW_VIRTQ_UNUSED;
+		txvq[i].usage = NTHW_VIRTQ_UNUSED;
+	}
+
+	dbs_reset(p_nthw_dbs);
+
+	for (i = 0; i < NT_DBS_RX_QUEUES_MAX; ++i)
+		dbs_init_rx_queue(p_nthw_dbs, i, 0, 0);
+
+	for (i = 0; i < NT_DBS_TX_QUEUES_MAX; ++i)
+		dbs_init_tx_queue(p_nthw_dbs, i, 0, 0);
+
+	set_rx_control(p_nthw_dbs, LAST_QUEUE, RX_AM_DISABLE, RX_AM_POLL_SPEED, RX_UW_DISABLE,
+		RX_UW_POLL_SPEED, RX_Q_DISABLE);
+	set_rx_control(p_nthw_dbs, LAST_QUEUE, RX_AM_ENABLE, RX_AM_POLL_SPEED, RX_UW_ENABLE,
+		RX_UW_POLL_SPEED, RX_Q_DISABLE);
+	set_rx_control(p_nthw_dbs, LAST_QUEUE, RX_AM_ENABLE, RX_AM_POLL_SPEED, RX_UW_ENABLE,
+		RX_UW_POLL_SPEED, RX_Q_ENABLE);
+
+	set_tx_control(p_nthw_dbs, LAST_QUEUE, TX_AM_DISABLE, TX_AM_POLL_SPEED, TX_UW_DISABLE,
+		TX_UW_POLL_SPEED, TX_Q_DISABLE);
+	set_tx_control(p_nthw_dbs, LAST_QUEUE, TX_AM_ENABLE, TX_AM_POLL_SPEED, TX_UW_ENABLE,
+		TX_UW_POLL_SPEED, TX_Q_DISABLE);
+	set_tx_control(p_nthw_dbs, LAST_QUEUE, TX_AM_ENABLE, TX_AM_POLL_SPEED, TX_UW_ENABLE,
+		TX_UW_POLL_SPEED, TX_Q_ENABLE);
+
+	return 0;
+}
+
+static struct sg_ops_s sg_ops = {
+	.nthw_virt_queue_init = nthw_virt_queue_init
+};
+
+void sg_init(void)
+{
+	NT_LOG(INF, NTNIC, "SG ops initialized\n");
+	register_sg_ops(&sg_ops);
+}
diff --git a/drivers/net/ntnic/include/ntnic_dbs.h b/drivers/net/ntnic/include/ntnic_dbs.h
index 551c6ade43..a64d2a0aeb 100644
--- a/drivers/net/ntnic/include/ntnic_dbs.h
+++ b/drivers/net/ntnic/include/ntnic_dbs.h
@@ -8,12 +8,81 @@
 
 #include "nthw_fpga_model.h"
 
+#define NT_DBS_RX_QUEUES_MAX (128)
+#define NT_DBS_TX_QUEUES_MAX (128)
+
 /*
  * Struct for implementation of memory bank shadows
  */
 
-struct nthw_dbs_s;
+struct nthw_dbs_s {
+	nthw_fpga_t *mp_fpga;
+	nthw_module_t *mp_mod_dbs;
+	int mn_instance;
+
+	int mn_param_dbs_present;
+
+	nthw_register_t *mp_reg_rx_control;
+	nthw_field_t *mp_fld_rx_control_last_queue;
+	nthw_field_t *mp_fld_rx_control_avail_monitor_enable;
+	nthw_field_t *mp_fld_rx_control_avail_monitor_scan_speed;
+	nthw_field_t *mp_fld_rx_control_used_write_enable;
+	nthw_field_t *mp_fld_rx_control_used_writer_update_speed;
+	nthw_field_t *mp_fld_rx_control_rx_queues_enable;
+
+	nthw_register_t *mp_reg_tx_control;
+	nthw_field_t *mp_fld_tx_control_last_queue;
+	nthw_field_t *mp_fld_tx_control_avail_monitor_enable;
+	nthw_field_t *mp_fld_tx_control_avail_monitor_scan_speed;
+	nthw_field_t *mp_fld_tx_control_used_write_enable;
+	nthw_field_t *mp_fld_tx_control_used_writer_update_speed;
+	nthw_field_t *mp_fld_tx_control_tx_queues_enable;
+
+	nthw_register_t *mp_reg_rx_init;
+	nthw_field_t *mp_fld_rx_init_init;
+	nthw_field_t *mp_fld_rx_init_queue;
+	nthw_field_t *mp_fld_rx_init_busy;
+
+	nthw_register_t *mp_reg_rx_init_val;
+	nthw_field_t *mp_fld_rx_init_val_idx;
+	nthw_field_t *mp_fld_rx_init_val_ptr;
+
+	nthw_register_t *mp_reg_tx_init;
+	nthw_field_t *mp_fld_tx_init_init;
+	nthw_field_t *mp_fld_tx_init_queue;
+	nthw_field_t *mp_fld_tx_init_busy;
+
+	nthw_register_t *mp_reg_tx_init_val;
+	nthw_field_t *mp_fld_tx_init_val_idx;
+	nthw_field_t *mp_fld_tx_init_val_ptr;
+
+};
 
 typedef struct nthw_dbs_s nthw_dbs_t;
 
+nthw_dbs_t *nthw_dbs_new(void);
+int dbs_init(nthw_dbs_t *p, nthw_fpga_t *p_fpga, int n_instance);
+void dbs_reset(nthw_dbs_t *p);
+
+int set_rx_control(nthw_dbs_t *p,
+	uint32_t last_queue,
+	uint32_t avail_monitor_enable,
+	uint32_t avail_monitor_speed,
+	uint32_t used_write_enable,
+	uint32_t used_write_speed,
+	uint32_t rx_queue_enable);
+int set_tx_control(nthw_dbs_t *p,
+	uint32_t last_queue,
+	uint32_t avail_monitor_enable,
+	uint32_t avail_monitor_speed,
+	uint32_t used_write_enable,
+	uint32_t used_write_speed,
+	uint32_t tx_queue_enable);
+int set_rx_init(nthw_dbs_t *p, uint32_t start_idx, uint32_t start_ptr, uint32_t init,
+	uint32_t queue);
+int get_rx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy);
+int set_tx_init(nthw_dbs_t *p, uint32_t start_idx, uint32_t start_ptr, uint32_t init,
+	uint32_t queue);
+int get_tx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy);
+
 #endif	/* _NTNIC_DBS_H_ */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 66d2770da7..3d9566a52e 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -24,9 +24,11 @@ includes = [
 # all sources
 sources = files(
         'adapter/nt4ga_adapter.c',
+        'dbsconfig/ntnic_dbsconfig.c',
         'link_mgmt/link_100g/nt4ga_link_100g.c',
         'link_mgmt/nt4ga_link.c',
         'nim/i2c_nim.c',
+        'nthw/dbs/nthw_dbs.c',
         'nthw/supported/nthw_fpga_9563_055_049_0000.c',
         'nthw/supported/nthw_fpga_instances.c',
         'nthw/supported/nthw_fpga_mod_str_map.c',
diff --git a/drivers/net/ntnic/nthw/dbs/nthw_dbs.c b/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
new file mode 100644
index 0000000000..853d7bc1ec
--- /dev/null
+++ b/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
@@ -0,0 +1,135 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <errno.h>
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+nthw_dbs_t *nthw_dbs_new(void)
+{
+	nthw_dbs_t *p = malloc(sizeof(nthw_dbs_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_dbs_t));
+
+	return p;
+}
+
+int dbs_init(nthw_dbs_t *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	nthw_module_t *mod = nthw_fpga_query_module(p_fpga, MOD_DBS, n_instance);
+
+	if (p == NULL)
+		return mod == NULL ? -1 : 0;
+
+	if (mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: DBS %d: no such instance\n",
+			p_fpga->p_fpga_info->mp_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_instance = n_instance;
+	p->mp_mod_dbs = mod;
+
+	p->mn_param_dbs_present = nthw_fpga_get_product_param(p_fpga, NT_DBS_PRESENT, 0);
+
+	if (p->mn_param_dbs_present == 0) {
+		NT_LOG(WRN, NTHW,
+			"%s: DBS %d: logical error: module found but not flagged at present\n",
+			p->mp_fpga->p_fpga_info->mp_adapter_id_str, p->mn_instance);
+	}
+
+	return 0;
+}
+
+void dbs_reset(nthw_dbs_t *p)
+{
+	(void)p;
+}
+
+int set_rx_control(nthw_dbs_t *p,
+	uint32_t last_queue,
+	uint32_t avail_monitor_enable,
+	uint32_t avail_monitor_speed,
+	uint32_t used_write_enable,
+	uint32_t used_write_speed,
+	uint32_t rx_queue_enable)
+{
+	nthw_field_set_val32(p->mp_fld_rx_control_last_queue, last_queue);
+	nthw_field_set_val32(p->mp_fld_rx_control_avail_monitor_enable, avail_monitor_enable);
+	nthw_field_set_val32(p->mp_fld_rx_control_avail_monitor_scan_speed, avail_monitor_speed);
+	nthw_field_set_val32(p->mp_fld_rx_control_used_write_enable, used_write_enable);
+	nthw_field_set_val32(p->mp_fld_rx_control_used_writer_update_speed, used_write_speed);
+	nthw_field_set_val32(p->mp_fld_rx_control_rx_queues_enable, rx_queue_enable);
+	nthw_register_flush(p->mp_reg_rx_control, 1);
+	return 0;
+}
+
+int set_tx_control(nthw_dbs_t *p,
+	uint32_t last_queue,
+	uint32_t avail_monitor_enable,
+	uint32_t avail_monitor_speed,
+	uint32_t used_write_enable,
+	uint32_t used_write_speed,
+	uint32_t tx_queue_enable)
+{
+	nthw_field_set_val32(p->mp_fld_tx_control_last_queue, last_queue);
+	nthw_field_set_val32(p->mp_fld_tx_control_avail_monitor_enable, avail_monitor_enable);
+	nthw_field_set_val32(p->mp_fld_tx_control_avail_monitor_scan_speed, avail_monitor_speed);
+	nthw_field_set_val32(p->mp_fld_tx_control_used_write_enable, used_write_enable);
+	nthw_field_set_val32(p->mp_fld_tx_control_used_writer_update_speed, used_write_speed);
+	nthw_field_set_val32(p->mp_fld_tx_control_tx_queues_enable, tx_queue_enable);
+	nthw_register_flush(p->mp_reg_tx_control, 1);
+	return 0;
+}
+
+int set_rx_init(nthw_dbs_t *p, uint32_t start_idx, uint32_t start_ptr, uint32_t init,
+	uint32_t queue)
+{
+	if (p->mp_reg_rx_init_val) {
+		nthw_field_set_val32(p->mp_fld_rx_init_val_idx, start_idx);
+		nthw_field_set_val32(p->mp_fld_rx_init_val_ptr, start_ptr);
+		nthw_register_flush(p->mp_reg_rx_init_val, 1);
+	}
+
+	nthw_field_set_val32(p->mp_fld_rx_init_init, init);
+	nthw_field_set_val32(p->mp_fld_rx_init_queue, queue);
+	nthw_register_flush(p->mp_reg_rx_init, 1);
+	return 0;
+}
+
+int get_rx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy)
+{
+	*init = nthw_field_get_val32(p->mp_fld_rx_init_init);
+	*queue = nthw_field_get_val32(p->mp_fld_rx_init_queue);
+	*busy = nthw_field_get_val32(p->mp_fld_rx_init_busy);
+	return 0;
+}
+
+int set_tx_init(nthw_dbs_t *p, uint32_t start_idx, uint32_t start_ptr, uint32_t init,
+	uint32_t queue)
+{
+	if (p->mp_reg_tx_init_val) {
+		nthw_field_set_val32(p->mp_fld_tx_init_val_idx, start_idx);
+		nthw_field_set_val32(p->mp_fld_tx_init_val_ptr, start_ptr);
+		nthw_register_flush(p->mp_reg_tx_init_val, 1);
+	}
+
+	nthw_field_set_val32(p->mp_fld_tx_init_init, init);
+	nthw_field_set_val32(p->mp_fld_tx_init_queue, queue);
+	nthw_register_flush(p->mp_reg_tx_init, 1);
+	return 0;
+}
+
+int get_tx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy)
+{
+	*init = nthw_field_get_val32(p->mp_fld_tx_init_init);
+	*queue = nthw_field_get_val32(p->mp_fld_tx_init_queue);
+	*busy = nthw_field_get_val32(p->mp_fld_tx_init_busy);
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
index 5d6aac122c..b6be02f45e 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_mod_defs.h
@@ -16,6 +16,7 @@
 #define MOD_UNKNOWN (0L)/* Unknown/uninitialized - keep this as the first element */
 #define MOD_CAT (0x30b447c2UL)
 #define MOD_CSU (0x3f470787UL)
+#define MOD_DBS (0x80b29727UL)
 #define MOD_FLM (0xe7ba53a4UL)
 #define MOD_GFG (0xfc423807UL)
 #define MOD_GMF (0x68b1d15aUL)
diff --git a/drivers/net/ntnic/ntnic_mod_reg.c b/drivers/net/ntnic/ntnic_mod_reg.c
index 8fe5193027..a03c97801b 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.c
+++ b/drivers/net/ntnic/ntnic_mod_reg.c
@@ -5,9 +5,18 @@
 
 #include "ntnic_mod_reg.h"
 
+static struct sg_ops_s *sg_ops;
+
+void register_sg_ops(struct sg_ops_s *ops)
+{
+	sg_ops = ops;
+}
+
 const struct sg_ops_s *get_sg_ops(void)
 {
-	return NULL;
+	if (sg_ops == NULL)
+		sg_init();
+	return sg_ops;
 }
 
 static struct link_ops_s *link_100g_ops;
diff --git a/drivers/net/ntnic/ntnic_mod_reg.h b/drivers/net/ntnic/ntnic_mod_reg.h
index e9dff51935..5b97b3d8ac 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.h
+++ b/drivers/net/ntnic/ntnic_mod_reg.h
@@ -105,7 +105,9 @@ struct sg_ops_s {
 	int (*nthw_virt_queue_init)(struct fpga_info_s *p_fpga_info);
 };
 
+void register_sg_ops(struct sg_ops_s *ops);
 const struct sg_ops_s *get_sg_ops(void);
+void sg_init(void);
 
 struct link_ops_s {
 	int (*link_init)(struct adapter_info_s *p_adapter_info, nthw_fpga_t *p_fpga);
-- 
2.45.0


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

* [PATCH v1 07/14] net/ntnic: add split-queue support
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (43 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 06/14] net/ntnic: add init for virt queues in the DBS Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 08/14] net/ntnic: add functions for availability monitor management Serhii Iliushyk
                   ` (6 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

Split-queue support was added.

Internal structures were enhanced with additional managmnet fields.

Implement a managed virtual queue function based on the queue type
and configuration parameters.

DBS control registers were added.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c | 411 +++++++++++++++++-
 drivers/net/ntnic/include/ntnic_dbs.h         |  19 +
 drivers/net/ntnic/include/ntnic_virt_queue.h  |   7 +
 drivers/net/ntnic/nthw/dbs/nthw_dbs.c         | 125 +++++-
 .../ntnic/nthw/supported/nthw_fpga_reg_defs.h |   1 +
 .../nthw/supported/nthw_fpga_reg_defs_dbs.h   |  79 ++++
 6 files changed, 640 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h

diff --git a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
index fc1dab6c5f..e69cf7ad21 100644
--- a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
+++ b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
@@ -10,6 +10,7 @@
 #include "ntnic_mod_reg.h"
 #include "ntlog.h"
 
+#define STRUCT_ALIGNMENT (4 * 1024LU)
 #define MAX_VIRT_QUEUES 128
 
 #define LAST_QUEUE 127
@@ -34,12 +35,79 @@
 #define TX_AM_POLL_SPEED 5
 #define TX_UW_POLL_SPEED 8
 
+#define VIRTQ_AVAIL_F_NO_INTERRUPT 1
+
+struct __rte_aligned(8) virtq_avail {
+	uint16_t flags;
+	uint16_t idx;
+	uint16_t ring[];	/* Queue Size */
+};
+
+struct __rte_aligned(8) virtq_used_elem {
+	/* Index of start of used descriptor chain. */
+	uint32_t id;
+	/* Total length of the descriptor chain which was used (written to) */
+	uint32_t len;
+};
+
+struct __rte_aligned(8) virtq_used {
+	uint16_t flags;
+	uint16_t idx;
+	struct virtq_used_elem ring[];	/* Queue Size */
+};
+
+struct virtq_struct_layout_s {
+	size_t used_offset;
+	size_t desc_offset;
+};
+
 enum nthw_virt_queue_usage {
-	NTHW_VIRTQ_UNUSED = 0
+	NTHW_VIRTQ_UNUSED = 0,
+	NTHW_VIRTQ_UNMANAGED,
+	NTHW_VIRTQ_MANAGED
 };
 
 struct nthw_virt_queue {
+	/* Pointers to virt-queue structs */
+	struct {
+		/* SPLIT virtqueue */
+		struct virtq_avail *p_avail;
+		struct virtq_used *p_used;
+		struct virtq_desc *p_desc;
+		/* Control variables for virt-queue structs */
+		uint16_t am_idx;
+		uint16_t used_idx;
+		uint16_t cached_idx;
+		uint16_t tx_descr_avail_idx;
+	};
+
+	/* Array with packet buffers */
+	struct nthw_memory_descriptor *p_virtual_addr;
+
+	/* Queue configuration info */
+	nthw_dbs_t *mp_nthw_dbs;
+
 	enum nthw_virt_queue_usage usage;
+	uint16_t irq_vector;
+	uint16_t vq_type;
+	uint16_t in_order;
+
+	uint16_t queue_size;
+	uint32_t index;
+	uint32_t am_enable;
+	uint32_t host_id;
+	uint32_t port;	/* Only used by TX queues */
+	uint32_t virtual_port;	/* Only used by TX queues */
+	/*
+	 * Only used by TX queues:
+	 *   0: VirtIO-Net header (12 bytes).
+	 *   1: Napatech DVIO0 descriptor (12 bytes).
+	 */
+};
+
+struct pvirtq_struct_layout_s {
+	size_t driver_event_offset;
+	size_t device_event_offset;
 };
 
 static struct nthw_virt_queue rxvq[MAX_VIRT_QUEUES];
@@ -143,7 +211,348 @@ static int nthw_virt_queue_init(struct fpga_info_s *p_fpga_info)
 	return 0;
 }
 
+static struct virtq_struct_layout_s dbs_calc_struct_layout(uint32_t queue_size)
+{
+	/* + sizeof(uint16_t); ("avail->used_event" is not used) */
+	size_t avail_mem = sizeof(struct virtq_avail) + queue_size * sizeof(uint16_t);
+	size_t avail_mem_aligned = ((avail_mem % STRUCT_ALIGNMENT) == 0)
+		? avail_mem
+		: STRUCT_ALIGNMENT * (avail_mem / STRUCT_ALIGNMENT + 1);
+
+	/* + sizeof(uint16_t); ("used->avail_event" is not used) */
+	size_t used_mem = sizeof(struct virtq_used) + queue_size * sizeof(struct virtq_used_elem);
+	size_t used_mem_aligned = ((used_mem % STRUCT_ALIGNMENT) == 0)
+		? used_mem
+		: STRUCT_ALIGNMENT * (used_mem / STRUCT_ALIGNMENT + 1);
+
+	struct virtq_struct_layout_s virtq_layout;
+	virtq_layout.used_offset = avail_mem_aligned;
+	virtq_layout.desc_offset = avail_mem_aligned + used_mem_aligned;
+
+	return virtq_layout;
+}
+
+static void dbs_initialize_avail_struct(void *addr, uint16_t queue_size,
+	uint16_t initial_avail_idx)
+{
+	uint16_t i;
+	struct virtq_avail *p_avail = (struct virtq_avail *)addr;
+
+	p_avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
+	p_avail->idx = initial_avail_idx;
+
+	for (i = 0; i < queue_size; ++i)
+		p_avail->ring[i] = i;
+}
+
+static void dbs_initialize_used_struct(void *addr, uint16_t queue_size)
+{
+	int i;
+	struct virtq_used *p_used = (struct virtq_used *)addr;
+
+	p_used->flags = 1;
+	p_used->idx = 0;
+
+	for (i = 0; i < queue_size; ++i) {
+		p_used->ring[i].id = 0;
+		p_used->ring[i].len = 0;
+	}
+}
+
+static void
+dbs_initialize_descriptor_struct(void *addr,
+	struct nthw_memory_descriptor *packet_buffer_descriptors,
+	uint16_t queue_size, uint16_t flgs)
+{
+	if (packet_buffer_descriptors) {
+		int i;
+		struct virtq_desc *p_desc = (struct virtq_desc *)addr;
+
+		for (i = 0; i < queue_size; ++i) {
+			p_desc[i].addr = (uint64_t)packet_buffer_descriptors[i].phys_addr;
+			p_desc[i].len = packet_buffer_descriptors[i].len;
+			p_desc[i].flags = flgs;
+			p_desc[i].next = 0;
+		}
+	}
+}
+
+static void
+dbs_initialize_virt_queue_structs(void *avail_struct_addr, void *used_struct_addr,
+	void *desc_struct_addr,
+	struct nthw_memory_descriptor *packet_buffer_descriptors,
+	uint16_t queue_size, uint16_t initial_avail_idx, uint16_t flgs)
+{
+	dbs_initialize_avail_struct(avail_struct_addr, queue_size, initial_avail_idx);
+	dbs_initialize_used_struct(used_struct_addr, queue_size);
+	dbs_initialize_descriptor_struct(desc_struct_addr, packet_buffer_descriptors, queue_size,
+		flgs);
+}
+
+static struct nthw_virt_queue *nthw_setup_rx_virt_queue(nthw_dbs_t *p_nthw_dbs,
+	uint32_t index,
+	uint16_t start_idx,
+	uint16_t start_ptr,
+	void *avail_struct_phys_addr,
+	void *used_struct_phys_addr,
+	void *desc_struct_phys_addr,
+	uint16_t queue_size,
+	uint32_t host_id,
+	uint32_t header,
+	uint32_t vq_type,
+	int irq_vector)
+{
+	(void)header;
+	(void)desc_struct_phys_addr;
+	(void)avail_struct_phys_addr;
+	(void)used_struct_phys_addr;
+
+
+	/*
+	 * 5. Initialize all RX queues (all DBS_RX_QUEUES of them) using the
+	 *   DBS.RX_INIT register.
+	 */
+	dbs_init_rx_queue(p_nthw_dbs, index, start_idx, start_ptr);
+
+	/* Save queue state */
+	rxvq[index].usage = NTHW_VIRTQ_UNMANAGED;
+	rxvq[index].mp_nthw_dbs = p_nthw_dbs;
+	rxvq[index].index = index;
+	rxvq[index].queue_size = queue_size;
+	rxvq[index].am_enable = (irq_vector < 0) ? RX_AM_ENABLE : RX_AM_DISABLE;
+	rxvq[index].host_id = host_id;
+	rxvq[index].vq_type = vq_type;
+	rxvq[index].in_order = 0;	/* not used */
+	rxvq[index].irq_vector = irq_vector;
+
+	/* Return queue handle */
+	return &rxvq[index];
+}
+
+static struct nthw_virt_queue *nthw_setup_tx_virt_queue(nthw_dbs_t *p_nthw_dbs,
+	uint32_t index,
+	uint16_t start_idx,
+	uint16_t start_ptr,
+	void *avail_struct_phys_addr,
+	void *used_struct_phys_addr,
+	void *desc_struct_phys_addr,
+	uint16_t queue_size,
+	uint32_t host_id,
+	uint32_t port,
+	uint32_t virtual_port,
+	uint32_t header,
+	uint32_t vq_type,
+	int irq_vector,
+	uint32_t in_order)
+{
+	(void)header;
+	(void)desc_struct_phys_addr;
+	(void)avail_struct_phys_addr;
+	(void)used_struct_phys_addr;
+
+	/*
+	 * 5. Initialize all TX queues (all DBS_TX_QUEUES of them) using the
+	 *    DBS.TX_INIT register.
+	 */
+	dbs_init_tx_queue(p_nthw_dbs, index, start_idx, start_ptr);
+
+	/* Save queue state */
+	txvq[index].usage = NTHW_VIRTQ_UNMANAGED;
+	txvq[index].mp_nthw_dbs = p_nthw_dbs;
+	txvq[index].index = index;
+	txvq[index].queue_size = queue_size;
+	txvq[index].am_enable = (irq_vector < 0) ? TX_AM_ENABLE : TX_AM_DISABLE;
+	txvq[index].host_id = host_id;
+	txvq[index].port = port;
+	txvq[index].virtual_port = virtual_port;
+	txvq[index].vq_type = vq_type;
+	txvq[index].in_order = in_order;
+	txvq[index].irq_vector = irq_vector;
+
+	/* Return queue handle */
+	return &txvq[index];
+}
+
+static struct nthw_virt_queue *
+nthw_setup_mngd_rx_virt_queue_split(nthw_dbs_t *p_nthw_dbs,
+	uint32_t index,
+	uint32_t queue_size,
+	uint32_t host_id,
+	uint32_t header,
+	struct nthw_memory_descriptor *p_virt_struct_area,
+	struct nthw_memory_descriptor *p_packet_buffers,
+	int irq_vector)
+{
+	struct virtq_struct_layout_s virtq_struct_layout = dbs_calc_struct_layout(queue_size);
+
+	dbs_initialize_virt_queue_structs(p_virt_struct_area->virt_addr,
+		(char *)p_virt_struct_area->virt_addr +
+		virtq_struct_layout.used_offset,
+		(char *)p_virt_struct_area->virt_addr +
+		virtq_struct_layout.desc_offset,
+		p_packet_buffers,
+		(uint16_t)queue_size,
+		p_packet_buffers ? (uint16_t)queue_size : 0,
+		VIRTQ_DESC_F_WRITE /* Rx */);
+
+	rxvq[index].p_avail = p_virt_struct_area->virt_addr;
+	rxvq[index].p_used =
+		(void *)((char *)p_virt_struct_area->virt_addr + virtq_struct_layout.used_offset);
+	rxvq[index].p_desc =
+		(void *)((char *)p_virt_struct_area->virt_addr + virtq_struct_layout.desc_offset);
+
+	rxvq[index].am_idx = p_packet_buffers ? (uint16_t)queue_size : 0;
+	rxvq[index].used_idx = 0;
+	rxvq[index].cached_idx = 0;
+	rxvq[index].p_virtual_addr = NULL;
+
+	if (p_packet_buffers) {
+		rxvq[index].p_virtual_addr = malloc(queue_size * sizeof(*p_packet_buffers));
+		memcpy(rxvq[index].p_virtual_addr, p_packet_buffers,
+			queue_size * sizeof(*p_packet_buffers));
+	}
+
+	nthw_setup_rx_virt_queue(p_nthw_dbs, index, 0, 0, (void *)p_virt_struct_area->phys_addr,
+		(char *)p_virt_struct_area->phys_addr +
+		virtq_struct_layout.used_offset,
+		(char *)p_virt_struct_area->phys_addr +
+		virtq_struct_layout.desc_offset,
+		(uint16_t)queue_size, host_id, header, SPLIT_RING, irq_vector);
+
+	rxvq[index].usage = NTHW_VIRTQ_MANAGED;
+
+	return &rxvq[index];
+}
+
+static struct nthw_virt_queue *
+nthw_setup_mngd_tx_virt_queue_split(nthw_dbs_t *p_nthw_dbs,
+	uint32_t index,
+	uint32_t queue_size,
+	uint32_t host_id,
+	uint32_t port,
+	uint32_t virtual_port,
+	uint32_t header,
+	int irq_vector,
+	uint32_t in_order,
+	struct nthw_memory_descriptor *p_virt_struct_area,
+	struct nthw_memory_descriptor *p_packet_buffers)
+{
+	struct virtq_struct_layout_s virtq_struct_layout = dbs_calc_struct_layout(queue_size);
+
+	dbs_initialize_virt_queue_structs(p_virt_struct_area->virt_addr,
+		(char *)p_virt_struct_area->virt_addr +
+		virtq_struct_layout.used_offset,
+		(char *)p_virt_struct_area->virt_addr +
+		virtq_struct_layout.desc_offset,
+		p_packet_buffers,
+		(uint16_t)queue_size,
+		0,
+		0 /* Tx */);
+
+	txvq[index].p_avail = p_virt_struct_area->virt_addr;
+	txvq[index].p_used =
+		(void *)((char *)p_virt_struct_area->virt_addr + virtq_struct_layout.used_offset);
+	txvq[index].p_desc =
+		(void *)((char *)p_virt_struct_area->virt_addr + virtq_struct_layout.desc_offset);
+	txvq[index].queue_size = (uint16_t)queue_size;
+	txvq[index].am_idx = 0;
+	txvq[index].used_idx = 0;
+	txvq[index].cached_idx = 0;
+	txvq[index].p_virtual_addr = NULL;
+
+	txvq[index].tx_descr_avail_idx = 0;
+
+	if (p_packet_buffers) {
+		txvq[index].p_virtual_addr = malloc(queue_size * sizeof(*p_packet_buffers));
+		memcpy(txvq[index].p_virtual_addr, p_packet_buffers,
+			queue_size * sizeof(*p_packet_buffers));
+	}
+
+	nthw_setup_tx_virt_queue(p_nthw_dbs, index, 0, 0, (void *)p_virt_struct_area->phys_addr,
+		(char *)p_virt_struct_area->phys_addr +
+		virtq_struct_layout.used_offset,
+		(char *)p_virt_struct_area->phys_addr +
+		virtq_struct_layout.desc_offset,
+		(uint16_t)queue_size, host_id, port, virtual_port, header,
+		SPLIT_RING, irq_vector, in_order);
+
+	txvq[index].usage = NTHW_VIRTQ_MANAGED;
+
+	return &txvq[index];
+}
+
+/*
+ * Create a Managed Rx Virt Queue
+ *
+ * Notice: The queue will be created with interrupts disabled.
+ *   If interrupts are required, make sure to call nthw_enable_rx_virt_queue()
+ *   afterwards.
+ */
+static struct nthw_virt_queue *
+nthw_setup_mngd_rx_virt_queue(nthw_dbs_t *p_nthw_dbs,
+	uint32_t index,
+	uint32_t queue_size,
+	uint32_t host_id,
+	uint32_t header,
+	struct nthw_memory_descriptor *p_virt_struct_area,
+	struct nthw_memory_descriptor *p_packet_buffers,
+	uint32_t vq_type,
+	int irq_vector)
+{
+	switch (vq_type) {
+	case SPLIT_RING:
+		return nthw_setup_mngd_rx_virt_queue_split(p_nthw_dbs, index, queue_size,
+				host_id, header, p_virt_struct_area,
+				p_packet_buffers, irq_vector);
+
+	default:
+		break;
+	}
+
+	return NULL;
+}
+
+/*
+ * Create a Managed Tx Virt Queue
+ *
+ * Notice: The queue will be created with interrupts disabled.
+ *   If interrupts are required, make sure to call nthw_enable_tx_virt_queue()
+ *   afterwards.
+ */
+static struct nthw_virt_queue *
+nthw_setup_mngd_tx_virt_queue(nthw_dbs_t *p_nthw_dbs,
+	uint32_t index,
+	uint32_t queue_size,
+	uint32_t host_id,
+	uint32_t port,
+	uint32_t virtual_port,
+	uint32_t header,
+	struct nthw_memory_descriptor *p_virt_struct_area,
+	struct nthw_memory_descriptor *p_packet_buffers,
+	uint32_t vq_type,
+	int irq_vector,
+	uint32_t in_order)
+{
+	switch (vq_type) {
+	case SPLIT_RING:
+		return nthw_setup_mngd_tx_virt_queue_split(p_nthw_dbs, index, queue_size,
+				host_id, port, virtual_port, header,
+				irq_vector, in_order,
+				p_virt_struct_area,
+				p_packet_buffers);
+
+	default:
+		break;
+	}
+
+	return NULL;
+}
+
 static struct sg_ops_s sg_ops = {
+	.nthw_setup_rx_virt_queue = nthw_setup_rx_virt_queue,
+	.nthw_setup_tx_virt_queue = nthw_setup_tx_virt_queue,
+	.nthw_setup_mngd_rx_virt_queue = nthw_setup_mngd_rx_virt_queue,
+	.nthw_setup_mngd_tx_virt_queue = nthw_setup_mngd_tx_virt_queue,
 	.nthw_virt_queue_init = nthw_virt_queue_init
 };
 
diff --git a/drivers/net/ntnic/include/ntnic_dbs.h b/drivers/net/ntnic/include/ntnic_dbs.h
index a64d2a0aeb..4e6236e8b4 100644
--- a/drivers/net/ntnic/include/ntnic_dbs.h
+++ b/drivers/net/ntnic/include/ntnic_dbs.h
@@ -47,6 +47,11 @@ struct nthw_dbs_s {
 	nthw_field_t *mp_fld_rx_init_val_idx;
 	nthw_field_t *mp_fld_rx_init_val_ptr;
 
+	nthw_register_t *mp_reg_rx_ptr;
+	nthw_field_t *mp_fld_rx_ptr_ptr;
+	nthw_field_t *mp_fld_rx_ptr_queue;
+	nthw_field_t *mp_fld_rx_ptr_valid;
+
 	nthw_register_t *mp_reg_tx_init;
 	nthw_field_t *mp_fld_tx_init_init;
 	nthw_field_t *mp_fld_tx_init_queue;
@@ -56,6 +61,20 @@ struct nthw_dbs_s {
 	nthw_field_t *mp_fld_tx_init_val_idx;
 	nthw_field_t *mp_fld_tx_init_val_ptr;
 
+	nthw_register_t *mp_reg_tx_ptr;
+	nthw_field_t *mp_fld_tx_ptr_ptr;
+	nthw_field_t *mp_fld_tx_ptr_queue;
+	nthw_field_t *mp_fld_tx_ptr_valid;
+
+	nthw_register_t *mp_reg_rx_idle;
+	nthw_field_t *mp_fld_rx_idle_idle;
+	nthw_field_t *mp_fld_rx_idle_queue;
+	nthw_field_t *mp_fld_rx_idle_busy;
+
+	nthw_register_t *mp_reg_tx_idle;
+	nthw_field_t *mp_fld_tx_idle_idle;
+	nthw_field_t *mp_fld_tx_idle_queue;
+	nthw_field_t *mp_fld_tx_idle_busy;
 };
 
 typedef struct nthw_dbs_s nthw_dbs_t;
diff --git a/drivers/net/ntnic/include/ntnic_virt_queue.h b/drivers/net/ntnic/include/ntnic_virt_queue.h
index f8842819e4..97cb474dc8 100644
--- a/drivers/net/ntnic/include/ntnic_virt_queue.h
+++ b/drivers/net/ntnic/include/ntnic_virt_queue.h
@@ -23,6 +23,13 @@ struct nthw_virt_queue;
  * contiguous) In Used descriptors it must be ignored
  */
 #define VIRTQ_DESC_F_NEXT 1
+/*
+ * SPLIT : This marks a buffer as device write-only (otherwise device read-only).
+ * PACKED: This marks a descriptor as device write-only (otherwise device read-only).
+ * PACKED: In a used descriptor, this bit is used to specify whether any data has been written by
+ * the device into any parts of the buffer.
+ */
+#define VIRTQ_DESC_F_WRITE 2
 
 /*
  * Split Ring virtq Descriptor
diff --git a/drivers/net/ntnic/nthw/dbs/nthw_dbs.c b/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
index 853d7bc1ec..cd1123b6f3 100644
--- a/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
+++ b/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
@@ -44,12 +44,135 @@ int dbs_init(nthw_dbs_t *p, nthw_fpga_t *p_fpga, int n_instance)
 			p->mp_fpga->p_fpga_info->mp_adapter_id_str, p->mn_instance);
 	}
 
+	p->mp_reg_rx_control = nthw_module_get_register(p->mp_mod_dbs, DBS_RX_CONTROL);
+	p->mp_fld_rx_control_last_queue =
+		nthw_register_get_field(p->mp_reg_rx_control, DBS_RX_CONTROL_LQ);
+	p->mp_fld_rx_control_avail_monitor_enable =
+		nthw_register_get_field(p->mp_reg_rx_control, DBS_RX_CONTROL_AME);
+	p->mp_fld_rx_control_avail_monitor_scan_speed =
+		nthw_register_get_field(p->mp_reg_rx_control, DBS_RX_CONTROL_AMS);
+	p->mp_fld_rx_control_used_write_enable =
+		nthw_register_get_field(p->mp_reg_rx_control, DBS_RX_CONTROL_UWE);
+	p->mp_fld_rx_control_used_writer_update_speed =
+		nthw_register_get_field(p->mp_reg_rx_control, DBS_RX_CONTROL_UWS);
+	p->mp_fld_rx_control_rx_queues_enable =
+		nthw_register_get_field(p->mp_reg_rx_control, DBS_RX_CONTROL_QE);
+
+	p->mp_reg_tx_control = nthw_module_get_register(p->mp_mod_dbs, DBS_TX_CONTROL);
+	p->mp_fld_tx_control_last_queue =
+		nthw_register_get_field(p->mp_reg_tx_control, DBS_TX_CONTROL_LQ);
+	p->mp_fld_tx_control_avail_monitor_enable =
+		nthw_register_get_field(p->mp_reg_tx_control, DBS_TX_CONTROL_AME);
+	p->mp_fld_tx_control_avail_monitor_scan_speed =
+		nthw_register_get_field(p->mp_reg_tx_control, DBS_TX_CONTROL_AMS);
+	p->mp_fld_tx_control_used_write_enable =
+		nthw_register_get_field(p->mp_reg_tx_control, DBS_TX_CONTROL_UWE);
+	p->mp_fld_tx_control_used_writer_update_speed =
+		nthw_register_get_field(p->mp_reg_tx_control, DBS_TX_CONTROL_UWS);
+	p->mp_fld_tx_control_tx_queues_enable =
+		nthw_register_get_field(p->mp_reg_tx_control, DBS_TX_CONTROL_QE);
+
+	p->mp_reg_rx_init = nthw_module_get_register(p->mp_mod_dbs, DBS_RX_INIT);
+	p->mp_fld_rx_init_init = nthw_register_get_field(p->mp_reg_rx_init, DBS_RX_INIT_INIT);
+	p->mp_fld_rx_init_queue = nthw_register_get_field(p->mp_reg_rx_init, DBS_RX_INIT_QUEUE);
+	p->mp_fld_rx_init_busy = nthw_register_get_field(p->mp_reg_rx_init, DBS_RX_INIT_BUSY);
+
+	p->mp_reg_rx_init_val = nthw_module_query_register(p->mp_mod_dbs, DBS_RX_INIT_VAL);
+
+	if (p->mp_reg_rx_init_val) {
+		p->mp_fld_rx_init_val_idx =
+			nthw_register_query_field(p->mp_reg_rx_init_val, DBS_RX_INIT_VAL_IDX);
+		p->mp_fld_rx_init_val_ptr =
+			nthw_register_query_field(p->mp_reg_rx_init_val, DBS_RX_INIT_VAL_PTR);
+	}
+
+	p->mp_reg_rx_ptr = nthw_module_query_register(p->mp_mod_dbs, DBS_RX_PTR);
+
+	if (p->mp_reg_rx_ptr) {
+		p->mp_fld_rx_ptr_ptr = nthw_register_query_field(p->mp_reg_rx_ptr, DBS_RX_PTR_PTR);
+		p->mp_fld_rx_ptr_queue =
+			nthw_register_query_field(p->mp_reg_rx_ptr, DBS_RX_PTR_QUEUE);
+		p->mp_fld_rx_ptr_valid =
+			nthw_register_query_field(p->mp_reg_rx_ptr, DBS_RX_PTR_VALID);
+	}
+
+	p->mp_reg_tx_init = nthw_module_get_register(p->mp_mod_dbs, DBS_TX_INIT);
+	p->mp_fld_tx_init_init = nthw_register_get_field(p->mp_reg_tx_init, DBS_TX_INIT_INIT);
+	p->mp_fld_tx_init_queue = nthw_register_get_field(p->mp_reg_tx_init, DBS_TX_INIT_QUEUE);
+	p->mp_fld_tx_init_busy = nthw_register_get_field(p->mp_reg_tx_init, DBS_TX_INIT_BUSY);
+
+	p->mp_reg_tx_init_val = nthw_module_query_register(p->mp_mod_dbs, DBS_TX_INIT_VAL);
+
+	if (p->mp_reg_tx_init_val) {
+		p->mp_fld_tx_init_val_idx =
+			nthw_register_query_field(p->mp_reg_tx_init_val, DBS_TX_INIT_VAL_IDX);
+		p->mp_fld_tx_init_val_ptr =
+			nthw_register_query_field(p->mp_reg_tx_init_val, DBS_TX_INIT_VAL_PTR);
+	}
+
+	p->mp_reg_tx_ptr = nthw_module_query_register(p->mp_mod_dbs, DBS_TX_PTR);
+
+	if (p->mp_reg_tx_ptr) {
+		p->mp_fld_tx_ptr_ptr = nthw_register_query_field(p->mp_reg_tx_ptr, DBS_TX_PTR_PTR);
+		p->mp_fld_tx_ptr_queue =
+			nthw_register_query_field(p->mp_reg_tx_ptr, DBS_TX_PTR_QUEUE);
+		p->mp_fld_tx_ptr_valid =
+			nthw_register_query_field(p->mp_reg_tx_ptr, DBS_TX_PTR_VALID);
+	}
+
+	p->mp_reg_rx_idle = nthw_module_query_register(p->mp_mod_dbs, DBS_RX_IDLE);
+
+	if (p->mp_reg_rx_idle) {
+		p->mp_fld_rx_idle_idle =
+			nthw_register_query_field(p->mp_reg_rx_idle, DBS_RX_IDLE_IDLE);
+		p->mp_fld_rx_idle_queue =
+			nthw_register_query_field(p->mp_reg_rx_idle, DBS_RX_IDLE_QUEUE);
+		p->mp_fld_rx_idle_busy =
+			nthw_register_query_field(p->mp_reg_rx_idle, DBS_RX_IDLE_BUSY);
+	}
+
+	p->mp_reg_tx_idle = nthw_module_query_register(p->mp_mod_dbs, DBS_TX_IDLE);
+
+	if (p->mp_reg_tx_idle) {
+		p->mp_fld_tx_idle_idle =
+			nthw_register_query_field(p->mp_reg_tx_idle, DBS_TX_IDLE_IDLE);
+		p->mp_fld_tx_idle_queue =
+			nthw_register_query_field(p->mp_reg_tx_idle, DBS_TX_IDLE_QUEUE);
+		p->mp_fld_tx_idle_busy =
+			nthw_register_query_field(p->mp_reg_tx_idle, DBS_TX_IDLE_BUSY);
+	}
+
+	return 0;
+}
+
+static int dbs_reset_rx_control(nthw_dbs_t *p)
+{
+	nthw_field_set_val32(p->mp_fld_rx_control_last_queue, 0);
+	nthw_field_set_val32(p->mp_fld_rx_control_avail_monitor_enable, 0);
+	nthw_field_set_val32(p->mp_fld_rx_control_avail_monitor_scan_speed, 8);
+	nthw_field_set_val32(p->mp_fld_rx_control_used_write_enable, 0);
+	nthw_field_set_val32(p->mp_fld_rx_control_used_writer_update_speed, 5);
+	nthw_field_set_val32(p->mp_fld_rx_control_rx_queues_enable, 0);
+	nthw_register_flush(p->mp_reg_rx_control, 1);
+	return 0;
+}
+
+static int dbs_reset_tx_control(nthw_dbs_t *p)
+{
+	nthw_field_set_val32(p->mp_fld_tx_control_last_queue, 0);
+	nthw_field_set_val32(p->mp_fld_tx_control_avail_monitor_enable, 0);
+	nthw_field_set_val32(p->mp_fld_tx_control_avail_monitor_scan_speed, 5);
+	nthw_field_set_val32(p->mp_fld_tx_control_used_write_enable, 0);
+	nthw_field_set_val32(p->mp_fld_tx_control_used_writer_update_speed, 8);
+	nthw_field_set_val32(p->mp_fld_tx_control_tx_queues_enable, 0);
+	nthw_register_flush(p->mp_reg_tx_control, 1);
 	return 0;
 }
 
 void dbs_reset(nthw_dbs_t *p)
 {
-	(void)p;
+	dbs_reset_rx_control(p);
+	dbs_reset_tx_control(p);
 }
 
 int set_rx_control(nthw_dbs_t *p,
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
index 45f9794958..3560eeda7d 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs.h
@@ -16,6 +16,7 @@
 #include "nthw_fpga_reg_defs_cat.h"
 #include "nthw_fpga_reg_defs_cpy.h"
 #include "nthw_fpga_reg_defs_csu.h"
+#include "nthw_fpga_reg_defs_dbs.h"
 #include "nthw_fpga_reg_defs_flm.h"
 #include "nthw_fpga_reg_defs_gfg.h"
 #include "nthw_fpga_reg_defs_gmf.h"
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h
new file mode 100644
index 0000000000..ee5d726aab
--- /dev/null
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h
@@ -0,0 +1,79 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+/*
+ * nthw_fpga_reg_defs_dbs.h
+ *
+ * Auto-generated file - do *NOT* edit
+ *
+ */
+
+#ifndef _NTHW_FPGA_REG_DEFS_DBS_
+#define _NTHW_FPGA_REG_DEFS_DBS_
+
+/* DBS */
+#define DBS_RX_CONTROL (0xb18b2866UL)
+#define DBS_RX_CONTROL_AME (0x1f9219acUL)
+#define DBS_RX_CONTROL_AMS (0xeb46acfdUL)
+#define DBS_RX_CONTROL_LQ (0xe65f90b2UL)
+#define DBS_RX_CONTROL_QE (0x3e928d3UL)
+#define DBS_RX_CONTROL_UWE (0xb490e8dbUL)
+#define DBS_RX_CONTROL_UWS (0x40445d8aUL)
+#define DBS_RX_IDLE (0x93c723bfUL)
+#define DBS_RX_IDLE_BUSY (0x8e043b5bUL)
+#define DBS_RX_IDLE_IDLE (0x9dba27ccUL)
+#define DBS_RX_IDLE_QUEUE (0xbbddab49UL)
+#define DBS_RX_INIT (0x899772deUL)
+#define DBS_RX_INIT_BUSY (0x8576d90aUL)
+#define DBS_RX_INIT_INIT (0x8c9894fcUL)
+#define DBS_RX_INIT_QUEUE (0xa7bab8c9UL)
+#define DBS_RX_INIT_VAL (0x7789b4d8UL)
+#define DBS_RX_INIT_VAL_IDX (0xead0e2beUL)
+#define DBS_RX_INIT_VAL_PTR (0x5330810eUL)
+#define DBS_RX_PTR (0x628ce523UL)
+#define DBS_RX_PTR_PTR (0x7f834481UL)
+#define DBS_RX_PTR_QUEUE (0x4f3fa6d1UL)
+#define DBS_RX_PTR_VALID (0xbcc5ec4dUL)
+#define DBS_STATUS (0xb5f35220UL)
+#define DBS_STATUS_OK (0xcf09a30fUL)
+#define DBS_TX_CONTROL (0xbc955821UL)
+#define DBS_TX_CONTROL_AME (0xe750521aUL)
+#define DBS_TX_CONTROL_AMS (0x1384e74bUL)
+#define DBS_TX_CONTROL_LQ (0x46ba4f6fUL)
+#define DBS_TX_CONTROL_QE (0xa30cf70eUL)
+#define DBS_TX_CONTROL_UWE (0x4c52a36dUL)
+#define DBS_TX_CONTROL_UWS (0xb886163cUL)
+#define DBS_TX_IDLE (0xf0171685UL)
+#define DBS_TX_IDLE_BUSY (0x61399ebbUL)
+#define DBS_TX_IDLE_IDLE (0x7287822cUL)
+#define DBS_TX_IDLE_QUEUE (0x1b387494UL)
+#define DBS_TX_INIT (0xea4747e4UL)
+#define DBS_TX_INIT_BUSY (0x6a4b7ceaUL)
+#define DBS_TX_INIT_INIT (0x63a5311cUL)
+#define DBS_TX_INIT_QUEUE (0x75f6714UL)
+#define DBS_TX_INIT_VAL (0x9f3c7e9bUL)
+#define DBS_TX_INIT_VAL_IDX (0xc82a364cUL)
+#define DBS_TX_INIT_VAL_PTR (0x71ca55fcUL)
+#define DBS_TX_PTR (0xb4d5063eUL)
+#define DBS_TX_PTR_PTR (0x729d34c6UL)
+#define DBS_TX_PTR_QUEUE (0xa0020331UL)
+#define DBS_TX_PTR_VALID (0x53f849adUL)
+#define DBS_TX_QOS_CTRL (0x3b2c3286UL)
+#define DBS_TX_QOS_CTRL_ADR (0x666600acUL)
+#define DBS_TX_QOS_CTRL_CNT (0x766e997dUL)
+#define DBS_TX_QOS_DATA (0x94fdb09fUL)
+#define DBS_TX_QOS_DATA_BS (0x2c394071UL)
+#define DBS_TX_QOS_DATA_EN (0x7eba6fUL)
+#define DBS_TX_QOS_DATA_IR (0xb8caa92cUL)
+#define DBS_TX_QOS_DATA_MUL (0xd7407a67UL)
+#define DBS_TX_QOS_RATE (0xe6e27cc5UL)
+#define DBS_TX_QOS_RATE_DIV (0x8cd07ba3UL)
+#define DBS_TX_QOS_RATE_MUL (0x9814e40bUL)
+
+#endif	/* _NTHW_FPGA_REG_DEFS_DBS_ */
+
+/*
+ * Auto-generated file - do *NOT* edit
+ */
-- 
2.45.0


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

* [PATCH v1 08/14] net/ntnic: add functions for availability monitor management
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (44 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 07/14] net/ntnic: add split-queue support Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 09/14] net/ntnic: used writer data handling functions Serhii Iliushyk
                   ` (5 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

Implemented functions to configure and manage availability monitor data.

Added functions to set and flush availability monitor data.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c |  61 +++-
 drivers/net/ntnic/include/ntnic_dbs.h         |  72 +++++
 drivers/net/ntnic/nthw/dbs/nthw_dbs.c         | 271 ++++++++++++++++++
 .../nthw/supported/nthw_fpga_reg_defs_dbs.h   |  23 ++
 4 files changed, 420 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
index e69cf7ad21..065dac6af0 100644
--- a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
+++ b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
@@ -103,11 +103,7 @@ struct nthw_virt_queue {
 	 *   0: VirtIO-Net header (12 bytes).
 	 *   1: Napatech DVIO0 descriptor (12 bytes).
 	 */
-};
-
-struct pvirtq_struct_layout_s {
-	size_t driver_event_offset;
-	size_t device_event_offset;
+	void *avail_struct_phys_addr;
 };
 
 static struct nthw_virt_queue rxvq[MAX_VIRT_QUEUES];
@@ -304,9 +300,22 @@ static struct nthw_virt_queue *nthw_setup_rx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 {
 	(void)header;
 	(void)desc_struct_phys_addr;
-	(void)avail_struct_phys_addr;
 	(void)used_struct_phys_addr;
 
+	/*
+	 * 2. Configure the DBS.RX_AM_DATA memory and enable the queues you plan to use;
+	 *  good idea to initialize all DBS_RX_QUEUES entries.
+	 *  Notice: We do this only for queues that don't require interrupts (i.e. if
+	 *    irq_vector < 0). Queues that require interrupts will have RX_AM_DATA enabled
+	 *    at a later time (after we have enabled vfio interrupts in the kernel).
+	 */
+	if (irq_vector < 0) {
+		if (set_rx_am_data(p_nthw_dbs, index, (uint64_t)avail_struct_phys_addr,
+				RX_AM_DISABLE, host_id, 0,
+				irq_vector >= 0 ? 1 : 0) != 0) {
+			return NULL;
+		}
+	}
 
 	/*
 	 * 5. Initialize all RX queues (all DBS_RX_QUEUES of them) using the
@@ -314,6 +323,15 @@ static struct nthw_virt_queue *nthw_setup_rx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 	 */
 	dbs_init_rx_queue(p_nthw_dbs, index, start_idx, start_ptr);
 
+	/*
+	 * 2. Configure the DBS.RX_AM_DATA memory and enable the queues you plan to use;
+	 *  good idea to initialize all DBS_RX_QUEUES entries.
+	 */
+	if (set_rx_am_data(p_nthw_dbs, index, (uint64_t)avail_struct_phys_addr, RX_AM_ENABLE,
+			host_id, 0, irq_vector >= 0 ? 1 : 0) != 0) {
+		return NULL;
+	}
+
 	/* Save queue state */
 	rxvq[index].usage = NTHW_VIRTQ_UNMANAGED;
 	rxvq[index].mp_nthw_dbs = p_nthw_dbs;
@@ -321,6 +339,7 @@ static struct nthw_virt_queue *nthw_setup_rx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 	rxvq[index].queue_size = queue_size;
 	rxvq[index].am_enable = (irq_vector < 0) ? RX_AM_ENABLE : RX_AM_DISABLE;
 	rxvq[index].host_id = host_id;
+	rxvq[index].avail_struct_phys_addr = avail_struct_phys_addr;
 	rxvq[index].vq_type = vq_type;
 	rxvq[index].in_order = 0;	/* not used */
 	rxvq[index].irq_vector = irq_vector;
@@ -347,15 +366,42 @@ static struct nthw_virt_queue *nthw_setup_tx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 {
 	(void)header;
 	(void)desc_struct_phys_addr;
-	(void)avail_struct_phys_addr;
 	(void)used_struct_phys_addr;
 
+	/*
+	 * 2. Configure the DBS.TX_AM_DATA memory and enable the queues you plan to use;
+	 *    good idea to initialize all DBS_TX_QUEUES entries.
+	 */
+	if (set_tx_am_data(p_nthw_dbs, index, (uint64_t)avail_struct_phys_addr, TX_AM_DISABLE,
+			host_id, 0, irq_vector >= 0 ? 1 : 0) != 0) {
+		return NULL;
+	}
+
 	/*
 	 * 5. Initialize all TX queues (all DBS_TX_QUEUES of them) using the
 	 *    DBS.TX_INIT register.
 	 */
 	dbs_init_tx_queue(p_nthw_dbs, index, start_idx, start_ptr);
 
+	if (nthw_dbs_set_tx_qp_data(p_nthw_dbs, index, virtual_port) != 0)
+		return NULL;
+
+	/*
+	 * 2. Configure the DBS.TX_AM_DATA memory and enable the queues you plan to use;
+	 *    good idea to initialize all DBS_TX_QUEUES entries.
+	 *    Notice: We do this only for queues that don't require interrupts (i.e. if
+	 *            irq_vector < 0). Queues that require interrupts will have TX_AM_DATA
+	 *            enabled at a later time (after we have enabled vfio interrupts in the
+	 *            kernel).
+	 */
+	if (irq_vector < 0) {
+		if (set_tx_am_data(p_nthw_dbs, index, (uint64_t)avail_struct_phys_addr,
+				TX_AM_ENABLE, host_id, 0,
+				irq_vector >= 0 ? 1 : 0) != 0) {
+			return NULL;
+		}
+	}
+
 	/* Save queue state */
 	txvq[index].usage = NTHW_VIRTQ_UNMANAGED;
 	txvq[index].mp_nthw_dbs = p_nthw_dbs;
@@ -365,6 +411,7 @@ static struct nthw_virt_queue *nthw_setup_tx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 	txvq[index].host_id = host_id;
 	txvq[index].port = port;
 	txvq[index].virtual_port = virtual_port;
+	txvq[index].avail_struct_phys_addr = avail_struct_phys_addr;
 	txvq[index].vq_type = vq_type;
 	txvq[index].in_order = in_order;
 	txvq[index].irq_vector = irq_vector;
diff --git a/drivers/net/ntnic/include/ntnic_dbs.h b/drivers/net/ntnic/include/ntnic_dbs.h
index 4e6236e8b4..438f1858f5 100644
--- a/drivers/net/ntnic/include/ntnic_dbs.h
+++ b/drivers/net/ntnic/include/ntnic_dbs.h
@@ -15,6 +15,29 @@
  * Struct for implementation of memory bank shadows
  */
 
+/* DBS_RX_AM_DATA */
+struct nthw_dbs_rx_am_data_s {
+	uint64_t guest_physical_address;
+	uint32_t enable;
+	uint32_t host_id;
+	uint32_t packed;
+	uint32_t int_enable;
+};
+
+/* DBS_TX_AM_DATA */
+struct nthw_dbs_tx_am_data_s {
+	uint64_t guest_physical_address;
+	uint32_t enable;
+	uint32_t host_id;
+	uint32_t packed;
+	uint32_t int_enable;
+};
+
+/* DBS_TX_QP_DATA */
+struct nthw_dbs_tx_qp_data_s {
+	uint32_t virtual_port;
+};
+
 struct nthw_dbs_s {
 	nthw_fpga_t *mp_fpga;
 	nthw_module_t *mp_mod_dbs;
@@ -75,6 +98,40 @@ struct nthw_dbs_s {
 	nthw_field_t *mp_fld_tx_idle_idle;
 	nthw_field_t *mp_fld_tx_idle_queue;
 	nthw_field_t *mp_fld_tx_idle_busy;
+
+	nthw_register_t *mp_reg_rx_avail_monitor_control;
+	nthw_field_t *mp_fld_rx_avail_monitor_control_adr;
+	nthw_field_t *mp_fld_rx_avail_monitor_control_cnt;
+
+	nthw_register_t *mp_reg_rx_avail_monitor_data;
+	nthw_field_t *mp_fld_rx_avail_monitor_data_guest_physical_address;
+	nthw_field_t *mp_fld_rx_avail_monitor_data_enable;
+	nthw_field_t *mp_fld_rx_avail_monitor_data_host_id;
+	nthw_field_t *mp_fld_rx_avail_monitor_data_packed;
+	nthw_field_t *mp_fld_rx_avail_monitor_data_int;
+
+	nthw_register_t *mp_reg_tx_avail_monitor_control;
+	nthw_field_t *mp_fld_tx_avail_monitor_control_adr;
+	nthw_field_t *mp_fld_tx_avail_monitor_control_cnt;
+
+	nthw_register_t *mp_reg_tx_avail_monitor_data;
+	nthw_field_t *mp_fld_tx_avail_monitor_data_guest_physical_address;
+	nthw_field_t *mp_fld_tx_avail_monitor_data_enable;
+	nthw_field_t *mp_fld_tx_avail_monitor_data_host_id;
+	nthw_field_t *mp_fld_tx_avail_monitor_data_packed;
+	nthw_field_t *mp_fld_tx_avail_monitor_data_int;
+
+	nthw_register_t *mp_reg_tx_queue_property_control;
+	nthw_field_t *mp_fld_tx_queue_property_control_adr;
+	nthw_field_t *mp_fld_tx_queue_property_control_cnt;
+
+	nthw_register_t *mp_reg_tx_queue_property_data;
+	nthw_field_t *mp_fld_tx_queue_property_data_v_port;
+
+	struct nthw_dbs_rx_am_data_s m_rx_am_shadow[NT_DBS_RX_QUEUES_MAX];
+
+	struct nthw_dbs_tx_am_data_s m_tx_am_shadow[NT_DBS_TX_QUEUES_MAX];
+	struct nthw_dbs_tx_qp_data_s m_tx_qp_shadow[NT_DBS_TX_QUEUES_MAX];
 };
 
 typedef struct nthw_dbs_s nthw_dbs_t;
@@ -103,5 +160,20 @@ int get_rx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy);
 int set_tx_init(nthw_dbs_t *p, uint32_t start_idx, uint32_t start_ptr, uint32_t init,
 	uint32_t queue);
 int get_tx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy);
+int set_rx_am_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t enable,
+	uint32_t host_id,
+	uint32_t packed,
+	uint32_t int_enable);
+int set_tx_am_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t enable,
+	uint32_t host_id,
+	uint32_t packed,
+	uint32_t int_enable);
+int nthw_dbs_set_tx_qp_data(nthw_dbs_t *p, uint32_t index, uint32_t virtual_port);
 
 #endif	/* _NTNIC_DBS_H_ */
diff --git a/drivers/net/ntnic/nthw/dbs/nthw_dbs.c b/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
index cd1123b6f3..99a1575036 100644
--- a/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
+++ b/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
@@ -9,6 +9,25 @@
 #include "nthw_drv.h"
 #include "nthw_register.h"
 
+static void set_shadow_tx_qp_data(nthw_dbs_t *p, uint32_t index, uint32_t virtual_port);
+static void flush_tx_qp_data(nthw_dbs_t *p, uint32_t index);
+static void set_shadow_rx_am_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t enable,
+	uint32_t host_id,
+	uint32_t packed,
+	uint32_t int_enable);
+static void flush_rx_am_data(nthw_dbs_t *p, uint32_t index);
+static void set_shadow_tx_am_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t enable,
+	uint32_t host_id,
+	uint32_t packed,
+	uint32_t int_enable);
+static void flush_tx_am_data(nthw_dbs_t *p, uint32_t index);
+
 nthw_dbs_t *nthw_dbs_new(void)
 {
 	nthw_dbs_t *p = malloc(sizeof(nthw_dbs_t));
@@ -142,6 +161,55 @@ int dbs_init(nthw_dbs_t *p, nthw_fpga_t *p_fpga, int n_instance)
 			nthw_register_query_field(p->mp_reg_tx_idle, DBS_TX_IDLE_BUSY);
 	}
 
+	p->mp_reg_rx_avail_monitor_control =
+		nthw_module_get_register(p->mp_mod_dbs, DBS_RX_AM_CTRL);
+	p->mp_fld_rx_avail_monitor_control_adr =
+		nthw_register_get_field(p->mp_reg_rx_avail_monitor_control, DBS_RX_AM_CTRL_ADR);
+	p->mp_fld_rx_avail_monitor_control_cnt =
+		nthw_register_get_field(p->mp_reg_rx_avail_monitor_control, DBS_RX_AM_CTRL_CNT);
+
+	p->mp_reg_rx_avail_monitor_data = nthw_module_get_register(p->mp_mod_dbs, DBS_RX_AM_DATA);
+	p->mp_fld_rx_avail_monitor_data_guest_physical_address =
+		nthw_register_get_field(p->mp_reg_rx_avail_monitor_data, DBS_RX_AM_DATA_GPA);
+	p->mp_fld_rx_avail_monitor_data_enable =
+		nthw_register_get_field(p->mp_reg_rx_avail_monitor_data, DBS_RX_AM_DATA_ENABLE);
+	p->mp_fld_rx_avail_monitor_data_host_id =
+		nthw_register_get_field(p->mp_reg_rx_avail_monitor_data, DBS_RX_AM_DATA_HID);
+	p->mp_fld_rx_avail_monitor_data_packed =
+		nthw_register_query_field(p->mp_reg_rx_avail_monitor_data, DBS_RX_AM_DATA_PCKED);
+	p->mp_fld_rx_avail_monitor_data_int =
+		nthw_register_query_field(p->mp_reg_rx_avail_monitor_data, DBS_RX_AM_DATA_INT);
+
+	p->mp_reg_tx_avail_monitor_control =
+		nthw_module_get_register(p->mp_mod_dbs, DBS_TX_AM_CTRL);
+	p->mp_fld_tx_avail_monitor_control_adr =
+		nthw_register_get_field(p->mp_reg_tx_avail_monitor_control, DBS_TX_AM_CTRL_ADR);
+	p->mp_fld_tx_avail_monitor_control_cnt =
+		nthw_register_get_field(p->mp_reg_tx_avail_monitor_control, DBS_TX_AM_CTRL_CNT);
+
+	p->mp_reg_tx_avail_monitor_data = nthw_module_get_register(p->mp_mod_dbs, DBS_TX_AM_DATA);
+	p->mp_fld_tx_avail_monitor_data_guest_physical_address =
+		nthw_register_get_field(p->mp_reg_tx_avail_monitor_data, DBS_TX_AM_DATA_GPA);
+	p->mp_fld_tx_avail_monitor_data_enable =
+		nthw_register_get_field(p->mp_reg_tx_avail_monitor_data, DBS_TX_AM_DATA_ENABLE);
+	p->mp_fld_tx_avail_monitor_data_host_id =
+		nthw_register_get_field(p->mp_reg_tx_avail_monitor_data, DBS_TX_AM_DATA_HID);
+	p->mp_fld_tx_avail_monitor_data_packed =
+		nthw_register_query_field(p->mp_reg_tx_avail_monitor_data, DBS_TX_AM_DATA_PCKED);
+	p->mp_fld_tx_avail_monitor_data_int =
+		nthw_register_query_field(p->mp_reg_tx_avail_monitor_data, DBS_TX_AM_DATA_INT);
+
+	p->mp_reg_tx_queue_property_control =
+		nthw_module_get_register(p->mp_mod_dbs, DBS_TX_QP_CTRL);
+	p->mp_fld_tx_queue_property_control_adr =
+		nthw_register_get_field(p->mp_reg_tx_queue_property_control, DBS_TX_QP_CTRL_ADR);
+	p->mp_fld_tx_queue_property_control_cnt =
+		nthw_register_get_field(p->mp_reg_tx_queue_property_control, DBS_TX_QP_CTRL_CNT);
+
+	p->mp_reg_tx_queue_property_data = nthw_module_get_register(p->mp_mod_dbs, DBS_TX_QP_DATA);
+	p->mp_fld_tx_queue_property_data_v_port =
+		nthw_register_get_field(p->mp_reg_tx_queue_property_data, DBS_TX_QP_DATA_VPORT);
+
 	return 0;
 }
 
@@ -171,8 +239,24 @@ static int dbs_reset_tx_control(nthw_dbs_t *p)
 
 void dbs_reset(nthw_dbs_t *p)
 {
+	int i;
 	dbs_reset_rx_control(p);
 	dbs_reset_tx_control(p);
+
+	/* Reset RX memory banks and shado */
+	for (i = 0; i < NT_DBS_RX_QUEUES_MAX; ++i) {
+		set_shadow_rx_am_data(p, i, 0, 0, 0, 0, 0);
+		flush_rx_am_data(p, i);
+	}
+
+	/* Reset TX memory banks and shado */
+	for (i = 0; i < NT_DBS_TX_QUEUES_MAX; ++i) {
+		set_shadow_tx_am_data(p, i, 0, 0, 0, 0, 0);
+		flush_tx_am_data(p, i);
+
+		set_shadow_tx_qp_data(p, i, 0);
+		flush_tx_qp_data(p, i);
+	}
 }
 
 int set_rx_control(nthw_dbs_t *p,
@@ -256,3 +340,190 @@ int get_tx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy)
 	*busy = nthw_field_get_val32(p->mp_fld_tx_init_busy);
 	return 0;
 }
+
+static void set_rx_am_data_index(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val32(p->mp_fld_rx_avail_monitor_control_adr, index);
+	nthw_field_set_val32(p->mp_fld_rx_avail_monitor_control_cnt, 1);
+	nthw_register_flush(p->mp_reg_rx_avail_monitor_control, 1);
+}
+
+static void set_shadow_rx_am_data_guest_physical_address(nthw_dbs_t *p, uint32_t index,
+	uint64_t guest_physical_address)
+{
+	p->m_rx_am_shadow[index].guest_physical_address = guest_physical_address;
+}
+
+static void nthw_dbs_set_shadow_rx_am_data_enable(nthw_dbs_t *p, uint32_t index, uint32_t enable)
+{
+	p->m_rx_am_shadow[index].enable = enable;
+}
+
+static void set_shadow_rx_am_data_host_id(nthw_dbs_t *p, uint32_t index, uint32_t host_id)
+{
+	p->m_rx_am_shadow[index].host_id = host_id;
+}
+
+static void set_shadow_rx_am_data_packed(nthw_dbs_t *p, uint32_t index, uint32_t packed)
+{
+	p->m_rx_am_shadow[index].packed = packed;
+}
+
+static void set_shadow_rx_am_data_int_enable(nthw_dbs_t *p, uint32_t index, uint32_t int_enable)
+{
+	p->m_rx_am_shadow[index].int_enable = int_enable;
+}
+
+static void set_shadow_rx_am_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t enable,
+	uint32_t host_id,
+	uint32_t packed,
+	uint32_t int_enable)
+{
+	set_shadow_rx_am_data_guest_physical_address(p, index, guest_physical_address);
+	nthw_dbs_set_shadow_rx_am_data_enable(p, index, enable);
+	set_shadow_rx_am_data_host_id(p, index, host_id);
+	set_shadow_rx_am_data_packed(p, index, packed);
+	set_shadow_rx_am_data_int_enable(p, index, int_enable);
+}
+
+static void flush_rx_am_data(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val(p->mp_fld_rx_avail_monitor_data_guest_physical_address,
+		(uint32_t *)&p->m_rx_am_shadow[index].guest_physical_address, 2);
+	nthw_field_set_val32(p->mp_fld_rx_avail_monitor_data_enable,
+		p->m_rx_am_shadow[index].enable);
+	nthw_field_set_val32(p->mp_fld_rx_avail_monitor_data_host_id,
+		p->m_rx_am_shadow[index].host_id);
+
+	if (p->mp_fld_rx_avail_monitor_data_packed) {
+		nthw_field_set_val32(p->mp_fld_rx_avail_monitor_data_packed,
+			p->m_rx_am_shadow[index].packed);
+	}
+
+	if (p->mp_fld_rx_avail_monitor_data_int) {
+		nthw_field_set_val32(p->mp_fld_rx_avail_monitor_data_int,
+			p->m_rx_am_shadow[index].int_enable);
+	}
+
+	set_rx_am_data_index(p, index);
+	nthw_register_flush(p->mp_reg_rx_avail_monitor_data, 1);
+}
+
+int set_rx_am_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t enable,
+	uint32_t host_id,
+	uint32_t packed,
+	uint32_t int_enable)
+{
+	if (!p->mp_reg_rx_avail_monitor_data)
+		return -ENOTSUP;
+
+	set_shadow_rx_am_data(p, index, guest_physical_address, enable, host_id, packed,
+		int_enable);
+	flush_rx_am_data(p, index);
+	return 0;
+}
+
+static void set_tx_am_data_index(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val32(p->mp_fld_tx_avail_monitor_control_adr, index);
+	nthw_field_set_val32(p->mp_fld_tx_avail_monitor_control_cnt, 1);
+	nthw_register_flush(p->mp_reg_tx_avail_monitor_control, 1);
+}
+
+static void set_shadow_tx_am_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t enable,
+	uint32_t host_id,
+	uint32_t packed,
+	uint32_t int_enable)
+{
+	p->m_tx_am_shadow[index].guest_physical_address = guest_physical_address;
+	p->m_tx_am_shadow[index].enable = enable;
+	p->m_tx_am_shadow[index].host_id = host_id;
+	p->m_tx_am_shadow[index].packed = packed;
+	p->m_tx_am_shadow[index].int_enable = int_enable;
+}
+
+static void flush_tx_am_data(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val(p->mp_fld_tx_avail_monitor_data_guest_physical_address,
+		(uint32_t *)&p->m_tx_am_shadow[index].guest_physical_address, 2);
+	nthw_field_set_val32(p->mp_fld_tx_avail_monitor_data_enable,
+		p->m_tx_am_shadow[index].enable);
+	nthw_field_set_val32(p->mp_fld_tx_avail_monitor_data_host_id,
+		p->m_tx_am_shadow[index].host_id);
+
+	if (p->mp_fld_tx_avail_monitor_data_packed) {
+		nthw_field_set_val32(p->mp_fld_tx_avail_monitor_data_packed,
+			p->m_tx_am_shadow[index].packed);
+	}
+
+	if (p->mp_fld_tx_avail_monitor_data_int) {
+		nthw_field_set_val32(p->mp_fld_tx_avail_monitor_data_int,
+			p->m_tx_am_shadow[index].int_enable);
+	}
+
+	set_tx_am_data_index(p, index);
+	nthw_register_flush(p->mp_reg_tx_avail_monitor_data, 1);
+}
+
+int set_tx_am_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t enable,
+	uint32_t host_id,
+	uint32_t packed,
+	uint32_t int_enable)
+{
+	if (!p->mp_reg_tx_avail_monitor_data)
+		return -ENOTSUP;
+
+	set_shadow_tx_am_data(p, index, guest_physical_address, enable, host_id, packed,
+		int_enable);
+	flush_tx_am_data(p, index);
+	return 0;
+}
+
+static void set_tx_qp_data_index(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val32(p->mp_fld_tx_queue_property_control_adr, index);
+	nthw_field_set_val32(p->mp_fld_tx_queue_property_control_cnt, 1);
+	nthw_register_flush(p->mp_reg_tx_queue_property_control, 1);
+}
+
+static void set_shadow_tx_qp_data_virtual_port(nthw_dbs_t *p, uint32_t index,
+	uint32_t virtual_port)
+{
+	p->m_tx_qp_shadow[index].virtual_port = virtual_port;
+}
+
+static void set_shadow_tx_qp_data(nthw_dbs_t *p, uint32_t index, uint32_t virtual_port)
+{
+	set_shadow_tx_qp_data_virtual_port(p, index, virtual_port);
+}
+
+static void flush_tx_qp_data(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val32(p->mp_fld_tx_queue_property_data_v_port,
+		p->m_tx_qp_shadow[index].virtual_port);
+
+	set_tx_qp_data_index(p, index);
+	nthw_register_flush(p->mp_reg_tx_queue_property_data, 1);
+}
+
+int nthw_dbs_set_tx_qp_data(nthw_dbs_t *p, uint32_t index, uint32_t virtual_port)
+{
+	if (!p->mp_reg_tx_queue_property_data)
+		return -ENOTSUP;
+
+	set_shadow_tx_qp_data(p, index, virtual_port);
+	flush_tx_qp_data(p, index);
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h
index ee5d726aab..00570fa8af 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h
@@ -14,6 +14,15 @@
 #define _NTHW_FPGA_REG_DEFS_DBS_
 
 /* DBS */
+#define DBS_RX_AM_CTRL (0x7359feUL)
+#define DBS_RX_AM_CTRL_ADR (0x4704a1UL)
+#define DBS_RX_AM_CTRL_CNT (0x104f9d70UL)
+#define DBS_RX_AM_DATA (0xafa2dbe7UL)
+#define DBS_RX_AM_DATA_ENABLE (0x11658278UL)
+#define DBS_RX_AM_DATA_GPA (0xbf307344UL)
+#define DBS_RX_AM_DATA_HID (0x5f0669eeUL)
+#define DBS_RX_AM_DATA_INT (0xc32857aUL)
+#define DBS_RX_AM_DATA_PCKED (0x7d840fb4UL)
 #define DBS_RX_CONTROL (0xb18b2866UL)
 #define DBS_RX_CONTROL_AME (0x1f9219acUL)
 #define DBS_RX_CONTROL_AMS (0xeb46acfdUL)
@@ -38,6 +47,15 @@
 #define DBS_RX_PTR_VALID (0xbcc5ec4dUL)
 #define DBS_STATUS (0xb5f35220UL)
 #define DBS_STATUS_OK (0xcf09a30fUL)
+#define DBS_TX_AM_CTRL (0xd6d29b9UL)
+#define DBS_TX_AM_CTRL_ADR (0xf8854f17UL)
+#define DBS_TX_AM_CTRL_CNT (0xe88dd6c6UL)
+#define DBS_TX_AM_DATA (0xa2bcaba0UL)
+#define DBS_TX_AM_DATA_ENABLE (0xb6513570UL)
+#define DBS_TX_AM_DATA_GPA (0x47f238f2UL)
+#define DBS_TX_AM_DATA_HID (0xa7c42258UL)
+#define DBS_TX_AM_DATA_INT (0xf4f0ceccUL)
+#define DBS_TX_AM_DATA_PCKED (0x2e156650UL)
 #define DBS_TX_CONTROL (0xbc955821UL)
 #define DBS_TX_CONTROL_AME (0xe750521aUL)
 #define DBS_TX_CONTROL_AMS (0x1384e74bUL)
@@ -71,6 +89,11 @@
 #define DBS_TX_QOS_RATE (0xe6e27cc5UL)
 #define DBS_TX_QOS_RATE_DIV (0x8cd07ba3UL)
 #define DBS_TX_QOS_RATE_MUL (0x9814e40bUL)
+#define DBS_TX_QP_CTRL (0xd5fba432UL)
+#define DBS_TX_QP_CTRL_ADR (0x84238184UL)
+#define DBS_TX_QP_CTRL_CNT (0x942b1855UL)
+#define DBS_TX_QP_DATA (0x7a2a262bUL)
+#define DBS_TX_QP_DATA_VPORT (0xda741d67UL)
 
 #endif	/* _NTHW_FPGA_REG_DEFS_DBS_ */
 
-- 
2.45.0


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

* [PATCH v1 09/14] net/ntnic: used writer data handling functions
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (45 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 08/14] net/ntnic: add functions for availability monitor management Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 10/14] net/ntnic: add descriptor reader " Serhii Iliushyk
                   ` (4 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

Introduced functions to set and flush RX and TX used writer data.

Added support for setting shadow data with functions for guest
physical address, host ID, queue size, packed, interrupt enable,
vector, and ISTK for RX and TX.

Implemented set_rx_used_writer_data and set_tx_used_writer_data to
configure and flush data based on updated shadow structures.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c |  60 +++-
 drivers/net/ntnic/include/ntnic_dbs.h         |  71 ++++
 drivers/net/ntnic/nthw/dbs/nthw_dbs.c         | 316 ++++++++++++++++++
 .../nthw/supported/nthw_fpga_reg_defs_dbs.h   |  23 ++
 4 files changed, 468 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
index 065dac6af0..1df42dad11 100644
--- a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
+++ b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
@@ -285,6 +285,19 @@ dbs_initialize_virt_queue_structs(void *avail_struct_addr, void *used_struct_add
 		flgs);
 }
 
+static uint16_t dbs_qsize_log2(uint16_t qsize)
+{
+	uint32_t qs = 0;
+
+	while (qsize) {
+		qsize = qsize >> 1;
+		++qs;
+	}
+
+	--qs;
+	return qs;
+}
+
 static struct nthw_virt_queue *nthw_setup_rx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 	uint32_t index,
 	uint16_t start_idx,
@@ -300,7 +313,29 @@ static struct nthw_virt_queue *nthw_setup_rx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 {
 	(void)header;
 	(void)desc_struct_phys_addr;
-	(void)used_struct_phys_addr;
+	uint32_t qs = dbs_qsize_log2(queue_size);
+	uint32_t int_enable;
+	uint32_t vec;
+	uint32_t istk;
+
+	/*
+	 * 4. Configure the DBS.RX_UW_DATA memory; good idea to initialize all
+	 *   DBS_RX_QUEUES entries.
+	 *   Notice: We always start out with interrupts disabled (by setting the
+	 *     "irq_vector" argument to -1). Queues that require interrupts will have
+	 *     it enabled at a later time (after we have enabled vfio interrupts in
+	 *     the kernel).
+	 */
+	int_enable = 0;
+	vec = 0;
+	istk = 0;
+	NT_LOG_DBGX(DBG, NTNIC, "set_rx_uw_data int=0 irq_vector=%u\n", irq_vector);
+
+	if (set_rx_uw_data(p_nthw_dbs, index,
+			(uint64_t)used_struct_phys_addr,
+			host_id, qs, 0, int_enable, vec, istk) != 0) {
+		return NULL;
+	}
 
 	/*
 	 * 2. Configure the DBS.RX_AM_DATA memory and enable the queues you plan to use;
@@ -366,7 +401,28 @@ static struct nthw_virt_queue *nthw_setup_tx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 {
 	(void)header;
 	(void)desc_struct_phys_addr;
-	(void)used_struct_phys_addr;
+	uint32_t int_enable;
+	uint32_t vec;
+	uint32_t istk;
+	uint32_t qs = dbs_qsize_log2(queue_size);
+
+	/*
+	 * 4. Configure the DBS.TX_UW_DATA memory; good idea to initialize all
+	 *    DBS_TX_QUEUES entries.
+	 *    Notice: We always start out with interrupts disabled (by setting the
+	 *            "irq_vector" argument to -1). Queues that require interrupts will have
+	 *             it enabled at a later time (after we have enabled vfio interrupts in the
+	 *             kernel).
+	 */
+	int_enable = 0;
+	vec = 0;
+	istk = 0;
+
+	if (set_tx_uw_data(p_nthw_dbs, index,
+			(uint64_t)used_struct_phys_addr,
+			host_id, qs, 0, int_enable, vec, istk, in_order) != 0) {
+		return NULL;
+	}
 
 	/*
 	 * 2. Configure the DBS.TX_AM_DATA memory and enable the queues you plan to use;
diff --git a/drivers/net/ntnic/include/ntnic_dbs.h b/drivers/net/ntnic/include/ntnic_dbs.h
index 438f1858f5..f3b5a20739 100644
--- a/drivers/net/ntnic/include/ntnic_dbs.h
+++ b/drivers/net/ntnic/include/ntnic_dbs.h
@@ -33,6 +33,29 @@ struct nthw_dbs_tx_am_data_s {
 	uint32_t int_enable;
 };
 
+/* DBS_RX_UW_DATA */
+struct nthw_dbs_rx_uw_data_s {
+	uint64_t guest_physical_address;
+	uint32_t host_id;
+	uint32_t queue_size;
+	uint32_t packed;
+	uint32_t int_enable;
+	uint32_t vec;
+	uint32_t istk;
+};
+
+/* DBS_TX_UW_DATA */
+struct nthw_dbs_tx_uw_data_s {
+	uint64_t guest_physical_address;
+	uint32_t host_id;
+	uint32_t queue_size;
+	uint32_t packed;
+	uint32_t int_enable;
+	uint32_t vec;
+	uint32_t istk;
+	uint32_t in_order;
+};
+
 /* DBS_TX_QP_DATA */
 struct nthw_dbs_tx_qp_data_s {
 	uint32_t virtual_port;
@@ -121,6 +144,33 @@ struct nthw_dbs_s {
 	nthw_field_t *mp_fld_tx_avail_monitor_data_packed;
 	nthw_field_t *mp_fld_tx_avail_monitor_data_int;
 
+	nthw_register_t *mp_reg_rx_used_writer_control;
+	nthw_field_t *mp_fld_rx_used_writer_control_adr;
+	nthw_field_t *mp_fld_rx_used_writer_control_cnt;
+
+	nthw_register_t *mp_reg_rx_used_writer_data;
+	nthw_field_t *mp_fld_rx_used_writer_data_guest_physical_address;
+	nthw_field_t *mp_fld_rx_used_writer_data_host_id;
+	nthw_field_t *mp_fld_rx_used_writer_data_queue_size;
+	nthw_field_t *mp_fld_rx_used_writer_data_packed;
+	nthw_field_t *mp_fld_rx_used_writer_data_int;
+	nthw_field_t *mp_fld_rx_used_writer_data_vec;
+	nthw_field_t *mp_fld_rx_used_writer_data_istk;
+
+	nthw_register_t *mp_reg_tx_used_writer_control;
+	nthw_field_t *mp_fld_tx_used_writer_control_adr;
+	nthw_field_t *mp_fld_tx_used_writer_control_cnt;
+
+	nthw_register_t *mp_reg_tx_used_writer_data;
+	nthw_field_t *mp_fld_tx_used_writer_data_guest_physical_address;
+	nthw_field_t *mp_fld_tx_used_writer_data_host_id;
+	nthw_field_t *mp_fld_tx_used_writer_data_queue_size;
+	nthw_field_t *mp_fld_tx_used_writer_data_packed;
+	nthw_field_t *mp_fld_tx_used_writer_data_int;
+	nthw_field_t *mp_fld_tx_used_writer_data_vec;
+	nthw_field_t *mp_fld_tx_used_writer_data_istk;
+	nthw_field_t *mp_fld_tx_used_writer_data_in_order;
+
 	nthw_register_t *mp_reg_tx_queue_property_control;
 	nthw_field_t *mp_fld_tx_queue_property_control_adr;
 	nthw_field_t *mp_fld_tx_queue_property_control_cnt;
@@ -129,8 +179,10 @@ struct nthw_dbs_s {
 	nthw_field_t *mp_fld_tx_queue_property_data_v_port;
 
 	struct nthw_dbs_rx_am_data_s m_rx_am_shadow[NT_DBS_RX_QUEUES_MAX];
+	struct nthw_dbs_rx_uw_data_s m_rx_uw_shadow[NT_DBS_RX_QUEUES_MAX];
 
 	struct nthw_dbs_tx_am_data_s m_tx_am_shadow[NT_DBS_TX_QUEUES_MAX];
+	struct nthw_dbs_tx_uw_data_s m_tx_uw_shadow[NT_DBS_TX_QUEUES_MAX];
 	struct nthw_dbs_tx_qp_data_s m_tx_qp_shadow[NT_DBS_TX_QUEUES_MAX];
 };
 
@@ -174,6 +226,25 @@ int set_tx_am_data(nthw_dbs_t *p,
 	uint32_t host_id,
 	uint32_t packed,
 	uint32_t int_enable);
+int set_rx_uw_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t packed,
+	uint32_t int_enable,
+	uint32_t vec,
+	uint32_t istk);
+int set_tx_uw_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t packed,
+	uint32_t int_enable,
+	uint32_t vec,
+	uint32_t istk,
+	uint32_t in_order);
 int nthw_dbs_set_tx_qp_data(nthw_dbs_t *p, uint32_t index, uint32_t virtual_port);
 
 #endif	/* _NTNIC_DBS_H_ */
diff --git a/drivers/net/ntnic/nthw/dbs/nthw_dbs.c b/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
index 99a1575036..11453d8d38 100644
--- a/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
+++ b/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
@@ -11,6 +11,27 @@
 
 static void set_shadow_tx_qp_data(nthw_dbs_t *p, uint32_t index, uint32_t virtual_port);
 static void flush_tx_qp_data(nthw_dbs_t *p, uint32_t index);
+static void set_shadow_tx_uw_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t packed,
+	uint32_t int_enable,
+	uint32_t vec,
+	uint32_t istk,
+	uint32_t in_order);
+static void flush_tx_uw_data(nthw_dbs_t *p, uint32_t index);
+static void set_shadow_rx_uw_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t packed,
+	uint32_t int_enable,
+	uint32_t vec,
+	uint32_t istk);
+static void flush_rx_uw_data(nthw_dbs_t *p, uint32_t index);
 static void set_shadow_rx_am_data(nthw_dbs_t *p,
 	uint32_t index,
 	uint64_t guest_physical_address,
@@ -199,6 +220,52 @@ int dbs_init(nthw_dbs_t *p, nthw_fpga_t *p_fpga, int n_instance)
 	p->mp_fld_tx_avail_monitor_data_int =
 		nthw_register_query_field(p->mp_reg_tx_avail_monitor_data, DBS_TX_AM_DATA_INT);
 
+	p->mp_reg_rx_used_writer_control = nthw_module_get_register(p->mp_mod_dbs, DBS_RX_UW_CTRL);
+	p->mp_fld_rx_used_writer_control_adr =
+		nthw_register_get_field(p->mp_reg_rx_used_writer_control, DBS_RX_UW_CTRL_ADR);
+	p->mp_fld_rx_used_writer_control_cnt =
+		nthw_register_get_field(p->mp_reg_rx_used_writer_control, DBS_RX_UW_CTRL_CNT);
+
+	p->mp_reg_rx_used_writer_data = nthw_module_get_register(p->mp_mod_dbs, DBS_RX_UW_DATA);
+	p->mp_fld_rx_used_writer_data_guest_physical_address =
+		nthw_register_get_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_GPA);
+	p->mp_fld_rx_used_writer_data_host_id =
+		nthw_register_get_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_HID);
+	p->mp_fld_rx_used_writer_data_queue_size =
+		nthw_register_get_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_QS);
+	p->mp_fld_rx_used_writer_data_packed =
+		nthw_register_query_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_PCKED);
+	p->mp_fld_rx_used_writer_data_int =
+		nthw_register_query_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_INT);
+	p->mp_fld_rx_used_writer_data_vec =
+		nthw_register_query_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_VEC);
+	p->mp_fld_rx_used_writer_data_istk =
+		nthw_register_query_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_ISTK);
+
+	p->mp_reg_tx_used_writer_control = nthw_module_get_register(p->mp_mod_dbs, DBS_TX_UW_CTRL);
+	p->mp_fld_tx_used_writer_control_adr =
+		nthw_register_get_field(p->mp_reg_tx_used_writer_control, DBS_TX_UW_CTRL_ADR);
+	p->mp_fld_tx_used_writer_control_cnt =
+		nthw_register_get_field(p->mp_reg_tx_used_writer_control, DBS_TX_UW_CTRL_CNT);
+
+	p->mp_reg_tx_used_writer_data = nthw_module_get_register(p->mp_mod_dbs, DBS_TX_UW_DATA);
+	p->mp_fld_tx_used_writer_data_guest_physical_address =
+		nthw_register_get_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_GPA);
+	p->mp_fld_tx_used_writer_data_host_id =
+		nthw_register_get_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_HID);
+	p->mp_fld_tx_used_writer_data_queue_size =
+		nthw_register_get_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_QS);
+	p->mp_fld_tx_used_writer_data_packed =
+		nthw_register_query_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_PCKED);
+	p->mp_fld_tx_used_writer_data_int =
+		nthw_register_query_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_INT);
+	p->mp_fld_tx_used_writer_data_vec =
+		nthw_register_query_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_VEC);
+	p->mp_fld_tx_used_writer_data_istk =
+		nthw_register_query_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_ISTK);
+	p->mp_fld_tx_used_writer_data_in_order =
+		nthw_register_query_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_INO);
+
 	p->mp_reg_tx_queue_property_control =
 		nthw_module_get_register(p->mp_mod_dbs, DBS_TX_QP_CTRL);
 	p->mp_fld_tx_queue_property_control_adr =
@@ -247,6 +314,9 @@ void dbs_reset(nthw_dbs_t *p)
 	for (i = 0; i < NT_DBS_RX_QUEUES_MAX; ++i) {
 		set_shadow_rx_am_data(p, i, 0, 0, 0, 0, 0);
 		flush_rx_am_data(p, i);
+
+		set_shadow_rx_uw_data(p, i, 0, 0, 0, 0, 0, 0, 0);
+		flush_rx_uw_data(p, i);
 	}
 
 	/* Reset TX memory banks and shado */
@@ -254,6 +324,9 @@ void dbs_reset(nthw_dbs_t *p)
 		set_shadow_tx_am_data(p, i, 0, 0, 0, 0, 0);
 		flush_tx_am_data(p, i);
 
+		set_shadow_tx_uw_data(p, i, 0, 0, 0, 0, 0, 0, 0, 0);
+		flush_tx_uw_data(p, i);
+
 		set_shadow_tx_qp_data(p, i, 0);
 		flush_tx_qp_data(p, i);
 	}
@@ -491,6 +564,249 @@ int set_tx_am_data(nthw_dbs_t *p,
 	return 0;
 }
 
+static void set_rx_uw_data_index(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val32(p->mp_fld_rx_used_writer_control_adr, index);
+	nthw_field_set_val32(p->mp_fld_rx_used_writer_control_cnt, 1);
+	nthw_register_flush(p->mp_reg_rx_used_writer_control, 1);
+}
+
+static void set_shadow_rx_uw_data_guest_physical_address(nthw_dbs_t *p, uint32_t index,
+	uint64_t guest_physical_address)
+{
+	p->m_rx_uw_shadow[index].guest_physical_address = guest_physical_address;
+}
+
+static void set_shadow_rx_uw_data_host_id(nthw_dbs_t *p, uint32_t index, uint32_t host_id)
+{
+	p->m_rx_uw_shadow[index].host_id = host_id;
+}
+
+static void set_shadow_rx_uw_data_queue_size(nthw_dbs_t *p, uint32_t index, uint32_t queue_size)
+{
+	p->m_rx_uw_shadow[index].queue_size = queue_size;
+}
+
+static void set_shadow_rx_uw_data_packed(nthw_dbs_t *p, uint32_t index, uint32_t packed)
+{
+	p->m_rx_uw_shadow[index].packed = packed;
+}
+
+static void set_shadow_rx_uw_data_int_enable(nthw_dbs_t *p, uint32_t index, uint32_t int_enable)
+{
+	p->m_rx_uw_shadow[index].int_enable = int_enable;
+}
+
+static void set_shadow_rx_uw_data_vec(nthw_dbs_t *p, uint32_t index, uint32_t vec)
+{
+	p->m_rx_uw_shadow[index].vec = vec;
+}
+
+static void set_shadow_rx_uw_data_istk(nthw_dbs_t *p, uint32_t index, uint32_t istk)
+{
+	p->m_rx_uw_shadow[index].istk = istk;
+}
+
+static void set_shadow_rx_uw_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t packed,
+	uint32_t int_enable,
+	uint32_t vec,
+	uint32_t istk)
+{
+	set_shadow_rx_uw_data_guest_physical_address(p, index, guest_physical_address);
+	set_shadow_rx_uw_data_host_id(p, index, host_id);
+	set_shadow_rx_uw_data_queue_size(p, index, queue_size);
+	set_shadow_rx_uw_data_packed(p, index, packed);
+	set_shadow_rx_uw_data_int_enable(p, index, int_enable);
+	set_shadow_rx_uw_data_vec(p, index, vec);
+	set_shadow_rx_uw_data_istk(p, index, istk);
+}
+
+static void flush_rx_uw_data(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val(p->mp_fld_rx_used_writer_data_guest_physical_address,
+		(uint32_t *)&p->m_rx_uw_shadow[index].guest_physical_address, 2);
+	nthw_field_set_val32(p->mp_fld_rx_used_writer_data_host_id,
+		p->m_rx_uw_shadow[index].host_id);
+
+	if (nthw_module_is_version_newer(p->mp_mod_dbs, 0, 8)) {
+		nthw_field_set_val32(p->mp_fld_rx_used_writer_data_queue_size,
+			(1U << p->m_rx_uw_shadow[index].queue_size) - 1U);
+
+	} else {
+		nthw_field_set_val32(p->mp_fld_rx_used_writer_data_queue_size,
+			p->m_rx_uw_shadow[index].queue_size);
+	}
+
+	if (p->mp_fld_rx_used_writer_data_packed) {
+		nthw_field_set_val32(p->mp_fld_rx_used_writer_data_packed,
+			p->m_rx_uw_shadow[index].packed);
+	}
+
+	if (p->mp_fld_rx_used_writer_data_int) {
+		nthw_field_set_val32(p->mp_fld_rx_used_writer_data_int,
+			p->m_rx_uw_shadow[index].int_enable);
+		nthw_field_set_val32(p->mp_fld_rx_used_writer_data_vec,
+			p->m_rx_uw_shadow[index].vec);
+		nthw_field_set_val32(p->mp_fld_rx_used_writer_data_istk,
+			p->m_rx_uw_shadow[index].istk);
+	}
+
+	set_rx_uw_data_index(p, index);
+	nthw_register_flush(p->mp_reg_rx_used_writer_data, 1);
+}
+
+int set_rx_uw_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t packed,
+	uint32_t int_enable,
+	uint32_t vec,
+	uint32_t istk)
+{
+	if (!p->mp_reg_rx_used_writer_data)
+		return -ENOTSUP;
+
+	set_shadow_rx_uw_data(p, index, guest_physical_address, host_id, queue_size, packed,
+		int_enable, vec, istk);
+	flush_rx_uw_data(p, index);
+	return 0;
+}
+
+static void set_tx_uw_data_index(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val32(p->mp_fld_tx_used_writer_control_adr, index);
+	nthw_field_set_val32(p->mp_fld_tx_used_writer_control_cnt, 1);
+	nthw_register_flush(p->mp_reg_tx_used_writer_control, 1);
+}
+
+static void set_shadow_tx_uw_data_guest_physical_address(nthw_dbs_t *p, uint32_t index,
+	uint64_t guest_physical_address)
+{
+	p->m_tx_uw_shadow[index].guest_physical_address = guest_physical_address;
+}
+
+static void set_shadow_tx_uw_data_host_id(nthw_dbs_t *p, uint32_t index, uint32_t host_id)
+{
+	p->m_tx_uw_shadow[index].host_id = host_id;
+}
+
+static void set_shadow_tx_uw_data_queue_size(nthw_dbs_t *p, uint32_t index, uint32_t queue_size)
+{
+	p->m_tx_uw_shadow[index].queue_size = queue_size;
+}
+
+static void set_shadow_tx_uw_data_packed(nthw_dbs_t *p, uint32_t index, uint32_t packed)
+{
+	p->m_tx_uw_shadow[index].packed = packed;
+}
+
+static void set_shadow_tx_uw_data_int_enable(nthw_dbs_t *p, uint32_t index, uint32_t int_enable)
+{
+	p->m_tx_uw_shadow[index].int_enable = int_enable;
+}
+
+static void set_shadow_tx_uw_data_vec(nthw_dbs_t *p, uint32_t index, uint32_t vec)
+{
+	p->m_tx_uw_shadow[index].vec = vec;
+}
+
+static void set_shadow_tx_uw_data_istk(nthw_dbs_t *p, uint32_t index, uint32_t istk)
+{
+	p->m_tx_uw_shadow[index].istk = istk;
+}
+
+static void set_shadow_tx_uw_data_in_order(nthw_dbs_t *p, uint32_t index, uint32_t in_order)
+{
+	p->m_tx_uw_shadow[index].in_order = in_order;
+}
+
+static void set_shadow_tx_uw_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t packed,
+	uint32_t int_enable,
+	uint32_t vec,
+	uint32_t istk,
+	uint32_t in_order)
+{
+	set_shadow_tx_uw_data_guest_physical_address(p, index, guest_physical_address);
+	set_shadow_tx_uw_data_host_id(p, index, host_id);
+	set_shadow_tx_uw_data_queue_size(p, index, queue_size);
+	set_shadow_tx_uw_data_packed(p, index, packed);
+	set_shadow_tx_uw_data_int_enable(p, index, int_enable);
+	set_shadow_tx_uw_data_vec(p, index, vec);
+	set_shadow_tx_uw_data_istk(p, index, istk);
+	set_shadow_tx_uw_data_in_order(p, index, in_order);
+}
+
+static void flush_tx_uw_data(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val(p->mp_fld_tx_used_writer_data_guest_physical_address,
+		(uint32_t *)&p->m_tx_uw_shadow[index].guest_physical_address, 2);
+	nthw_field_set_val32(p->mp_fld_tx_used_writer_data_host_id,
+		p->m_tx_uw_shadow[index].host_id);
+
+	if (nthw_module_is_version_newer(p->mp_mod_dbs, 0, 8)) {
+		nthw_field_set_val32(p->mp_fld_tx_used_writer_data_queue_size,
+			(1U << p->m_tx_uw_shadow[index].queue_size) - 1U);
+
+	} else {
+		nthw_field_set_val32(p->mp_fld_tx_used_writer_data_queue_size,
+			p->m_tx_uw_shadow[index].queue_size);
+	}
+
+	if (p->mp_fld_tx_used_writer_data_packed) {
+		nthw_field_set_val32(p->mp_fld_tx_used_writer_data_packed,
+			p->m_tx_uw_shadow[index].packed);
+	}
+
+	if (p->mp_fld_tx_used_writer_data_int) {
+		nthw_field_set_val32(p->mp_fld_tx_used_writer_data_int,
+			p->m_tx_uw_shadow[index].int_enable);
+		nthw_field_set_val32(p->mp_fld_tx_used_writer_data_vec,
+			p->m_tx_uw_shadow[index].vec);
+		nthw_field_set_val32(p->mp_fld_tx_used_writer_data_istk,
+			p->m_tx_uw_shadow[index].istk);
+	}
+
+	if (p->mp_fld_tx_used_writer_data_in_order) {
+		nthw_field_set_val32(p->mp_fld_tx_used_writer_data_in_order,
+			p->m_tx_uw_shadow[index].in_order);
+	}
+
+	set_tx_uw_data_index(p, index);
+	nthw_register_flush(p->mp_reg_tx_used_writer_data, 1);
+}
+
+int set_tx_uw_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t packed,
+	uint32_t int_enable,
+	uint32_t vec,
+	uint32_t istk,
+	uint32_t in_order)
+{
+	if (!p->mp_reg_tx_used_writer_data)
+		return -ENOTSUP;
+
+	set_shadow_tx_uw_data(p, index, guest_physical_address, host_id, queue_size, packed,
+		int_enable, vec, istk, in_order);
+	flush_tx_uw_data(p, index);
+	return 0;
+}
+
 static void set_tx_qp_data_index(nthw_dbs_t *p, uint32_t index)
 {
 	nthw_field_set_val32(p->mp_fld_tx_queue_property_control_adr, index);
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h
index 00570fa8af..c6c23de0ef 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h
@@ -45,6 +45,17 @@
 #define DBS_RX_PTR_PTR (0x7f834481UL)
 #define DBS_RX_PTR_QUEUE (0x4f3fa6d1UL)
 #define DBS_RX_PTR_VALID (0xbcc5ec4dUL)
+#define DBS_RX_UW_CTRL (0x31afc0deUL)
+#define DBS_RX_UW_CTRL_ADR (0x2ee4a2c9UL)
+#define DBS_RX_UW_CTRL_CNT (0x3eec3b18UL)
+#define DBS_RX_UW_DATA (0x9e7e42c7UL)
+#define DBS_RX_UW_DATA_GPA (0x9193d52cUL)
+#define DBS_RX_UW_DATA_HID (0x71a5cf86UL)
+#define DBS_RX_UW_DATA_INT (0x22912312UL)
+#define DBS_RX_UW_DATA_ISTK (0xd469a7ddUL)
+#define DBS_RX_UW_DATA_PCKED (0xef15c665UL)
+#define DBS_RX_UW_DATA_QS (0x7d422f44UL)
+#define DBS_RX_UW_DATA_VEC (0x55cc9b53UL)
 #define DBS_STATUS (0xb5f35220UL)
 #define DBS_STATUS_OK (0xcf09a30fUL)
 #define DBS_TX_AM_CTRL (0xd6d29b9UL)
@@ -94,6 +105,18 @@
 #define DBS_TX_QP_CTRL_CNT (0x942b1855UL)
 #define DBS_TX_QP_DATA (0x7a2a262bUL)
 #define DBS_TX_QP_DATA_VPORT (0xda741d67UL)
+#define DBS_TX_UW_CTRL (0x3cb1b099UL)
+#define DBS_TX_UW_CTRL_ADR (0xd626e97fUL)
+#define DBS_TX_UW_CTRL_CNT (0xc62e70aeUL)
+#define DBS_TX_UW_DATA (0x93603280UL)
+#define DBS_TX_UW_DATA_GPA (0x69519e9aUL)
+#define DBS_TX_UW_DATA_HID (0x89678430UL)
+#define DBS_TX_UW_DATA_INO (0x5036a148UL)
+#define DBS_TX_UW_DATA_INT (0xda5368a4UL)
+#define DBS_TX_UW_DATA_ISTK (0xf693732fUL)
+#define DBS_TX_UW_DATA_PCKED (0xbc84af81UL)
+#define DBS_TX_UW_DATA_QS (0xdda7f099UL)
+#define DBS_TX_UW_DATA_VEC (0xad0ed0e5UL)
 
 #endif	/* _NTHW_FPGA_REG_DEFS_DBS_ */
 
-- 
2.45.0


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

* [PATCH v1 10/14] net/ntnic: add descriptor reader data handling functions
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (46 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 09/14] net/ntnic: used writer data handling functions Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 11/14] net/ntnic: update FPGA registeris related to DBS Serhii Iliushyk
                   ` (3 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

Added functions for setting and flushing RX and TX descriptor
reader data.

Implemented internal strcutres to update shadow structures with
guest physical address, host ID, queue size, header, and packed
status.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c |  30 +-
 drivers/net/ntnic/include/ntnic_dbs.h         |  59 ++++
 drivers/net/ntnic/nthw/dbs/nthw_dbs.c         | 267 ++++++++++++++++++
 .../nthw/supported/nthw_fpga_reg_defs_dbs.h   |  19 ++
 4 files changed, 371 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
index 1df42dad11..5232a95eaa 100644
--- a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
+++ b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
@@ -104,6 +104,8 @@ struct nthw_virt_queue {
 	 *   1: Napatech DVIO0 descriptor (12 bytes).
 	 */
 	void *avail_struct_phys_addr;
+	void *used_struct_phys_addr;
+	void *desc_struct_phys_addr;
 };
 
 static struct nthw_virt_queue rxvq[MAX_VIRT_QUEUES];
@@ -311,13 +313,21 @@ static struct nthw_virt_queue *nthw_setup_rx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 	uint32_t vq_type,
 	int irq_vector)
 {
-	(void)header;
-	(void)desc_struct_phys_addr;
 	uint32_t qs = dbs_qsize_log2(queue_size);
 	uint32_t int_enable;
 	uint32_t vec;
 	uint32_t istk;
 
+	/*
+	 * Setup DBS module - DSF00094
+	 * 3. Configure the DBS.RX_DR_DATA memory; good idea to initialize all
+	 * DBS_RX_QUEUES entries.
+	 */
+	if (set_rx_dr_data(p_nthw_dbs, index, (uint64_t)desc_struct_phys_addr, host_id, qs, header,
+			0) != 0) {
+		return NULL;
+	}
+
 	/*
 	 * 4. Configure the DBS.RX_UW_DATA memory; good idea to initialize all
 	 *   DBS_RX_QUEUES entries.
@@ -375,6 +385,8 @@ static struct nthw_virt_queue *nthw_setup_rx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 	rxvq[index].am_enable = (irq_vector < 0) ? RX_AM_ENABLE : RX_AM_DISABLE;
 	rxvq[index].host_id = host_id;
 	rxvq[index].avail_struct_phys_addr = avail_struct_phys_addr;
+	rxvq[index].used_struct_phys_addr = used_struct_phys_addr;
+	rxvq[index].desc_struct_phys_addr = desc_struct_phys_addr;
 	rxvq[index].vq_type = vq_type;
 	rxvq[index].in_order = 0;	/* not used */
 	rxvq[index].irq_vector = irq_vector;
@@ -399,13 +411,21 @@ static struct nthw_virt_queue *nthw_setup_tx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 	int irq_vector,
 	uint32_t in_order)
 {
-	(void)header;
-	(void)desc_struct_phys_addr;
 	uint32_t int_enable;
 	uint32_t vec;
 	uint32_t istk;
 	uint32_t qs = dbs_qsize_log2(queue_size);
 
+	/*
+	 * Setup DBS module - DSF00094
+	 * 3. Configure the DBS.TX_DR_DATA memory; good idea to initialize all
+	 *    DBS_TX_QUEUES entries.
+	 */
+	if (set_tx_dr_data(p_nthw_dbs, index, (uint64_t)desc_struct_phys_addr, host_id, qs, port,
+			header, 0) != 0) {
+		return NULL;
+	}
+
 	/*
 	 * 4. Configure the DBS.TX_UW_DATA memory; good idea to initialize all
 	 *    DBS_TX_QUEUES entries.
@@ -468,6 +488,8 @@ static struct nthw_virt_queue *nthw_setup_tx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 	txvq[index].port = port;
 	txvq[index].virtual_port = virtual_port;
 	txvq[index].avail_struct_phys_addr = avail_struct_phys_addr;
+	txvq[index].used_struct_phys_addr = used_struct_phys_addr;
+	txvq[index].desc_struct_phys_addr = desc_struct_phys_addr;
 	txvq[index].vq_type = vq_type;
 	txvq[index].in_order = in_order;
 	txvq[index].irq_vector = irq_vector;
diff --git a/drivers/net/ntnic/include/ntnic_dbs.h b/drivers/net/ntnic/include/ntnic_dbs.h
index f3b5a20739..64947b4d8f 100644
--- a/drivers/net/ntnic/include/ntnic_dbs.h
+++ b/drivers/net/ntnic/include/ntnic_dbs.h
@@ -56,6 +56,25 @@ struct nthw_dbs_tx_uw_data_s {
 	uint32_t in_order;
 };
 
+/* DBS_RX_DR_DATA */
+struct nthw_dbs_rx_dr_data_s {
+	uint64_t guest_physical_address;
+	uint32_t host_id;
+	uint32_t queue_size;
+	uint32_t header;
+	uint32_t packed;
+};
+
+/* DBS_TX_DR_DATA */
+struct nthw_dbs_tx_dr_data_s {
+	uint64_t guest_physical_address;
+	uint32_t host_id;
+	uint32_t queue_size;
+	uint32_t header;
+	uint32_t port;
+	uint32_t packed;
+};
+
 /* DBS_TX_QP_DATA */
 struct nthw_dbs_tx_qp_data_s {
 	uint32_t virtual_port;
@@ -171,6 +190,29 @@ struct nthw_dbs_s {
 	nthw_field_t *mp_fld_tx_used_writer_data_istk;
 	nthw_field_t *mp_fld_tx_used_writer_data_in_order;
 
+	nthw_register_t *mp_reg_rx_descriptor_reader_control;
+	nthw_field_t *mp_fld_rx_descriptor_reader_control_adr;
+	nthw_field_t *mp_fld_rx_descriptor_reader_control_cnt;
+
+	nthw_register_t *mp_reg_rx_descriptor_reader_data;
+	nthw_field_t *mp_fld_rx_descriptor_reader_data_guest_physical_address;
+	nthw_field_t *mp_fld_rx_descriptor_reader_data_host_id;
+	nthw_field_t *mp_fld_rx_descriptor_reader_data_queue_size;
+	nthw_field_t *mp_fld_rx_descriptor_reader_data_header;
+	nthw_field_t *mp_fld_rx_descriptor_reader_data_packed;
+
+	nthw_register_t *mp_reg_tx_descriptor_reader_control;
+	nthw_field_t *mp_fld_tx_descriptor_reader_control_adr;
+	nthw_field_t *mp_fld_tx_descriptor_reader_control_cnt;
+
+	nthw_register_t *mp_reg_tx_descriptor_reader_data;
+	nthw_field_t *mp_fld_tx_descriptor_reader_data_guest_physical_address;
+	nthw_field_t *mp_fld_tx_descriptor_reader_data_host_id;
+	nthw_field_t *mp_fld_tx_descriptor_reader_data_queue_size;
+	nthw_field_t *mp_fld_tx_descriptor_reader_data_port;
+	nthw_field_t *mp_fld_tx_descriptor_reader_data_header;
+	nthw_field_t *mp_fld_tx_descriptor_reader_data_packed;
+
 	nthw_register_t *mp_reg_tx_queue_property_control;
 	nthw_field_t *mp_fld_tx_queue_property_control_adr;
 	nthw_field_t *mp_fld_tx_queue_property_control_cnt;
@@ -180,9 +222,11 @@ struct nthw_dbs_s {
 
 	struct nthw_dbs_rx_am_data_s m_rx_am_shadow[NT_DBS_RX_QUEUES_MAX];
 	struct nthw_dbs_rx_uw_data_s m_rx_uw_shadow[NT_DBS_RX_QUEUES_MAX];
+	struct nthw_dbs_rx_dr_data_s m_rx_dr_shadow[NT_DBS_RX_QUEUES_MAX];
 
 	struct nthw_dbs_tx_am_data_s m_tx_am_shadow[NT_DBS_TX_QUEUES_MAX];
 	struct nthw_dbs_tx_uw_data_s m_tx_uw_shadow[NT_DBS_TX_QUEUES_MAX];
+	struct nthw_dbs_tx_dr_data_s m_tx_dr_shadow[NT_DBS_TX_QUEUES_MAX];
 	struct nthw_dbs_tx_qp_data_s m_tx_qp_shadow[NT_DBS_TX_QUEUES_MAX];
 };
 
@@ -245,6 +289,21 @@ int set_tx_uw_data(nthw_dbs_t *p,
 	uint32_t vec,
 	uint32_t istk,
 	uint32_t in_order);
+int set_rx_dr_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t header,
+	uint32_t packed);
+int set_tx_dr_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t port,
+	uint32_t header,
+	uint32_t packed);
 int nthw_dbs_set_tx_qp_data(nthw_dbs_t *p, uint32_t index, uint32_t virtual_port);
 
 #endif	/* _NTNIC_DBS_H_ */
diff --git a/drivers/net/ntnic/nthw/dbs/nthw_dbs.c b/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
index 11453d8d38..6e1c5a5af6 100644
--- a/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
+++ b/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
@@ -11,6 +11,23 @@
 
 static void set_shadow_tx_qp_data(nthw_dbs_t *p, uint32_t index, uint32_t virtual_port);
 static void flush_tx_qp_data(nthw_dbs_t *p, uint32_t index);
+static void set_shadow_tx_dr_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t port,
+	uint32_t header,
+	uint32_t packed);
+static void flush_tx_dr_data(nthw_dbs_t *p, uint32_t index);
+static void set_shadow_rx_dr_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t header,
+	uint32_t packed);
+static void flush_rx_dr_data(nthw_dbs_t *p, uint32_t index);
 static void set_shadow_tx_uw_data(nthw_dbs_t *p,
 	uint32_t index,
 	uint64_t guest_physical_address,
@@ -266,6 +283,54 @@ int dbs_init(nthw_dbs_t *p, nthw_fpga_t *p_fpga, int n_instance)
 	p->mp_fld_tx_used_writer_data_in_order =
 		nthw_register_query_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_INO);
 
+	p->mp_reg_rx_descriptor_reader_control =
+		nthw_module_get_register(p->mp_mod_dbs, DBS_RX_DR_CTRL);
+	p->mp_fld_rx_descriptor_reader_control_adr =
+		nthw_register_get_field(p->mp_reg_rx_descriptor_reader_control,
+			DBS_RX_DR_CTRL_ADR);
+	p->mp_fld_rx_descriptor_reader_control_cnt =
+		nthw_register_get_field(p->mp_reg_rx_descriptor_reader_control,
+			DBS_RX_DR_CTRL_CNT);
+
+	p->mp_reg_rx_descriptor_reader_data =
+		nthw_module_get_register(p->mp_mod_dbs, DBS_RX_DR_DATA);
+	p->mp_fld_rx_descriptor_reader_data_guest_physical_address =
+		nthw_register_get_field(p->mp_reg_rx_descriptor_reader_data, DBS_RX_DR_DATA_GPA);
+	p->mp_fld_rx_descriptor_reader_data_host_id =
+		nthw_register_get_field(p->mp_reg_rx_descriptor_reader_data, DBS_RX_DR_DATA_HID);
+	p->mp_fld_rx_descriptor_reader_data_queue_size =
+		nthw_register_get_field(p->mp_reg_rx_descriptor_reader_data, DBS_RX_DR_DATA_QS);
+	p->mp_fld_rx_descriptor_reader_data_header =
+		nthw_register_get_field(p->mp_reg_rx_descriptor_reader_data, DBS_RX_DR_DATA_HDR);
+	p->mp_fld_rx_descriptor_reader_data_packed =
+		nthw_register_query_field(p->mp_reg_rx_descriptor_reader_data,
+			DBS_RX_DR_DATA_PCKED);
+
+	p->mp_reg_tx_descriptor_reader_control =
+		nthw_module_get_register(p->mp_mod_dbs, DBS_TX_DR_CTRL);
+	p->mp_fld_tx_descriptor_reader_control_adr =
+		nthw_register_get_field(p->mp_reg_tx_descriptor_reader_control,
+			DBS_TX_DR_CTRL_ADR);
+	p->mp_fld_tx_descriptor_reader_control_cnt =
+		nthw_register_get_field(p->mp_reg_tx_descriptor_reader_control,
+			DBS_TX_DR_CTRL_CNT);
+
+	p->mp_reg_tx_descriptor_reader_data =
+		nthw_module_get_register(p->mp_mod_dbs, DBS_TX_DR_DATA);
+	p->mp_fld_tx_descriptor_reader_data_guest_physical_address =
+		nthw_register_get_field(p->mp_reg_tx_descriptor_reader_data, DBS_TX_DR_DATA_GPA);
+	p->mp_fld_tx_descriptor_reader_data_host_id =
+		nthw_register_get_field(p->mp_reg_tx_descriptor_reader_data, DBS_TX_DR_DATA_HID);
+	p->mp_fld_tx_descriptor_reader_data_queue_size =
+		nthw_register_get_field(p->mp_reg_tx_descriptor_reader_data, DBS_TX_DR_DATA_QS);
+	p->mp_fld_tx_descriptor_reader_data_header =
+		nthw_register_get_field(p->mp_reg_tx_descriptor_reader_data, DBS_TX_DR_DATA_HDR);
+	p->mp_fld_tx_descriptor_reader_data_port =
+		nthw_register_get_field(p->mp_reg_tx_descriptor_reader_data, DBS_TX_DR_DATA_PORT);
+	p->mp_fld_tx_descriptor_reader_data_packed =
+		nthw_register_query_field(p->mp_reg_tx_descriptor_reader_data,
+			DBS_TX_DR_DATA_PCKED);
+
 	p->mp_reg_tx_queue_property_control =
 		nthw_module_get_register(p->mp_mod_dbs, DBS_TX_QP_CTRL);
 	p->mp_fld_tx_queue_property_control_adr =
@@ -317,6 +382,9 @@ void dbs_reset(nthw_dbs_t *p)
 
 		set_shadow_rx_uw_data(p, i, 0, 0, 0, 0, 0, 0, 0);
 		flush_rx_uw_data(p, i);
+
+		set_shadow_rx_dr_data(p, i, 0, 0, 0, 0, 0);
+		flush_rx_dr_data(p, i);
 	}
 
 	/* Reset TX memory banks and shado */
@@ -327,6 +395,9 @@ void dbs_reset(nthw_dbs_t *p)
 		set_shadow_tx_uw_data(p, i, 0, 0, 0, 0, 0, 0, 0, 0);
 		flush_tx_uw_data(p, i);
 
+		set_shadow_tx_dr_data(p, i, 0, 0, 0, 0, 0, 0);
+		flush_tx_dr_data(p, i);
+
 		set_shadow_tx_qp_data(p, i, 0);
 		flush_tx_qp_data(p, i);
 	}
@@ -807,6 +878,202 @@ int set_tx_uw_data(nthw_dbs_t *p,
 	return 0;
 }
 
+static void set_rx_dr_data_index(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val32(p->mp_fld_rx_descriptor_reader_control_adr, index);
+	nthw_field_set_val32(p->mp_fld_rx_descriptor_reader_control_cnt, 1);
+	nthw_register_flush(p->mp_reg_rx_descriptor_reader_control, 1);
+}
+
+static void set_shadow_rx_dr_data_guest_physical_address(nthw_dbs_t *p, uint32_t index,
+	uint64_t guest_physical_address)
+{
+	p->m_rx_dr_shadow[index].guest_physical_address = guest_physical_address;
+}
+
+static void set_shadow_rx_dr_data_host_id(nthw_dbs_t *p, uint32_t index, uint32_t host_id)
+{
+	p->m_rx_dr_shadow[index].host_id = host_id;
+}
+
+static void set_shadow_rx_dr_data_queue_size(nthw_dbs_t *p, uint32_t index, uint32_t queue_size)
+{
+	p->m_rx_dr_shadow[index].queue_size = queue_size;
+}
+
+static void set_shadow_rx_dr_data_header(nthw_dbs_t *p, uint32_t index, uint32_t header)
+{
+	p->m_rx_dr_shadow[index].header = header;
+}
+
+static void set_shadow_rx_dr_data_packed(nthw_dbs_t *p, uint32_t index, uint32_t packed)
+{
+	p->m_rx_dr_shadow[index].packed = packed;
+}
+
+static void set_shadow_rx_dr_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t header,
+	uint32_t packed)
+{
+	set_shadow_rx_dr_data_guest_physical_address(p, index, guest_physical_address);
+	set_shadow_rx_dr_data_host_id(p, index, host_id);
+	set_shadow_rx_dr_data_queue_size(p, index, queue_size);
+	set_shadow_rx_dr_data_header(p, index, header);
+	set_shadow_rx_dr_data_packed(p, index, packed);
+}
+
+static void flush_rx_dr_data(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val(p->mp_fld_rx_descriptor_reader_data_guest_physical_address,
+		(uint32_t *)&p->m_rx_dr_shadow[index].guest_physical_address, 2);
+	nthw_field_set_val32(p->mp_fld_rx_descriptor_reader_data_host_id,
+		p->m_rx_dr_shadow[index].host_id);
+
+	if (nthw_module_is_version_newer(p->mp_mod_dbs, 0, 8)) {
+		nthw_field_set_val32(p->mp_fld_rx_descriptor_reader_data_queue_size,
+			(1U << p->m_rx_dr_shadow[index].queue_size) - 1U);
+
+	} else {
+		nthw_field_set_val32(p->mp_fld_rx_descriptor_reader_data_queue_size,
+			p->m_rx_dr_shadow[index].queue_size);
+	}
+
+	nthw_field_set_val32(p->mp_fld_rx_descriptor_reader_data_header,
+		p->m_rx_dr_shadow[index].header);
+
+	if (p->mp_fld_rx_descriptor_reader_data_packed) {
+		nthw_field_set_val32(p->mp_fld_rx_descriptor_reader_data_packed,
+			p->m_rx_dr_shadow[index].packed);
+	}
+
+	set_rx_dr_data_index(p, index);
+	nthw_register_flush(p->mp_reg_rx_descriptor_reader_data, 1);
+}
+
+int set_rx_dr_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t header,
+	uint32_t packed)
+{
+	if (!p->mp_reg_rx_descriptor_reader_data)
+		return -ENOTSUP;
+
+	set_shadow_rx_dr_data(p, index, guest_physical_address, host_id, queue_size, header,
+		packed);
+	flush_rx_dr_data(p, index);
+	return 0;
+}
+
+static void set_tx_dr_data_index(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val32(p->mp_fld_tx_descriptor_reader_control_adr, index);
+	nthw_field_set_val32(p->mp_fld_tx_descriptor_reader_control_cnt, 1);
+	nthw_register_flush(p->mp_reg_tx_descriptor_reader_control, 1);
+}
+
+static void set_shadow_tx_dr_data_guest_physical_address(nthw_dbs_t *p, uint32_t index,
+	uint64_t guest_physical_address)
+{
+	p->m_tx_dr_shadow[index].guest_physical_address = guest_physical_address;
+}
+
+static void set_shadow_tx_dr_data_host_id(nthw_dbs_t *p, uint32_t index, uint32_t host_id)
+{
+	p->m_tx_dr_shadow[index].host_id = host_id;
+}
+
+static void set_shadow_tx_dr_data_queue_size(nthw_dbs_t *p, uint32_t index, uint32_t queue_size)
+{
+	p->m_tx_dr_shadow[index].queue_size = queue_size;
+}
+
+static void set_shadow_tx_dr_data_header(nthw_dbs_t *p, uint32_t index, uint32_t header)
+{
+	p->m_tx_dr_shadow[index].header = header;
+}
+
+static void set_shadow_tx_dr_data_port(nthw_dbs_t *p, uint32_t index, uint32_t port)
+{
+	p->m_tx_dr_shadow[index].port = port;
+}
+
+static void set_shadow_tx_dr_data_packed(nthw_dbs_t *p, uint32_t index, uint32_t packed)
+{
+	p->m_tx_dr_shadow[index].packed = packed;
+}
+
+static void set_shadow_tx_dr_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t port,
+	uint32_t header,
+	uint32_t packed)
+{
+	set_shadow_tx_dr_data_guest_physical_address(p, index, guest_physical_address);
+	set_shadow_tx_dr_data_host_id(p, index, host_id);
+	set_shadow_tx_dr_data_queue_size(p, index, queue_size);
+	set_shadow_tx_dr_data_header(p, index, header);
+	set_shadow_tx_dr_data_port(p, index, port);
+	set_shadow_tx_dr_data_packed(p, index, packed);
+}
+
+static void flush_tx_dr_data(nthw_dbs_t *p, uint32_t index)
+{
+	nthw_field_set_val(p->mp_fld_tx_descriptor_reader_data_guest_physical_address,
+		(uint32_t *)&p->m_tx_dr_shadow[index].guest_physical_address, 2);
+	nthw_field_set_val32(p->mp_fld_tx_descriptor_reader_data_host_id,
+		p->m_tx_dr_shadow[index].host_id);
+
+	if (nthw_module_is_version_newer(p->mp_mod_dbs, 0, 8)) {
+		nthw_field_set_val32(p->mp_fld_tx_descriptor_reader_data_queue_size,
+			(1U << p->m_tx_dr_shadow[index].queue_size) - 1U);
+
+	} else {
+		nthw_field_set_val32(p->mp_fld_tx_descriptor_reader_data_queue_size,
+			p->m_tx_dr_shadow[index].queue_size);
+	}
+
+	nthw_field_set_val32(p->mp_fld_tx_descriptor_reader_data_header,
+		p->m_tx_dr_shadow[index].header);
+	nthw_field_set_val32(p->mp_fld_tx_descriptor_reader_data_port,
+		p->m_tx_dr_shadow[index].port);
+
+	if (p->mp_fld_tx_descriptor_reader_data_packed) {
+		nthw_field_set_val32(p->mp_fld_tx_descriptor_reader_data_packed,
+			p->m_tx_dr_shadow[index].packed);
+	}
+
+	set_tx_dr_data_index(p, index);
+	nthw_register_flush(p->mp_reg_tx_descriptor_reader_data, 1);
+}
+
+int set_tx_dr_data(nthw_dbs_t *p,
+	uint32_t index,
+	uint64_t guest_physical_address,
+	uint32_t host_id,
+	uint32_t queue_size,
+	uint32_t port,
+	uint32_t header,
+	uint32_t packed)
+{
+	if (!p->mp_reg_tx_descriptor_reader_data)
+		return -ENOTSUP;
+
+	set_shadow_tx_dr_data(p, index, guest_physical_address, host_id, queue_size, port, header,
+		packed);
+	flush_tx_dr_data(p, index);
+	return 0;
+}
+
 static void set_tx_qp_data_index(nthw_dbs_t *p, uint32_t index)
 {
 	nthw_field_set_val32(p->mp_fld_tx_queue_property_control_adr, index);
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h
index c6c23de0ef..0c7bbd8efd 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_reg_defs_dbs.h
@@ -30,6 +30,15 @@
 #define DBS_RX_CONTROL_QE (0x3e928d3UL)
 #define DBS_RX_CONTROL_UWE (0xb490e8dbUL)
 #define DBS_RX_CONTROL_UWS (0x40445d8aUL)
+#define DBS_RX_DR_CTRL (0xa0cbc617UL)
+#define DBS_RX_DR_CTRL_ADR (0xa7b57286UL)
+#define DBS_RX_DR_CTRL_CNT (0xb7bdeb57UL)
+#define DBS_RX_DR_DATA (0xf1a440eUL)
+#define DBS_RX_DR_DATA_GPA (0x18c20563UL)
+#define DBS_RX_DR_DATA_HDR (0xb98ed4d5UL)
+#define DBS_RX_DR_DATA_HID (0xf8f41fc9UL)
+#define DBS_RX_DR_DATA_PCKED (0x1e27ce2aUL)
+#define DBS_RX_DR_DATA_QS (0xffb980ddUL)
 #define DBS_RX_IDLE (0x93c723bfUL)
 #define DBS_RX_IDLE_BUSY (0x8e043b5bUL)
 #define DBS_RX_IDLE_IDLE (0x9dba27ccUL)
@@ -74,6 +83,16 @@
 #define DBS_TX_CONTROL_QE (0xa30cf70eUL)
 #define DBS_TX_CONTROL_UWE (0x4c52a36dUL)
 #define DBS_TX_CONTROL_UWS (0xb886163cUL)
+#define DBS_TX_DR_CTRL (0xadd5b650UL)
+#define DBS_TX_DR_CTRL_ADR (0x5f773930UL)
+#define DBS_TX_DR_CTRL_CNT (0x4f7fa0e1UL)
+#define DBS_TX_DR_DATA (0x2043449UL)
+#define DBS_TX_DR_DATA_GPA (0xe0004ed5UL)
+#define DBS_TX_DR_DATA_HDR (0x414c9f63UL)
+#define DBS_TX_DR_DATA_HID (0x36547fUL)
+#define DBS_TX_DR_DATA_PCKED (0x4db6a7ceUL)
+#define DBS_TX_DR_DATA_PORT (0xf306968cUL)
+#define DBS_TX_DR_DATA_QS (0x5f5c5f00UL)
 #define DBS_TX_IDLE (0xf0171685UL)
 #define DBS_TX_IDLE_BUSY (0x61399ebbUL)
 #define DBS_TX_IDLE_IDLE (0x7287822cUL)
-- 
2.45.0


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

* [PATCH v1 11/14] net/ntnic: update FPGA registeris related to DBS
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (47 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 10/14] net/ntnic: add descriptor reader " Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 12/14] net/ntnic: virtqueue setup managed packed-ring was added Serhii Iliushyk
                   ` (2 subsequent siblings)
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev; +Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit

DBS - DVIO Buffer System

Signed-off-by: Serhii Iliushyk <sil-plv@napatech.com>
---
 .../supported/nthw_fpga_9563_055_049_0000.c   | 184 +++++++++++++++++-
 1 file changed, 183 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
index 98b857158e..6df7208649 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
@@ -1541,10 +1541,192 @@ static nthw_fpga_register_init_s rst9563_registers[] = {
 	{ RST9563_STICKY, 3, 6, NTHW_FPGA_REG_TYPE_RC1, 0, 6, rst9563_sticky_fields },
 };
 
+static nthw_fpga_field_init_s dbs_rx_am_ctrl_fields[] = {
+	{ DBS_RX_AM_CTRL_ADR, 7, 0, 0x0000 },
+	{ DBS_RX_AM_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_rx_am_data_fields[] = {
+	{ DBS_RX_AM_DATA_ENABLE, 1, 72, 0x0000 }, { DBS_RX_AM_DATA_GPA, 64, 0, 0x0000 },
+	{ DBS_RX_AM_DATA_HID, 8, 64, 0x0000 }, { DBS_RX_AM_DATA_INT, 1, 74, 0x0000 },
+	{ DBS_RX_AM_DATA_PCKED, 1, 73, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_rx_control_fields[] = {
+	{ DBS_RX_CONTROL_AME, 1, 7, 0 }, { DBS_RX_CONTROL_AMS, 4, 8, 8 },
+	{ DBS_RX_CONTROL_LQ, 7, 0, 0 }, { DBS_RX_CONTROL_QE, 1, 17, 0 },
+	{ DBS_RX_CONTROL_UWE, 1, 12, 0 }, { DBS_RX_CONTROL_UWS, 4, 13, 5 },
+};
+
+static nthw_fpga_field_init_s dbs_rx_dr_ctrl_fields[] = {
+	{ DBS_RX_DR_CTRL_ADR, 7, 0, 0x0000 },
+	{ DBS_RX_DR_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_rx_dr_data_fields[] = {
+	{ DBS_RX_DR_DATA_GPA, 64, 0, 0x0000 }, { DBS_RX_DR_DATA_HDR, 1, 88, 0x0000 },
+	{ DBS_RX_DR_DATA_HID, 8, 64, 0x0000 }, { DBS_RX_DR_DATA_PCKED, 1, 87, 0x0000 },
+	{ DBS_RX_DR_DATA_QS, 15, 72, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_rx_idle_fields[] = {
+	{ DBS_RX_IDLE_BUSY, 1, 8, 0 },
+	{ DBS_RX_IDLE_IDLE, 1, 0, 0x0000 },
+	{ DBS_RX_IDLE_QUEUE, 7, 1, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_rx_init_fields[] = {
+	{ DBS_RX_INIT_BUSY, 1, 8, 0 },
+	{ DBS_RX_INIT_INIT, 1, 0, 0x0000 },
+	{ DBS_RX_INIT_QUEUE, 7, 1, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_rx_init_val_fields[] = {
+	{ DBS_RX_INIT_VAL_IDX, 16, 0, 0x0000 },
+	{ DBS_RX_INIT_VAL_PTR, 15, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_rx_ptr_fields[] = {
+	{ DBS_RX_PTR_PTR, 16, 0, 0x0000 },
+	{ DBS_RX_PTR_QUEUE, 7, 16, 0x0000 },
+	{ DBS_RX_PTR_VALID, 1, 23, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_rx_uw_ctrl_fields[] = {
+	{ DBS_RX_UW_CTRL_ADR, 7, 0, 0x0000 },
+	{ DBS_RX_UW_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_rx_uw_data_fields[] = {
+	{ DBS_RX_UW_DATA_GPA, 64, 0, 0x0000 }, { DBS_RX_UW_DATA_HID, 8, 64, 0x0000 },
+	{ DBS_RX_UW_DATA_INT, 1, 88, 0x0000 }, { DBS_RX_UW_DATA_ISTK, 1, 92, 0x0000 },
+	{ DBS_RX_UW_DATA_PCKED, 1, 87, 0x0000 }, { DBS_RX_UW_DATA_QS, 15, 72, 0x0000 },
+	{ DBS_RX_UW_DATA_VEC, 3, 89, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_am_ctrl_fields[] = {
+	{ DBS_TX_AM_CTRL_ADR, 7, 0, 0x0000 },
+	{ DBS_TX_AM_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_am_data_fields[] = {
+	{ DBS_TX_AM_DATA_ENABLE, 1, 72, 0x0000 }, { DBS_TX_AM_DATA_GPA, 64, 0, 0x0000 },
+	{ DBS_TX_AM_DATA_HID, 8, 64, 0x0000 }, { DBS_TX_AM_DATA_INT, 1, 74, 0x0000 },
+	{ DBS_TX_AM_DATA_PCKED, 1, 73, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_control_fields[] = {
+	{ DBS_TX_CONTROL_AME, 1, 7, 0 }, { DBS_TX_CONTROL_AMS, 4, 8, 5 },
+	{ DBS_TX_CONTROL_LQ, 7, 0, 0 }, { DBS_TX_CONTROL_QE, 1, 17, 0 },
+	{ DBS_TX_CONTROL_UWE, 1, 12, 0 }, { DBS_TX_CONTROL_UWS, 4, 13, 8 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_dr_ctrl_fields[] = {
+	{ DBS_TX_DR_CTRL_ADR, 7, 0, 0x0000 },
+	{ DBS_TX_DR_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_dr_data_fields[] = {
+	{ DBS_TX_DR_DATA_GPA, 64, 0, 0x0000 }, { DBS_TX_DR_DATA_HDR, 1, 88, 0x0000 },
+	{ DBS_TX_DR_DATA_HID, 8, 64, 0x0000 }, { DBS_TX_DR_DATA_PCKED, 1, 87, 0x0000 },
+	{ DBS_TX_DR_DATA_PORT, 1, 89, 0x0000 }, { DBS_TX_DR_DATA_QS, 15, 72, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_idle_fields[] = {
+	{ DBS_TX_IDLE_BUSY, 1, 8, 0 },
+	{ DBS_TX_IDLE_IDLE, 1, 0, 0x0000 },
+	{ DBS_TX_IDLE_QUEUE, 7, 1, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_init_fields[] = {
+	{ DBS_TX_INIT_BUSY, 1, 8, 0 },
+	{ DBS_TX_INIT_INIT, 1, 0, 0x0000 },
+	{ DBS_TX_INIT_QUEUE, 7, 1, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_init_val_fields[] = {
+	{ DBS_TX_INIT_VAL_IDX, 16, 0, 0x0000 },
+	{ DBS_TX_INIT_VAL_PTR, 15, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_ptr_fields[] = {
+	{ DBS_TX_PTR_PTR, 16, 0, 0x0000 },
+	{ DBS_TX_PTR_QUEUE, 7, 16, 0x0000 },
+	{ DBS_TX_PTR_VALID, 1, 23, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_qos_ctrl_fields[] = {
+	{ DBS_TX_QOS_CTRL_ADR, 1, 0, 0x0000 },
+	{ DBS_TX_QOS_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_qos_data_fields[] = {
+	{ DBS_TX_QOS_DATA_BS, 27, 17, 0x0000 },
+	{ DBS_TX_QOS_DATA_EN, 1, 0, 0x0000 },
+	{ DBS_TX_QOS_DATA_IR, 16, 1, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_qos_rate_fields[] = {
+	{ DBS_TX_QOS_RATE_DIV, 19, 16, 2 },
+	{ DBS_TX_QOS_RATE_MUL, 16, 0, 1 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_qp_ctrl_fields[] = {
+	{ DBS_TX_QP_CTRL_ADR, 7, 0, 0x0000 },
+	{ DBS_TX_QP_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_qp_data_fields[] = {
+	{ DBS_TX_QP_DATA_VPORT, 1, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_uw_ctrl_fields[] = {
+	{ DBS_TX_UW_CTRL_ADR, 7, 0, 0x0000 },
+	{ DBS_TX_UW_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s dbs_tx_uw_data_fields[] = {
+	{ DBS_TX_UW_DATA_GPA, 64, 0, 0x0000 }, { DBS_TX_UW_DATA_HID, 8, 64, 0x0000 },
+	{ DBS_TX_UW_DATA_INO, 1, 93, 0x0000 }, { DBS_TX_UW_DATA_INT, 1, 88, 0x0000 },
+	{ DBS_TX_UW_DATA_ISTK, 1, 92, 0x0000 }, { DBS_TX_UW_DATA_PCKED, 1, 87, 0x0000 },
+	{ DBS_TX_UW_DATA_QS, 15, 72, 0x0000 }, { DBS_TX_UW_DATA_VEC, 3, 89, 0x0000 },
+};
+
+static nthw_fpga_register_init_s dbs_registers[] = {
+	{ DBS_RX_AM_CTRL, 10, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, dbs_rx_am_ctrl_fields },
+	{ DBS_RX_AM_DATA, 11, 75, NTHW_FPGA_REG_TYPE_WO, 0, 5, dbs_rx_am_data_fields },
+	{ DBS_RX_CONTROL, 0, 18, NTHW_FPGA_REG_TYPE_RW, 43008, 6, dbs_rx_control_fields },
+	{ DBS_RX_DR_CTRL, 18, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, dbs_rx_dr_ctrl_fields },
+	{ DBS_RX_DR_DATA, 19, 89, NTHW_FPGA_REG_TYPE_WO, 0, 5, dbs_rx_dr_data_fields },
+	{ DBS_RX_IDLE, 8, 9, NTHW_FPGA_REG_TYPE_MIXED, 0, 3, dbs_rx_idle_fields },
+	{ DBS_RX_INIT, 2, 9, NTHW_FPGA_REG_TYPE_MIXED, 0, 3, dbs_rx_init_fields },
+	{ DBS_RX_INIT_VAL, 3, 31, NTHW_FPGA_REG_TYPE_WO, 0, 2, dbs_rx_init_val_fields },
+	{ DBS_RX_PTR, 4, 24, NTHW_FPGA_REG_TYPE_MIXED, 0, 3, dbs_rx_ptr_fields },
+	{ DBS_RX_UW_CTRL, 14, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, dbs_rx_uw_ctrl_fields },
+	{ DBS_RX_UW_DATA, 15, 93, NTHW_FPGA_REG_TYPE_WO, 0, 7, dbs_rx_uw_data_fields },
+	{ DBS_TX_AM_CTRL, 12, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, dbs_tx_am_ctrl_fields },
+	{ DBS_TX_AM_DATA, 13, 75, NTHW_FPGA_REG_TYPE_WO, 0, 5, dbs_tx_am_data_fields },
+	{ DBS_TX_CONTROL, 1, 18, NTHW_FPGA_REG_TYPE_RW, 66816, 6, dbs_tx_control_fields },
+	{ DBS_TX_DR_CTRL, 20, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, dbs_tx_dr_ctrl_fields },
+	{ DBS_TX_DR_DATA, 21, 90, NTHW_FPGA_REG_TYPE_WO, 0, 6, dbs_tx_dr_data_fields },
+	{ DBS_TX_IDLE, 9, 9, NTHW_FPGA_REG_TYPE_MIXED, 0, 3, dbs_tx_idle_fields },
+	{ DBS_TX_INIT, 5, 9, NTHW_FPGA_REG_TYPE_MIXED, 0, 3, dbs_tx_init_fields },
+	{ DBS_TX_INIT_VAL, 6, 31, NTHW_FPGA_REG_TYPE_WO, 0, 2, dbs_tx_init_val_fields },
+	{ DBS_TX_PTR, 7, 24, NTHW_FPGA_REG_TYPE_MIXED, 0, 3, dbs_tx_ptr_fields },
+	{ DBS_TX_QOS_CTRL, 24, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, dbs_tx_qos_ctrl_fields },
+	{ DBS_TX_QOS_DATA, 25, 44, NTHW_FPGA_REG_TYPE_WO, 0, 3, dbs_tx_qos_data_fields },
+	{ DBS_TX_QOS_RATE, 26, 35, NTHW_FPGA_REG_TYPE_RW, 131073, 2, dbs_tx_qos_rate_fields },
+	{ DBS_TX_QP_CTRL, 22, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, dbs_tx_qp_ctrl_fields },
+	{ DBS_TX_QP_DATA, 23, 1, NTHW_FPGA_REG_TYPE_WO, 0, 1, dbs_tx_qp_data_fields },
+	{ DBS_TX_UW_CTRL, 16, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, dbs_tx_uw_ctrl_fields },
+	{ DBS_TX_UW_DATA, 17, 94, NTHW_FPGA_REG_TYPE_WO, 0, 8, dbs_tx_uw_data_fields },
+};
+
 static nthw_fpga_module_init_s fpga_modules[] = {
 	{ MOD_CAT, 0, MOD_CAT, 0, 21, NTHW_FPGA_BUS_TYPE_RAB1, 768, 34, cat_registers },
 	{ MOD_GFG, 0, MOD_GFG, 1, 1, NTHW_FPGA_BUS_TYPE_RAB2, 8704, 10, gfg_registers },
 	{ MOD_GMF, 0, MOD_GMF, 2, 5, NTHW_FPGA_BUS_TYPE_RAB2, 9216, 12, gmf_registers },
+	{ MOD_DBS, 0, MOD_DBS, 0, 11, NTHW_FPGA_BUS_TYPE_RAB2, 12832, 27, dbs_registers},
 	{ MOD_GMF, 1, MOD_GMF, 2, 5, NTHW_FPGA_BUS_TYPE_RAB2, 9728, 12, gmf_registers },
 	{
 		MOD_GPIO_PHY, 0, MOD_GPIO_PHY, 1, 0, NTHW_FPGA_BUS_TYPE_RAB0, 16386, 2,
@@ -1737,5 +1919,5 @@ static nthw_fpga_prod_param_s product_parameters[] = {
 };
 
 nthw_fpga_prod_init_s nthw_fpga_9563_055_049_0000 = {
-	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 21, fpga_modules,
+	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 22, fpga_modules,
 };
-- 
2.45.0


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

* [PATCH v1 12/14] net/ntnic: virtqueue setup managed packed-ring was added
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (48 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 11/14] net/ntnic: update FPGA registeris related to DBS Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 13/14] net/ntnic: add functions for releasing virt queues Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 14/14] net/ntnic: add functions for retrieving and managing packets Serhii Iliushyk
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

Structures were enhanced with PACKED virtqueue fields.
Managed function was extended with packed ring configuration and
initialization support.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c | 191 +++++++++++++++++-
 drivers/net/ntnic/include/ntnic_virt_queue.h  |  27 +++
 2 files changed, 208 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
index 5232a95eaa..46b4c4415c 100644
--- a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
+++ b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
@@ -69,16 +69,33 @@ enum nthw_virt_queue_usage {
 
 struct nthw_virt_queue {
 	/* Pointers to virt-queue structs */
-	struct {
-		/* SPLIT virtqueue */
-		struct virtq_avail *p_avail;
-		struct virtq_used *p_used;
-		struct virtq_desc *p_desc;
-		/* Control variables for virt-queue structs */
-		uint16_t am_idx;
-		uint16_t used_idx;
-		uint16_t cached_idx;
-		uint16_t tx_descr_avail_idx;
+	union {
+		struct {
+			/* SPLIT virtqueue */
+			struct virtq_avail *p_avail;
+			struct virtq_used *p_used;
+			struct virtq_desc *p_desc;
+			/* Control variables for virt-queue structs */
+			uint16_t am_idx;
+			uint16_t used_idx;
+			uint16_t cached_idx;
+			uint16_t tx_descr_avail_idx;
+		};
+		struct {
+			/* PACKED virtqueue */
+			struct pvirtq_event_suppress *driver_event;
+			struct pvirtq_event_suppress *device_event;
+			struct pvirtq_desc *desc;
+			/*
+			 * when in-order release used Tx packets from FPGA it may collapse
+			 * into a batch. When getting new Tx buffers we may only need
+			 * partial
+			 */
+			uint16_t next_avail;
+			uint16_t next_used;
+			uint16_t avail_wrap_count;
+			uint16_t used_wrap_count;
+		};
 	};
 
 	/* Array with packet buffers */
@@ -108,6 +125,11 @@ struct nthw_virt_queue {
 	void *desc_struct_phys_addr;
 };
 
+struct pvirtq_struct_layout_s {
+	size_t driver_event_offset;
+	size_t device_event_offset;
+};
+
 static struct nthw_virt_queue rxvq[MAX_VIRT_QUEUES];
 static struct nthw_virt_queue txvq[MAX_VIRT_QUEUES];
 
@@ -606,6 +628,143 @@ nthw_setup_mngd_tx_virt_queue_split(nthw_dbs_t *p_nthw_dbs,
 	return &txvq[index];
 }
 
+/*
+ * Packed Ring
+ */
+static int nthw_setup_managed_virt_queue_packed(struct nthw_virt_queue *vq,
+	struct pvirtq_struct_layout_s *pvirtq_layout,
+	struct nthw_memory_descriptor *p_virt_struct_area,
+	struct nthw_memory_descriptor *p_packet_buffers,
+	uint16_t flags,
+	int rx)
+{
+	/* page aligned */
+	assert(((uintptr_t)p_virt_struct_area->phys_addr & 0xfff) == 0);
+	assert(p_packet_buffers);
+
+	/* clean canvas */
+	memset(p_virt_struct_area->virt_addr, 0,
+		sizeof(struct pvirtq_desc) * vq->queue_size +
+		sizeof(struct pvirtq_event_suppress) * 2 + sizeof(int) * vq->queue_size);
+
+	pvirtq_layout->device_event_offset = sizeof(struct pvirtq_desc) * vq->queue_size;
+	pvirtq_layout->driver_event_offset =
+		pvirtq_layout->device_event_offset + sizeof(struct pvirtq_event_suppress);
+
+	vq->desc = p_virt_struct_area->virt_addr;
+	vq->device_event = (void *)((uintptr_t)vq->desc + pvirtq_layout->device_event_offset);
+	vq->driver_event = (void *)((uintptr_t)vq->desc + pvirtq_layout->driver_event_offset);
+
+	vq->next_avail = 0;
+	vq->next_used = 0;
+	vq->avail_wrap_count = 1;
+	vq->used_wrap_count = 1;
+
+	/*
+	 * Only possible if FPGA always delivers in-order
+	 * Buffer ID used is the index in the p_packet_buffers array
+	 */
+	unsigned int i;
+	struct pvirtq_desc *p_desc = vq->desc;
+
+	for (i = 0; i < vq->queue_size; i++) {
+		if (rx) {
+			p_desc[i].addr = (uint64_t)p_packet_buffers[i].phys_addr;
+			p_desc[i].len = p_packet_buffers[i].len;
+		}
+
+		p_desc[i].id = i;
+		p_desc[i].flags = flags;
+	}
+
+	if (rx)
+		vq->avail_wrap_count ^= 1;	/* filled up available buffers for Rx */
+	else
+		vq->used_wrap_count ^= 1;	/* pre-fill free buffer IDs */
+
+	if (vq->queue_size == 0)
+		return -1;	/* don't allocate memory with size of 0 bytes */
+
+	vq->p_virtual_addr = malloc(vq->queue_size * sizeof(*p_packet_buffers));
+
+	if (vq->p_virtual_addr == NULL)
+		return -1;
+
+	memcpy(vq->p_virtual_addr, p_packet_buffers, vq->queue_size * sizeof(*p_packet_buffers));
+
+	/* Not used yet by FPGA - make sure we disable */
+	vq->device_event->flags = RING_EVENT_FLAGS_DISABLE;
+
+	return 0;
+}
+
+static struct nthw_virt_queue *
+nthw_setup_managed_rx_virt_queue_packed(nthw_dbs_t *p_nthw_dbs,
+	uint32_t index,
+	uint32_t queue_size,
+	uint32_t host_id,
+	uint32_t header,
+	struct nthw_memory_descriptor *p_virt_struct_area,
+	struct nthw_memory_descriptor *p_packet_buffers,
+	int irq_vector)
+{
+	struct pvirtq_struct_layout_s pvirtq_layout;
+	struct nthw_virt_queue *vq = &rxvq[index];
+	/* Set size and setup packed vq ring */
+	vq->queue_size = queue_size;
+
+	/* Use Avail flag bit == 1 because wrap bit is initially set to 1 - and Used is inverse */
+	if (nthw_setup_managed_virt_queue_packed(vq, &pvirtq_layout, p_virt_struct_area,
+			p_packet_buffers,
+			VIRTQ_DESC_F_WRITE | VIRTQ_DESC_F_AVAIL, 1) != 0)
+		return NULL;
+
+	nthw_setup_rx_virt_queue(p_nthw_dbs, index, 0x8000, 0,	/* start wrap ring counter as 1 */
+		(void *)((uintptr_t)p_virt_struct_area->phys_addr +
+			pvirtq_layout.driver_event_offset),
+		(void *)((uintptr_t)p_virt_struct_area->phys_addr +
+			pvirtq_layout.device_event_offset),
+		p_virt_struct_area->phys_addr, (uint16_t)queue_size, host_id,
+		header, PACKED_RING, irq_vector);
+
+	vq->usage = NTHW_VIRTQ_MANAGED;
+	return vq;
+}
+
+static struct nthw_virt_queue *
+nthw_setup_managed_tx_virt_queue_packed(nthw_dbs_t *p_nthw_dbs,
+	uint32_t index,
+	uint32_t queue_size,
+	uint32_t host_id,
+	uint32_t port,
+	uint32_t virtual_port,
+	uint32_t header,
+	int irq_vector,
+	uint32_t in_order,
+	struct nthw_memory_descriptor *p_virt_struct_area,
+	struct nthw_memory_descriptor *p_packet_buffers)
+{
+	struct pvirtq_struct_layout_s pvirtq_layout;
+	struct nthw_virt_queue *vq = &txvq[index];
+	/* Set size and setup packed vq ring */
+	vq->queue_size = queue_size;
+
+	if (nthw_setup_managed_virt_queue_packed(vq, &pvirtq_layout, p_virt_struct_area,
+			p_packet_buffers, 0, 0) != 0)
+		return NULL;
+
+	nthw_setup_tx_virt_queue(p_nthw_dbs, index, 0x8000, 0,	/* start wrap ring counter as 1 */
+		(void *)((uintptr_t)p_virt_struct_area->phys_addr +
+			pvirtq_layout.driver_event_offset),
+		(void *)((uintptr_t)p_virt_struct_area->phys_addr +
+			pvirtq_layout.device_event_offset),
+		p_virt_struct_area->phys_addr, (uint16_t)queue_size, host_id,
+		port, virtual_port, header, PACKED_RING, irq_vector, in_order);
+
+	vq->usage = NTHW_VIRTQ_MANAGED;
+	return vq;
+}
+
 /*
  * Create a Managed Rx Virt Queue
  *
@@ -630,6 +789,11 @@ nthw_setup_mngd_rx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 				host_id, header, p_virt_struct_area,
 				p_packet_buffers, irq_vector);
 
+	case PACKED_RING:
+		return nthw_setup_managed_rx_virt_queue_packed(p_nthw_dbs, index, queue_size,
+				host_id, header, p_virt_struct_area,
+				p_packet_buffers, irq_vector);
+
 	default:
 		break;
 	}
@@ -666,6 +830,13 @@ nthw_setup_mngd_tx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 				p_virt_struct_area,
 				p_packet_buffers);
 
+	case PACKED_RING:
+		return nthw_setup_managed_tx_virt_queue_packed(p_nthw_dbs, index, queue_size,
+				host_id, port, virtual_port, header,
+				irq_vector, in_order,
+				p_virt_struct_area,
+				p_packet_buffers);
+
 	default:
 		break;
 	}
diff --git a/drivers/net/ntnic/include/ntnic_virt_queue.h b/drivers/net/ntnic/include/ntnic_virt_queue.h
index 97cb474dc8..d4c9a9835a 100644
--- a/drivers/net/ntnic/include/ntnic_virt_queue.h
+++ b/drivers/net/ntnic/include/ntnic_virt_queue.h
@@ -45,6 +45,9 @@ struct __rte_aligned(8) virtq_desc {
 	uint16_t next;
 };
 
+/* additional packed ring flags */
+#define VIRTQ_DESC_F_AVAIL     (1 << 7)
+
 /* descr phys address must be 16 byte aligned */
 struct __rte_aligned(16) pvirtq_desc {
 	/* Buffer Address. */
@@ -57,6 +60,30 @@ struct __rte_aligned(16) pvirtq_desc {
 	uint16_t flags;
 };
 
+/* Disable events */
+#define RING_EVENT_FLAGS_DISABLE 0x1
+
+struct __rte_aligned(16) pvirtq_event_suppress {
+	union {
+		struct {
+			/* Descriptor Ring Change Event Offset */
+			uint16_t desc_event_off : 15;
+			/* Descriptor Ring Change Event Wrap Counter */
+			uint16_t desc_event_wrap : 1;
+		};
+		/* If desc_event_flags set to RING_EVENT_FLAGS_DESC */
+		uint16_t desc;
+	};
+
+	union {
+		struct {
+			uint16_t desc_event_flags : 2;	/* Descriptor Ring Change Event Flags */
+			uint16_t reserved : 14;	/* Reserved, set to 0 */
+		};
+		uint16_t flags;
+	};
+};
+
 /*
  * Common virtq descr
  */
-- 
2.45.0


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

* [PATCH v1 13/14] net/ntnic: add functions for releasing virt queues
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (49 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 12/14] net/ntnic: virtqueue setup managed packed-ring was added Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  2024-10-04 15:07 ` [PATCH v1 14/14] net/ntnic: add functions for retrieving and managing packets Serhii Iliushyk
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

Implemented handler busy states and shutdowns of hardware queues.

Added functionality for releasing RX and TX virtual queue resources,
managed and releasing packets back into the availability ring.

Updated sg_ops structure to include new queue management functions.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c | 353 ++++++++++++++++++
 drivers/net/ntnic/include/ntnic_dbs.h         |   4 +
 drivers/net/ntnic/include/ntnic_virt_queue.h  |   6 +
 drivers/net/ntnic/nthw/dbs/nthw_dbs.c         |  45 +++
 4 files changed, 408 insertions(+)

diff --git a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
index 46b4c4415c..6d7862791d 100644
--- a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
+++ b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
@@ -6,6 +6,7 @@
 #include <unistd.h>
 
 #include "ntos_drv.h"
+#include "nt_util.h"
 #include "ntnic_virt_queue.h"
 #include "ntnic_mod_reg.h"
 #include "ntlog.h"
@@ -37,6 +38,26 @@
 
 #define VIRTQ_AVAIL_F_NO_INTERRUPT 1
 
+#define vq_log_arg(vq, format, ...)
+
+/*
+ * Packed Ring helper macros
+ */
+#define PACKED(vq_type) ((vq_type) == PACKED_RING ? 1 : 0)
+
+#define avail_flag(vq) ((vq)->avail_wrap_count ? VIRTQ_DESC_F_AVAIL : 0)
+#define used_flag_inv(vq) ((vq)->avail_wrap_count ? 0 : VIRTQ_DESC_F_USED)
+
+#define inc_avail(vq, num)                                                                        \
+	do {                                                                                      \
+		struct nthw_virt_queue *temp_vq = (vq);                                           \
+		temp_vq->next_avail += (num);                                                     \
+		if (temp_vq->next_avail >= temp_vq->queue_size) {                                 \
+			temp_vq->next_avail -= temp_vq->queue_size;                               \
+			temp_vq->avail_wrap_count ^= 1;                                           \
+		}                                                                                 \
+	} while (0)
+
 struct __rte_aligned(8) virtq_avail {
 	uint16_t flags;
 	uint16_t idx;
@@ -115,6 +136,7 @@ struct nthw_virt_queue {
 	uint32_t host_id;
 	uint32_t port;	/* Only used by TX queues */
 	uint32_t virtual_port;	/* Only used by TX queues */
+	uint32_t header;
 	/*
 	 * Only used by TX queues:
 	 *   0: VirtIO-Net header (12 bytes).
@@ -417,6 +439,237 @@ static struct nthw_virt_queue *nthw_setup_rx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 	return &rxvq[index];
 }
 
+static int dbs_wait_hw_queue_shutdown(struct nthw_virt_queue *vq, int rx);
+
+static int dbs_wait_on_busy(struct nthw_virt_queue *vq, uint32_t *idle, int rx)
+{
+	uint32_t busy;
+	uint32_t queue;
+	int err = 0;
+	nthw_dbs_t *p_nthw_dbs = vq->mp_nthw_dbs;
+
+	do {
+		if (rx)
+			err = get_rx_idle(p_nthw_dbs, idle, &queue, &busy);
+
+		else
+			err = get_tx_idle(p_nthw_dbs, idle, &queue, &busy);
+	} while (!err && busy);
+
+	return err;
+}
+
+static int dbs_wait_hw_queue_shutdown(struct nthw_virt_queue *vq, int rx)
+{
+	int err = 0;
+	uint32_t idle = 0;
+	nthw_dbs_t *p_nthw_dbs = vq->mp_nthw_dbs;
+
+	err = dbs_wait_on_busy(vq, &idle, rx);
+
+	if (err) {
+		if (err == -ENOTSUP) {
+			nt_os_wait_usec(200000);
+			return 0;
+		}
+
+		return -1;
+	}
+
+	do {
+		if (rx)
+			err = set_rx_idle(p_nthw_dbs, 1, vq->index);
+
+		else
+			err = set_tx_idle(p_nthw_dbs, 1, vq->index);
+
+		if (err)
+			return -1;
+
+		if (dbs_wait_on_busy(vq, &idle, rx) != 0)
+			return -1;
+
+	} while (idle == 0);
+
+	return 0;
+}
+
+static int dbs_internal_release_rx_virt_queue(struct nthw_virt_queue *rxvq)
+{
+	nthw_dbs_t *p_nthw_dbs = rxvq->mp_nthw_dbs;
+
+	if (rxvq == NULL)
+		return -1;
+
+	/* Clear UW */
+	rxvq->used_struct_phys_addr = NULL;
+
+	if (set_rx_uw_data(p_nthw_dbs, rxvq->index, (uint64_t)rxvq->used_struct_phys_addr,
+			rxvq->host_id, 0, PACKED(rxvq->vq_type), 0, 0, 0) != 0) {
+		return -1;
+	}
+
+	/* Disable AM */
+	rxvq->am_enable = RX_AM_DISABLE;
+
+	if (set_rx_am_data(p_nthw_dbs,
+			rxvq->index,
+			(uint64_t)rxvq->avail_struct_phys_addr,
+			rxvq->am_enable,
+			rxvq->host_id,
+			PACKED(rxvq->vq_type),
+			0) != 0) {
+		return -1;
+	}
+
+	/* Let the FPGA finish packet processing */
+	if (dbs_wait_hw_queue_shutdown(rxvq, 1) != 0)
+		return -1;
+
+	/* Clear rest of AM */
+	rxvq->avail_struct_phys_addr = NULL;
+	rxvq->host_id = 0;
+
+	if (set_rx_am_data(p_nthw_dbs,
+			rxvq->index,
+			(uint64_t)rxvq->avail_struct_phys_addr,
+			rxvq->am_enable,
+			rxvq->host_id,
+			PACKED(rxvq->vq_type),
+			0) != 0)
+		return -1;
+
+	/* Clear DR */
+	rxvq->desc_struct_phys_addr = NULL;
+
+	if (set_rx_dr_data(p_nthw_dbs,
+			rxvq->index,
+			(uint64_t)rxvq->desc_struct_phys_addr,
+			rxvq->host_id,
+			0,
+			rxvq->header,
+			PACKED(rxvq->vq_type)) != 0)
+		return -1;
+
+	/* Initialize queue */
+	dbs_init_rx_queue(p_nthw_dbs, rxvq->index, 0, 0);
+
+	/* Reset queue state */
+	rxvq->usage = NTHW_VIRTQ_UNUSED;
+	rxvq->mp_nthw_dbs = p_nthw_dbs;
+	rxvq->index = 0;
+	rxvq->queue_size = 0;
+
+	return 0;
+}
+
+static int nthw_release_mngd_rx_virt_queue(struct nthw_virt_queue *rxvq)
+{
+	if (rxvq == NULL || rxvq->usage != NTHW_VIRTQ_MANAGED)
+		return -1;
+
+	if (rxvq->p_virtual_addr) {
+		free(rxvq->p_virtual_addr);
+		rxvq->p_virtual_addr = NULL;
+	}
+
+	return dbs_internal_release_rx_virt_queue(rxvq);
+}
+
+static int dbs_internal_release_tx_virt_queue(struct nthw_virt_queue *txvq)
+{
+	nthw_dbs_t *p_nthw_dbs = txvq->mp_nthw_dbs;
+
+	if (txvq == NULL)
+		return -1;
+
+	/* Clear UW */
+	txvq->used_struct_phys_addr = NULL;
+
+	if (set_tx_uw_data(p_nthw_dbs, txvq->index, (uint64_t)txvq->used_struct_phys_addr,
+			txvq->host_id, 0, PACKED(txvq->vq_type), 0, 0, 0,
+			txvq->in_order) != 0) {
+		return -1;
+	}
+
+	/* Disable AM */
+	txvq->am_enable = TX_AM_DISABLE;
+
+	if (set_tx_am_data(p_nthw_dbs,
+			txvq->index,
+			(uint64_t)txvq->avail_struct_phys_addr,
+			txvq->am_enable,
+			txvq->host_id,
+			PACKED(txvq->vq_type),
+			0) != 0) {
+		return -1;
+	}
+
+	/* Let the FPGA finish packet processing */
+	if (dbs_wait_hw_queue_shutdown(txvq, 0) != 0)
+		return -1;
+
+	/* Clear rest of AM */
+	txvq->avail_struct_phys_addr = NULL;
+	txvq->host_id = 0;
+
+	if (set_tx_am_data(p_nthw_dbs,
+			txvq->index,
+			(uint64_t)txvq->avail_struct_phys_addr,
+			txvq->am_enable,
+			txvq->host_id,
+			PACKED(txvq->vq_type),
+			0) != 0) {
+		return -1;
+	}
+
+	/* Clear DR */
+	txvq->desc_struct_phys_addr = NULL;
+	txvq->port = 0;
+	txvq->header = 0;
+
+	if (set_tx_dr_data(p_nthw_dbs,
+			txvq->index,
+			(uint64_t)txvq->desc_struct_phys_addr,
+			txvq->host_id,
+			0,
+			txvq->port,
+			txvq->header,
+			PACKED(txvq->vq_type)) != 0) {
+		return -1;
+	}
+
+	/* Clear QP */
+	txvq->virtual_port = 0;
+
+	if (nthw_dbs_set_tx_qp_data(p_nthw_dbs, txvq->index, txvq->virtual_port) != 0)
+		return -1;
+
+	/* Initialize queue */
+	dbs_init_tx_queue(p_nthw_dbs, txvq->index, 0, 0);
+
+	/* Reset queue state */
+	txvq->usage = NTHW_VIRTQ_UNUSED;
+	txvq->mp_nthw_dbs = p_nthw_dbs;
+	txvq->index = 0;
+	txvq->queue_size = 0;
+
+	return 0;
+}
+
+static int nthw_release_mngd_tx_virt_queue(struct nthw_virt_queue *txvq)
+{
+	if (txvq == NULL || txvq->usage != NTHW_VIRTQ_MANAGED)
+		return -1;
+
+	if (txvq->p_virtual_addr) {
+		free(txvq->p_virtual_addr);
+		txvq->p_virtual_addr = NULL;
+	}
+
+	return dbs_internal_release_tx_virt_queue(txvq);
+}
+
 static struct nthw_virt_queue *nthw_setup_tx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 	uint32_t index,
 	uint16_t start_idx,
@@ -844,11 +1097,111 @@ nthw_setup_mngd_tx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 	return NULL;
 }
 
+/*
+ * Put buffers back into Avail Ring
+ */
+static void nthw_release_rx_packets(struct nthw_virt_queue *rxvq, uint16_t n)
+{
+	if (rxvq->vq_type == SPLIT_RING) {
+		rxvq->am_idx = (uint16_t)(rxvq->am_idx + n);
+		rxvq->p_avail->idx = rxvq->am_idx;
+
+	} else if (rxvq->vq_type == PACKED_RING) {
+		int i;
+		/*
+		 * Defer flags update on first segment - due to serialization towards HW and
+		 * when jumbo segments are added
+		 */
+
+		uint16_t first_flags = VIRTQ_DESC_F_WRITE | avail_flag(rxvq) | used_flag_inv(rxvq);
+		struct pvirtq_desc *first_desc = &rxvq->desc[rxvq->next_avail];
+
+		uint32_t len = rxvq->p_virtual_addr[0].len;	/* all same size */
+
+		/* Optimization point: use in-order release */
+
+		for (i = 0; i < n; i++) {
+			struct pvirtq_desc *desc = &rxvq->desc[rxvq->next_avail];
+
+			desc->id = rxvq->next_avail;
+			desc->addr = (uint64_t)rxvq->p_virtual_addr[desc->id].phys_addr;
+			desc->len = len;
+
+			if (i)
+				desc->flags = VIRTQ_DESC_F_WRITE | avail_flag(rxvq) |
+					used_flag_inv(rxvq);
+
+			inc_avail(rxvq, 1);
+		}
+
+		rte_rmb();
+		first_desc->flags = first_flags;
+	}
+}
+
+static void nthw_release_tx_packets(struct nthw_virt_queue *txvq, uint16_t n, uint16_t n_segs[])
+{
+	int i;
+
+	if (txvq->vq_type == SPLIT_RING) {
+		/* Valid because queue_size is always 2^n */
+		uint16_t queue_mask = (uint16_t)(txvq->queue_size - 1);
+
+		vq_log_arg(txvq, "pkts %i, avail idx %i, start at %i\n", n, txvq->am_idx,
+			txvq->tx_descr_avail_idx);
+
+		for (i = 0; i < n; i++) {
+			int idx = txvq->am_idx & queue_mask;
+			txvq->p_avail->ring[idx] = txvq->tx_descr_avail_idx;
+			txvq->tx_descr_avail_idx =
+				(txvq->tx_descr_avail_idx + n_segs[i]) & queue_mask;
+			txvq->am_idx++;
+		}
+
+		/* Make sure the ring has been updated before HW reads index update */
+		rte_mb();
+		txvq->p_avail->idx = txvq->am_idx;
+		vq_log_arg(txvq, "new avail idx %i, descr_idx %i\n", txvq->p_avail->idx,
+			txvq->tx_descr_avail_idx);
+
+	} else if (txvq->vq_type == PACKED_RING) {
+		/*
+		 * Defer flags update on first segment - due to serialization towards HW and
+		 * when jumbo segments are added
+		 */
+
+		uint16_t first_flags = avail_flag(txvq) | used_flag_inv(txvq);
+		struct pvirtq_desc *first_desc = &txvq->desc[txvq->next_avail];
+
+		for (i = 0; i < n; i++) {
+			struct pvirtq_desc *desc = &txvq->desc[txvq->next_avail];
+
+			desc->id = txvq->next_avail;
+			desc->addr = (uint64_t)txvq->p_virtual_addr[desc->id].phys_addr;
+
+			if (i)
+				/* bitwise-or here because next flags may already have been setup
+				 */
+				desc->flags |= avail_flag(txvq) | used_flag_inv(txvq);
+
+			inc_avail(txvq, 1);
+		}
+
+		/* Proper read barrier before FPGA may see first flags */
+		rte_rmb();
+		first_desc->flags = first_flags;
+	}
+}
+
 static struct sg_ops_s sg_ops = {
 	.nthw_setup_rx_virt_queue = nthw_setup_rx_virt_queue,
 	.nthw_setup_tx_virt_queue = nthw_setup_tx_virt_queue,
 	.nthw_setup_mngd_rx_virt_queue = nthw_setup_mngd_rx_virt_queue,
+	.nthw_release_mngd_rx_virt_queue = nthw_release_mngd_rx_virt_queue,
 	.nthw_setup_mngd_tx_virt_queue = nthw_setup_mngd_tx_virt_queue,
+	.nthw_release_mngd_tx_virt_queue = nthw_release_mngd_tx_virt_queue,
+	.nthw_release_rx_packets = nthw_release_rx_packets,
+	.nthw_release_tx_packets = nthw_release_tx_packets,
 	.nthw_virt_queue_init = nthw_virt_queue_init
 };
 
diff --git a/drivers/net/ntnic/include/ntnic_dbs.h b/drivers/net/ntnic/include/ntnic_dbs.h
index 64947b4d8f..d70a7c445e 100644
--- a/drivers/net/ntnic/include/ntnic_dbs.h
+++ b/drivers/net/ntnic/include/ntnic_dbs.h
@@ -256,6 +256,10 @@ int get_rx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy);
 int set_tx_init(nthw_dbs_t *p, uint32_t start_idx, uint32_t start_ptr, uint32_t init,
 	uint32_t queue);
 int get_tx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy);
+int set_rx_idle(nthw_dbs_t *p, uint32_t idle, uint32_t queue);
+int get_rx_idle(nthw_dbs_t *p, uint32_t *idle, uint32_t *queue, uint32_t *busy);
+int set_tx_idle(nthw_dbs_t *p, uint32_t idle, uint32_t queue);
+int get_tx_idle(nthw_dbs_t *p, uint32_t *idle, uint32_t *queue, uint32_t *busy);
 int set_rx_am_data(nthw_dbs_t *p,
 	uint32_t index,
 	uint64_t guest_physical_address,
diff --git a/drivers/net/ntnic/include/ntnic_virt_queue.h b/drivers/net/ntnic/include/ntnic_virt_queue.h
index d4c9a9835a..b95efabf97 100644
--- a/drivers/net/ntnic/include/ntnic_virt_queue.h
+++ b/drivers/net/ntnic/include/ntnic_virt_queue.h
@@ -45,8 +45,14 @@ struct __rte_aligned(8) virtq_desc {
 	uint16_t next;
 };
 
+
+/*
+ * Packed Ring special structures and defines
+ */
+
 /* additional packed ring flags */
 #define VIRTQ_DESC_F_AVAIL     (1 << 7)
+#define VIRTQ_DESC_F_USED      (1 << 15)
 
 /* descr phys address must be 16 byte aligned */
 struct __rte_aligned(16) pvirtq_desc {
diff --git a/drivers/net/ntnic/nthw/dbs/nthw_dbs.c b/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
index 6e1c5a5af6..89aa5428eb 100644
--- a/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
+++ b/drivers/net/ntnic/nthw/dbs/nthw_dbs.c
@@ -485,6 +485,51 @@ int get_tx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy)
 	return 0;
 }
 
+int set_rx_idle(nthw_dbs_t *p, uint32_t idle, uint32_t queue)
+{
+	if (!p->mp_reg_rx_idle)
+		return -ENOTSUP;
+
+	nthw_field_set_val32(p->mp_fld_rx_idle_idle, idle);
+	nthw_field_set_val32(p->mp_fld_rx_idle_queue, queue);
+	nthw_register_flush(p->mp_reg_rx_idle, 1);
+	return 0;
+}
+
+int get_rx_idle(nthw_dbs_t *p, uint32_t *idle, uint32_t *queue, uint32_t *busy)
+{
+	if (!p->mp_reg_rx_idle)
+		return -ENOTSUP;
+
+	*idle = nthw_field_get_updated(p->mp_fld_rx_idle_idle);
+	*queue = 0;
+	*busy = nthw_field_get_updated(p->mp_fld_rx_idle_busy);
+	return 0;
+}
+
+int set_tx_idle(nthw_dbs_t *p, uint32_t idle, uint32_t queue)
+{
+	if (!p->mp_reg_tx_idle)
+		return -ENOTSUP;
+
+	nthw_field_set_val32(p->mp_fld_tx_idle_idle, idle);
+	nthw_field_set_val32(p->mp_fld_tx_idle_queue, queue);
+	nthw_register_flush(p->mp_reg_tx_idle, 1);
+	return 0;
+}
+
+int get_tx_idle(nthw_dbs_t *p, uint32_t *idle, uint32_t *queue, uint32_t *busy)
+{
+	if (!p->mp_reg_tx_idle)
+		return -ENOTSUP;
+
+	*idle = nthw_field_get_updated(p->mp_fld_tx_idle_idle);
+	*queue = 0;
+	*busy = nthw_field_get_updated(p->mp_fld_tx_idle_busy);
+	return 0;
+}
+
+
 static void set_rx_am_data_index(nthw_dbs_t *p, uint32_t index)
 {
 	nthw_field_set_val32(p->mp_fld_rx_avail_monitor_control_adr, index);
-- 
2.45.0


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

* [PATCH v1 14/14] net/ntnic: add functions for retrieving and managing packets
  2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
                   ` (50 preceding siblings ...)
  2024-10-04 15:07 ` [PATCH v1 13/14] net/ntnic: add functions for releasing virt queues Serhii Iliushyk
@ 2024-10-04 15:07 ` Serhii Iliushyk
  51 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:07 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit, Danylo Vodopianov

From: Danylo Vodopianov <dvo-plv@napatech.com>

Implemented functionality for retrieving received packets from
virtual queues, supporting both SPLIT_RING and PACKED_RING types.

Updated sg_ops structure to include the new packet retrieval functions.

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 doc/guides/nics/ntnic.rst                     |  44 ++++
 drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c | 216 ++++++++++++++++++
 2 files changed, 260 insertions(+)

diff --git a/doc/guides/nics/ntnic.rst b/doc/guides/nics/ntnic.rst
index 7ac92c891c..9ac8098735 100644
--- a/doc/guides/nics/ntnic.rst
+++ b/doc/guides/nics/ntnic.rst
@@ -51,6 +51,50 @@ and they are also supported.
 If vfio-pci is not required, kernel version 4.18 is supported.
 
 
+Configuration
+-------------
+
+Command line arguments
+~~~~~~~~~~~~~~~~~~~~~
+
+Following standard DPDK command line arguments are used by the PMD:
+
+    -a: Used to specifically define the NT adapter by PCI ID.
+    --iova-mode: Must be set to ‘pa’ for Physical Address mode.
+
+NTNIC specific arguments can be passed to the PMD in the PCI device parameter list::
+
+    <application> ... -a 0000:03:00.0[{,<NTNIC specific argument>}]
+
+The NTNIC specific argument format is::
+
+    <object>.<attribute>=[<object-ids>:]<value>
+
+Multiple arguments for the same device are separated by ‘,’ comma.
+<object-ids> can be a single value or a range.
+
+
+- ``rxqs`` parameter [int]
+
+    Specify number of RX queues to use.
+
+    To specify number of RX queues::
+
+        -a <domain>:<bus>:00.0,rxqs=4,txqs=4
+
+    By default, the value is set to 1.
+
+- ``txqs`` parameter [int]
+
+    Specify number of TX queues to use.
+
+    To specify number of TX queues::
+
+        -a <domain>:<bus>:00.0,rxqs=4,txqs=4
+
+    By default, the value is set to 1.
+
+
 Logging and Debugging
 ---------------------
 
diff --git a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
index 6d7862791d..a5051891e8 100644
--- a/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
+++ b/drivers/net/ntnic/dbsconfig/ntnic_dbsconfig.c
@@ -58,6 +58,15 @@
 		}                                                                                 \
 	} while (0)
 
+#define inc_used(vq, num) do { \
+	struct nthw_virt_queue *temp_vq = (vq); \
+	temp_vq->next_used += (num); \
+	if (temp_vq->next_used >= temp_vq->queue_size) { \
+		temp_vq->next_used -= temp_vq->queue_size; \
+		temp_vq->used_wrap_count ^= 1; \
+	} \
+} while (0)
+
 struct __rte_aligned(8) virtq_avail {
 	uint16_t flags;
 	uint16_t idx;
@@ -107,6 +116,10 @@ struct nthw_virt_queue {
 			struct pvirtq_event_suppress *driver_event;
 			struct pvirtq_event_suppress *device_event;
 			struct pvirtq_desc *desc;
+			struct {
+				uint16_t next;
+				uint16_t num;
+			} outs;
 			/*
 			 * when in-order release used Tx packets from FPGA it may collapse
 			 * into a batch. When getting new Tx buffers we may only need
@@ -1097,6 +1110,107 @@ nthw_setup_mngd_tx_virt_queue(nthw_dbs_t *p_nthw_dbs,
 	return NULL;
 }
 
+static uint16_t nthw_get_rx_packets(struct nthw_virt_queue *rxvq,
+	uint16_t n,
+	struct nthw_received_packets *rp,
+	uint16_t *nb_pkts)
+{
+	uint16_t segs = 0;
+	uint16_t pkts = 0;
+
+	if (rxvq->vq_type == SPLIT_RING) {
+		uint16_t i;
+		uint16_t entries_ready = (uint16_t)(rxvq->cached_idx - rxvq->used_idx);
+
+		if (entries_ready < n) {
+			/* Look for more packets */
+			rxvq->cached_idx = rxvq->p_used->idx;
+			entries_ready = (uint16_t)(rxvq->cached_idx - rxvq->used_idx);
+
+			if (entries_ready == 0) {
+				*nb_pkts = 0;
+				return 0;
+			}
+
+			if (n > entries_ready)
+				n = entries_ready;
+		}
+
+		/*
+		 * Give packets - make sure all packets are whole packets.
+		 * Valid because queue_size is always 2^n
+		 */
+		const uint16_t queue_mask = (uint16_t)(rxvq->queue_size - 1);
+		const uint32_t buf_len = rxvq->p_desc[0].len;
+
+		uint16_t used = rxvq->used_idx;
+
+		for (i = 0; i < n; ++i) {
+			uint32_t id = rxvq->p_used->ring[used & queue_mask].id;
+			rp[i].addr = rxvq->p_virtual_addr[id].virt_addr;
+			rp[i].len = rxvq->p_used->ring[used & queue_mask].len;
+
+			uint32_t pkt_len = ((struct _pkt_hdr_rx *)rp[i].addr)->cap_len;
+
+			if (pkt_len > buf_len) {
+				/* segmented */
+				int nbsegs = (pkt_len + buf_len - 1) / buf_len;
+
+				if (((int)i + nbsegs) > n) {
+					/* don't have enough segments - break out */
+					break;
+				}
+
+				int ii;
+
+				for (ii = 1; ii < nbsegs; ii++) {
+					++i;
+					id = rxvq->p_used->ring[(used + ii) & queue_mask].id;
+					rp[i].addr = rxvq->p_virtual_addr[id].virt_addr;
+					rp[i].len =
+						rxvq->p_used->ring[(used + ii) & queue_mask].len;
+				}
+
+				used += nbsegs;
+
+			} else {
+				++used;
+			}
+
+			pkts++;
+			segs = i + 1;
+		}
+
+		rxvq->used_idx = used;
+
+	} else if (rxvq->vq_type == PACKED_RING) {
+		/* This requires in-order behavior from FPGA */
+		int i;
+
+		for (i = 0; i < n; i++) {
+			struct pvirtq_desc *desc = &rxvq->desc[rxvq->next_used];
+
+			uint16_t flags = desc->flags;
+			uint8_t avail = !!(flags & VIRTQ_DESC_F_AVAIL);
+			uint8_t used = !!(flags & VIRTQ_DESC_F_USED);
+
+			if (avail != rxvq->used_wrap_count || used != rxvq->used_wrap_count)
+				break;
+
+			rp[pkts].addr = rxvq->p_virtual_addr[desc->id].virt_addr;
+			rp[pkts].len = desc->len;
+			pkts++;
+
+			inc_used(rxvq, 1);
+		}
+
+		segs = pkts;
+	}
+
+	*nb_pkts = pkts;
+	return segs;
+}
+
 /*
  * Put buffers back into Avail Ring
  */
@@ -1139,6 +1253,106 @@ static void nthw_release_rx_packets(struct nthw_virt_queue *rxvq, uint16_t n)
 	}
 }
 
+static uint16_t nthw_get_tx_packets(struct nthw_virt_queue *txvq,
+	uint16_t n,
+	uint16_t *first_idx,
+	struct nthw_cvirtq_desc *cvq,
+	struct nthw_memory_descriptor **p_virt_addr)
+{
+	int m = 0;
+	uint16_t queue_mask =
+		(uint16_t)(txvq->queue_size - 1);	/* Valid because queue_size is always 2^n */
+	*p_virt_addr = txvq->p_virtual_addr;
+
+	if (txvq->vq_type == SPLIT_RING) {
+		cvq->s = txvq->p_desc;
+		cvq->vq_type = SPLIT_RING;
+
+		*first_idx = txvq->tx_descr_avail_idx;
+
+		uint16_t entries_used =
+			(uint16_t)((txvq->tx_descr_avail_idx - txvq->cached_idx) & queue_mask);
+		uint16_t entries_ready = (uint16_t)(txvq->queue_size - 1 - entries_used);
+
+		vq_log_arg(txvq,
+			"ask %i: descrAvail %i, cachedidx %i, used: %i, ready %i used->idx %i\n",
+			n, txvq->tx_descr_avail_idx, txvq->cached_idx, entries_used, entries_ready,
+			txvq->p_used->idx);
+
+		if (entries_ready < n) {
+			/*
+			 * Look for more packets.
+			 * Using the used_idx in the avail ring since they are held synchronous
+			 * because of in-order
+			 */
+			txvq->cached_idx =
+				txvq->p_avail->ring[(txvq->p_used->idx - 1) & queue_mask];
+
+			vq_log_arg(txvq, "Update: get cachedidx %i (used_idx-1 %i)\n",
+				txvq->cached_idx, (txvq->p_used->idx - 1) & queue_mask);
+			entries_used =
+				(uint16_t)((txvq->tx_descr_avail_idx - txvq->cached_idx)
+				& queue_mask);
+			entries_ready = (uint16_t)(txvq->queue_size - 1 - entries_used);
+			vq_log_arg(txvq, "new used: %i, ready %i\n", entries_used, entries_ready);
+
+			if (n > entries_ready)
+				n = entries_ready;
+		}
+
+	} else if (txvq->vq_type == PACKED_RING) {
+		int i;
+
+		cvq->p = txvq->desc;
+		cvq->vq_type = PACKED_RING;
+
+		if (txvq->outs.num) {
+			*first_idx = txvq->outs.next;
+			uint16_t num = min(n, txvq->outs.num);
+			txvq->outs.next = (txvq->outs.next + num) & queue_mask;
+			txvq->outs.num -= num;
+
+			if (n == num)
+				return n;
+
+			m = num;
+			n -= num;
+
+		} else {
+			*first_idx = txvq->next_used;
+		}
+
+		/* iterate the ring - this requires in-order behavior from FPGA */
+		for (i = 0; i < n; i++) {
+			struct pvirtq_desc *desc = &txvq->desc[txvq->next_used];
+
+			uint16_t flags = desc->flags;
+			uint8_t avail = !!(flags & VIRTQ_DESC_F_AVAIL);
+			uint8_t used = !!(flags & VIRTQ_DESC_F_USED);
+
+			if (avail != txvq->used_wrap_count || used != txvq->used_wrap_count) {
+				n = i;
+				break;
+			}
+
+			uint16_t incr = (desc->id - txvq->next_used) & queue_mask;
+			i += incr;
+			inc_used(txvq, incr + 1);
+		}
+
+		if (i > n) {
+			int outs_num = i - n;
+			txvq->outs.next = (txvq->next_used - outs_num) & queue_mask;
+			txvq->outs.num = outs_num;
+		}
+
+	} else {
+		return 0;
+	}
+
+	return m + n;
+}
+
 static void nthw_release_tx_packets(struct nthw_virt_queue *txvq, uint16_t n, uint16_t n_segs[])
 {
 	int i;
@@ -1200,7 +1414,9 @@ static struct sg_ops_s sg_ops = {
 	.nthw_release_mngd_rx_virt_queue = nthw_release_mngd_rx_virt_queue,
 	.nthw_setup_mngd_tx_virt_queue = nthw_setup_mngd_tx_virt_queue,
 	.nthw_release_mngd_tx_virt_queue = nthw_release_mngd_tx_virt_queue,
+	.nthw_get_rx_packets = nthw_get_rx_packets,
 	.nthw_release_rx_packets = nthw_release_rx_packets,
+	.nthw_get_tx_packets = nthw_get_tx_packets,
 	.nthw_release_tx_packets = nthw_release_tx_packets,
 	.nthw_virt_queue_init = nthw_virt_queue_init
 };
-- 
2.45.0


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

* Re: [PATCH v1 01/31] net/ntnic: add flow filter init API
  2024-10-04 15:06 ` [PATCH v1 01/31] net/ntnic: add flow filter init API Serhii Iliushyk
@ 2024-10-21 23:24   ` Stephen Hemminger
  0 siblings, 0 replies; 55+ messages in thread
From: Stephen Hemminger @ 2024-10-21 23:24 UTC (permalink / raw)
  To: Serhii Iliushyk
  Cc: dev, mko-plv, ckm, andrew.rybchenko, ferruh.yigit, Oleksandr Kolomeiets

On Fri,  4 Oct 2024 17:06:54 +0200
Serhii Iliushyk <sil-plv@napatech.com> wrote:

> From: Oleksandr Kolomeiets <okl-plv@napatech.com>
> 
> Add high-level interfaces for the initialization of the flow filter.
> 
> Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
> ---

Please send a v2 of this patch series after fixing build issues with:

CC=clang meson setup -Denable_stdatomic=true build

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

* [PATCH v1 01/31] net/ntnic: add flow filter init API
  2024-10-04 15:34 [PATCH v1 00/50] Provide: flow filter init API, Enable virtual queues, fix ntnic issues for release 24.07 Serhii Iliushyk
@ 2024-10-04 15:34 ` Serhii Iliushyk
  0 siblings, 0 replies; 55+ messages in thread
From: Serhii Iliushyk @ 2024-10-04 15:34 UTC (permalink / raw)
  To: dev
  Cc: mko-plv, sil-plv, ckm, andrew.rybchenko, ferruh.yigit,
	Oleksandr Kolomeiets

From: Oleksandr Kolomeiets <okl-plv@napatech.com>

Add high-level interfaces for the initialization of the flow filter.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/adapter/nt4ga_adapter.c | 18 ++++++++++++++++++
 drivers/net/ntnic/include/flow_api.h      | 12 ++++++++++++
 drivers/net/ntnic/include/nt4ga_adapter.h |  6 ++++++
 drivers/net/ntnic/include/nt4ga_filter.h  | 13 +++++++++++++
 drivers/net/ntnic/ntnic_mod_reg.c         |  7 +++++++
 drivers/net/ntnic/ntnic_mod_reg.h         |  8 ++++++++
 6 files changed, 64 insertions(+)
 create mode 100644 drivers/net/ntnic/include/flow_api.h
 create mode 100644 drivers/net/ntnic/include/nt4ga_filter.h

diff --git a/drivers/net/ntnic/adapter/nt4ga_adapter.c b/drivers/net/ntnic/adapter/nt4ga_adapter.c
index b704a256c6..4105a6eb5a 100644
--- a/drivers/net/ntnic/adapter/nt4ga_adapter.c
+++ b/drivers/net/ntnic/adapter/nt4ga_adapter.c
@@ -75,6 +75,11 @@ static int nt4ga_adapter_show_info(struct adapter_info_s *p_adapter_info, FILE *
 
 static int nt4ga_adapter_init(struct adapter_info_s *p_adapter_info)
 {
+	const struct flow_filter_ops *flow_filter_ops = get_flow_filter_ops();
+
+	if (flow_filter_ops == NULL)
+		NT_LOG(ERR, NTNIC, "%s: flow_filter module uninitialized\n", __func__);
+
 	char *const p_dev_name = malloc(24);
 	char *const p_adapter_id_str = malloc(24);
 	fpga_info_t *fpga_info = &p_adapter_info->fpga_info;
@@ -155,6 +160,19 @@ static int nt4ga_adapter_init(struct adapter_info_s *p_adapter_info)
 	n_nim_ports = fpga_info->n_nims;
 	assert(n_nim_ports >= 1);
 
+	/* Nt4ga Init Filter */
+	nt4ga_filter_t *p_filter = &p_adapter_info->nt4ga_filter;
+
+	if (flow_filter_ops != NULL) {
+		res = flow_filter_ops->flow_filter_init(p_fpga, &p_filter->mp_flow_device,
+				p_adapter_info->adapter_no);
+
+		if (res != 0) {
+			NT_LOG(ERR, NTNIC, "%s: Cannot initialize filter\n", p_adapter_id_str);
+			return res;
+		}
+	}
+
 	{
 		int i;
 		const struct link_ops_s *link_ops = NULL;
diff --git a/drivers/net/ntnic/include/flow_api.h b/drivers/net/ntnic/include/flow_api.h
new file mode 100644
index 0000000000..036e652b76
--- /dev/null
+++ b/drivers/net/ntnic/include/flow_api.h
@@ -0,0 +1,12 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _FLOW_API_H_
+#define _FLOW_API_H_
+
+/* registered NIC backends */
+struct flow_nic_dev;
+
+#endif
diff --git a/drivers/net/ntnic/include/nt4ga_adapter.h b/drivers/net/ntnic/include/nt4ga_adapter.h
index 4b204742a2..93218fd45b 100644
--- a/drivers/net/ntnic/include/nt4ga_adapter.h
+++ b/drivers/net/ntnic/include/nt4ga_adapter.h
@@ -23,7 +23,13 @@ typedef struct hw_info_s {
 	int hw_reserved1;
 } hw_info_t;
 
+/*
+ * Services provided by the adapter module
+ */
+#include "nt4ga_filter.h"
+
 typedef struct adapter_info_s {
+	struct nt4ga_filter_s nt4ga_filter;
 	struct nt4ga_link_s nt4ga_link;
 
 	struct hw_info_s hw_info;
diff --git a/drivers/net/ntnic/include/nt4ga_filter.h b/drivers/net/ntnic/include/nt4ga_filter.h
new file mode 100644
index 0000000000..2024b500f3
--- /dev/null
+++ b/drivers/net/ntnic/include/nt4ga_filter.h
@@ -0,0 +1,13 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef NT4GA_FILTER_H_
+#define NT4GA_FILTER_H_
+
+typedef struct nt4ga_filter_s {
+	struct flow_nic_dev *mp_flow_device;
+} nt4ga_filter_t;
+
+#endif  /* NT4GA_FILTER_H_ */
diff --git a/drivers/net/ntnic/ntnic_mod_reg.c b/drivers/net/ntnic/ntnic_mod_reg.c
index 40e22c60fa..45cc767c90 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.c
+++ b/drivers/net/ntnic/ntnic_mod_reg.c
@@ -88,3 +88,10 @@ struct rst9563_ops *get_rst9563_ops(void)
 		rst9563_ops_init();
 	return rst9563_ops;
 }
+
+static const struct flow_filter_ops *flow_filter_ops;
+
+const struct flow_filter_ops *get_flow_filter_ops(void)
+{
+	return flow_filter_ops;
+}
diff --git a/drivers/net/ntnic/ntnic_mod_reg.h b/drivers/net/ntnic/ntnic_mod_reg.h
index 3189b04f33..6dd6240c6f 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.h
+++ b/drivers/net/ntnic/ntnic_mod_reg.h
@@ -7,6 +7,7 @@
 #define __NTNIC_MOD_REG_H__
 
 #include <stdint.h>
+#include "flow_api.h"
 #include "nthw_fpga_model.h"
 #include "nthw_platform_drv.h"
 #include "nthw_drv.h"
@@ -117,4 +118,11 @@ void register_rst9563_ops(struct rst9563_ops *ops);
 struct rst9563_ops *get_rst9563_ops(void);
 void rst9563_ops_init(void);
 
+struct flow_filter_ops {
+	int (*flow_filter_init)(nthw_fpga_t *p_fpga, struct flow_nic_dev **p_flow_device,
+		int adapter_no);
+};
+
+const struct flow_filter_ops *get_flow_filter_ops(void);
+
 #endif	/* __NTNIC_MOD_REG_H__ */
-- 
2.45.0


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

end of thread, other threads:[~2024-10-21 23:24 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-04 15:06 [PATCH v1 0/5] Fixes for release 24.07 Serhii Iliushyk
2024-10-04 15:06 ` [PATCH v1 1/5] net/ntnic: update NT NiC PMD driver with FPGA version Serhii Iliushyk
2024-10-04 15:06 ` [PATCH v1 2/5] net/ntnic: fix coverity issues: Serhii Iliushyk
2024-10-04 15:06 ` [PATCH v1 3/5] net/ntnic: update documentation Serhii Iliushyk
2024-10-04 15:06 ` [PATCH v1 4/5] net/ntnic: remove extra calling of the API for release port Serhii Iliushyk
2024-10-04 15:06 ` [PATCH v1 5/5] net/ntnic: extend and fix logging implementation Serhii Iliushyk
2024-10-04 15:06 ` [PATCH v1 00/31] Enable flow filter initialization Serhii Iliushyk
2024-10-04 15:06 ` [PATCH v1 01/31] net/ntnic: add flow filter init API Serhii Iliushyk
2024-10-21 23:24   ` Stephen Hemminger
2024-10-04 15:06 ` [PATCH v1 02/31] net/ntnic: add flow filter deinitialization API Serhii Iliushyk
2024-10-04 15:06 ` [PATCH v1 03/31] net/ntnic: add flow backend initialization API Serhii Iliushyk
2024-10-04 15:06 ` [PATCH v1 04/31] net/ntnic: add flow backend deinitialization API Serhii Iliushyk
2024-10-04 15:06 ` [PATCH v1 05/31] net/ntnic: add INFO flow module Serhii Iliushyk
2024-10-04 15:06 ` [PATCH v1 06/31] net/ntnic: add categorizer (CAT) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 07/31] net/ntnic: add key match (KM) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 08/31] net/ntnic: add flow matcher (FLM) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 09/31] net/ntnic: add IP fragmenter (IFR) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 10/31] net/ntnic: add hasher (HSH) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 11/31] net/ntnic: add queue select (QSL) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 12/31] net/ntnic: add slicer (SLC LR) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 13/31] net/ntnic: add packet descriptor builder (PDB) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 14/31] net/ntnic: add header field update (HFU) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 15/31] net/ntnic: add RPP local retransmit (RPP LR) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 16/31] net/ntnic: add copier (Tx CPY) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 17/31] net/ntnic: add checksum update (CSU) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 18/31] net/ntnic: add insert (Tx INS) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 19/31] net/ntnic: add replacer (Tx RPL) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 20/31] net/ntnic: add Tx Packet Editor (TPE) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 21/31] net/ntnic: add base init and deinit of the NT flow API Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 22/31] net/ntnic: add base init and deinit the NT flow backend Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 23/31] net/ntnic: add categorizer (CAT) FPGA module Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 24/31] net/ntnic: add key match (KM) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 25/31] net/ntnic: add flow matcher (FLM) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 26/31] net/ntnic: add hasher (HSH) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 27/31] net/ntnic: add queue select (QSL) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 28/31] net/ntnic: add slicer (SLC LR) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 29/31] net/ntnic: add packet descriptor builder (PDB) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 30/31] net/ntnic: add Tx Packet Editor (TPE) " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 31/31] net/ntnic: add receive MAC converter (RMC) core module Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 00/14] Enable virtual queues Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 01/14] net/ntnic: add basic queue operations Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 02/14] net/ntnic: enhance Ethernet device configuration Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 03/14] net/ntnic: add scatter-gather HW deallocation Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 04/14] net/ntnic: add queue setup operations Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 05/14] net/ntnic: add packet handler for virtio queues Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 06/14] net/ntnic: add init for virt queues in the DBS Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 07/14] net/ntnic: add split-queue support Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 08/14] net/ntnic: add functions for availability monitor management Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 09/14] net/ntnic: used writer data handling functions Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 10/14] net/ntnic: add descriptor reader " Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 11/14] net/ntnic: update FPGA registeris related to DBS Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 12/14] net/ntnic: virtqueue setup managed packed-ring was added Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 13/14] net/ntnic: add functions for releasing virt queues Serhii Iliushyk
2024-10-04 15:07 ` [PATCH v1 14/14] net/ntnic: add functions for retrieving and managing packets Serhii Iliushyk
2024-10-04 15:34 [PATCH v1 00/50] Provide: flow filter init API, Enable virtual queues, fix ntnic issues for release 24.07 Serhii Iliushyk
2024-10-04 15:34 ` [PATCH v1 01/31] net/ntnic: add flow filter init API Serhii Iliushyk

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).