[v1,08/31] net/ntnic: add flow matcher (FLM) flow module

Message ID 20241004150749.261020-15-sil-plv@napatech.com (mailing list archive)
State Superseded
Headers
Series Fixes for release 24.07 |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Serhii Iliushyk Oct. 4, 2024, 3:07 p.m. UTC
From: Oleksandr Kolomeiets <okl-plv@napatech.com>

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

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

Patch

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