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 18/23] net/ntnic: add NIM module
Date: Thu, 27 Jun 2024 09:38:59 +0200	[thread overview]
Message-ID: <20240627073918.2039719-18-sil-plv@napatech.com> (raw)
In-Reply-To: <20240627073918.2039719-1-sil-plv@napatech.com>

Add API for control NIM

Signed-off-by: Serhii Iliushyk <sil-plv@napatech.com>
---
 drivers/net/ntnic/adapter/nt4ga_adapter.c     |  34 +++
 drivers/net/ntnic/include/nt4ga_adapter.h     |   3 +
 drivers/net/ntnic/include/nt4ga_link.h        |  13 +
 drivers/net/ntnic/include/ntnic_nim.h         |  61 +++++
 .../link_mgmt/link_100g/nt4ga_link_100g.c     | 214 ++++++++++++++++-
 drivers/net/ntnic/link_mgmt/nt4ga_link.c      |  13 +
 drivers/net/ntnic/meson.build                 |   3 +
 drivers/net/ntnic/nim/i2c_nim.c               | 224 ++++++++++++++++++
 drivers/net/ntnic/nim/i2c_nim.h               |  24 ++
 drivers/net/ntnic/nim/nim_defines.h           |  29 +++
 .../net/ntnic/nthw/core/include/nthw_core.h   |   1 +
 .../net/ntnic/nthw/core/include/nthw_i2cm.h   |  50 ++++
 drivers/net/ntnic/nthw/core/nthw_fpga.c       |   3 +
 drivers/net/ntnic/nthw/core/nthw_i2cm.c       | 192 +++++++++++++++
 drivers/net/ntnic/nthw/nthw_drv.h             |   1 +
 drivers/net/ntnic/ntnic_mod_reg.h             |   7 +
 16 files changed, 871 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ntnic/include/ntnic_nim.h
 create mode 100644 drivers/net/ntnic/nim/i2c_nim.c
 create mode 100644 drivers/net/ntnic/nim/i2c_nim.h
 create mode 100644 drivers/net/ntnic/nim/nim_defines.h
 create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_i2cm.h
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_i2cm.c

diff --git a/drivers/net/ntnic/adapter/nt4ga_adapter.c b/drivers/net/ntnic/adapter/nt4ga_adapter.c
index 807c1dcde3..b22ffd6cef 100644
--- a/drivers/net/ntnic/adapter/nt4ga_adapter.c
+++ b/drivers/net/ntnic/adapter/nt4ga_adapter.c
@@ -9,6 +9,32 @@
 #include "nthw_fpga.h"
 #include "ntnic_mod_reg.h"
 
