[22/24] net/axgbe: add support for Rx adaptation

Message ID 20240412125249.10625-22-VenkatKumar.Ande@amd.com (mailing list archive)
State Changes Requested
Delegated to: Ferruh Yigit
Headers
Series [01/24] net/axgbe: remove use of comm_owned field |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Venkat Kumar Ande April 12, 2024, 12:52 p.m. UTC
  The existing implementation for non-Autonegotiation 10G speed modes does
not enable RX adaptation in the Driver and FW. The RX Equalization
settings (AFE settings alone) are manually configured and the existing
link-up sequence in the driver does not perform rx adaptation process as
mentioned in the Synopsys databook. There's a customer request for 10G
backplane mode without Auto-negotiation and for the DAC cables of more
significant length that follow the non-Autonegotiation mode. These modes
require PHY to perform RX Adaptation.

The proposed logic adds the necessary changes to Yellow Carp devices to
ensure seamless RX Adaptation for 10G-SFI (LONG DAC) and 10G-KR without
AN (CL72 not present). The RX adaptation core algorithm is executed by
firmware, however, to achieve that a new mailbox sub-command is required
to be sent by the driver.

Signed-off-by: Venkat Kumar Ande <VenkatKumar.Ande@amd.com>
---
 drivers/net/axgbe/axgbe_common.h   |  38 +++++++
 drivers/net/axgbe/axgbe_ethdev.h   |   5 +
 drivers/net/axgbe/axgbe_phy_impl.c | 170 ++++++++++++++++++++++++++++-
 3 files changed, 210 insertions(+), 3 deletions(-)
  

Patch

diff --git a/drivers/net/axgbe/axgbe_common.h b/drivers/net/axgbe/axgbe_common.h
index 1a43192630..0e1b2c1500 100644
--- a/drivers/net/axgbe/axgbe_common.h
+++ b/drivers/net/axgbe/axgbe_common.h
@@ -1274,6 +1274,22 @@ 
 #define MDIO_PMA_RX_CTRL1		0x8051
 #endif
 
+#ifndef MDIO_PMA_RX_LSTS
+#define MDIO_PMA_RX_LSTS		0x018020
+#endif
+
+#ifndef MDIO_PMA_RX_EQ_CTRL4
+#define MDIO_PMA_RX_EQ_CTRL4		0x0001805C
+#endif
+
+#ifndef MDIO_PMA_MP_MISC_STS
+#define MDIO_PMA_MP_MISC_STS		0x0078
+#endif
+
+#ifndef MDIO_PMA_PHY_RX_EQ_CEU
+#define MDIO_PMA_PHY_RX_EQ_CEU		0x1800E
+#endif
+
 #ifndef MDIO_PCS_DIG_CTRL
 #define MDIO_PCS_DIG_CTRL		0x8000
 #endif
@@ -1415,6 +1431,28 @@  static inline uint32_t high32_value(uint64_t addr)
 #define XGBE_PMA_RX_RST_0_RESET_ON     0x10
 #define XGBE_PMA_RX_RST_0_RESET_OFF    0x00
 
