DPDK patches and discussions
 help / color / mirror / Atom feed
From: Serhii Iliushyk <sil-plv@napatech.com>
To: dev@dpdk.org
Cc: mko-plv@napatech.com, sil-plv@napatech.com, ckm@napatech.com,
	andrew.rybchenko@oktetlabs.ru, ferruh.yigit@amd.com
Subject: [PATCH v5 10/23] net/ntnic: add core platform functionality
Date: Thu, 27 Jun 2024 09:38:51 +0200	[thread overview]
Message-ID: <20240627073918.2039719-10-sil-plv@napatech.com> (raw)
In-Reply-To: <20240627073918.2039719-1-sil-plv@napatech.com>

Add ntnic platform interfaces for FPGA registers

Signed-off-by: Serhii Iliushyk <sil-plv@napatech.com>
---
 drivers/net/ntnic/meson.build                 |   1 +
 .../net/ntnic/nthw/core/include/nthw_core.h   |  16 +
 .../net/ntnic/nthw/core/include/nthw_hif.h    | 151 ++++
 .../net/ntnic/nthw/core/include/nthw_iic.h    | 100 +++
 .../net/ntnic/nthw/core/include/nthw_pcie3.h  |  96 +++
 drivers/net/ntnic/nthw/core/nthw_hif.c        | 312 +++++++
 drivers/net/ntnic/nthw/core/nthw_iic.c        | 527 ++++++++++++
 drivers/net/ntnic/nthw/core/nthw_pcie3.c      | 259 ++++++
 drivers/net/ntnic/nthw/nthw_drv.h             |   3 +-
 drivers/net/ntnic/nthw/nthw_rac.c             | 785 ++++++++++++++++++
 drivers/net/ntnic/nthw/nthw_rac.h             | 153 ++++
 11 files changed, 2401 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_core.h
 create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_hif.h
 create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_iic.h
 create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_pcie3.h
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_hif.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_iic.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_pcie3.c
 create mode 100644 drivers/net/ntnic/nthw/nthw_rac.c
 create mode 100644 drivers/net/ntnic/nthw/nthw_rac.h

diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 490a10c442..aa839f4de3 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -18,6 +18,7 @@ includes = [
     include_directories('include'),
     include_directories('ntlog/include'),
     include_directories('ntutil/include'),
+    include_directories('nthw/core/include'),
     include_directories('nthw'),
     include_directories('nthw/supported'),
 ]
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_core.h b/drivers/net/ntnic/nthw/core/include/nthw_core.h
new file mode 100644
index 0000000000..c2602e396f
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/include/nthw_core.h
@@ -0,0 +1,16 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NTHW_CORE_H__
+#define __NTHW_CORE_H__
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "nthw_platform_drv.h"
+
+
+#endif	/* __NTHW_CORE_H__ */
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_hif.h b/drivers/net/ntnic/nthw/core/include/nthw_hif.h
new file mode 100644
index 0000000000..c8f4669f83
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/include/nthw_hif.h
@@ -0,0 +1,151 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NTHW_HIF_H__
+#define __NTHW_HIF_H__
+
+#define NTHW_TG_CNT_SIZE (4ULL)
+
+struct nthw_hif {
+	nthw_fpga_t *mp_fpga;
+	nthw_module_t *mp_mod_hif;
+	int mn_instance;
+
+	nthw_register_t *mp_reg_ctrl;
+	nthw_field_t *mp_fld_ctrl_fsr;
+
+	nthw_register_t *mp_reg_prod_id_lsb;
+	nthw_field_t *mp_fld_prod_id_lsb_rev_id;
+	nthw_field_t *mp_fld_prod_id_lsb_ver_id;
+	nthw_field_t *mp_fld_prod_id_lsb_group_id;
+
+	nthw_register_t *mp_reg_prod_id_msb;
+	nthw_field_t *mp_fld_prod_id_msb_type_id;
+	nthw_field_t *mp_fld_prod_id_msb_build_no;
+
+	nthw_register_t *mp_reg_build_time;
+	nthw_field_t *mp_fld_build_time;
+
+	nthw_register_t *mp_reg_build_seed;
+	nthw_field_t *mp_fld_build_seed;
+
+	nthw_register_t *mp_reg_core_speed;
+	nthw_field_t *mp_fld_core_speed;
+	nthw_field_t *mp_fld_ddr3_speed;
+
+	nthw_register_t *mp_reg_int_mask;
+	nthw_field_t *mp_fld_int_mask_timer;
+	nthw_field_t *mp_fld_int_mask_port;
+	nthw_field_t *mp_fld_int_mask_pps;
+
+	nthw_register_t *mp_reg_int_clr;
+	nthw_field_t *mp_fld_int_clr_timer;
+	nthw_field_t *mp_fld_int_clr_port;
+	nthw_field_t *mp_fld_int_clr_pps;
+
+	nthw_register_t *mp_reg_int_force;
+	nthw_field_t *mp_fld_int_force_timer;
+	nthw_field_t *mp_fld_int_force_port;
+	nthw_field_t *mp_fld_int_force_pps;
+
+	nthw_register_t *mp_reg_sample_time;
+	nthw_field_t *mp_fld_sample_time;
+
+	nthw_register_t *mp_reg_status;
+	nthw_field_t *mp_fld_status_tags_in_use;
+	nthw_field_t *mp_fld_status_wr_err;
+	nthw_field_t *mp_fld_status_rd_err;
+
+	nthw_register_t *mp_reg_stat_ctrl;
+	nthw_field_t *mp_fld_stat_ctrl_ena;
+	nthw_field_t *mp_fld_stat_ctrl_req;
+
+	nthw_register_t *mp_reg_stat_rx;
+	nthw_field_t *mp_fld_stat_rx_counter;
+
+	nthw_register_t *mp_reg_stat_tx;
+	nthw_field_t *mp_fld_stat_tx_counter;
+
+	nthw_register_t *mp_reg_stat_ref_clk;
+	nthw_field_t *mp_fld_stat_ref_clk_ref_clk;
+
+	nthw_register_t *mp_reg_pci_test0;
+	nthw_field_t *mp_fld_pci_test0;
+
+	nthw_register_t *mp_reg_pci_test1;
+	nthw_field_t *mp_fld_pci_test1;
+
+	nthw_register_t *mp_reg_pci_test2;
+	nthw_field_t *mp_fld_pci_test2;
+
+	nthw_register_t *mp_reg_pci_test3;
+	nthw_field_t *mp_fld_pci_test3;
+
+	nthw_register_t *mp_reg_config;
+	nthw_field_t *mp_fld_max_tlp;
+	nthw_field_t *mp_fld_max_read;
+	nthw_field_t *mp_fld_ext_tag;
+
+	int mn_fpga_id_item;
+	int mn_fpga_id_prod;
+	int mn_fpga_id_ver;
+	int mn_fpga_id_rev;
+	int mn_fpga_id_build_no;
+
+	int mn_fpga_param_hif_per_ps;
+	uint32_t mn_fpga_hif_ref_clk_freq;
+};
+
+typedef struct nthw_hif nthw_hif_t;
+
+struct nthw_hif_end_point_err_counters {
+	uint32_t n_err_correctable, n_err_non_fatal, n_err_fatal;
+};
+
+struct nthw_hif_end_point_counters {
+	int n_numa_node;
+
+	int n_tg_direction;
+	int n_tg_pkt_size;
+	int n_tg_num_pkts;
+	int n_tg_delay;
+
+	uint64_t cur_rx, cur_tx;
+	uint64_t cur_pci_nt_util, cur_pci_xil_util;
+	uint64_t n_ref_clk_cnt;
+
+	uint64_t n_tags_in_use;
+	uint64_t n_rd_err;
+	uint64_t n_wr_err;
+
+	struct nthw_hif_end_point_err_counters s_rc_ep_pre, s_rc_ep_post, s_rc_ep_delta;
+	struct nthw_hif_end_point_err_counters s_ep_rc_pre, s_ep_rc_post, s_ep_rc_delta;
+
+	int bo_error;
+};
+
+struct nthw_hif_end_points {
+	struct nthw_hif_end_point_counters pri, sla;
+};
+
+nthw_hif_t *nthw_hif_new(void);
+void nthw_hif_delete(nthw_hif_t *p);
+int nthw_hif_init(nthw_hif_t *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int nthw_hif_trigger_sample_time(nthw_hif_t *p);
+
+int nthw_hif_stat_req_enable(nthw_hif_t *p);
+int nthw_hif_stat_req_disable(nthw_hif_t *p);
+
+int nthw_hif_get_stat(nthw_hif_t *p, uint32_t *p_rx_cnt, uint32_t *p_tx_cnt,
+	uint32_t *p_ref_clk_cnt, uint32_t *p_tg_unit_size, uint32_t *p_tg_ref_freq,
+	uint64_t *p_tags_in_use, uint64_t *p_rd_err, uint64_t *p_wr_err);
+int nthw_hif_get_stat_rate(nthw_hif_t *p, uint64_t *p_pci_rx_rate, uint64_t *p_pci_tx_rate,
+	uint64_t *p_ref_clk_cnt, uint64_t *p_tags_in_use,
+	uint64_t *p_rd_err_cnt, uint64_t *p_wr_err_cnt);
+
+int nthw_hif_end_point_counters_sample(nthw_hif_t *p, struct nthw_hif_end_point_counters *epc);
+
+#endif	/* __NTHW_HIF_H__ */
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_iic.h b/drivers/net/ntnic/nthw/core/include/nthw_iic.h
new file mode 100644
index 0000000000..41574f51f3
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/include/nthw_iic.h
@@ -0,0 +1,100 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NTHW_IIC_H__
+#define __NTHW_IIC_H__
+
+#include "nthw_fpga_model.h"
+
+struct nthw_iic {
+	nthw_fpga_t *mp_fpga;
+	nthw_module_t *mp_mod_iic;
+	int mn_iic_instance;
+
+	uint32_t mn_iic_cycle_time;
+	int mn_poll_delay;
+	int mn_bus_ready_retry;
+	int mn_data_ready_retry;
+	int mn_read_data_retry;
+	int mn_write_data_retry;
+
+	nthw_register_t *mp_reg_tsusta;
+	nthw_field_t *mp_fld_tsusta;
+
+	nthw_register_t *mp_reg_tsusto;
+	nthw_field_t *mp_fld_tsusto;
+
+	nthw_register_t *mp_reg_thdsta;
+	nthw_field_t *mp_fld_thdsta;
+
+	nthw_register_t *mp_reg_tsudat;
+	nthw_field_t *mp_fld_tsudat;
+
+	nthw_register_t *mp_reg_tbuf;
+	nthw_field_t *mp_fld_tbuf;
+
+	nthw_register_t *mp_reg_thigh;
+	nthw_field_t *mp_fld_thigh;
+
+	nthw_register_t *mp_reg_tlow;
+	nthw_field_t *mp_fld_tlow;
+
+	nthw_register_t *mp_reg_thddat;
+	nthw_field_t *mp_fld_thddat;
+
+	nthw_register_t *mp_reg_cr;
+	nthw_field_t *mp_fld_cr_en;
+	nthw_field_t *mp_fld_cr_msms;
+	nthw_field_t *mp_fld_cr_txfifo_reset;
+	nthw_field_t *mp_fld_cr_txak;
+
+	nthw_register_t *mp_reg_sr;
+	nthw_field_t *mp_fld_sr_bb;
+	nthw_field_t *mp_fld_sr_rxfifo_full;
+	nthw_field_t *mp_fld_sr_rxfifo_empty;
+	nthw_field_t *mp_fld_sr_txfifo_full;
+	nthw_field_t *mp_fld_sr_txfifo_empty;
+
+	nthw_register_t *mp_reg_tx_fifo;
+	nthw_field_t *mp_fld_tx_fifo_txdata;
+	nthw_field_t *mp_fld_tx_fifo_start;
+	nthw_field_t *mp_fld_tx_fifo_stop;
+
+	nthw_register_t *mp_reg_rx_fifo_pirq;
+	nthw_field_t *mp_fld_rx_fifo_pirq_cmp_val;
+
+	nthw_register_t *mp_reg_rx_fifo;
+	nthw_field_t *mp_fld_rx_fifo_rxdata;
+
+	nthw_register_t *mp_reg_softr;
+	nthw_field_t *mp_fld_softr_rkey;
+};
+
+typedef struct nthw_iic nthw_iic_t;
+
+nthw_iic_t *nthw_iic_new(void);
+int nthw_iic_init(nthw_iic_t *p, nthw_fpga_t *p_fpga, int n_iic_instance,
+	uint32_t n_iic_cycle_time);
+void nthw_iic_delete(nthw_iic_t *p);
+
+int nthw_iic_set_retry_params(nthw_iic_t *p, const int n_poll_delay, const int n_bus_ready_retry,
+	const int n_data_ready_retry, const int n_read_data_retry,
+	const int n_write_data_retry);
+
+int nthw_iic_read_data(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint8_t data_len,
+	void *p_void);
+int nthw_iic_readbyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint8_t data_len,
+	uint8_t *p_byte);
+int nthw_iic_write_data(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint8_t data_len,
+	void *p_void);
+int nthw_iic_writebyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint8_t data_len,
+	uint8_t *p_byte);
+bool nthw_iic_bus_ready(nthw_iic_t *p);
+bool nthw_iic_data_ready(nthw_iic_t *p);
+
+int nthw_iic_scan(nthw_iic_t *p);
+int nthw_iic_scan_dev_addr(nthw_iic_t *p, int n_dev_addr, int n_reg_addr);
+
+#endif	/* __NTHW_IIC_H__ */
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_pcie3.h b/drivers/net/ntnic/nthw/core/include/nthw_pcie3.h
new file mode 100644
index 0000000000..846c09b1b9
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/include/nthw_pcie3.h
@@ -0,0 +1,96 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NTHW_PCIE3_H__
+#define __NTHW_PCIE3_H__
+
+struct nthw_pcie3 {
+	nthw_fpga_t *mp_fpga;
+	nthw_module_t *mp_mod_pcie3;
+	int mn_instance;
+
+	nthw_register_t *mp_reg_stat_ctrl;
+	nthw_field_t *mp_fld_stat_ctrl_req;
+	nthw_field_t *mp_fld_stat_ctrl_ena;
+
+	nthw_register_t *mp_reg_stat_rx;
+	nthw_field_t *mp_fld_stat_rx_counter;
+
+	nthw_register_t *mp_reg_stat_tx;
+	nthw_field_t *mp_fld_stat_tx_counter;
+
+	nthw_register_t *mp_reg_stat_rq_rdy;
+	nthw_field_t *mp_fld_stat_rq_rdy_counter;
+
+	nthw_register_t *mp_reg_stat_rq_vld;
+	nthw_field_t *mp_fld_stat_rq_vld_counter;
+
+	nthw_register_t *mp_reg_status0;
+	nthw_field_t *mp_fld_status0_tags_in_use;
+
+	nthw_register_t *mp_reg_stat_ref_clk;
+	nthw_field_t *mp_fld_stat_ref_clk_ref_clk;
+
+	nthw_register_t *mp_reg_rp_to_ep_err;
+	nthw_field_t *mp_fld_rp_to_ep_err_cor;
+	nthw_field_t *mp_fld_rp_to_ep_err_non_fatal;
+	nthw_field_t *mp_fld_rp_to_ep_err_fatal;
+
+	nthw_register_t *mp_reg_ep_to_rp_err;
+	nthw_field_t *mp_fld_ep_to_rp_err_cor;
+	nthw_field_t *mp_fld_ep_to_rp_err_non_fatal;
+	nthw_field_t *mp_fld_ep_to_rp_err_fatal;
+
+	nthw_register_t *mp_reg_sample_time;
+	nthw_field_t *mp_fld_sample_time;
+
+	nthw_register_t *mp_reg_pci_end_point;
+	nthw_field_t *mp_fld_pci_end_point_if_id;
+	nthw_field_t *mp_fld_pci_end_point_send_msg;
+	nthw_field_t *mp_fld_pci_end_point_get_msg;
+	nthw_field_t *mp_fld_pci_end_point_dmaep0_allow_mask;
+	nthw_field_t *mp_fld_pci_end_point_dmaep1_allow_mask;
+
+	nthw_register_t *mp_reg_pci_e3_mark_adr_lsb;
+	nthw_field_t *mp_fld_pci_e3_mark_adr_lsb_adr;
+
+	nthw_register_t *mp_reg_pci_e3_mark_adr_msb;
+	nthw_field_t *mp_fld_pci_e3_mark_adr_msb_adr;
+
+	nthw_register_t *mp_reg_pci_test0;
+	nthw_field_t *mp_fld_pci_test0;
+
+	nthw_register_t *mp_reg_pci_test1;
+	nthw_field_t *mp_fld_pci_test1;
+
+	nthw_register_t *mp_reg_pci_test2;
+	nthw_field_t *mp_fld_pci_test2;
+
+	nthw_register_t *mp_reg_pci_test3;
+	nthw_field_t *mp_fld_pci_test3;
+};
+
+typedef struct nthw_pcie3 nthw_pcie3_t;
+
+nthw_pcie3_t *nthw_pcie3_new(void);
+void nthw_pcie3_delete(nthw_pcie3_t *p);
+int nthw_pcie3_init(nthw_pcie3_t *p, nthw_fpga_t *p_fpga, int n_instance);
+
+int nthw_pcie3_trigger_sample_time(nthw_pcie3_t *p);
+
+int nthw_pcie3_stat_req_enable(nthw_pcie3_t *p);
+int nthw_pcie3_stat_req_disable(nthw_pcie3_t *p);
+
+int nthw_pcie3_get_stat(nthw_pcie3_t *p, uint32_t *p_rx_cnt, uint32_t *p_tx_cnt,
+	uint32_t *p_ref_clk_cnt, uint32_t *p_tg_unit_size, uint32_t *p_tg_ref_freq,
+	uint32_t *p_tag_use_cnt, uint32_t *p_rq_rdy_cnt, uint32_t *p_rq_vld_cnt);
+int nthw_pcie3_get_stat_rate(nthw_pcie3_t *p, uint64_t *p_pci_rx_rate, uint64_t *p_pci_tx_rate,
+	uint64_t *p_ref_clk_cnt, uint64_t *p_tag_use_cnt,
+	uint64_t *p_pci_nt_bus_util, uint64_t *p_pci_xil_bus_util);
+
+int nthw_pcie3_end_point_counters_sample_post(nthw_pcie3_t *p,
+	struct nthw_hif_end_point_counters *epc);
+
+#endif	/* __NTHW_PCIE3_H__ */
diff --git a/drivers/net/ntnic/nthw/core/nthw_hif.c b/drivers/net/ntnic/nthw/core/nthw_hif.c
new file mode 100644
index 0000000000..f05e1a0c51
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_hif.c
@@ -0,0 +1,312 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "nt_util.h"
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_hif.h"
+
+nthw_hif_t *nthw_hif_new(void)
+{
+	nthw_hif_t *p = malloc(sizeof(nthw_hif_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_hif_t));
+
+	return p;
+}
+
+void nthw_hif_delete(nthw_hif_t *p)
+{
+	if (p) {
+		memset(p, 0, sizeof(nthw_hif_t));
+		free(p);
+	}
+}
+
+int nthw_hif_init(nthw_hif_t *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	(void)p_adapter_id_str;
+	nthw_module_t *mod = nthw_fpga_query_module(p_fpga, MOD_HIF, n_instance);
+
+	if (p == NULL)
+		return mod == NULL ? -1 : 0;
+
+	if (mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: HIF %d: no such instance\n",
+			p_fpga->p_fpga_info->mp_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_instance = n_instance;
+	p->mp_mod_hif = mod;
+
+	/* default for (Xilinx-based) products until august 2022: (1e6/4000 = 250 MHz) */
+	p->mn_fpga_param_hif_per_ps = nthw_fpga_get_product_param(p->mp_fpga, NT_HIF_PER_PS, 4000);
+	p->mn_fpga_hif_ref_clk_freq =
+		(uint32_t)(1000000000000ULL / (unsigned int)p->mn_fpga_param_hif_per_ps);
+
+	p->mp_reg_prod_id_lsb = nthw_module_get_register(p->mp_mod_hif, HIF_PROD_ID_LSB);
+	p->mp_fld_prod_id_lsb_rev_id =
+		nthw_register_get_field(p->mp_reg_prod_id_lsb, HIF_PROD_ID_LSB_REV_ID);
+	p->mp_fld_prod_id_lsb_ver_id =
+		nthw_register_get_field(p->mp_reg_prod_id_lsb, HIF_PROD_ID_LSB_VER_ID);
+	p->mp_fld_prod_id_lsb_group_id =
+		nthw_register_get_field(p->mp_reg_prod_id_lsb, HIF_PROD_ID_LSB_GROUP_ID);
+
+	p->mp_reg_prod_id_msb = nthw_module_get_register(p->mp_mod_hif, HIF_PROD_ID_MSB);
+	p->mp_fld_prod_id_msb_type_id =
+		nthw_register_get_field(p->mp_reg_prod_id_msb, HIF_PROD_ID_MSB_TYPE_ID);
+	p->mp_fld_prod_id_msb_build_no =
+		nthw_register_get_field(p->mp_reg_prod_id_msb, HIF_PROD_ID_MSB_BUILD_NO);
+
+	p->mp_reg_build_time = nthw_module_get_register(p->mp_mod_hif, HIF_BUILD_TIME);
+	p->mp_fld_build_time = nthw_register_get_field(p->mp_reg_build_time, HIF_BUILD_TIME_TIME);
+
+	p->mn_fpga_id_prod = nthw_field_get_updated(p->mp_fld_prod_id_lsb_group_id);
+	p->mn_fpga_id_ver = nthw_field_get_updated(p->mp_fld_prod_id_lsb_ver_id);
+	p->mn_fpga_id_rev = nthw_field_get_updated(p->mp_fld_prod_id_lsb_rev_id);
+	p->mn_fpga_id_build_no = nthw_field_get_updated(p->mp_fld_prod_id_msb_build_no);
+	p->mn_fpga_id_item = nthw_field_get_updated(p->mp_fld_prod_id_msb_type_id);
+
+	NT_LOG(DBG, NTHW, "%s: HIF %d: %d-%d-%d-%d-%d\n", p_adapter_id_str, p->mn_instance,
+		p->mn_fpga_id_item, p->mn_fpga_id_prod, p->mn_fpga_id_ver,
+		p->mn_fpga_id_rev, p->mn_fpga_id_build_no);
+	NT_LOG(DBG, NTHW, "%s: HIF %d: HIF ref clock: %d Hz (%d ticks/ps)\n", p_adapter_id_str,
+		p->mn_instance, p->mn_fpga_hif_ref_clk_freq, p->mn_fpga_param_hif_per_ps);
+
+	p->mp_reg_build_seed = NULL;	/* Reg/Fld not present on HIF */
+
+	if (p->mp_reg_build_seed)
+		p->mp_fld_build_seed = NULL;	/* Reg/Fld not present on HIF */
+	else
+		p->mp_fld_build_seed = NULL;
+
+	p->mp_reg_core_speed = NULL;	/* Reg/Fld not present on HIF */
+
+	if (p->mp_reg_core_speed) {
+		p->mp_fld_core_speed = NULL;	/* Reg/Fld not present on HIF */
+		p->mp_fld_ddr3_speed = NULL;	/* Reg/Fld not present on HIF */
+
+	} else {
+		p->mp_reg_core_speed = NULL;
+		p->mp_fld_core_speed = NULL;
+		p->mp_fld_ddr3_speed = NULL;
+	}
+
+	/* Optional registers since: 2018-04-25 */
+	p->mp_reg_int_mask = NULL;	/* Reg/Fld not present on HIF */
+	p->mp_reg_int_clr = NULL;	/* Reg/Fld not present on HIF */
+	p->mp_reg_int_force = NULL;	/* Reg/Fld not present on HIF */
+
+	p->mp_fld_int_mask_timer = NULL;
+	p->mp_fld_int_clr_timer = NULL;
+	p->mp_fld_int_force_timer = NULL;
+
+	p->mp_fld_int_mask_port = NULL;
+	p->mp_fld_int_clr_port = NULL;
+	p->mp_fld_int_force_port = NULL;
+
+	p->mp_fld_int_mask_pps = NULL;
+	p->mp_fld_int_clr_pps = NULL;
+	p->mp_fld_int_force_pps = NULL;
+
+	p->mp_reg_ctrl = nthw_module_get_register(p->mp_mod_hif, HIF_CONTROL);
+	p->mp_fld_ctrl_fsr = nthw_register_query_field(p->mp_reg_ctrl, HIF_CONTROL_FSR);
+
+	p->mp_reg_stat_ctrl = nthw_module_get_register(p->mp_mod_hif, HIF_STAT_CTRL);
+	p->mp_fld_stat_ctrl_ena =
+		nthw_register_get_field(p->mp_reg_stat_ctrl, HIF_STAT_CTRL_STAT_ENA);
+	p->mp_fld_stat_ctrl_req =
+		nthw_register_get_field(p->mp_reg_stat_ctrl, HIF_STAT_CTRL_STAT_REQ);
+
+	p->mp_reg_stat_rx = nthw_module_get_register(p->mp_mod_hif, HIF_STAT_RX);
+	p->mp_fld_stat_rx_counter =
+		nthw_register_get_field(p->mp_reg_stat_rx, HIF_STAT_RX_COUNTER);
+
+	p->mp_reg_stat_tx = nthw_module_get_register(p->mp_mod_hif, HIF_STAT_TX);
+	p->mp_fld_stat_tx_counter =
+		nthw_register_get_field(p->mp_reg_stat_tx, HIF_STAT_TX_COUNTER);
+
+	p->mp_reg_stat_ref_clk = nthw_module_get_register(p->mp_mod_hif, HIF_STAT_REFCLK);
+	p->mp_fld_stat_ref_clk_ref_clk =
+		nthw_register_get_field(p->mp_reg_stat_ref_clk, HIF_STAT_REFCLK_REFCLK250);
+
+	p->mp_reg_status = nthw_module_query_register(p->mp_mod_hif, HIF_STATUS);
+
+	if (p->mp_reg_status) {
+		p->mp_fld_status_tags_in_use =
+			nthw_register_query_field(p->mp_reg_status, HIF_STATUS_TAGS_IN_USE);
+		p->mp_fld_status_wr_err =
+			nthw_register_query_field(p->mp_reg_status, HIF_STATUS_WR_ERR);
+		p->mp_fld_status_rd_err =
+			nthw_register_query_field(p->mp_reg_status, HIF_STATUS_RD_ERR);
+
+	} else {
+		p->mp_reg_status = nthw_module_query_register(p->mp_mod_hif, HIF_STATUS);
+		p->mp_fld_status_tags_in_use =
+			nthw_register_query_field(p->mp_reg_status, HIF_STATUS_TAGS_IN_USE);
+		p->mp_fld_status_wr_err = NULL;
+		p->mp_fld_status_rd_err = NULL;
+	}
+
+	p->mp_reg_pci_test0 = nthw_module_get_register(p->mp_mod_hif, HIF_TEST0);
+	p->mp_fld_pci_test0 = nthw_register_get_field(p->mp_reg_pci_test0, HIF_TEST0_DATA);
+
+	p->mp_reg_pci_test1 = nthw_module_get_register(p->mp_mod_hif, HIF_TEST1);
+	p->mp_fld_pci_test1 = nthw_register_get_field(p->mp_reg_pci_test1, HIF_TEST1_DATA);
+
+	/* Module::Version({2, 0})+ */
+	p->mp_reg_pci_test2 = nthw_module_query_register(p->mp_mod_hif, HIF_TEST2);
+
+	if (p->mp_reg_pci_test2)
+		p->mp_fld_pci_test2 = nthw_register_get_field(p->mp_reg_pci_test2, HIF_TEST2_DATA);
+
+	else
+		p->mp_fld_pci_test2 = NULL;
+
+	/* Module::Version({1, 2})+ */
+	p->mp_reg_pci_test3 = nthw_module_query_register(p->mp_mod_hif, HIF_TEST3);
+
+	if (p->mp_reg_pci_test3)
+		p->mp_fld_pci_test3 = nthw_register_get_field(p->mp_reg_pci_test3, HIF_TEST3_DATA);
+
+	else
+		p->mp_fld_pci_test3 = NULL;
+
+	/* Required to run TSM */
+	p->mp_reg_sample_time = nthw_module_get_register(p->mp_mod_hif, HIF_SAMPLE_TIME);
+
+	if (p->mp_reg_sample_time) {
+		p->mp_fld_sample_time = nthw_register_get_field(p->mp_reg_sample_time,
+				HIF_SAMPLE_TIME_SAMPLE_TIME);
+
+	} else {
+		p->mp_fld_sample_time = NULL;
+	}
+
+	/* We need to optimize PCIe3 TLP-size read-request and extended tag usage */
+	{
+		p->mp_reg_config = nthw_module_query_register(p->mp_mod_hif, HIF_CONFIG);
+
+		if (p->mp_reg_config) {
+			p->mp_fld_max_tlp =
+				nthw_register_get_field(p->mp_reg_config, HIF_CONFIG_MAX_TLP);
+			p->mp_fld_max_read =
+				nthw_register_get_field(p->mp_reg_config, HIF_CONFIG_MAX_READ);
+			p->mp_fld_ext_tag =
+				nthw_register_get_field(p->mp_reg_config, HIF_CONFIG_EXT_TAG);
+
+		} else {
+			p->mp_fld_max_tlp = NULL;
+			p->mp_fld_max_read = NULL;
+			p->mp_fld_ext_tag = NULL;
+		}
+	}
+
+	return 0;
+}
+
+int nthw_hif_trigger_sample_time(nthw_hif_t *p)
+{
+	nthw_field_set_val_flush32(p->mp_fld_sample_time, 0xfee1dead);
+
+	return 0;
+}
+
+int nthw_hif_get_stat(nthw_hif_t *p, uint32_t *p_rx_cnt, uint32_t *p_tx_cnt,
+	uint32_t *p_ref_clk_cnt, uint32_t *p_tg_unit_size, uint32_t *p_tg_ref_freq,
+	uint64_t *p_tags_in_use, uint64_t *p_rd_err, uint64_t *p_wr_err)
+{
+	*p_rx_cnt = nthw_field_get_updated(p->mp_fld_stat_rx_counter);
+	*p_tx_cnt = nthw_field_get_updated(p->mp_fld_stat_tx_counter);
+
+	*p_ref_clk_cnt = nthw_field_get_updated(p->mp_fld_stat_ref_clk_ref_clk);
+
+	*p_tg_unit_size = NTHW_TG_CNT_SIZE;
+	*p_tg_ref_freq = p->mn_fpga_hif_ref_clk_freq;
+
+	*p_tags_in_use = (p->mp_fld_status_tags_in_use
+			? nthw_field_get_updated(p->mp_fld_status_tags_in_use)
+			: 0);
+
+	*p_rd_err =
+		(p->mp_fld_status_rd_err ? nthw_field_get_updated(p->mp_fld_status_rd_err) : 0);
+	*p_wr_err =
+		(p->mp_fld_status_wr_err ? nthw_field_get_updated(p->mp_fld_status_wr_err) : 0);
+
+	return 0;
+}
+
+int nthw_hif_get_stat_rate(nthw_hif_t *p, uint64_t *p_pci_rx_rate, uint64_t *p_pci_tx_rate,
+	uint64_t *p_ref_clk_cnt, uint64_t *p_tags_in_use,
+	uint64_t *p_rd_err_cnt, uint64_t *p_wr_err_cnt)
+{
+	uint32_t rx_cnt, tx_cnt, ref_clk_cnt, tg_unit_size, tg_ref_freq;
+	uint64_t n_tags_in_use, n_rd_err, n_wr_err;
+
+	nthw_hif_get_stat(p, &rx_cnt, &tx_cnt, &ref_clk_cnt, &tg_unit_size, &tg_ref_freq,
+		&n_tags_in_use, &n_rd_err, &n_wr_err);
+
+	*p_tags_in_use = n_tags_in_use;
+
+	if (n_rd_err)
+		(*p_rd_err_cnt)++;
+
+	if (n_wr_err)
+		(*p_wr_err_cnt)++;
+
+	if (ref_clk_cnt) {
+		uint64_t rx_rate;
+		uint64_t tx_rate;
+
+		*p_ref_clk_cnt = ref_clk_cnt;
+
+		rx_rate = ((uint64_t)rx_cnt * tg_unit_size * tg_ref_freq) / (uint64_t)ref_clk_cnt;
+		*p_pci_rx_rate = rx_rate;
+
+		tx_rate = ((uint64_t)tx_cnt * tg_unit_size * tg_ref_freq) / (uint64_t)ref_clk_cnt;
+		*p_pci_tx_rate = tx_rate;
+
+	} else {
+		*p_pci_rx_rate = 0;
+		*p_pci_tx_rate = 0;
+		*p_ref_clk_cnt = 0;
+	}
+
+	return 0;
+}
+
+int nthw_hif_stat_req_enable(nthw_hif_t *p)
+{
+	nthw_field_set_all(p->mp_fld_stat_ctrl_ena);
+	nthw_field_set_all(p->mp_fld_stat_ctrl_req);
+	nthw_field_flush_register(p->mp_fld_stat_ctrl_req);
+	return 0;
+}
+
+int nthw_hif_stat_req_disable(nthw_hif_t *p)
+{
+	nthw_field_clr_all(p->mp_fld_stat_ctrl_ena);
+	nthw_field_set_all(p->mp_fld_stat_ctrl_req);
+	nthw_field_flush_register(p->mp_fld_stat_ctrl_req);
+	return 0;
+}
+
+int nthw_hif_end_point_counters_sample(nthw_hif_t *p, struct nthw_hif_end_point_counters *epc)
+{
+	assert(epc);
+
+	/* Get stat rate and maintain rx/tx min/max */
+	nthw_hif_get_stat_rate(p, &epc->cur_tx, &epc->cur_rx, &epc->n_ref_clk_cnt,
+		&epc->n_tags_in_use, &epc->n_rd_err, &epc->n_wr_err);
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_iic.c b/drivers/net/ntnic/nthw/core/nthw_iic.c
new file mode 100644
index 0000000000..7f324dec78
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_iic.c
@@ -0,0 +1,527 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "nt_util.h"
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_iic.h"
+
+#define I2C_TRANSMIT_WR (0x00)
+#define I2C_TRANSMIT_RD (0x01)
+
+#define I2C_WAIT_US(x) nt_os_wait_usec(x)
+
+/*
+ * Minimum timing values for I2C for a Marvel 88E11111 Phy.
+ * This Phy is used in many Trispeed NIMs.
+ * In order to access this Phy, the I2C clock speed is needed to be set to 100KHz.
+ */
+static const uint32_t SUSTA = 4700;	/* ns */
+static const uint32_t SUSTO = 4000;	/* ns */
+static const uint32_t HDSTA = 4000;	/* ns */
+static const uint32_t SUDAT = 250;	/* ns */
+static const uint32_t BUF = 4700;	/* ns */
+static const uint32_t HIGH = 4000;	/* ns */
+static const uint32_t LOW = 4700;	/* ns */
+static const uint32_t HDDAT = 300;	/* ns */
+
+static int nthw_iic_reg_control_txfifo_reset(nthw_iic_t *p)
+{
+	nthw_field_update_register(p->mp_fld_cr_txfifo_reset);
+
+	nthw_field_set_all(p->mp_fld_cr_txfifo_reset);
+	nthw_field_flush_register(p->mp_fld_cr_txfifo_reset);
+
+	nthw_field_clr_all(p->mp_fld_cr_txfifo_reset);
+	nthw_field_flush_register(p->mp_fld_cr_txfifo_reset);
+
+	return 0;
+}
+
+static int nthw_iic_reg_tx_fifo_write(nthw_iic_t *p, uint32_t data, bool start, bool stop)
+{
+	if (start)
+		nthw_field_set_all(p->mp_fld_tx_fifo_start);
+
+	else
+		nthw_field_clr_all(p->mp_fld_tx_fifo_start);
+
+	if (stop)
+		nthw_field_set_all(p->mp_fld_tx_fifo_stop);
+
+	else
+		nthw_field_clr_all(p->mp_fld_tx_fifo_stop);
+
+	nthw_field_set_val32(p->mp_fld_tx_fifo_txdata, data);
+
+	nthw_register_flush(p->mp_reg_tx_fifo, 1);
+
+	return 0;
+}
+
+static int nthw_iic_reg_read_i2c_rx_fifo(nthw_iic_t *p, uint8_t *p_data)
+{
+	assert(p_data);
+
+	*p_data = (uint8_t)nthw_field_get_updated(p->mp_fld_rx_fifo_rxdata);
+
+	return 0;
+}
+
+static int nthw_iic_reg_softr(nthw_iic_t *p)
+{
+	nthw_field_update_register(p->mp_fld_cr_en);
+	nthw_field_set_val_flush32(p->mp_fld_softr_rkey, 0x0A);
+
+	return 0;
+}
+
+static int nthw_iic_reg_enable(nthw_iic_t *p)
+{
+	nthw_field_update_register(p->mp_fld_cr_en);
+	nthw_field_set_flush(p->mp_fld_cr_en);
+
+	return 0;
+}
+
+static int nthw_iic_reg_busbusy(nthw_iic_t *p, bool *pb_flag)
+{
+	assert(pb_flag);
+
+	*pb_flag = nthw_field_get_updated(p->mp_fld_sr_bb) ? true : false;
+
+	return 0;
+}
+
+static int nthw_iic_reg_rxfifo_empty(nthw_iic_t *p, bool *pb_flag)
+{
+	assert(pb_flag);
+
+	*pb_flag = nthw_field_get_updated(p->mp_fld_sr_rxfifo_empty) ? true : false;
+
+	return 0;
+}
+
+/*
+ * n_iic_cycle_time is the I2C clock cycle time in ns ie 125MHz = 8ns
+ */
+static int nthw_iic_reg_set_timing(nthw_iic_t *p, uint32_t n_iic_cycle_time)
+{
+	uint32_t val;
+
+	val = SUSTA / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_tsusta, &val, 1);
+
+	val = SUSTO / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_tsusto, &val, 1);
+
+	val = HDSTA / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_thdsta, &val, 1);
+
+	val = SUDAT / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_tsudat, &val, 1);
+
+	val = BUF / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_tbuf, &val, 1);
+
+	val = HIGH / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_thigh, &val, 1);
+
+	val = LOW / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_tlow, &val, 1);
+
+	val = HDDAT / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_thddat, &val, 1);
+
+	return 0;
+}
+
+nthw_iic_t *nthw_iic_new(void)
+{
+	nthw_iic_t *p = malloc(sizeof(nthw_iic_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_iic_t));
+
+	return p;
+}
+
+int nthw_iic_init(nthw_iic_t *p, nthw_fpga_t *p_fpga, int n_iic_instance,
+	uint32_t n_iic_cycle_time)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *mod = nthw_fpga_query_module(p_fpga, MOD_IIC, n_iic_instance);
+
+	if (p == NULL)
+		return mod == NULL ? -1 : 0;
+
+	if (mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: I2C %d: no such instance\n", p_adapter_id_str,
+			n_iic_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_iic_instance = n_iic_instance;
+
+	p->mn_iic_cycle_time = n_iic_cycle_time;
+
+	nthw_iic_set_retry_params(p, -1, -1, -1, -1, -1);
+
+	p->mp_mod_iic = mod;
+
+	/* I2C is a primary communication channel - turn off debug by default */
+	nthw_module_set_debug_mode(p->mp_mod_iic, 0x00);
+
+	p->mp_reg_tsusta = nthw_module_get_register(p->mp_mod_iic, IIC_TSUSTA);
+	p->mp_fld_tsusta = nthw_register_get_field(p->mp_reg_tsusta, IIC_TSUSTA_TSUSTA_VAL);
+
+	p->mp_reg_tsusto = nthw_module_get_register(p->mp_mod_iic, IIC_TSUSTO);
+	p->mp_fld_tsusto = nthw_register_get_field(p->mp_reg_tsusto, IIC_TSUSTO_TSUSTO_VAL);
+
+	p->mp_reg_thdsta = nthw_module_get_register(p->mp_mod_iic, IIC_THDSTA);
+	p->mp_fld_thdsta = nthw_register_get_field(p->mp_reg_thdsta, IIC_THDSTA_THDSTA_VAL);
+
+	p->mp_reg_tsudat = nthw_module_get_register(p->mp_mod_iic, IIC_TSUDAT);
+	p->mp_fld_tsudat = nthw_register_get_field(p->mp_reg_tsudat, IIC_TSUDAT_TSUDAT_VAL);
+
+	p->mp_reg_tbuf = nthw_module_get_register(p->mp_mod_iic, IIC_TBUF);
+	p->mp_fld_tbuf = nthw_register_get_field(p->mp_reg_tbuf, IIC_TBUF_TBUF_VAL);
+
+	p->mp_reg_thigh = nthw_module_get_register(p->mp_mod_iic, IIC_THIGH);
+	p->mp_fld_thigh = nthw_register_get_field(p->mp_reg_thigh, IIC_THIGH_THIGH_VAL);
+
+	p->mp_reg_tlow = nthw_module_get_register(p->mp_mod_iic, IIC_TLOW);
+	p->mp_fld_tlow = nthw_register_get_field(p->mp_reg_tlow, IIC_TLOW_TLOW_VAL);
+
+	p->mp_reg_thddat = nthw_module_get_register(p->mp_mod_iic, IIC_THDDAT);
+	p->mp_fld_thddat = nthw_register_get_field(p->mp_reg_thddat, IIC_THDDAT_THDDAT_VAL);
+
+	p->mp_reg_cr = nthw_module_get_register(p->mp_mod_iic, IIC_CR);
+	p->mp_fld_cr_en = nthw_register_get_field(p->mp_reg_cr, IIC_CR_EN);
+	p->mp_fld_cr_msms = nthw_register_get_field(p->mp_reg_cr, IIC_CR_MSMS);
+	p->mp_fld_cr_txfifo_reset = nthw_register_get_field(p->mp_reg_cr, IIC_CR_TXFIFO_RESET);
+	p->mp_fld_cr_txak = nthw_register_get_field(p->mp_reg_cr, IIC_CR_TXAK);
+
+	p->mp_reg_sr = nthw_module_get_register(p->mp_mod_iic, IIC_SR);
+	p->mp_fld_sr_bb = nthw_register_get_field(p->mp_reg_sr, IIC_SR_BB);
+	p->mp_fld_sr_rxfifo_full = nthw_register_get_field(p->mp_reg_sr, IIC_SR_RXFIFO_FULL);
+	p->mp_fld_sr_rxfifo_empty = nthw_register_get_field(p->mp_reg_sr, IIC_SR_RXFIFO_EMPTY);
+	p->mp_fld_sr_txfifo_full = nthw_register_get_field(p->mp_reg_sr, IIC_SR_TXFIFO_FULL);
+	p->mp_fld_sr_txfifo_empty = nthw_register_get_field(p->mp_reg_sr, IIC_SR_TXFIFO_EMPTY);
+
+	p->mp_reg_tx_fifo = nthw_module_get_register(p->mp_mod_iic, IIC_TX_FIFO);
+	p->mp_fld_tx_fifo_txdata = nthw_register_get_field(p->mp_reg_tx_fifo, IIC_TX_FIFO_TXDATA);
+	p->mp_fld_tx_fifo_start = nthw_register_get_field(p->mp_reg_tx_fifo, IIC_TX_FIFO_START);
+	p->mp_fld_tx_fifo_stop = nthw_register_get_field(p->mp_reg_tx_fifo, IIC_TX_FIFO_STOP);
+
+	p->mp_reg_rx_fifo_pirq = nthw_module_get_register(p->mp_mod_iic, IIC_RX_FIFO_PIRQ);
+	p->mp_fld_rx_fifo_pirq_cmp_val =
+		nthw_register_get_field(p->mp_reg_rx_fifo_pirq, IIC_RX_FIFO_PIRQ_CMP_VAL);
+
+	p->mp_reg_rx_fifo = nthw_module_get_register(p->mp_mod_iic, IIC_RX_FIFO);
+	p->mp_fld_rx_fifo_rxdata = nthw_register_get_field(p->mp_reg_rx_fifo, IIC_RX_FIFO_RXDATA);
+
+	p->mp_reg_softr = nthw_module_get_register(p->mp_mod_iic, IIC_SOFTR);
+	p->mp_fld_softr_rkey = nthw_register_get_field(p->mp_reg_softr, IIC_SOFTR_RKEY);
+
+	/*
+	 * Initialize I2C controller by applying soft reset and enable the controller
+	 */
+	nthw_iic_reg_softr(p);
+	/* Enable the controller */
+	nthw_iic_reg_enable(p);
+
+	/* Setup controller timing */
+	if (p->mn_iic_cycle_time) {
+		NT_LOG(DBG, NTHW, "%s: I2C%d: cycletime=%d\n", p_adapter_id_str,
+			p->mn_iic_instance, p->mn_iic_cycle_time);
+		nthw_iic_reg_set_timing(p, p->mn_iic_cycle_time);
+	}
+
+	/* Reset TX fifo - must be after enable */
+	nthw_iic_reg_control_txfifo_reset(p);
+	nthw_iic_reg_tx_fifo_write(p, 0, 0, 0);
+
+	return 0;
+}
+
+void nthw_iic_delete(nthw_iic_t *p)
+{
+	if (p) {
+		memset(p, 0, sizeof(nthw_iic_t));
+		free(p);
+	}
+}
+
+int nthw_iic_set_retry_params(nthw_iic_t *p, const int n_poll_delay, const int n_bus_ready_retry,
+	const int n_data_ready_retry, const int n_read_data_retry,
+	const int n_write_data_retry)
+{
+	p->mn_poll_delay = n_poll_delay >= 0 ? n_poll_delay : 10;
+
+	p->mn_bus_ready_retry = n_bus_ready_retry >= 0 ? n_bus_ready_retry : 1000;
+	p->mn_data_ready_retry = n_data_ready_retry >= 0 ? n_data_ready_retry : 1000;
+
+	p->mn_read_data_retry = n_read_data_retry >= 0 ? n_read_data_retry : 10;
+	p->mn_write_data_retry = n_write_data_retry >= 0 ? n_write_data_retry : 10;
+
+	return 0;
+}
+
+int nthw_iic_read_data(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint8_t data_len,
+	void *p_void)
+{
+	const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str;
+	const int n_debug_mode = nthw_module_get_debug_mode(p->mp_mod_iic);
+
+	uint8_t *pb = (uint8_t *)p_void;
+	int retry = (p->mn_read_data_retry >= 0 ? p->mn_read_data_retry : 10);
+
+	if (n_debug_mode == 0xff) {
+		NT_LOG(DBG, NTHW, "%s: adr=0x%2.2x, reg=%d, len=%d\n", p_adapter_id_str, dev_addr,
+			a_reg_addr, data_len);
+	}
+
+	while (nthw_iic_readbyte(p, dev_addr, a_reg_addr, data_len, pb) != 0) {
+		retry--;
+
+		if (retry <= 0) {
+			NT_LOG(ERR, NTHW,
+				"%s: I2C%d: Read retry exhausted (dev_addr=%d a_reg_addr=%d)\n",
+				p_adapter_id_str, p->mn_iic_instance, dev_addr, a_reg_addr);
+			return -1;
+
+		} else {
+			NT_LOG(DBG, NTHW, "%s: I2C%d: Read retry=%d (dev_addr=%d a_reg_addr=%d)\n",
+				p_adapter_id_str, p->mn_iic_instance, retry, dev_addr, a_reg_addr);
+		}
+	}
+
+	if (n_debug_mode == 0xff) {
+		NT_LOG(DBG, NTHW, "%s: adr=0x%2.2x, reg=%d, len=%d, retries remaining: %d\n",
+			p_adapter_id_str, dev_addr, a_reg_addr, data_len, retry);
+	}
+
+	return 0;
+}
+
+int nthw_iic_readbyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint8_t data_len,
+	uint8_t *p_byte)
+{
+	const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str;
+
+	uint32_t value;
+	uint32_t i;
+
+	if (nthw_iic_bus_ready(p)) {
+		/* Reset TX fifo */
+		nthw_iic_reg_control_txfifo_reset(p);
+
+		/* Write device address to TX_FIFO and set start bit!! */
+		value = (dev_addr << 1) | I2C_TRANSMIT_WR;
+		nthw_iic_reg_tx_fifo_write(p, value, 1, 0);
+
+		/* Write a_reg_addr to TX FIFO */
+		nthw_iic_reg_tx_fifo_write(p, a_reg_addr, 0, 1);
+
+		if (!nthw_iic_bus_ready(p)) {
+			NT_LOG_DBGX(ERR, NTHW, "%s: error:\n", p_adapter_id_str);
+			return -1;
+		}
+
+		/* Write device address + RD bit to TX_FIFO and set start bit!! */
+		value = (dev_addr << 1) | I2C_TRANSMIT_RD;
+		nthw_iic_reg_tx_fifo_write(p, value, 1, 0);
+
+		/* Write data_len to TX_FIFO and set stop bit!! */
+		nthw_iic_reg_tx_fifo_write(p, data_len, 0, 1);
+
+		for (i = 0; i < data_len; i++) {
+			/* Wait for RX FIFO not empty */
+			if (!nthw_iic_data_ready(p))
+				return -1;
+
+			/* Read data_len bytes from RX_FIFO */
+			nthw_iic_reg_read_i2c_rx_fifo(p, p_byte);
+			p_byte++;
+		}
+
+		return 0;
+
+	} else {
+		NT_LOG_DBGX(ERR, NTHW, "%s: error\n", p_adapter_id_str);
+		return -1;
+	}
+
+	return 0;
+}
+
+int nthw_iic_write_data(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint8_t data_len,
+	void *p_void)
+{
+	const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str;
+	int retry = (p->mn_write_data_retry >= 0 ? p->mn_write_data_retry : 10);
+	uint8_t *pb = (uint8_t *)p_void;
+
+	while (nthw_iic_writebyte(p, dev_addr, a_reg_addr, data_len, pb) != 0) {
+		retry--;
+
+		if (retry <= 0) {
+			NT_LOG(ERR, NTHW,
+				"%s: I2C%d: Write retry exhausted (dev_addr=%d a_reg_addr=%d)\n",
+				p_adapter_id_str, p->mn_iic_instance, dev_addr, a_reg_addr);
+			return -1;
+
+		} else {
+			NT_LOG(DBG, NTHW,
+				"%s: I2C%d: Write retry=%d (dev_addr=%d a_reg_addr=%d)\n",
+				p_adapter_id_str, p->mn_iic_instance, retry, dev_addr, a_reg_addr);
+		}
+	}
+
+	return 0;
+}
+
+int nthw_iic_writebyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint8_t data_len,
+	uint8_t *p_byte)
+{
+	const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str;
+	uint32_t value;
+	int count;
+	int i;
+
+	if (data_len == 0)
+		return -1;
+
+	count = data_len - 1;
+
+	if (nthw_iic_bus_ready(p)) {
+		/* Reset TX fifo */
+		nthw_iic_reg_control_txfifo_reset(p);
+
+		/* Write device address to TX_FIFO and set start bit!! */
+		value = (dev_addr << 1) | I2C_TRANSMIT_WR;
+		nthw_iic_reg_tx_fifo_write(p, value, 1, 0);
+
+		/* Write a_reg_addr to TX FIFO */
+		nthw_iic_reg_tx_fifo_write(p, a_reg_addr, 0, 0);
+
+		for (i = 0; i < count; i++) {
+			/* Write data byte to TX fifo and set stop bit */
+			nthw_iic_reg_tx_fifo_write(p, *p_byte, 0, 0);
+			p_byte++;
+		}
+
+		/* Write data byte to TX fifo and set stop bit */
+		nthw_iic_reg_tx_fifo_write(p, *p_byte, 0, 1);
+
+		if (!nthw_iic_bus_ready(p)) {
+			NT_LOG_DBGX(WARNING, NTHW, "%s: warn: !busReady\n", p_adapter_id_str);
+
+			while (true)
+				if (nthw_iic_bus_ready(p)) {
+					NT_LOG_DBGX(DEBUG, NTHW, "%s: info: busReady\n",
+					p_adapter_id_str);
+					break;
+				}
+		}
+
+		return 0;
+
+	} else {
+		NT_LOG_DBGX(WARNING, NTHW, "%s\n", p_adapter_id_str);
+		return -1;
+	}
+}
+
+/*
+ * Support function for read/write functions below. Waits for bus ready.
+ */
+bool nthw_iic_bus_ready(nthw_iic_t *p)
+{
+	int count = (p->mn_bus_ready_retry >= 0 ? p->mn_bus_ready_retry : 1000);
+	bool b_bus_busy = true;
+
+	while (true) {
+		nthw_iic_reg_busbusy(p, &b_bus_busy);
+
+		if (!b_bus_busy)
+			break;
+
+		count--;
+
+		if (count <= 0)	/* Test for timeout */
+			break;
+
+		if (p->mn_poll_delay != 0)
+			I2C_WAIT_US(p->mn_poll_delay);
+	}
+
+	if (count == 0)
+		return false;
+
+	return true;
+}
+
+/*
+ * Support function for read function. Waits for data ready.
+ */
+bool nthw_iic_data_ready(nthw_iic_t *p)
+{
+	int count = (p->mn_data_ready_retry >= 0 ? p->mn_data_ready_retry : 1000);
+	bool b_rx_fifo_empty = true;
+
+	while (true) {
+		nthw_iic_reg_rxfifo_empty(p, &b_rx_fifo_empty);
+
+		if (!b_rx_fifo_empty)
+			break;
+
+		count--;
+
+		if (count <= 0)	/* Test for timeout */
+			break;
+
+		if (p->mn_poll_delay != 0)
+			I2C_WAIT_US(p->mn_poll_delay);
+	}
+
+	if (count == 0)
+		return false;
+
+	return true;
+}
+
+int nthw_iic_scan_dev_addr(nthw_iic_t *p, int n_dev_addr, int n_reg_addr)
+{
+	const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str;
+	(void)p_adapter_id_str;
+	int res;
+	uint8_t data_val = -1;
+	res = nthw_iic_readbyte(p, (uint8_t)n_dev_addr, (uint8_t)n_reg_addr, 1, &data_val);
+
+	if (res == 0) {
+		NT_LOG(DBG, NTHW,
+			"%s: I2C%d: devaddr=0x%02X (%03d) regaddr=%02X val=%02X (%03d) res=%d\n",
+			p_adapter_id_str, p->mn_iic_instance, n_dev_addr, n_dev_addr, n_reg_addr,
+			data_val, data_val, res);
+	}
+
+	return res;
+}
+
+int nthw_iic_scan(nthw_iic_t *p)
+{
+	int i;
+
+	for (i = 0; i < 128; i++)
+		(void)nthw_iic_scan_dev_addr(p, i, 0x00);
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_pcie3.c b/drivers/net/ntnic/nthw/core/nthw_pcie3.c
new file mode 100644
index 0000000000..c6cb3ce8de
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_pcie3.c
@@ -0,0 +1,259 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_pcie3.h"
+
+#define NTHW_TG_REF_FREQ (250000000ULL)
+
+nthw_pcie3_t *nthw_pcie3_new(void)
+{
+	nthw_pcie3_t *p = malloc(sizeof(nthw_pcie3_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_pcie3_t));
+
+	return p;
+}
+
+void nthw_pcie3_delete(nthw_pcie3_t *p)
+{
+	if (p) {
+		memset(p, 0, sizeof(nthw_pcie3_t));
+		free(p);
+	}
+}
+
+int nthw_pcie3_init(nthw_pcie3_t *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	nthw_module_t *mod = nthw_fpga_query_module(p_fpga, MOD_PCIE3, n_instance);
+
+	if (p == NULL)
+		return mod == NULL ? -1 : 0;
+
+	if (mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: PCIE3 %d: no such instance\n",
+			p_fpga->p_fpga_info->mp_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_instance = n_instance;
+	p->mp_mod_pcie3 = mod;
+
+	/* PCIe3 */
+	p->mp_reg_stat_ctrl = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_CTRL);
+	p->mp_fld_stat_ctrl_ena =
+		nthw_register_get_field(p->mp_reg_stat_ctrl, PCIE3_STAT_CTRL_STAT_ENA);
+	p->mp_fld_stat_ctrl_req =
+		nthw_register_get_field(p->mp_reg_stat_ctrl, PCIE3_STAT_CTRL_STAT_REQ);
+
+	p->mp_reg_stat_rx = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_RX);
+	p->mp_fld_stat_rx_counter =
+		nthw_register_get_field(p->mp_reg_stat_rx, PCIE3_STAT_RX_COUNTER);
+
+	p->mp_reg_stat_tx = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_TX);
+	p->mp_fld_stat_tx_counter =
+		nthw_register_get_field(p->mp_reg_stat_tx, PCIE3_STAT_TX_COUNTER);
+
+	p->mp_reg_stat_ref_clk = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_REFCLK);
+	p->mp_fld_stat_ref_clk_ref_clk =
+		nthw_register_get_field(p->mp_reg_stat_ref_clk, PCIE3_STAT_REFCLK_REFCLK250);
+
+	p->mp_reg_stat_rq_rdy = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_RQ_RDY);
+	p->mp_fld_stat_rq_rdy_counter =
+		nthw_register_get_field(p->mp_reg_stat_rq_rdy, PCIE3_STAT_RQ_RDY_COUNTER);
+
+	p->mp_reg_stat_rq_vld = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_RQ_VLD);
+	p->mp_fld_stat_rq_vld_counter =
+		nthw_register_get_field(p->mp_reg_stat_rq_vld, PCIE3_STAT_RQ_VLD_COUNTER);
+
+	p->mp_reg_status0 = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STATUS0);
+	p->mp_fld_status0_tags_in_use =
+		nthw_register_get_field(p->mp_reg_status0, PCIE3_STATUS0_TAGS_IN_USE);
+
+	p->mp_reg_rp_to_ep_err = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_RP_TO_EP_ERR);
+	p->mp_fld_rp_to_ep_err_cor =
+		nthw_register_get_field(p->mp_reg_rp_to_ep_err, PCIE3_RP_TO_EP_ERR_ERR_COR);
+	p->mp_fld_rp_to_ep_err_non_fatal =
+		nthw_register_get_field(p->mp_reg_rp_to_ep_err, PCIE3_RP_TO_EP_ERR_ERR_NONFATAL);
+	p->mp_fld_rp_to_ep_err_fatal =
+		nthw_register_get_field(p->mp_reg_rp_to_ep_err, PCIE3_RP_TO_EP_ERR_ERR_FATAL);
+
+	p->mp_reg_ep_to_rp_err = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_EP_TO_RP_ERR);
+	p->mp_fld_ep_to_rp_err_cor =
+		nthw_register_get_field(p->mp_reg_ep_to_rp_err, PCIE3_EP_TO_RP_ERR_ERR_COR);
+	p->mp_fld_ep_to_rp_err_non_fatal =
+		nthw_register_get_field(p->mp_reg_ep_to_rp_err, PCIE3_EP_TO_RP_ERR_ERR_NONFATAL);
+	p->mp_fld_ep_to_rp_err_fatal =
+		nthw_register_get_field(p->mp_reg_ep_to_rp_err, PCIE3_EP_TO_RP_ERR_ERR_FATAL);
+
+	p->mp_reg_sample_time = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_SAMPLE_TIME);
+	p->mp_fld_sample_time =
+		nthw_register_get_field(p->mp_reg_sample_time, PCIE3_SAMPLE_TIME_SAMPLE_TIME);
+
+	p->mp_reg_pci_end_point = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_PCI_ENDPOINT);
+	p->mp_fld_pci_end_point_if_id =
+		nthw_register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_IF_ID);
+	p->mp_fld_pci_end_point_send_msg =
+		nthw_register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_SEND_MSG);
+	p->mp_fld_pci_end_point_get_msg =
+		nthw_register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_GET_MSG);
+	p->mp_fld_pci_end_point_dmaep0_allow_mask =
+		nthw_register_get_field(p->mp_reg_pci_end_point,
+			PCIE3_PCI_ENDPOINT_DMA_EP0_ALLOW_MASK);
+	p->mp_fld_pci_end_point_dmaep1_allow_mask =
+		nthw_register_get_field(p->mp_reg_pci_end_point,
+			PCIE3_PCI_ENDPOINT_DMA_EP1_ALLOW_MASK);
+
+	if (p->mp_reg_pci_end_point)
+		nthw_register_update(p->mp_reg_pci_end_point);
+
+	p->mp_reg_pci_test0 = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_PCI_TEST0);
+	p->mp_fld_pci_test0 = nthw_register_get_field(p->mp_reg_pci_test0, PCIE3_PCI_TEST0_DATA);
+
+	if (p->mp_reg_pci_test0)
+		nthw_register_update(p->mp_reg_pci_test0);
+
+	p->mp_reg_pci_test1 = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_PCI_TEST1);
+	p->mp_fld_pci_test1 = nthw_register_get_field(p->mp_reg_pci_test1, PCIE3_PCI_TEST1_DATA);
+
+	if (p->mp_reg_pci_test1)
+		nthw_register_update(p->mp_reg_pci_test1);
+
+	p->mp_reg_pci_e3_mark_adr_lsb =
+		nthw_module_get_register(p->mp_mod_pcie3, PCIE3_MARKADR_LSB);
+	p->mp_fld_pci_e3_mark_adr_lsb_adr =
+		nthw_register_get_field(p->mp_reg_pci_e3_mark_adr_lsb, PCIE3_MARKADR_LSB_ADR);
+
+	if (p->mp_reg_pci_e3_mark_adr_lsb)
+		nthw_register_update(p->mp_reg_pci_e3_mark_adr_lsb);
+
+	p->mp_reg_pci_e3_mark_adr_msb =
+		nthw_module_get_register(p->mp_mod_pcie3, PCIE3_MARKADR_MSB);
+	p->mp_fld_pci_e3_mark_adr_msb_adr =
+		nthw_register_get_field(p->mp_reg_pci_e3_mark_adr_msb, PCIE3_MARKADR_MSB_ADR);
+
+	if (p->mp_reg_pci_e3_mark_adr_msb)
+		nthw_register_update(p->mp_reg_pci_e3_mark_adr_msb);
+
+	/* Initial setup - disable markerscheme and bifurcation */
+	if (p->mp_fld_pci_end_point_dmaep0_allow_mask)
+		nthw_field_clr_flush(p->mp_fld_pci_end_point_dmaep0_allow_mask);
+
+	if (p->mp_fld_pci_end_point_dmaep1_allow_mask)
+		nthw_field_clr_flush(p->mp_fld_pci_end_point_dmaep1_allow_mask);
+
+	if (p->mp_fld_pci_e3_mark_adr_lsb_adr)
+		nthw_field_set_val_flush32(p->mp_fld_pci_e3_mark_adr_lsb_adr, 0UL);
+
+	if (p->mp_fld_pci_e3_mark_adr_msb_adr)
+		nthw_field_set_val_flush32(p->mp_fld_pci_e3_mark_adr_msb_adr, 0UL);
+
+	if (p->mp_fld_pci_end_point_dmaep0_allow_mask)
+		nthw_field_set_flush(p->mp_fld_pci_end_point_dmaep0_allow_mask);
+
+	if (p->mp_fld_pci_end_point_dmaep1_allow_mask)
+		nthw_field_clr_flush(p->mp_fld_pci_end_point_dmaep1_allow_mask);
+
+	return 0;
+};
+
+int nthw_pcie3_trigger_sample_time(nthw_pcie3_t *p)
+{
+	nthw_field_set_val_flush32(p->mp_fld_sample_time, 0xfee1dead);
+
+	return 0;
+}
+
+int nthw_pcie3_stat_req_enable(nthw_pcie3_t *p)
+{
+	nthw_field_set_all(p->mp_fld_stat_ctrl_ena);
+	nthw_field_set_all(p->mp_fld_stat_ctrl_req);
+	nthw_field_flush_register(p->mp_fld_stat_ctrl_req);
+	return 0;
+}
+
+int nthw_pcie3_stat_req_disable(nthw_pcie3_t *p)
+{
+	nthw_field_clr_all(p->mp_fld_stat_ctrl_ena);
+	nthw_field_set_all(p->mp_fld_stat_ctrl_req);
+	nthw_field_flush_register(p->mp_fld_stat_ctrl_req);
+	return 0;
+}
+
+int nthw_pcie3_get_stat(nthw_pcie3_t *p, uint32_t *p_rx_cnt, uint32_t *p_tx_cnt,
+	uint32_t *p_ref_clk_cnt, uint32_t *p_tg_unit_size, uint32_t *p_tg_ref_freq,
+	uint32_t *p_tag_use_cnt, uint32_t *p_rq_rdy_cnt, uint32_t *p_rq_vld_cnt)
+{
+	*p_rx_cnt = nthw_field_get_updated(p->mp_fld_stat_rx_counter);
+	*p_tx_cnt = nthw_field_get_updated(p->mp_fld_stat_tx_counter);
+
+	*p_ref_clk_cnt = nthw_field_get_updated(p->mp_fld_stat_ref_clk_ref_clk);
+
+	*p_tg_unit_size = NTHW_TG_CNT_SIZE;
+	*p_tg_ref_freq = NTHW_TG_REF_FREQ;
+
+	*p_tag_use_cnt = nthw_field_get_updated(p->mp_fld_status0_tags_in_use);
+
+	*p_rq_rdy_cnt = nthw_field_get_updated(p->mp_fld_stat_rq_rdy_counter);
+	*p_rq_vld_cnt = nthw_field_get_updated(p->mp_fld_stat_rq_vld_counter);
+
+	return 0;
+}
+
+int nthw_pcie3_get_stat_rate(nthw_pcie3_t *p, uint64_t *p_pci_rx_rate, uint64_t *p_pci_tx_rate,
+	uint64_t *p_ref_clk_cnt, uint64_t *p_tag_use_cnt,
+	uint64_t *p_pci_nt_bus_util, uint64_t *p_pci_xil_bus_util)
+{
+	uint32_t rx_cnt, tx_cnt, ref_clk_cnt;
+	uint32_t tg_unit_size, tg_ref_freq;
+	uint32_t tag_use_cnt, rq_rdy_cnt, rq_vld_cnt;
+
+	nthw_pcie3_get_stat(p, &rx_cnt, &tx_cnt, &ref_clk_cnt, &tg_unit_size, &tg_ref_freq,
+		&tag_use_cnt, &rq_rdy_cnt, &rq_vld_cnt);
+
+	if (ref_clk_cnt) {
+		uint64_t nt_bus_util, xil_bus_util;
+		uint64_t rx_rate, tx_rate;
+
+		rx_rate = ((uint64_t)rx_cnt * tg_unit_size * tg_ref_freq) / (uint64_t)ref_clk_cnt;
+		*p_pci_rx_rate = rx_rate;
+
+		tx_rate = ((uint64_t)tx_cnt * tg_unit_size * tg_ref_freq) / (uint64_t)ref_clk_cnt;
+		*p_pci_tx_rate = tx_rate;
+
+		*p_ref_clk_cnt = ref_clk_cnt;
+
+		*p_tag_use_cnt = tag_use_cnt;
+
+		nt_bus_util = ((uint64_t)rq_vld_cnt * 1000000ULL) / (uint64_t)ref_clk_cnt;
+		*p_pci_nt_bus_util = nt_bus_util;
+		xil_bus_util = ((uint64_t)rq_rdy_cnt * 1000000ULL) / (uint64_t)ref_clk_cnt;
+		*p_pci_xil_bus_util = xil_bus_util;
+
+	} else {
+		*p_ref_clk_cnt = 0;
+		*p_pci_nt_bus_util = 0;
+		*p_pci_xil_bus_util = 0;
+	}
+
+	return 0;
+}
+
+int nthw_pcie3_end_point_counters_sample_post(nthw_pcie3_t *p,
+	struct nthw_hif_end_point_counters *epc)
+{
+	NT_LOG_DBGX(DEBUG, NTHW);
+	assert(epc);
+	nthw_pcie3_get_stat_rate(p, &epc->cur_tx, &epc->cur_rx, &epc->n_ref_clk_cnt,
+		&epc->n_tags_in_use, &epc->cur_pci_nt_util,
+		&epc->cur_pci_xil_util);
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/nthw_drv.h b/drivers/net/ntnic/nthw/nthw_drv.h
index 0b89a5c5a0..d7cd64bb1d 100644
--- a/drivers/net/ntnic/nthw/nthw_drv.h
+++ b/drivers/net/ntnic/nthw/nthw_drv.h
@@ -6,8 +6,7 @@
 #ifndef __NTHW_DRV_H__
 #define __NTHW_DRV_H__
 
-#include <stddef.h>
-#include "nthw_platform_drv.h"
+#include "nthw_core.h"
 
 typedef enum nt_meta_port_type_e {
 	PORT_TYPE_PHYSICAL,
diff --git a/drivers/net/ntnic/nthw/nthw_rac.c b/drivers/net/ntnic/nthw/nthw_rac.c
new file mode 100644
index 0000000000..d202f4ea1c
--- /dev/null
+++ b/drivers/net/ntnic/nthw/nthw_rac.c
@@ -0,0 +1,785 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "nt_util.h"
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+#include "nthw_rac.h"
+
+#include <pthread.h>
+
+
+#define RAB_READ (0x01)
+#define RAB_WRITE (0x02)
+#define RAB_ECHO (0x08)
+#define RAB_COMPLETION (0x0F)
+
+#define RAB_OPR_LO (28)
+
+#define RAB_CNT_LO (20)
+#define RAB_CNT_BW (8)
+
+#define RAB_BUSID_LO (16)
+#define RAB_BUSID_BW (4)
+
+#define RAB_ADDR_BW (16)
+
+nthw_rac_t *nthw_rac_new(void)
+{
+	nthw_rac_t *p = malloc(sizeof(nthw_rac_t));
+	memset(p, 0, sizeof(nthw_rac_t));
+	return p;
+}
+
+int nthw_rac_init(nthw_rac_t *p, nthw_fpga_t *p_fpga, struct fpga_info_s *p_fpga_info)
+{
+	assert(p_fpga_info);
+
+	const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_RAC, 0);
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: RAC %d: no such instance\n", p_adapter_id_str, 0);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mp_mod_rac = p_mod;
+
+	/* Params */
+	p->mn_param_rac_rab_interfaces =
+		nthw_fpga_get_product_param(p->mp_fpga, NT_RAC_RAB_INTERFACES, 3);
+	NT_LOG(DBG, NTHW, "%s: NT_RAC_RAB_INTERFACES=%d\n", p_adapter_id_str,
+		p->mn_param_rac_rab_interfaces);
+
+	p->mn_param_rac_rab_ob_update =
+		nthw_fpga_get_product_param(p->mp_fpga, NT_RAC_RAB_OB_UPDATE, 0);
+	NT_LOG(DBG, NTHW, "%s: NT_RAC_RAB_OB_UPDATE=%d\n", p_adapter_id_str,
+		p->mn_param_rac_rab_ob_update);
+
+	/* Optional dummy test registers */
+	p->mp_reg_dummy0 = nthw_module_query_register(p->mp_mod_rac, RAC_DUMMY0);
+	p->mp_reg_dummy1 = nthw_module_query_register(p->mp_mod_rac, RAC_DUMMY1);
+	p->mp_reg_dummy2 = nthw_module_query_register(p->mp_mod_rac, RAC_DUMMY2);
+
+	p->mp_reg_rab_init = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_INIT);
+	p->mp_fld_rab_init = nthw_register_get_field(p->mp_reg_rab_init, RAC_RAB_INIT_RAB);
+	p->mn_fld_rab_init_bw = nthw_field_get_bit_width(p->mp_fld_rab_init);
+	p->mn_fld_rab_init_mask = nthw_field_get_mask(p->mp_fld_rab_init);
+
+	/* RAC_RAB_INIT_RAB reg/field sanity checks: */
+	assert(p->mn_fld_rab_init_mask == ((1UL << p->mn_fld_rab_init_bw) - 1));
+	assert(p->mn_fld_rab_init_bw == p->mn_param_rac_rab_interfaces);
+
+	p->mp_reg_dbg_ctrl = nthw_module_query_register(p->mp_mod_rac, RAC_DBG_CTRL);
+
+	if (p->mp_reg_dbg_ctrl)
+		p->mp_fld_dbg_ctrl = nthw_register_query_field(p->mp_reg_dbg_ctrl, RAC_DBG_CTRL_C);
+
+	else
+		p->mp_fld_dbg_ctrl = NULL;
+
+	p->mp_reg_dbg_data = nthw_module_query_register(p->mp_mod_rac, RAC_DBG_DATA);
+
+	if (p->mp_reg_dbg_data)
+		p->mp_fld_dbg_data = nthw_register_query_field(p->mp_reg_dbg_data, RAC_DBG_DATA_D);
+
+	else
+		p->mp_reg_dbg_data = NULL;
+
+	p->mp_reg_rab_ib_data = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_IB_DATA);
+	p->mp_fld_rab_ib_data = nthw_register_get_field(p->mp_reg_rab_ib_data, RAC_RAB_IB_DATA_D);
+
+	p->mp_reg_rab_ob_data = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_OB_DATA);
+	p->mp_fld_rab_ob_data = nthw_register_get_field(p->mp_reg_rab_ob_data, RAC_RAB_OB_DATA_D);
+
+	p->mp_reg_rab_buf_free = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_BUF_FREE);
+	p->mp_fld_rab_buf_free_ib_free =
+		nthw_register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_IB_FREE);
+	p->mp_fld_rab_buf_free_ib_ovf =
+		nthw_register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_IB_OVF);
+	p->mp_fld_rab_buf_free_ob_free =
+		nthw_register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_OB_FREE);
+	p->mp_fld_rab_buf_free_ob_ovf =
+		nthw_register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_OB_OVF);
+	p->mp_fld_rab_buf_free_timeout =
+		nthw_register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_TIMEOUT);
+
+	p->mp_reg_rab_buf_used = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_BUF_USED);
+	p->mp_fld_rab_buf_used_ib_used =
+		nthw_register_get_field(p->mp_reg_rab_buf_used, RAC_RAB_BUF_USED_IB_USED);
+	p->mp_fld_rab_buf_used_ob_used =
+		nthw_register_get_field(p->mp_reg_rab_buf_used, RAC_RAB_BUF_USED_OB_USED);
+	p->mp_fld_rab_buf_used_flush =
+		nthw_register_get_field(p->mp_reg_rab_buf_used, RAC_RAB_BUF_USED_FLUSH);
+
+	/*
+	 * RAC_RAB_DMA regs are optional - only found in real
+	 * NT4GA - not found in 9231/9232 and earlier
+	 */
+	p->mp_reg_rab_dma_ib_lo = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_IB_LO);
+	p->mp_fld_rab_dma_ib_lo_phy_addr =
+		nthw_register_get_field(p->mp_reg_rab_dma_ib_lo, RAC_RAB_DMA_IB_LO_PHYADDR);
+
+	p->mp_reg_rab_dma_ib_hi = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_IB_HI);
+	p->mp_fld_rab_dma_ib_hi_phy_addr =
+		nthw_register_get_field(p->mp_reg_rab_dma_ib_hi, RAC_RAB_DMA_IB_HI_PHYADDR);
+
+	p->mp_reg_rab_dma_ob_lo = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_OB_LO);
+	p->mp_fld_rab_dma_ob_lo_phy_addr =
+		nthw_register_get_field(p->mp_reg_rab_dma_ob_lo, RAC_RAB_DMA_OB_LO_PHYADDR);
+
+	p->mp_reg_rab_dma_ob_hi = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_OB_HI);
+	p->mp_fld_rab_dma_ob_hi_phy_addr =
+		nthw_register_get_field(p->mp_reg_rab_dma_ob_hi, RAC_RAB_DMA_OB_HI_PHYADDR);
+
+	p->mp_reg_rab_dma_ib_wr = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_IB_WR);
+	p->mp_fld_rab_dma_ib_wr_ptr =
+		nthw_register_get_field(p->mp_reg_rab_dma_ib_wr, RAC_RAB_DMA_IB_WR_PTR);
+
+	p->mp_reg_rab_dma_ib_rd = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_IB_RD);
+	p->mp_fld_rab_dma_ib_rd_ptr =
+		nthw_register_get_field(p->mp_reg_rab_dma_ib_rd, RAC_RAB_DMA_IB_RD_PTR);
+
+	p->mp_reg_rab_dma_ob_wr = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_OB_WR);
+	p->mp_fld_rab_dma_ob_wr_ptr =
+		nthw_register_get_field(p->mp_reg_rab_dma_ob_wr, RAC_RAB_DMA_OB_WR_PTR);
+
+	p->RAC_RAB_INIT_ADDR = nthw_register_get_address(p->mp_reg_rab_init);
+	p->RAC_RAB_IB_DATA_ADDR = nthw_register_get_address(p->mp_reg_rab_ib_data);
+	p->RAC_RAB_OB_DATA_ADDR = nthw_register_get_address(p->mp_reg_rab_ob_data);
+	p->RAC_RAB_BUF_FREE_ADDR = nthw_register_get_address(p->mp_reg_rab_buf_free);
+	p->RAC_RAB_BUF_USED_ADDR = nthw_register_get_address(p->mp_reg_rab_buf_used);
+
+	/*
+	 * RAC_RAB_DMA regs are optional - only found in real NT4GA - not found in 9231/9232 and
+	 * earlier
+	 */
+
+	p->RAC_RAB_DMA_IB_LO_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ib_lo);
+	p->RAC_RAB_DMA_IB_HI_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ib_hi);
+	p->RAC_RAB_DMA_OB_LO_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ob_lo);
+	p->RAC_RAB_DMA_OB_HI_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ob_hi);
+	p->RAC_RAB_DMA_IB_RD_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ib_rd);
+	p->RAC_RAB_DMA_OB_WR_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ob_wr);
+	p->RAC_RAB_DMA_IB_WR_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ib_wr);
+
+	p->RAC_RAB_BUF_FREE_IB_FREE_MASK = nthw_field_get_mask(p->mp_fld_rab_buf_free_ib_free);
+	p->RAC_RAB_BUF_FREE_OB_FREE_MASK = nthw_field_get_mask(p->mp_fld_rab_buf_free_ob_free);
+	p->RAC_RAB_BUF_USED_IB_USED_MASK = nthw_field_get_mask(p->mp_fld_rab_buf_used_ib_used);
+	p->RAC_RAB_BUF_USED_OB_USED_MASK = nthw_field_get_mask(p->mp_fld_rab_buf_used_ob_used);
+
+	p->RAC_RAB_BUF_USED_FLUSH_MASK = nthw_field_get_mask(p->mp_fld_rab_buf_used_flush);
+
+	p->RAC_RAB_BUF_USED_OB_USED_LOW =
+		nthw_field_get_bit_pos_low(p->mp_fld_rab_buf_used_ob_used);
+
+	p->mp_reg_rab_nmb_rd = nthw_module_query_register(p->mp_mod_rac, RAC_NMB_RD_ADR);
+
+	if (p->mp_reg_rab_nmb_rd)
+		p->RAC_NMB_RD_ADR_ADDR = nthw_register_get_address(p->mp_reg_rab_nmb_rd);
+
+	p->mp_reg_rab_nmb_data = nthw_module_query_register(p->mp_mod_rac, RAC_NMB_DATA);
+
+	if (p->mp_reg_rab_nmb_data)
+		p->RAC_NMB_DATA_ADDR = nthw_register_get_address(p->mp_reg_rab_nmb_data);
+
+	p->mp_reg_rab_nmb_wr = nthw_module_query_register(p->mp_mod_rac, RAC_NMB_WR_ADR);
+
+	if (p->mp_reg_rab_nmb_wr)
+		p->RAC_NMB_WR_ADR_ADDR = nthw_register_get_address(p->mp_reg_rab_nmb_wr);
+
+	p->mp_reg_rab_nmb_status = nthw_module_query_register(p->mp_mod_rac, RAC_NMB_STATUS);
+
+	if (p->mp_reg_rab_nmb_status)
+		p->RAC_NMB_STATUS_ADDR = nthw_register_get_address(p->mp_reg_rab_nmb_status);
+
+	p->m_dma = NULL;
+
+	{
+		/*
+		 * RAC is a primary communication channel - debug will be messy
+		 * turn off debug by default - except for rac_rab_init
+		 * NOTE: currently debug will not work - due to optimizations
+		 */
+		const int n_debug_mode = nthw_module_get_debug_mode(p->mp_mod_rac);
+
+		if (n_debug_mode && n_debug_mode <= 0xff) {
+			nthw_module_set_debug_mode(p->mp_mod_rac, 0);
+			nthw_register_set_debug_mode(p->mp_reg_rab_init, n_debug_mode);
+		}
+	}
+
+	pthread_mutex_init(&p->m_mutex, NULL);
+
+	return 0;
+}
+
+static int nthw_rac_get_rab_interface_count(const nthw_rac_t *p)
+{
+	return p->mn_param_rac_rab_interfaces;
+}
+
+/* private function for internal RAC operations -
+ * improves log flexibility and prevents log flooding
+ */
+static void nthw_rac_reg_read32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr,
+	uint32_t *p_data)
+{
+	*p_data = *(volatile uint32_t *)((uint8_t *)p_fpga_info->bar0_addr + reg_addr);
+}
+
+/* private function for internal RAC operations -
+ * improves log flexibility and prevents log flooding
+ */
+static void nthw_rac_reg_write32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr,
+	uint32_t n_data)
+{
+	*(volatile uint32_t *)((uint8_t *)p_fpga_info->bar0_addr + reg_addr) = n_data;
+}
+
+static inline int _nthw_rac_wait_for_rab_done(const nthw_rac_t *p, uint32_t address,
+	uint32_t word_cnt)
+{
+	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;
+	uint32_t used = 0;
+	uint32_t retry;
+
+	for (retry = 0; retry < 100000; retry++) {
+		nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_BUF_USED_ADDR, &used);
+		used = (used & p->RAC_RAB_BUF_USED_OB_USED_MASK) >>
+			p->RAC_RAB_BUF_USED_OB_USED_LOW;
+
+		if (used >= word_cnt)
+			break;
+	}
+
+	if (used < word_cnt) {
+		NT_LOG(ERR, NTHW, "%s: Fail rab bus r/w addr=0x%08X used=%x wordcount=%d\n",
+			p_adapter_id_str, address, used, word_cnt);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * NT_PCI_REG_P9xyz_RAC_RAB_INIT
+ *
+ * Initializes (resets) the programmable registers on the Register Access Buses (RAB).
+ * This initialization must be performed by software as part of the driver load procedure.
+ *
+ * Bit n of this field initializes the programmable registers on RAB interface n.
+ * Software must write one to the bit and then clear the bit again.
+ *
+ * All RAB module registers will be reset to their defaults.
+ * This includes the product specific RESET module (eg RST9xyz)
+ * As a consequence of this behavior the official reset sequence
+ * must be excersised - as all RAB modules will be held in reset.
+ */
+int nthw_rac_rab_init(nthw_rac_t *p, uint32_t n_rab_intf_mask)
+{
+	/*
+	 * Write rac_rab_init
+	 * Perform operation twice - first to get trace of operation -
+	 * second to get things done...
+	 */
+	const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info;
+	nthw_field_set_val_flush32(p->mp_fld_rab_init, n_rab_intf_mask);
+	nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_INIT_ADDR, n_rab_intf_mask);
+	return 0;
+}
+
+int nthw_rac_rab_reset(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;
+	(void)p_adapter_id_str;
+
+	/* RAC RAB bus "flip/flip" reset */
+	const int n_rac_rab_bus_count = nthw_rac_get_rab_interface_count(p);
+	const int n_rac_rab_bus_mask = (1 << n_rac_rab_bus_count) - 1;
+
+	NT_LOG(DBG, NTHW, "%s: NT_RAC_RAB_INTERFACES=%d (0x%02X)\n", p_adapter_id_str,
+		n_rac_rab_bus_count, n_rac_rab_bus_mask);
+	assert(n_rac_rab_bus_count);
+	assert(n_rac_rab_bus_mask);
+
+	/* RAC RAB bus "flip/flip" reset first stage - new impl (ref RMT#37020) */
+	nthw_rac_rab_init(p, 0);
+	nthw_rac_rab_init(p, n_rac_rab_bus_mask);
+	nthw_rac_rab_init(p, n_rac_rab_bus_mask & ~0x01);
+
+	return 0;
+}
+
+int nthw_rac_rab_setup(nthw_rac_t *p)
+{
+	int rc = 0;
+
+	const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info;
+	uint32_t n_dma_buf_size = 2L * RAB_DMA_BUF_CNT * sizeof(uint32_t);
+	const size_t align_size = nt_util_align_size(n_dma_buf_size);
+	int numa_node = p_fpga_info->numa_node;
+	uint64_t dma_addr;
+	uint32_t buf;
+
+	if (!p->m_dma) {
+		struct nt_dma_s *vfio_dma;
+		/* FPGA needs Page alignment (4K) */
+		vfio_dma = nt_dma_alloc(align_size, 0x1000, numa_node);
+
+		if (vfio_dma == NULL) {
+			NT_LOG(ERR, NTNIC, "nt_dma_alloc failed\n");
+			return -1;
+		}
+
+		p->m_dma_in_buf = (uint32_t *)vfio_dma->addr;
+		p->m_dma_out_buf = p->m_dma_in_buf + RAB_DMA_BUF_CNT;
+		p->m_dma = vfio_dma;
+	}
+
+	/* Setup DMA on the adapter */
+	dma_addr = p->m_dma->iova;
+	nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_DMA_IB_LO_ADDR, dma_addr & 0xffffffff);
+	nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_DMA_IB_HI_ADDR,
+		(uint32_t)(dma_addr >> 32) & 0xffffffff);
+	dma_addr += RAB_DMA_BUF_CNT * sizeof(uint32_t);
+	nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_DMA_OB_LO_ADDR, dma_addr & 0xffffffff);
+	nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_DMA_OB_HI_ADDR,
+		(uint32_t)(dma_addr >> 32) & 0xffffffff);
+
+	/* Set initial value of internal pointers */
+	nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_DMA_IB_RD_ADDR, &buf);
+	p->m_dma_in_ptr_wr = (uint16_t)(buf / sizeof(uint32_t));
+	nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_DMA_OB_WR_ADDR, &buf);
+	p->m_dma_out_ptr_rd = (uint16_t)(buf / sizeof(uint32_t));
+	p->m_in_free = RAB_DMA_BUF_CNT;
+
+	return rc;
+}
+
+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)
+{
+	volatile const uint32_t *const src_addr =
+		(uint32_t *)((uint8_t *)p_fpga_info->bar0_addr + reg_addr);
+
+	for (uint32_t i = 0; i < word_cnt; i++)
+		p_data[i] = src_addr[i];
+}
+
+void nthw_rac_bar0_write32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr,
+	uint32_t word_cnt, const uint32_t *p_data)
+{
+	volatile uint32_t *const dst_addr =
+		(uint32_t *)((uint8_t *)p_fpga_info->bar0_addr + reg_addr);
+
+	for (uint32_t i = 0; i < word_cnt; i++)
+		dst_addr[i] = p_data[i];
+}
+
+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)
+{
+	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;
+	uint32_t buf_used;
+	uint32_t buf_free;
+	uint32_t in_buf_free;
+	uint32_t out_buf_free;
+	int res = 0;
+
+	if (address > (1 << RAB_ADDR_BW)) {
+		NT_LOG(ERR, NTHW, "%s: RAB: Illegal address: value too large %d - max %d\n",
+			p_adapter_id_str, address, (1 << RAB_ADDR_BW));
+		return -1;
+	}
+
+	if (bus_id > (1 << RAB_BUSID_BW)) {
+		NT_LOG(ERR, NTHW, "%s: RAB: Illegal bus id: value too large %d - max %d\n",
+			p_adapter_id_str, bus_id, (1 << RAB_BUSID_BW));
+		return -1;
+	}
+
+	if (word_cnt == 0) {
+		NT_LOG(ERR, NTHW, "%s: RAB: Illegal word count: value is zero (%d)\n",
+			p_adapter_id_str, word_cnt);
+		return -1;
+	}
+
+	if (word_cnt > (1 << RAB_CNT_BW)) {
+		NT_LOG(ERR, NTHW, "%s: RAB: Illegal word count: value too large %d - max %d\n",
+			p_adapter_id_str, word_cnt, (1 << RAB_CNT_BW));
+		return -1;
+	}
+
+	pthread_mutex_lock(&p->m_mutex);
+
+	if (p->m_dma_active) {
+		NT_LOG(ERR, NTHW, "%s: RAB: Illegal operation: DMA enabled\n", p_adapter_id_str);
+		res = -1;
+		goto exit_unlock_res;
+	}
+
+	/* Read buffer free register */
+	nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_BUF_FREE_ADDR, &buf_free);
+
+	in_buf_free = buf_free & p->RAC_RAB_BUF_FREE_IB_FREE_MASK;
+	out_buf_free = (buf_free & p->RAC_RAB_BUF_FREE_OB_FREE_MASK) >> 16;
+
+	/* Read buffer used register */
+	nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_BUF_USED_ADDR, &buf_used);
+
+	buf_used =
+		buf_used & (p->RAC_RAB_BUF_USED_IB_USED_MASK | p->RAC_RAB_BUF_USED_OB_USED_MASK);
+
+	/*
+	 * Verify that output buffer can hold one completion word,
+	 * input buffer can hold the number of words to be written +
+	 * one write and one completion command
+	 * and that the input and output "used" buffer is 0
+	 */
+	if (out_buf_free >= 1 && in_buf_free >= word_cnt + 2 && buf_used == 0) {
+		const uint32_t rab_oper_cmpl = (RAB_COMPLETION << RAB_OPR_LO);
+		uint32_t rab_echo_oper_cmpl;
+		uint32_t word_cnt_expected = 1;
+		uint32_t rab_oper_wr;
+		uint32_t i;
+
+		rab_oper_wr = (RAB_WRITE << RAB_OPR_LO) |
+			((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) |
+			(bus_id << RAB_BUSID_LO) | address;
+
+		if (trc) {
+			rab_oper_wr |= (RAB_ECHO << RAB_OPR_LO);
+			word_cnt_expected += word_cnt + 1;
+		}
+
+		/* Write command */
+		nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_IB_DATA_ADDR, rab_oper_wr);
+
+		/* Write data to input buffer */
+		for (i = 0; i < word_cnt; i++)
+			nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_IB_DATA_ADDR, p_data[i]);
+
+		/* Write completion command */
+		nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_IB_DATA_ADDR, rab_oper_cmpl);
+
+		/* Wait until done */
+		if (_nthw_rac_wait_for_rab_done(p, address, word_cnt_expected)) {
+			res = -1;
+			goto exit_unlock_res;
+		}
+
+		if (trc) {
+			uint32_t rab_echo_oper_wr;
+			nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR,
+				&rab_echo_oper_wr);
+
+			if (p->mn_param_rac_rab_ob_update)
+				nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR, 0);
+
+			if (rab_oper_wr != rab_echo_oper_wr) {
+				NT_LOG(ERR, NTHW,
+					"%s: expected rab read echo oper (0x%08X) - read (0x%08X)\n",
+					p_adapter_id_str, rab_oper_wr, rab_echo_oper_wr);
+			}
+		}
+
+		{
+			/* Read data from output buffer */
+			uint32_t data;
+			char *tmp_string;
+
+			if (trc) {
+				tmp_string = ntlog_helper_str_alloc("Register::write");
+				ntlog_helper_str_add(tmp_string,
+					"(Dev: NA, Bus: RAB%u, Addr: 0x%08X, Cnt: %d, Data:",
+					bus_id, address, word_cnt);
+			}
+
+			for (i = 0; i < word_cnt; i++) {
+				nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR, &data);
+
+				if (p->mn_param_rac_rab_ob_update) {
+					nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR,
+						0);
+				}
+
+				if (trc)
+					ntlog_helper_str_add(tmp_string, " 0x%08X", data);
+			}
+
+			if (trc) {
+				ntlog_helper_str_add(tmp_string, ")");
+				NT_LOG(DBG, NTHW, "%s", tmp_string);
+				ntlog_helper_str_free(tmp_string);
+			}
+		}
+
+		/* Read completion from out buffer */
+		nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR, &rab_echo_oper_cmpl);
+
+		if (p->mn_param_rac_rab_ob_update)
+			nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR, 0);
+
+		if (rab_echo_oper_cmpl != rab_oper_cmpl) {
+			NT_LOG(ERR, NTHW,
+				"%s: RAB: Unexpected value of completion (0x%08X)- inBufFree: 0x%08X, outBufFree: 0x%08X, bufUsed: 0x%08X\n",
+				p_adapter_id_str, rab_echo_oper_cmpl, in_buf_free, out_buf_free,
+				buf_used);
+			res = -1;
+			goto exit_unlock_res;
+		}
+
+		/* Read buffer free register */
+		nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_BUF_FREE_ADDR, &buf_free);
+
+		if (buf_free & 0x80000000) {
+			/* Clear Timeout and overflow bits */
+			nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_BUF_FREE_ADDR, 0x0);
+			NT_LOG(ERR, NTHW,
+				"%s: RAB: timeout - Access outside register - bus: %d addr: 0x%08X - inBufFree: 0x%08X, outBufFree: 0x%08X, bufUsed: 0x%08X\n",
+				p_adapter_id_str, bus_id, address, in_buf_free, out_buf_free,
+				buf_used);
+			res = -1;
+			goto exit_unlock_res;
+		}
+
+		res = 0;
+		goto exit_unlock_res;
+
+	} else {
+		NT_LOG(ERR, NTHW,
+			"%s: RAB: Fail rab bus buffer check - bus: %d addr: 0x%08X wordcount: %d - inBufFree: 0x%08X, outBufFree: 0x%08X, bufUsed: 0x%08X\n",
+			p_adapter_id_str, bus_id, address, word_cnt, in_buf_free, out_buf_free,
+			buf_used);
+		res = -1;
+		goto exit_unlock_res;
+	}
+
+exit_unlock_res:
+	pthread_mutex_unlock(&p->m_mutex);
+	return res;
+}
+
+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)
+{
+	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;
+	uint32_t buf_used;
+	uint32_t buf_free;
+	uint32_t in_buf_free;
+	uint32_t out_buf_free;
+	int res = 0;
+
+	pthread_mutex_lock(&p->m_mutex);
+
+	if (address > (1 << RAB_ADDR_BW)) {
+		NT_LOG(ERR, NTHW, "%s: RAB: Illegal address: value too large %d - max %d\n",
+			p_adapter_id_str, address, (1 << RAB_ADDR_BW));
+		res = -1;
+		goto exit_unlock_res;
+	}
+
+	if (bus_id > (1 << RAB_BUSID_BW)) {
+		NT_LOG(ERR, NTHW, "%s: RAB: Illegal bus id: value too large %d - max %d\n",
+			p_adapter_id_str, bus_id, (1 << RAB_BUSID_BW));
+		res = -1;
+		goto exit_unlock_res;
+	}
+
+	if (word_cnt == 0) {
+		NT_LOG(ERR, NTHW, "%s: RAB: Illegal word count: value is zero (%d)\n",
+			p_adapter_id_str, word_cnt);
+		res = -1;
+		goto exit_unlock_res;
+	}
+
+	if (word_cnt > (1 << RAB_CNT_BW)) {
+		NT_LOG(ERR, NTHW, "%s: RAB: Illegal word count: value too large %d - max %d\n",
+			p_adapter_id_str, word_cnt, (1 << RAB_CNT_BW));
+		res = -1;
+		goto exit_unlock_res;
+	}
+
+	/* Read buffer free register */
+	nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_BUF_FREE_ADDR, &buf_free);
+
+	in_buf_free = buf_free & p->RAC_RAB_BUF_FREE_IB_FREE_MASK;
+	out_buf_free = (buf_free & p->RAC_RAB_BUF_FREE_OB_FREE_MASK) >> 16;
+
+	/* Read buffer used register */
+	nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_BUF_USED_ADDR, &buf_used);
+
+	buf_used =
+		buf_used & (p->RAC_RAB_BUF_USED_IB_USED_MASK | p->RAC_RAB_BUF_USED_OB_USED_MASK);
+
+	/*
+	 * Verify that output buffer can hold the number of words to be read,
+	 * input buffer can hold one read command
+	 * and that the input and output "used" buffer is 0
+	 */
+	if (out_buf_free >= word_cnt && in_buf_free >= 1 && buf_used == 0) {
+		const uint32_t rab_oper_cmpl = (RAB_COMPLETION << RAB_OPR_LO);
+		uint32_t rab_read_oper_cmpl;
+		uint32_t word_cnt_expected = word_cnt + 1;
+		uint32_t rab_oper_rd;
+
+		rab_oper_rd = (RAB_READ << RAB_OPR_LO) |
+			((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) |
+			(bus_id << RAB_BUSID_LO) | address;
+
+		if (trc) {
+			rab_oper_rd |= (RAB_ECHO << RAB_OPR_LO);
+			word_cnt_expected++;
+		}
+
+		/* Write command */
+		nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_IB_DATA_ADDR, rab_oper_rd);
+
+		/* Write completion command */
+		nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_IB_DATA_ADDR, rab_oper_cmpl);
+
+		/* Wait until done */
+		if (_nthw_rac_wait_for_rab_done(p, address, word_cnt_expected)) {
+			res = -1;
+			goto exit_unlock_res;
+		}
+
+		if (trc) {
+			uint32_t rab_echo_oper_rd;
+			nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR,
+				&rab_echo_oper_rd);
+
+			if (p->mn_param_rac_rab_ob_update)
+				nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR, 0);
+
+			if (rab_oper_rd != rab_echo_oper_rd) {
+				NT_LOG(ERR, NTHW,
+					"%s: RAB: expected rab read echo oper (0x%08X) - read (0x%08X)\n",
+					p_adapter_id_str, rab_oper_rd, rab_echo_oper_rd);
+			}
+		}
+
+		{
+			/* Read data from output buffer */
+			uint32_t i;
+
+			for (i = 0; i < word_cnt; i++) {
+				nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR,
+					&p_data[i]);
+
+				if (p->mn_param_rac_rab_ob_update) {
+					nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR,
+						0);
+				}
+			}
+
+			if (trc) {
+				char *tmp_string = ntlog_helper_str_alloc("Register::read");
+				ntlog_helper_str_add(tmp_string,
+					"(Dev: NA, Bus: RAB%u, Addr: 0x%08X, Cnt: %d, Data:",
+					bus_id, address, word_cnt);
+
+				for (i = 0; i < word_cnt; i++)
+					ntlog_helper_str_add(tmp_string, " 0x%08X", p_data[i]);
+
+				ntlog_helper_str_add(tmp_string, ")");
+				NT_LOG(DBG, NTHW, "%s", tmp_string);
+				ntlog_helper_str_free(tmp_string);
+			}
+		}
+
+		/* Read completion from out buffer */
+		nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR, &rab_read_oper_cmpl);
+
+		if (p->mn_param_rac_rab_ob_update)
+			nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR, 0);
+
+		if (rab_read_oper_cmpl != rab_oper_cmpl) {
+			NT_LOG(ERR, NTHW,
+				"%s: RAB: Unexpected value of completion (0x%08X)- inBufFree: 0x%08X, outBufFree: 0x%08X, bufUsed: 0x%08X\n",
+				p_adapter_id_str, rab_read_oper_cmpl, in_buf_free, out_buf_free,
+				buf_used);
+			res = -1;
+			goto exit_unlock_res;
+		}
+
+		/* Read buffer free register */
+		nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_BUF_FREE_ADDR, &buf_free);
+
+		if (buf_free & 0x80000000) {
+			/* Clear Timeout and overflow bits */
+			nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_BUF_FREE_ADDR, 0x0);
+			NT_LOG(ERR, NTHW,
+				"%s: RAB: timeout - Access outside register - bus: %d addr: 0x%08X - inBufFree: 0x%08X, outBufFree: 0x%08X, bufUsed: 0x%08X\n",
+				p_adapter_id_str, bus_id, address, in_buf_free, out_buf_free,
+				buf_used);
+			res = -1;
+			goto exit_unlock_res;
+		}
+
+		res = 0;
+		goto exit_unlock_res;
+
+	} else {
+		NT_LOG(ERR, NTHW,
+			"%s: RAB: Fail rab bus buffer check - bus: %d addr: 0x%08X wordcount: %d - inBufFree: 0x%08X, outBufFree: 0x%08X, bufUsed: 0x%08X\n",
+			p_adapter_id_str, bus_id, address, word_cnt, in_buf_free, out_buf_free,
+			buf_used);
+		res = -1;
+		goto exit_unlock_res;
+	}
+
+exit_unlock_res:
+	pthread_mutex_unlock(&p->m_mutex);
+	return res;
+}
+
+int nthw_rac_rab_flush(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;
+	uint32_t data = 0;
+	uint32_t retry;
+	int res = 0;
+
+	pthread_mutex_lock(&p->m_mutex);
+
+	/* Set the flush bit */
+	nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_BUF_USED_ADDR,
+		p->RAC_RAB_BUF_USED_FLUSH_MASK);
+
+	/* Reset BUF FREE register */
+	nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_BUF_FREE_ADDR, 0x0);
+
+	/* Wait until OB_USED and IB_USED are 0 */
+	for (retry = 0; retry < 100000; retry++) {
+		nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_BUF_USED_ADDR, &data);
+
+		if ((data & 0xFFFFFFFF) == p->RAC_RAB_BUF_USED_FLUSH_MASK)
+			break;
+	}
+
+	if (data != p->RAC_RAB_BUF_USED_FLUSH_MASK) {
+		NT_LOG(ERR, NTHW, "%s: RAB: Rab bus flush error.\n", p_adapter_id_str);
+		res = -1;
+	}
+
+	/* Clear flush bit when done */
+	nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_BUF_USED_ADDR, 0x0);
+
+	pthread_mutex_unlock(&p->m_mutex);
+	return res;
+}
diff --git a/drivers/net/ntnic/nthw/nthw_rac.h b/drivers/net/ntnic/nthw/nthw_rac.h
new file mode 100644
index 0000000000..c16ff77189
--- /dev/null
+++ b/drivers/net/ntnic/nthw/nthw_rac.h
@@ -0,0 +1,153 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NTHW_RAC_H__
+#define __NTHW_RAC_H__
+
+#include "nt_util.h"
+
+#define RAB_DMA_BUF_CNT (0x4000)
+
+typedef uint8_t nthw_rab_bus_id_t;
+
+struct nthw_rac {
+	nthw_fpga_t *mp_fpga;
+	nthw_module_t *mp_mod_rac;
+
+	pthread_mutex_t m_mutex;
+
+	int mn_param_rac_rab_interfaces;
+	int mn_param_rac_rab_ob_update;
+
+	nthw_register_t *mp_reg_dummy0;
+	nthw_register_t *mp_reg_dummy1;
+	nthw_register_t *mp_reg_dummy2;
+
+	nthw_register_t *mp_reg_rab_init;
+	nthw_field_t *mp_fld_rab_init;
+
+	int mn_fld_rab_init_bw;
+	uint32_t mn_fld_rab_init_mask;
+
+	nthw_register_t *mp_reg_dbg_ctrl;
+	nthw_field_t *mp_fld_dbg_ctrl;
+
+	nthw_register_t *mp_reg_dbg_data;
+	nthw_field_t *mp_fld_dbg_data;
+
+	nthw_register_t *mp_reg_rab_ib_data;
+	nthw_field_t *mp_fld_rab_ib_data;
+
+	nthw_register_t *mp_reg_rab_ob_data;
+	nthw_field_t *mp_fld_rab_ob_data;
+
+	nthw_register_t *mp_reg_rab_buf_free;
+	nthw_field_t *mp_fld_rab_buf_free_ib_free;
+	nthw_field_t *mp_fld_rab_buf_free_ib_ovf;
+	nthw_field_t *mp_fld_rab_buf_free_ob_free;
+	nthw_field_t *mp_fld_rab_buf_free_ob_ovf;
+	nthw_field_t *mp_fld_rab_buf_free_timeout;
+
+	nthw_register_t *mp_reg_rab_buf_used;
+	nthw_field_t *mp_fld_rab_buf_used_ib_used;
+	nthw_field_t *mp_fld_rab_buf_used_ob_used;
+	nthw_field_t *mp_fld_rab_buf_used_flush;
+
+	nthw_register_t *mp_reg_rab_dma_ib_lo;
+	nthw_field_t *mp_fld_rab_dma_ib_lo_phy_addr;
+
+	nthw_register_t *mp_reg_rab_dma_ib_hi;
+	nthw_field_t *mp_fld_rab_dma_ib_hi_phy_addr;
+
+	nthw_register_t *mp_reg_rab_dma_ob_hi;
+	nthw_field_t *mp_fld_rab_dma_ob_hi_phy_addr;
+
+	nthw_register_t *mp_reg_rab_dma_ob_lo;
+	nthw_field_t *mp_fld_rab_dma_ob_lo_phy_addr;
+
+	nthw_register_t *mp_reg_rab_dma_ib_wr;
+	nthw_field_t *mp_fld_rab_dma_ib_wr_ptr;
+
+	nthw_register_t *mp_reg_rab_dma_ib_rd;
+	nthw_field_t *mp_fld_rab_dma_ib_rd_ptr;
+
+	nthw_register_t *mp_reg_rab_dma_ob_wr;
+	nthw_field_t *mp_fld_rab_dma_ob_wr_ptr;
+
+	nthw_register_t *mp_reg_rab_nmb_rd;
+	nthw_register_t *mp_reg_rab_nmb_data;
+	nthw_register_t *mp_reg_rab_nmb_wr;
+	nthw_register_t *mp_reg_rab_nmb_status;
+
+	uint32_t RAC_RAB_INIT_ADDR;
+	uint32_t RAC_RAB_IB_DATA_ADDR;
+	uint32_t RAC_RAB_OB_DATA_ADDR;
+	uint32_t RAC_RAB_BUF_FREE_ADDR;
+	uint32_t RAC_RAB_BUF_USED_ADDR;
+
+	uint32_t RAC_RAB_DMA_IB_LO_ADDR;
+	uint32_t RAC_RAB_DMA_IB_HI_ADDR;
+	uint32_t RAC_RAB_DMA_OB_LO_ADDR;
+	uint32_t RAC_RAB_DMA_OB_HI_ADDR;
+	uint32_t RAC_RAB_DMA_IB_RD_ADDR;
+	uint32_t RAC_RAB_DMA_OB_WR_ADDR;
+	uint32_t RAC_RAB_DMA_IB_WR_ADDR;
+
+	uint32_t RAC_RAB_BUF_FREE_IB_FREE_MASK;
+	uint32_t RAC_RAB_BUF_FREE_OB_FREE_MASK;
+	uint32_t RAC_RAB_BUF_USED_IB_USED_MASK;
+	uint32_t RAC_RAB_BUF_USED_OB_USED_MASK;
+	uint32_t RAC_RAB_BUF_USED_FLUSH_MASK;
+
+	uint32_t RAC_RAB_BUF_USED_OB_USED_LOW;
+
+	uint32_t RAC_NMB_RD_ADR_ADDR;
+	uint32_t RAC_NMB_DATA_ADDR;
+	uint32_t RAC_NMB_WR_ADR_ADDR;
+	uint32_t RAC_NMB_STATUS_ADDR;
+
+	bool m_dma_active;
+
+	struct nt_dma_s *m_dma;
+
+	volatile uint32_t *m_dma_in_buf;
+	volatile uint32_t *m_dma_out_buf;
+
+	uint16_t m_dma_out_ptr_rd;
+	uint16_t m_dma_in_ptr_wr;
+	uint32_t m_in_free;
+};
+
+typedef struct nthw_rac nthw_rac_t;
+typedef struct nthw_rac nthw_rac;
+
+struct dma_buf_ptr {
+	uint32_t size;
+	uint32_t index;
+	volatile uint32_t *base;
+};
+
+nthw_rac_t *nthw_rac_new(void);
+int nthw_rac_init(nthw_rac_t *p, nthw_fpga_t *p_fpga, struct fpga_info_s *p_fpga_info);
+
+int nthw_rac_rab_init(nthw_rac_t *p, uint32_t n_rab_intf_mask);
+
+int nthw_rac_rab_setup(nthw_rac_t *p);
+
+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_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_flush(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,
+	uint32_t word_cnt, const uint32_t *p_data);
+
+#endif	/* __NTHW_RAC_H__ */
-- 
2.45.0


  parent reply	other threads:[~2024-06-27  7:40 UTC|newest]