+/*
+ * Global variables shared by NT adapter types
+ */
+rte_thread_t monitor_tasks[NUM_ADAPTER_MAX];
+volatile int monitor_task_is_running[NUM_ADAPTER_MAX];
+
+/*
+ * Signal-handler to stop all monitor threads
+ */
+static void stop_monitor_tasks(int signum)
+{
+	const size_t N = ARRAY_SIZE(monitor_task_is_running);
+	size_t i;
+
+	/* Stop all monitor tasks */
+	for (i = 0; i < N; i++) {
+		const int is_running = monitor_task_is_running[i];
+		monitor_task_is_running[i] = 0;
+
+		if (signum == -1 && is_running != 0) {
+			rte_thread_join(monitor_tasks[i], NULL);
+			memset(&monitor_tasks[i], 0, sizeof(monitor_tasks[0]));
+		}
+	}
+}
+
 static int nt4ga_adapter_show_info(struct adapter_info_s *p_adapter_info, FILE *pfh)
 {
 	const char *const p_dev_name = p_adapter_info->p_dev_name;
@@ -35,6 +61,9 @@ static int nt4ga_adapter_show_info(struct adapter_info_s *p_adapter_info, FILE *
 		p_fpga_info->n_fpga_ver_id, p_fpga_info->n_fpga_rev_id, p_fpga_info->n_fpga_ident,
 		p_fpga_info->n_fpga_build_time);
 	fprintf(pfh, "%s: FpgaDebugMode=0x%x\n", p_adapter_id_str, p_fpga_info->n_fpga_debug_mode);
+	fprintf(pfh, "%s: Nims=%d PhyPorts=%d PhyQuads=%d RxPorts=%d TxPorts=%d\n",
+		p_adapter_id_str, p_fpga_info->n_nims, p_fpga_info->n_phy_ports,
+		p_fpga_info->n_phy_quads, p_fpga_info->n_rx_ports, p_fpga_info->n_tx_ports);
 	fprintf(pfh, "%s: Hw=0x%02X_rev%d: %s\n", p_adapter_id_str, p_hw_info->hw_platform_id,
 		p_fpga_info->nthw_hw_info.hw_id, p_fpga_info->nthw_hw_info.hw_plat_id_str);
 	fprintf(pfh, "%s: MCU Details:\n", p_adapter_id_str);
@@ -56,6 +85,7 @@ static int nt4ga_adapter_init(struct adapter_info_s *p_adapter_info)
 	 * (nthw_fpga_init())
 	 */
 	int n_phy_ports = -1;
+	int n_nim_ports = -1;
 	int res = -1;
 	nthw_fpga_t *p_fpga = NULL;
 
@@ -124,6 +154,8 @@ static int nt4ga_adapter_init(struct adapter_info_s *p_adapter_info)
 	assert(p_fpga);
 	n_phy_ports = fpga_info->n_phy_ports;
 	assert(n_phy_ports >= 1);
+	n_nim_ports = fpga_info->n_nims;
+	assert(n_nim_ports >= 1);
 
 	{
 		int i;
@@ -173,6 +205,8 @@ static int nt4ga_adapter_deinit(struct adapter_info_s *p_adapter_info)
 	int i;
 	int res;
 
+	stop_monitor_tasks(-1);
+
 	nthw_fpga_shutdown(&p_adapter_info->fpga_info);
 
 	/* Rac rab reset flip flop */
diff --git a/drivers/net/ntnic/include/nt4ga_adapter.h b/drivers/net/ntnic/include/nt4ga_adapter.h
index ed14936b38..4b204742a2 100644
--- a/drivers/net/ntnic/include/nt4ga_adapter.h
+++ b/drivers/net/ntnic/include/nt4ga_adapter.h
@@ -39,5 +39,8 @@ typedef struct adapter_info_s {
 	int n_tx_host_buffers;
 } adapter_info_t;
 
+extern rte_thread_t monitor_tasks[NUM_ADAPTER_MAX];
+extern volatile int monitor_task_is_running[NUM_ADAPTER_MAX];
+
 
 #endif	/* _NT4GA_ADAPTER_H_ */
diff --git a/drivers/net/ntnic/include/nt4ga_link.h b/drivers/net/ntnic/include/nt4ga_link.h
index 849261ce3a..0851057f81 100644
--- a/drivers/net/ntnic/include/nt4ga_link.h
+++ b/drivers/net/ntnic/include/nt4ga_link.h
@@ -7,6 +7,7 @@
 #define NT4GA_LINK_H_
 
 #include "ntos_drv.h"
+#include "ntnic_nim.h"
 
 enum nt_link_state_e {
 	NT_LINK_STATE_UNKNOWN = 0,	/* The link state has not been read yet */
@@ -41,6 +42,8 @@ enum nt_link_auto_neg_e {
 
 typedef struct link_state_s {
 	bool link_disabled;
+	bool nim_present;
+	bool lh_nim_absent;
 	bool link_up;
 	enum nt_link_state_e link_state;
 	enum nt_link_state_e link_state_latched;
@@ -73,12 +76,22 @@ typedef struct port_action_s {
 	uint32_t port_lpbk_mode;
 } port_action_t;
 
+typedef struct adapter_100g_s {
+	nim_i2c_ctx_t nim_ctx[NUM_ADAPTER_PORTS_MAX];	/* Should be the first field */
+} adapter_100g_t;
+
+typedef union adapter_var_s {
+	nim_i2c_ctx_t nim_ctx[NUM_ADAPTER_PORTS_MAX];	/* First field in all the adapters type */
+	adapter_100g_t var100g;
+} adapter_var_u;
+
 typedef struct nt4ga_link_s {
 	link_state_t link_state[NUM_ADAPTER_PORTS_MAX];
 	link_info_t link_info[NUM_ADAPTER_PORTS_MAX];
 	port_action_t port_action[NUM_ADAPTER_PORTS_MAX];
 	uint32_t speed_capa;
 	bool variables_initialized;
+	adapter_var_u u;
 } nt4ga_link_t;
 
 #endif	/* NT4GA_LINK_H_ */
diff --git a/drivers/net/ntnic/include/ntnic_nim.h b/drivers/net/ntnic/include/ntnic_nim.h
new file mode 100644
index 0000000000..263875a857
--- /dev/null
+++ b/drivers/net/ntnic/include/ntnic_nim.h
@@ -0,0 +1,61 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+#ifndef _NTNIC_NIM_H_
+#define _NTNIC_NIM_H_
+
+#include <stdint.h>
+
+typedef enum i2c_type {
+	I2C_HWIIC,
+} i2c_type_e;
+
+enum nt_port_type_e {
+	NT_PORT_TYPE_NOT_AVAILABLE = 0,	/* The NIM/port type is not available (unknown) */
+	NT_PORT_TYPE_NOT_RECOGNISED,	/* The NIM/port type not recognized */
+};
+
+typedef enum nt_port_type_e nt_port_type_t, *nt_port_type_p;
+
+typedef struct nim_i2c_ctx {
+	union {
+		nthw_iic_t hwiic;	/* depends on *Fpga_t, instance number, and cycle time */
+		struct {
+			nthw_i2cm_t *p_nt_i2cm;
+			int mux_channel;
+		} hwagx;
+	};
+	i2c_type_e type;/* 0 = hwiic (xilinx) - 1 =  hwagx (agilex) */
+	uint8_t instance;
+	uint8_t devaddr;
+	uint8_t regaddr;
+	uint8_t nim_id;
+	nt_port_type_t port_type;
+
+	char vendor_name[17];
+	char prod_no[17];
+	char serial_no[17];
+	char date[9];
+	char rev[5];
+	bool avg_pwr;
+	bool content_valid;
+	uint8_t pwr_level_req;
+	uint8_t pwr_level_cur;
+	uint16_t len_info[5];
+	uint32_t speed_mask;	/* Speeds supported by the NIM */
+	int8_t lane_idx;
+	uint8_t lane_count;
+	uint32_t options;
+	bool tx_disable;
+	bool dmi_supp;
+
+} nim_i2c_ctx_t, *nim_i2c_ctx_p;
+
+struct nim_sensor_group {
+	struct nim_i2c_ctx *ctx;
+	struct nim_sensor_group *next;
+};
+
+#endif	/* _NTNIC_NIM_H_ */
diff --git a/drivers/net/ntnic/link_mgmt/link_100g/nt4ga_link_100g.c b/drivers/net/ntnic/link_mgmt/link_100g/nt4ga_link_100g.c
index 36c4bf031f..4c159431e1 100644
--- a/drivers/net/ntnic/link_mgmt/link_100g/nt4ga_link_100g.c
+++ b/drivers/net/ntnic/link_mgmt/link_100g/nt4ga_link_100g.c
@@ -7,16 +7,202 @@
 
 #include "nt_util.h"
 #include "ntlog.h"
+#include "i2c_nim.h"
 #include "ntnic_mod_reg.h"
 
+/*
+ * Initialize NIM, Code based on nt200e3_2_ptp.cpp: MyPort::createNim()
+ */
+static int _create_nim(adapter_info_t *drv, int port)
+{
+	int res = 0;
+	const uint8_t valid_nim_id = 17U;
+	nim_i2c_ctx_t *nim_ctx;
+	nt4ga_link_t *link_info = &drv->nt4ga_link;
+
+	assert(port >= 0 && port < NUM_ADAPTER_PORTS_MAX);
+	assert(link_info->variables_initialized);
+
+	nim_ctx = &link_info->u.var100g.nim_ctx[port];
+
+	/*
+	 * Wait a little after a module has been inserted before trying to access I2C
+	 * data, otherwise the module will not respond correctly.
+	 */
+	nt_os_wait_usec(1000000);	/* pause 1.0s */
+
+	res = construct_and_preinit_nim(nim_ctx);
+
+	if (res)
+		return res;
+
+	/*
+	 * Does the driver support the NIM module type?
+	 */
+	if (nim_ctx->nim_id != valid_nim_id) {
+		NT_LOG(ERR, NTHW, "%s: The driver does not support the NIM module type %s\n",
+			drv->mp_port_id_str[port], nim_id_to_text(nim_ctx->nim_id));
+		NT_LOG(DBG, NTHW, "%s: The driver supports the NIM module type %s\n",
+			drv->mp_port_id_str[port], nim_id_to_text(valid_nim_id));
+		return -1;
+	}
+
+	return res;
+}
+
+/*
+ * Initialize one 100 Gbps port.
+ * The function shall not assume anything about the state of the adapter
+ * and/or port.
+ */
+static int _port_init(adapter_info_t *drv, int port)
+{
+	int res;
+	nt4ga_link_t *link_info = &drv->nt4ga_link;
+
+	assert(port >= 0 && port < NUM_ADAPTER_PORTS_MAX);
+	assert(link_info->variables_initialized);
+
+	/*
+	 * Phase 1. Pre-state machine (`port init` functions)
+	 * 1.1) nt4ga_adapter::port_init()
+	 */
+
+	/* No adapter set-up here, only state variables */
+
+	/* 1.2) MyPort::init() */
+	link_info->link_info[port].link_speed = NT_LINK_SPEED_100G;
+	link_info->link_info[port].link_duplex = NT_LINK_DUPLEX_FULL;
+	link_info->link_info[port].link_auto_neg = NT_LINK_AUTONEG_OFF;
+	link_info->speed_capa |= NT_LINK_SPEED_100G;
+
+	/* Phase 3. Link state machine steps */
+
+	/* 3.1) Create NIM, ::createNim() */
+	res = _create_nim(drv, port);
+
+	if (res) {
+		NT_LOG(WRN, NTNIC, "%s: NIM initialization failed\n", drv->mp_port_id_str[port]);
+		return res;
+	}
+
+	NT_LOG(DBG, NTNIC, "%s: NIM initialized\n", drv->mp_port_id_str[port]);
+
+	return res;
+}
+
+/*
+ * State machine shared between kernel and userland
+ */
+static int _common_ptp_nim_state_machine(void *data)
+{
+	adapter_info_t *drv = (adapter_info_t *)data;
+	fpga_info_t *fpga_info = &drv->fpga_info;
+	nt4ga_link_t *link_info = &drv->nt4ga_link;
+	nthw_fpga_t *fpga = fpga_info->mp_fpga;
+	const int adapter_no = drv->adapter_no;
+	const int nb_ports = fpga_info->n_phy_ports;
+	uint32_t last_lpbk_mode[NUM_ADAPTER_PORTS_MAX];
+
+	link_state_t *link_state;
+
+	if (!fpga) {
+		NT_LOG(ERR, NTNIC, "%s: fpga is NULL\n", drv->mp_adapter_id_str);
+		goto NT4GA_LINK_100G_MON_EXIT;
+	}
+
+	assert(adapter_no >= 0 && adapter_no < NUM_ADAPTER_MAX);
+	link_state = link_info->link_state;
+
+	monitor_task_is_running[adapter_no] = 1;
+	memset(last_lpbk_mode, 0, sizeof(last_lpbk_mode));
+
+	if (monitor_task_is_running[adapter_no])
+		NT_LOG(DBG, NTNIC, "%s: link state machine running...\n", drv->mp_adapter_id_str);
+
+	while (monitor_task_is_running[adapter_no]) {
+		int i;
+
+		for (i = 0; i < nb_ports; i++) {
+			const bool is_port_disabled = link_info->port_action[i].port_disable;
+			const bool was_port_disabled = link_state[i].link_disabled;
+			const bool disable_port = is_port_disabled && !was_port_disabled;
+			const bool enable_port = !is_port_disabled && was_port_disabled;
+
+			if (!monitor_task_is_running[adapter_no])	/* stop quickly */
+				break;
+
+			/* Has the administrative port state changed? */
+			assert(!(disable_port && enable_port));
+
+			if (disable_port) {
+				memset(&link_state[i], 0, sizeof(link_state[i]));
+				link_info->link_info[i].link_speed = NT_LINK_SPEED_UNKNOWN;
+				link_state[i].link_disabled = true;
+				/* Turn off laser and LED, etc. */
+				(void)_create_nim(drv, i);
+				NT_LOG(DBG, NTNIC, "%s: Port %i is disabled\n",
+					drv->mp_port_id_str[i], i);
+				continue;
+			}
+
+			if (enable_port) {
+				link_state[i].link_disabled = false;
+				NT_LOG(DBG, NTNIC, "%s: Port %i is enabled\n",
+					drv->mp_port_id_str[i], i);
+			}
+
+			if (is_port_disabled)
+				continue;
+
+			if (link_info->port_action[i].port_lpbk_mode != last_lpbk_mode[i]) {
+				/* Loopback mode has changed. Do something */
+				_port_init(drv, i);
+
+				NT_LOG(INF, NTNIC, "%s: Loopback mode changed=%u\n",
+					drv->mp_port_id_str[i],
+					link_info->port_action[i].port_lpbk_mode);
+
+				if (link_info->port_action[i].port_lpbk_mode == 1)
+					link_state[i].link_up = true;
+
+				last_lpbk_mode[i] = link_info->port_action[i].port_lpbk_mode;
+				continue;
+			}
+
+		}	/* end-for */
+
+		if (monitor_task_is_running[adapter_no])
+			nt_os_wait_usec(5 * 100000U);	/* 5 x 0.1s = 0.5s */
+	}
+
+NT4GA_LINK_100G_MON_EXIT:
+
+	NT_LOG(DBG, NTNIC, "%s: Stopped NT4GA 100 Gbps link monitoring thread.\n",
+		drv->mp_adapter_id_str);
+
+	return 0;
+}
+
+/*
+ * Userland NIM state machine
+ */
+static uint32_t nt4ga_link_100g_mon(void *data)
+{
+	(void)_common_ptp_nim_state_machine(data);
+
+	return 0;
+}
+
 /*
  * Initialize all ports
  * The driver calls this function during initialization (of the driver).
  */
 static int nt4ga_link_100g_ports_init(struct adapter_info_s *p_adapter_info, nthw_fpga_t *fpga)
 {
-	(void)fpga;
+	fpga_info_t *fpga_info = &p_adapter_info->fpga_info;
 	const int adapter_no = p_adapter_info->adapter_no;
+	const int nb_ports = fpga_info->n_phy_ports;
 	int res = 0;
 
 	NT_LOG(DBG, NTNIC, "%s: Initializing ports\n", p_adapter_info->mp_adapter_id_str);
@@ -27,12 +213,38 @@ static int nt4ga_link_100g_ports_init(struct adapter_info_s *p_adapter_info, nth
 	assert(adapter_no >= 0 && adapter_no < NUM_ADAPTER_MAX);
 
 	if (res == 0 && !p_adapter_info->nt4ga_link.variables_initialized) {
+		nim_i2c_ctx_t *nim_ctx = p_adapter_info->nt4ga_link.u.var100g.nim_ctx;
+		int i;
+
+		for (i = 0; i < nb_ports; i++) {
+			/* 2 + adapter port number */
+			const uint8_t instance = (uint8_t)(2U + i);
+
+			res = nthw_iic_init(&nim_ctx[i].hwiic, fpga, instance, 8 /* timing */);
+
+			if (res != 0)
+				break;
+
+			nim_ctx[i].instance = instance;
+			nim_ctx[i].devaddr = 0x50;	/* 0xA0 / 2 */
+			nim_ctx[i].regaddr = 0U;
+			nim_ctx[i].type = I2C_HWIIC;
+		}
+
 		if (res == 0) {
 			p_adapter_info->nt4ga_link.speed_capa = NT_LINK_SPEED_100G;
 			p_adapter_info->nt4ga_link.variables_initialized = true;
 		}
 	}
 
+	/* Create state-machine thread */
+	if (res == 0) {
+		if (!monitor_task_is_running[adapter_no]) {
+			res = rte_thread_create(&monitor_tasks[adapter_no], NULL,
+					nt4ga_link_100g_mon, p_adapter_info);
+		}
+	}
+
 	return res;
 }
 
diff --git a/drivers/net/ntnic/link_mgmt/nt4ga_link.c b/drivers/net/ntnic/link_mgmt/nt4ga_link.c
index ad23046aae..bc362776fc 100644
--- a/drivers/net/ntnic/link_mgmt/nt4ga_link.c
+++ b/drivers/net/ntnic/link_mgmt/nt4ga_link.c
@@ -12,6 +12,7 @@
 #include "ntnic_mod_reg.h"
 
 #include "nt4ga_link.h"
+#include "i2c_nim.h"
 
 /*
  * port: speed capabilities
@@ -26,6 +27,16 @@ static uint32_t nt4ga_port_get_link_speed_capabilities(struct adapter_info_s *p,
 	return nt_link_speed_capa;
 }
 
+/*
+ * port: nim present
+ */
+static bool nt4ga_port_get_nim_present(struct adapter_info_s *p, int port)
+{
+	nt4ga_link_t *const p_link = &p->nt4ga_link;
+	const bool nim_present = p_link->link_state[port].nim_present;
+	return nim_present;
+}
+
 /*
  * port: link mode
  */
@@ -131,6 +142,8 @@ static uint32_t nt4ga_port_get_loopback_mode(struct adapter_info_s *p, int port)
 
 
 static const struct port_ops ops = {
+	.get_nim_present = nt4ga_port_get_nim_present,
+
 	/*
 	 * port:s link mode
 	 */
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index ace080c0b8..d6346a5986 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -22,6 +22,7 @@ includes = [
     include_directories('nthw'),
     include_directories('nthw/supported'),
     include_directories('nthw/model'),
+    include_directories('nim/'),
 ]
 
 # all sources
@@ -29,6 +30,7 @@ sources = files(
     'adapter/nt4ga_adapter.c',
     'link_mgmt/link_100g/nt4ga_link_100g.c',
     'link_mgmt/nt4ga_link.c',
+    'nim/i2c_nim.c',
     'nthw/supported/nthw_fpga_9563_055_039_0000.c',
     'nthw/supported/nthw_fpga_instances.c',
     'nthw/supported/nthw_fpga_mod_str_map.c',
@@ -38,6 +40,7 @@ sources = files(
     'nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c',
     'nthw/core/nthw_fpga.c',
     'nthw/core/nthw_hif.c',
+    'nthw/core/nthw_i2cm.c',
     'nthw/core/nthw_iic.c',
     'nthw/core/nthw_pcie3.c',
     'nthw/core/nthw_sdc.c',
diff --git a/drivers/net/ntnic/nim/i2c_nim.c b/drivers/net/ntnic/nim/i2c_nim.c
new file mode 100644
index 0000000000..2918eda072
--- /dev/null
+++ b/drivers/net/ntnic/nim/i2c_nim.c
@@ -0,0 +1,224 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <string.h>	/* memset */
+
+#include "nthw_drv.h"
+#include "i2c_nim.h"
+#include "ntlog.h"
+#include "nt_util.h"
+#include "ntnic_mod_reg.h"
+#include "nim_defines.h"
+
+#define NIM_READ false
+#define NIM_WRITE true
+#define NIM_PAGE_SEL_REGISTER 127
+#define NIM_I2C_0XA0 0xA0	/* Basic I2C address */
+
+static int nim_read_write_i2c_data(nim_i2c_ctx_p ctx, bool do_write, uint16_t lin_addr,
+	uint8_t i2c_addr, uint8_t a_reg_addr, uint8_t seq_cnt,
+	uint8_t *p_data)
+{
+	/* Divide i2c_addr by 2 because nthw_iic_read/writeData multiplies by 2 */
+	const uint8_t i2c_devaddr = i2c_addr / 2U;
+	(void)lin_addr;	/* Unused */
+
+	if (do_write) {
+		if (ctx->type == I2C_HWIIC) {
+			return nthw_iic_write_data(&ctx->hwiic, i2c_devaddr, a_reg_addr, seq_cnt,
+					p_data);
+
+		} else {
+			return 0;
+		}
+
+	} else if (ctx->type == I2C_HWIIC) {
+		return nthw_iic_read_data(&ctx->hwiic, i2c_devaddr, a_reg_addr, seq_cnt, p_data);
+
+	} else {
+		return 0;
+	}
+}
+
+/*
+ * ------------------------------------------------------------------------------
+ * Selects a new page for page addressing. This is only relevant if the NIM
+ * supports this. Since page switching can take substantial time the current page
+ * select is read and subsequently only changed if necessary.
+ * Important:
+ * XFP Standard 8077, Ver 4.5, Page 61 states that:
+ * If the host attempts to write a table select value which is not supported in
+ * a particular module, the table select byte will revert to 01h.
+ * This can lead to some surprising result that some pages seems to be duplicated.
+ * ------------------------------------------------------------------------------
+ */
+
+static int nim_setup_page(nim_i2c_ctx_p ctx, uint8_t page_sel)
+{
+	uint8_t curr_page_sel;
+
+	/* Read the current page select value */
+	if (nim_read_write_i2c_data(ctx, NIM_READ, NIM_PAGE_SEL_REGISTER, NIM_I2C_0XA0,
+			NIM_PAGE_SEL_REGISTER, sizeof(curr_page_sel),
+			&curr_page_sel) != 0) {
+		return -1;
+	}
+
+	/* Only write new page select value if necessary */
+	if (page_sel != curr_page_sel) {
+		if (nim_read_write_i2c_data(ctx, NIM_WRITE, NIM_PAGE_SEL_REGISTER, NIM_I2C_0XA0,
+				NIM_PAGE_SEL_REGISTER, sizeof(page_sel),
+				&page_sel) != 0) {
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int nim_read_write_data_lin(nim_i2c_ctx_p ctx, bool m_page_addressing, uint16_t lin_addr,
+	uint16_t length, uint8_t *p_data, bool do_write)
+{
+	uint16_t i;
+	uint8_t a_reg_addr;	/* The actual register address in I2C device */
+	uint8_t i2c_addr;
+	int block_size = 128;	/* Equal to size of MSA pages */
+	int seq_cnt;
+	int max_seq_cnt = 1;
+	int multi_byte = 1;	/* One byte per I2C register is default */
+
+	for (i = 0; i < length;) {
+		bool use_page_select = false;
+
+		/*
+		 * Find out how much can be read from the current block in case of
+		 * single byte access
+		 */
+		if (multi_byte == 1)
+			max_seq_cnt = block_size - (lin_addr % block_size);
+
+		if (m_page_addressing) {
+			if (lin_addr >= 128) {	/* Only page setup above this address */
+				use_page_select = true;
+
+				/* Map to [128..255] of 0xA0 device */
+				a_reg_addr = (uint8_t)(block_size + (lin_addr % block_size));
+
+			} else {
+				a_reg_addr = (uint8_t)lin_addr;
+			}
+
+			i2c_addr = NIM_I2C_0XA0;/* Base I2C address */
+
+		} else if (lin_addr >= 256) {
+			/* Map to address [0..255] of 0xA2 device */
+			a_reg_addr = (uint8_t)(lin_addr - 256);
+			i2c_addr = NIM_I2C_0XA2;
+
+		} else {
+			a_reg_addr = (uint8_t)lin_addr;
+			i2c_addr = NIM_I2C_0XA0;/* Base I2C address */
+		}
+
+		/* Now actually do the reading/writing */
+		seq_cnt = length - i;	/* Number of remaining bytes */
+
+		if (seq_cnt > max_seq_cnt)
+			seq_cnt = max_seq_cnt;
+
+		/*
+		 * Read a number of bytes without explicitly specifying a new address.
+		 * This can speed up I2C access since automatic incrementation of the
+		 * I2C device internal address counter can be used. It also allows
+		 * a HW implementation, that can deal with block access.
+		 * Furthermore it also allows for access to data that must be accessed
+		 * as 16bit words reading two bytes at each address eg PHYs.
+		 */
+		if (use_page_select) {
+			if (nim_setup_page(ctx, (uint8_t)((lin_addr / 128) - 1)) != 0) {
+				NT_LOG(ERR, NTNIC,
+					"Cannot set up page for linear address %u\n", lin_addr);
+				return -1;
+			}
+		}
+
+		if (nim_read_write_i2c_data(ctx, do_write, lin_addr, i2c_addr, a_reg_addr,
+				(uint8_t)seq_cnt, p_data) != 0) {
+			NT_LOG(ERR, NTNIC, " Call to nim_read_write_i2c_data failed\n");
+			return -1;
+		}
+
+		p_data += seq_cnt;
+		i = (uint16_t)(i + seq_cnt);
+		lin_addr = (uint16_t)(lin_addr + (seq_cnt / multi_byte));
+	}
+
+	return 0;
+}
+
+static int nim_read_id(nim_i2c_ctx_t *ctx)
+{
+	/* We are only reading the first byte so we don't care about pages here. */
+	const bool USE_PAGE_ADDRESSING = false;
+
+	if (nim_read_write_data_lin(ctx, USE_PAGE_ADDRESSING, NIM_IDENTIFIER_ADDR,
+			sizeof(ctx->nim_id), &ctx->nim_id, NIM_READ) != 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int i2c_nim_common_construct(nim_i2c_ctx_p ctx)
+{
+	ctx->nim_id = 0;
+	int res;
+
+	if (ctx->type == I2C_HWIIC)
+		res = nim_read_id(ctx);
+
+	else
+		res = -1;
+
+	if (res) {
+		NT_LOG(ERR, PMD, "Can't read NIM id.");
+		return res;
+	}
+
+	memset(ctx->vendor_name, 0, sizeof(ctx->vendor_name));
+	memset(ctx->prod_no, 0, sizeof(ctx->prod_no));
+	memset(ctx->serial_no, 0, sizeof(ctx->serial_no));
+	memset(ctx->date, 0, sizeof(ctx->date));
+	memset(ctx->rev, 0, sizeof(ctx->rev));
+
+	ctx->content_valid = false;
+	memset(ctx->len_info, 0, sizeof(ctx->len_info));
+	ctx->pwr_level_req = 0;
+	ctx->pwr_level_cur = 0;
+	ctx->avg_pwr = false;
+	ctx->tx_disable = false;
+	ctx->lane_idx = -1;
+	ctx->lane_count = 1;
+	ctx->options = 0;
+	return 0;
+}
+
+const char *nim_id_to_text(uint8_t nim_id)
+{
+	switch (nim_id) {
+	case 0x0:
+		return "UNKNOWN";
+
+	default:
+		return "ILLEGAL!";
+	}
+}
+
+int construct_and_preinit_nim(nim_i2c_ctx_p ctx)
+{
+	int res = i2c_nim_common_construct(ctx);
+
+	return res;
+}
diff --git a/drivers/net/ntnic/nim/i2c_nim.h b/drivers/net/ntnic/nim/i2c_nim.h
new file mode 100644
index 0000000000..e89ae47835
--- /dev/null
+++ b/drivers/net/ntnic/nim/i2c_nim.h
@@ -0,0 +1,24 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef I2C_NIM_H_
+#define I2C_NIM_H_
+
+#include "ntnic_nim.h"
+
+/*
+ * Returns a type name such as "SFP/SFP+" for a given NIM type identifier,
+ * or the string "ILLEGAL!".
+ */
+const char *nim_id_to_text(uint8_t nim_id);
+
+/*
+ * This function tries to classify NIM based on it's ID and some register reads
+ * and collects information into ctx structure. The @extra parameter could contain
+ * the initialization argument for specific type of NIMS.
+ */
+int construct_and_preinit_nim(nim_i2c_ctx_p ctx);
+
+#endif	/* I2C_NIM_H_ */
diff --git a/drivers/net/ntnic/nim/nim_defines.h b/drivers/net/ntnic/nim/nim_defines.h
new file mode 100644
index 0000000000..9ba861bb4f
--- /dev/null
+++ b/drivers/net/ntnic/nim/nim_defines.h
@@ -0,0 +1,29 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef NIM_DEFINES_H_
+#define NIM_DEFINES_H_
+
+#define NIM_IDENTIFIER_ADDR 0	/* 1 byte */
+
+/* I2C addresses */
+#define NIM_I2C_0XA0 0xA0	/* Basic I2C address */
+#define NIM_I2C_0XA2 0xA2	/* Diagnostic monitoring */
+
+typedef enum {
+	NIM_OPTION_TX_DISABLE,
+	/* Indicates that the module should be checked for the two next FEC types */
+	NIM_OPTION_FEC,
+	NIM_OPTION_MEDIA_SIDE_FEC,
+	NIM_OPTION_HOST_SIDE_FEC,
+	NIM_OPTION_RX_ONLY
+} nim_option_t;
+
+enum nt_nim_identifier_e {
+	NT_NIM_UNKNOWN = 0x00,	/* Nim type is unknown */
+};
+typedef enum nt_nim_identifier_e nt_nim_identifier_t;
+
+#endif	/* NIM_DEFINES_H_ */
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_core.h b/drivers/net/ntnic/nthw/core/include/nthw_core.h
index 5648bd8983..8d9d78b86d 100644
--- a/drivers/net/ntnic/nthw/core/include/nthw_core.h
+++ b/drivers/net/ntnic/nthw/core/include/nthw_core.h
@@ -15,6 +15,7 @@
 #include "nthw_hif.h"
 #include "nthw_pcie3.h"
 #include "nthw_iic.h"
+#include "nthw_i2cm.h"
 
 #include "nthw_sdc.h"
 
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_i2cm.h b/drivers/net/ntnic/nthw/core/include/nthw_i2cm.h
new file mode 100644
index 0000000000..6e0ec4cf5e
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/include/nthw_i2cm.h
@@ -0,0 +1,50 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NTHW_II2CM_H__
+#define __NTHW_II2CM_H__
+
+#include "nthw_fpga_model.h"
+#include "pthread.h"
+
+struct nt_i2cm {
+	nthw_fpga_t *mp_fpga;
+
+	nthw_module_t *m_mod_i2cm;
+
+	int mn_i2c_instance;
+
+	nthw_register_t *mp_reg_prer_low;
+	nthw_field_t *mp_fld_prer_low_prer_low;
+
+	nthw_register_t *mp_reg_prer_high;
+	nthw_field_t *mp_fld_prer_high_prer_high;
+
+	nthw_register_t *mp_reg_ctrl;
+	nthw_field_t *mp_fld_ctrl_ien;
+	nthw_field_t *mp_fld_ctrl_en;
+
+	nthw_register_t *mp_reg_data;
+	nthw_field_t *mp_fld_data_data;
+
+	nthw_register_t *mp_reg_cmd_status;
+	nthw_field_t *mp_fld_cmd_status_cmd_status;
+
+	nthw_register_t *mp_reg_select;
+	nthw_field_t *mp_fld_select_select;
+
+	nthw_register_t *mp_reg_io_exp;
+	nthw_field_t *mp_fld_io_exp_rst;
+	nthw_field_t *mp_fld_io_exp_int_b;
+
+	pthread_mutex_t i2cmmutex;
+};
+
+typedef struct nt_i2cm nthw_i2cm_t;
+
+int nthw_i2cm_read(nthw_i2cm_t *p, uint8_t dev_addr, uint8_t reg_addr, uint8_t *value);
+int nthw_i2cm_write(nthw_i2cm_t *p, uint8_t dev_addr, uint8_t reg_addr, uint8_t value);
+
+#endif	/* __NTHW_II2CM_H__ */
diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga.c b/drivers/net/ntnic/nthw/core/nthw_fpga.c
index 38169176a5..d70205e5e3 100644
--- a/drivers/net/ntnic/nthw/core/nthw_fpga.c
+++ b/drivers/net/ntnic/nthw/core/nthw_fpga.c
@@ -19,12 +19,14 @@ int nthw_fpga_get_param_info(struct fpga_info_s *p_fpga_info, nthw_fpga_t *p_fpg
 {
 	mcu_info_t *p_mcu_info = &p_fpga_info->mcu_info;
 
+	const int n_nims = nthw_fpga_get_product_param(p_fpga, NT_NIMS, -1);
 	const int n_phy_ports = nthw_fpga_get_product_param(p_fpga, NT_PHY_PORTS, -1);
 	const int n_phy_quads = nthw_fpga_get_product_param(p_fpga, NT_PHY_QUADS, -1);
 	const int n_rx_ports = nthw_fpga_get_product_param(p_fpga, NT_RX_PORTS, -1);
 	const int n_tx_ports = nthw_fpga_get_product_param(p_fpga, NT_TX_PORTS, -1);
 	const int n_vf_offset = nthw_fpga_get_product_param(p_fpga, NT_HIF_VF_OFFSET, 4);
 
+	p_fpga_info->n_nims = n_nims;
 	p_fpga_info->n_phy_ports = n_phy_ports;
 	p_fpga_info->n_phy_quads = n_phy_quads;
 	p_fpga_info->n_rx_ports = n_rx_ports;
@@ -236,6 +238,7 @@ int nthw_fpga_init(struct fpga_info_s *p_fpga_info)
 	nthw_fpga_get_param_info(p_fpga_info, p_fpga);
 
 	/* debug: report params */
+	NT_LOG(DBG, NTHW, "%s: NT_NIMS=%d\n", p_adapter_id_str, p_fpga_info->n_nims);
 	NT_LOG(DBG, NTHW, "%s: NT_PHY_PORTS=%d\n", p_adapter_id_str, p_fpga_info->n_phy_ports);
 	NT_LOG(DBG, NTHW, "%s: NT_PHY_QUADS=%d\n", p_adapter_id_str, p_fpga_info->n_phy_quads);
 	NT_LOG(DBG, NTHW, "%s: NT_RX_PORTS=%d\n", p_adapter_id_str, p_fpga_info->n_rx_ports);
diff --git a/drivers/net/ntnic/nthw/core/nthw_i2cm.c b/drivers/net/ntnic/nthw/core/nthw_i2cm.c
new file mode 100644
index 0000000000..b5f8e299ff
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_i2cm.c
@@ -0,0 +1,192 @@
+/*
+ * 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_i2cm.h"
+
+#define NT_I2C_CMD_START 0x80
+#define NT_I2C_CMD_STOP 0x40
+#define NT_I2C_CMD_RD 0x20
+#define NT_I2C_CMD_WR 0x10
+#define NT_I2C_CMD_NACK 0x08
+#define NT_I2C_CMD_IRQ_ACK 0x01
+
+#define NT_I2C_STATUS_NACK 0x80
+#define NT_I2C_STATUS_TIP 0x02
+
+#define NT_I2C_TRANSMIT_WR 0x00
+#define NT_I2C_TRANSMIT_RD 0x01
+
+#define NUM_RETRIES 50U
+#define SLEEP_USECS 100U/* 0.1 ms */
+
+
+static bool nthw_i2cm_ready(nthw_i2cm_t *p, bool wait_for_ack)
+{
+	uint32_t flags = NT_I2C_STATUS_TIP | (wait_for_ack ? NT_I2C_STATUS_NACK : 0U);
+
+	for (uint32_t i = 0U; i < NUM_RETRIES; i++) {
+		uint32_t status = nthw_field_get_updated(p->mp_fld_cmd_status_cmd_status);
+		uint32_t ready = (status & flags) == 0U;
+		/* MUST have a short break to avoid time-outs, even if ready == true */
+		nt_os_wait_usec(SLEEP_USECS);
+
+		if (ready)
+			return true;
+	}
+
+	return false;
+}
+
+static int nthw_i2cm_write_internal(nthw_i2cm_t *p, uint8_t value)
+{
+	/* Write data to data register */
+	nthw_field_set_val_flush32(p->mp_fld_data_data, value);
+	nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+		NT_I2C_CMD_WR | NT_I2C_CMD_IRQ_ACK);
+
+	if (!nthw_i2cm_ready(p, true)) {
+		nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+			NT_I2C_CMD_STOP | NT_I2C_CMD_IRQ_ACK);
+		NT_LOG(ERR, NTHW, "%s: Time-out writing data %u", __PRETTY_FUNCTION__, value);
+		return 1;
+	}
+
+	/* Generate stop condition and clear interrupt */
+	nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+		NT_I2C_CMD_STOP | NT_I2C_CMD_IRQ_ACK);
+
+	if (!nthw_i2cm_ready(p, true)) {
+		nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+			NT_I2C_CMD_STOP | NT_I2C_CMD_IRQ_ACK);
+		NT_LOG(ERR, NTHW, "%s: Time-out sending stop condition", __PRETTY_FUNCTION__);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int nthw_i2cm_write_reg_addr_internal(nthw_i2cm_t *p, uint8_t dev_addr, uint8_t reg_addr,
+	bool send_stop)
+{
+	/* Write device address to data register */
+	nthw_field_set_val_flush32(p->mp_fld_data_data,
+		(uint8_t)(dev_addr << 1 | NT_I2C_TRANSMIT_WR));
+
+	/* #Set start condition along with secondary I2C dev_addr */
+	nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+		NT_I2C_CMD_START | NT_I2C_CMD_WR | NT_I2C_CMD_IRQ_ACK);
+
+	if (!nthw_i2cm_ready(p, true)) {
+		nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+			NT_I2C_CMD_STOP | NT_I2C_CMD_IRQ_ACK);
+		NT_LOG(ERR, NTHW, "%s: Time-out writing device address %u, reg_addr=%u",
+			__PRETTY_FUNCTION__, dev_addr, reg_addr);
+		return 1;
+	}
+
+	/* Writing I2C register address */
+	nthw_field_set_val_flush32(p->mp_fld_data_data, reg_addr);
+
+	if (send_stop) {
+		nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+			NT_I2C_CMD_WR | NT_I2C_CMD_IRQ_ACK | NT_I2C_CMD_STOP);
+
+	} else {
+		nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+			NT_I2C_CMD_WR | NT_I2C_CMD_IRQ_ACK);
+	}
+
+	if (!nthw_i2cm_ready(p, true)) {
+		nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+			NT_I2C_CMD_STOP | NT_I2C_CMD_IRQ_ACK);
+		NT_LOG(ERR, NTHW, "%s: Time-out writing register address %u", __PRETTY_FUNCTION__,
+			reg_addr);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int nthw_i2cm_read_internal(nthw_i2cm_t *p, uint8_t dev_addr, uint8_t *value)
+{
+	/* Write I2C device address - with LSBit set to READ */
+
+	nthw_field_set_val_flush32(p->mp_fld_data_data,
+		(uint8_t)(dev_addr << 1 | NT_I2C_TRANSMIT_RD));
+	/* #Send START condition along with secondary I2C dev_addr */
+	nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+		NT_I2C_CMD_START | NT_I2C_CMD_WR | NT_I2C_CMD_IRQ_ACK);
+
+	if (!nthw_i2cm_ready(p, true)) {
+		nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+			NT_I2C_CMD_STOP | NT_I2C_CMD_IRQ_ACK);
+		NT_LOG(ERR, NTHW, "%s: Time-out rewriting device address %u", __PRETTY_FUNCTION__,
+			dev_addr);
+		return 1;
+	}
+
+	nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+		NT_I2C_CMD_RD | NT_I2C_CMD_NACK | NT_I2C_CMD_IRQ_ACK);
+
+	if (!nthw_i2cm_ready(p, false)) {
+		nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+			NT_I2C_CMD_STOP | NT_I2C_CMD_IRQ_ACK);
+		NT_LOG(ERR, NTHW, "%s: Time-out during read operation", __PRETTY_FUNCTION__);
+		return 1;
+	}
+
+	*value = (uint8_t)nthw_field_get_updated(p->mp_fld_data_data);
+
+	/* Generate stop condition and clear interrupt */
+	nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+		NT_I2C_CMD_STOP | NT_I2C_CMD_IRQ_ACK);
+
+	if (!nthw_i2cm_ready(p, false)) {
+		nthw_field_set_val_flush32(p->mp_fld_cmd_status_cmd_status,
+			NT_I2C_CMD_STOP | NT_I2C_CMD_IRQ_ACK);
+		NT_LOG(ERR, NTHW, "%s: Time-out sending stop condition", __PRETTY_FUNCTION__);
+		return 1;
+	}
+
+	return 0;
+}
+
+int nthw_i2cm_read(nthw_i2cm_t *p, uint8_t dev_addr, uint8_t reg_addr, uint8_t *value)
+{
+	int status;
+	status = nthw_i2cm_write_reg_addr_internal(p, dev_addr, reg_addr, false);
+
+	if (status != 0)
+		return status;
+
+	status = nthw_i2cm_read_internal(p, dev_addr, value);
+
+	if (status != 0)
+		return status;
+
+	return 0;
+}
+
+int nthw_i2cm_write(nthw_i2cm_t *p, uint8_t dev_addr, uint8_t reg_addr, uint8_t value)
+{
+	int status;
+	status = nthw_i2cm_write_reg_addr_internal(p, dev_addr, reg_addr, false);
+
+	if (status != 0)
+		return status;
+
+	status = nthw_i2cm_write_internal(p, value);
+
+	if (status != 0)
+		return status;
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/nthw_drv.h b/drivers/net/ntnic/nthw/nthw_drv.h
index 071618eb6e..de60ae171e 100644
--- a/drivers/net/ntnic/nthw/nthw_drv.h
+++ b/drivers/net/ntnic/nthw/nthw_drv.h
@@ -52,6 +52,7 @@ typedef struct fpga_info_s {
 
 	int n_fpga_debug_mode;
 
+	int n_nims;
 	int n_phy_ports;
 	int n_phy_quads;
 	int n_rx_ports;
diff --git a/drivers/net/ntnic/ntnic_mod_reg.h b/drivers/net/ntnic/ntnic_mod_reg.h
index 68629412b7..3189b04f33 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.h
+++ b/drivers/net/ntnic/ntnic_mod_reg.h
@@ -22,6 +22,8 @@ const struct link_ops_s *get_100g_link_ops(void);
 void link_100g_init(void);
 
 struct port_ops {
+	bool (*get_nim_present)(struct adapter_info_s *p, int port);
+
 	/*
 	 * port:s link mode
 	 */
@@ -60,6 +62,11 @@ struct port_ops {
 
 	uint32_t (*get_link_speed_capabilities)(struct adapter_info_s *p, int port);
 
+	/*
+	 * port: nim capabilities
+	 */
+	nim_i2c_ctx_t (*get_nim_capabilities)(struct adapter_info_s *p, int port);
+
 	/*
 	 * port: tx power
 	 */
-- 
2.45.0


  parent reply	other threads:[~2024-06-27  7:42 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   ` [PATCH v5 10/23] net/ntnic: add core platform functionality Serhii Iliushyk
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   ` Serhii Iliushyk [this message]
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-18-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).