+#define XGBE_PMA_RX_SIG_DET_0_MASK	BIT(4)
+#define XGBE_PMA_RX_SIG_DET_0_ENABLE	BIT(4)
+#define XGBE_PMA_RX_SIG_DET_0_DISABLE	0x0000
+
+#define XGBE_PMA_RX_VALID_0_MASK	BIT(12)
+#define XGBE_PMA_RX_VALID_0_ENABLE	BIT(12)
+#define XGBE_PMA_RX_VALID_0_DISABLE	0x0000
+
+#define XGBE_PMA_RX_AD_REQ_MASK		BIT(12)
+#define XGBE_PMA_RX_AD_REQ_ENABLE	BIT(12)
+#define XGBE_PMA_RX_AD_REQ_DISABLE	0x0000
+
+#define XGBE_PMA_RX_ADPT_ACK_MASK	BIT(12)
+#define XGBE_PMA_RX_ADPT_ACK		BIT(12)
+
+#define XGBE_PMA_CFF_UPDTM1_VLD		BIT(8)
+#define XGBE_PMA_CFF_UPDT0_VLD		BIT(9)
+#define XGBE_PMA_CFF_UPDT1_VLD		BIT(10)
+#define XGBE_PMA_CFF_UPDT_MASK		(XGBE_PMA_CFF_UPDTM1_VLD |\
+					 XGBE_PMA_CFF_UPDT0_VLD | \
+					 XGBE_PMA_CFF_UPDT1_VLD)
+
 /*END*/
 
 /* Bit setting and getting macros
diff --git a/drivers/net/axgbe/axgbe_ethdev.h b/drivers/net/axgbe/axgbe_ethdev.h
index cb3df47a63..dd00ae8af5 100644
--- a/drivers/net/axgbe/axgbe_ethdev.h
+++ b/drivers/net/axgbe/axgbe_ethdev.h
@@ -244,6 +244,7 @@  enum axgbe_mb_cmd {
 
 enum axgbe_mb_subcmd {
 	AXGBE_MB_SUBCMD_NONE = 0,
+	AXGBE_MB_SUBCMD_RX_ADAP,
 
 	/* 10GbE SFP subcommands */
 	AXGBE_MB_SUBCMD_ACTIVE = 0,
@@ -722,6 +723,10 @@  struct axgbe_port {
 	struct rte_timecounter tx_tstamp;
 	unsigned int tstamp_addend;
 
+	bool en_rx_adap;
+	int rx_adapt_retries;
+	bool rx_adapt_done;
+	bool mode_set;
 };
 
 void axgbe_init_function_ptrs_dev(struct axgbe_hw_if *hw_if);
diff --git a/drivers/net/axgbe/axgbe_phy_impl.c b/drivers/net/axgbe/axgbe_phy_impl.c
index 13b37e9b8b..a1c42b7dd4 100644
--- a/drivers/net/axgbe/axgbe_phy_impl.c
+++ b/drivers/net/axgbe/axgbe_phy_impl.c
@@ -247,6 +247,10 @@  struct axgbe_phy_data {
 };
 
 static enum axgbe_an_mode axgbe_phy_an_mode(struct axgbe_port *pdata);
+static void axgbe_phy_perform_ratechange(struct axgbe_port *pdata,
+		enum axgbe_mb_cmd cmd, enum axgbe_mb_subcmd sub_cmd);
+static void axgbe_phy_rrc(struct axgbe_port *pdata);
+
 
 static int axgbe_phy_i2c_xfer(struct axgbe_port *pdata,
 			      struct axgbe_i2c_op *i2c_op)
@@ -1194,6 +1198,92 @@  static void axgbe_phy_set_redrv_mode(struct axgbe_port *pdata)
 	axgbe_phy_put_comm_ownership(pdata);
 }
 
