[PATCH v1 05/32] net/ntnic: add host loopback init

Serhii Iliushyk sil-plv at napatech.com
Thu Feb 20 23:03:29 CET 2025


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

Implement PHY line loopback configuration for Agilex FPGA

Signed-off-by: Danylo Vodopianov <dvo-plv at napatech.com>
---
 .../link_agx_100g/nt4ga_agx_link_100g.c       | 111 ++++++++++++++++++
 .../ntnic/nthw/core/include/nthw_phy_tile.h   |   1 +
 drivers/net/ntnic/nthw/core/nthw_phy_tile.c   |  28 +++++
 3 files changed, 140 insertions(+)

diff --git a/drivers/net/ntnic/link_mgmt/link_agx_100g/nt4ga_agx_link_100g.c b/drivers/net/ntnic/link_mgmt/link_agx_100g/nt4ga_agx_link_100g.c
index a6455ee598..f3862b7fe3 100644
--- a/drivers/net/ntnic/link_mgmt/link_agx_100g/nt4ga_agx_link_100g.c
+++ b/drivers/net/ntnic/link_mgmt/link_agx_100g/nt4ga_agx_link_100g.c
@@ -14,6 +14,11 @@
 #include "nthw_gfg.h"
 #include "nthw_phy_tile.h"
 
+typedef enum {
+	LOOPBACK_HOST_NONE,
+	LOOPBACK_HOST
+} loopback_host_t;
+
 static int nt4ga_agx_link_100g_ports_init(struct adapter_info_s *p_adapter_info,
 	nthw_fpga_t *fpga);
 
@@ -29,6 +34,65 @@ void link_agx_100g_init(void)
 	register_agx_100g_link_ops(&link_agx_100g_ops);
 }
 