Thread overview: 101+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-30 14:48 [PATCH v1 01/17] net/ntnic: Add registers for NapaTech SmartNiC Serhii Iliushyk
2024-05-30 14:48 ` [PATCH v1 02/17] net/ntnic: add core platform functionality Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 03/17] net/ntnic: add interfaces for " Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 04/17] net/ntnic: add FPGA model implementation Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 05/17] net/ntnic: add NTNIC adapter interfaces Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 06/17] net/ntnic: add interfaces for PMD driver modules Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 07/17] net/ntnic: add API " Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 08/17] net/ntnic: add interfaces for flow API engine Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 09/17] net/ntnic: add VFIO module Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 10/17] net/ntnic: add Logs and utilities implementation Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 11/17] net/ntnic: add ethdev and makes PMD available Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 12/17] net/ntnic: add support of the NT200A0X smartNIC Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 13/17] net/ntnic: add adapter initialization Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 14/17] net/ntnic: add adapter initialization API Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 15/17] net/ntnic: add link management module Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 16/17] net/ntnic: add link 100G module Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 17/17] net/ntnic: add NIM module Serhii Iliushyk
2024-05-31 15:47 ` [PATCH v2 01/17] net/ntnic: Add registers for NapaTech SmartNiC Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 02/17] net/ntnic: add core platform functionality Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 03/17] net/ntnic: add interfaces for " Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 04/17] net/ntnic: add FPGA model implementation Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 05/17] net/ntnic: add NTNIC adapter interfaces Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 06/17] net/ntnic: add interfaces for PMD driver modules Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 07/17] net/ntnic: add API " Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 08/17] net/ntnic: add interfaces for flow API engine Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 09/17] net/ntnic: add VFIO module Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 10/17] net/ntnic: add Logs and utilities implementation Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 11/17] net/ntnic: add ethdev and makes PMD available Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 12/17] net/ntnic: add support of the NT200A0X smartNIC Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 13/17] net/ntnic: add adapter initialization Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 14/17] net/ntnic: add adapter initialization API Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 15/17] net/ntnic: add link management module Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 16/17] net/ntnic: add link 100G module Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 17/17] net/ntnic: add NIM module Serhii Iliushyk
2024-06-03 16:17 ` [PATCH v3 01/17] net/ntnic: Add registers for NapaTech SmartNiC Serhii Iliushyk
2024-06-03 16:17   ` [PATCH v3 02/17] net/ntnic: add core platform functionality Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 03/17] net/ntnic: add interfaces for " Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 04/17] net/ntnic: add FPGA model implementation Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 05/17] net/ntnic: add NTNIC adapter interfaces Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 06/17] net/ntnic: add interfaces for PMD driver modules Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 07/17] net/ntnic: add API " Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 08/17] net/ntnic: add interfaces for flow API engine Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 09/17] net/ntnic: add VFIO module Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 10/17] net/ntnic: add Logs and utilities implementation Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 11/17] net/ntnic: add ethdev and makes PMD available Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 12/17] net/ntnic: add support of the NT200A0X smartNIC Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 13/17] net/ntnic: add adapter initialization Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 14/17] net/ntnic: add adapter initialization API Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 15/17] net/ntnic: add link management module Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 16/17] net/ntnic: add link 100G module Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 17/17] net/ntnic: add NIM module Serhii Iliushyk
2024-06-04 10:29   ` [PATCH v3 01/17] net/ntnic: Add registers for NapaTech SmartNiC Mykola Kostenok
2024-06-07 13:03     ` Serhii Iliushyk
2024-06-12  8:50       ` Ferruh Yigit
2024-06-12  8:55         ` Ferruh Yigit
2024-06-26 19:55 ` [PATCH v4 01/23] net/ntnic: add ethdev and makes PMD available Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 02/23] net/ntnic: add logging implementation Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 03/23] net/ntnic: add minimal initialization for PCI device Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 04/23] net/ntnic: add NT utilities implementation Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 05/23] net/ntnic: add VFIO module Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 06/23] net/ntnic: add NT NIC driver dependencies Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 07/23] net/ntnic: add core platform functionality Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 08/23] net/ntnic: add adapter initialization Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 09/23] net/ntnic: add registers and FPGA model for NapaTech NIC Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 10/23] net/ntnic: add core platform functionality Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 11/23] net/ntnic: add FPGA initialization functionality Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 12/23] net/ntnic: add support of the NT200A0X smartNIC Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 13/23] net/ntnic: add reset module for " Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 14/23] net/ntnic: add clock profiles " Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 15/23] net/ntnic: add MAC and packet features Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 16/23] net/ntnic: add link management module Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 17/23] net/ntnic: add link 100G module Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 18/23] net/ntnic: add NIM module Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 19/23] net/ntnic: add QSFP support Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 20/23] net/ntnic: add QSFP28 support Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 21/23] net/ntnic: add GPIO PHY module Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 22/23] net/ntnic: add MAC PCS register interface module Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 23/23] net/ntnic: add GMF (Generic MAC Feeder) module Serhii Iliushyk
2024-06-27  7:38 ` [PATCH v5 01/23] net/ntnic: add ethdev and makes PMD available Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 02/23] net/ntnic: add logging implementation Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 03/23] net/ntnic: add minimal initialization for PCI device Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 04/23] net/ntnic: add NT utilities implementation Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 05/23] net/ntnic: add VFIO module Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 06/23] net/ntnic: add NT NIC driver dependencies Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 07/23] net/ntnic: add core platform functionality Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 08/23] net/ntnic: add adapter initialization Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 09/23] net/ntnic: add registers and FPGA model for NapaTech NIC Serhii Iliushyk
2024-06-27  7:38   ` Serhii Iliushyk [this message]
2024-06-27  7:38   ` [PATCH v5 11/23] net/ntnic: add FPGA initialization functionality Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 12/23] net/ntnic: add support of the NT200A0X smartNIC Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 13/23] net/ntnic: add reset module for " Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 14/23] net/ntnic: add clock profiles " Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 15/23] net/ntnic: add MAC and packet features Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 16/23] net/ntnic: add link management module Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 17/23] net/ntnic: add link 100G module Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 18/23] net/ntnic: add NIM module Serhii Iliushyk
2024-06-27  7:39   ` [PATCH v5 19/23] net/ntnic: add QSFP support Serhii Iliushyk
2024-06-27  7:39   ` [PATCH v5 20/23] net/ntnic: add QSFP28 support Serhii Iliushyk
2024-06-27  7:39   ` [PATCH v5 21/23] net/ntnic: add GPIO PHY module Serhii Iliushyk
2024-06-27  7:39   ` [PATCH v5 22/23] net/ntnic: add MAC PCS register interface module Serhii Iliushyk
2024-06-27  7:39   ` [PATCH v5 23/23] net/ntnic: add GMF (Generic MAC Feeder) module Serhii Iliushyk

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20240627073918.2039719-10-sil-plv@napatech.com \
    --to=sil-plv@napatech.com \
    --cc=andrew.rybchenko@oktetlabs.ru \
    --cc=ckm@napatech.com \
    --cc=dev@dpdk.org \
    --cc=ferruh.yigit@amd.com \
    --cc=mko-plv@napatech.com \
    /path/to/YOUR_REPLY

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

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).