+#define MAX_RX_ADAPT_RETRIES		1
+#define XGBE_PMA_RX_VAL_SIG_MASK	(XGBE_PMA_RX_SIG_DET_0_MASK | \
+					 XGBE_PMA_RX_VALID_0_MASK)
+
+static void axgbe_set_rx_adap_mode(struct axgbe_port *pdata,
+				  enum axgbe_mode mode)
+{
+	if (pdata->rx_adapt_retries++ >= MAX_RX_ADAPT_RETRIES) {
+		pdata->rx_adapt_retries = 0;
+		return;
+	}
+
+	axgbe_phy_perform_ratechange(pdata,
+				    mode == AXGBE_MODE_KR ?
+				    AXGBE_MB_CMD_SET_10G_KR :
+				    AXGBE_MB_CMD_SET_10G_SFI,
+				    AXGBE_MB_SUBCMD_RX_ADAP);
+}
+
+static void axgbe_rx_adaptation(struct axgbe_port *pdata)
+{
+	struct axgbe_phy_data *phy_data = pdata->phy_data;
+	unsigned int reg;
+
+	/* step 2: force PCS to send RX_ADAPT Req to PHY */
+	XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL4,
+			 XGBE_PMA_RX_AD_REQ_MASK, XGBE_PMA_RX_AD_REQ_ENABLE);
+
+	/* Step 3: Wait for RX_ADAPT ACK from the PHY */
+	rte_delay_ms(200);
+
+	/* Software polls for coefficient update command (given by local PHY) */
+	reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_PHY_RX_EQ_CEU);
+
+	/* Clear the RX_AD_REQ bit */
+	XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL4,
+			 XGBE_PMA_RX_AD_REQ_MASK, XGBE_PMA_RX_AD_REQ_DISABLE);
+
+	/* Check if coefficient update command is set */
+	if ((reg & XGBE_PMA_CFF_UPDT_MASK) != XGBE_PMA_CFF_UPDT_MASK)
+		goto set_mode;
+
+	/* Step 4: Check for Block lock */
+
+	/* Link status is latched low, so read once to clear
+	 * and then read again to get current state
+	 */
+	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
+	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
+	if (reg & MDIO_STAT1_LSTATUS) {
+		/* If the block lock is found, update the helpers
+		 * and declare the link up
+		 */
+		PMD_DRV_LOG(NOTICE, "Rx adaptation - Block_lock done\n");
+		pdata->rx_adapt_done = true;
+		pdata->mode_set = false;
+		return;
+	}
+
+set_mode:
+	axgbe_set_rx_adap_mode(pdata, phy_data->cur_mode);
+}
+
+static void axgbe_phy_rx_adaptation(struct axgbe_port *pdata)
+{
+	unsigned int reg;
+
+rx_adapt_reinit:
+	reg = XMDIO_READ_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_LSTS,
+			      XGBE_PMA_RX_VAL_SIG_MASK);
+
+	/* step 1: Check for RX_VALID && LF_SIGDET */
+	if ((reg & XGBE_PMA_RX_VAL_SIG_MASK) != XGBE_PMA_RX_VAL_SIG_MASK) {
+		PMD_DRV_LOG(NOTICE, "RX_VALID or LF_SIGDET is unset, issue rrc\n");
+		axgbe_phy_rrc(pdata);
+		if (pdata->rx_adapt_retries++ >= MAX_RX_ADAPT_RETRIES) {
+			pdata->rx_adapt_retries = 0;
+			return;
+		}
+		goto rx_adapt_reinit;
+	}
+
+	/* perform rx adaptation */
+	axgbe_rx_adaptation(pdata);
+}
+
 static void axgbe_phy_rx_reset(struct axgbe_port *pdata)
 {
 	int reg;
@@ -1258,12 +1348,27 @@  static void axgbe_phy_perform_ratechange(struct axgbe_port *pdata,
 	wait = AXGBE_RATECHANGE_COUNT;
 	while (wait--) {
 		if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS))
-			goto reenable_pll;
+			goto do_rx_adaptation;
 		rte_delay_us(1500);
 	}
 	PMD_DRV_LOG(NOTICE, "firmware mailbox command did not complete\n");
 	/* Reset on error */
 	axgbe_phy_rx_reset(pdata);
+	goto reenable_pll;
+
+
+do_rx_adaptation:
+	if (pdata->en_rx_adap && sub_cmd == AXGBE_MB_SUBCMD_RX_ADAP &&
+	    (cmd == AXGBE_MB_CMD_SET_10G_KR || cmd == AXGBE_MB_CMD_SET_10G_SFI)) {
+		PMD_DRV_LOG(NOTICE, "Enabling RX adaptation\n");
+		pdata->mode_set = true;
+		axgbe_phy_rx_adaptation(pdata);
+		/* return from here to avoid enabling PLL ctrl
+		 * during adaptation phase
+		 */
+		return;
+	}
+
 
 reenable_pll:
 	/* Enable PLL re-initialization, not needed for PHY Power Off and RRC cmds */
@@ -1296,6 +1401,31 @@  static void axgbe_phy_power_off(struct axgbe_port *pdata)
 	PMD_DRV_LOG(DEBUG, "phy powered off\n");
 }
 