+/*
+ * Phy handling
+ */
+
+static void phy_rx_path_rst(adapter_info_t *drv, int port, bool reset)
+{
+	nthw_phy_tile_t *p = drv->fpga_info.mp_nthw_agx.p_phy_tile;
+	NT_LOG(DBG, NTNIC, "Port %d: %s", port, reset ? "assert" : "deassert");
+	nthw_phy_tile_set_rx_reset(p, port, reset);
+}
+
+static void phy_tx_path_rst(adapter_info_t *drv, int port, bool reset)
+{
+	nthw_phy_tile_t *p = drv->fpga_info.mp_nthw_agx.p_phy_tile;
+	NT_LOG(DBG, NTNIC, "Port %d: %s", port, reset ? "assert" : "deassert");
+	nthw_phy_tile_set_tx_reset(p, port, reset);
+}
+
+static void phy_reset_rx(adapter_info_t *drv, int port)
+{
+	phy_rx_path_rst(drv, port, true);
+	nt_os_wait_usec(10000);	/* 10ms */
+	phy_rx_path_rst(drv, port, false);
+	nt_os_wait_usec(10000);	/* 10ms */
+}
+
+static void phy_reset_tx(adapter_info_t *drv, int port)
+{
+	phy_tx_path_rst(drv, port, true);
+	nt_os_wait_usec(10000);	/* 10ms */
+	phy_tx_path_rst(drv, port, false);
+	nt_os_wait_usec(10000);	/* 10ms */
+}
+
+static int phy_set_host_loopback(adapter_info_t *drv, int port, loopback_host_t loopback)
+{
+	nthw_phy_tile_t *p = drv->fpga_info.mp_nthw_agx.p_phy_tile;
+
+	switch (loopback) {
+	case LOOPBACK_HOST_NONE:
+		for (uint8_t lane = 0; lane < 4; lane++)
+			nthw_phy_tile_set_host_loopback(p, port, lane, false);
+
+		break;
+
+	case LOOPBACK_HOST:
+		for (uint8_t lane = 0; lane < 4; lane++)
+			nthw_phy_tile_set_host_loopback(p, port, lane, true);
+
+		break;
+
+	default:
+		NT_LOG(ERR, NTNIC, "Port %d: Unhandled loopback value (%d)", port, loopback);
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * Utility functions
  */
@@ -81,6 +145,40 @@ static int swap_tx_rx_polarity(adapter_info_t *drv, int port, bool swap)
 	return -1;
 }
 
+static void
+set_loopback(struct adapter_info_s *p_adapter_info, int port, uint32_t mode, uint32_t last_mode)
+{
+	switch (mode) {
+	case 1:
+		NT_LOG(INF, NTNIC, "%s: Applying host loopback",
+			p_adapter_info->mp_port_id_str[port]);
+		phy_set_host_loopback(p_adapter_info, port, LOOPBACK_HOST);
+		swap_tx_rx_polarity(p_adapter_info, port, false);
+		break;
+
+	default:
+		switch (last_mode) {
+		case 1:
+			NT_LOG(INF, NTNIC, "%s: Removing host loopback",
+				p_adapter_info->mp_port_id_str[port]);
+			phy_set_host_loopback(p_adapter_info, port, LOOPBACK_HOST_NONE);
+			swap_tx_rx_polarity(p_adapter_info, port, true);
+			break;
+
+		default:
+			/* do nothing */
+			break;
+		}
+
+		break;
+	}
+
+	/* After changing the loopback the system must be properly reset */
+	phy_reset_rx(p_adapter_info, port);
+	phy_reset_tx(p_adapter_info, port);
+	nt_os_wait_usec(10000);	/* 10ms - arbitrary choice */
+}
+
 /*
  * Link state machine
  */
@@ -146,6 +244,19 @@ static void *_common_ptp_nim_state_machine(void *data)
 			if (is_port_disabled)
 				continue;
 
+			if (link_info->port_action[i].port_lpbk_mode != last_lpbk_mode[i]) {
+				set_loopback(drv,
+					i,
+					link_info->port_action[i].port_lpbk_mode,
+					last_lpbk_mode[i]);
+
+				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;
+			}
+
 			link_state[i].link_disabled = is_port_disabled;
 
 			if (!link_state[i].nim_present) {
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_phy_tile.h b/drivers/net/ntnic/nthw/core/include/nthw_phy_tile.h
index 930c897046..5577f95944 100644
--- a/drivers/net/ntnic/nthw/core/include/nthw_phy_tile.h
+++ b/drivers/net/ntnic/nthw/core/include/nthw_phy_tile.h
@@ -52,6 +52,7 @@ void nthw_phy_tile_set_tx_pol_inv(nthw_phy_tile_t *p, uint8_t intf_no, uint8_t l
 void nthw_phy_tile_set_rx_pol_inv(nthw_phy_tile_t *p, uint8_t intf_no, uint8_t lane, bool invert);
 void nthw_phy_tile_set_host_loopback(nthw_phy_tile_t *p, uint8_t intf_no, uint8_t lane,
 	bool enable);
+void nthw_phy_tile_set_tx_reset(nthw_phy_tile_t *p, uint8_t intf_no, bool reset);
 void nthw_phy_tile_set_rx_reset(nthw_phy_tile_t *p, uint8_t intf_no, bool reset);
 
 uint32_t nthw_phy_tile_read_xcvr(nthw_phy_tile_t *p, uint8_t intf_no, uint8_t lane,
diff --git a/drivers/net/ntnic/nthw/core/nthw_phy_tile.c b/drivers/net/ntnic/nthw/core/nthw_phy_tile.c
index fd7a1e1214..6402e5caf3 100644
--- a/drivers/net/ntnic/nthw/core/nthw_phy_tile.c
+++ b/drivers/net/ntnic/nthw/core/nthw_phy_tile.c
@@ -64,6 +64,34 @@ void nthw_phy_tile_set_rx_reset(nthw_phy_tile_t *p, uint8_t intf_no, bool reset)
 	}
 }
 
+void nthw_phy_tile_set_tx_reset(nthw_phy_tile_t *p, uint8_t intf_no, bool reset)
+{
+	/* Reset is active low */
+	nthw_field_get_updated(p->mp_fld_port_config_tx_reset[intf_no]);
+
+	if (reset) {
+		nthw_field_clr_flush(p->mp_fld_port_config_tx_reset[intf_no]);
+
+		/* Wait for ack */
+		if (p->mp_fld_port_status_tx_reset_ackn[intf_no]) {
+			int32_t count = 1000;
+
+			do {
+				nt_os_wait_usec(1000);	/* 1ms */
+			} while (nthw_field_get_updated(p->mp_fld_port_status_tx_reset_ackn
+				[intf_no]) && (--count > 0));
+
+			if (count <= 0) {
+				NT_LOG(ERR, NTHW, "intf_no %u: Time-out waiting for TxResetAck",
+					intf_no);
+			}
+		}
+
+	} else {
+		nthw_field_set_flush(p->mp_fld_port_config_tx_reset[intf_no]);
+	}
+}
+
 uint32_t nthw_phy_tile_read_xcvr(nthw_phy_tile_t *p, uint8_t intf_no, uint8_t lane,
 	uint32_t address)
 {
-- 
2.45.0



More information about the dev mailing list