All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mykola Kostenok <mko-plv@napatech.com>
To: dev@dpdk.org, mko-plv@napatech.com, thomas@monjalon.net
Cc: ckm@napatech.com
Subject: [PATCH v12 4/8] net/ntnic: adds flow related FPGA functionality
Date: Thu, 31 Aug 2023 15:51:08 +0200	[thread overview]
Message-ID: <20230831135112.1435200-4-mko-plv@napatech.com> (raw)
In-Reply-To: <20230831135112.1435200-1-mko-plv@napatech.com>

From: Christian Koue Muf <ckm@napatech.com>

The PMD will control the registers used for flow programming,
and this commit adds support for this.

Signed-off-by: Christian Koue Muf <ckm@napatech.com>
Reviewed-by: Mykola Kostenok <mko-plv@napatech.com>
---
v2:
* Fixed compilation with Fedora 38
---
 drivers/net/ntnic/meson.build                 |   21 +
 .../ntnic/nthw/flow_filter/flow_nthw_cat.c    | 1107 ++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_cat.h    |  372 ++++++
 .../ntnic/nthw/flow_filter/flow_nthw_csu.c    |  146 +++
 .../ntnic/nthw/flow_filter/flow_nthw_csu.h    |   42 +
 .../ntnic/nthw/flow_filter/flow_nthw_flm.c    | 1140 +++++++++++++++++
 .../ntnic/nthw/flow_filter/flow_nthw_flm.h    |  422 ++++++
 .../ntnic/nthw/flow_filter/flow_nthw_hfu.c    |  293 +++++
 .../ntnic/nthw/flow_filter/flow_nthw_hfu.h    |  100 ++
 .../ntnic/nthw/flow_filter/flow_nthw_hsh.c    |  254 ++++
 .../ntnic/nthw/flow_filter/flow_nthw_hsh.h    |   81 ++
 .../ntnic/nthw/flow_filter/flow_nthw_hst.c    |  202 +++
 .../ntnic/nthw/flow_filter/flow_nthw_hst.h    |   72 ++
 .../ntnic/nthw/flow_filter/flow_nthw_ifr.c    |   93 ++
 .../ntnic/nthw/flow_filter/flow_nthw_ifr.h    |   39 +
 .../ntnic/nthw/flow_filter/flow_nthw_info.c   |  341 +++++
 .../ntnic/nthw/flow_filter/flow_nthw_info.h   |  104 ++
 .../ntnic/nthw/flow_filter/flow_nthw_ioa.c    |  234 ++++
 .../ntnic/nthw/flow_filter/flow_nthw_ioa.h    |   80 ++
 .../net/ntnic/nthw/flow_filter/flow_nthw_km.c |  685 ++++++++++
 .../net/ntnic/nthw/flow_filter/flow_nthw_km.h |  224 ++++
 .../ntnic/nthw/flow_filter/flow_nthw_pdb.c    |  230 ++++
 .../ntnic/nthw/flow_filter/flow_nthw_pdb.h    |   84 ++
 .../ntnic/nthw/flow_filter/flow_nthw_qsl.c    |  355 +++++
 .../ntnic/nthw/flow_filter/flow_nthw_qsl.h    |  121 ++
 .../ntnic/nthw/flow_filter/flow_nthw_rmc.c    |  112 ++
 .../ntnic/nthw/flow_filter/flow_nthw_rmc.h    |   40 +
 .../ntnic/nthw/flow_filter/flow_nthw_roa.c    |  294 +++++
 .../ntnic/nthw/flow_filter/flow_nthw_roa.h    |  109 ++
 .../ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c |  132 ++
 .../ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h |   53 +
 .../ntnic/nthw/flow_filter/flow_nthw_slc.c    |  109 ++
 .../ntnic/nthw/flow_filter/flow_nthw_slc.h    |   46 +
 .../ntnic/nthw/flow_filter/flow_nthw_slc_lr.c |  109 ++
 .../ntnic/nthw/flow_filter/flow_nthw_slc_lr.h |   46 +
 .../ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c |  394 ++++++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h |   72 ++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_ins.c |   96 ++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_ins.h |   42 +
 .../ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c |  165 +++
 .../ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h |   70 +
 41 files changed, 8731 insertions(+)
 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_hst.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_hst.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_ioa.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_ioa.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_rmc.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_rmc.h
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_roa.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_roa.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.c
 create mode 100644 drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc.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

diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 2552b5d68d..8c065ee9a3 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -18,6 +18,7 @@ includes = [
     include_directories('nthw'),
     include_directories('nthw/core'),
     include_directories('nthw/supported'),
+    include_directories('nthw/flow_filter'),
     include_directories('sensors'),
     include_directories('sensors/avr_sensors'),
     include_directories('sensors/board_sensors'),
@@ -59,6 +60,26 @@ sources = files(
     'nthw/core/nthw_spim.c',
     'nthw/core/nthw_spis.c',
     'nthw/core/nthw_tsm.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',
+    'nthw/flow_filter/flow_nthw_hst.c',
+    'nthw/flow_filter/flow_nthw_ifr.c',
+    'nthw/flow_filter/flow_nthw_info.c',
+    'nthw/flow_filter/flow_nthw_ioa.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_rmc.c',
+    'nthw/flow_filter/flow_nthw_roa.c',
+    'nthw/flow_filter/flow_nthw_rpp_lr.c',
+    'nthw/flow_filter/flow_nthw_slc.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/flow_filter/flow_nthw_tx_rpl.c',
     'nthw/nthw_fpga_model.c',
     'nthw/nthw_dbs.c',
     'nthw/nthw_epp.c',
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..91376363c1
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_cat.c
@@ -0,0 +1,1107 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_cat.h"
+
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+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)
+{
+	module_set_debug_mode(p->m_cat, n_debug_mode);
+}
+
+int cat_nthw_init(struct cat_nthw *p, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = fpga_get_product_param(p->mp_fpga, NT_CAT_KM_IF_CNT, -1);
+
+	/* CFN */
+	p->mp_cfn_ctrl = module_get_register(p->m_cat, CAT_CFN_CTRL);
+	p->mp_cfn_addr = register_get_field(p->mp_cfn_ctrl, CAT_CFN_CTRL_ADR);
+	p->mp_cfn_cnt = register_get_field(p->mp_cfn_ctrl, CAT_CFN_CTRL_CNT);
+	p->mp_cfn_data = module_get_register(p->m_cat, CAT_CFN_DATA);
+	p->mp_cfn_data_enable =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_ENABLE);
+	p->mp_cfn_data_inv = register_get_field(p->mp_cfn_data, CAT_CFN_DATA_INV);
+	p->mp_cfn_data_ptc_inv =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_INV);
+	p->mp_cfn_data_ptc_isl =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_ISL);
+	p->mp_cfn_data_ptc_mac =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_MAC);
+	p->mp_cfn_data_ptc_l2 =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_L2);
+	p->mp_cfn_data_ptc_vn_tag =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_VNTAG);
+	p->mp_cfn_data_ptc_vlan =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_VLAN);
+	p->mp_cfn_data_ptc_mpls =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_MPLS);
+	p->mp_cfn_data_ptc_l3 =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_L3);
+	p->mp_cfn_data_ptc_frag =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_FRAG);
+	p->mp_cfn_data_ptc_ip_prot =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_IP_PROT);
+	p->mp_cfn_data_ptc_l4 =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_L4);
+	p->mp_cfn_data_ptc_tunnel =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TUNNEL);
+	p->mp_cfn_data_ptc_tnl_l2 =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_L2);
+	p->mp_cfn_data_ptc_tnl_vlan =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_VLAN);
+	p->mp_cfn_data_ptc_tnl_mpls =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_MPLS);
+	p->mp_cfn_data_ptc_tnl_l3 =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_L3);
+	p->mp_cfn_data_ptc_tnl_frag =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_FRAG);
+	p->mp_cfn_data_ptc_tnl_ip_prot =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_IP_PROT);
+	p->mp_cfn_data_ptc_tnl_l4 =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_TNL_L4);
+	p->mp_cfn_data_err_inv =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_INV);
+	p->mp_cfn_data_err_cv =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_CV);
+	p->mp_cfn_data_err_fcs =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_FCS);
+	p->mp_cfn_data_err_trunc =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_TRUNC);
+	p->mp_cfn_data_mac_port =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_MAC_PORT);
+	p->mp_cfn_data_pm_cmp =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_CMP);
+	p->mp_cfn_data_pm_dct =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_DCT);
+	p->mp_cfn_data_pm_ext_inv =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_EXT_INV);
+	p->mp_cfn_data_pm_cmb =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_CMB);
+	p->mp_cfn_data_pm_and_inv =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_AND_INV);
+	p->mp_cfn_data_pm_or_inv =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_OR_INV);
+	p->mp_cfn_data_pm_inv =
+		register_get_field(p->mp_cfn_data, CAT_CFN_DATA_PM_INV);
+	p->mp_cfn_data_lc = register_get_field(p->mp_cfn_data, CAT_CFN_DATA_LC);
+	p->mp_cfn_data_lc_inv =
+		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 =
+			register_get_field(p->mp_cfn_data, CAT_CFN_DATA_KM_OR);
+	} else {
+		p->mp_cfn_data_km0_or =
+			register_get_field(p->mp_cfn_data, CAT_CFN_DATA_KM0_OR);
+		p->mp_cfn_data_km1_or =
+			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] = module_get_register(p->m_cat, CAT_KCE_CTRL);
+		p->mp_kce_addr[0] =
+			register_get_field(p->mp_kce_ctrl[0], CAT_KCE_CTRL_ADR);
+		p->mp_kce_cnt[0] =
+			register_get_field(p->mp_kce_ctrl[0], CAT_KCE_CTRL_CNT);
+		p->mp_kce_data[0] = module_get_register(p->m_cat, CAT_KCE_DATA);
+		p->mp_kce_data_enable[0] =
+			register_get_field(p->mp_kce_data[0], CAT_KCE_DATA_ENABLE);
+		/* KCS */
+		p->mp_kcs_ctrl[0] = module_get_register(p->m_cat, CAT_KCS_CTRL);
+		p->mp_kcs_addr[0] =
+			register_get_field(p->mp_kcs_ctrl[0], CAT_KCS_CTRL_ADR);
+		p->mp_kcs_cnt[0] =
+			register_get_field(p->mp_kcs_ctrl[0], CAT_KCS_CTRL_CNT);
+		p->mp_kcs_data[0] = module_get_register(p->m_cat, CAT_KCS_DATA);
+		p->mp_kcs_data_category[0] =
+			register_get_field(p->mp_kcs_data[0], CAT_KCS_DATA_CATEGORY);
+		/* FTE */
+		p->mp_fte_ctrl[0] = module_get_register(p->m_cat, CAT_FTE_CTRL);
+		p->mp_fte_addr[0] =
+			register_get_field(p->mp_fte_ctrl[0], CAT_FTE_CTRL_ADR);
+		p->mp_fte_cnt[0] =
+			register_get_field(p->mp_fte_ctrl[0], CAT_FTE_CTRL_CNT);
+		p->mp_fte_data[0] = module_get_register(p->m_cat, CAT_FTE_DATA);
+		p->mp_fte_data_enable[0] =
+			register_get_field(p->mp_fte_data[0], CAT_FTE_DATA_ENABLE);
+	} else {
+		/* KCE 0 */
+		p->mp_kce_ctrl[0] = module_get_register(p->m_cat, CAT_KCE0_CTRL);
+		p->mp_kce_addr[0] =
+			register_get_field(p->mp_kce_ctrl[0], CAT_KCE0_CTRL_ADR);
+		p->mp_kce_cnt[0] =
+			register_get_field(p->mp_kce_ctrl[0], CAT_KCE0_CTRL_CNT);
+		p->mp_kce_data[0] = module_get_register(p->m_cat, CAT_KCE0_DATA);
+		p->mp_kce_data_enable[0] = register_get_field(p->mp_kce_data[0],
+					CAT_KCE0_DATA_ENABLE);
+		/* KCS 0 */
+		p->mp_kcs_ctrl[0] = module_get_register(p->m_cat, CAT_KCS0_CTRL);
+		p->mp_kcs_addr[0] =
+			register_get_field(p->mp_kcs_ctrl[0], CAT_KCS0_CTRL_ADR);
+		p->mp_kcs_cnt[0] =
+			register_get_field(p->mp_kcs_ctrl[0], CAT_KCS0_CTRL_CNT);
+		p->mp_kcs_data[0] = module_get_register(p->m_cat, CAT_KCS0_DATA);
+		p->mp_kcs_data_category[0] =
+			register_get_field(p->mp_kcs_data[0], CAT_KCS0_DATA_CATEGORY);
+		/* FTE 0 */
+		p->mp_fte_ctrl[0] = module_get_register(p->m_cat, CAT_FTE0_CTRL);
+		p->mp_fte_addr[0] =
+			register_get_field(p->mp_fte_ctrl[0], CAT_FTE0_CTRL_ADR);
+		p->mp_fte_cnt[0] =
+			register_get_field(p->mp_fte_ctrl[0], CAT_FTE0_CTRL_CNT);
+		p->mp_fte_data[0] = module_get_register(p->m_cat, CAT_FTE0_DATA);
+		p->mp_fte_data_enable[0] = register_get_field(p->mp_fte_data[0],
+					CAT_FTE0_DATA_ENABLE);
+		/* KCE 1 */
+		p->mp_kce_ctrl[1] = module_get_register(p->m_cat, CAT_KCE1_CTRL);
+		p->mp_kce_addr[1] =
+			register_get_field(p->mp_kce_ctrl[1], CAT_KCE1_CTRL_ADR);
+		p->mp_kce_cnt[1] =
+			register_get_field(p->mp_kce_ctrl[1], CAT_KCE1_CTRL_CNT);
+		p->mp_kce_data[1] = module_get_register(p->m_cat, CAT_KCE1_DATA);
+		p->mp_kce_data_enable[1] = register_get_field(p->mp_kce_data[1],
+					CAT_KCE1_DATA_ENABLE);
+		/* KCS 1 */
+		p->mp_kcs_ctrl[1] = module_get_register(p->m_cat, CAT_KCS1_CTRL);
+		p->mp_kcs_addr[1] =
+			register_get_field(p->mp_kcs_ctrl[1], CAT_KCS1_CTRL_ADR);
+		p->mp_kcs_cnt[1] =
+			register_get_field(p->mp_kcs_ctrl[1], CAT_KCS1_CTRL_CNT);
+		p->mp_kcs_data[1] = module_get_register(p->m_cat, CAT_KCS1_DATA);
+		p->mp_kcs_data_category[1] =
+			register_get_field(p->mp_kcs_data[1], CAT_KCS1_DATA_CATEGORY);
+		/* FTE 1 */
+		p->mp_fte_ctrl[1] = module_get_register(p->m_cat, CAT_FTE1_CTRL);
+		p->mp_fte_addr[1] =
+			register_get_field(p->mp_fte_ctrl[1], CAT_FTE1_CTRL_ADR);
+		p->mp_fte_cnt[1] =
+			register_get_field(p->mp_fte_ctrl[1], CAT_FTE1_CTRL_CNT);
+		p->mp_fte_data[1] = module_get_register(p->m_cat, CAT_FTE1_DATA);
+		p->mp_fte_data_enable[1] = register_get_field(p->mp_fte_data[1],
+					CAT_FTE1_DATA_ENABLE);
+	}
+
+	/* CTE */
+	p->mp_cte_ctrl = module_get_register(p->m_cat, CAT_CTE_CTRL);
+	p->mp_cte_addr = register_get_field(p->mp_cte_ctrl, CAT_CTE_CTRL_ADR);
+	p->mp_cte_cnt = register_get_field(p->mp_cte_ctrl, CAT_CTE_CTRL_CNT);
+	p->mp_cte_data = module_get_register(p->m_cat, CAT_CTE_DATA);
+	p->mp_cte_data_col =
+		register_get_field(p->mp_cte_data, CAT_CTE_DATA_COL_ENABLE);
+	p->mp_cte_data_cor =
+		register_get_field(p->mp_cte_data, CAT_CTE_DATA_COR_ENABLE);
+	p->mp_cte_data_hsh =
+		register_get_field(p->mp_cte_data, CAT_CTE_DATA_HSH_ENABLE);
+	p->mp_cte_data_qsl =
+		register_get_field(p->mp_cte_data, CAT_CTE_DATA_QSL_ENABLE);
+	p->mp_cte_data_ipf =
+		register_get_field(p->mp_cte_data, CAT_CTE_DATA_IPF_ENABLE);
+	p->mp_cte_data_slc =
+		register_get_field(p->mp_cte_data, CAT_CTE_DATA_SLC_ENABLE);
+	p->mp_cte_data_pdb =
+		register_get_field(p->mp_cte_data, CAT_CTE_DATA_PDB_ENABLE);
+	p->mp_cte_data_msk =
+		register_query_field(p->mp_cte_data, CAT_CTE_DATA_MSK_ENABLE);
+	p->mp_cte_data_hst =
+		register_query_field(p->mp_cte_data, CAT_CTE_DATA_HST_ENABLE);
+	p->mp_cte_data_epp =
+		register_query_field(p->mp_cte_data, CAT_CTE_DATA_EPP_ENABLE);
+	p->mp_cte_data_tpe =
+		register_query_field(p->mp_cte_data, CAT_CTE_DATA_TPE_ENABLE);
+	p->mp_cte_data_rrb =
+		register_query_field(p->mp_cte_data, CAT_CTE_DATA_RRB_ENABLE);
+	/* CTS */
+	p->mp_cts_ctrl = module_get_register(p->m_cat, CAT_CTS_CTRL);
+	p->mp_cts_addr = register_get_field(p->mp_cts_ctrl, CAT_CTS_CTRL_ADR);
+	p->mp_cts_cnt = register_get_field(p->mp_cts_ctrl, CAT_CTS_CTRL_CNT);
+	p->mp_cts_data = module_get_register(p->m_cat, CAT_CTS_DATA);
+	p->mp_cts_data_cat_a = register_get_field(p->mp_cts_data, CAT_CTS_DATA_CAT_A);
+	p->mp_cts_data_cat_b = register_get_field(p->mp_cts_data, CAT_CTS_DATA_CAT_B);
+	/* COT */
+	p->mp_cot_ctrl = module_get_register(p->m_cat, CAT_COT_CTRL);
+	p->mp_cot_addr = register_get_field(p->mp_cot_ctrl, CAT_COT_CTRL_ADR);
+	p->mp_cot_cnt = register_get_field(p->mp_cot_ctrl, CAT_COT_CTRL_CNT);
+	p->mp_cot_data = module_get_register(p->m_cat, CAT_COT_DATA);
+	p->mp_cot_data_color = register_get_field(p->mp_cot_data, CAT_COT_DATA_COLOR);
+	p->mp_cot_data_km = register_get_field(p->mp_cot_data, CAT_COT_DATA_KM);
+	p->mp_cot_data_nfv_sb =
+		register_query_field(p->mp_cot_data, CAT_COT_DATA_NFV_SB);
+	/* CCT */
+	p->mp_cct_ctrl = module_get_register(p->m_cat, CAT_CCT_CTRL);
+	p->mp_cct_addr = register_get_field(p->mp_cct_ctrl, CAT_CCT_CTRL_ADR);
+	p->mp_cct_cnt = register_get_field(p->mp_cct_ctrl, CAT_CCT_CTRL_CNT);
+	p->mp_cct_data = module_get_register(p->m_cat, CAT_CCT_DATA);
+	p->mp_cct_data_color = register_get_field(p->mp_cct_data, CAT_CCT_DATA_COLOR);
+	p->mp_cct_data_km = register_get_field(p->mp_cct_data, CAT_CCT_DATA_KM);
+	/* EXO */
+	p->mp_exo_ctrl = module_get_register(p->m_cat, CAT_EXO_CTRL);
+	p->mp_exo_addr = register_get_field(p->mp_exo_ctrl, CAT_EXO_CTRL_ADR);
+	p->mp_exo_cnt = register_get_field(p->mp_exo_ctrl, CAT_EXO_CTRL_CNT);
+	p->mp_exo_data = module_get_register(p->m_cat, CAT_EXO_DATA);
+	p->mp_exo_data_dyn = register_get_field(p->mp_exo_data, CAT_EXO_DATA_DYN);
+	p->mp_exo_data_ofs = register_get_field(p->mp_exo_data, CAT_EXO_DATA_OFS);
+	/* RCK */
+	p->mp_rck_ctrl = module_get_register(p->m_cat, CAT_RCK_CTRL);
+	p->mp_rck_addr = register_get_field(p->mp_rck_ctrl, CAT_RCK_CTRL_ADR);
+	p->mp_rck_cnt = register_get_field(p->mp_rck_ctrl, CAT_RCK_CTRL_CNT);
+	p->mp_rck_data = module_get_register(p->m_cat, CAT_RCK_DATA);
+	/* LEN */
+	p->mp_len_ctrl = module_get_register(p->m_cat, CAT_LEN_CTRL);
+	p->mp_len_addr = register_get_field(p->mp_len_ctrl, CAT_LEN_CTRL_ADR);
+	p->mp_len_cnt = register_get_field(p->mp_len_ctrl, CAT_LEN_CTRL_CNT);
+	p->mp_len_data = module_get_register(p->m_cat, CAT_LEN_DATA);
+	p->mp_len_data_lower = register_get_field(p->mp_len_data, CAT_LEN_DATA_LOWER);
+	p->mp_len_data_upper = register_get_field(p->mp_len_data, CAT_LEN_DATA_UPPER);
+	p->mp_len_data_dyn1 = register_get_field(p->mp_len_data, CAT_LEN_DATA_DYN1);
+	p->mp_len_data_dyn2 = register_get_field(p->mp_len_data, CAT_LEN_DATA_DYN2);
+	p->mp_len_data_inv = register_get_field(p->mp_len_data, CAT_LEN_DATA_INV);
+
+	p->mp_cfn_data_ptc_cfp =
+		register_query_field(p->mp_cfn_data, CAT_CFN_DATA_PTC_CFP);
+	p->mp_cfn_data_err_l3_cs =
+		register_query_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_L3_CS);
+	p->mp_cfn_data_err_l4_cs =
+		register_query_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_L4_CS);
+	p->mp_cfn_data_err_tnl_l3_cs =
+		register_query_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_TNL_L3_CS);
+	p->mp_cfn_data_err_tnl_l4_cs =
+		register_query_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_TNL_L4_CS);
+	p->mp_cfn_data_err_ttl_exp =
+		register_query_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_TTL_EXP);
+	p->mp_cfn_data_err_tnl_ttl_exp =
+		register_query_field(p->mp_cfn_data, CAT_CFN_DATA_ERR_TNL_TTL_EXP);
+
+	p->mp_kcc_ctrl = module_query_register(p->m_cat, CAT_KCC_CTRL);
+	if (p->mp_kcc_ctrl != NULL) {
+		p->mp_kcc_addr =
+			register_query_field(p->mp_kcc_ctrl, CAT_KCC_CTRL_ADR);
+		p->mp_kcc_cnt =
+			register_query_field(p->mp_kcc_ctrl, CAT_KCC_CTRL_CNT);
+	}
+	p->mp_kcc_data = module_query_register(p->m_cat, CAT_KCC_DATA);
+	if (p->mp_kcc_data != NULL) {
+		p->mp_kcc_data_key =
+			register_query_field(p->mp_kcc_data, CAT_KCC_DATA_KEY);
+		p->mp_kcc_data_category =
+			register_query_field(p->mp_kcc_data, CAT_KCC_DATA_CATEGORY);
+		p->mp_kcc_data_id =
+			register_query_field(p->mp_kcc_data, CAT_KCC_DATA_ID);
+	}
+
+	p->mp_cce_ctrl = module_query_register(p->m_cat, CAT_CCE_CTRL);
+	if (p->mp_cce_ctrl != NULL) {
+		p->mp_cce_addr =
+			register_query_field(p->mp_cce_ctrl, CAT_CCE_CTRL_ADR);
+		p->mp_cce_cnt =
+			register_query_field(p->mp_cce_ctrl, CAT_CCE_CTRL_CNT);
+	}
+	p->mp_cce_data = module_query_register(p->m_cat, CAT_CCE_DATA);
+	if (p->mp_cce_data != NULL) {
+		p->mp_cce_data_imm =
+			register_query_field(p->mp_cce_data, CAT_CCE_DATA_IMM);
+		p->mp_cce_data_ind =
+			register_query_field(p->mp_cce_data, CAT_CCE_DATA_IND);
+	}
+
+	p->mp_ccs_ctrl = module_query_register(p->m_cat, CAT_CCS_CTRL);
+	if (p->mp_ccs_ctrl != NULL) {
+		p->mp_ccs_addr =
+			register_query_field(p->mp_ccs_ctrl, CAT_CCS_CTRL_ADR);
+		p->mp_ccs_cnt =
+			register_query_field(p->mp_ccs_ctrl, CAT_CCS_CTRL_CNT);
+	}
+	p->mp_ccs_data = module_query_register(p->m_cat, CAT_CCS_DATA);
+	if (p->mp_ccs_data != NULL) {
+		p->mp_ccs_data_cor_en =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_COR_EN);
+		p->mp_ccs_data_cor =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_COR);
+		p->mp_ccs_data_hsh_en =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_HSH_EN);
+		p->mp_ccs_data_hsh =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_HSH);
+		p->mp_ccs_data_qsl_en =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_QSL_EN);
+		p->mp_ccs_data_qsl =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_QSL);
+		p->mp_ccs_data_ipf_en =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_IPF_EN);
+		p->mp_ccs_data_ipf =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_IPF);
+		p->mp_ccs_data_slc_en =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_SLC_EN);
+		p->mp_ccs_data_slc =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_SLC);
+		p->mp_ccs_data_pdb_en =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_PDB_EN);
+		p->mp_ccs_data_pdb =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_PDB);
+		p->mp_ccs_data_msk_en =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_MSK_EN);
+		p->mp_ccs_data_msk =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_MSK);
+		p->mp_ccs_data_hst_en =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_HST_EN);
+		p->mp_ccs_data_hst =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_HST);
+		p->mp_ccs_data_epp_en =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_EPP_EN);
+		p->mp_ccs_data_epp =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_EPP);
+		p->mp_ccs_data_tpe_en =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_TPE_EN);
+		p->mp_ccs_data_tpe =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_TPE);
+		p->mp_ccs_data_rrb_en =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_RRB_EN);
+		p->mp_ccs_data_rrb =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_RRB);
+		p->mp_ccs_data_sb0_type =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_SB0_TYPE);
+		p->mp_ccs_data_sb0_data =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_SB0_DATA);
+		p->mp_ccs_data_sb1_type =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_SB1_TYPE);
+		p->mp_ccs_data_sb1_data =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_SB1_DATA);
+		p->mp_ccs_data_sb2_type =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_SB2_TYPE);
+		p->mp_ccs_data_sb2_data =
+			register_query_field(p->mp_ccs_data, CAT_CCS_DATA_SB2_DATA);
+	}
+
+	return 0;
+}
+
+/* CFN */
+void cat_nthw_cfn_select(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_addr, val);
+}
+
+void r(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_cnt, val);
+}
+
+void cat_nthw_cfn_enable(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_data_enable, val);
+}
+
+void cat_nthw_cfn_inv(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_data_inv, val);
+}
+
+void cat_nthw_cfn_ptc_inv(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_data_ptc_inv, val);
+}
+
+void cat_nthw_cfn_ptc_isl(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_data_ptc_isl, val);
+}
+
+void cat_nthw_cfn_ptc_mac(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_data_ptc_mac, val);
+}
+
+void cat_nthw_cfn_ptc_l2(const struct cat_nthw *p, uint32_t val)
+{
+	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)
+{
+	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)
+{
+	field_set_val32(p->mp_cfn_data_ptc_vlan, val);
+}
+
+void cat_nthw_cfn_ptc_mpls(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_data_ptc_mpls, val);
+}
+
+void cat_nthw_cfn_ptc_l3(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_data_ptc_l3, val);
+}
+
+void cat_nthw_cfn_ptc_frag(const struct cat_nthw *p, uint32_t val)
+{
+	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)
+{
+	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)
+{
+	field_set_val32(p->mp_cfn_data_ptc_l4, val);
+}
+
+void cat_nthw_cfn_ptc_tunnel(const struct cat_nthw *p, uint32_t val)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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);
+	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);
+	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);
+	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);
+	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);
+	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);
+	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);
+	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)
+{
+	field_set_val32(p->mp_cfn_data_err_inv, val);
+}
+
+void cat_nthw_cfn_err_cv(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_data_err_cv, val);
+}
+
+void cat_nthw_cfn_err_fcs(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_data_err_fcs, val);
+}
+
+void cat_nthw_cfn_err_trunc(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_data_err_trunc, val);
+}
+
+void cat_nthw_cfn_mac_port(const struct cat_nthw *p, uint32_t val)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	field_set_val32(p->mp_cfn_data_pm_inv, val);
+}
+
+void cat_nthw_cfn_lc(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_data_lc, val);
+}
+
+void cat_nthw_cfn_lc_inv(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cfn_data_lc_inv, val);
+}
+
+void cat_nthw_cfn_km0_or(const struct cat_nthw *p, uint32_t val)
+{
+	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);
+	field_set_val32(p->mp_cfn_data_km1_or, val);
+}
+
+void cat_nthw_cfn_flush(const struct cat_nthw *p)
+{
+	register_flush(p->mp_cfn_ctrl, 1);
+	register_flush(p->mp_cfn_data, 1);
+}
+
+void cat_nthw_kce_select(const struct cat_nthw *p, int index, uint32_t val)
+{
+	field_set_val32(p->mp_kce_addr[index], val);
+}
+
+void cat_nthw_kce_cnt(const struct cat_nthw *p, int index, uint32_t val)
+{
+	field_set_val32(p->mp_kce_cnt[index], val);
+}
+
+void cat_nthw_kce_enable(const struct cat_nthw *p, int index, uint32_t val)
+{
+	field_set_val32(p->mp_kce_data_enable[index], val);
+}
+
+void cat_nthw_kce_flush(const struct cat_nthw *p, int index)
+{
+	register_flush(p->mp_kce_ctrl[index], 1);
+	register_flush(p->mp_kce_data[index], 1);
+}
+
+void cat_nthw_kcs_select(const struct cat_nthw *p, int index, uint32_t val)
+{
+	field_set_val32(p->mp_kcs_addr[index], val);
+}
+
+void cat_nthw_kcs_cnt(const struct cat_nthw *p, int index, uint32_t val)
+{
+	field_set_val32(p->mp_kcs_cnt[index], val);
+}
+
+void cat_nthw_kcs_category(const struct cat_nthw *p, int index, uint32_t val)
+{
+	field_set_val32(p->mp_kcs_data_category[index], val);
+}
+
+void cat_nthw_kcs_flush(const struct cat_nthw *p, int index)
+{
+	register_flush(p->mp_kcs_ctrl[index], 1);
+	register_flush(p->mp_kcs_data[index], 1);
+}
+
+void cat_nthw_fte_select(const struct cat_nthw *p, int index, uint32_t val)
+{
+	field_set_val32(p->mp_fte_addr[index], val);
+}
+
+void cat_nthw_fte_cnt(const struct cat_nthw *p, int index, uint32_t val)
+{
+	field_set_val32(p->mp_fte_cnt[index], val);
+}
+
+void cat_nthw_fte_enable(const struct cat_nthw *p, int index, uint32_t val)
+{
+	field_set_val32(p->mp_fte_data_enable[index], val);
+}
+
+void cat_nthw_fte_flush(const struct cat_nthw *p, int index)
+{
+	register_flush(p->mp_fte_ctrl[index], 1);
+	register_flush(p->mp_fte_data[index], 1);
+}
+
+void cat_nthw_cte_select(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cte_addr, val);
+}
+
+void cat_nthw_cte_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cte_cnt, val);
+}
+
+void cat_nthw_cte_enable_col(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cte_data_col, val);
+}
+
+void cat_nthw_cte_enable_cor(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cte_data_cor, val);
+}
+
+void cat_nthw_cte_enable_hsh(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cte_data_hsh, val);
+}
+
+void cat_nthw_cte_enable_qsl(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cte_data_qsl, val);
+}
+
+void cat_nthw_cte_enable_ipf(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cte_data_ipf, val);
+}
+
+void cat_nthw_cte_enable_slc(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cte_data_slc, val);
+}
+
+void cat_nthw_cte_enable_pdb(const struct cat_nthw *p, uint32_t val)
+{
+	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);
+	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);
+	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);
+	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);
+	field_set_val32(p->mp_cte_data_tpe, val);
+}
+
+void cat_nthw_cte_enable_rrb(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cte_data_rrb);
+	field_set_val32(p->mp_cte_data_rrb, val);
+}
+
+void cat_nthw_cte_flush(const struct cat_nthw *p)
+{
+	register_flush(p->mp_cte_ctrl, 1);
+	register_flush(p->mp_cte_data, 1);
+}
+
+void cat_nthw_cts_select(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cts_addr, val);
+}
+
+void cat_nthw_cts_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cts_cnt, val);
+}
+
+void cat_nthw_cts_cat_a(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cts_data_cat_a, val);
+}
+
+void cat_nthw_cts_cat_b(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cts_data_cat_b, val);
+}
+
+void cat_nthw_cts_flush(const struct cat_nthw *p)
+{
+	register_flush(p->mp_cts_ctrl, 1);
+	register_flush(p->mp_cts_data, 1);
+}
+
+void cat_nthw_cot_select(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cot_addr, val);
+}
+
+void cat_nthw_cot_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cot_cnt, val);
+}
+
+void cat_nthw_cot_color(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cot_data_color, val);
+}
+
+void cat_nthw_cot_km(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cot_data_km, val);
+}
+
+void cat_nthw_cot_nfv_sb(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cot_data_nfv_sb);
+	field_set_val32(p->mp_cot_data_nfv_sb, val);
+}
+
+void cat_nthw_cot_flush(const struct cat_nthw *p)
+{
+	register_flush(p->mp_cot_ctrl, 1);
+	register_flush(p->mp_cot_data, 1);
+}
+
+void cat_nthw_cct_select(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cct_addr, val);
+}
+
+void cat_nthw_cct_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cct_cnt, val);
+}
+
+void cat_nthw_cct_color(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cct_data_color, val);
+}
+
+void cat_nthw_cct_km(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cct_data_km, val);
+}
+
+void cat_nthw_cct_flush(const struct cat_nthw *p)
+{
+	register_flush(p->mp_cct_ctrl, 1);
+	register_flush(p->mp_cct_data, 1);
+}
+
+void cat_nthw_exo_select(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_exo_addr, val);
+}
+
+void cat_nthw_exo_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_exo_cnt, val);
+}
+
+void cat_nthw_exo_dyn(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_exo_data_dyn, val);
+}
+
+void cat_nthw_exo_ofs(const struct cat_nthw *p, int32_t val)
+{
+	field_set_val32(p->mp_exo_data_ofs, val);
+}
+
+void cat_nthw_exo_flush(const struct cat_nthw *p)
+{
+	register_flush(p->mp_exo_ctrl, 1);
+	register_flush(p->mp_exo_data, 1);
+}
+
+void cat_nthw_rck_select(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rck_addr, val);
+}
+
+void cat_nthw_rck_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rck_cnt, val);
+}
+
+void cat_nthw_rck_data(const struct cat_nthw *p, uint32_t val)
+{
+	register_set_val(p->mp_rck_data, &val, 1);
+	register_make_dirty(p->mp_rck_data);
+}
+
+void cat_nthw_rck_flush(const struct cat_nthw *p)
+{
+	register_flush(p->mp_rck_ctrl, 1);
+	register_flush(p->mp_rck_data, 1);
+}
+
+void cat_nthw_len_select(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_len_addr, val);
+}
+
+void cat_nthw_len_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_len_cnt, val);
+}
+
+void cat_nthw_len_lower(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_len_data_lower, val);
+}
+
+void cat_nthw_len_upper(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_len_data_upper, val);
+}
+
+void cat_nthw_len_dyn1(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_len_data_dyn1, val);
+}
+
+void cat_nthw_len_dyn2(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_len_data_dyn2, val);
+}
+
+void cat_nthw_len_inv(const struct cat_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_len_data_inv, val);
+}
+
+void cat_nthw_len_flush(const struct cat_nthw *p)
+{
+	register_flush(p->mp_len_ctrl, 1);
+	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);
+	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);
+	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);
+	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);
+	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);
+	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);
+	register_flush(p->mp_kcc_ctrl, 1);
+	register_flush(p->mp_kcc_data, 1);
+}
+
+void cat_nthw_cce_select(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cce_addr);
+	field_set_val32(p->mp_cce_addr, val);
+}
+
+void cat_nthw_cce_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cce_cnt);
+	field_set_val32(p->mp_cce_cnt, val);
+}
+
+void cat_nthw_cce_data_imm(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cce_data_imm);
+	field_set_val32(p->mp_cce_data_imm, val);
+}
+
+void cat_nthw_cce_data_ind(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_cce_data_ind);
+	field_set_val32(p->mp_cce_data_ind, val);
+}
+
+void cat_nthw_cce_flush(const struct cat_nthw *p)
+{
+	assert(p->mp_cce_ctrl);
+	assert(p->mp_cce_data);
+	register_flush(p->mp_cce_ctrl, 1);
+	register_flush(p->mp_cce_data, 1);
+}
+
+void cat_nthw_ccs_select(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_ccs_addr);
+	field_set_val32(p->mp_ccs_addr, val);
+}
+
+void cat_nthw_ccs_cnt(const struct cat_nthw *p, uint32_t val)
+{
+	assert(p->mp_ccs_cnt);
+	field_set_val32(p->mp_ccs_cnt, val);
+}
+
+#define CATNTHW_CCS_SET(name)                                             \
+	void cat_nthw_ccs_data_##name(const struct cat_nthw *p, uint32_t val) \
+	{                                                                 \
+		assert(p->mp_ccs_data_##name);                               \
+		field_set_val32(p->mp_ccs_data_##name, val);                  \
+	}
+
+CATNTHW_CCS_SET(cor_en);
+CATNTHW_CCS_SET(cor);
+CATNTHW_CCS_SET(hsh_en);
+CATNTHW_CCS_SET(hsh);
+CATNTHW_CCS_SET(qsl_en);
+CATNTHW_CCS_SET(qsl);
+CATNTHW_CCS_SET(ipf_en);
+CATNTHW_CCS_SET(ipf);
+CATNTHW_CCS_SET(slc_en);
+CATNTHW_CCS_SET(slc);
+CATNTHW_CCS_SET(pdb_en);
+CATNTHW_CCS_SET(pdb);
+CATNTHW_CCS_SET(msk_en);
+CATNTHW_CCS_SET(msk);
+CATNTHW_CCS_SET(hst_en);
+CATNTHW_CCS_SET(hst);
+CATNTHW_CCS_SET(epp_en);
+CATNTHW_CCS_SET(epp);
+CATNTHW_CCS_SET(tpe_en);
+CATNTHW_CCS_SET(tpe);
+CATNTHW_CCS_SET(rrb_en);
+CATNTHW_CCS_SET(rrb);
+CATNTHW_CCS_SET(sb0_type);
+CATNTHW_CCS_SET(sb0_data);
+CATNTHW_CCS_SET(sb1_type);
+CATNTHW_CCS_SET(sb1_data);
+CATNTHW_CCS_SET(sb2_type);
+CATNTHW_CCS_SET(sb2_data);
+
+void cat_nthw_ccs_flush(const struct cat_nthw *p)
+{
+	assert(p->mp_ccs_ctrl);
+	assert(p->mp_ccs_data);
+	register_flush(p->mp_ccs_ctrl, 1);
+	register_flush(p->mp_ccs_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..41ac891a93
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_cat.h
@@ -0,0 +1,372 @@
+/* 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> /* uint32_t */
+#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, nt_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 r(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_enable_rrb(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_nfv_sb(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);
+/* CCE */
+void cat_nthw_cce_select(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cce_cnt(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cce_data_imm(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cce_data_ind(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_cce_flush(const struct cat_nthw *p);
+/* CCS */
+void cat_nthw_ccs_select(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_cnt(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_cor_en(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_cor(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_hsh_en(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_hsh(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_qsl_en(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_qsl(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_ipf_en(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_ipf(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_slc_en(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_slc(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_pdb_en(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_pdb(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_msk_en(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_msk(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_hst_en(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_hst(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_epp_en(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_epp(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_tpe_en(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_tpe(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_rrb_en(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_rrb(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_sb0_type(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_sb0_data(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_sb1_type(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_sb1_data(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_sb2_type(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_data_sb2_data(const struct cat_nthw *p, uint32_t val);
+void cat_nthw_ccs_flush(const struct cat_nthw *p);
+
+struct cat_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_fpga_t *mp_fpga;
+	nt_module_t *m_cat;
+	int m_km_if_cnt;
+
+	nt_register_t *mp_cfn_ctrl;
+	nt_field_t *mp_cfn_addr;
+	nt_field_t *mp_cfn_cnt;
+	nt_register_t *mp_cfn_data;
+	nt_field_t *mp_cfn_data_enable;
+	nt_field_t *mp_cfn_data_inv;
+	nt_field_t *mp_cfn_data_ptc_inv;
+	nt_field_t *mp_cfn_data_ptc_isl;
+	nt_field_t *mp_cfn_data_ptc_cfp;
+	nt_field_t *mp_cfn_data_ptc_mac;
+	nt_field_t *mp_cfn_data_ptc_l2;
+	nt_field_t *mp_cfn_data_ptc_vn_tag;
+	nt_field_t *mp_cfn_data_ptc_vlan;
+	nt_field_t *mp_cfn_data_ptc_mpls;
+	nt_field_t *mp_cfn_data_ptc_l3;
+	nt_field_t *mp_cfn_data_ptc_frag;
+	nt_field_t *mp_cfn_data_ptc_ip_prot;
+	nt_field_t *mp_cfn_data_ptc_l4;
+	nt_field_t *mp_cfn_data_ptc_tunnel;
+	nt_field_t *mp_cfn_data_ptc_tnl_l2;
+	nt_field_t *mp_cfn_data_ptc_tnl_vlan;
+	nt_field_t *mp_cfn_data_ptc_tnl_mpls;
+	nt_field_t *mp_cfn_data_ptc_tnl_l3;
+	nt_field_t *mp_cfn_data_ptc_tnl_frag;
+	nt_field_t *mp_cfn_data_ptc_tnl_ip_prot;
+	nt_field_t *mp_cfn_data_ptc_tnl_l4;
+	nt_field_t *mp_cfn_data_err_inv;
+	nt_field_t *mp_cfn_data_err_cv;
+	nt_field_t *mp_cfn_data_err_fcs;
+	nt_field_t *mp_cfn_data_err_trunc;
+	nt_field_t *mp_cfn_data_err_l3_cs;
+	nt_field_t *mp_cfn_data_err_l4_cs;
+	nt_field_t *mp_cfn_data_err_tnl_l3_cs;
+	nt_field_t *mp_cfn_data_err_tnl_l4_cs;
+	nt_field_t *mp_cfn_data_err_ttl_exp;
+	nt_field_t *mp_cfn_data_err_tnl_ttl_exp;
+	nt_field_t *mp_cfn_data_mac_port;
+	nt_field_t *mp_cfn_data_pm_cmp;
+	nt_field_t *mp_cfn_data_pm_dct;
+	nt_field_t *mp_cfn_data_pm_ext_inv;
+	nt_field_t *mp_cfn_data_pm_cmb;
+	nt_field_t *mp_cfn_data_pm_and_inv;
+	nt_field_t *mp_cfn_data_pm_or_inv;
+	nt_field_t *mp_cfn_data_pm_inv;
+	nt_field_t *mp_cfn_data_lc;
+	nt_field_t *mp_cfn_data_lc_inv;
+	nt_field_t *mp_cfn_data_km0_or;
+	nt_field_t *mp_cfn_data_km1_or;
+
+	nt_register_t *mp_kce_ctrl[2];
+	nt_field_t *mp_kce_addr[2];
+	nt_field_t *mp_kce_cnt[2];
+	nt_register_t *mp_kce_data[2];
+	nt_field_t *mp_kce_data_enable[2];
+
+	nt_register_t *mp_kcs_ctrl[2];
+	nt_field_t *mp_kcs_addr[2];
+	nt_field_t *mp_kcs_cnt[2];
+	nt_register_t *mp_kcs_data[2];
+	nt_field_t *mp_kcs_data_category[2];
+
+	nt_register_t *mp_fte_ctrl[2];
+	nt_field_t *mp_fte_addr[2];
+	nt_field_t *mp_fte_cnt[2];
+	nt_register_t *mp_fte_data[2];
+	nt_field_t *mp_fte_data_enable[2];
+
+	nt_register_t *mp_cte_ctrl;
+	nt_field_t *mp_cte_addr;
+	nt_field_t *mp_cte_cnt;
+	nt_register_t *mp_cte_data;
+	nt_field_t *mp_cte_data_col;
+	nt_field_t *mp_cte_data_cor;
+	nt_field_t *mp_cte_data_hsh;
+	nt_field_t *mp_cte_data_qsl;
+	nt_field_t *mp_cte_data_ipf;
+	nt_field_t *mp_cte_data_slc;
+	nt_field_t *mp_cte_data_pdb;
+	nt_field_t *mp_cte_data_msk;
+	nt_field_t *mp_cte_data_hst;
+	nt_field_t *mp_cte_data_epp;
+	nt_field_t *mp_cte_data_tpe;
+	nt_field_t *mp_cte_data_rrb;
+
+	nt_register_t *mp_cts_ctrl;
+	nt_field_t *mp_cts_addr;
+	nt_field_t *mp_cts_cnt;
+	nt_register_t *mp_cts_data;
+	nt_field_t *mp_cts_data_cat_a;
+	nt_field_t *mp_cts_data_cat_b;
+
+	nt_register_t *mp_cot_ctrl;
+	nt_field_t *mp_cot_addr;
+	nt_field_t *mp_cot_cnt;
+	nt_register_t *mp_cot_data;
+	nt_field_t *mp_cot_data_color;
+	nt_field_t *mp_cot_data_km;
+	nt_field_t *mp_cot_data_nfv_sb;
+
+	nt_register_t *mp_cct_ctrl;
+	nt_field_t *mp_cct_addr;
+	nt_field_t *mp_cct_cnt;
+	nt_register_t *mp_cct_data;
+	nt_field_t *mp_cct_data_color;
+	nt_field_t *mp_cct_data_km;
+
+	nt_register_t *mp_exo_ctrl;
+	nt_field_t *mp_exo_addr;
+	nt_field_t *mp_exo_cnt;
+	nt_register_t *mp_exo_data;
+	nt_field_t *mp_exo_data_dyn;
+	nt_field_t *mp_exo_data_ofs;
+
+	nt_register_t *mp_rck_ctrl;
+	nt_field_t *mp_rck_addr;
+	nt_field_t *mp_rck_cnt;
+	nt_register_t *mp_rck_data;
+
+	nt_register_t *mp_len_ctrl;
+	nt_field_t *mp_len_addr;
+	nt_field_t *mp_len_cnt;
+	nt_register_t *mp_len_data;
+	nt_field_t *mp_len_data_lower;
+	nt_field_t *mp_len_data_upper;
+	nt_field_t *mp_len_data_dyn1;
+	nt_field_t *mp_len_data_dyn2;
+	nt_field_t *mp_len_data_inv;
+	nt_register_t *mp_kcc_ctrl;
+	nt_field_t *mp_kcc_addr;
+	nt_field_t *mp_kcc_cnt;
+
+	nt_register_t *mp_kcc_data;
+	nt_field_t *mp_kcc_data_key;
+	nt_field_t *mp_kcc_data_category;
+	nt_field_t *mp_kcc_data_id;
+
+	nt_register_t *mp_cce_ctrl;
+	nt_field_t *mp_cce_addr;
+	nt_field_t *mp_cce_cnt;
+
+	nt_register_t *mp_cce_data;
+	nt_field_t *mp_cce_data_imm;
+	nt_field_t *mp_cce_data_ind;
+
+	nt_register_t *mp_ccs_ctrl;
+	nt_field_t *mp_ccs_addr;
+	nt_field_t *mp_ccs_cnt;
+
+	nt_register_t *mp_ccs_data;
+	nt_field_t *mp_ccs_data_cor_en;
+	nt_field_t *mp_ccs_data_cor;
+
+	nt_field_t *mp_ccs_data_hsh_en;
+	nt_field_t *mp_ccs_data_hsh;
+	nt_field_t *mp_ccs_data_qsl_en;
+	nt_field_t *mp_ccs_data_qsl;
+	nt_field_t *mp_ccs_data_ipf_en;
+	nt_field_t *mp_ccs_data_ipf;
+	nt_field_t *mp_ccs_data_slc_en;
+	nt_field_t *mp_ccs_data_slc;
+	nt_field_t *mp_ccs_data_pdb_en;
+	nt_field_t *mp_ccs_data_pdb;
+	nt_field_t *mp_ccs_data_msk_en;
+	nt_field_t *mp_ccs_data_msk;
+	nt_field_t *mp_ccs_data_hst_en;
+	nt_field_t *mp_ccs_data_hst;
+	nt_field_t *mp_ccs_data_epp_en;
+	nt_field_t *mp_ccs_data_epp;
+	nt_field_t *mp_ccs_data_tpe_en;
+	nt_field_t *mp_ccs_data_tpe;
+	nt_field_t *mp_ccs_data_rrb_en;
+	nt_field_t *mp_ccs_data_rrb;
+	nt_field_t *mp_ccs_data_sb0_type;
+	nt_field_t *mp_ccs_data_sb0_data;
+	nt_field_t *mp_ccs_data_sb1_type;
+	nt_field_t *mp_ccs_data_sb1_data;
+	nt_field_t *mp_ccs_data_sb2_type;
+	nt_field_t *mp_ccs_data_sb2_data;
+};
+
+#endif /* __FLOW_NTHW_CAT_H__ */
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..5a7f90ad69
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.c
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_csu.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+void csu_nthw_set_debug_mode(struct csu_nthw *p, unsigned int n_debug_mode)
+{
+	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));
+
+	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, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = module_get_register(p->m_csu, CSU_RCP_CTRL);
+	p->mp_rcp_ctrl_adr = register_get_field(p->mp_rcp_ctrl, CSU_RCP_CTRL_ADR);
+	p->mp_rcp_ctrl_cnt = register_get_field(p->mp_rcp_ctrl, CSU_RCP_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_csu, CSU_RCP_DATA);
+	p->mp_rcp_data_ol3_cmd =
+		register_get_field(p->mp_rcp_data, CSU_RCP_DATA_OL3_CMD);
+	p->mp_rcp_data_ol4_cmd =
+		register_get_field(p->mp_rcp_data, CSU_RCP_DATA_OL4_CMD);
+	p->mp_rcp_data_il3_cmd =
+		register_get_field(p->mp_rcp_data, CSU_RCP_DATA_IL3_CMD);
+	p->mp_rcp_data_il4_cmd =
+		register_get_field(p->mp_rcp_data, CSU_RCP_DATA_IL4_CMD);
+
+	return 0;
+}
+
+void csu_nthw_rcp_select(const struct csu_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_ctrl_adr, val);
+}
+
+void csu_nthw_rcp_cnt(const struct csu_nthw *p, uint32_t val)
+{
+	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.
+	 */
+	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.
+	 */
+	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.
+	 */
+	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.
+	 */
+	field_set_val32(p->mp_rcp_data_il4_cmd, val);
+}
+
+void csu_nthw_rcp_flush(const struct csu_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	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
new file mode 100644
index 0000000000..6cb0e1f781
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_csu.h
@@ -0,0 +1,42 @@
+/* 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;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_csu;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_ctrl_adr;
+	nt_field_t *mp_rcp_ctrl_cnt;
+	nt_register_t *mp_rcp_data;
+	nt_field_t *mp_rcp_data_ol3_cmd;
+	nt_field_t *mp_rcp_data_ol4_cmd;
+	nt_field_t *mp_rcp_data_il3_cmd;
+	nt_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, nt_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_flm.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.c
new file mode 100644
index 0000000000..4549898cc1
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.c
@@ -0,0 +1,1140 @@
+/* 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_rac.h"
+
+#include "flow_nthw_flm.h"
+
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+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)
+{
+	module_set_debug_mode(p->m_flm, n_debug_mode);
+}
+
+int flm_nthw_init(struct flm_nthw *p, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = module_get_register(p->m_flm, FLM_CONTROL);
+	p->mp_control_enable =
+		register_get_field(p->mp_control, FLM_CONTROL_ENABLE);
+	p->mp_control_init = register_get_field(p->mp_control, FLM_CONTROL_INIT);
+	p->mp_control_lds = register_get_field(p->mp_control, FLM_CONTROL_LDS);
+	p->mp_control_lfs = register_get_field(p->mp_control, FLM_CONTROL_LFS);
+	p->mp_control_lis = register_get_field(p->mp_control, FLM_CONTROL_LIS);
+	p->mp_control_uds = register_get_field(p->mp_control, FLM_CONTROL_UDS);
+	p->mp_control_uis = register_get_field(p->mp_control, FLM_CONTROL_UIS);
+	p->mp_control_rds = register_get_field(p->mp_control, FLM_CONTROL_RDS);
+	p->mp_control_ris = register_get_field(p->mp_control, FLM_CONTROL_RIS);
+	p->mp_control_pds = register_query_field(p->mp_control, FLM_CONTROL_PDS);
+	p->mp_control_pis = register_query_field(p->mp_control, FLM_CONTROL_PIS);
+	p->mp_control_crcwr = register_get_field(p->mp_control, FLM_CONTROL_CRCWR);
+	p->mp_control_crcrd = register_get_field(p->mp_control, FLM_CONTROL_CRCRD);
+	p->mp_control_rbl = register_get_field(p->mp_control, FLM_CONTROL_RBL);
+	p->mp_control_eab = register_get_field(p->mp_control, FLM_CONTROL_EAB);
+	p->mp_control_split_sdram_usage =
+		register_get_field(p->mp_control, FLM_CONTROL_SPLIT_SDRAM_USAGE);
+
+	p->mp_status = module_get_register(p->m_flm, FLM_STATUS);
+	p->mp_status_calibdone =
+		register_get_field(p->mp_status, FLM_STATUS_CALIBDONE);
+	p->mp_status_initdone =
+		register_get_field(p->mp_status, FLM_STATUS_INITDONE);
+	p->mp_status_idle = register_get_field(p->mp_status, FLM_STATUS_IDLE);
+	p->mp_status_critical =
+		register_get_field(p->mp_status, FLM_STATUS_CRITICAL);
+	p->mp_status_panic = register_get_field(p->mp_status, FLM_STATUS_PANIC);
+	p->mp_status_crcerr = register_get_field(p->mp_status, FLM_STATUS_CRCERR);
+	p->mp_status_eft_bp = register_get_field(p->mp_status, FLM_STATUS_EFT_BP);
+
+	p->mp_timeout = module_get_register(p->m_flm, FLM_TIMEOUT);
+	p->mp_timeout_t = register_get_field(p->mp_timeout, FLM_TIMEOUT_T);
+
+	p->mp_scrub = module_get_register(p->m_flm, FLM_SCRUB);
+	p->mp_scrub_i = register_get_field(p->mp_scrub, FLM_SCRUB_I);
+
+	p->mp_load_bin = module_get_register(p->m_flm, FLM_LOAD_BIN);
+	p->mp_load_bin_bin = register_get_field(p->mp_load_bin, FLM_LOAD_BIN_BIN);
+
+	p->mp_load_pps = module_get_register(p->m_flm, FLM_LOAD_PPS);
+	p->mp_load_pps_pps = register_get_field(p->mp_load_pps, FLM_LOAD_PPS_PPS);
+
+	p->mp_load_lps = module_get_register(p->m_flm, FLM_LOAD_LPS);
+	p->mp_load_lps_lps = register_get_field(p->mp_load_lps, FLM_LOAD_LPS_LPS);
+
+	p->mp_load_aps = module_get_register(p->m_flm, FLM_LOAD_APS);
+	p->mp_load_aps_aps = register_get_field(p->mp_load_aps, FLM_LOAD_APS_APS);
+
+	p->mp_prio = module_get_register(p->m_flm, FLM_PRIO);
+	p->mp_prio_limit0 = register_get_field(p->mp_prio, FLM_PRIO_LIMIT0);
+	p->mp_prio_ft0 = register_get_field(p->mp_prio, FLM_PRIO_FT0);
+	p->mp_prio_limit1 = register_get_field(p->mp_prio, FLM_PRIO_LIMIT1);
+	p->mp_prio_ft1 = register_get_field(p->mp_prio, FLM_PRIO_FT1);
+	p->mp_prio_limit2 = register_get_field(p->mp_prio, FLM_PRIO_LIMIT2);
+	p->mp_prio_ft2 = register_get_field(p->mp_prio, FLM_PRIO_FT2);
+	p->mp_prio_limit3 = register_get_field(p->mp_prio, FLM_PRIO_LIMIT3);
+	p->mp_prio_ft3 = register_get_field(p->mp_prio, FLM_PRIO_FT3);
+
+	p->mp_pst_ctrl = module_get_register(p->m_flm, FLM_PST_CTRL);
+	p->mp_pst_ctrl_adr = register_get_field(p->mp_pst_ctrl, FLM_PST_CTRL_ADR);
+	p->mp_pst_ctrl_cnt = register_get_field(p->mp_pst_ctrl, FLM_PST_CTRL_CNT);
+	p->mp_pst_data = module_get_register(p->m_flm, FLM_PST_DATA);
+	p->mp_pst_data_bp = register_get_field(p->mp_pst_data, FLM_PST_DATA_BP);
+	p->mp_pst_data_pp = register_get_field(p->mp_pst_data, FLM_PST_DATA_PP);
+	p->mp_pst_data_tp = register_get_field(p->mp_pst_data, FLM_PST_DATA_TP);
+
+	p->mp_rcp_ctrl = module_get_register(p->m_flm, FLM_RCP_CTRL);
+	p->mp_rcp_ctrl_adr = register_get_field(p->mp_rcp_ctrl, FLM_RCP_CTRL_ADR);
+	p->mp_rcp_ctrl_cnt = register_get_field(p->mp_rcp_ctrl, FLM_RCP_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_flm, FLM_RCP_DATA);
+	p->mp_rcp_data_lookup =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_LOOKUP);
+	p->mp_rcp_data_qw0_dyn =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_QW0_DYN);
+	p->mp_rcp_data_qw0_ofs =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_QW0_OFS);
+	p->mp_rcp_data_qw0_sel =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_QW0_SEL);
+	p->mp_rcp_data_qw4_dyn =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_QW4_DYN);
+	p->mp_rcp_data_qw4_ofs =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_QW4_OFS);
+	p->mp_rcp_data_sw8_dyn =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_SW8_DYN);
+	p->mp_rcp_data_sw8_ofs =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_SW8_OFS);
+	p->mp_rcp_data_sw8_sel =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_SW8_SEL);
+	p->mp_rcp_data_sw9_dyn =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_SW9_DYN);
+	p->mp_rcp_data_sw9_ofs =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_SW9_OFS);
+	p->mp_rcp_data_mask = register_get_field(p->mp_rcp_data, FLM_RCP_DATA_MASK);
+	p->mp_rcp_data_kid = register_get_field(p->mp_rcp_data, FLM_RCP_DATA_KID);
+	p->mp_rcp_data_opn = register_get_field(p->mp_rcp_data, FLM_RCP_DATA_OPN);
+	p->mp_rcp_data_ipn = register_get_field(p->mp_rcp_data, FLM_RCP_DATA_IPN);
+	p->mp_rcp_data_byt_dyn =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_BYT_DYN);
+	p->mp_rcp_data_byt_ofs =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_BYT_OFS);
+	p->mp_rcp_data_txplm = register_get_field(p->mp_rcp_data, FLM_RCP_DATA_TXPLM);
+	p->mp_rcp_data_auto_ipv4_mask =
+		register_get_field(p->mp_rcp_data, FLM_RCP_DATA_AUTO_IPV4_MASK);
+
+	p->mp_buf_ctrl = module_get_register(p->m_flm, FLM_BUF_CTRL);
+
+	p->mp_lrn_data = module_get_register(p->m_flm, FLM_LRN_DATA);
+	p->mp_inf_data = module_get_register(p->m_flm, FLM_INF_DATA);
+	p->mp_sta_data = module_get_register(p->m_flm, FLM_STA_DATA);
+
+	p->mp_stat_lrn_done = module_get_register(p->m_flm, FLM_STAT_LRN_DONE);
+	p->mp_stat_lrn_done_cnt =
+		register_get_field(p->mp_stat_lrn_done, FLM_STAT_LRN_DONE_CNT);
+
+	p->mp_stat_lrn_ignore = module_get_register(p->m_flm, FLM_STAT_LRN_IGNORE);
+	p->mp_stat_lrn_ignore_cnt =
+		register_get_field(p->mp_stat_lrn_ignore, FLM_STAT_LRN_IGNORE_CNT);
+
+	p->mp_stat_lrn_fail = module_get_register(p->m_flm, FLM_STAT_LRN_FAIL);
+	p->mp_stat_lrn_fail_cnt =
+		register_get_field(p->mp_stat_lrn_fail, FLM_STAT_LRN_FAIL_CNT);
+
+	p->mp_stat_unl_done = module_get_register(p->m_flm, FLM_STAT_UNL_DONE);
+	p->mp_stat_unl_done_cnt =
+		register_get_field(p->mp_stat_unl_done, FLM_STAT_UNL_DONE_CNT);
+
+	p->mp_stat_unl_ignore = module_get_register(p->m_flm, FLM_STAT_UNL_IGNORE);
+	p->mp_stat_unl_ignore_cnt =
+		register_get_field(p->mp_stat_unl_ignore, FLM_STAT_UNL_IGNORE_CNT);
+
+	p->mp_stat_prb_done = module_query_register(p->m_flm, FLM_STAT_PRB_DONE);
+	p->mp_stat_prb_done_cnt =
+		register_query_field(p->mp_stat_prb_done, FLM_STAT_PRB_DONE_CNT);
+
+	p->mp_stat_prb_ignore = module_query_register(p->m_flm, FLM_STAT_PRB_IGNORE);
+	p->mp_stat_prb_ignore_cnt = register_query_field(p->mp_stat_prb_ignore,
+				FLM_STAT_PRB_IGNORE_CNT);
+
+	p->mp_stat_rel_done = module_get_register(p->m_flm, FLM_STAT_REL_DONE);
+	p->mp_stat_rel_done_cnt =
+		register_get_field(p->mp_stat_rel_done, FLM_STAT_REL_DONE_CNT);
+
+	p->mp_stat_rel_ignore = module_get_register(p->m_flm, FLM_STAT_REL_IGNORE);
+	p->mp_stat_rel_ignore_cnt =
+		register_get_field(p->mp_stat_rel_ignore, FLM_STAT_REL_IGNORE_CNT);
+
+	p->mp_stat_aul_done = module_get_register(p->m_flm, FLM_STAT_AUL_DONE);
+	p->mp_stat_aul_done_cnt =
+		register_get_field(p->mp_stat_aul_done, FLM_STAT_AUL_DONE_CNT);
+
+	p->mp_stat_aul_ignore = module_get_register(p->m_flm, FLM_STAT_AUL_IGNORE);
+	p->mp_stat_aul_ignore_cnt =
+		register_get_field(p->mp_stat_aul_ignore, FLM_STAT_AUL_IGNORE_CNT);
+
+	p->mp_stat_aul_fail = module_get_register(p->m_flm, FLM_STAT_AUL_FAIL);
+	p->mp_stat_aul_fail_cnt =
+		register_get_field(p->mp_stat_aul_fail, FLM_STAT_AUL_FAIL_CNT);
+
+	p->mp_stat_tul_done = module_get_register(p->m_flm, FLM_STAT_TUL_DONE);
+	p->mp_stat_tul_done_cnt =
+		register_get_field(p->mp_stat_tul_done, FLM_STAT_TUL_DONE_CNT);
+
+	p->mp_stat_flows = module_get_register(p->m_flm, FLM_STAT_FLOWS);
+	p->mp_stat_flows_cnt =
+		register_get_field(p->mp_stat_flows, FLM_STAT_FLOWS_CNT);
+
+	p->mp_stat_sta_done = module_query_register(p->m_flm, FLM_STAT_STA_DONE);
+	p->mp_stat_sta_done_cnt =
+		register_query_field(p->mp_stat_sta_done, FLM_STAT_STA_DONE_CNT);
+
+	p->mp_stat_inf_done = module_query_register(p->m_flm, FLM_STAT_INF_DONE);
+	p->mp_stat_inf_done_cnt =
+		register_query_field(p->mp_stat_inf_done, FLM_STAT_INF_DONE_CNT);
+
+	p->mp_stat_inf_skip = module_query_register(p->m_flm, FLM_STAT_INF_SKIP);
+	p->mp_stat_inf_skip_cnt =
+		register_query_field(p->mp_stat_inf_skip, FLM_STAT_INF_SKIP_CNT);
+
+	p->mp_stat_pck_hit = module_query_register(p->m_flm, FLM_STAT_PCK_HIT);
+	p->mp_stat_pck_hit_cnt =
+		register_query_field(p->mp_stat_pck_hit, FLM_STAT_PCK_HIT_CNT);
+
+	p->mp_stat_pck_miss = module_query_register(p->m_flm, FLM_STAT_PCK_MISS);
+	p->mp_stat_pck_miss_cnt =
+		register_query_field(p->mp_stat_pck_miss, FLM_STAT_PCK_MISS_CNT);
+
+	p->mp_stat_pck_unh = module_query_register(p->m_flm, FLM_STAT_PCK_UNH);
+	p->mp_stat_pck_unh_cnt =
+		register_query_field(p->mp_stat_pck_unh, FLM_STAT_PCK_UNH_CNT);
+
+	p->mp_stat_pck_dis = module_query_register(p->m_flm, FLM_STAT_PCK_DIS);
+	p->mp_stat_pck_dis_cnt =
+		register_query_field(p->mp_stat_pck_dis, FLM_STAT_PCK_DIS_CNT);
+
+	p->mp_stat_csh_hit = module_query_register(p->m_flm, FLM_STAT_CSH_HIT);
+	p->mp_stat_csh_hit_cnt =
+		register_query_field(p->mp_stat_csh_hit, FLM_STAT_CSH_HIT_CNT);
+
+	p->mp_stat_csh_miss = module_query_register(p->m_flm, FLM_STAT_CSH_MISS);
+	p->mp_stat_csh_miss_cnt =
+		register_query_field(p->mp_stat_csh_miss, FLM_STAT_CSH_MISS_CNT);
+
+	p->mp_stat_csh_unh = module_query_register(p->m_flm, FLM_STAT_CSH_UNH);
+	p->mp_stat_csh_unh_cnt =
+		register_query_field(p->mp_stat_csh_unh, FLM_STAT_CSH_UNH_CNT);
+
+	p->mp_stat_cuc_start = module_query_register(p->m_flm, FLM_STAT_CUC_START);
+	p->mp_stat_cuc_start_cnt =
+		register_query_field(p->mp_stat_cuc_start, FLM_STAT_CUC_START_CNT);
+
+	p->mp_stat_cuc_move = module_query_register(p->m_flm, FLM_STAT_CUC_MOVE);
+	p->mp_stat_cuc_move_cnt =
+		register_query_field(p->mp_stat_cuc_move, FLM_STAT_CUC_MOVE_CNT);
+
+	return 0;
+}
+
+void flm_nthw_control_enable(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_enable, val);
+}
+
+void flm_nthw_control_init(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_init, val);
+}
+
+void flm_nthw_control_lds(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_lds, val);
+}
+
+void flm_nthw_control_lfs(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_lfs, val);
+}
+
+void flm_nthw_control_lis(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_lis, val);
+}
+
+void flm_nthw_control_uds(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_uds, val);
+}
+
+void flm_nthw_control_uis(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_uis, val);
+}
+
+void flm_nthw_control_rds(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_rds, val);
+}
+
+void flm_nthw_control_ris(const struct flm_nthw *p, uint32_t val)
+{
+	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);
+	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);
+	field_set_val32(p->mp_control_pis, val);
+}
+
+void flm_nthw_control_crcwr(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_crcwr, val);
+}
+
+void flm_nthw_control_crcrd(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_crcrd, val);
+}
+
+void flm_nthw_control_rbl(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_rbl, val);
+}
+
+void flm_nthw_control_eab(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_eab, val);
+}
+
+void flm_nthw_control_split_sdram_usage(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_control_split_sdram_usage, val);
+}
+
+void flm_nthw_control_flush(const struct flm_nthw *p)
+{
+	register_flush(p->mp_control, 1);
+}
+
+void flm_nthw_status_calibdone(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = field_get_val32(p->mp_status_calibdone);
+}
+
+void flm_nthw_status_initdone(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = 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 = 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 = field_get_val32(p->mp_status_critical);
+
+	else
+		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 = field_get_val32(p->mp_status_panic);
+
+	else
+		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 = field_get_val32(p->mp_status_crcerr);
+
+	else
+		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 = field_get_val32(p->mp_status_eft_bp);
+}
+
+void flm_nthw_status_flush(const struct flm_nthw *p)
+{
+	register_flush(p->mp_status, 1);
+}
+
+void flm_nthw_status_update(const struct flm_nthw *p)
+{
+	register_update(p->mp_status);
+}
+
+void flm_nthw_timeout_t(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_timeout_t, val);
+}
+
+void flm_nthw_timeout_flush(const struct flm_nthw *p)
+{
+	register_flush(p->mp_timeout, 1);
+}
+
+void flm_nthw_scrub_i(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_scrub_i, val);
+}
+
+void flm_nthw_scrub_flush(const struct flm_nthw *p)
+{
+	register_flush(p->mp_scrub, 1);
+}
+
+void flm_nthw_load_bin(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_load_bin_bin, val);
+}
+
+void flm_nthw_load_bin_flush(const struct flm_nthw *p)
+{
+	register_flush(p->mp_load_bin, 1);
+}
+
+void flm_nthw_load_pps(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_load_pps_pps, val);
+}
+
+void flm_nthw_load_pps_flush(const struct flm_nthw *p)
+{
+	register_flush(p->mp_load_pps, 1);
+}
+
+void flm_nthw_load_lps(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_load_lps_lps, val);
+}
+
+void flm_nthw_load_lps_flush(const struct flm_nthw *p)
+{
+	register_flush(p->mp_load_lps, 1);
+}
+
+void flm_nthw_load_aps(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_load_aps_aps, val);
+}
+
+void flm_nthw_load_aps_flush(const struct flm_nthw *p)
+{
+	register_flush(p->mp_load_aps, 1);
+}
+
+void flm_nthw_prio_limit0(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_prio_limit0, val);
+}
+
+void flm_nthw_prio_ft0(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_prio_ft0, val);
+}
+
+void flm_nthw_prio_limit1(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_prio_limit1, val);
+}
+
+void flm_nthw_prio_ft1(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_prio_ft1, val);
+}
+
+void flm_nthw_prio_limit2(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_prio_limit2, val);
+}
+
+void flm_nthw_prio_ft2(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_prio_ft2, val);
+}
+
+void flm_nthw_prio_limit3(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_prio_limit3, val);
+}
+
+void flm_nthw_prio_ft3(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_prio_ft3, val);
+}
+
+void flm_nthw_prio_flush(const struct flm_nthw *p)
+{
+	register_flush(p->mp_prio, 1);
+}
+
+void flm_nthw_pst_select(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_pst_ctrl_adr, val);
+}
+
+void flm_nthw_pst_cnt(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_pst_ctrl_cnt, val);
+}
+
+void flm_nthw_pst_bp(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_pst_data_bp, val);
+}
+
+void flm_nthw_pst_pp(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_pst_data_pp, val);
+}
+
+void flm_nthw_pst_tp(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_pst_data_tp, val);
+}
+
+void flm_nthw_pst_flush(const struct flm_nthw *p)
+{
+	register_flush(p->mp_pst_ctrl, 1);
+	register_flush(p->mp_pst_data, 1);
+}
+
+void flm_nthw_rcp_select(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_ctrl_adr, val);
+}
+
+void flm_nthw_rcp_cnt(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_ctrl_cnt, val);
+}
+
+void flm_nthw_rcp_lookup(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_lookup, val);
+}
+
+void flm_nthw_rcp_qw0_dyn(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_qw0_dyn, val);
+}
+
+void flm_nthw_rcp_qw0_ofs(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_qw0_ofs, val);
+}
+
+void flm_nthw_rcp_qw0_sel(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_qw0_sel, val);
+}
+
+void flm_nthw_rcp_qw4_dyn(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_qw4_dyn, val);
+}
+
+void flm_nthw_rcp_qw4_ofs(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_qw4_ofs, val);
+}
+
+void flm_nthw_rcp_sw8_dyn(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_sw8_dyn, val);
+}
+
+void flm_nthw_rcp_sw8_ofs(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_sw8_ofs, val);
+}
+
+void flm_nthw_rcp_sw8_sel(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_sw8_sel, val);
+}
+
+void flm_nthw_rcp_sw9_dyn(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_sw9_dyn, val);
+}
+
+void flm_nthw_rcp_sw9_ofs(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_sw9_ofs, val);
+}
+
+void flm_nthw_rcp_mask(const struct flm_nthw *p, const uint32_t *val)
+{
+	field_set_val(p->mp_rcp_data_mask, val, 10);
+}
+
+void flm_nthw_rcp_kid(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_kid, val);
+}
+
+void flm_nthw_rcp_opn(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_opn, val);
+}
+
+void flm_nthw_rcp_ipn(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_ipn, val);
+}
+
+void flm_nthw_rcp_byt_dyn(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_byt_dyn, val);
+}
+
+void flm_nthw_rcp_byt_ofs(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_byt_ofs, val);
+}
+
+void flm_nthw_rcp_txplm(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_txplm, val);
+}
+
+void flm_nthw_rcp_auto_ipv4_mask(const struct flm_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_auto_ipv4_mask, val);
+}
+
+void flm_nthw_rcp_flush(const struct flm_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	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 = register_get_address(p->mp_buf_ctrl);
+	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, address_bufctrl, bus_id, 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 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 = register_get_address(p->mp_lrn_data);
+	uint32_t address_bufctrl = register_get_address(p->mp_buf_ctrl);
+	rab_bus_id_t bus_id = 1;
+	struct dma_buf_ptr bc_buf;
+
+	if (nthw_rac_rab_dma_begin(rac) == 0) {
+		/* Announce the number of words to write to LRN_DATA */
+		uint32_t bufctrl_data[2];
+
+		bufctrl_data[0] = word_count;
+		bufctrl_data[1] = 0;
+		nthw_rac_rab_write32_dma(rac, address_bufctrl, bus_id, 2,
+					bufctrl_data);
+		nthw_rac_rab_write32_dma(rac, address, bus_id, word_count, data);
+		nthw_rac_rab_read32_dma(rac, address_bufctrl, bus_id, 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_inf_data_update(const struct flm_nthw *p, uint32_t *data,
+			  uint32_t 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_infdata = register_get_address(p->mp_inf_data);
+	uint32_t address_bufctrl = register_get_address(p->mp_buf_ctrl);
+	rab_bus_id_t bus_id = 1;
+	struct dma_buf_ptr buf;
+	struct dma_buf_ptr bc_buf;
+
+	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] = word_count << 16;
+		bufctrl_data[1] = 0;
+		nthw_rac_rab_write32_dma(rac, address_bufctrl, bus_id, 2,
+					bufctrl_data);
+		nthw_rac_rab_read32_dma(rac, address_infdata, bus_id, word_count,
+				       &buf);
+		nthw_rac_rab_read32_dma(rac, address_bufctrl, bus_id, 2, &bc_buf);
+		ret = nthw_rac_rab_dma_commit(rac);
+		if (ret != 0)
+			return ret;
+
+		uint32_t mask = buf.size - 1;
+		uint32_t index = buf.index;
+
+		for (uint32_t i = 0; i < word_count; ++index, ++i)
+			data[i] = buf.base[index & mask];
+
+		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_sta_data_update(const struct flm_nthw *p, uint32_t *data,
+			  uint32_t 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_stadata = register_get_address(p->mp_sta_data);
+	uint32_t address_bufctrl = register_get_address(p->mp_buf_ctrl);
+	rab_bus_id_t bus_id = 1;
+	struct dma_buf_ptr buf;
+	struct dma_buf_ptr bc_buf;
+
+	ret = nthw_rac_rab_dma_begin(rac);
+	if (ret == 0) {
+		/* Announce the number of words to read from STA_DATA */
+		uint32_t bufctrl_data[2];
+
+		bufctrl_data[0] = 0;
+		bufctrl_data[1] = word_count;
+		nthw_rac_rab_write32_dma(rac, address_bufctrl, bus_id, 2,
+					bufctrl_data);
+		nthw_rac_rab_read32_dma(rac, address_stadata, bus_id, word_count,
+				       &buf);
+		nthw_rac_rab_read32_dma(rac, address_bufctrl, bus_id, 2, &bc_buf);
+		ret = nthw_rac_rab_dma_commit(rac);
+		if (ret != 0)
+			return ret;
+
+		uint32_t mask = buf.size - 1;
+		uint32_t index = buf.index;
+
+		for (uint32_t i = 0; i < word_count; ++index, ++i)
+			data[i] = buf.base[index & mask];
+
+		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;
+}
+
+void flm_nthw_stat_lrn_done_cnt(const struct flm_nthw *p, uint32_t *val, int get)
+{
+	if (get)
+		*val = field_get_val32(p->mp_stat_lrn_done_cnt);
+}
+
+void flm_nthw_stat_lrn_done_update(const struct flm_nthw *p)
+{
+	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 = field_get_val32(p->mp_stat_lrn_ignore_cnt);
+}
+
+void flm_nthw_stat_lrn_ignore_update(const struct flm_nthw *p)
+{
+	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 = field_get_val32(p->mp_stat_lrn_fail_cnt);
+}
+
+void flm_nthw_stat_lrn_fail_update(const struct flm_nthw *p)
+{
+	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 = field_get_val32(p->mp_stat_unl_done_cnt);
+}
+
+void flm_nthw_stat_unl_done_update(const struct flm_nthw *p)
+{
+	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 = field_get_val32(p->mp_stat_unl_ignore_cnt);
+}
+
+void flm_nthw_stat_unl_ignore_update(const struct flm_nthw *p)
+{
+	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 = 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);
+	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 = 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);
+	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 = field_get_val32(p->mp_stat_rel_done_cnt);
+}
+
+void flm_nthw_stat_rel_done_update(const struct flm_nthw *p)
+{
+	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 = field_get_val32(p->mp_stat_rel_ignore_cnt);
+}
+
+void flm_nthw_stat_rel_ignore_update(const struct flm_nthw *p)
+{
+	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 = field_get_val32(p->mp_stat_aul_done_cnt);
+}
+
+void flm_nthw_stat_aul_done_update(const struct flm_nthw *p)
+{
+	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 = field_get_val32(p->mp_stat_aul_ignore_cnt);
+}
+
+void flm_nthw_stat_aul_ignore_update(const struct flm_nthw *p)
+{
+	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 = field_get_val32(p->mp_stat_aul_fail_cnt);
+}
+
+void flm_nthw_stat_aul_fail_update(const struct flm_nthw *p)
+{
+	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 = field_get_val32(p->mp_stat_tul_done_cnt);
+}
+
+void flm_nthw_stat_tul_done_update(const struct flm_nthw *p)
+{
+	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 = field_get_val32(p->mp_stat_flows_cnt);
+}
+
+void flm_nthw_stat_flows_update(const struct flm_nthw *p)
+{
+	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 = 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);
+	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 = 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);
+	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 = 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);
+	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 = 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);
+	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 = 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);
+	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 = 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);
+	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 = 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);
+	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 = 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);
+	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 = 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);
+	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 = 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);
+	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 = 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);
+	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 = 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);
+	register_update(p->mp_stat_cuc_move);
+}
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..4796d43940
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_flm.h
@@ -0,0 +1,422 @@
+/* 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> /* uint32_t */
+#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, nt_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_calibdone(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_flush(const struct flm_nthw *p);
+void flm_nthw_status_update(const struct flm_nthw *p);
+
+/* Timeout */
+void flm_nthw_timeout_t(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_timeout_flush(const struct flm_nthw *p);
+
+/* Scrub */
+void flm_nthw_scrub_i(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_scrub_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 PPS */
+void flm_nthw_load_pps(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_load_pps_flush(const struct flm_nthw *p);
+
+/* Load LPS */
+void flm_nthw_load_lps(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_load_lps_flush(const struct flm_nthw *p);
+
+/* Load APS */
+void flm_nthw_load_aps(const struct flm_nthw *p, uint32_t val);
+void flm_nthw_load_aps_flush(const struct flm_nthw *p);
+
+/* 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 word_count, uint32_t *lrn_free,
+			 uint32_t *inf_avail, uint32_t *sta_avail);
+
+/* Inf Data */
+int flm_nthw_inf_data_update(const struct flm_nthw *p, uint32_t *data,
+			  uint32_t word_count, uint32_t *lrn_free,
+			  uint32_t *inf_avail, uint32_t *sta_avail);
+
+/* Sta Data */
+int flm_nthw_sta_data_update(const struct flm_nthw *p, uint32_t *data,
+			  uint32_t 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);
+
+struct flm_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_fpga_t *mp_fpga;
+	void *mp_rac;
+
+	nt_module_t *m_flm;
+
+	nt_register_t *mp_control;
+	nt_field_t *mp_control_enable;
+	nt_field_t *mp_control_init;
+	nt_field_t *mp_control_lds;
+	nt_field_t *mp_control_lfs;
+	nt_field_t *mp_control_lis;
+	nt_field_t *mp_control_uds;
+	nt_field_t *mp_control_uis;
+	nt_field_t *mp_control_rds;
+	nt_field_t *mp_control_ris;
+	nt_field_t *mp_control_pds;
+	nt_field_t *mp_control_pis;
+	nt_field_t *mp_control_crcwr;
+	nt_field_t *mp_control_crcrd;
+	nt_field_t *mp_control_rbl;
+	nt_field_t *mp_control_eab;
+	nt_field_t *mp_control_split_sdram_usage;
+
+	nt_register_t *mp_status;
+	nt_field_t *mp_status_calibdone;
+	nt_field_t *mp_status_initdone;
+	nt_field_t *mp_status_idle;
+	nt_field_t *mp_status_critical;
+	nt_field_t *mp_status_panic;
+	nt_field_t *mp_status_crcerr;
+	nt_field_t *mp_status_eft_bp;
+
+	nt_register_t *mp_timeout;
+	nt_field_t *mp_timeout_t;
+
+	nt_register_t *mp_scrub;
+	nt_field_t *mp_scrub_i;
+
+	nt_register_t *mp_load_bin;
+	nt_field_t *mp_load_bin_bin;
+
+	nt_register_t *mp_load_pps;
+	nt_field_t *mp_load_pps_pps;
+
+	nt_register_t *mp_load_lps;
+	nt_field_t *mp_load_lps_lps;
+
+	nt_register_t *mp_load_aps;
+	nt_field_t *mp_load_aps_aps;
+
+	nt_register_t *mp_prio;
+	nt_field_t *mp_prio_limit0;
+	nt_field_t *mp_prio_ft0;
+	nt_field_t *mp_prio_limit1;
+	nt_field_t *mp_prio_ft1;
+	nt_field_t *mp_prio_limit2;
+	nt_field_t *mp_prio_ft2;
+	nt_field_t *mp_prio_limit3;
+	nt_field_t *mp_prio_ft3;
+
+	nt_register_t *mp_pst_ctrl;
+	nt_field_t *mp_pst_ctrl_adr;
+	nt_field_t *mp_pst_ctrl_cnt;
+	nt_register_t *mp_pst_data;
+	nt_field_t *mp_pst_data_bp;
+	nt_field_t *mp_pst_data_pp;
+	nt_field_t *mp_pst_data_tp;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_ctrl_adr;
+	nt_field_t *mp_rcp_ctrl_cnt;
+	nt_register_t *mp_rcp_data;
+	nt_field_t *mp_rcp_data_lookup;
+	nt_field_t *mp_rcp_data_qw0_dyn;
+	nt_field_t *mp_rcp_data_qw0_ofs;
+	nt_field_t *mp_rcp_data_qw0_sel;
+	nt_field_t *mp_rcp_data_qw4_dyn;
+	nt_field_t *mp_rcp_data_qw4_ofs;
+	nt_field_t *mp_rcp_data_sw8_dyn;
+	nt_field_t *mp_rcp_data_sw8_ofs;
+	nt_field_t *mp_rcp_data_sw8_sel;
+	nt_field_t *mp_rcp_data_sw9_dyn;
+	nt_field_t *mp_rcp_data_sw9_ofs;
+	nt_field_t *mp_rcp_data_mask;
+	nt_field_t *mp_rcp_data_kid;
+	nt_field_t *mp_rcp_data_opn;
+	nt_field_t *mp_rcp_data_ipn;
+	nt_field_t *mp_rcp_data_byt_dyn;
+	nt_field_t *mp_rcp_data_byt_ofs;
+	nt_field_t *mp_rcp_data_txplm;
+	nt_field_t *mp_rcp_data_auto_ipv4_mask;
+
+	nt_register_t *mp_buf_ctrl;
+	nt_field_t *mp_buf_ctrl_lrn_free;
+	nt_field_t *mp_buf_ctrl_inf_avail;
+	nt_field_t *mp_buf_ctrl_sta_avail;
+
+	nt_register_t *mp_lrn_data;
+	nt_register_t *mp_inf_data;
+	nt_register_t *mp_sta_data;
+
+	nt_register_t *mp_stat_lrn_done;
+	nt_field_t *mp_stat_lrn_done_cnt;
+
+	nt_register_t *mp_stat_lrn_ignore;
+	nt_field_t *mp_stat_lrn_ignore_cnt;
+
+	nt_register_t *mp_stat_lrn_fail;
+	nt_field_t *mp_stat_lrn_fail_cnt;
+
+	nt_register_t *mp_stat_unl_done;
+	nt_field_t *mp_stat_unl_done_cnt;
+
+	nt_register_t *mp_stat_unl_ignore;
+	nt_field_t *mp_stat_unl_ignore_cnt;
+
+	nt_register_t *mp_stat_prb_done;
+	nt_field_t *mp_stat_prb_done_cnt;
+
+	nt_register_t *mp_stat_prb_ignore;
+	nt_field_t *mp_stat_prb_ignore_cnt;
+
+	nt_register_t *mp_stat_rel_done;
+	nt_field_t *mp_stat_rel_done_cnt;
+
+	nt_register_t *mp_stat_rel_ignore;
+	nt_field_t *mp_stat_rel_ignore_cnt;
+
+	nt_register_t *mp_stat_aul_done;
+	nt_field_t *mp_stat_aul_done_cnt;
+
+	nt_register_t *mp_stat_aul_ignore;
+	nt_field_t *mp_stat_aul_ignore_cnt;
+
+	nt_register_t *mp_stat_aul_fail;
+	nt_field_t *mp_stat_aul_fail_cnt;
+
+	nt_register_t *mp_stat_tul_done;
+	nt_field_t *mp_stat_tul_done_cnt;
+
+	nt_register_t *mp_stat_flows;
+	nt_field_t *mp_stat_flows_cnt;
+
+	nt_register_t *mp_stat_sta_done;
+	nt_field_t *mp_stat_sta_done_cnt;
+
+	nt_register_t *mp_stat_inf_done;
+	nt_field_t *mp_stat_inf_done_cnt;
+
+	nt_register_t *mp_stat_inf_skip;
+	nt_field_t *mp_stat_inf_skip_cnt;
+
+	nt_register_t *mp_stat_pck_hit;
+	nt_field_t *mp_stat_pck_hit_cnt;
+
+	nt_register_t *mp_stat_pck_miss;
+	nt_field_t *mp_stat_pck_miss_cnt;
+
+	nt_register_t *mp_stat_pck_unh;
+	nt_field_t *mp_stat_pck_unh_cnt;
+
+	nt_register_t *mp_stat_pck_dis;
+	nt_field_t *mp_stat_pck_dis_cnt;
+
+	nt_register_t *mp_stat_csh_hit;
+	nt_field_t *mp_stat_csh_hit_cnt;
+
+	nt_register_t *mp_stat_csh_miss;
+	nt_field_t *mp_stat_csh_miss_cnt;
+
+	nt_register_t *mp_stat_csh_unh;
+	nt_field_t *mp_stat_csh_unh_cnt;
+
+	nt_register_t *mp_stat_cuc_start;
+	nt_field_t *mp_stat_cuc_start_cnt;
+
+	nt_register_t *mp_stat_cuc_move;
+	nt_field_t *mp_stat_cuc_move_cnt;
+};
+
+#endif /* __FLOW_NTHW_FLM_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
new file mode 100644
index 0000000000..b7fe7c5863
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.c
@@ -0,0 +1,293 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_hfu.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+void hfu_nthw_set_debug_mode(struct hfu_nthw *p, unsigned int n_debug_mode)
+{
+	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));
+
+	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, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = fpga_query_module(p_fpga, MOD_HFU, n_instance);
+
+	p->mp_rcp_ctrl = module_get_register(p->m_hfu, HFU_RCP_CTRL);
+	p->mp_rcp_addr = register_get_field(p->mp_rcp_ctrl, HFU_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = register_get_field(p->mp_rcp_ctrl, HFU_RCP_CTRL_CNT);
+
+	p->mp_rcp_data = module_get_register(p->m_hfu, HFU_RCP_DATA);
+	p->mp_rcp_data_len_a_wr =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_WR);
+	p->mp_rcp_data_len_a_ol4len =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_OL4LEN);
+	p->mp_rcp_data_len_a_pos_dyn =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_POS_DYN);
+	p->mp_rcp_data_len_a_pos_ofs =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_POS_OFS);
+	p->mp_rcp_data_len_a_add_dyn =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_ADD_DYN);
+	p->mp_rcp_data_len_a_add_ofs =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_ADD_OFS);
+	p->mp_rcp_data_len_a_sub_dyn =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_A_SUB_DYN);
+	p->mp_rcp_data_len_b_wr =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_B_WR);
+	p->mp_rcp_data_len_b_pos_dyn =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_B_POS_DYN);
+	p->mp_rcp_data_len_b_pos_ofs =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_B_POS_OFS);
+	p->mp_rcp_data_len_b_add_dyn =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_B_ADD_DYN);
+	p->mp_rcp_data_len_b_add_ofs =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_B_ADD_OFS);
+	p->mp_rcp_data_len_b_sub_dyn =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_B_SUB_DYN);
+	p->mp_rcp_data_len_c_wr =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_C_WR);
+	p->mp_rcp_data_len_c_pos_dyn =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_C_POS_DYN);
+	p->mp_rcp_data_len_c_pos_ofs =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_C_POS_OFS);
+	p->mp_rcp_data_len_c_add_dyn =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_C_ADD_DYN);
+	p->mp_rcp_data_len_c_add_ofs =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_C_ADD_OFS);
+	p->mp_rcp_data_len_c_sub_dyn =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_LEN_C_SUB_DYN);
+	p->mp_rcp_data_ttl_wr =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_TTL_WR);
+	p->mp_rcp_data_ttl_pos_dyn =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_TTL_POS_DYN);
+	p->mp_rcp_data_ttl_pos_ofs =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_TTL_POS_OFS);
+	p->mp_rcp_data_csinf = register_get_field(p->mp_rcp_data, HFU_RCP_DATA_CSINF);
+	p->mp_rcp_data_l3prt = register_get_field(p->mp_rcp_data, HFU_RCP_DATA_L3PRT);
+	p->mp_rcp_data_l3frag =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_L3FRAG);
+	p->mp_rcp_data_tunnel =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_TUNNEL);
+	p->mp_rcp_data_l4prt = register_get_field(p->mp_rcp_data, HFU_RCP_DATA_L4PRT);
+	p->mp_rcp_data_ol3ofs =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_OL3OFS);
+	p->mp_rcp_data_ol4ofs =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_OL4OFS);
+	p->mp_rcp_data_il3ofs =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_IL3OFS);
+	p->mp_rcp_data_il4ofs =
+		register_get_field(p->mp_rcp_data, HFU_RCP_DATA_IL4OFS);
+
+	return 0;
+}
+
+void hfu_nthw_rcp_select(const struct hfu_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_addr, val);
+}
+
+void hfu_nthw_rcp_cnt(const struct hfu_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void hfu_nthw_rcp_len_a_wr(const struct hfu_nthw *p, uint32_t val)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	field_set_val32(p->mp_rcp_data_ttl_pos_ofs, val);
+}
+
+void hfu_nthw_rcp_csinf(const struct hfu_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_csinf, val);
+}
+
+void hfu_nthw_rcp_l3prt(const struct hfu_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_l3prt, val);
+}
+
+void hfu_nthw_rcp_l3frag(const struct hfu_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_l3frag, val);
+}
+
+void hfu_nthw_rcp_tunnel(const struct hfu_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_tunnel, val);
+}
+
+void hfu_nthw_rcp_l4prt(const struct hfu_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_l4prt, val);
+}
+
+void hfu_nthw_rcp_ol3ofs(const struct hfu_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_ol3ofs, val);
+}
+
+void hfu_nthw_rcp_ol4ofs(const struct hfu_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_ol4ofs, val);
+}
+
+void hfu_nthw_rcp_il3ofs(const struct hfu_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_il3ofs, val);
+}
+
+void hfu_nthw_rcp_il4ofs(const struct hfu_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_il4ofs, val);
+}
+
+void hfu_nthw_rcp_flush(const struct hfu_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	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
new file mode 100644
index 0000000000..ecba1a8822
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hfu.h
@@ -0,0 +1,100 @@
+/* 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;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_hfu;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_addr;
+	nt_field_t *mp_rcp_cnt;
+
+	nt_register_t *mp_rcp_data;
+	nt_field_t *mp_rcp_data_len_a_wr;
+	nt_field_t *mp_rcp_data_len_a_ol4len;
+	nt_field_t *mp_rcp_data_len_a_pos_dyn;
+	nt_field_t *mp_rcp_data_len_a_pos_ofs;
+	nt_field_t *mp_rcp_data_len_a_add_dyn;
+	nt_field_t *mp_rcp_data_len_a_add_ofs;
+	nt_field_t *mp_rcp_data_len_a_sub_dyn;
+	nt_field_t *mp_rcp_data_len_b_wr;
+	nt_field_t *mp_rcp_data_len_b_pos_dyn;
+	nt_field_t *mp_rcp_data_len_b_pos_ofs;
+	nt_field_t *mp_rcp_data_len_b_add_dyn;
+	nt_field_t *mp_rcp_data_len_b_add_ofs;
+	nt_field_t *mp_rcp_data_len_b_sub_dyn;
+	nt_field_t *mp_rcp_data_len_c_wr;
+	nt_field_t *mp_rcp_data_len_c_pos_dyn;
+	nt_field_t *mp_rcp_data_len_c_pos_ofs;
+	nt_field_t *mp_rcp_data_len_c_add_dyn;
+	nt_field_t *mp_rcp_data_len_c_add_ofs;
+	nt_field_t *mp_rcp_data_len_c_sub_dyn;
+	nt_field_t *mp_rcp_data_ttl_wr;
+	nt_field_t *mp_rcp_data_ttl_pos_dyn;
+	nt_field_t *mp_rcp_data_ttl_pos_ofs;
+	nt_field_t *mp_rcp_data_csinf;
+	nt_field_t *mp_rcp_data_l3prt;
+	nt_field_t *mp_rcp_data_l3frag;
+	nt_field_t *mp_rcp_data_tunnel;
+	nt_field_t *mp_rcp_data_l4prt;
+	nt_field_t *mp_rcp_data_ol3ofs;
+	nt_field_t *mp_rcp_data_ol4ofs;
+	nt_field_t *mp_rcp_data_il3ofs;
+	nt_field_t *mp_rcp_data_il4ofs;
+};
+
+struct hfu_nthw *hfu_nthw_new(void);
+void hfu_nthw_delete(struct hfu_nthw *p);
+int hfu_nthw_init(struct hfu_nthw *p, nt_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_csinf(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_l3prt(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_l3frag(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_tunnel(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_l4prt(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_ol3ofs(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_ol4ofs(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_il3ofs(const struct hfu_nthw *p, uint32_t val);
+void hfu_nthw_rcp_il4ofs(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_hsh.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.c
new file mode 100644
index 0000000000..0dc6434e88
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.c
@@ -0,0 +1,254 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_hsh.h"
+
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+void hsh_nthw_set_debug_mode(struct hsh_nthw *p, unsigned int n_debug_mode)
+{
+	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, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = module_get_register(p->m_hsh, HSH_RCP_CTRL);
+	p->mp_rcp_addr = register_get_field(p->mp_rcp_ctrl, HSH_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = register_get_field(p->mp_rcp_ctrl, HSH_RCP_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_hsh, HSH_RCP_DATA);
+	p->mp_rcp_data_load_dist_type =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_LOAD_DIST_TYPE);
+	p->mp_rcp_data_mac_port_mask =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_MAC_PORT_MASK);
+	p->mp_rcp_data_sort = register_get_field(p->mp_rcp_data, HSH_RCP_DATA_SORT);
+	p->mp_rcp_data_qw0_pe =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_QW0_PE);
+	p->mp_rcp_data_qw0_ofs =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_QW0_OFS);
+	p->mp_rcp_data_qw4_pe =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_QW4_PE);
+	p->mp_rcp_data_qw4_ofs =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_QW4_OFS);
+	p->mp_rcp_data_w8_pe = register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W8_PE);
+	p->mp_rcp_data_w8_ofs =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W8_OFS);
+	p->mp_rcp_data_w8_sort =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W8_SORT);
+	p->mp_rcp_data_w9_pe = register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W9_PE);
+	p->mp_rcp_data_w9_ofs =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W9_OFS);
+	p->mp_rcp_data_w9_sort =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W9_SORT);
+	p->mp_rcp_data_w9_p = register_get_field(p->mp_rcp_data, HSH_RCP_DATA_W9_P);
+	p->mp_rcp_data_p_mask =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_P_MASK);
+	p->mp_rcp_data_word_mask =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_WORD_MASK);
+	p->mp_rcp_data_seed = register_get_field(p->mp_rcp_data, HSH_RCP_DATA_SEED);
+	p->mp_rcp_data_tnl_p = register_get_field(p->mp_rcp_data, HSH_RCP_DATA_TNL_P);
+	p->mp_rcp_data_hsh_valid =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_HSH_VALID);
+	p->mp_rcp_data_hsh_type =
+		register_get_field(p->mp_rcp_data, HSH_RCP_DATA_HSH_TYPE);
+	p->mp_rcp_data_auto_ipv4_mask =
+		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 };
+
+	field_set_val32(p->mp_rcp_addr, 0);
+	field_set_val32(p->mp_rcp_cnt, 1);
+
+	field_set_val32(p->mp_rcp_data_load_dist_type, 0);
+	field_set_val(p->mp_rcp_data_mac_port_mask, val,
+		     p->mp_rcp_data_mac_port_mask->mn_words);
+	field_set_val32(p->mp_rcp_data_sort, 0);
+	field_set_val32(p->mp_rcp_data_qw0_pe, 0);
+	field_set_val32(p->mp_rcp_data_qw0_ofs, 0);
+	field_set_val32(p->mp_rcp_data_qw4_pe, 0);
+	field_set_val32(p->mp_rcp_data_qw4_ofs, 0);
+	field_set_val32(p->mp_rcp_data_w8_pe, 0);
+	field_set_val32(p->mp_rcp_data_w8_ofs, 0);
+	field_set_val32(p->mp_rcp_data_w8_sort, 0);
+	field_set_val32(p->mp_rcp_data_w9_pe, 0);
+	field_set_val32(p->mp_rcp_data_w9_ofs, 0);
+	field_set_val32(p->mp_rcp_data_w9_sort, 0);
+	field_set_val32(p->mp_rcp_data_w9_p, 0);
+	field_set_val(p->mp_rcp_data_word_mask, val, 10);
+	field_set_val32(p->mp_rcp_data_seed, 0);
+	field_set_val32(p->mp_rcp_data_tnl_p, 0);
+	field_set_val32(p->mp_rcp_data_hsh_valid, 0);
+	field_set_val32(p->mp_rcp_data_hsh_type, 31);
+
+	register_flush(p->mp_rcp_ctrl, 1);
+	register_flush(p->mp_rcp_data, 1);
+
+	return 0;
+}
+
+void hsh_nthw_rcp_select(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_addr, val);
+}
+
+void hsh_nthw_rcp_cnt(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void hsh_nthw_rcp_load_dist_type(const struct hsh_nthw *p, uint32_t val)
+{
+	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)
+{
+	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)
+{
+	field_set_val32(p->mp_rcp_data_sort, val);
+}
+
+void hsh_nthw_rcp_qw0_pe(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_qw0_pe, val);
+}
+
+void hsh_nthw_rcp_qw0_ofs(const struct hsh_nthw *p, int32_t val)
+{
+	field_set_val32(p->mp_rcp_data_qw0_ofs, val);
+}
+
+void hsh_nthw_rcp_qw4_pe(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_qw4_pe, val);
+}
+
+void hsh_nthw_rcp_qw4_ofs(const struct hsh_nthw *p, int32_t val)
+{
+	field_set_val32(p->mp_rcp_data_qw4_ofs, val);
+}
+
+void hsh_nthw_rcp_w8_pe(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_w8_pe, val);
+}
+
+void hsh_nthw_rcp_w8_ofs(const struct hsh_nthw *p, int32_t val)
+{
+	field_set_val32(p->mp_rcp_data_w8_ofs, val);
+}
+
+void hsh_nthw_rcp_w8_sort(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_w8_sort, val);
+}
+
+void hsh_nthw_rcp_w9_pe(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_w9_pe, val);
+}
+
+void hsh_nthw_rcp_w9_ofs(const struct hsh_nthw *p, int32_t val)
+{
+	field_set_val32(p->mp_rcp_data_w9_ofs, val);
+}
+
+void hsh_nthw_rcp_w9_sort(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_w9_sort, val);
+}
+
+void hsh_nthw_rcp_w9_p(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_w9_p, val);
+}
+
+void hsh_nthw_rcp_p_mask(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_p_mask, val);
+}
+
+void hsh_nthw_rcp_word_mask(const struct hsh_nthw *p, uint32_t *val)
+{
+	field_set_val(p->mp_rcp_data_word_mask, val, 10);
+}
+
+void hsh_nthw_rcp_seed(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_seed, val);
+}
+
+void hsh_nthw_rcp_tnl_p(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_tnl_p, val);
+}
+
+void hsh_nthw_rcp_hsh_valid(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_hsh_valid, val);
+}
+
+void hsh_nthw_rcp_hsh_type(const struct hsh_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_hsh_type, val);
+}
+
+void hsh_nthw_rcp_auto_ipv4_mask(const struct hsh_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_auto_ipv4_mask)
+		field_set_val32(p->mp_rcp_data_auto_ipv4_mask, val);
+}
+
+void hsh_nthw_rcp_flush(const struct hsh_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	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..7cb7dbb743
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hsh.h
@@ -0,0 +1,81 @@
+/* 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> /* uint32_t */
+#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, nt_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_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;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_hsh;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_addr;
+	nt_field_t *mp_rcp_cnt;
+	nt_register_t *mp_rcp_data;
+	nt_field_t *mp_rcp_data_load_dist_type;
+	nt_field_t *mp_rcp_data_mac_port_mask;
+	nt_field_t *mp_rcp_data_sort;
+	nt_field_t *mp_rcp_data_qw0_pe;
+	nt_field_t *mp_rcp_data_qw0_ofs;
+	nt_field_t *mp_rcp_data_qw4_pe;
+	nt_field_t *mp_rcp_data_qw4_ofs;
+	nt_field_t *mp_rcp_data_w8_pe;
+	nt_field_t *mp_rcp_data_w8_ofs;
+	nt_field_t *mp_rcp_data_w8_sort;
+	nt_field_t *mp_rcp_data_w9_pe;
+	nt_field_t *mp_rcp_data_w9_ofs;
+	nt_field_t *mp_rcp_data_w9_sort;
+	nt_field_t *mp_rcp_data_w9_p;
+	nt_field_t *mp_rcp_data_p_mask;
+	nt_field_t *mp_rcp_data_word_mask;
+	nt_field_t *mp_rcp_data_seed;
+	nt_field_t *mp_rcp_data_tnl_p;
+	nt_field_t *mp_rcp_data_hsh_valid;
+	nt_field_t *mp_rcp_data_hsh_type;
+	nt_field_t *mp_rcp_data_auto_ipv4_mask;
+};
+
+#endif /* __FLOW_NTHW_HSH_H__ */
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hst.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hst.c
new file mode 100644
index 0000000000..fc3dc443a2
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hst.c
@@ -0,0 +1,202 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_hst.h"
+
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+void hst_nthw_set_debug_mode(struct hst_nthw *p, unsigned int n_debug_mode)
+{
+	module_set_debug_mode(p->m_hst, n_debug_mode);
+}
+
+struct hst_nthw *hst_nthw_new(void)
+{
+	struct hst_nthw *p = malloc(sizeof(struct hst_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void hst_nthw_delete(struct hst_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int hst_nthw_init(struct hst_nthw *p, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = fpga_query_module(p_fpga, MOD_HST, 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: Hst %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_hst = p_mod;
+
+	/* RCP */
+	p->mp_rcp_ctrl = module_get_register(p->m_hst, HST_RCP_CTRL);
+	p->mp_rcp_addr = register_get_field(p->mp_rcp_ctrl, HST_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = register_get_field(p->mp_rcp_ctrl, HST_RCP_CTRL_CNT);
+
+	p->mp_rcp_data = module_get_register(p->m_hst, HST_RCP_DATA);
+	p->mp_rcp_data_strip_mode =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_STRIP_MODE);
+	p->mp_rcp_data_start_dyn =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_START_DYN);
+	p->mp_rcp_data_start_ofs =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_START_OFS);
+	p->mp_rcp_data_end_dyn =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_END_DYN);
+	p->mp_rcp_data_end_ofs =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_END_OFS);
+	p->mp_rcp_data_modif0_cmd =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_MODIF0_CMD);
+	p->mp_rcp_data_modif0_dyn =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_MODIF0_DYN);
+	p->mp_rcp_data_modif0_ofs =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_MODIF0_OFS);
+	p->mp_rcp_data_modif0_value =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_MODIF0_VALUE);
+	p->mp_rcp_data_modif1_cmd =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_MODIF1_CMD);
+	p->mp_rcp_data_modif1_dyn =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_MODIF1_DYN);
+	p->mp_rcp_data_modif1_ofs =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_MODIF1_OFS);
+	p->mp_rcp_data_modif1_value =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_MODIF1_VALUE);
+	p->mp_rcp_data_modif2_cmd =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_MODIF2_CMD);
+	p->mp_rcp_data_modif2_dyn =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_MODIF2_DYN);
+	p->mp_rcp_data_modif2_ofs =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_MODIF2_OFS);
+	p->mp_rcp_data_modif2_value =
+		register_get_field(p->mp_rcp_data, HST_RCP_DATA_MODIF2_VALUE);
+
+	return 0;
+}
+
+/* RCP */
+void hst_nthw_rcp_select(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_addr, val);
+}
+
+void hst_nthw_rcp_cnt(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void hst_nthw_rcp_strip_mode(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_strip_mode, val);
+}
+
+void hst_nthw_rcp_start_dyn(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_start_dyn, val);
+}
+
+void hst_nthw_rcp_start_ofs(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_start_ofs, val);
+}
+
+void hst_nthw_rcp_end_dyn(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_end_dyn, val);
+}
+
+void hst_nthw_rcp_end_ofs(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_end_ofs, val);
+}
+
+void hst_nthw_rcp_modif0_cmd(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_modif0_cmd, val);
+}
+
+void hst_nthw_rcp_modif0_dyn(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_modif0_dyn, val);
+}
+
+void hst_nthw_rcp_modif0_ofs(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_modif0_ofs, val);
+}
+
+void hst_nthw_rcp_modif0_value(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_modif0_value, val);
+}
+
+void hst_nthw_rcp_modif1_cmd(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_modif1_cmd, val);
+}
+
+void hst_nthw_rcp_modif1_dyn(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_modif1_dyn, val);
+}
+
+void hst_nthw_rcp_modif1_ofs(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_modif1_ofs, val);
+}
+
+void hst_nthw_rcp_modif1_value(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_modif1_value, val);
+}
+
+void hst_nthw_rcp_modif2_cmd(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_modif2_cmd, val);
+}
+
+void hst_nthw_rcp_modif2_dyn(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_modif2_dyn, val);
+}
+
+void hst_nthw_rcp_modif2_ofs(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_modif2_ofs, val);
+}
+
+void hst_nthw_rcp_modif2_value(const struct hst_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_modif2_value, val);
+}
+
+void hst_nthw_rcp_flush(const struct hst_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	register_flush(p->mp_rcp_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hst.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hst.h
new file mode 100644
index 0000000000..5bc7eb6e55
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_hst.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_HST_H__
+#define __FLOW_NTHW_HST_H__
+
+#include <stdint.h> /* uint32_t */
+#include "nthw_fpga_model.h"
+
+struct hst_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_hst;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_addr;
+	nt_field_t *mp_rcp_cnt;
+	nt_register_t *mp_rcp_data;
+	nt_field_t *mp_rcp_data_strip_mode;
+	nt_field_t *mp_rcp_data_start_dyn;
+	nt_field_t *mp_rcp_data_start_ofs;
+	nt_field_t *mp_rcp_data_end_dyn;
+	nt_field_t *mp_rcp_data_end_ofs;
+	nt_field_t *mp_rcp_data_modif0_cmd;
+	nt_field_t *mp_rcp_data_modif0_dyn;
+	nt_field_t *mp_rcp_data_modif0_ofs;
+	nt_field_t *mp_rcp_data_modif0_value;
+	nt_field_t *mp_rcp_data_modif1_cmd;
+	nt_field_t *mp_rcp_data_modif1_dyn;
+	nt_field_t *mp_rcp_data_modif1_ofs;
+	nt_field_t *mp_rcp_data_modif1_value;
+	nt_field_t *mp_rcp_data_modif2_cmd;
+	nt_field_t *mp_rcp_data_modif2_dyn;
+	nt_field_t *mp_rcp_data_modif2_ofs;
+	nt_field_t *mp_rcp_data_modif2_value;
+};
+
+typedef struct hst_nthw hst_nthw_t;
+
+struct hst_nthw *hst_nthw_new(void);
+void hst_nthw_delete(struct hst_nthw *p);
+int hst_nthw_init(struct hst_nthw *p, nt_fpga_t *p_fpga, int n_instance);
+
+int hst_nthw_setup(struct hst_nthw *p, int n_idx, int n_idx_cnt);
+void hst_nthw_set_debug_mode(struct hst_nthw *p, unsigned int n_debug_mode);
+
+/* RCP */
+void hst_nthw_rcp_select(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_cnt(const struct hst_nthw *p, uint32_t val);
+
+void hst_nthw_rcp_strip_mode(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_start_dyn(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_start_ofs(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_end_dyn(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_end_ofs(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_modif0_cmd(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_modif0_dyn(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_modif0_ofs(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_modif0_value(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_modif1_cmd(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_modif1_dyn(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_modif1_ofs(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_modif1_value(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_modif2_cmd(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_modif2_dyn(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_modif2_ofs(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_modif2_value(const struct hst_nthw *p, uint32_t val);
+void hst_nthw_rcp_flush(const struct hst_nthw *p);
+
+#endif /* __FLOW_NTHW_HST_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
new file mode 100644
index 0000000000..0f51a36e57
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.c
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_ifr.h"
+
+void ifr_nthw_set_debug_mode(struct ifr_nthw *p, unsigned int n_debug_mode)
+{
+	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));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+	return p;
+}
+
+void ifr_nthw_delete(struct ifr_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int ifr_nthw_init(struct ifr_nthw *p, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = fpga_query_module(p_fpga, MOD_IFR, n_instance);
+
+	p->mp_rcp_ctrl = module_get_register(p->m_ifr, IFR_RCP_CTRL);
+	p->mp_rcp_addr = register_get_field(p->mp_rcp_ctrl, IFR_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = register_get_field(p->mp_rcp_ctrl, IFR_RCP_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_ifr, IFR_RCP_DATA);
+	p->mp_rcp_data_en = register_get_field(p->mp_rcp_data, IFR_RCP_DATA_EN);
+	p->mp_rcp_data_mtu = register_get_field(p->mp_rcp_data, IFR_RCP_DATA_MTU);
+
+	return 0;
+}
+
+void ifr_nthw_rcp_select(const struct ifr_nthw *p, uint32_t val)
+{
+	assert(p->mp_rcp_addr);
+	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);
+	field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void ifr_nthw_rcp_en(const struct ifr_nthw *p, uint32_t val)
+{
+	assert(p->mp_rcp_data_en);
+	field_set_val32(p->mp_rcp_data_en, val);
+}
+
+void ifr_nthw_rcp_mtu(const struct ifr_nthw *p, uint32_t val)
+{
+	assert(p->mp_rcp_data_en);
+	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);
+	register_flush(p->mp_rcp_ctrl, 1);
+	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
new file mode 100644
index 0000000000..626ca3d193
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ifr.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_IFR_H__
+#define __FLOW_NTHW_IFR_H__
+
+#include "nthw_fpga_model.h"
+
+struct ifr_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_ifr;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_addr;
+	nt_field_t *mp_rcp_cnt;
+
+	nt_register_t *mp_rcp_data;
+	nt_field_t *mp_rcp_data_en;
+	nt_field_t *mp_rcp_data_mtu;
+};
+
+struct ifr_nthw *ifr_nthw_new(void);
+void ifr_nthw_delete(struct ifr_nthw *p);
+int ifr_nthw_init(struct ifr_nthw *p, nt_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_en(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_info.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_info.c
new file mode 100644
index 0000000000..27b55e3b7c
--- /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 "nt_util.h"
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+#include "nthw_fpga_model.h"
+
+#include "flow_nthw_info.h"
+
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+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, nt_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(fpga_get_product_param(p_fpga, NT_KM_PRESENT, 0));
+	unsigned int kcc_present =
+		clamp_one(fpga_get_product_param(p_fpga, NT_CAT_KCC_PRESENT, 0));
+	unsigned int ioa_present =
+		clamp_one(fpga_get_product_param(p_fpga, NT_IOA_PRESENT, 0));
+	unsigned int roa_present =
+		clamp_one(fpga_get_product_param(p_fpga, NT_ROA_PRESENT, 0));
+	unsigned int dbs_present =
+		clamp_one(fpga_get_product_param(p_fpga, NT_DBS_PRESENT, 0));
+	unsigned int flm_present =
+		clamp_one(fpga_get_product_param(p_fpga, NT_FLM_PRESENT, 0));
+	unsigned int hst_present =
+		clamp_one(fpga_get_product_param(p_fpga, NT_HST_PRESENT, 0));
+
+	/* Modules for Tx Packet Edit function */
+	unsigned int hfu_present =
+		clamp_one(fpga_get_product_param(p_fpga, NT_HFU_PRESENT, 0));
+	unsigned int tx_cpy_present =
+		clamp_one(fpga_get_product_param(p_fpga, NT_TX_CPY_PRESENT, 0));
+	unsigned int tx_ins_present =
+		clamp_one(fpga_get_product_param(p_fpga, NT_TX_INS_PRESENT, 0));
+	unsigned int tx_rpl_present =
+		clamp_one(fpga_get_product_param(p_fpga, NT_TX_RPL_PRESENT, 0));
+	unsigned int csu_present =
+		clamp_one(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 = fpga_get_product_param(p_fpga, NT_PHY_PORTS, 0);
+	p->n_rx_ports = fpga_get_product_param(p_fpga, NT_RX_PORTS, 0);
+	p->n_ltx_avail = fpga_get_product_param(p_fpga, NT_LR_PRESENT, 0);
+	p->nb_cat_func = fpga_get_product_param(p_fpga, NT_CAT_FUNCS, 0);
+	p->nb_categories = fpga_get_product_param(p_fpga, NT_CATEGORIES, 0);
+	p->nb_queues = fpga_get_product_param(p_fpga, NT_QUEUES, 0);
+	p->nb_flow_types = fpga_get_product_param(p_fpga, NT_KM_FLOW_TYPES, 0) *
+			 clamp_one(km_present + flm_present);
+	p->nb_pm_ext = fpga_get_product_param(p_fpga, NT_CAT_N_EXT, 0);
+	p->nb_len = fpga_get_product_param(p_fpga, NT_CAT_N_LEN, 0);
+	p->nb_kcc_size =
+		fpga_get_product_param(p_fpga, NT_CAT_KCC_SIZE, 0) * kcc_present;
+	p->nb_kcc_banks =
+		fpga_get_product_param(p_fpga, NT_CAT_KCC_BANKS, 0) * kcc_present;
+	p->nb_km_categories =
+		fpga_get_product_param(p_fpga, NT_KM_CATEGORIES, 0) * km_present;
+	p->nb_km_cam_banks =
+		fpga_get_product_param(p_fpga, NT_KM_CAM_BANKS, 0) * km_present;
+	p->nb_km_cam_record_words =
+		fpga_get_product_param(p_fpga, NT_KM_CAM_REC_WORDS, 0) * km_present;
+	p->nb_km_cam_records =
+		fpga_get_product_param(p_fpga, NT_KM_CAM_RECORDS, 0) * km_present;
+	p->nb_km_tcam_banks =
+		fpga_get_product_param(p_fpga, NT_KM_TCAM_BANKS, 0) * km_present;
+	p->nb_km_tcam_bank_width =
+		fpga_get_product_param(p_fpga, NT_KM_TCAM_BANK_WIDTH, 0) *
+		km_present;
+	p->nb_flm_categories =
+		fpga_get_product_param(p_fpga, NT_FLM_CATEGORIES, 0) * flm_present;
+	p->nb_flm_size_mb = fpga_get_product_param(p_fpga, NT_FLM_SIZE_MB, 0);
+	p->nb_flm_entry_size = fpga_get_product_param(p_fpga, NT_FLM_ENTRY_SIZE, 0);
+	p->nb_flm_variant = fpga_get_product_param(p_fpga, NT_FLM_VARIANT, 0);
+	p->nb_flm_prios =
+		fpga_get_product_param(p_fpga, NT_FLM_PRIOS, 0) * flm_present;
+	p->nb_flm_pst_profiles =
+		fpga_get_product_param(p_fpga, NT_FLM_PST_PROFILES, 0) *
+		flm_present;
+	p->nb_hst_categories =
+		fpga_get_product_param(p_fpga, NT_HST_CATEGORIES, 0) * hst_present;
+	p->nb_qsl_categories = fpga_get_product_param(p_fpga, NT_QSL_CATEGORIES, 0);
+	p->nb_qsl_qst_entries = fpga_get_product_param(p_fpga, NT_QSL_QST_SIZE, 0);
+	p->nb_pdb_categories = fpga_get_product_param(p_fpga, NT_PDB_CATEGORIES, 0);
+	p->nb_ioa_categories =
+		fpga_get_product_param(p_fpga, NT_IOA_CATEGORIES, 0) * ioa_present;
+	p->nb_roa_categories =
+		fpga_get_product_param(p_fpga, NT_ROA_CATEGORIES, 0) * roa_present;
+	p->nb_dbs_categories =
+		RTE_MIN(fpga_get_product_param(p_fpga, NT_DBS_RX_QUEUES, 0),
+		    fpga_get_product_param(p_fpga, NT_DBS_TX_QUEUES, 0)) *
+		dbs_present;
+	p->nb_cat_km_if_cnt = fpga_get_product_param(p_fpga, NT_CAT_KM_IF_CNT,
+					       km_present + flm_present);
+	p->m_cat_km_if_m0 = fpga_get_product_param(p_fpga, NT_CAT_KM_IF_M0, -1);
+	p->m_cat_km_if_m1 = fpga_get_product_param(p_fpga, NT_CAT_KM_IF_M1, -1);
+	p->nb_tpe_categories =
+		fpga_get_product_param(p_fpga, NT_TPE_CATEGORIES, 0) * tpe_present;
+	p->nb_tx_cpy_writers =
+		fpga_get_product_param(p_fpga, NT_TX_CPY_WRITERS, 0) * tpe_present;
+	p->nb_tx_cpy_mask_mem =
+		fpga_get_product_param(p_fpga, NT_CPY_MASK_MEM, 0) * tpe_present;
+	p->nb_tx_rpl_depth =
+		fpga_get_product_param(p_fpga, NT_TX_RPL_DEPTH, 0) * tpe_present;
+	p->nb_tx_rpl_ext_categories =
+		fpga_get_product_param(p_fpga, NT_TX_RPL_EXT_CATEGORIES, 0) *
+		tpe_present;
+	p->nb_tpe_ifr_categories =
+		fpga_get_product_param(p_fpga, NT_TX_MTU_PROFILE_IFR, 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_hst_categories(const struct info_nthw *p)
+{
+	return p->nb_hst_categories;
+}
+
+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_ioa_categories(const struct info_nthw *p)
+{
+	return p->nb_ioa_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_dbs_categories(const struct info_nthw *p)
+{
+	return p->nb_dbs_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;
+}
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..c697ba84e9
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_info.h
@@ -0,0 +1,104 @@
+/* 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> /* uint32_t */
+#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, nt_fpga_t *p_fpga, int n_instance);
+
+int info_nthw_setup(struct info_nthw *p, int n_idx, int n_idx_cnt);
+
+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_hst_categories(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_ioa_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_dbs_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);
+
+struct info_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_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_hst_categories;
+	unsigned int nb_qsl_categories;
+	unsigned int nb_qsl_qst_entries;
+	unsigned int nb_pdb_categories;
+	unsigned int nb_ioa_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;
+};
+
+#endif /* __FLOW_NTHW_INFO_H__ */
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ioa.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ioa.c
new file mode 100644
index 0000000000..a83d443f6f
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ioa.c
@@ -0,0 +1,234 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_ioa.h"
+
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+void ioa_nthw_set_debug_mode(struct ioa_nthw *p, unsigned int n_debug_mode)
+{
+	module_set_debug_mode(p->m_ioa, n_debug_mode);
+}
+
+struct ioa_nthw *ioa_nthw_new(void)
+{
+	struct ioa_nthw *p = malloc(sizeof(struct ioa_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void ioa_nthw_delete(struct ioa_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int ioa_nthw_init(struct ioa_nthw *p, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = fpga_query_module(p_fpga, MOD_IOA, 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: Ioa %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_ioa = p_mod;
+
+	/* RCP */
+	p->mp_rcp_ctrl = module_get_register(p->m_ioa, IOA_RECIPE_CTRL);
+	p->mp_rcp_addr = register_get_field(p->mp_rcp_ctrl, IOA_RECIPE_CTRL_ADR);
+	p->mp_rcp_cnt = register_get_field(p->mp_rcp_ctrl, IOA_RECIPE_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_ioa, IOA_RECIPE_DATA);
+	p->mp_rcp_data_tunnel_pop =
+		register_get_field(p->mp_rcp_data, IOA_RECIPE_DATA_TUNNEL_POP);
+	p->mp_rcp_data_vlan_pop =
+		register_get_field(p->mp_rcp_data, IOA_RECIPE_DATA_VLAN_POP);
+	p->mp_rcp_data_vlan_push =
+		register_get_field(p->mp_rcp_data, IOA_RECIPE_DATA_VLAN_PUSH);
+	p->mp_rcp_data_vlan_vid =
+		register_get_field(p->mp_rcp_data, IOA_RECIPE_DATA_VLAN_VID);
+	p->mp_rcp_data_vlan_dei =
+		register_get_field(p->mp_rcp_data, IOA_RECIPE_DATA_VLAN_DEI);
+	p->mp_rcp_data_vlan_pcp =
+		register_get_field(p->mp_rcp_data, IOA_RECIPE_DATA_VLAN_PCP);
+	p->mp_rcp_data_vlan_tpid_sel =
+		register_get_field(p->mp_rcp_data, IOA_RECIPE_DATA_VLAN_TPID_SEL);
+	p->mp_rcp_data_queue_override_en =
+		register_get_field(p->mp_rcp_data, IOA_RECIPE_DATA_QUEUE_OVERRIDE_EN);
+	p->mp_rcp_data_queue_id =
+		register_get_field(p->mp_rcp_data, IOA_RECIPE_DATA_QUEUE_ID);
+
+	/* Special Vlan Tpid */
+	p->mp_special = module_get_register(p->m_ioa, IOA_VLAN_TPID_SPECIAL);
+	p->mp_special_vlan_tpid_cust_tpid0 =
+		register_get_field(p->mp_special, IOA_VLAN_TPID_SPECIAL_CUSTTPID0);
+	p->mp_special_vlan_tpid_cust_tpid1 =
+		register_get_field(p->mp_special, IOA_VLAN_TPID_SPECIAL_CUSTTPID1);
+	{
+		/*
+		 * This extension in IOA is a messy way FPGA have chosen to
+		 * put control bits for EPP module in IOA. It is accepted as
+		 * we are going towards exchange IOA and ROA modules later
+		 * to get higher scalability in future.
+		 */
+		p->mp_roa_epp_ctrl =
+			module_query_register(p->m_ioa, IOA_ROA_EPP_CTRL);
+		if (p->mp_roa_epp_ctrl) {
+			p->mp_roa_epp_addr =
+				register_get_field(p->mp_roa_epp_ctrl,
+						   IOA_ROA_EPP_CTRL_ADR);
+			p->mp_roa_epp_cnt =
+				register_get_field(p->mp_roa_epp_ctrl,
+						   IOA_ROA_EPP_CTRL_CNT);
+		} else {
+			p->mp_roa_epp_addr = NULL;
+			p->mp_roa_epp_cnt = NULL;
+		}
+
+		p->mp_roa_epp_data =
+			module_query_register(p->m_ioa, IOA_ROA_EPP_DATA);
+		if (p->mp_roa_epp_data) {
+			p->mp_roa_epp_data_push_tunnel =
+				register_get_field(p->mp_roa_epp_data,
+						   IOA_ROA_EPP_DATA_PUSH_TUNNEL);
+			p->mp_roa_epp_data_tx_port =
+				register_get_field(p->mp_roa_epp_data,
+						   IOA_ROA_EPP_DATA_TX_PORT);
+		} else {
+			p->mp_roa_epp_data_push_tunnel = NULL;
+			p->mp_roa_epp_data_tx_port = NULL;
+		}
+	}
+	return 0;
+}
+
+/* RCP */
+void ioa_nthw_rcp_select(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_addr, val);
+}
+
+void ioa_nthw_rcp_cnt(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void ioa_nthw_rcp_tunnel_pop(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_tunnel_pop, val);
+}
+
+void ioa_nthw_rcp_vlan_pop(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_vlan_pop, val);
+}
+
+void ioa_nthw_rcp_vlan_push(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_vlan_push, val);
+}
+
+void ioa_nthw_rcp_vlan_vid(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_vlan_vid, val);
+}
+
+void ioa_nthw_rcp_vlan_dei(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_vlan_dei, val);
+}
+
+void ioa_nthw_rcp_vlan_pcp(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_vlan_pcp, val);
+}
+
+void ioa_nthw_rcp_vlan_tpid_sel(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_vlan_tpid_sel, val);
+}
+
+void ioa_nthw_rcp_queue_override_en(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_queue_override_en, val);
+}
+
+void ioa_nthw_rcp_queue_id(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_queue_id, val);
+}
+
+void ioa_nthw_rcp_flush(const struct ioa_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	register_flush(p->mp_rcp_data, 1);
+}
+
+/* Vlan Tpid Special */
+void ioa_nthw_special_vlan_tpid_cust_tpid0(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_special_vlan_tpid_cust_tpid0, val);
+}
+
+void ioa_nthw_special_vlan_tpid_cust_tpid1(const struct ioa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_special_vlan_tpid_cust_tpid1, val);
+}
+
+void ioa_nthw_special_vlan_tpid_flush(const struct ioa_nthw *p)
+{
+	register_flush(p->mp_special, 1);
+}
+
+void ioa_nthw_roa_epp_select(const struct ioa_nthw *p, uint32_t val)
+{
+	if (p->mp_roa_epp_addr)
+		field_set_val32(p->mp_roa_epp_addr, val);
+}
+
+void ioa_nthw_roa_epp_cnt(const struct ioa_nthw *p, uint32_t val)
+{
+	if (p->mp_roa_epp_cnt)
+		field_set_val32(p->mp_roa_epp_cnt, val);
+}
+
+void ioa_nthw_roa_epp_push_tunnel(const struct ioa_nthw *p, uint32_t val)
+{
+	if (p->mp_roa_epp_data_push_tunnel)
+		field_set_val32(p->mp_roa_epp_data_push_tunnel, val);
+}
+
+void ioa_nthw_roa_epp_tx_port(const struct ioa_nthw *p, uint32_t val)
+{
+	if (p->mp_roa_epp_data_tx_port)
+		field_set_val32(p->mp_roa_epp_data_tx_port, val);
+}
+
+void ioa_nthw_roa_epp_flush(const struct ioa_nthw *p)
+{
+	if (p->mp_roa_epp_ctrl)
+		register_flush(p->mp_roa_epp_ctrl, 1);
+	if (p->mp_roa_epp_data)
+		register_flush(p->mp_roa_epp_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ioa.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ioa.h
new file mode 100644
index 0000000000..8ab30d2d28
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_ioa.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_IOA_H__
+#define __FLOW_NTHW_IOA_H__
+
+#include "nthw_fpga_model.h"
+
+#include <stdint.h> /* uint32_t */
+
+struct ioa_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_ioa;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_addr;
+	nt_field_t *mp_rcp_cnt;
+	nt_register_t *mp_rcp_data;
+
+	nt_field_t *mp_rcp_data_tunnel_pop;
+	nt_field_t *mp_rcp_data_vlan_pop;
+	nt_field_t *mp_rcp_data_vlan_push;
+	nt_field_t *mp_rcp_data_vlan_vid;
+	nt_field_t *mp_rcp_data_vlan_dei;
+	nt_field_t *mp_rcp_data_vlan_pcp;
+	nt_field_t *mp_rcp_data_vlan_tpid_sel;
+	nt_field_t *mp_rcp_data_queue_override_en;
+	nt_field_t *mp_rcp_data_queue_id;
+
+	nt_register_t *mp_special;
+	nt_field_t *mp_special_vlan_tpid_cust_tpid0;
+	nt_field_t *mp_special_vlan_tpid_cust_tpid1;
+
+	nt_register_t *mp_roa_epp_ctrl;
+	nt_field_t *mp_roa_epp_addr;
+	nt_field_t *mp_roa_epp_cnt;
+	nt_register_t *mp_roa_epp_data;
+	nt_field_t *mp_roa_epp_data_push_tunnel;
+	nt_field_t *mp_roa_epp_data_tx_port;
+};
+
+typedef struct ioa_nthw ioa_nthw_t;
+
+struct ioa_nthw *ioa_nthw_new(void);
+void ioa_nthw_delete(struct ioa_nthw *p);
+int ioa_nthw_init(struct ioa_nthw *p, nt_fpga_t *p_fpga, int n_instance);
+
+int ioa_nthw_setup(struct ioa_nthw *p, int n_idx, int n_idx_cnt);
+void ioa_nthw_set_debug_mode(struct ioa_nthw *p, unsigned int n_debug_mode);
+
+/* RCP */
+void ioa_nthw_rcp_select(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_rcp_cnt(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_rcp_tunnel_pop(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_rcp_vlan_pop(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_rcp_vlan_push(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_rcp_vlan_vid(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_rcp_vlan_dei(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_rcp_vlan_pcp(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_rcp_vlan_tpid_sel(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_rcp_queue_override_en(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_rcp_queue_id(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_rcp_flush(const struct ioa_nthw *p);
+
+/* Vlan Tpid Special */
+void ioa_nthw_special_vlan_tpid_cust_tpid0(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_special_vlan_tpid_cust_tpid1(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_special_vlan_tpid_flush(const struct ioa_nthw *p);
+
+/* EPP module */
+void ioa_nthw_roa_epp_select(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_roa_epp_cnt(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_roa_epp_push_tunnel(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_roa_epp_tx_port(const struct ioa_nthw *p, uint32_t val);
+void ioa_nthw_roa_epp_flush(const struct ioa_nthw *p);
+
+#endif /* __FLOW_NTHW_IOA_H__ */
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..af54e14940
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_km.c
@@ -0,0 +1,685 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_km.h"
+
+#include <stdint.h>
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+#define CHECK_AND_SET_VALUE(_a, val)             \
+	do {                                    \
+		__typeof__(_a) (a) = (_a); \
+		if (a) {                        \
+			field_set_val32(a, val); \
+		}                               \
+	} while (0)
+
+void km_nthw_set_debug_mode(struct km_nthw *p, unsigned int n_debug_mode)
+{
+	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, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = module_get_register(p->m_km, KM_RCP_CTRL);
+	p->mp_rcp_addr = register_get_field(p->mp_rcp_ctrl, KM_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = register_get_field(p->mp_rcp_ctrl, KM_RCP_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_km, KM_RCP_DATA);
+	p->mp_rcp_data_qw0_dyn =
+		register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW0_DYN);
+	p->mp_rcp_data_qw0_ofs =
+		register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW0_OFS);
+	p->mp_rcp_data_qw0_sel_a =
+		register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW0_SEL_A);
+	p->mp_rcp_data_qw0_sel_b =
+		register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW0_SEL_B);
+	p->mp_rcp_data_qw4_dyn =
+		register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW4_DYN);
+	p->mp_rcp_data_qw4_ofs =
+		register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW4_OFS);
+	p->mp_rcp_data_qw4_sel_a =
+		register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW4_SEL_A);
+	p->mp_rcp_data_qw4_sel_b =
+		register_get_field(p->mp_rcp_data, KM_RCP_DATA_QW4_SEL_B);
+
+	p->mp_rcp_data_sw8_dyn =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW8_DYN);
+	p->mp_rcp_data_dw8_dyn =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW8_DYN);
+
+	p->mp_rcp_data_swx_ovs_sb =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_SWX_OVS_SB);
+	p->mp_rcp_data_swx_cch =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_SWX_CCH);
+	p->mp_rcp_data_swx_sel_a =
+		register_get_field(p->mp_rcp_data, KM_RCP_DATA_SWX_SEL_A);
+	p->mp_rcp_data_swx_sel_b =
+		register_get_field(p->mp_rcp_data, KM_RCP_DATA_SWX_SEL_B);
+	p->mp_rcp_data_mask_a = register_get_field(p->mp_rcp_data, KM_RCP_DATA_MASK_A);
+	p->mp_rcp_data_mask_b = register_get_field(p->mp_rcp_data, KM_RCP_DATA_MASK_B);
+	p->mp_rcp_data_dual = register_get_field(p->mp_rcp_data, KM_RCP_DATA_DUAL);
+	p->mp_rcp_data_paired =
+		register_get_field(p->mp_rcp_data, KM_RCP_DATA_PAIRED);
+	p->mp_rcp_data_el_a = register_get_field(p->mp_rcp_data, KM_RCP_DATA_EL_A);
+	p->mp_rcp_data_el_b = register_get_field(p->mp_rcp_data, KM_RCP_DATA_EL_B);
+	p->mp_rcp_data_info_a = register_get_field(p->mp_rcp_data, KM_RCP_DATA_INFO_A);
+	p->mp_rcp_data_info_b = register_get_field(p->mp_rcp_data, KM_RCP_DATA_INFO_B);
+	p->mp_rcp_data_ftm_a = register_get_field(p->mp_rcp_data, KM_RCP_DATA_FTM_A);
+	p->mp_rcp_data_ftm_b = register_get_field(p->mp_rcp_data, KM_RCP_DATA_FTM_B);
+	p->mp_rcp_data_bank_a = register_get_field(p->mp_rcp_data, KM_RCP_DATA_BANK_A);
+	p->mp_rcp_data_bank_b = register_get_field(p->mp_rcp_data, KM_RCP_DATA_BANK_B);
+	p->mp_rcp_data_kl_a = register_get_field(p->mp_rcp_data, KM_RCP_DATA_KL_A);
+	p->mp_rcp_data_kl_b = register_get_field(p->mp_rcp_data, KM_RCP_DATA_KL_B);
+	p->mp_rcp_data_flow_set =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_FLOW_SET);
+	p->mp_rcp_data_keyway_a =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_KEYWAY_A);
+	p->mp_rcp_data_keyway_b =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_KEYWAY_B);
+	p->mp_rcp_data_synergy_mode =
+		register_get_field(p->mp_rcp_data, KM_RCP_DATA_SYNERGY_MODE);
+
+	/* CAM */
+	p->mp_cam_ctrl = module_get_register(p->m_km, KM_CAM_CTRL);
+	p->mp_cam_addr = register_get_field(p->mp_cam_ctrl, KM_CAM_CTRL_ADR);
+	p->mp_cam_cnt = register_get_field(p->mp_cam_ctrl, KM_CAM_CTRL_CNT);
+	p->mp_cam_data = module_get_register(p->m_km, KM_CAM_DATA);
+	p->mp_cam_data_w0 = register_get_field(p->mp_cam_data, KM_CAM_DATA_W0);
+	p->mp_cam_data_w1 = register_get_field(p->mp_cam_data, KM_CAM_DATA_W1);
+	p->mp_cam_data_w2 = register_get_field(p->mp_cam_data, KM_CAM_DATA_W2);
+	p->mp_cam_data_w3 = register_get_field(p->mp_cam_data, KM_CAM_DATA_W3);
+	p->mp_cam_data_w4 = register_get_field(p->mp_cam_data, KM_CAM_DATA_W4);
+	p->mp_cam_data_w5 = register_get_field(p->mp_cam_data, KM_CAM_DATA_W5);
+	p->mp_cam_data_ft0 = register_get_field(p->mp_cam_data, KM_CAM_DATA_FT0);
+	p->mp_cam_data_ft1 = register_get_field(p->mp_cam_data, KM_CAM_DATA_FT1);
+	p->mp_cam_data_ft2 = register_get_field(p->mp_cam_data, KM_CAM_DATA_FT2);
+	p->mp_cam_data_ft3 = register_get_field(p->mp_cam_data, KM_CAM_DATA_FT3);
+	p->mp_cam_data_ft4 = register_get_field(p->mp_cam_data, KM_CAM_DATA_FT4);
+	p->mp_cam_data_ft5 = register_get_field(p->mp_cam_data, KM_CAM_DATA_FT5);
+	/* TCAM */
+	p->mp_tcam_ctrl = module_get_register(p->m_km, KM_TCAM_CTRL);
+	p->mp_tcam_addr = register_get_field(p->mp_tcam_ctrl, KM_TCAM_CTRL_ADR);
+	p->mp_tcam_cnt = register_get_field(p->mp_tcam_ctrl, KM_TCAM_CTRL_CNT);
+	p->mp_tcam_data = module_get_register(p->m_km, KM_TCAM_DATA);
+	p->mp_tcam_data_t = register_get_field(p->mp_tcam_data, KM_TCAM_DATA_T);
+	/* TCI */
+	p->mp_tci_ctrl = module_get_register(p->m_km, KM_TCI_CTRL);
+	p->mp_tci_addr = register_get_field(p->mp_tci_ctrl, KM_TCI_CTRL_ADR);
+	p->mp_tci_cnt = register_get_field(p->mp_tci_ctrl, KM_TCI_CTRL_CNT);
+	p->mp_tci_data = module_get_register(p->m_km, KM_TCI_DATA);
+	p->mp_tci_data_color = register_get_field(p->mp_tci_data, KM_TCI_DATA_COLOR);
+	p->mp_tci_data_ft = register_get_field(p->mp_tci_data, KM_TCI_DATA_FT);
+	/* TCQ */
+	p->mp_tcq_ctrl = module_get_register(p->m_km, KM_TCQ_CTRL);
+	p->mp_tcq_addr = register_get_field(p->mp_tcq_ctrl, KM_TCQ_CTRL_ADR);
+	p->mp_tcq_cnt = register_get_field(p->mp_tcq_ctrl, KM_TCQ_CTRL_CNT);
+	p->mp_tcq_data = module_get_register(p->m_km, KM_TCQ_DATA);
+	p->mp_tcq_data_bank_mask =
+		register_query_field(p->mp_tcq_data, KM_TCQ_DATA_BANK_MASK);
+	p->mp_tcq_data_qual = register_get_field(p->mp_tcq_data, KM_TCQ_DATA_QUAL);
+
+	p->mp_rcp_data_dw0_b_dyn =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW0_B_DYN);
+	p->mp_rcp_data_dw0_b_ofs =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW0_B_OFS);
+	p->mp_rcp_data_dw2_b_dyn =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW2_B_DYN);
+	p->mp_rcp_data_dw2_b_ofs =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW2_B_OFS);
+	p->mp_rcp_data_sw4_b_dyn =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW4_B_DYN);
+	p->mp_rcp_data_sw4_b_ofs =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW4_B_OFS);
+	p->mp_rcp_data_sw5_b_dyn =
+		register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW5_B_DYN);
+	p->mp_rcp_data_sw5_b_ofs =
+		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 =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_QW0_B_DYN);
+		p->mp_rcp_data_dw0_b_ofs =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_QW0_B_OFS);
+		p->mp_rcp_data_dw2_b_dyn =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_QW4_B_DYN);
+		p->mp_rcp_data_dw2_b_ofs =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_QW4_B_OFS);
+		p->mp_rcp_data_sw4_b_dyn =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW8_B_DYN);
+		p->mp_rcp_data_sw4_b_ofs =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW8_B_OFS);
+		p->mp_rcp_data_sw5_b_dyn =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW9_B_DYN);
+		p->mp_rcp_data_sw5_b_ofs =
+			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 =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW8_OFS);
+		p->mp_rcp_data_dw8_sel_a =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW8_SEL_A);
+		p->mp_rcp_data_dw8_sel_b =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW8_SEL_B);
+		p->mp_rcp_data_dw10_dyn =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW10_DYN);
+		p->mp_rcp_data_dw10_ofs =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW10_OFS);
+		p->mp_rcp_data_dw10_sel_a =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_DW10_SEL_A);
+		p->mp_rcp_data_dw10_sel_b =
+			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 =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW8_OFS);
+		p->mp_rcp_data_sw8_sel_a =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW8_SEL_A);
+		p->mp_rcp_data_sw8_sel_b =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW8_SEL_B);
+		p->mp_rcp_data_sw9_dyn =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW9_DYN);
+		p->mp_rcp_data_sw9_ofs =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW9_OFS);
+		p->mp_rcp_data_sw9_sel_a =
+			register_query_field(p->mp_rcp_data, KM_RCP_DATA_SW9_SEL_A);
+		p->mp_rcp_data_sw9_sel_b =
+			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)
+{
+	field_set_val32(p->mp_rcp_addr, val);
+};
+
+void km_nthw_rcp_cnt(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_cnt, val);
+};
+
+void km_nthw_rcp_qw0_dyn(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_qw0_dyn, val);
+};
+
+void km_nthw_rcp_qw0_ofs(const struct km_nthw *p, int32_t val)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	field_set_val32(p->mp_rcp_data_qw4_dyn, val);
+};
+
+void km_nthw_rcp_qw4_ofs(const struct km_nthw *p, int32_t val)
+{
+	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)
+{
+	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)
+{
+	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_sw8_dyn(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_sw8_dyn, val);
+};
+
+void km_nthw_rcp_sw8_ofs(const struct km_nthw *p, int32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_sw8_ofs, val);
+};
+
+void km_nthw_rcp_sw8_sel_a(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_sw8_sel_a, val);
+};
+
+void km_nthw_rcp_sw8_sel_b(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_sw8_sel_b, val);
+};
+
+void km_nthw_rcp_sw9_dyn(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_sw9_dyn, val);
+};
+
+void km_nthw_rcp_sw9_ofs(const struct km_nthw *p, int32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_sw9_ofs, val);
+};
+
+void km_nthw_rcp_sw9_sel_a(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_sw9_sel_a, val);
+};
+
+void km_nthw_rcp_sw9_sel_b(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_sw9_sel_b, val);
+};
+
+void km_nthw_rcp_swx_ovs_sb(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_swx_ovs_sb, 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)
+{
+	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)
+{
+	field_set_val32(p->mp_rcp_data_swx_sel_b, val);
+};
+
+void km_nthw_rcp_mask_a(const struct km_nthw *p, const uint32_t *val)
+{
+	field_set_val(p->mp_rcp_data_mask_a, val, p->mp_rcp_data_mask_a->mn_words);
+};
+
+void km_nthw_rcp_mask_b(const struct km_nthw *p, const uint32_t *val)
+{
+	field_set_val(p->mp_rcp_data_mask_b, val, p->mp_rcp_data_mask_b->mn_words);
+};
+
+void km_nthw_rcp_mask_d_a(const struct km_nthw *p, const uint32_t *val)
+{
+	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)
+{
+	field_set_val32(p->mp_rcp_data_dual, val);
+};
+
+void km_nthw_rcp_paired(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_paired, val);
+};
+
+void km_nthw_rcp_el_a(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_el_a, val);
+};
+
+void km_nthw_rcp_el_b(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_el_b, val);
+};
+
+void km_nthw_rcp_info_a(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_info_a, val);
+};
+
+void km_nthw_rcp_info_b(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_info_b, val);
+};
+
+void km_nthw_rcp_ftm_a(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_ftm_a, val);
+};
+
+void km_nthw_rcp_ftm_b(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_ftm_b, val);
+};
+
+void km_nthw_rcp_bank_a(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_bank_a, val);
+};
+
+void km_nthw_rcp_bank_b(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_bank_b, val);
+};
+
+void km_nthw_rcp_kl_a(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_kl_a, val);
+};
+
+void km_nthw_rcp_kl_b(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_kl_b, val);
+};
+
+void km_nthw_rcp_flow_set(const struct km_nthw *p, uint32_t val)
+{
+	CHECK_AND_SET_VALUE(p->mp_rcp_data_flow_set, 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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	field_set_val32(p->mp_rcp_data_sw5_b_ofs, val);
+};
+
+void km_nthw_rcp_flush(const struct km_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	register_flush(p->mp_rcp_data, 1);
+};
+
+/* CAM */
+void km_nthw_cam_select(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_addr, val);
+};
+
+void km_nthw_cam_cnt(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_cnt, val);
+};
+
+void km_nthw_cam_w0(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_data_w0, val);
+};
+
+void km_nthw_cam_w1(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_data_w1, val);
+};
+
+void km_nthw_cam_w2(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_data_w2, val);
+};
+
+void km_nthw_cam_w3(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_data_w3, val);
+};
+
+void km_nthw_cam_w4(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_data_w4, val);
+};
+
+void km_nthw_cam_w5(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_data_w5, val);
+};
+
+void km_nthw_cam_ft0(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_data_ft0, val);
+};
+
+void km_nthw_cam_ft1(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_data_ft1, val);
+};
+
+void km_nthw_cam_ft2(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_data_ft2, val);
+};
+
+void km_nthw_cam_ft3(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_data_ft3, val);
+};
+
+void km_nthw_cam_ft4(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_data_ft4, val);
+};
+
+void km_nthw_cam_ft5(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_cam_data_ft5, val);
+};
+
+void km_nthw_cam_flush(const struct km_nthw *p)
+{
+	register_flush(p->mp_cam_ctrl, 1);
+	register_flush(p->mp_cam_data, 1);
+};
+
+/* TCAM */
+void km_nthw_tcam_select(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tcam_addr, val);
+};
+
+void km_nthw_tcam_cnt(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tcam_cnt, val);
+};
+
+void km_nthw_tcam_t(const struct km_nthw *p, uint32_t *val)
+{
+	field_set_val(p->mp_tcam_data_t, val, 3);
+};
+
+void km_nthw_tcam_flush(const struct km_nthw *p)
+{
+	register_flush(p->mp_tcam_ctrl, 1);
+	register_flush(p->mp_tcam_data, 1);
+};
+
+/* TCI */
+void km_nthw_tci_select(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tci_addr, val);
+};
+
+void km_nthw_tci_cnt(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tci_cnt, val);
+};
+
+void km_nthw_tci_color(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tci_data_color, val);
+};
+
+void km_nthw_tci_ft(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tci_data_ft, val);
+};
+
+void km_nthw_tci_flush(const struct km_nthw *p)
+{
+	register_flush(p->mp_tci_ctrl, 1);
+	register_flush(p->mp_tci_data, 1);
+};
+
+/* TCQ */
+void km_nthw_tcq_select(const struct km_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tcq_addr, val);
+};
+
+void km_nthw_tcq_cnt(const struct km_nthw *p, uint32_t val)
+{
+	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)
+{
+	field_set_val32(p->mp_tcq_data_qual, val);
+};
+
+void km_nthw_tcq_qual72(const struct km_nthw *p, uint32_t *val)
+{
+	field_set_val(p->mp_tcq_data_qual, val, 3);
+}; /* to use in v4 */
+
+void km_nthw_tcq_flush(const struct km_nthw *p)
+{
+	register_flush(p->mp_tcq_ctrl, 1);
+	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..61f9ed2ae4
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_km.h
@@ -0,0 +1,224 @@
+/* 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> /* uint32_t */
+#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, nt_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);
+void km_nthw_rcp_sw8_dyn(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_sw8_ofs(const struct km_nthw *p, int32_t val);
+void km_nthw_rcp_sw8_sel_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_sw8_sel_b(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_sw9_dyn(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_sw9_ofs(const struct km_nthw *p, int32_t val);
+void km_nthw_rcp_sw9_sel_a(const struct km_nthw *p, uint32_t val);
+void km_nthw_rcp_sw9_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_ovs_sb(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_a(const struct km_nthw *p, const uint32_t *val);
+void km_nthw_rcp_mask_d_a(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_flow_set(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_qual72(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;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_km;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_addr;
+	nt_field_t *mp_rcp_cnt;
+	nt_register_t *mp_rcp_data;
+	nt_field_t *mp_rcp_data_qw0_dyn;
+	nt_field_t *mp_rcp_data_qw0_ofs;
+	nt_field_t *mp_rcp_data_qw0_sel_a;
+	nt_field_t *mp_rcp_data_qw0_sel_b;
+	nt_field_t *mp_rcp_data_qw4_dyn;
+	nt_field_t *mp_rcp_data_qw4_ofs;
+	nt_field_t *mp_rcp_data_qw4_sel_a;
+	nt_field_t *mp_rcp_data_qw4_sel_b;
+	nt_field_t *mp_rcp_data_sw8_dyn;
+	nt_field_t *mp_rcp_data_sw8_ofs;
+	nt_field_t *mp_rcp_data_sw8_sel_a;
+	nt_field_t *mp_rcp_data_sw8_sel_b;
+	nt_field_t *mp_rcp_data_sw9_dyn;
+	nt_field_t *mp_rcp_data_sw9_ofs;
+	nt_field_t *mp_rcp_data_sw9_sel_a;
+	nt_field_t *mp_rcp_data_sw9_sel_b;
+
+	nt_field_t *mp_rcp_data_dw8_dyn; /* substituted Sw<x> from v6+ */
+	nt_field_t *mp_rcp_data_dw8_ofs; /* substituted Sw<x> from v6+ */
+	nt_field_t *mp_rcp_data_dw8_sel_a; /* substituted Sw<x> from v6+ */
+	nt_field_t *mp_rcp_data_dw8_sel_b; /* substituted Sw<x> from v6+ */
+	nt_field_t *mp_rcp_data_dw10_dyn; /* substituted Sw<x> from v6+ */
+	nt_field_t *mp_rcp_data_dw10_ofs; /* substituted Sw<x> from v6+ */
+	nt_field_t *mp_rcp_data_dw10_sel_a; /* substituted Sw<x> from v6+ */
+	nt_field_t *mp_rcp_data_dw10_sel_b; /* substituted Sw<x> from v6+ */
+
+	nt_field_t *mp_rcp_data_swx_ovs_sb;
+	nt_field_t *mp_rcp_data_swx_cch;
+	nt_field_t *mp_rcp_data_swx_sel_a;
+	nt_field_t *mp_rcp_data_swx_sel_b;
+	nt_field_t *mp_rcp_data_mask_a;
+	nt_field_t *mp_rcp_data_mask_b;
+	nt_field_t *mp_rcp_data_dual;
+	nt_field_t *mp_rcp_data_paired;
+	nt_field_t *mp_rcp_data_el_a;
+	nt_field_t *mp_rcp_data_el_b;
+	nt_field_t *mp_rcp_data_info_a;
+	nt_field_t *mp_rcp_data_info_b;
+	nt_field_t *mp_rcp_data_ftm_a;
+	nt_field_t *mp_rcp_data_ftm_b;
+	nt_field_t *mp_rcp_data_bank_a;
+	nt_field_t *mp_rcp_data_bank_b;
+	nt_field_t *mp_rcp_data_kl_a;
+	nt_field_t *mp_rcp_data_kl_b;
+	nt_field_t *mp_rcp_data_flow_set;
+	nt_field_t *mp_rcp_data_keyway_a;
+	nt_field_t *mp_rcp_data_keyway_b;
+	nt_field_t *mp_rcp_data_synergy_mode;
+	nt_field_t *mp_rcp_data_dw0_b_dyn;
+	nt_field_t *mp_rcp_data_dw0_b_ofs;
+	nt_field_t *mp_rcp_data_dw2_b_dyn;
+	nt_field_t *mp_rcp_data_dw2_b_ofs;
+	nt_field_t *mp_rcp_data_sw4_b_dyn;
+	nt_field_t *mp_rcp_data_sw4_b_ofs;
+	nt_field_t *mp_rcp_data_sw5_b_dyn;
+	nt_field_t *mp_rcp_data_sw5_b_ofs;
+
+	nt_register_t *mp_cam_ctrl;
+	nt_field_t *mp_cam_addr;
+	nt_field_t *mp_cam_cnt;
+	nt_register_t *mp_cam_data;
+	nt_field_t *mp_cam_data_w0;
+	nt_field_t *mp_cam_data_w1;
+	nt_field_t *mp_cam_data_w2;
+	nt_field_t *mp_cam_data_w3;
+	nt_field_t *mp_cam_data_w4;
+	nt_field_t *mp_cam_data_w5;
+	nt_field_t *mp_cam_data_ft0;
+	nt_field_t *mp_cam_data_ft1;
+	nt_field_t *mp_cam_data_ft2;
+	nt_field_t *mp_cam_data_ft3;
+	nt_field_t *mp_cam_data_ft4;
+	nt_field_t *mp_cam_data_ft5;
+
+	nt_register_t *mp_tcam_ctrl;
+	nt_field_t *mp_tcam_addr;
+	nt_field_t *mp_tcam_cnt;
+	nt_register_t *mp_tcam_data;
+	nt_field_t *mp_tcam_data_t;
+
+	nt_register_t *mp_tci_ctrl;
+	nt_field_t *mp_tci_addr;
+	nt_field_t *mp_tci_cnt;
+	nt_register_t *mp_tci_data;
+	nt_field_t *mp_tci_data_color;
+	nt_field_t *mp_tci_data_ft;
+
+	nt_register_t *mp_tcq_ctrl;
+	nt_field_t *mp_tcq_addr;
+	nt_field_t *mp_tcq_cnt;
+	nt_register_t *mp_tcq_data;
+	nt_field_t *mp_tcq_data_bank_mask;
+	nt_field_t *mp_tcq_data_qual;
+};
+
+#endif /* __FLOW_NTHW_KM_H__ */
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..e823a527bb
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_pdb.c
@@ -0,0 +1,230 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_pdb.h"
+
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+void pdb_nthw_set_debug_mode(struct pdb_nthw *p, unsigned int n_debug_mode)
+{
+	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, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = module_get_register(p->m_pdb, PDB_RCP_CTRL);
+	p->mp_rcp_addr = register_get_field(p->mp_rcp_ctrl, PDB_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = register_get_field(p->mp_rcp_ctrl, PDB_RCP_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_pdb, PDB_RCP_DATA);
+	p->mp_rcp_data_descriptor =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_DESCRIPTOR);
+	p->mp_rcp_data_desc_len =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_DESC_LEN);
+	p->mp_rcp_data_tx_port =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_TX_PORT);
+	p->mp_rcp_data_tx_ignore =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_TX_IGNORE);
+	p->mp_rcp_data_tx_now =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_TX_NOW);
+	p->mp_rcp_data_crc_overwrite =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_CRC_OVERWRITE);
+	p->mp_rcp_data_align = register_get_field(p->mp_rcp_data, PDB_RCP_DATA_ALIGN);
+	p->mp_rcp_data_ofs0_dyn =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_OFS0_DYN);
+	p->mp_rcp_data_ofs0_rel =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_OFS0_REL);
+	p->mp_rcp_data_ofs1_dyn =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_OFS1_DYN);
+	p->mp_rcp_data_ofs1_rel =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_OFS1_REL);
+	p->mp_rcp_data_ofs2_dyn =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_OFS2_DYN);
+	p->mp_rcp_data_ofs2_rel =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_OFS2_REL);
+	p->mp_rcp_data_ip_prot_tnl =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_IP_PROT_TNL);
+	p->mp_rcp_data_ppc_hsh =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_PPC_HSH);
+	p->mp_rcp_data_duplicate_en =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_DUPLICATE_EN);
+	p->mp_rcp_data_duplicate_bit =
+		register_get_field(p->mp_rcp_data, PDB_RCP_DATA_DUPLICATE_BIT);
+	p->mp_rcp_data_pcap_keep_fcs =
+		register_query_field(p->mp_rcp_data, PDB_RCP_DATA_PCAP_KEEP_FCS);
+	/* CONFIG */
+	p->mp_config = module_get_register(p->m_pdb, PDB_CONFIG);
+	p->mp_config_ts_format =
+		register_get_field(p->mp_config, PDB_CONFIG_TS_FORMAT);
+	p->mp_config_port_ofs =
+		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)
+{
+	field_set_val32(p->mp_rcp_addr, val);
+}
+
+void pdb_nthw_rcp_cnt(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void pdb_nthw_rcp_descriptor(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_descriptor, val);
+}
+
+void pdb_nthw_rcp_desc_len(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_desc_len, val);
+}
+
+void pdb_nthw_rcp_tx_port(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_tx_port, val);
+}
+
+void pdb_nthw_rcp_tx_ignore(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_tx_ignore, val);
+}
+
+void pdb_nthw_rcp_tx_now(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_tx_now, val);
+}
+
+void pdb_nthw_rcp_crc_overwrite(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_crc_overwrite, val);
+}
+
+void pdb_nthw_rcp_align(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_align, val);
+}
+
+void pdb_nthw_rcp_ofs0_dyn(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_ofs0_dyn, val);
+}
+
+void pdb_nthw_rcp_ofs0_rel(const struct pdb_nthw *p, int32_t val)
+{
+	field_set_val32(p->mp_rcp_data_ofs0_rel, val);
+}
+
+void pdb_nthw_rcp_ofs1_dyn(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_ofs1_dyn, val);
+}
+
+void pdb_nthw_rcp_ofs1_rel(const struct pdb_nthw *p, int32_t val)
+{
+	field_set_val32(p->mp_rcp_data_ofs1_rel, val);
+}
+
+void pdb_nthw_rcp_ofs2_dyn(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_ofs2_dyn, val);
+}
+
+void pdb_nthw_rcp_ofs2_rel(const struct pdb_nthw *p, int32_t val)
+{
+	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)
+{
+	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)
+{
+	field_set_val32(p->mp_rcp_data_ppc_hsh, val);
+}
+
+void pdb_nthw_rcp_duplicate_en(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_duplicate_en, val);
+}
+
+void pdb_nthw_rcp_duplicate_bit(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_duplicate_bit, val);
+}
+
+void pdb_nthw_rcp_data_pcap_keep_fcs(const struct pdb_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_pcap_keep_fcs)
+		field_set_val32(p->mp_rcp_data_pcap_keep_fcs, val);
+}
+
+void pdb_nthw_rcp_flush(const struct pdb_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	register_flush(p->mp_rcp_data, 1);
+}
+
+/* CONFIG */
+void pdb_nthw_config_ts_format(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_config_ts_format, val);
+}
+
+void pdb_nthw_config_port_ofs(const struct pdb_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_config_port_ofs, val);
+}
+
+void pdb_nthw_config_flush(const struct pdb_nthw *p)
+{
+	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..aed050eca5
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_pdb.h
@@ -0,0 +1,84 @@
+/* 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> /* uint32_t */
+#include "nthw_fpga_model.h"
+
+struct pdb_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_pdb;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_addr;
+	nt_field_t *mp_rcp_cnt;
+	nt_register_t *mp_rcp_data;
+	nt_field_t *mp_rcp_data_descriptor;
+	nt_field_t *mp_rcp_data_desc_len;
+	nt_field_t *mp_rcp_data_tx_port;
+	nt_field_t *mp_rcp_data_tx_ignore;
+	nt_field_t *mp_rcp_data_tx_now;
+	nt_field_t *mp_rcp_data_crc_overwrite;
+	nt_field_t *mp_rcp_data_align;
+	nt_field_t *mp_rcp_data_ofs0_dyn;
+	nt_field_t *mp_rcp_data_ofs0_rel;
+	nt_field_t *mp_rcp_data_ofs1_dyn;
+	nt_field_t *mp_rcp_data_ofs1_rel;
+	nt_field_t *mp_rcp_data_ofs2_dyn;
+	nt_field_t *mp_rcp_data_ofs2_rel;
+	nt_field_t *mp_rcp_data_ip_prot_tnl;
+	nt_field_t *mp_rcp_data_ppc_hsh;
+	nt_field_t *mp_rcp_data_duplicate_en;
+	nt_field_t *mp_rcp_data_duplicate_bit;
+	nt_field_t *mp_rcp_data_pcap_keep_fcs;
+
+	nt_register_t *mp_config;
+	nt_field_t *mp_config_ts_format;
+	nt_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, nt_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_data_pcap_keep_fcs(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/flow_filter/flow_nthw_qsl.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.c
new file mode 100644
index 0000000000..6c13824df6
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.c
@@ -0,0 +1,355 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_qsl.h"
+
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+void qsl_nthw_set_debug_mode(struct qsl_nthw *p, unsigned int n_debug_mode)
+{
+	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, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = module_get_register(p->m_qsl, QSL_RCP_CTRL);
+	p->mp_rcp_addr = register_get_field(p->mp_rcp_ctrl, QSL_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = register_get_field(p->mp_rcp_ctrl, QSL_RCP_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_qsl, QSL_RCP_DATA);
+	p->mp_rcp_data_discard =
+		register_get_field(p->mp_rcp_data, QSL_RCP_DATA_DISCARD);
+	p->mp_rcp_data_drop = register_get_field(p->mp_rcp_data, QSL_RCP_DATA_DROP);
+	p->mp_rcp_data_tbl_lo =
+		register_get_field(p->mp_rcp_data, QSL_RCP_DATA_TBL_LO);
+	p->mp_rcp_data_tbl_hi =
+		register_get_field(p->mp_rcp_data, QSL_RCP_DATA_TBL_HI);
+	p->mp_rcp_data_tbl_idx =
+		register_get_field(p->mp_rcp_data, QSL_RCP_DATA_TBL_IDX);
+	p->mp_rcp_data_tbl_msk =
+		register_get_field(p->mp_rcp_data, QSL_RCP_DATA_TBL_MSK);
+	p->mp_rcp_data_cao = register_query_field(p->mp_rcp_data, QSL_RCP_DATA_CAO);
+	p->mp_rcp_data_lr = register_query_field(p->mp_rcp_data, QSL_RCP_DATA_LR);
+	p->mp_rcp_data_tsa = register_query_field(p->mp_rcp_data, QSL_RCP_DATA_TSA);
+	p->mp_rcp_data_vli = register_query_field(p->mp_rcp_data, QSL_RCP_DATA_VLI);
+
+	/* QST */
+	p->mp_qst_ctrl = module_get_register(p->m_qsl, QSL_QST_CTRL);
+	p->mp_qst_addr = register_get_field(p->mp_qst_ctrl, QSL_QST_CTRL_ADR);
+	p->mp_qst_cnt = register_get_field(p->mp_qst_ctrl, QSL_QST_CTRL_CNT);
+	p->mp_qst_data = module_get_register(p->m_qsl, QSL_QST_DATA);
+	p->mp_qst_data_queue = register_get_field(p->mp_qst_data, QSL_QST_DATA_QUEUE);
+	p->mp_qst_data_en = register_query_field(p->mp_qst_data, QSL_QST_DATA_EN);
+	p->mp_qst_data_tx_port =
+		register_query_field(p->mp_qst_data, QSL_QST_DATA_TX_PORT);
+	p->mp_qst_data_lre = register_query_field(p->mp_qst_data, QSL_QST_DATA_LRE);
+	p->mp_qst_data_tci = register_query_field(p->mp_qst_data, QSL_QST_DATA_TCI);
+	p->mp_qst_data_ven = register_query_field(p->mp_qst_data, QSL_QST_DATA_VEN);
+	/* QEN */
+	p->mp_qen_ctrl = module_get_register(p->m_qsl, QSL_QEN_CTRL);
+	p->mp_qen_addr = register_get_field(p->mp_qen_ctrl, QSL_QEN_CTRL_ADR);
+	p->mp_qen_cnt = register_get_field(p->mp_qen_ctrl, QSL_QEN_CTRL_CNT);
+	p->mp_qen_data = module_get_register(p->m_qsl, QSL_QEN_DATA);
+	p->mp_qen_data_en = register_get_field(p->mp_qen_data, QSL_QEN_DATA_EN);
+	/* UNMQ */
+	p->mp_unmq_ctrl = module_get_register(p->m_qsl, QSL_UNMQ_CTRL);
+	p->mp_unmq_addr = register_get_field(p->mp_unmq_ctrl, QSL_UNMQ_CTRL_ADR);
+	p->mp_unmq_cnt = register_get_field(p->mp_unmq_ctrl, QSL_UNMQ_CTRL_CNT);
+	p->mp_unmq_data = module_get_register(p->m_qsl, QSL_UNMQ_DATA);
+	p->mp_unmq_data_dest_queue =
+		register_get_field(p->mp_unmq_data, QSL_UNMQ_DATA_DEST_QUEUE);
+	p->mp_unmq_data_en = 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 =
+			register_get_field(p->mp_qst_data, QSL_QST_DATA_QEN);
+	}
+
+	/* LTX - not there anymore from v0.7+ */
+	p->mp_ltx_ctrl = module_query_register(p->m_qsl, QSL_LTX_CTRL);
+	if (p->mp_ltx_ctrl) {
+		p->mp_ltx_addr =
+			register_get_field(p->mp_ltx_ctrl, QSL_LTX_CTRL_ADR);
+		p->mp_ltx_cnt = 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 = module_query_register(p->m_qsl, QSL_LTX_DATA);
+	if (p->mp_ltx_data) {
+		p->mp_ltx_data_lr =
+			register_get_field(p->mp_ltx_data, QSL_LTX_DATA_LR);
+		p->mp_ltx_data_tx_port =
+			register_get_field(p->mp_ltx_data, QSL_LTX_DATA_TX_PORT);
+		p->mp_ltx_data_tsa =
+			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;
+}
+
+int qsl_nthw_setup(struct qsl_nthw *p, int n_idx, int n_idx_cnt)
+{
+	(void)p;
+	(void)n_idx;
+	(void)n_idx_cnt;
+
+	return 0;
+}
+
+/* RCP */
+void qsl_nthw_rcp_select(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_addr, val);
+};
+
+void qsl_nthw_rcp_cnt(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void qsl_nthw_rcp_discard(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_discard, val);
+}
+
+void qsl_nthw_rcp_drop(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_drop, val);
+}
+
+void qsl_nthw_rcp_tbl_lo(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_tbl_lo, val);
+}
+
+void qsl_nthw_rcp_tbl_hi(const struct qsl_nthw *p, uint32_t val)
+
+{
+	field_set_val32(p->mp_rcp_data_tbl_hi, val);
+}
+
+void qsl_nthw_rcp_tbl_idx(const struct qsl_nthw *p, uint32_t val)
+
+{
+	field_set_val32(p->mp_rcp_data_tbl_idx, val);
+}
+
+void qsl_nthw_rcp_tbl_msk(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_tbl_msk, val);
+}
+
+void qsl_nthw_rcp_cao(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_cao)
+		field_set_val32(p->mp_rcp_data_cao, val);
+}
+
+void qsl_nthw_rcp_lr(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_rcp_data_lr)
+		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)
+		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)
+		field_set_val32(p->mp_rcp_data_vli, val);
+}
+
+void qsl_nthw_rcp_flush(const struct qsl_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	register_flush(p->mp_rcp_data, 1);
+}
+
+/* LTX */
+void qsl_nthw_ltx_select(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_ltx_addr)
+		field_set_val32(p->mp_ltx_addr, val);
+}
+
+void qsl_nthw_ltx_cnt(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_ltx_addr)
+		field_set_val32(p->mp_ltx_cnt, val);
+}
+
+void qsl_nthw_ltx_lr(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_ltx_data_lr)
+		field_set_val32(p->mp_ltx_data_lr, val);
+}
+
+void qsl_nthw_ltx_tx_port(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_ltx_data_tx_port)
+		field_set_val32(p->mp_ltx_data_tx_port, val);
+}
+
+void qsl_nthw_ltx_tsa(const struct qsl_nthw *p, uint32_t val)
+{
+	if (p->mp_ltx_data_tsa)
+		field_set_val32(p->mp_ltx_data_tsa, val);
+};
+
+void qsl_nthw_ltx_flush(const struct qsl_nthw *p)
+{
+	register_flush(p->mp_ltx_ctrl, 1);
+	register_flush(p->mp_ltx_data, 1);
+}
+
+/* QST */
+void qsl_nthw_qst_select(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_qst_addr, val);
+}
+
+void qsl_nthw_qst_cnt(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_qst_cnt, val);
+}
+
+void qsl_nthw_qst_queue(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_qst_data_queue, val);
+}
+
+void qsl_nthw_qst_en(const struct qsl_nthw *p, uint32_t val)
+{
+	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)
+		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)
+		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)
+		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)
+		field_set_val32(p->mp_qst_data_ven, val);
+}
+
+void qsl_nthw_qst_flush(const struct qsl_nthw *p)
+{
+	register_flush(p->mp_qst_ctrl, 1);
+	register_flush(p->mp_qst_data, 1);
+}
+
+/* QEN */
+void qsl_nthw_qen_select(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_qen_addr, val);
+}
+
+void qsl_nthw_qen_cnt(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_qen_cnt, val);
+}
+
+void qsl_nthw_qen_en(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_qen_data_en, val);
+}
+
+void qsl_nthw_qen_flush(const struct qsl_nthw *p)
+{
+	register_flush(p->mp_qen_ctrl, 1);
+	register_flush(p->mp_qen_data, 1);
+}
+
+/* UNMQ */
+void qsl_nthw_unmq_select(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_unmq_addr, val);
+}
+
+void qsl_nthw_unmq_cnt(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_unmq_cnt, val);
+}
+
+void qsl_nthw_unmq_dest_queue(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_unmq_data_dest_queue, val);
+}
+
+void qsl_nthw_unmq_en(const struct qsl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_unmq_data_en, val);
+}
+
+void qsl_nthw_unmq_flush(const struct qsl_nthw *p)
+{
+	register_flush(p->mp_unmq_ctrl, 1);
+	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..eeebbcf1c4
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_qsl.h
@@ -0,0 +1,121 @@
+/* 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> /* uint32_t */
+#include "nthw_fpga_model.h"
+
+struct qsl_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_qsl;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_addr;
+	nt_field_t *mp_rcp_cnt;
+	nt_register_t *mp_rcp_data;
+	nt_field_t *mp_rcp_data_discard;
+	nt_field_t *mp_rcp_data_drop;
+	nt_field_t *mp_rcp_data_tbl_lo;
+	nt_field_t *mp_rcp_data_tbl_hi;
+	nt_field_t *mp_rcp_data_tbl_idx;
+	nt_field_t *mp_rcp_data_tbl_msk;
+	nt_field_t *mp_rcp_data_cao;
+	nt_field_t *mp_rcp_data_lr;
+	nt_field_t *mp_rcp_data_tsa;
+	nt_field_t *mp_rcp_data_vli;
+
+	nt_register_t *mp_ltx_ctrl;
+	nt_field_t *mp_ltx_addr;
+	nt_field_t *mp_ltx_cnt;
+	nt_register_t *mp_ltx_data;
+	nt_field_t *mp_ltx_data_lr;
+	nt_field_t *mp_ltx_data_tx_port;
+	nt_field_t *mp_ltx_data_tsa;
+
+	nt_register_t *mp_qst_ctrl;
+	nt_field_t *mp_qst_addr;
+	nt_field_t *mp_qst_cnt;
+	nt_register_t *mp_qst_data;
+	nt_field_t *mp_qst_data_queue;
+	nt_field_t *mp_qst_data_en;
+	nt_field_t *mp_qst_data_tx_port;
+	nt_field_t *mp_qst_data_lre;
+	nt_field_t *mp_qst_data_tci;
+	nt_field_t *mp_qst_data_ven;
+
+	nt_register_t *mp_qen_ctrl;
+	nt_field_t *mp_qen_addr;
+	nt_field_t *mp_qen_cnt;
+	nt_register_t *mp_qen_data;
+	nt_field_t *mp_qen_data_en;
+
+	nt_register_t *mp_unmq_ctrl;
+	nt_field_t *mp_unmq_addr;
+	nt_field_t *mp_unmq_cnt;
+	nt_register_t *mp_unmq_data;
+	nt_field_t *mp_unmq_data_dest_queue;
+	nt_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, nt_fpga_t *p_fpga, int n_instance);
+
+int qsl_nthw_setup(struct qsl_nthw *p, int n_idx, int n_idx_cnt);
+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_cao(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);
+
+/* LTX */
+void qsl_nthw_ltx_select(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_ltx_cnt(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_ltx_lr(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_ltx_tx_port(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_ltx_tsa(const struct qsl_nthw *p, uint32_t val);
+void qsl_nthw_ltx_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/flow_filter/flow_nthw_rmc.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rmc.c
new file mode 100644
index 0000000000..8f519b7728
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rmc.c
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_rmc.h"
+
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+void rmc_nthw_set_debug_mode(struct rmc_nthw *p, unsigned int n_debug_mode)
+{
+	module_set_debug_mode(p->m_rmc, n_debug_mode);
+}
+
+struct rmc_nthw *rmc_nthw_new(void)
+{
+	struct rmc_nthw *p = malloc(sizeof(struct rmc_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void rmc_nthw_delete(struct rmc_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int rmc_nthw_init(struct rmc_nthw *p, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = fpga_query_module(p_fpga, MOD_RMC, 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: RMC %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_rmc = p_mod;
+
+	/* CTRL */
+	p->mp_ctrl = module_get_register(p->m_rmc, RMC_CTRL);
+	p->mp_ctrl_block_statt =
+		register_get_field(p->mp_ctrl, RMC_CTRL_BLOCK_STATT);
+	p->mp_ctrl_block_keep_a =
+		register_get_field(p->mp_ctrl, RMC_CTRL_BLOCK_KEEPA);
+	p->mp_ctrl_block_rpp_slice =
+		register_query_field(p->mp_ctrl, RMC_CTRL_BLOCK_RPP_SLICE);
+	p->mp_ctrl_block_mac_port =
+		register_get_field(p->mp_ctrl, RMC_CTRL_BLOCK_MAC_PORT);
+	p->mp_ctrl_lag_phy_odd_even =
+		register_get_field(p->mp_ctrl, RMC_CTRL_LAG_PHY_ODD_EVEN);
+	return 0;
+}
+
+int rmc_nthw_setup(struct rmc_nthw *p, int n_idx, int n_idx_cnt)
+{
+	(void)p;
+	(void)n_idx;
+	(void)n_idx_cnt;
+
+	return 0;
+}
+
+/* CTRL */
+void rmc_nthw_ctrl_block_statt(const struct rmc_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_ctrl_block_statt, val);
+}
+
+void rmc_nthw_ctrl_block_keep_a(const struct rmc_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_ctrl_block_keep_a, val);
+}
+
+void rmc_nthw_ctrl_block_rpp_slice(const struct rmc_nthw *p, uint32_t val)
+{
+	if (p->mp_ctrl_block_rpp_slice)
+		field_set_val32(p->mp_ctrl_block_rpp_slice, val);
+}
+
+void rmc_nthw_ctrl_block_mac_port(const struct rmc_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_ctrl_block_mac_port, val);
+}
+
+void rmc_nthw_ctrl_lag_phy_odd_even(const struct rmc_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_ctrl_lag_phy_odd_even, val);
+}
+
+void rmc_nthw_ctrl_flush(const struct rmc_nthw *p)
+{
+	register_flush(p->mp_ctrl, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rmc.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rmc.h
new file mode 100644
index 0000000000..57d5776002
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rmc.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_RMC_H__
+#define __FLOW_NTHW_RMC_H__
+
+#include <stdint.h> /* uint32_t */
+#include "nthw_fpga_model.h"
+
+struct rmc_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_rmc;
+
+	nt_register_t *mp_ctrl;
+	nt_field_t *mp_ctrl_block_statt;
+	nt_field_t *mp_ctrl_block_keep_a;
+	nt_field_t *mp_ctrl_block_rpp_slice;
+	nt_field_t *mp_ctrl_block_mac_port;
+	nt_field_t *mp_ctrl_lag_phy_odd_even;
+};
+
+struct rmc_nthw *rmc_nthw_new(void);
+void rmc_nthw_delete(struct rmc_nthw *p);
+int rmc_nthw_init(struct rmc_nthw *p, nt_fpga_t *p_fpga, int n_instance);
+
+int rmc_nthw_setup(struct rmc_nthw *p, int n_idx, int n_idx_cnt);
+void rmc_nthw_set_debug_mode(struct rmc_nthw *p, unsigned int n_debug_mode);
+
+/* CTRL */
+void rmc_nthw_ctrl_block_statt(const struct rmc_nthw *p, uint32_t val);
+void rmc_nthw_ctrl_block_keep_a(const struct rmc_nthw *p, uint32_t val);
+void rmc_nthw_ctrl_block_rpp_slice(const struct rmc_nthw *p, uint32_t val);
+void rmc_nthw_ctrl_block_mac_port(const struct rmc_nthw *p, uint32_t val);
+void rmc_nthw_ctrl_lag_phy_odd_even(const struct rmc_nthw *p, uint32_t val);
+void rmc_nthw_ctrl_flush(const struct rmc_nthw *p);
+
+#endif /* __FLOW_NTHW_RMC_H__ */
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_roa.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_roa.c
new file mode 100644
index 0000000000..934778f426
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_roa.c
@@ -0,0 +1,294 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_roa.h"
+
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+void roa_nthw_set_debug_mode(struct roa_nthw *p, unsigned int n_debug_mode)
+{
+	module_set_debug_mode(p->m_roa, n_debug_mode);
+}
+
+struct roa_nthw *roa_nthw_new(void)
+{
+	struct roa_nthw *p = malloc(sizeof(struct roa_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void roa_nthw_delete(struct roa_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int roa_nthw_init(struct roa_nthw *p, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = fpga_query_module(p_fpga, MOD_ROA, 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: ROA %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_roa = p_mod;
+
+	/* TUN HDR */
+	p->mp_tun_hdr_ctrl = module_get_register(p->m_roa, ROA_TUNHDR_CTRL);
+	p->mp_tun_hdr_addr =
+		register_get_field(p->mp_tun_hdr_ctrl, ROA_TUNHDR_CTRL_ADR);
+	p->mp_tun_hdr_cnt =
+		register_get_field(p->mp_tun_hdr_ctrl, ROA_TUNHDR_CTRL_CNT);
+	p->mp_tun_hdr_data = module_get_register(p->m_roa, ROA_TUNHDR_DATA);
+	p->mp_tun_hdr_data_tunnel_hdr =
+		register_get_field(p->mp_tun_hdr_data, ROA_TUNHDR_DATA_TUNNEL_HDR);
+	/* TUN CFG */
+	p->mp_tun_cfg_ctrl = module_get_register(p->m_roa, ROA_TUNCFG_CTRL);
+	p->mp_tun_cfg_addr =
+		register_get_field(p->mp_tun_cfg_ctrl, ROA_TUNCFG_CTRL_ADR);
+	p->mp_tun_cfg_cnt =
+		register_get_field(p->mp_tun_cfg_ctrl, ROA_TUNCFG_CTRL_CNT);
+	p->mp_tun_cfg_data = module_get_register(p->m_roa, ROA_TUNCFG_DATA);
+	p->mp_tun_cfg_data_tun_len =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_TUN_LEN);
+	p->mp_tun_cfg_data_tun_type =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_TUN_TYPE);
+	p->mp_tun_cfg_data_tun_vlan =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_TUN_VLAN);
+	p->mp_tun_cfg_data_ip_type =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_TUN_IP_TYPE);
+	p->mp_tun_cfg_data_ipcs_upd =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_TUN_IPCS_UPD);
+	p->mp_tun_cfg_data_ipcs_precalc =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_TUN_IPCS_PRECALC);
+	p->mp_tun_cfg_data_iptl_upd =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_TUN_IPTL_UPD);
+	p->mp_tun_cfg_data_iptl_precalc =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_TUN_IPTL_PRECALC);
+	p->mp_tun_cfg_data_vxlan_udp_len_upd =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_TUN_VXLAN_UDP_LEN_UPD);
+	p->mp_tun_cfg_data_tx_lag_ix =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_TX_LAG_IX);
+	p->mp_tun_cfg_data_recirculate =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_RECIRCULATE);
+	p->mp_tun_cfg_data_push_tunnel =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_PUSH_TUNNEL);
+	p->mp_tun_cfg_data_recirc_port =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_RECIRC_PORT);
+	p->mp_tun_cfg_data_recirc_bypass =
+		register_get_field(p->mp_tun_cfg_data, ROA_TUNCFG_DATA_RECIRC_BYPASS);
+	/* CONFIG */
+	p->mp_config = module_get_register(p->m_roa, ROA_CONFIG);
+	p->mp_config_fwd_recirculate =
+		register_get_field(p->mp_config, ROA_CONFIG_FWD_RECIRCULATE);
+	p->mp_config_fwd_normal_pcks =
+		register_get_field(p->mp_config, ROA_CONFIG_FWD_NORMAL_PCKS);
+	p->mp_config_fwd_tx_port0 =
+		register_get_field(p->mp_config, ROA_CONFIG_FWD_TXPORT0);
+	p->mp_config_fwd_tx_port1 =
+		register_get_field(p->mp_config, ROA_CONFIG_FWD_TXPORT1);
+	p->mp_config_fwd_cell_builder_pcks =
+		register_get_field(p->mp_config, ROA_CONFIG_FWD_CELLBUILDER_PCKS);
+	p->mp_config_fwd_non_normal_pcks =
+		register_get_field(p->mp_config, ROA_CONFIG_FWD_NON_NORMAL_PCKS);
+	/* LAG */
+	p->mp_lag_cfg_ctrl = module_get_register(p->m_roa, ROA_LAGCFG_CTRL);
+	p->mp_lag_cfg_addr =
+		register_get_field(p->mp_lag_cfg_ctrl, ROA_LAGCFG_CTRL_ADR);
+	p->mp_lag_cfg_cnt =
+		register_get_field(p->mp_lag_cfg_ctrl, ROA_LAGCFG_CTRL_CNT);
+	p->mp_lag_cfg_data = module_get_register(p->m_roa, ROA_LAGCFG_DATA);
+	p->mp_lag_cfg_data_tx_phy_port =
+		register_get_field(p->mp_lag_cfg_data, ROA_LAGCFG_DATA_TXPHY_PORT);
+
+	return 0;
+}
+
+/* TUN HDR */
+void roa_nthw_tun_hdr_select(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_hdr_addr, val);
+}
+
+void roa_nthw_tun_hdr_cnt(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_hdr_cnt, val);
+}
+
+void roa_nthw_tun_hdr_tunnel_hdr(const struct roa_nthw *p, uint32_t *val)
+{
+	field_set_val(p->mp_tun_hdr_data_tunnel_hdr, val, 4);
+}
+
+void roa_nthw_tun_hdr_flush(const struct roa_nthw *p)
+{
+	register_flush(p->mp_tun_hdr_ctrl, 1);
+	register_flush(p->mp_tun_hdr_data, 1);
+}
+
+/* TUN CFG */
+void roa_nthw_tun_cfg_select(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_addr, val);
+}
+
+void roa_nthw_tun_cfg_cnt(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_cnt, val);
+}
+
+void roa_nthw_tun_cfg_tun_len(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_tun_len, val);
+}
+
+void roa_nthw_tun_cfg_tun_type(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_tun_type, val);
+}
+
+void roa_nthw_tun_cfg_tun_vlan(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_tun_vlan, val);
+}
+
+void roa_nthw_tun_cfg_ip_type(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_ip_type, val);
+}
+
+void roa_nthw_tun_cfg_ipcs_upd(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_ipcs_upd, val);
+}
+
+void roa_nthw_tun_cfg_ipcs_precalc(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_ipcs_precalc, val);
+}
+
+void roa_nthw_tun_cfg_iptl_upd(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_iptl_upd, val);
+}
+
+void roa_nthw_tun_cfg_iptl_precalc(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_iptl_precalc, val);
+}
+
+void roa_nthw_tun_cfg_vxlan_udp_len_upd(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_vxlan_udp_len_upd, val);
+}
+
+void roa_nthw_tun_cfg_tx_lag_ix(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_tx_lag_ix, val);
+};
+
+void roa_nthw_tun_cfg_recirculate(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_recirculate, val);
+}
+
+void roa_nthw_tun_cfg_push_tunnel(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_push_tunnel, val);
+}
+
+void roa_nthw_tun_cfg_recirc_port(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_recirc_port, val);
+}
+
+void roa_nthw_tun_cfg_recirc_bypass(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_tun_cfg_data_recirc_bypass, val);
+}
+
+void roa_nthw_tun_cfg_flush(const struct roa_nthw *p)
+{
+	register_flush(p->mp_tun_cfg_ctrl, 1);
+	register_flush(p->mp_tun_cfg_data, 1);
+}
+
+/* ROA CONFIG */
+void roa_nthw_config_fwd_recirculate(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_config_fwd_recirculate, val);
+}
+
+void roa_nthw_config_fwd_normal_pcks(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_config_fwd_normal_pcks, val);
+}
+
+void roa_nthw_config_fwd_tx_port0(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_config_fwd_tx_port0, val);
+}
+
+void roa_nthw_config_fwd_tx_port1(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_config_fwd_tx_port1, val);
+}
+
+void roa_nthw_config_fwd_cell_builder_pcks(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_config_fwd_cell_builder_pcks, val);
+}
+
+void roa_nthw_config_fwd_non_normal_pcks(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_config_fwd_non_normal_pcks, val);
+}
+
+void roa_nthw_config_flush(const struct roa_nthw *p)
+{
+	register_flush(p->mp_config, 1);
+}
+
+/* LAG */
+void roa_nthw_lag_cfg_select(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_lag_cfg_addr, val);
+}
+
+void roa_nthw_lag_cfg_cnt(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_lag_cfg_cnt, val);
+}
+
+void roa_nthw_lag_cfg_tx_phy_port(const struct roa_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_lag_cfg_data_tx_phy_port, val);
+}
+
+void roa_nthw_lag_cfg_flush(const struct roa_nthw *p)
+{
+	register_flush(p->mp_lag_cfg_ctrl, 1);
+	register_flush(p->mp_lag_cfg_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_roa.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_roa.h
new file mode 100644
index 0000000000..9398ef5ae9
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_roa.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_ROA_H__
+#define __FLOW_NTHW_ROA_H__
+
+#include <stdint.h> /* uint32_t */
+#include "nthw_fpga_model.h"
+
+struct roa_nthw;
+
+typedef struct roa_nthw roa_nthw_t;
+
+struct roa_nthw *roa_nthw_new(void);
+void roa_nthw_delete(struct roa_nthw *p);
+int roa_nthw_init(struct roa_nthw *p, nt_fpga_t *p_fpga, int n_instance);
+
+int roa_nthw_setup(struct roa_nthw *p, int n_idx, int n_idx_cnt);
+void roa_nthw_set_debug_mode(struct roa_nthw *p, unsigned int n_debug_mode);
+
+/* TUN HDR */
+void roa_nthw_tun_hdr_select(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_hdr_cnt(const struct roa_nthw *p, uint32_t val);
+
+void roa_nthw_tun_hdr_tunnel_hdr(const struct roa_nthw *p, uint32_t *val);
+void roa_nthw_tun_hdr_flush(const struct roa_nthw *p);
+
+/* TUN CFG */
+void roa_nthw_tun_cfg_select(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_cnt(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_tun_len(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_tun_type(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_tun_vlan(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_ip_type(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_ipcs_upd(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_ipcs_precalc(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_iptl_upd(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_iptl_precalc(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_vxlan_udp_len_upd(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_tx_lag_ix(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_recirculate(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_push_tunnel(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_recirc_port(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_recirc_bypass(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_tun_cfg_flush(const struct roa_nthw *p);
+
+/* ROA CONFIG */
+void roa_nthw_config_fwd_recirculate(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_config_fwd_normal_pcks(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_config_fwd_tx_port0(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_config_fwd_tx_port1(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_config_fwd_cell_builder_pcks(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_config_fwd_non_normal_pcks(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_config_flush(const struct roa_nthw *p);
+
+/* LAG */
+void roa_nthw_lag_cfg_select(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_lag_cfg_cnt(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_lag_cfg_tx_phy_port(const struct roa_nthw *p, uint32_t val);
+void roa_nthw_lag_cfg_flush(const struct roa_nthw *p);
+
+struct roa_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_roa;
+
+	nt_register_t *mp_tun_hdr_ctrl;
+	nt_field_t *mp_tun_hdr_addr;
+	nt_field_t *mp_tun_hdr_cnt;
+	nt_register_t *mp_tun_hdr_data;
+	nt_field_t *mp_tun_hdr_data_tunnel_hdr;
+
+	nt_register_t *mp_tun_cfg_ctrl;
+	nt_field_t *mp_tun_cfg_addr;
+	nt_field_t *mp_tun_cfg_cnt;
+	nt_register_t *mp_tun_cfg_data;
+	nt_field_t *mp_tun_cfg_data_tun_len;
+	nt_field_t *mp_tun_cfg_data_tun_type;
+	nt_field_t *mp_tun_cfg_data_tun_vlan;
+	nt_field_t *mp_tun_cfg_data_ip_type;
+	nt_field_t *mp_tun_cfg_data_ipcs_upd;
+	nt_field_t *mp_tun_cfg_data_ipcs_precalc;
+	nt_field_t *mp_tun_cfg_data_iptl_upd;
+	nt_field_t *mp_tun_cfg_data_iptl_precalc;
+	nt_field_t *mp_tun_cfg_data_vxlan_udp_len_upd;
+	nt_field_t *mp_tun_cfg_data_tx_lag_ix;
+	nt_field_t *mp_tun_cfg_data_recirculate;
+	nt_field_t *mp_tun_cfg_data_push_tunnel;
+	nt_field_t *mp_tun_cfg_data_recirc_port;
+	nt_field_t *mp_tun_cfg_data_recirc_bypass;
+
+	nt_register_t *mp_config;
+	nt_field_t *mp_config_fwd_recirculate;
+	nt_field_t *mp_config_fwd_normal_pcks;
+	nt_field_t *mp_config_fwd_tx_port0;
+	nt_field_t *mp_config_fwd_tx_port1;
+	nt_field_t *mp_config_fwd_cell_builder_pcks;
+	nt_field_t *mp_config_fwd_non_normal_pcks;
+
+	nt_register_t *mp_lag_cfg_ctrl;
+	nt_field_t *mp_lag_cfg_addr;
+	nt_field_t *mp_lag_cfg_cnt;
+	nt_register_t *mp_lag_cfg_data;
+	nt_field_t *mp_lag_cfg_data_tx_phy_port;
+};
+
+#endif /* __FLOW_NTHW_ROA_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
new file mode 100644
index 0000000000..2ce3ce6cf8
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.c
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_rpp_lr.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+void rpp_lr_nthw_set_debug_mode(struct rpp_lr_nthw *p, unsigned int n_debug_mode)
+{
+	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));
+
+	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, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = fpga_query_module(p_fpga, MOD_RPP_LR, n_instance);
+
+	p->mp_rcp_ctrl = module_get_register(p->m_rpp_lr, RPP_LR_RCP_CTRL);
+	p->mp_rcp_addr = register_get_field(p->mp_rcp_ctrl, RPP_LR_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = register_get_field(p->mp_rcp_ctrl, RPP_LR_RCP_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_rpp_lr, RPP_LR_RCP_DATA);
+	p->mp_rcp_data_exp = register_get_field(p->mp_rcp_data, RPP_LR_RCP_DATA_EXP);
+
+	p->mp_ifr_rcp_ctrl = module_query_register(p->m_rpp_lr, RPP_LR_IFR_RCP_CTRL);
+	p->mp_ifr_rcp_addr =
+		register_query_field(p->mp_ifr_rcp_ctrl, RPP_LR_IFR_RCP_CTRL_ADR);
+	p->mp_ifr_rcp_cnt =
+		register_query_field(p->mp_ifr_rcp_ctrl, RPP_LR_IFR_RCP_CTRL_CNT);
+	p->mp_ifr_rcp_data = module_query_register(p->m_rpp_lr, RPP_LR_IFR_RCP_DATA);
+	p->mp_ifr_rcp_data_en =
+		register_query_field(p->mp_ifr_rcp_data, RPP_LR_IFR_RCP_DATA_EN);
+	p->mp_ifr_rcp_data_mtu =
+		register_query_field(p->mp_ifr_rcp_data, RPP_LR_IFR_RCP_DATA_MTU);
+
+	return 0;
+}
+
+void rpp_lr_nthw_rcp_select(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	assert(p->mp_rcp_addr);
+	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);
+	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);
+	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);
+	register_flush(p->mp_rcp_ctrl, 1);
+	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);
+	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);
+	field_set_val32(p->mp_ifr_rcp_cnt, val);
+}
+
+void rpp_lr_nthw_ifr_rcp_en(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	assert(p->mp_ifr_rcp_data_en);
+	field_set_val32(p->mp_ifr_rcp_data_en, val);
+}
+
+void rpp_lr_nthw_ifr_rcp_mtu(const struct rpp_lr_nthw *p, uint32_t val)
+{
+	assert(p->mp_ifr_rcp_data_mtu);
+	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);
+	register_flush(p->mp_ifr_rcp_ctrl, 1);
+	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
new file mode 100644
index 0000000000..e442c9d8d2
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_rpp_lr.h
@@ -0,0 +1,53 @@
+/* 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;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_rpp_lr;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_addr;
+	nt_field_t *mp_rcp_cnt;
+
+	nt_register_t *mp_rcp_data;
+	nt_field_t *mp_rcp_data_exp;
+
+	nt_register_t *mp_ifr_rcp_ctrl;
+	nt_field_t *mp_ifr_rcp_addr;
+	nt_field_t *mp_ifr_rcp_cnt;
+
+	nt_register_t *mp_ifr_rcp_data;
+	nt_field_t *mp_ifr_rcp_data_en;
+	nt_field_t *mp_ifr_rcp_data_mtu;
+};
+
+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, nt_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_en(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_slc.c b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc.c
new file mode 100644
index 0000000000..a409e68869
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc.c
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_slc.h"
+
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+void slc_nthw_set_debug_mode(struct slc_nthw *p, unsigned int n_debug_mode)
+{
+	module_set_debug_mode(p->m_slc, n_debug_mode);
+}
+
+struct slc_nthw *slc_nthw_new(void)
+{
+	struct slc_nthw *p = malloc(sizeof(struct slc_nthw));
+
+	if (p)
+		(void)memset(p, 0, sizeof(*p));
+
+	return p;
+}
+
+void slc_nthw_delete(struct slc_nthw *p)
+{
+	if (p) {
+		(void)memset(p, 0, sizeof(*p));
+		free(p);
+	}
+}
+
+int slc_nthw_init(struct slc_nthw *p, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = fpga_query_module(p_fpga, MOD_SLC, 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 = fpga_query_module(p_fpga, MOD_SLC, n_instance);
+
+	/* RCP */
+	p->mp_rcp_ctrl = module_get_register(p->m_slc, SLC_RCP_CTRL);
+	p->mp_rcp_addr = register_get_field(p->mp_rcp_ctrl, SLC_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = register_get_field(p->mp_rcp_ctrl, SLC_RCP_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_slc, SLC_RCP_DATA);
+	p->mp_rcp_data_tail_slc_en =
+		register_get_field(p->mp_rcp_data, SLC_RCP_DATA_TAIL_SLC_EN);
+	p->mp_rcp_data_tail_dyn =
+		register_get_field(p->mp_rcp_data, SLC_RCP_DATA_TAIL_DYN);
+	p->mp_rcp_data_tail_ofs =
+		register_get_field(p->mp_rcp_data, SLC_RCP_DATA_TAIL_OFS);
+	p->mp_rcp_data_pcap = register_get_field(p->mp_rcp_data, SLC_RCP_DATA_PCAP);
+
+	return 0;
+}
+
+/* RCP */
+void slc_nthw_rcp_select(const struct slc_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_addr, val);
+}
+
+void slc_nthw_rcp_cnt(const struct slc_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void slc_nthw_rcp_tail_slc_en(const struct slc_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_tail_slc_en, val);
+}
+
+void slc_nthw_rcp_tail_dyn(const struct slc_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_tail_dyn, val);
+}
+
+void slc_nthw_rcp_tail_ofs(const struct slc_nthw *p, int32_t val)
+{
+	field_set_val32(p->mp_rcp_data_tail_ofs, val);
+}
+
+void slc_nthw_rcp_pcap(const struct slc_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_pcap, val);
+}
+
+void slc_nthw_rcp_flush(const struct slc_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	register_flush(p->mp_rcp_data, 1);
+}
diff --git a/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc.h b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc.h
new file mode 100644
index 0000000000..e0f58e27e4
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __FLOW_NTHW_SLC_H__
+#define __FLOW_NTHW_SLC_H__
+
+#include <stdint.h> /* uint32_t */
+#include "nthw_fpga_model.h"
+
+struct slc_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_slc;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_addr;
+	nt_field_t *mp_rcp_cnt;
+	nt_register_t *mp_rcp_data;
+
+	nt_field_t *mp_rcp_data_tail_slc_en;
+	nt_field_t *mp_rcp_data_tail_dyn;
+	nt_field_t *mp_rcp_data_tail_ofs;
+	nt_field_t *mp_rcp_data_pcap;
+};
+
+typedef struct slc_nthw slc_nthw_t;
+
+struct slc_nthw *slc_nthw_new(void);
+void slc_nthw_delete(struct slc_nthw *p);
+int slc_nthw_init(struct slc_nthw *p, nt_fpga_t *p_fpga, int n_instance);
+
+int slc_nthw_setup(struct slc_nthw *p, int n_idx, int n_idx_cnt);
+void slc_nthw_set_debug_mode(struct slc_nthw *p, unsigned int n_debug_mode);
+
+/* RCP */
+void slc_nthw_rcp_select(const struct slc_nthw *p, uint32_t val);
+void slc_nthw_rcp_cnt(const struct slc_nthw *p, uint32_t val);
+void slc_nthw_rcp_tail_slc_en(const struct slc_nthw *p, uint32_t val);
+void slc_nthw_rcp_tail_dyn(const struct slc_nthw *p, uint32_t val);
+void slc_nthw_rcp_tail_ofs(const struct slc_nthw *p, int32_t val);
+void slc_nthw_rcp_pcap(const struct slc_nthw *p, uint32_t val);
+void slc_nthw_rcp_flush(const struct slc_nthw *p);
+
+#endif /* __FLOW_NTHW_SLC_H__ */
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..f106974bdd
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc_lr.c
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_slc_lr.h"
+
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+void slc_lr_nthw_set_debug_mode(struct slc_lr_nthw *p, unsigned int n_debug_mode)
+{
+	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, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = fpga_query_module(p_fpga, MOD_SLC_LR, n_instance);
+
+	/* RCP */
+	p->mp_rcp_ctrl = module_get_register(p->m_slc_lr, SLC_RCP_CTRL);
+	p->mp_rcp_addr = register_get_field(p->mp_rcp_ctrl, SLC_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = register_get_field(p->mp_rcp_ctrl, SLC_RCP_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_slc_lr, SLC_RCP_DATA);
+	p->mp_rcp_data_tail_slc_en =
+		register_get_field(p->mp_rcp_data, SLC_RCP_DATA_TAIL_SLC_EN);
+	p->mp_rcp_data_tail_dyn =
+		register_get_field(p->mp_rcp_data, SLC_RCP_DATA_TAIL_DYN);
+	p->mp_rcp_data_tail_ofs =
+		register_get_field(p->mp_rcp_data, SLC_RCP_DATA_TAIL_OFS);
+	p->mp_rcp_data_pcap = 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)
+{
+	field_set_val32(p->mp_rcp_addr, val);
+}
+
+void slc_lr_nthw_rcp_cnt(const struct slc_lr_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void slc_lr_nthw_rcp_tail_slc_en(const struct slc_lr_nthw *p, uint32_t val)
+{
+	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)
+{
+	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)
+{
+	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)
+{
+	field_set_val32(p->mp_rcp_data_pcap, val);
+}
+
+void slc_lr_nthw_rcp_flush(const struct slc_lr_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	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..533f2efbeb
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_slc_lr.h
@@ -0,0 +1,46 @@
+/* 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> /* uint32_t */
+#include "nthw_fpga_model.h"
+
+struct slc_lr_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_slc_lr;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_addr;
+	nt_field_t *mp_rcp_cnt;
+	nt_register_t *mp_rcp_data;
+
+	nt_field_t *mp_rcp_data_tail_slc_en;
+	nt_field_t *mp_rcp_data_tail_dyn;
+	nt_field_t *mp_rcp_data_tail_ofs;
+	nt_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, nt_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_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/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..4d28d8cc3d
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.c
@@ -0,0 +1,394 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_tx_cpy.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+void tx_cpy_nthw_set_debug_mode(struct tx_cpy_nthw *p, unsigned int n_debug_mode)
+{
+	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));
+
+	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, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = fpga_query_module(p_fpga, MOD_TX_CPY, n_instance);
+
+	const int writers_cnt =
+		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 =
+		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 =
+			module_get_register(p->m_tx_cpy, CPY_WRITER5_CTRL);
+		p->m_writers[5].mp_writer_ctrl_addr =
+			register_get_field(p->m_writers[5].mp_writer_ctrl,
+					   CPY_WRITER5_CTRL_ADR);
+		p->m_writers[5].mp_writer_ctrl_cnt =
+			register_get_field(p->m_writers[5].mp_writer_ctrl,
+					   CPY_WRITER5_CTRL_CNT);
+		p->m_writers[5].mp_writer_data =
+			module_get_register(p->m_tx_cpy, CPY_WRITER5_DATA);
+		p->m_writers[5].mp_writer_data_reader_select =
+			register_get_field(p->m_writers[5].mp_writer_data,
+					  CPY_WRITER5_DATA_READER_SELECT);
+		p->m_writers[5].mp_writer_data_dyn =
+			register_get_field(p->m_writers[5].mp_writer_data,
+					   CPY_WRITER5_DATA_DYN);
+		p->m_writers[5].mp_writer_data_ofs =
+			register_get_field(p->m_writers[5].mp_writer_data,
+					   CPY_WRITER5_DATA_OFS);
+		p->m_writers[5].mp_writer_data_len =
+			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 =
+				register_get_field(p->m_writers[5].mp_writer_data,
+						   CPY_WRITER5_DATA_MASK_POINTER);
+			p->m_writers[5].mp_writer_mask_ctrl =
+				module_get_register(p->m_tx_cpy, CPY_WRITER5_MASK_CTRL);
+			p->m_writers[5].mp_writer_mask_ctrl_addr =
+				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 =
+				register_get_field(p->m_writers[5].mp_writer_mask_ctrl,
+						   CPY_WRITER5_MASK_CTRL_CNT);
+			p->m_writers[5].mp_writer_mask_data =
+				module_get_register(p->m_tx_cpy, CPY_WRITER5_MASK_DATA);
+			p->m_writers[5].mp_writer_mask_data_byte_mask =
+				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 =
+			module_get_register(p->m_tx_cpy, CPY_WRITER4_CTRL);
+		p->m_writers[4].mp_writer_ctrl_addr =
+			register_get_field(p->m_writers[4].mp_writer_ctrl, CPY_WRITER4_CTRL_ADR);
+		p->m_writers[4].mp_writer_ctrl_cnt =
+			register_get_field(p->m_writers[4].mp_writer_ctrl, CPY_WRITER4_CTRL_CNT);
+		p->m_writers[4].mp_writer_data =
+			module_get_register(p->m_tx_cpy, CPY_WRITER4_DATA);
+		p->m_writers[4].mp_writer_data_reader_select =
+			register_get_field(p->m_writers[4].mp_writer_data,
+					   CPY_WRITER4_DATA_READER_SELECT);
+		p->m_writers[4].mp_writer_data_dyn =
+			register_get_field(p->m_writers[4].mp_writer_data, CPY_WRITER4_DATA_DYN);
+		p->m_writers[4].mp_writer_data_ofs =
+			register_get_field(p->m_writers[4].mp_writer_data, CPY_WRITER4_DATA_OFS);
+		p->m_writers[4].mp_writer_data_len =
+			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 =
+				register_get_field(p->m_writers[4].mp_writer_data,
+						   CPY_WRITER4_DATA_MASK_POINTER);
+			p->m_writers[4].mp_writer_mask_ctrl =
+				module_get_register(p->m_tx_cpy, CPY_WRITER4_MASK_CTRL);
+			p->m_writers[4].mp_writer_mask_ctrl_addr =
+				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 =
+				register_get_field(p->m_writers[4].mp_writer_mask_ctrl,
+						   CPY_WRITER4_MASK_CTRL_CNT);
+			p->m_writers[4].mp_writer_mask_data =
+				module_get_register(p->m_tx_cpy, CPY_WRITER4_MASK_DATA);
+			p->m_writers[4].mp_writer_mask_data_byte_mask =
+				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 =
+			module_get_register(p->m_tx_cpy, CPY_WRITER3_CTRL);
+		p->m_writers[3].mp_writer_ctrl_addr =
+			register_get_field(p->m_writers[3].mp_writer_ctrl, CPY_WRITER3_CTRL_ADR);
+		p->m_writers[3].mp_writer_ctrl_cnt =
+			register_get_field(p->m_writers[3].mp_writer_ctrl, CPY_WRITER3_CTRL_CNT);
+		p->m_writers[3].mp_writer_data =
+			module_get_register(p->m_tx_cpy, CPY_WRITER3_DATA);
+		p->m_writers[3].mp_writer_data_reader_select =
+			register_get_field(p->m_writers[3].mp_writer_data,
+					   CPY_WRITER3_DATA_READER_SELECT);
+		p->m_writers[3].mp_writer_data_dyn =
+			register_get_field(p->m_writers[3].mp_writer_data, CPY_WRITER3_DATA_DYN);
+		p->m_writers[3].mp_writer_data_ofs =
+			register_get_field(p->m_writers[3].mp_writer_data, CPY_WRITER3_DATA_OFS);
+		p->m_writers[3].mp_writer_data_len =
+			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 =
+				register_get_field(p->m_writers[3].mp_writer_data,
+						   CPY_WRITER3_DATA_MASK_POINTER);
+			p->m_writers[3].mp_writer_mask_ctrl =
+				module_get_register(p->m_tx_cpy, CPY_WRITER3_MASK_CTRL);
+			p->m_writers[3].mp_writer_mask_ctrl_addr =
+				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 =
+				register_get_field(p->m_writers[3].mp_writer_mask_ctrl,
+						   CPY_WRITER3_MASK_CTRL_CNT);
+			p->m_writers[3].mp_writer_mask_data =
+				module_get_register(p->m_tx_cpy, CPY_WRITER3_MASK_DATA);
+			p->m_writers[3].mp_writer_mask_data_byte_mask =
+				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 =
+			module_get_register(p->m_tx_cpy, CPY_WRITER2_CTRL);
+		p->m_writers[2].mp_writer_ctrl_addr =
+			register_get_field(p->m_writers[2].mp_writer_ctrl, CPY_WRITER2_CTRL_ADR);
+		p->m_writers[2].mp_writer_ctrl_cnt =
+			register_get_field(p->m_writers[2].mp_writer_ctrl, CPY_WRITER2_CTRL_CNT);
+		p->m_writers[2].mp_writer_data =
+			module_get_register(p->m_tx_cpy, CPY_WRITER2_DATA);
+		p->m_writers[2].mp_writer_data_reader_select =
+			register_get_field(p->m_writers[2].mp_writer_data,
+					   CPY_WRITER2_DATA_READER_SELECT);
+		p->m_writers[2].mp_writer_data_dyn =
+			register_get_field(p->m_writers[2].mp_writer_data, CPY_WRITER2_DATA_DYN);
+		p->m_writers[2].mp_writer_data_ofs =
+			register_get_field(p->m_writers[2].mp_writer_data, CPY_WRITER2_DATA_OFS);
+		p->m_writers[2].mp_writer_data_len =
+			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 =
+				register_get_field(p->m_writers[2].mp_writer_data,
+						   CPY_WRITER2_DATA_MASK_POINTER);
+			p->m_writers[2].mp_writer_mask_ctrl =
+				module_get_register(p->m_tx_cpy, CPY_WRITER2_MASK_CTRL);
+			p->m_writers[2].mp_writer_mask_ctrl_addr =
+				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 =
+				register_get_field(p->m_writers[2].mp_writer_mask_ctrl,
+						   CPY_WRITER2_MASK_CTRL_CNT);
+			p->m_writers[2].mp_writer_mask_data =
+				module_get_register(p->m_tx_cpy, CPY_WRITER2_MASK_DATA);
+			p->m_writers[2].mp_writer_mask_data_byte_mask =
+				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 =
+			module_get_register(p->m_tx_cpy, CPY_WRITER1_CTRL);
+		p->m_writers[1].mp_writer_ctrl_addr =
+			register_get_field(p->m_writers[1].mp_writer_ctrl, CPY_WRITER1_CTRL_ADR);
+		p->m_writers[1].mp_writer_ctrl_cnt =
+			register_get_field(p->m_writers[1].mp_writer_ctrl, CPY_WRITER1_CTRL_CNT);
+		p->m_writers[1].mp_writer_data =
+			module_get_register(p->m_tx_cpy, CPY_WRITER1_DATA);
+		p->m_writers[1].mp_writer_data_reader_select =
+			register_get_field(p->m_writers[1].mp_writer_data,
+					   CPY_WRITER1_DATA_READER_SELECT);
+		p->m_writers[1].mp_writer_data_dyn =
+			register_get_field(p->m_writers[1].mp_writer_data, CPY_WRITER1_DATA_DYN);
+		p->m_writers[1].mp_writer_data_ofs =
+			register_get_field(p->m_writers[1].mp_writer_data, CPY_WRITER1_DATA_OFS);
+		p->m_writers[1].mp_writer_data_len =
+			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 =
+				register_get_field(p->m_writers[1].mp_writer_data,
+						   CPY_WRITER1_DATA_MASK_POINTER);
+			p->m_writers[1].mp_writer_mask_ctrl =
+				module_get_register(p->m_tx_cpy, CPY_WRITER1_MASK_CTRL);
+			p->m_writers[1].mp_writer_mask_ctrl_addr =
+				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 =
+				register_get_field(p->m_writers[1].mp_writer_mask_ctrl,
+						   CPY_WRITER1_MASK_CTRL_CNT);
+			p->m_writers[1].mp_writer_mask_data =
+				module_get_register(p->m_tx_cpy, CPY_WRITER1_MASK_DATA);
+			p->m_writers[1].mp_writer_mask_data_byte_mask =
+				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 =
+			module_get_register(p->m_tx_cpy, CPY_WRITER0_CTRL);
+		p->m_writers[0].mp_writer_ctrl_addr =
+			register_get_field(p->m_writers[0].mp_writer_ctrl, CPY_WRITER0_CTRL_ADR);
+		p->m_writers[0].mp_writer_ctrl_cnt =
+			register_get_field(p->m_writers[0].mp_writer_ctrl, CPY_WRITER0_CTRL_CNT);
+		p->m_writers[0].mp_writer_data =
+			module_get_register(p->m_tx_cpy, CPY_WRITER0_DATA);
+		p->m_writers[0].mp_writer_data_reader_select =
+			register_get_field(p->m_writers[0].mp_writer_data,
+					   CPY_WRITER0_DATA_READER_SELECT);
+		p->m_writers[0].mp_writer_data_dyn =
+			register_get_field(p->m_writers[0].mp_writer_data, CPY_WRITER0_DATA_DYN);
+		p->m_writers[0].mp_writer_data_ofs =
+			register_get_field(p->m_writers[0].mp_writer_data, CPY_WRITER0_DATA_OFS);
+		p->m_writers[0].mp_writer_data_len =
+			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 =
+				register_get_field(p->m_writers[0].mp_writer_data,
+						   CPY_WRITER0_DATA_MASK_POINTER);
+			p->m_writers[0].mp_writer_mask_ctrl =
+				module_get_register(p->m_tx_cpy, CPY_WRITER0_MASK_CTRL);
+			p->m_writers[0].mp_writer_mask_ctrl_addr =
+			 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 =
+				register_get_field(p->m_writers[0].mp_writer_mask_ctrl,
+						   CPY_WRITER0_MASK_CTRL_CNT);
+			p->m_writers[0].mp_writer_mask_data =
+				module_get_register(p->m_tx_cpy, CPY_WRITER0_MASK_DATA);
+			p->m_writers[0].mp_writer_mask_data_byte_mask =
+				register_get_field(p->m_writers[0].mp_writer_mask_data,
+						   CPY_WRITER0_MASK_DATA_BYTE_MASK);
+		}
+		break;
+	case 0:
+		return -1;
+	}
+
+	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);
+	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);
+	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);
+	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);
+	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);
+	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);
+	field_set_val32(p->m_writers[index].mp_writer_data_len, val);
+}
+
+void tx_cpy_nthw_writer_mask_pointer(const struct tx_cpy_nthw *p, unsigned int index,
+				 uint32_t val)
+{
+	assert(index < p->m_writers_cnt);
+	assert(p->m_writers[index].mp_writer_data_mask_pointer);
+	field_set_val32(p->m_writers[index].mp_writer_data_mask_pointer, val);
+}
+
+void tx_cpy_nthw_writer_flush(const struct tx_cpy_nthw *p, unsigned int index)
+{
+	assert(index < p->m_writers_cnt);
+	register_flush(p->m_writers[index].mp_writer_ctrl, 1);
+	register_flush(p->m_writers[index].mp_writer_data, 1);
+}
+
+void tx_cpy_nthw_writer_mask_select(const struct tx_cpy_nthw *p, unsigned int index,
+				uint32_t val)
+{
+	assert(index < p->m_writers_cnt);
+	assert(p->m_writers[index].mp_writer_mask_ctrl_addr);
+	field_set_val32(p->m_writers[index].mp_writer_mask_ctrl_addr, val);
+}
+
+void tx_cpy_nthw_writer_mask_cnt(const struct tx_cpy_nthw *p, unsigned int index,
+			     uint32_t val)
+{
+	assert(index < p->m_writers_cnt);
+	assert(p->m_writers[index].mp_writer_mask_ctrl_cnt);
+	field_set_val32(p->m_writers[index].mp_writer_mask_ctrl_cnt, val);
+}
+
+void tx_cpy_nthw_writer_mask(const struct tx_cpy_nthw *p, unsigned int index,
+			  uint32_t val)
+{
+	assert(index < p->m_writers_cnt);
+	assert(p->m_writers[index].mp_writer_mask_data_byte_mask);
+	field_set_val32(p->m_writers[index].mp_writer_mask_data_byte_mask, val);
+}
+
+void tx_cpy_nthw_writer_mask_flush(const struct tx_cpy_nthw *p, unsigned int index)
+{
+	assert(index < p->m_writers_cnt);
+	assert(p->m_writers[index].mp_writer_mask_ctrl);
+	assert(p->m_writers[index].mp_writer_mask_data);
+	register_flush(p->m_writers[index].mp_writer_mask_ctrl, 1);
+	register_flush(p->m_writers[index].mp_writer_mask_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
new file mode 100644
index 0000000000..f97983b29a
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_cpy.h
@@ -0,0 +1,72 @@
+/* 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 {
+	nt_register_t *mp_writer_ctrl;
+	nt_field_t *mp_writer_ctrl_addr;
+	nt_field_t *mp_writer_ctrl_cnt;
+
+	nt_register_t *mp_writer_data;
+	nt_field_t *mp_writer_data_reader_select;
+	nt_field_t *mp_writer_data_dyn;
+	nt_field_t *mp_writer_data_ofs;
+	nt_field_t *mp_writer_data_len;
+	nt_field_t *mp_writer_data_mask_pointer;
+
+	nt_register_t *mp_writer_mask_ctrl;
+	nt_field_t *mp_writer_mask_ctrl_addr;
+	nt_field_t *mp_writer_mask_ctrl_cnt;
+
+	nt_register_t *mp_writer_mask_data;
+	nt_field_t *mp_writer_mask_data_byte_mask;
+};
+
+struct tx_cpy_nthw {
+	uint8_t m_physical_adapter_no;
+	nt_fpga_t *mp_fpga;
+
+	nt_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, nt_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_mask_pointer(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);
+
+void tx_cpy_nthw_writer_mask_select(const struct tx_cpy_nthw *p, unsigned int index,
+				uint32_t val);
+void tx_cpy_nthw_writer_mask_cnt(const struct tx_cpy_nthw *p, unsigned int index,
+			     uint32_t val);
+void tx_cpy_nthw_writer_mask(const struct tx_cpy_nthw *p, unsigned int index,
+			  uint32_t val);
+void tx_cpy_nthw_writer_mask_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
new file mode 100644
index 0000000000..998c3613ee
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.c
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_tx_ins.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+void tx_ins_nthw_set_debug_mode(struct tx_ins_nthw *p, unsigned int n_debug_mode)
+{
+	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));
+
+	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, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = fpga_query_module(p_fpga, MOD_TX_INS, n_instance);
+
+	p->mp_rcp_ctrl = module_get_register(p->m_tx_ins, INS_RCP_CTRL);
+	p->mp_rcp_addr = register_get_field(p->mp_rcp_ctrl, INS_RCP_CTRL_ADR);
+	p->mp_rcp_cnt = register_get_field(p->mp_rcp_ctrl, INS_RCP_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_tx_ins, INS_RCP_DATA);
+	p->mp_rcp_data_dyn = register_get_field(p->mp_rcp_data, INS_RCP_DATA_DYN);
+	p->mp_rcp_data_ofs = register_get_field(p->mp_rcp_data, INS_RCP_DATA_OFS);
+	p->mp_rcp_data_len = register_get_field(p->mp_rcp_data, INS_RCP_DATA_LEN);
+
+	return 0;
+}
+
+void tx_ins_nthw_rcp_select(const struct tx_ins_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_addr, val);
+}
+
+void tx_ins_nthw_rcp_cnt(const struct tx_ins_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_cnt, val);
+}
+
+void tx_ins_nthw_rcp_dyn(const struct tx_ins_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_dyn, val);
+}
+
+void tx_ins_nthw_rcp_ofs(const struct tx_ins_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_ofs, val);
+}
+
+void tx_ins_nthw_rcp_len(const struct tx_ins_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_len, val);
+}
+
+void tx_ins_nthw_rcp_flush(const struct tx_ins_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	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
new file mode 100644
index 0000000000..813bd30c62
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_ins.h
@@ -0,0 +1,42 @@
+/* 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;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_tx_ins;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_addr;
+	nt_field_t *mp_rcp_cnt;
+
+	nt_register_t *mp_rcp_data;
+	nt_field_t *mp_rcp_data_dyn;
+	nt_field_t *mp_rcp_data_ofs;
+	nt_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, nt_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
new file mode 100644
index 0000000000..5e7e26f74d
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.c
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "flow_nthw_tx_rpl.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+void tx_rpl_nthw_set_debug_mode(struct tx_rpl_nthw *p, unsigned int n_debug_mode)
+{
+	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));
+
+	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, nt_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nt_module_t *p_mod = 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 = fpga_query_module(p_fpga, MOD_TX_RPL, n_instance);
+
+	p->mp_rcp_ctrl = module_get_register(p->m_tx_rpl, RPL_RCP_CTRL);
+	p->mp_rcp_ctrl_addr = register_get_field(p->mp_rcp_ctrl, RPL_RCP_CTRL_ADR);
+	p->mp_rcp_ctrl_cnt = register_get_field(p->mp_rcp_ctrl, RPL_RCP_CTRL_CNT);
+	p->mp_rcp_data = module_get_register(p->m_tx_rpl, RPL_RCP_DATA);
+	p->mp_rcp_data_dyn = register_get_field(p->mp_rcp_data, RPL_RCP_DATA_DYN);
+	p->mp_rcp_data_ofs = register_get_field(p->mp_rcp_data, RPL_RCP_DATA_OFS);
+	p->mp_rcp_data_len = register_get_field(p->mp_rcp_data, RPL_RCP_DATA_LEN);
+	p->mp_rcp_data_rpl_ptr =
+		register_get_field(p->mp_rcp_data, RPL_RCP_DATA_RPL_PTR);
+	p->mp_rcp_data_ext_prio =
+		register_get_field(p->mp_rcp_data, RPL_RCP_DATA_EXT_PRIO);
+
+	p->mp_ext_ctrl = module_get_register(p->m_tx_rpl, RPL_EXT_CTRL);
+	p->mp_ext_ctrl_addr = register_get_field(p->mp_ext_ctrl, RPL_EXT_CTRL_ADR);
+	p->mp_ext_ctrl_cnt = register_get_field(p->mp_ext_ctrl, RPL_EXT_CTRL_CNT);
+	p->mp_ext_data = module_get_register(p->m_tx_rpl, RPL_EXT_DATA);
+	p->mp_ext_data_rpl_ptr =
+		register_get_field(p->mp_ext_data, RPL_EXT_DATA_RPL_PTR);
+
+	p->mp_rpl_ctrl = module_get_register(p->m_tx_rpl, RPL_RPL_CTRL);
+	p->mp_rpl_ctrl_addr = register_get_field(p->mp_rpl_ctrl, RPL_RPL_CTRL_ADR);
+	p->mp_rpl_ctrl_cnt = register_get_field(p->mp_rpl_ctrl, RPL_RPL_CTRL_CNT);
+	p->mp_rpl_data = module_get_register(p->m_tx_rpl, RPL_RPL_DATA);
+	p->mp_rpl_data_value = register_get_field(p->mp_rpl_data, RPL_RPL_DATA_VALUE);
+
+	return 0;
+}
+
+void tx_rpl_nthw_rcp_select(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_ctrl_addr, val);
+}
+
+void tx_rpl_nthw_rcp_cnt(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_ctrl_cnt, val);
+}
+
+void tx_rpl_nthw_rcp_dyn(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_dyn, val);
+}
+
+void tx_rpl_nthw_rcp_ofs(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rcp_data_ofs, val);
+}
+
+void tx_rpl_nthw_rcp_len(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	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)
+{
+	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)
+{
+	field_set_val32(p->mp_rcp_data_ext_prio, val);
+}
+
+void tx_rpl_nthw_rcp_flush(const struct tx_rpl_nthw *p)
+{
+	register_flush(p->mp_rcp_ctrl, 1);
+	register_flush(p->mp_rcp_data, 1);
+}
+
+void tx_rpl_nthw_ext_select(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_ext_ctrl_addr, val);
+}
+
+void tx_rpl_nthw_ext_cnt(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	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)
+{
+	field_set_val32(p->mp_ext_data_rpl_ptr, val);
+}
+
+void tx_rpl_nthw_ext_flush(const struct tx_rpl_nthw *p)
+{
+	register_flush(p->mp_ext_ctrl, 1);
+	register_flush(p->mp_ext_data, 1);
+}
+
+void tx_rpl_nthw_rpl_select(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	field_set_val32(p->mp_rpl_ctrl_addr, val);
+}
+
+void tx_rpl_nthw_rpl_cnt(const struct tx_rpl_nthw *p, uint32_t val)
+{
+	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)
+{
+	field_set_val(p->mp_rpl_data_value, val, 4);
+}
+
+void tx_rpl_nthw_rpl_flush(const struct tx_rpl_nthw *p)
+{
+	register_flush(p->mp_rpl_ctrl, 1);
+	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
new file mode 100644
index 0000000000..e5f724361b
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_filter/flow_nthw_tx_rpl.h
@@ -0,0 +1,70 @@
+/* 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;
+	nt_fpga_t *mp_fpga;
+
+	nt_module_t *m_tx_rpl;
+
+	nt_register_t *mp_rcp_ctrl;
+	nt_field_t *mp_rcp_ctrl_addr;
+	nt_field_t *mp_rcp_ctrl_cnt;
+
+	nt_register_t *mp_rcp_data;
+	nt_field_t *mp_rcp_data_dyn;
+	nt_field_t *mp_rcp_data_ofs;
+	nt_field_t *mp_rcp_data_len;
+	nt_field_t *mp_rcp_data_rpl_ptr;
+	nt_field_t *mp_rcp_data_ext_prio;
+
+	nt_register_t *mp_ext_ctrl;
+	nt_field_t *mp_ext_ctrl_addr;
+	nt_field_t *mp_ext_ctrl_cnt;
+
+	nt_register_t *mp_ext_data;
+	nt_field_t *mp_ext_data_rpl_ptr;
+
+	nt_register_t *mp_rpl_ctrl;
+	nt_field_t *mp_rpl_ctrl_addr;
+	nt_field_t *mp_rpl_ctrl_cnt;
+
+	nt_register_t *mp_rpl_data;
+	nt_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, nt_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_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.39.3


  parent reply	other threads:[~2023-08-31 13:51 UTC|newest]

Thread overview: 142+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-16 13:25 [PATCH 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-08-16 13:25 ` [PATCH 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-08-16 13:25 ` [PATCH 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-08-16 13:25 ` [PATCH 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-08-16 13:25 ` [PATCH 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-08-16 13:25 ` [PATCH 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-08-16 13:25 ` [PATCH 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-08-16 13:25 ` [PATCH 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-08-16 14:46   ` Stephen Hemminger
2023-08-25 13:52     ` Christian Koue Muf
2023-08-16 14:47   ` Stephen Hemminger
2023-08-17 14:43 ` [PATCH v2 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-08-17 14:43   ` [PATCH v2 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-08-17 14:43   ` [PATCH v2 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-08-17 14:43   ` [PATCH v2 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-08-17 14:43   ` [PATCH v2 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-08-17 14:43   ` [PATCH v2 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-08-17 14:43   ` [PATCH v2 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-08-17 14:43   ` [PATCH v2 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-08-17 22:08   ` [PATCH v2 1/8] net/ntnic: initial commit which adds register defines Tyler Retzlaff
2023-08-18 11:01     ` Mykola Kostenok
2023-08-18 18:41 ` [PATCH v4 " Mykola Kostenok
2023-08-18 18:41   ` [PATCH v4 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-08-18 18:41   ` [PATCH v4 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-08-18 18:41   ` [PATCH v4 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-08-18 18:41   ` [PATCH v4 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-08-18 18:41   ` [PATCH v4 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-08-18 18:41   ` [PATCH v4 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-08-18 18:41   ` [PATCH v4 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-08-21 11:34 ` [PATCH v5 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-08-21 11:34   ` [PATCH v5 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-08-21 11:34   ` [PATCH v5 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-08-21 11:34   ` [PATCH v5 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-08-21 11:34   ` [PATCH v5 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-08-21 11:34   ` [PATCH v5 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-08-21 11:34   ` [PATCH v5 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-08-21 11:34   ` [PATCH v5 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-08-21 13:54 ` [PATCH v6 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-08-21 13:54   ` [PATCH v6 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-08-21 13:54   ` [PATCH v6 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-08-21 13:54   ` [PATCH v6 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-08-21 13:54   ` [PATCH v6 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-08-21 13:54   ` [PATCH v6 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-08-21 13:54   ` [PATCH v6 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-08-21 13:54   ` [PATCH v6 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-08-22 15:41 ` [PATCH v7 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-08-22 15:41   ` [PATCH v7 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-08-22 15:41   ` [PATCH v7 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-08-22 15:41   ` [PATCH v7 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-08-22 15:41   ` [PATCH v7 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-08-22 15:41   ` [PATCH v7 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-08-22 15:41   ` [PATCH v7 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-08-29  8:13     ` David Marchand
2023-08-22 15:41   ` [PATCH v7 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-08-29  8:15 ` [PATCH v8 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-08-29  8:15   ` [PATCH v8 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-08-29  8:15   ` [PATCH v8 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-08-29  8:15   ` [PATCH v8 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-08-29  8:15   ` [PATCH v8 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-08-29  8:15   ` [PATCH v8 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-08-29  8:15   ` [PATCH v8 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-08-29  8:15   ` [PATCH v8 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-08-29 10:17 ` [PATCH v9 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-08-29 10:17   ` [PATCH v9 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-08-29 10:17   ` [PATCH v9 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-08-29 10:17   ` [PATCH v9 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-08-29 10:17   ` [PATCH v9 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-08-29 10:17   ` [PATCH v9 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-08-29 10:17   ` [PATCH v9 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-08-29 10:17   ` [PATCH v9 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-08-30 16:51 ` [PATCH v10 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-08-30 16:51   ` [PATCH v10 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-08-30 16:51   ` [PATCH v10 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-08-30 16:51   ` [PATCH v10 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-08-30 16:51   ` [PATCH v10 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-08-30 16:51   ` [PATCH v10 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-08-30 16:51   ` [PATCH v10 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-08-30 16:51   ` [PATCH v10 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-08-31 12:23 ` [PATCH v11 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-08-31 12:23   ` [PATCH v11 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-08-31 12:23   ` [PATCH v11 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-08-31 12:23   ` [PATCH v11 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-08-31 12:23   ` [PATCH v11 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-08-31 12:23   ` [PATCH v11 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-08-31 12:23   ` [PATCH v11 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-08-31 12:23   ` [PATCH v11 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-08-31 13:51 ` [PATCH v12 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-08-31 13:51   ` [PATCH v12 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-08-31 13:51   ` [PATCH v12 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-08-31 13:51   ` Mykola Kostenok [this message]
2023-08-31 13:51   ` [PATCH v12 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-08-31 13:51   ` [PATCH v12 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-08-31 13:51   ` [PATCH v12 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-08-31 13:51   ` [PATCH v12 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-09-01 12:18 ` [PATCH v13 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-09-01 12:18   ` [PATCH v13 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-09-01 12:18   ` [PATCH v13 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-09-01 12:18   ` [PATCH v13 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-09-01 12:18   ` [PATCH v13 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-09-01 12:18   ` [PATCH v13 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-09-01 12:18   ` [PATCH v13 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-09-01 12:18   ` [PATCH v13 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-09-02 17:26     ` Patrick Robb
2023-09-04 13:53 ` [PATCH v14 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-09-04 13:53   ` [PATCH v14 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-09-04 13:53   ` [PATCH v14 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-09-04 13:53   ` [PATCH v14 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-09-04 13:53   ` [PATCH v14 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-09-04 13:53   ` [PATCH v14 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-09-04 13:54   ` [PATCH v14 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-09-04 13:54   ` [PATCH v14 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-09-05 14:54 ` [PATCH v15 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-09-05 14:54   ` [PATCH v15 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-09-05 14:54   ` [PATCH v15 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-09-05 14:54   ` [PATCH v15 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-09-05 14:54   ` [PATCH v15 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-09-05 14:54   ` [PATCH v15 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-09-05 14:54   ` [PATCH v15 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-09-05 14:54   ` [PATCH v15 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-09-08 16:07 ` [PATCH v16 1/8] net/ntnic: initial commit which adds register defines Mykola Kostenok
2023-09-08 16:07   ` [PATCH v16 2/8] net/ntnic: adds core registers and fpga functionality Mykola Kostenok
2023-09-08 16:07   ` [PATCH v16 3/8] net/ntnic: adds NT200A02 adapter support Mykola Kostenok
2023-09-08 16:07   ` [PATCH v16 4/8] net/ntnic: adds flow related FPGA functionality Mykola Kostenok
2023-09-08 16:07   ` [PATCH v16 5/8] net/ntnic: adds FPGA abstraction layer Mykola Kostenok
2023-09-08 16:07   ` [PATCH v16 6/8] net/ntnic: adds flow logic Mykola Kostenok
2023-09-08 16:07   ` [PATCH v16 7/8] net/ntnic: adds ethdev and makes PMD available Mykola Kostenok
2023-09-08 16:07   ` [PATCH v16 8/8] net/ntnic: adds socket connection to PMD Mykola Kostenok
2023-09-15 15:54   ` [PATCH v16 1/8] net/ntnic: initial commit which adds register defines Ferruh Yigit
2023-09-15 18:37     ` Morten Brørup
2023-09-18  9:33       ` Ferruh Yigit
2023-09-19  9:06         ` Christian Koue Muf
2023-09-20  9:48           ` Ferruh Yigit
2023-09-20 13:17           ` Thomas Monjalon
2023-09-21 14:04             ` Ferruh Yigit
2023-09-29  9:21               ` Christian Koue Muf
2023-09-29  9:46                 ` Ferruh Yigit
2023-09-29 10:23                   ` Thomas Monjalon
2023-10-09  7:57                     ` Christian Koue Muf
2023-10-09  9:52                       ` Ferruh Yigit
2024-03-29 11:24                       ` Ferruh Yigit
2024-04-03 10:55                         ` Mykola Kostenok
2024-04-04 12:49                           ` Ferruh Yigit

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230831135112.1435200-4-mko-plv@napatech.com \
    --to=mko-plv@napatech.com \
    --cc=ckm@napatech.com \
    --cc=dev@dpdk.org \
    --cc=thomas@monjalon.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.