+static bool enable_rx_adap(struct axgbe_port *pdata, enum axgbe_mode mode)
+{
+	struct axgbe_phy_data *phy_data = pdata->phy_data;
+	unsigned int ver;
+
+	/* Rx-Adaptation is not supported on older platforms(< 0x30H) */
+	ver = AXGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER);
+	if (ver < 0x30)
+		return false;
+
+	/* Re-driver models 4223 && 4227 do not support Rx-Adaptation */
+	if (phy_data->redrv &&
+	    (phy_data->redrv_model == AXGBE_PHY_REDRV_MODEL_4223 ||
+	     phy_data->redrv_model == AXGBE_PHY_REDRV_MODEL_4227))
+		return false;
+
+	/* 10G KR mode with AN does not support Rx-Adaptation */
+	if (mode == AXGBE_MODE_KR &&
+	    phy_data->port_mode != AXGBE_PORT_MODE_BACKPLANE_NO_AUTONEG)
+		return false;
+
+	pdata->en_rx_adap = 1;
+	return true;
+}
+
 static void axgbe_phy_sfi_mode(struct axgbe_port *pdata)
 {
 	struct axgbe_phy_data *phy_data = pdata->phy_data;
@@ -1304,8 +1434,13 @@  static void axgbe_phy_sfi_mode(struct axgbe_port *pdata)
 
 	/* 10G/SFI */
 	if (phy_data->sfp_cable != AXGBE_SFP_CABLE_PASSIVE) {
+		pdata->en_rx_adap = 0;
 		axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_10G_SFI,
 							AXGBE_MB_SUBCMD_ACTIVE);
+	} else if ((phy_data->sfp_cable == AXGBE_SFP_CABLE_PASSIVE) &&
+				(enable_rx_adap(pdata, AXGBE_MODE_SFI))) {
+		axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_10G_SFI,
+						AXGBE_MB_SUBCMD_RX_ADAP);
 	} else {
 		if (phy_data->sfp_cable_len <= 1)
 			axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_10G_SFI,
@@ -1330,6 +1465,10 @@  static void axgbe_phy_kr_mode(struct axgbe_port *pdata)
 	axgbe_phy_set_redrv_mode(pdata);
 
 	/* 10G/KR */
+	if (enable_rx_adap(pdata, AXGBE_MODE_KR))
+		axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_10G_KR,
+						AXGBE_MB_SUBCMD_RX_ADAP);
+	else
 		axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_10G_KR,
 						AXGBE_MB_SUBCMD_NONE);
 	phy_data->cur_mode = AXGBE_MODE_KR;
@@ -1719,8 +1858,11 @@  static int axgbe_phy_link_status(struct axgbe_port *pdata, int *an_restart)
 			return 0;
 		}
 
-		if (phy_data->sfp_mod_absent || phy_data->sfp_rx_los)
+		if (phy_data->sfp_mod_absent || phy_data->sfp_rx_los) {
+			if (pdata->en_rx_adap)
+				pdata->rx_adapt_done = false;
 			return 0;
+		}
 	}
 
 	/* Link status is latched low, so read once to clear
@@ -1728,7 +1870,29 @@  static int axgbe_phy_link_status(struct axgbe_port *pdata, int *an_restart)
 	 */
 	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
 	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
-	if (reg & MDIO_STAT1_LSTATUS)
+
+	if (pdata->en_rx_adap) {
+		/* if the link is available and adaptation is done,
+		 * declare link up
+		 */
+		if ((reg & MDIO_STAT1_LSTATUS) && pdata->rx_adapt_done)
+			return 1;
+		/* If either link is not available or adaptation is not done,
+		 * retrigger the adaptation logic. (if the mode is not set,
+		 * then issue mailbox command first)
+		 */
+		if (pdata->mode_set) {
+			axgbe_phy_rx_adaptation(pdata);
+		} else {
+			pdata->rx_adapt_done = false;
+			axgbe_phy_set_mode(pdata, phy_data->cur_mode);
+		}
+
+		/* check again for the link and adaptation status */
+		reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
+		if ((reg & MDIO_STAT1_LSTATUS) && pdata->rx_adapt_done)
+			return 1;
+	} else if (reg & MDIO_STAT1_LSTATUS)
 		return 1;
 
 	if (pdata->phy.autoneg == AUTONEG_ENABLE &&