From: Danylo Vodopianov <dvo-...@napatech.com>

Implement PHY line loopback configuration for Agilex FPGA

Signed-off-by: Danylo Vodopianov <dvo-...@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

Reply via email to