* [PATCH v7 10/21] net/txgbe: fix a mass of unknown interrupts
From: Zaiyu Wang @ 2026-06-17 3:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu, Ferruh Yigit
In-Reply-To: <20260617033400.376-1-zaiyuwang@trustnetic.com>
When RSC is enabled, Rx ring IVAR is set to configure ITR. It causes Rx
ring interrupts report on the default msix_vector. Thus a mass of unknown
interrupts occupy CPU.
Fix the issue by setting ring IVAR only when the rxq interrupt is enabled.
Fixes: be797cbf4582 ("net/txgbe: add Rx and Tx init")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/txgbe_rxtx.c | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index d6efb3b8cc..2d0c4989d9 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -4347,6 +4347,8 @@ static int
txgbe_set_rsc(struct rte_eth_dev *dev)
{
struct rte_eth_rxmode *rx_conf = &dev->data->dev_conf.rxmode;
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
struct rte_eth_dev_info dev_info = { 0 };
bool rsc_capable = false;
@@ -4397,8 +4399,6 @@ txgbe_set_rsc(struct rte_eth_dev *dev)
rd32(hw, TXGBE_RXCFG(rxq->reg_idx));
uint32_t psrtype =
rd32(hw, TXGBE_POOLRSS(rxq->reg_idx));
- uint32_t eitr =
- rd32(hw, TXGBE_ITR(rxq->reg_idx));
/*
* txgbe PMD doesn't support header-split at the moment.
@@ -4417,6 +4417,9 @@ txgbe_set_rsc(struct rte_eth_dev *dev)
srrctl |= txgbe_get_rscctl_maxdesc(rxq->mb_pool);
psrtype |= TXGBE_POOLRSS_L4HDR;
+ wr32(hw, TXGBE_RXCFG(rxq->reg_idx), srrctl);
+ wr32(hw, TXGBE_POOLRSS(rxq->reg_idx), psrtype);
+
/*
* RSC: Set ITR interval corresponding to 2K ints/s.
*
@@ -4430,19 +4433,20 @@ txgbe_set_rsc(struct rte_eth_dev *dev)
* For a sparse streaming case this setting will yield
* at most 500us latency for a single RSC aggregation.
*/
- eitr &= ~TXGBE_ITR_IVAL_MASK;
- eitr |= TXGBE_ITR_IVAL_10G(TXGBE_QUEUE_ITR_INTERVAL_DEFAULT);
- eitr |= TXGBE_ITR_WRDSA;
+ if (rte_intr_dp_is_en(intr_handle)) {
+ uint32_t eitr = rd32(hw, TXGBE_ITR(rxq->reg_idx));
- wr32(hw, TXGBE_RXCFG(rxq->reg_idx), srrctl);
- wr32(hw, TXGBE_POOLRSS(rxq->reg_idx), psrtype);
- wr32(hw, TXGBE_ITR(rxq->reg_idx), eitr);
+ eitr &= ~TXGBE_ITR_IVAL_MASK;
+ eitr |= TXGBE_ITR_IVAL_10G(TXGBE_QUEUE_ITR_INTERVAL_DEFAULT);
+ eitr |= TXGBE_ITR_WRDSA;
+ wr32(hw, TXGBE_ITR(rxq->reg_idx), eitr);
- /*
- * RSC requires the mapping of the queue to the
- * interrupt vector.
- */
- txgbe_set_ivar_map(hw, 0, rxq->reg_idx, i);
+ /*
+ * RSC requires the mapping of the queue to the
+ * interrupt vector.
+ */
+ txgbe_set_ivar_map(hw, 0, rxq->reg_idx, i);
+ }
}
dev->data->lro = 1;
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v7 11/21] net/txgbe: fix traffic class priority configuration
From: Zaiyu Wang @ 2026-06-17 3:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu, Ferruh Yigit
In-Reply-To: <20260617033400.376-1-zaiyuwang@trustnetic.com>
After applying the following testpmd command, 802.1Q packets with specific
priorities were not properly directed to the corresponding traffic classes:
port config 0 dcb vt off 4 pfc off
The old driver had two issues:
1. The hardware uses a 4-bit mapping register per traffic class for
priority-to-TC mapping, but the driver incorrectly configured it
as 3 bits.
2. The DCB TX configuration mistakenly wrote to the RX register.
Fix both issues, ensuring that tc-prio mapping works as expected.
Additionally, remove the stale and inconsistent TXGBE_DCBUP2TC_DEC macro as
it has no callers.
Fixes: 8bdc7882f376 ("net/txgbe: support DCB")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_dcb_hw.c | 2 +-
drivers/net/txgbe/base/txgbe_regs.h | 6 ++----
drivers/net/txgbe/txgbe_rxtx.c | 7 ++-----
3 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_dcb_hw.c b/drivers/net/txgbe/base/txgbe_dcb_hw.c
index 75c91a6b6a..79e1da447b 100644
--- a/drivers/net/txgbe/base/txgbe_dcb_hw.c
+++ b/drivers/net/txgbe/base/txgbe_dcb_hw.c
@@ -154,7 +154,7 @@ s32 txgbe_dcb_config_tx_data_arbiter_raptor(struct txgbe_hw *hw, u16 *refill,
for (i = 0; i < TXGBE_DCB_UP_MAX; i++)
reg |= TXGBE_DCBUP2TC_MAP(i, map[i]);
- wr32(hw, TXGBE_PBRXUP2TC, reg);
+ wr32(hw, TXGBE_PBTXUP2TC, reg);
/* Configure traffic class credits and priority */
for (i = 0; i < TXGBE_DCB_TC_MAX; i++) {
diff --git a/drivers/net/txgbe/base/txgbe_regs.h b/drivers/net/txgbe/base/txgbe_regs.h
index 22c46e3d56..4aa62919b4 100644
--- a/drivers/net/txgbe/base/txgbe_regs.h
+++ b/drivers/net/txgbe/base/txgbe_regs.h
@@ -503,10 +503,8 @@
#define TXGBE_PBRXCTL 0x019000
#define TXGBE_PBRXCTL_ST MS(0, 0x1)
#define TXGBE_PBRXCTL_ENA MS(31, 0x1)
-#define TXGBE_PBRXUP2TC 0x019008
#define TXGBE_PBTXUP2TC 0x01C800
-#define TXGBE_DCBUP2TC_MAP(tc, v) LS(v, 3 * (tc), 0x7)
-#define TXGBE_DCBUP2TC_DEC(tc, r) RS(r, 3 * (tc), 0x7)
+#define TXGBE_DCBUP2TC_MAP(tc, v) LS(v, 4 * (tc), 0x7)
#define TXGBE_PBRXSIZE(tc) (0x019020 + (tc) * 4)
#define TXGBE_PBRXSIZE_KB(v) LS(v, 10, 0x3FF)
@@ -1705,7 +1703,7 @@ enum txgbe_5tuple_protocol {
#define TXGBE_RDM_PF_HIDE(_i) (0x12090 + ((_i) * 4))
#define TXGBE_RPUP2TC 0x019008
-#define TXGBE_RPUP2TC_UP_SHIFT 3
+#define TXGBE_RPUP2TC_UP_SHIFT 4
#define TXGBE_RPUP2TC_UP_MASK 0x7
#define TXGBE_RDM_DCACHE_CTL 0x0120A8
diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index 2d0c4989d9..4611124b68 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -3378,11 +3378,8 @@ txgbe_vmdq_dcb_configure(struct rte_eth_dev *dev)
queue_mapping = 0;
for (i = 0; i < RTE_ETH_DCB_NUM_USER_PRIORITIES; i++)
- /*
- * mapping is done with 3 bits per priority,
- * so shift by i*3 each time
- */
- queue_mapping |= ((cfg->dcb_tc[i] & 0x07) << (i * 3));
+ queue_mapping |= ((cfg->dcb_tc[i] & TXGBE_RPUP2TC_UP_MASK) <<
+ (i * TXGBE_RPUP2TC_UP_SHIFT));
wr32(hw, TXGBE_RPUP2TC, queue_mapping);
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v7 13/21] net/txgbe: fix link stability for 40G NIC
From: Zaiyu Wang @ 2026-06-17 3:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617033400.376-1-zaiyuwang@trustnetic.com>
The link was previously configured via firmware, but this approach
resulted in unstable link behavior. To resolve the issue, re-add the
PHY configuration flow directly into the driver.
Fixes: ead3616f630d ("net/txgbe: support PHY configuration via SW-FW mailbox")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_aml40.c | 73 +-
drivers/net/txgbe/base/txgbe_aml40.h | 6 +-
drivers/net/txgbe/base/txgbe_e56.c | 1473 ++++++++++++++++++++++++--
drivers/net/txgbe/base/txgbe_e56.h | 9 +-
drivers/net/txgbe/txgbe_ethdev.c | 4 +-
5 files changed, 1447 insertions(+), 118 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index eefd7119fd..09bc7ed58c 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -13,6 +13,7 @@
#include "txgbe_hw.h"
#include "txgbe_aml.h"
#include "txgbe_aml40.h"
+#include "txgbe_e56.h"
void txgbe_init_ops_aml40(struct txgbe_hw *hw)
{
@@ -24,6 +25,7 @@ void txgbe_init_ops_aml40(struct txgbe_hw *hw)
/* PHY */
phy->get_media_type = txgbe_get_media_type_aml40;
+ phy->setup_link_core = txgbe_setup_phy_link_aml40;
/* LINK */
mac->init_mac_link_ops = txgbe_init_mac_link_ops_aml40;
@@ -52,6 +54,13 @@ s32 txgbe_check_mac_link_aml40(struct txgbe_hw *hw, u32 *speed,
if (link_up_wait_to_complete) {
for (i = 0; i < hw->mac.max_link_up_time; i++) {
+ if (!hw->link_valid) {
+ *link_up = false;
+
+ msleep(100);
+ continue;
+ }
+
if (!(links_reg & TXGBE_PORTSTAT_UP)) {
*link_up = false;
} else {
@@ -68,6 +77,9 @@ s32 txgbe_check_mac_link_aml40(struct txgbe_hw *hw, u32 *speed,
*link_up = false;
}
+ if (!hw->link_valid)
+ *link_up = false;
+
if (*link_up) {
if ((links_reg & TXGBE_CFG_PORT_ST_AML_LINK_40G) ==
TXGBE_CFG_PORT_ST_AML_LINK_40G)
@@ -107,20 +119,24 @@ u32 txgbe_get_media_type_aml40(struct txgbe_hw *hw)
return txgbe_media_type_fiber_qsfp;
}
-s32 txgbe_setup_mac_link_aml40(struct txgbe_hw *hw,
- u32 speed,
- bool autoneg_wait_to_complete)
+s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
+ u32 speed,
+ bool autoneg_wait_to_complete,
+ bool *need_reset)
{
bool autoneg = false;
s32 status = 0;
+ s32 ret_status = 0;
u32 link_speed = TXGBE_LINK_SPEED_UNKNOWN;
bool link_up = false;
+ int i;
u32 link_capabilities = TXGBE_LINK_SPEED_UNKNOWN;
+ u32 value;
- if (hw->phy.sfp_type == txgbe_sfp_type_not_present) {
- DEBUGOUT("SFP not detected, skip setup mac link");
- return 0;
- }
+ *need_reset = false;
+
+ if (hw->phy.sfp_type == txgbe_sfp_type_not_present)
+ hw->phy.identify_sfp(hw);
/* Check to see if speed passed in is supported. */
status = hw->mac.get_link_capabilities(hw,
@@ -132,18 +148,42 @@ s32 txgbe_setup_mac_link_aml40(struct txgbe_hw *hw,
if (speed == TXGBE_LINK_SPEED_UNKNOWN)
return TXGBE_ERR_LINK_SETUP;
- status = hw->mac.check_link(hw, &link_speed, &link_up,
- autoneg_wait_to_complete);
+ for (i = 0; i < 4; i++) {
+ txgbe_e56_check_phy_link(hw, &link_speed, &link_up);
+ if (link_up)
+ break;
+ msleep(250);
+ }
if (link_speed == speed && link_up)
- return status;
-
- if (speed & TXGBE_LINK_SPEED_40GB_FULL)
- speed = 0x20;
-
- status = hw->phy.set_link_hostif(hw, (u8)speed, autoneg, true);
+ goto out;
+
+ rte_spinlock_lock(&hw->phy_lock);
+ ret_status = txgbe_set_link_to_amlite(hw, speed);
+ if (ret_status == TXGBE_ERR_TIMEOUT)
+ hw->link_valid = false;
+ rte_spinlock_unlock(&hw->phy_lock);
+
+ for (i = 0; i < 4; i++) {
+ txgbe_e56_check_phy_link(hw, &link_speed, &link_up);
+ if (link_up)
+ goto out;
+ msleep(250);
+ }
- txgbe_wait_for_link_up_aml(hw, speed);
+out:
+ if (link_up) {
+ value = rd32(hw, TXGBE_PORTSTAT);
+ if (!(value & TXGBE_PORTSTAT_UP)) {
+ DEBUGOUT("MAC link 0x14404: 0x%x", value);
+ *need_reset = true;
+ value = rd32(hw, 0x110b0);
+ DEBUGOUT("MAC intr status 0x110b0: 0x%x", value);
+ }
+ } else {
+ *need_reset = true;
+ DEBUGOUT("Link reconfiguration required. Reset scheduled in 2000ms.");
+ }
return status;
}
@@ -159,6 +199,5 @@ void txgbe_init_mac_link_ops_aml40(struct txgbe_hw *hw)
mac->flap_tx_laser =
txgbe_flap_tx_laser_multispeed_fiber;
- mac->setup_link = txgbe_setup_mac_link_aml40;
mac->set_rate_select_speed = txgbe_set_hard_rate_select_speed;
}
diff --git a/drivers/net/txgbe/base/txgbe_aml40.h b/drivers/net/txgbe/base/txgbe_aml40.h
index f31360c899..d97654fbf8 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.h
+++ b/drivers/net/txgbe/base/txgbe_aml40.h
@@ -14,7 +14,9 @@ s32 txgbe_check_mac_link_aml40(struct txgbe_hw *hw,
s32 txgbe_get_link_capabilities_aml40(struct txgbe_hw *hw,
u32 *speed, bool *autoneg);
u32 txgbe_get_media_type_aml40(struct txgbe_hw *hw);
-s32 txgbe_setup_mac_link_aml40(struct txgbe_hw *hw, u32 speed,
- bool autoneg_wait_to_complete);
+s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
+ u32 speed,
+ bool autoneg_wait_to_complete,
+ bool *need_reset);
void txgbe_init_mac_link_ops_aml40(struct txgbe_hw *hw);
#endif /* _TXGBE_AML40_H_ */
diff --git a/drivers/net/txgbe/base/txgbe_e56.c b/drivers/net/txgbe/base/txgbe_e56.c
index 870f4135ed..3566d13426 100644
--- a/drivers/net/txgbe/base/txgbe_e56.c
+++ b/drivers/net/txgbe/base/txgbe_e56.c
@@ -102,11 +102,29 @@ u32 txgbe_e56_tx_ffe_cfg(struct txgbe_hw *hw, u32 speed)
} else if (speed == TXGBE_LINK_SPEED_25GB_FULL) {
if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1) {
+ ffe_main = S25G_TX_FFE_CFG_DAC_MAIN;
+ pre1 = S25G_TX_FFE_CFG_DAC_PRE1;
+ pre2 = S25G_TX_FFE_CFG_DAC_PRE2;
+ post = S25G_TX_FFE_CFG_DAC_POST;
+ } else {
ffe_main = S25G_TX_FFE_CFG_MAIN;
pre1 = S25G_TX_FFE_CFG_PRE1;
pre2 = S25G_TX_FFE_CFG_PRE2;
post = S25G_TX_FFE_CFG_POST;
}
+ } else if (speed == TXGBE_LINK_SPEED_40GB_FULL) {
+ ffe_main = S10G_TX_FFE_CFG_MAIN;
+ pre1 = S10G_TX_FFE_CFG_PRE1;
+ pre2 = S10G_TX_FFE_CFG_PRE2;
+ post = S10G_TX_FFE_CFG_POST;
+
+ if (hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core0 ||
+ hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core1) {
+ ffe_main = S40G_TX_FFE_CFG_MAIN;
+ pre1 = S40G_TX_FFE_CFG_PRE1;
+ pre2 = S40G_TX_FFE_CFG_PRE2;
+ post = S40G_TX_FFE_CFG_POST;
+ }
}
if (hw->phy.ffe_set) {
@@ -154,6 +172,416 @@ txgbe_e56_get_temp(struct txgbe_hw *hw, int *temp)
return 0;
}
+u32 txgbe_e56_cfg_40g(struct txgbe_hw *hw)
+{
+ u32 addr;
+ u32 rdata = 0;
+ int i;
+
+ /* CMS Config Master */
+ addr = E56G_CMS_ANA_OVRDVAL_7_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ ((E56G_CMS_ANA_OVRDVAL_7 *)&rdata)->ana_lcpll_lf_vco_swing_ctrl_i = 0xf;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G_CMS_ANA_OVRDEN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ ((E56G_CMS_ANA_OVRDEN_1 *)&rdata)->ovrd_en_ana_lcpll_lf_vco_swing_ctrl_i = 0x1;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G_CMS_ANA_OVRDVAL_9_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 23, 0, 0x260000);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G_CMS_ANA_OVRDEN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ ((E56G_CMS_ANA_OVRDEN_1 *)&rdata)->ovrd_en_ana_lcpll_lf_test_in_i = 0x1;
+ wr32_ephy(hw, addr, rdata);
+
+ /* TXS Config Master */
+ for (i = 0; i < 4; i++) {
+ addr = E56PHY_TXS_TXS_CFG_1_ADDR + (E56PHY_TXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_TXS_CFG_1_ADAPTATION_WAIT_CNT_X256, 0xf);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_TXS_WKUP_CNT_ADDR + (E56PHY_TXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_WKUP_CNTLDO_WKUP_CNT_X32, 0xff);
+ set_fields_e56(&rdata, E56PHY_TXS_WKUP_CNTDCC_WKUP_CNT_X32, 0xff);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_TXS_PIN_OVRDVAL_6_ADDR + (E56PHY_TXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 19, 16, 0x6);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_TXS_PIN_OVRDEN_0_ADDR + (E56PHY_TXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_PIN_OVRDEN_0_OVRD_EN_TX0_EFUSE_BITS_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_TXS_ANA_OVRDVAL_1_ADDR + (E56PHY_TXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_ANA_OVRDVAL_1_ANA_TEST_DAC_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_TXS_ANA_OVRDEN_0_ADDR + (E56PHY_TXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_ANA_OVRDEN_0_OVRD_EN_ANA_TEST_DAC_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+ }
+ /* Setting TX FFE */
+ txgbe_e56_tx_ffe_cfg(hw, TXGBE_LINK_SPEED_40GB_FULL);
+
+ /* RXS Config master */
+ for (i = 0; i < 4; i++) {
+ addr = E56PHY_RXS_RXS_CFG_0_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_RXS_CFG_0_DSER_DATA_SEL, 0x0);
+ set_fields_e56(&rdata, E56PHY_RXS_RXS_CFG_0_TRAIN_CLK_GATE_BYPASS_EN, 0x1fff);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_OSC_CAL_N_CDR_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ ((E56G_RXS0_OSC_CAL_N_CDR_0 *)&rdata)->prediv0 = 0xfa0;
+ ((E56G_RXS0_OSC_CAL_N_CDR_0 *)&rdata)->target_cnt0 = 0x203a;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_OSC_CAL_N_CDR_4_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ ((E56G_RXS0_OSC_CAL_N_CDR_4 *)&rdata)->osc_range_sel0 = 0x2;
+ ((E56G_RXS0_OSC_CAL_N_CDR_4 *)&rdata)->vco_code_init = 0x7ff;
+ ((E56G_RXS0_OSC_CAL_N_CDR_4 *)&rdata)->osc_current_boost_en0 = 0x1;
+ ((E56G_RXS0_OSC_CAL_N_CDR_4 *)&rdata)->bbcdr_current_boost0 = 0x0;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_OSC_CAL_N_CDR_5_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_SDM_WIDTH, 0x3);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BB_CDR_PROP_STEP_PRELOCK, 0xf);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BB_CDR_PROP_STEP_POSTLOCK, 0xf);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BB_CDR_GAIN_CTRL_POSTLOCK, 0xc);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BB_CDR_GAIN_CTRL_PRELOCK, 0xf);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BBCDR_RDY_CNT, 0x3);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_OSC_CAL_N_CDR_6_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_6_PI_GAIN_CTRL_PRELOCK, 0x7);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_6_PI_GAIN_CTRL_POSTLOCK, 0x5);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_INTL_CONFIG_0_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ ((E56G_RXS0_INTL_CONFIG_0 *)&rdata)->adc_intl2slice_delay0 = 0x5555;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_INTL_CONFIG_2_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ ((E56G_RXS0_INTL_CONFIG_2 *)&rdata)->interleaver_hbw_disable0 = 0x1;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_TXFFE_TRAINING_0_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_0_ADC_DATA_PEAK_LTH, 0x56);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_0_ADC_DATA_PEAK_UTH, 0x6a);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_TXFFE_TRAINING_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_1_C1_LTH, 0x1e8);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_1_C1_UTH, 0x78);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_TXFFE_TRAINING_2_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_2_CM1_LTH, 0x100);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_2_CM1_UTH, 0xff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_TXFFE_TRAINING_3_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_3_CM2_LTH, 0x4);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_3_CM2_UTH, 0x37);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_3_TXFFE_TRAIN_MOD_TYPE, 0x38);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_VGA_TRAINING_0_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_0_VGA_TARGET, 0x34);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_VGA_TRAINING_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_1_VGA1_CODE_INIT0, 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_1_VGA2_CODE_INIT0, 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_1_VGA1_CODE_INIT123, 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_1_VGA2_CODE_INIT123, 0xa);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_CTLE_TRAINING_0_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_0_CTLE_CODE_INIT0, 0x9);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_0_CTLE_CODE_INIT123, 0x9);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_CTLE_TRAINING_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_1_LFEQ_LUT, 0x1ffffea);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_CTLE_TRAINING_2_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_2_ISI_TH_FRAC_P1,
+ S10G_PHY_RX_CTLE_TAP_FRACP1);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_2_ISI_TH_FRAC_P2,
+ S10G_PHY_RX_CTLE_TAP_FRACP2);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_2_ISI_TH_FRAC_P3,
+ S10G_PHY_RX_CTLE_TAP_FRACP3);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_CTLE_TRAINING_3_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_3_TAP_WEIGHT_P1,
+ S10G_PHY_RX_CTLE_TAPWT_WEIGHT1);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_3_TAP_WEIGHT_P2,
+ S10G_PHY_RX_CTLE_TAPWT_WEIGHT2);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_3_TAP_WEIGHT_P3,
+ S10G_PHY_RX_CTLE_TAPWT_WEIGHT3);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_OFFSET_N_GAIN_CAL_0_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OFFSET_N_GAIN_CAL_0_ADC_SLICE_DATA_AVG_CNT, 0x3);
+ set_fields_e56(&rdata, E56PHY_RXS_OFFSET_N_GAIN_CAL_0_ADC_DATA_AVG_CNT, 0x3);
+ set_fields_e56(&rdata, E56PHY_RXS_OFFSET_N_GAIN_CAL_0_FE_OFFSET_DAC_CLK_CNT_X8,
+ 0xc);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_OFFSET_N_GAIN_CAL_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OFFSET_N_GAIN_CAL_1_SAMP_ADAPT_CFG, 0x5);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_FFE_TRAINING_0_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_FFE_TRAINING_0_FFE_TAP_EN, 0xf9ff);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_IDLE_DETECT_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MAX, 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MIN, 0x5);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__RXS3_ANA_OVRDVAL_11_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ ((E56G__RXS3_ANA_OVRDVAL_11 *)&rdata)->ana_test_adc_clkgen_i = 0x0;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__RXS0_ANA_OVRDEN_2_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ ((E56G__RXS0_ANA_OVRDEN_2 *)&rdata)->ovrd_en_ana_test_adc_clkgen_i = 0x0;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_ANA_OVRDVAL_0_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDVAL_0_ANA_EN_RTERM_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_ANA_OVRDEN_0_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_0_OVRD_EN_ANA_EN_RTERM_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_ANA_OVRDVAL_6_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 4, 0, 0x6);
+ set_fields_e56(&rdata, 14, 13, 0x2);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_ANA_OVRDEN_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_1_OVRD_EN_ANA_BBCDR_VCOFILT_BYP_I,
+ 0x1);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_1_OVRD_EN_ANA_TEST_BBCDR_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_ANA_OVRDVAL_15_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 2, 0, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_ANA_OVRDVAL_17_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDVAL_17_ANA_VGA2_BOOST_CSTM_I, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_ANA_OVRDEN_3_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_3_OVRD_EN_ANA_ANABS_CONFIG_I, 0x1);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_3_OVRD_EN_ANA_VGA2_BOOST_CSTM_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_ANA_OVRDVAL_14_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 13, 13, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_ANA_OVRDEN_4_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 13, 13, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_EYE_SCAN_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_EYE_SCAN_1_EYE_SCAN_REF_TIMER, 0x400);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS_RINGO_0_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 9, 4, 0x366);
+ wr32_ephy(hw, addr, rdata);
+ }
+
+ /* PDIG Config master */
+ addr = E56PHY_PMD_CFG_3_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_3_CTRL_FSM_TIMEOUT_X64K, 0x80);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_PMD_CFG_4_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_4_TRAIN_DC_ON_PERIOD_X64K, 0x18);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_4_TRAIN_DC_PERIOD_X512K, 0x3e);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_PMD_CFG_5_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_5_USE_RECENT_MARKER_OFFSET, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_0_CONT_ON_ADC_GAIN_CAL_ERR, 0x1);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_0_DO_RX_ADC_OFST_CAL, 0x3);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_0_RX_ERR_ACTION_EN, 0x40);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_1_TRAIN_ST0_WAIT_CNT_X4096, 0xff);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_1_TRAIN_ST1_WAIT_CNT_X4096, 0xff);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_1_TRAIN_ST2_WAIT_CNT_X4096, 0xff);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_1_TRAIN_ST3_WAIT_CNT_X4096, 0xff);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_2_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_2_TRAIN_ST4_WAIT_CNT_X4096, 0x1);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_2_TRAIN_ST5_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_2_TRAIN_ST6_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_2_TRAIN_ST7_WAIT_CNT_X4096, 0x4);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_3_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_3_TRAIN_ST8_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_3_TRAIN_ST9_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_3_TRAIN_ST10_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_3_TRAIN_ST11_WAIT_CNT_X4096, 0x4);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_4_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_4_TRAIN_ST12_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_4_TRAIN_ST13_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_4_TRAIN_ST14_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_4_TRAIN_ST15_WAIT_CNT_X4096, 0x4);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_7_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_7_TRAIN_ST4_EN, 0x4bf);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_7_TRAIN_ST5_EN, 0xc4bf);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_8_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_8_TRAIN_ST7_EN, 0x47ff);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_12_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_12_TRAIN_ST15_EN, 0x67ff);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_13_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_13_TRAIN_ST0_DONE_EN, 0x8001);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_13_TRAIN_ST1_DONE_EN, 0x8002);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_14_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_14_TRAIN_ST3_DONE_EN, 0x8008);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_15_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_15_TRAIN_ST4_DONE_EN, 0x8004);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_17_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_17_TRAIN_ST8_DONE_EN, 0x20c0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_18_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_18_TRAIN_ST10_DONE_EN, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_29_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_29_TRAIN_ST15_DC_EN, 0x3f6d);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_33_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_33_TRAIN0_RATE_SEL, 0x8000);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_33_TRAIN1_RATE_SEL, 0x8000);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_CTRL_FSM_CFG_34_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_34_TRAIN2_RATE_SEL, 0x8000);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_34_TRAIN3_RATE_SEL, 0x8000);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_KRT_TFSM_CFG_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_KRT_TFSM_CFGKRT_TFSM_MAX_WAIT_TIMER_X1000K, 0x49);
+ set_fields_e56(&rdata, E56PHY_KRT_TFSM_CFGKRT_TFSM_MAX_WAIT_TIMER_X8000K, 0x37);
+ set_fields_e56(&rdata, E56PHY_KRT_TFSM_CFGKRT_TFSM_HOLDOFF_TIMER_X256K, 0x2f);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2, 0x2);
+ wr32_ephy(hw, addr, rdata);
+
+ return 0;
+}
+
u32
txgbe_e56_cfg_25g(struct txgbe_hw *hw)
{
@@ -1294,6 +1722,46 @@ txgbe_e56_rxs_osc_init_for_temp_track_range(struct txgbe_hw *hw, u32 speed)
return status;
}
+static int txgbe_e56_set_rxs_ufine_le_max_40g(struct txgbe_hw *hw, u32 speed)
+{
+ int status = 0;
+ unsigned int rdata;
+ unsigned int ULTRAFINE_CODE;
+ int i = 0;
+ unsigned int CMVAR_UFINE_MAX = 0;
+ u32 addr;
+
+ for (i = 0; i < 4; i++) {
+ if (speed == TXGBE_LINK_SPEED_10GB_FULL || speed == TXGBE_LINK_SPEED_40GB_FULL)
+ CMVAR_UFINE_MAX = S10G_CMVAR_UFINE_MAX;
+ else if (speed == TXGBE_LINK_SPEED_25GB_FULL)
+ CMVAR_UFINE_MAX = S25G_CMVAR_UFINE_MAX;
+
+ /* a. Assign software defined variables as below */
+ addr = E56G__RXS0_ANA_OVRDVAL_5_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ ULTRAFINE_CODE = EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_ultrafine_i);
+
+ /* b. Perform the below logic sequence */
+ while (ULTRAFINE_CODE > CMVAR_UFINE_MAX) {
+ ULTRAFINE_CODE = ULTRAFINE_CODE - 1;
+ addr = E56G__RXS0_ANA_OVRDVAL_5_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_ultrafine_i) = ULTRAFINE_CODE;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__RXS0_ANA_OVRDEN_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ wr32_ephy(hw, addr, rdata);
+
+ /* Wait until 1milliseconds or greater */
+ msleep(10);
+ }
+ }
+ return status;
+}
+
static inline
int txgbe_e56_set_rxs_ufine_le_max(struct txgbe_hw *hw, u32 speed)
{
@@ -1325,41 +1793,271 @@ int txgbe_e56_set_rxs_ufine_le_max(struct txgbe_hw *hw, u32 speed)
msleep(10);
}
- return status;
-}
+ return status;
+}
+
+#define RXS_READ_COUNT 5
+
+void txgbe_e56_rx_rd_second_code_40g(struct txgbe_hw *hw, int *SECOND_CODE, int lane)
+{
+ int i, median;
+ unsigned int rdata;
+ u32 addr;
+ int RXS_BBCDR_SECOND_ORDER_ST[RXS_READ_COUNT];
+
+ /* Set ovrd_en=0 to read ASIC value */
+ addr = E56G__RXS0_ANA_OVRDEN_1_ADDR + (lane * E56PHY_RXS_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_int_cstm_i) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ /*
+ * As status update from RXS hardware is asynchronous to read status of SECOND_ORDER,
+ * follow sequence mentioned below.
+ */
+ for (i = 0; i < RXS_READ_COUNT; i = i + 1) {
+ addr = E56G__RXS0_ANA_OVRDVAL_5_ADDR + (lane * E56PHY_RXS_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ RXS_BBCDR_SECOND_ORDER_ST[i] = EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_int_cstm_i);
+ usec_delay(100);
+ }
+
+ /* sort array RXS_BBCDR_SECOND_ORDER_ST[i] */
+ qsort(RXS_BBCDR_SECOND_ORDER_ST, RXS_READ_COUNT, sizeof(int), txgbe_e56_int_cmp);
+
+ median = ((RXS_READ_COUNT + 1) / 2) - 1;
+ *SECOND_CODE = RXS_BBCDR_SECOND_ORDER_ST[median];
+
+ return;
+}
+
+void txgbe_e56_rx_rd_second_code(struct txgbe_hw *hw, int *SECOND_CODE)
+{
+ int i, median;
+ unsigned int rdata;
+ int RXS_BBCDR_SECOND_ORDER_ST[RXS_READ_COUNT];
+
+ /* Set ovrd_en=0 to read ASIC value */
+ txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_int_cstm_i, 0);
+
+ /*
+ * As status update from RXS hardware is asynchronous to read status
+ * of SECOND_ORDER, follow sequence mentioned below.
+ */
+ for (i = 0; i < RXS_READ_COUNT; i = i + 1) {
+ EPHY_RREG(E56G__RXS0_ANA_OVRDVAL_5);
+ RXS_BBCDR_SECOND_ORDER_ST[i] = EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_int_cstm_i);
+ usec_delay(100);
+ }
+
+ /* sort array RXS_BBCDR_SECOND_ORDER_ST[i] */
+ qsort(RXS_BBCDR_SECOND_ORDER_ST, RXS_READ_COUNT, sizeof(int), txgbe_e56_int_cmp);
+
+ median = ((RXS_READ_COUNT + 1) / 2) - 1;
+ *SECOND_CODE = RXS_BBCDR_SECOND_ORDER_ST[median];
+
+ return;
+}
+
+/*
+ * 2.3.4 RXS post CDR lock temperature tracking sequence
+ *
+ * Below sequence must be run before the temperature drifts by >5degC
+ * after the CDR locks for the first time or after the ious time this
+ * sequence was run. It is recommended to call this sequence periodically
+ * (eg: once every 100ms) or trigger sequence if the temperature drifts
+ * by >=5degC. Temperature must be read from an on-die temperature sensor.
+ */
+int txgbe_temp_track_seq_40g(struct txgbe_hw *hw, u32 speed)
+{
+ int status = 0;
+ unsigned int rdata;
+ int SECOND_CODE;
+ int COARSE_CODE;
+ int FINE_CODE;
+ int ULTRAFINE_CODE;
+
+ int CMVAR_SEC_LOW_TH;
+ int CMVAR_UFINE_MAX = 0;
+ int CMVAR_FINE_MAX;
+ int CMVAR_UFINE_UMAX_WRAP = 0;
+ int CMVAR_COARSE_MAX;
+ int CMVAR_UFINE_FMAX_WRAP = 0;
+ int CMVAR_FINE_FMAX_WRAP = 0;
+ int CMVAR_SEC_HIGH_TH;
+ int CMVAR_UFINE_MIN;
+ int CMVAR_FINE_MIN;
+ int CMVAR_UFINE_UMIN_WRAP;
+ int CMVAR_COARSE_MIN;
+ int CMVAR_UFINE_FMIN_WRAP;
+ int CMVAR_FINE_FMIN_WRAP;
+ int i;
+ u32 addr;
+ int temperature;
+
+ for (i = 0; i < 4; i++) {
+ if (speed == TXGBE_LINK_SPEED_10GB_FULL || speed == TXGBE_LINK_SPEED_40GB_FULL) {
+ CMVAR_SEC_LOW_TH = S10G_CMVAR_SEC_LOW_TH;
+ CMVAR_UFINE_MAX = S10G_CMVAR_UFINE_MAX;
+ CMVAR_FINE_MAX = S10G_CMVAR_FINE_MAX;
+ CMVAR_UFINE_UMAX_WRAP = S10G_CMVAR_UFINE_UMAX_WRAP;
+ CMVAR_COARSE_MAX = S10G_CMVAR_COARSE_MAX;
+ CMVAR_UFINE_FMAX_WRAP = S10G_CMVAR_UFINE_FMAX_WRAP;
+ CMVAR_FINE_FMAX_WRAP = S10G_CMVAR_FINE_FMAX_WRAP;
+ CMVAR_SEC_HIGH_TH = S10G_CMVAR_SEC_HIGH_TH;
+ CMVAR_UFINE_MIN = S10G_CMVAR_UFINE_MIN;
+ CMVAR_FINE_MIN = S10G_CMVAR_FINE_MIN;
+ CMVAR_UFINE_UMIN_WRAP = S10G_CMVAR_UFINE_UMIN_WRAP;
+ CMVAR_COARSE_MIN = S10G_CMVAR_COARSE_MIN;
+ CMVAR_UFINE_FMIN_WRAP = S10G_CMVAR_UFINE_FMIN_WRAP;
+ CMVAR_FINE_FMIN_WRAP = S10G_CMVAR_FINE_FMIN_WRAP;
+ } else if (speed == TXGBE_LINK_SPEED_25GB_FULL) {
+ CMVAR_SEC_LOW_TH = S25G_CMVAR_SEC_LOW_TH;
+ CMVAR_UFINE_MAX = S25G_CMVAR_UFINE_MAX;
+ CMVAR_FINE_MAX = S25G_CMVAR_FINE_MAX;
+ CMVAR_UFINE_UMAX_WRAP = S25G_CMVAR_UFINE_UMAX_WRAP;
+ CMVAR_COARSE_MAX = S25G_CMVAR_COARSE_MAX;
+ CMVAR_UFINE_FMAX_WRAP = S25G_CMVAR_UFINE_FMAX_WRAP;
+ CMVAR_FINE_FMAX_WRAP = S25G_CMVAR_FINE_FMAX_WRAP;
+ CMVAR_SEC_HIGH_TH = S25G_CMVAR_SEC_HIGH_TH;
+ CMVAR_UFINE_MIN = S25G_CMVAR_UFINE_MIN;
+ CMVAR_FINE_MIN = S25G_CMVAR_FINE_MIN;
+ CMVAR_UFINE_UMIN_WRAP = S25G_CMVAR_UFINE_UMIN_WRAP;
+ CMVAR_COARSE_MIN = S25G_CMVAR_COARSE_MIN;
+ CMVAR_UFINE_FMIN_WRAP = S25G_CMVAR_UFINE_FMIN_WRAP;
+ CMVAR_FINE_FMIN_WRAP = S25G_CMVAR_FINE_FMIN_WRAP;
+ } else {
+ DEBUGOUT("Error Speed\n");
+ return 0;
+ }
-#define RXS_READ_COUNT 5
+ status = txgbe_e56_get_temp(hw, &temperature);
+ if (status)
+ return 0;
-void txgbe_e56_rx_rd_second_code(struct txgbe_hw *hw, int *SECOND_CODE)
-{
- int i, median;
- unsigned int rdata;
- int RXS_BBCDR_SECOND_ORDER_ST[RXS_READ_COUNT];
+ hw->temperature = temperature;
- /* Set ovrd_en=0 to read ASIC value */
- txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_int_cstm_i, 0);
+ /* Assign software defined variables as below */
+ /* a. SECOND_CODE = ALIAS::RXS::SECOND_ORDER */
+ txgbe_e56_rx_rd_second_code_40g(hw, &SECOND_CODE, i);
- /*
- * As status update from RXS hardware is asynchronous to read status
- * of SECOND_ORDER, follow sequence mentioned below.
- */
- for (i = 0; i < RXS_READ_COUNT; i = i + 1) {
- /* set RXS_BBCDR_SECOND_ORDER_ST[i] =
- * RXS::ANA_OVRDVAL[5]::ana_bbcdr_int_cstm_i[4:0]
+ /*
+ * b. COARSE_CODE = ALIAS::RXS::COARSE
+ * c. FINE_CODE = ALIAS::RXS::FINE
+ * d. ULTRAFINE_CODE = ALIAS::RXS::ULTRAFINE
*/
- EPHY_RREG(E56G__RXS0_ANA_OVRDVAL_5);
- RXS_BBCDR_SECOND_ORDER_ST[i] = EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
- ana_bbcdr_int_cstm_i);
- usec_delay(100);
+ addr = E56G__RXS0_ANA_OVRDVAL_5_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ COARSE_CODE = EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_coarse_i);
+ FINE_CODE = EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_fine_i);
+ ULTRAFINE_CODE = EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_ultrafine_i);
+
+ if (SECOND_CODE <= CMVAR_SEC_LOW_TH) {
+ if (ULTRAFINE_CODE < CMVAR_UFINE_MAX) {
+ addr = E56G__RXS0_ANA_OVRDVAL_5_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_ultrafine_i) = ULTRAFINE_CODE + 1;
+ wr32_ephy(hw, addr, rdata);
+
+ /* Set ovrd_en=1 to override ASIC value */
+ addr = E56G__RXS0_ANA_OVRDEN_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1,
+ ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ wr32_ephy(hw, addr, rdata);
+ } else if (FINE_CODE < CMVAR_FINE_MAX) {
+ addr = E56G__RXS0_ANA_OVRDVAL_5_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_ultrafine_i) = CMVAR_UFINE_UMAX_WRAP;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_fine_i) = FINE_CODE + 1;
+ wr32_ephy(hw, addr, rdata);
+ addr = E56G__RXS0_ANA_OVRDEN_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_fine_i) = 1;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1,
+ ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ wr32_ephy(hw, addr, rdata);
+ } else if (COARSE_CODE < CMVAR_COARSE_MAX) {
+ addr = E56G__RXS0_ANA_OVRDVAL_5_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_ultrafine_i) = CMVAR_UFINE_FMAX_WRAP;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_fine_i) = CMVAR_FINE_FMAX_WRAP;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_coarse_i) = COARSE_CODE + 1;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__RXS0_ANA_OVRDEN_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_coarse_i) = 1;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_fine_i) = 1;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1,
+ ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ wr32_ephy(hw, addr, rdata);
+ } else {
+ DEBUGOUT("ERROR: (SECOND_CODE <= CMVAR_SEC_LOW_TH) temperature "
+ "tracking occurs Error condition");
+ }
+ } else if (SECOND_CODE >= CMVAR_SEC_HIGH_TH) {
+ if (ULTRAFINE_CODE > CMVAR_UFINE_MIN) {
+ addr = E56G__RXS0_ANA_OVRDVAL_5_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_ultrafine_i) = ULTRAFINE_CODE - 1;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__RXS0_ANA_OVRDEN_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1,
+ ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ wr32_ephy(hw, addr, rdata);
+ } else if (FINE_CODE > CMVAR_FINE_MIN) {
+ addr = E56G__RXS0_ANA_OVRDVAL_5_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_ultrafine_i) = CMVAR_UFINE_UMIN_WRAP;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_fine_i) = FINE_CODE - 1;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__RXS0_ANA_OVRDEN_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_fine_i) = 1;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1,
+ ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ wr32_ephy(hw, addr, rdata);
+ } else if (COARSE_CODE > CMVAR_COARSE_MIN) {
+ addr = E56G__RXS0_ANA_OVRDVAL_5_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_ultrafine_i) = CMVAR_UFINE_FMIN_WRAP;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_fine_i) = CMVAR_FINE_FMIN_WRAP;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_coarse_i) = COARSE_CODE - 1;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__RXS0_ANA_OVRDEN_1_ADDR + (E56PHY_RXS_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_coarse_i) = 1;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_fine_i) = 1;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1,
+ ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ wr32_ephy(hw, addr, rdata);
+ } else {
+ DEBUGOUT("ERROR: (SECOND_CODE >= CMVAR_SEC_HIGH_TH) temperature "
+ "tracking occurs Error condition");
+ }
+ }
}
- /* sort array RXS_BBCDR_SECOND_ORDER_ST[i] */
- qsort(RXS_BBCDR_SECOND_ORDER_ST, RXS_READ_COUNT, sizeof(int), txgbe_e56_int_cmp);
-
- median = ((RXS_READ_COUNT + 1) / 2) - 1;
- *SECOND_CODE = RXS_BBCDR_SECOND_ORDER_ST[median];
-
- return;
+ return status;
}
/*
@@ -1533,78 +2231,409 @@ int txgbe_temp_track_seq(struct txgbe_hw *hw, u32 speed)
PMD_DRV_LOG(ERR, "ERROR: (SECOND_CODE >= CMVAR_SEC_HIGH_TH) "
"temperature tracking occurs Error condition");
}
- }
+ }
+
+ return status;
+}
+
+static inline int
+txgbe_e56_ctle_bypass_seq(struct txgbe_hw *hw, u32 speed)
+{
+ unsigned int rdata;
+
+ /* 1. Program the following RXS registers as mentioned below. */
+ txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDVAL_0, ana_ctle_bypass_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDEN_0, ovrd_en_ana_ctle_bypass_i, 1);
+
+ txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDVAL_3, ana_ctle_cz_cstm_i, 0);
+ txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDEN_0, ovrd_en_ana_ctle_cz_cstm_i, 1);
+
+ /* 2. Program the following PDIG registers as mentioned below. */
+ EPHY_RREG(E56G__PMD_RXS0_OVRDVAL_1);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1, rxs0_rx0_ctle_train_en_i) = 0;
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1, rxs0_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS0_OVRDVAL_1);
+
+ EPHY_RREG(E56G__PMD_RXS0_OVRDEN_1);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_ctle_train_en_i) = 1;
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS0_OVRDEN_1);
+
+ if (speed == TXGBE_LINK_SPEED_40GB_FULL) {
+ /* 1. Program the following RXS registers as mentioned below. */
+ txgbe_e56_ephy_config(E56G__RXS1_ANA_OVRDVAL_0, ana_ctle_bypass_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS1_ANA_OVRDEN_0, ovrd_en_ana_ctle_bypass_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS2_ANA_OVRDVAL_0, ana_ctle_bypass_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS2_ANA_OVRDEN_0, ovrd_en_ana_ctle_bypass_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS3_ANA_OVRDVAL_0, ana_ctle_bypass_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS3_ANA_OVRDEN_0, ovrd_en_ana_ctle_bypass_i, 1);
+
+ txgbe_e56_ephy_config(E56G__RXS1_ANA_OVRDVAL_3, ana_ctle_cz_cstm_i, 0);
+ txgbe_e56_ephy_config(E56G__RXS1_ANA_OVRDEN_0, ovrd_en_ana_ctle_cz_cstm_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS2_ANA_OVRDVAL_3, ana_ctle_cz_cstm_i, 0);
+ txgbe_e56_ephy_config(E56G__RXS2_ANA_OVRDEN_0, ovrd_en_ana_ctle_cz_cstm_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS3_ANA_OVRDVAL_3, ana_ctle_cz_cstm_i, 0);
+ txgbe_e56_ephy_config(E56G__RXS3_ANA_OVRDEN_0, ovrd_en_ana_ctle_cz_cstm_i, 1);
+
+ /* 2. Program the following PDIG registers as mentioned below. */
+ EPHY_RREG(E56G__PMD_RXS1_OVRDVAL_1);
+ EPHY_XFLD(E56G__PMD_RXS1_OVRDVAL_1, rxs1_rx0_ctle_train_en_i) = 0;
+ EPHY_XFLD(E56G__PMD_RXS1_OVRDVAL_1, rxs1_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS1_OVRDVAL_1);
+ EPHY_RREG(E56G__PMD_RXS2_OVRDVAL_1);
+ EPHY_XFLD(E56G__PMD_RXS2_OVRDVAL_1, rxs2_rx0_ctle_train_en_i) = 0;
+ EPHY_XFLD(E56G__PMD_RXS2_OVRDVAL_1, rxs2_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS2_OVRDVAL_1);
+ EPHY_RREG(E56G__PMD_RXS3_OVRDVAL_1);
+ EPHY_XFLD(E56G__PMD_RXS3_OVRDVAL_1, rxs3_rx0_ctle_train_en_i) = 0;
+ EPHY_XFLD(E56G__PMD_RXS3_OVRDVAL_1, rxs3_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS3_OVRDVAL_1);
+
+ EPHY_RREG(E56G__PMD_RXS1_OVRDEN_1);
+ EPHY_XFLD(E56G__PMD_RXS1_OVRDEN_1, ovrd_en_rxs1_rx0_ctle_train_en_i) = 1;
+ EPHY_XFLD(E56G__PMD_RXS1_OVRDEN_1, ovrd_en_rxs1_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS1_OVRDEN_1);
+ EPHY_RREG(E56G__PMD_RXS2_OVRDEN_1);
+ EPHY_XFLD(E56G__PMD_RXS2_OVRDEN_1, ovrd_en_rxs2_rx0_ctle_train_en_i) = 1;
+ EPHY_XFLD(E56G__PMD_RXS2_OVRDEN_1, ovrd_en_rxs2_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS2_OVRDEN_1);
+ EPHY_RREG(E56G__PMD_RXS3_OVRDEN_1);
+ EPHY_XFLD(E56G__PMD_RXS3_OVRDEN_1, ovrd_en_rxs3_rx0_ctle_train_en_i) = 1;
+ EPHY_XFLD(E56G__PMD_RXS3_OVRDEN_1, ovrd_en_rxs3_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS3_OVRDEN_1);
+ }
+ return 0;
+}
+
+static int txgbe_e56_rxs_calib_adapt_seq_40G(struct txgbe_hw *hw, u32 speed)
+{
+ int status = 0, i, j;
+ u32 addr, timer;
+ u32 rdata = 0x0;
+ const bool bypass_ctle = true;
+
+ for (i = 0; i < 4; i++) {
+ rdata = 0x0000;
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_ADC_OFST_ADAPT_EN_I, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS0_OVRDEN_2_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_RXS0_OVRDEN_2_OVRD_EN_RXS0_RX0_ADC_OFST_ADAPT_EN_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_ADC_GAIN_ADAPT_EN_I, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS0_OVRDEN_2_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_RXS0_OVRDEN_2_OVRD_EN_RXS0_RX0_ADC_GAIN_ADAPT_EN_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_ADC_INTL_CAL_EN_I, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS0_OVRDEN_1_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_RXS0_OVRDEN_1_OVRD_EN_RXS0_RX0_ADC_INTL_CAL_EN_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_ADC_INTL_CAL_DONE_O, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS0_OVRDEN_1_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_RXS0_OVRDEN_1_OVRD_EN_RXS0_RX0_ADC_INTL_CAL_DONE_O, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_ADC_INTL_ADAPT_EN_I, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS0_OVRDEN_2_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_RXS0_OVRDEN_2_OVRD_EN_RXS0_RX0_ADC_INTL_ADAPT_EN_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+ }
+
+ if (bypass_ctle == 1)
+ txgbe_e56_ctle_bypass_seq(hw, speed);
+
+ /*
+ * 2. Follow sequence described in 2.3.2 RXS Osc Initialization for temperature tracking
+ * range here. RXS would be enabled at the end of this sequence. For the case when PAM4 KR
+ * training is not enabled (including PAM4 mode without KR training), wait until
+ * ALIAS::PDIG::CTRL_FSM_RX_ST would return RX_TRAIN_15_ST (RX_RDY_ST).
+ */
+ txgbe_e56_rxs_osc_init_for_temp_track_range(hw, speed);
+
+ addr = E56PHY_CTRL_FSM_RX_STAT_0_ADDR;
+ timer = 0;
+ rdata = 0;
+ while (EPHY_XFLD(E56G__PMD_CTRL_FSM_RX_STAT_0, ctrl_fsm_rx0_st) != E56PHY_RX_RDY_ST ||
+ EPHY_XFLD(E56G__PMD_CTRL_FSM_RX_STAT_0, ctrl_fsm_rx1_st) != E56PHY_RX_RDY_ST ||
+ EPHY_XFLD(E56G__PMD_CTRL_FSM_RX_STAT_0, ctrl_fsm_rx2_st) != E56PHY_RX_RDY_ST ||
+ EPHY_XFLD(E56G__PMD_CTRL_FSM_RX_STAT_0, ctrl_fsm_rx3_st) != E56PHY_RX_RDY_ST) {
+ rdata = rd32_ephy(hw, addr);
+ usec_delay(500);
+ if (timer++ > PHYINIT_TIMEOUT) {
+ rdata = 0;
+ addr = E56PHY_PMD_CFG_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_0_RX_EN_CFG, 0x0);
+ wr32_ephy(hw, addr, rdata);
+ return TXGBE_ERR_TIMEOUT;
+ }
+ }
+
+ rdata = 0;
+ timer = 0;
+ while (EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1, rxs0_rx0_cdr_rdy_o) != 1) {
+ EPHY_RREG(E56G__PMD_RXS0_OVRDVAL_1);
+ usec_delay(500);
+ if (timer++ > PHYINIT_TIMEOUT)
+ return TXGBE_ERR_TIMEOUT;
+ }
+
+ rdata = 0;
+ timer = 0;
+ while (EPHY_XFLD(E56G__PMD_RXS1_OVRDVAL_1, rxs1_rx0_cdr_rdy_o) != 1) {
+ EPHY_RREG(E56G__PMD_RXS1_OVRDVAL_1);
+ usec_delay(500);
+ if (timer++ > PHYINIT_TIMEOUT)
+ return TXGBE_ERR_TIMEOUT;
+ }
+
+ rdata = 0;
+ timer = 0;
+ while (EPHY_XFLD(E56G__PMD_RXS2_OVRDVAL_1, rxs2_rx0_cdr_rdy_o) != 1) {
+ EPHY_RREG(E56G__PMD_RXS2_OVRDVAL_1);
+ usec_delay(500);
+ if (timer++ > PHYINIT_TIMEOUT)
+ return TXGBE_ERR_TIMEOUT;
+ }
+
+ rdata = 0;
+ timer = 0;
+ while (EPHY_XFLD(E56G__PMD_RXS3_OVRDVAL_1, rxs3_rx0_cdr_rdy_o) != 1) {
+ EPHY_RREG(E56G__PMD_RXS3_OVRDVAL_1);
+ usec_delay(500);
+ if (timer++ > PHYINIT_TIMEOUT)
+ return TXGBE_ERR_TIMEOUT;
+ }
+
+ for (i = 0; i < 4; i++) {
+ /* 4. Disable VGA and CTLE training so they don't interfere with ADC calibration */
+ /* a. Set ALIAS::RXS::VGA_TRAIN_EN = 0b0 */
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_VGA_TRAIN_EN_I, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS0_OVRDEN_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS0_OVRDEN_1_OVRD_EN_RXS0_RX0_VGA_TRAIN_EN_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ /* b. Set ALIAS::RXS::CTLE_TRAIN_EN = 0b0 */
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_CTLE_TRAIN_EN_I, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS0_OVRDEN_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS0_OVRDEN_1_OVRD_EN_RXS0_RX0_CTLE_TRAIN_EN_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ /* 5. Perform ADC interleaver calibration */
+ /* a. Remove the OVERRIDE on ALIAS::RXS::ADC_INTL_CAL_DONE */
+ addr = E56PHY_RXS0_OVRDEN_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_RXS0_OVRDEN_1_OVRD_EN_RXS0_RX0_ADC_INTL_CAL_DONE_O, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_ADC_INTL_CAL_EN_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ timer = 0;
+ while (((rdata >> E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_ADC_INTL_CAL_DONE_O_LSB)
+ & 1) != 1) {
+ rdata = rd32_ephy(hw, addr);
+ usec_delay(1000);
+
+ if (timer++ > PHYINIT_TIMEOUT)
+ break;
+ }
+
+ /*
+ * 6. Perform ADC offset adaptation and ADC gain adaptation, repeat them a few
+ * times and after that keep it disabled.
+ */
+ for (j = 0; j < 16; j++) {
+ /* a. ALIAS::RXS::ADC_OFST_ADAPT_EN = 0b1 */
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_ADC_OFST_ADAPT_EN_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ /* b. Wait for 1ms or greater */
+ addr = E56G__PMD_RXS0_OVRDEN_2_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_2,
+ ovrd_en_rxs0_rx0_adc_ofst_adapt_done_o) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0;
+ addr = E56G__PMD_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ timer = 0;
+ while (EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1,
+ rxs0_rx0_adc_ofst_adapt_done_o) != 1) {
+ rdata = rd32_ephy(hw, addr);
+ usec_delay(500);
+ if (timer++ > PHYINIT_TIMEOUT)
+ break;
+ }
+
+ /* c. ALIAS::RXS::ADC_OFST_ADAPT_EN = 0b0 */
+ rdata = 0x0000;
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_ADC_OFST_ADAPT_EN_I, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ /* d. ALIAS::RXS::ADC_GAIN_ADAPT_EN = 0b1 */
+ rdata = 0x0000;
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_ADC_GAIN_ADAPT_EN_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ /* e. Wait for 1ms or greater */
+ addr = E56G__PMD_RXS0_OVRDEN_2_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_2,
+ ovrd_en_rxs0_rx0_adc_ofst_adapt_done_o) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0;
+ timer = 0;
+ addr = E56G__PMD_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ while (EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1,
+ rxs0_rx0_adc_gain_adapt_done_o) != 1) {
+ rdata = rd32_ephy(hw, addr);
+ usec_delay(500);
+
+ if (timer++ > PHYINIT_TIMEOUT)
+ break;
+ }
+
+ /* f. ALIAS::RXS::ADC_GAIN_ADAPT_EN = 0b0 */
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_ADC_GAIN_ADAPT_EN_I, 0x0);
+ wr32_ephy(hw, addr, rdata);
+ /* g. Repeat #a to #f total 16 times */
+ }
- return status;
-}
+ /*
+ * 7. Perform ADC interleaver adaptation for 10ms or greater,
+ * and after that disable it
+ * a. ALIAS::RXS::ADC_INTL_ADAPT_EN = 0b1
+ */
+ addr = E56PHY_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS0_OVRDVAL_1_RXS0_RX0_ADC_INTL_ADAPT_EN_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+ /* b. Wait for 10ms or greater */
+ msleep(10);
-static inline int
-txgbe_e56_ctle_bypass_seq(struct txgbe_hw *hw, u32 speed)
-{
- unsigned int rdata;
+ /* c. ALIAS::RXS::ADC_INTL_ADAPT_EN = 0b0 */
+ addr = E56G__PMD_RXS0_OVRDEN_2_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_2, ovrd_en_rxs0_rx0_adc_intl_adapt_en_i) = 0;
+ wr32_ephy(hw, addr, rdata);
- /* 1. Program the following RXS registers as mentioned below. */
- txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDVAL_0, ana_ctle_bypass_i, 1);
- txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDEN_0, ovrd_en_ana_ctle_bypass_i, 1);
+ /*
+ * 8. Now re-enable VGA and CTLE trainings, so that it continues to adapt tracking
+ * changes in temperature or voltage
+ */
+ addr = E56G__PMD_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1, rxs0_rx0_vga_train_en_i) = 1;
+ if (bypass_ctle == 0)
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1, rxs0_rx0_ctle_train_en_i) = 1;
+ wr32_ephy(hw, addr, rdata);
- txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDVAL_3, ana_ctle_cz_cstm_i, 0);
- txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDEN_0, ovrd_en_ana_ctle_cz_cstm_i, 1);
+ addr = E56G__PMD_RXS0_OVRDEN_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_vga_train_done_o) = 0;
+ wr32_ephy(hw, addr, rdata);
- /* 2. Program the following PDIG registers as mentioned below. */
- EPHY_RREG(E56G__PMD_RXS0_OVRDVAL_1);
- EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1, rxs0_rx0_ctle_train_en_i) = 0;
- EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1, rxs0_rx0_ctle_train_done_o) = 1;
- EPHY_WREG(E56G__PMD_RXS0_OVRDVAL_1);
+ rdata = 0;
+ timer = 0;
+ addr = E56G__PMD_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ while (EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1, rxs0_rx0_vga_train_done_o) != 1) {
+ rdata = rd32_ephy(hw, addr);
+ usec_delay(500);
- EPHY_RREG(E56G__PMD_RXS0_OVRDEN_1);
- EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_ctle_train_en_i) = 1;
- EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_ctle_train_done_o) = 1;
- EPHY_WREG(E56G__PMD_RXS0_OVRDEN_1);
+ if (timer++ > PHYINIT_TIMEOUT)
+ break;
+ }
- if (speed == TXGBE_LINK_SPEED_40GB_FULL) {
- /* 1. Program the following RXS registers as mentioned below. */
- txgbe_e56_ephy_config(E56G__RXS1_ANA_OVRDVAL_0, ana_ctle_bypass_i, 1);
- txgbe_e56_ephy_config(E56G__RXS1_ANA_OVRDEN_0, ovrd_en_ana_ctle_bypass_i, 1);
- txgbe_e56_ephy_config(E56G__RXS2_ANA_OVRDVAL_0, ana_ctle_bypass_i, 1);
- txgbe_e56_ephy_config(E56G__RXS2_ANA_OVRDEN_0, ovrd_en_ana_ctle_bypass_i, 1);
- txgbe_e56_ephy_config(E56G__RXS3_ANA_OVRDVAL_0, ana_ctle_bypass_i, 1);
- txgbe_e56_ephy_config(E56G__RXS3_ANA_OVRDEN_0, ovrd_en_ana_ctle_bypass_i, 1);
+ if (bypass_ctle == 0) {
+ addr = E56G__PMD_RXS0_OVRDEN_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_ctle_train_done_o) = 0;
+ wr32_ephy(hw, addr, rdata);
- txgbe_e56_ephy_config(E56G__RXS1_ANA_OVRDVAL_3, ana_ctle_cz_cstm_i, 0);
- txgbe_e56_ephy_config(E56G__RXS1_ANA_OVRDEN_0, ovrd_en_ana_ctle_cz_cstm_i, 1);
- txgbe_e56_ephy_config(E56G__RXS2_ANA_OVRDVAL_3, ana_ctle_cz_cstm_i, 0);
- txgbe_e56_ephy_config(E56G__RXS2_ANA_OVRDEN_0, ovrd_en_ana_ctle_cz_cstm_i, 1);
- txgbe_e56_ephy_config(E56G__RXS3_ANA_OVRDVAL_3, ana_ctle_cz_cstm_i, 0);
- txgbe_e56_ephy_config(E56G__RXS3_ANA_OVRDEN_0, ovrd_en_ana_ctle_cz_cstm_i, 1);
+ rdata = 0;
+ timer = 0;
+ addr = E56G__PMD_RXS0_OVRDVAL_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ while (EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1,
+ rxs0_rx0_ctle_train_done_o) != 1) {
+ rdata = rd32_ephy(hw, addr);
+ usec_delay(500);
+
+ if (timer++ > PHYINIT_TIMEOUT)
+ break;
+ }
+ }
- /* 2. Program the following PDIG registers as mentioned below. */
- EPHY_RREG(E56G__PMD_RXS1_OVRDVAL_1);
- EPHY_XFLD(E56G__PMD_RXS1_OVRDVAL_1, rxs1_rx0_ctle_train_en_i) = 0;
- EPHY_XFLD(E56G__PMD_RXS1_OVRDVAL_1, rxs1_rx0_ctle_train_done_o) = 1;
- EPHY_WREG(E56G__PMD_RXS1_OVRDVAL_1);
- EPHY_RREG(E56G__PMD_RXS2_OVRDVAL_1);
- EPHY_XFLD(E56G__PMD_RXS2_OVRDVAL_1, rxs2_rx0_ctle_train_en_i) = 0;
- EPHY_XFLD(E56G__PMD_RXS2_OVRDVAL_1, rxs2_rx0_ctle_train_done_o) = 1;
- EPHY_WREG(E56G__PMD_RXS2_OVRDVAL_1);
- EPHY_RREG(E56G__PMD_RXS3_OVRDVAL_1);
- EPHY_XFLD(E56G__PMD_RXS3_OVRDVAL_1, rxs3_rx0_ctle_train_en_i) = 0;
- EPHY_XFLD(E56G__PMD_RXS3_OVRDVAL_1, rxs3_rx0_ctle_train_done_o) = 1;
- EPHY_WREG(E56G__PMD_RXS3_OVRDVAL_1);
+ /* a. Remove the OVERRIDE on ALIAS::RXS::VGA_TRAIN_EN */
+ addr = E56G__PMD_RXS0_OVRDEN_1_ADDR + (E56PHY_PMD_RX_OFFSET * i);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_vga_train_en_i) = 0;
+ /* b. Remove the OVERRIDE on ALIAS::RXS::CTLE_TRAIN_EN */
+ if (bypass_ctle == 0)
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_ctle_train_en_i) = 0;
+ wr32_ephy(hw, addr, rdata);
- EPHY_RREG(E56G__PMD_RXS1_OVRDEN_1);
- EPHY_XFLD(E56G__PMD_RXS1_OVRDEN_1, ovrd_en_rxs1_rx0_ctle_train_en_i) = 1;
- EPHY_XFLD(E56G__PMD_RXS1_OVRDEN_1, ovrd_en_rxs1_rx0_ctle_train_done_o) = 1;
- EPHY_WREG(E56G__PMD_RXS1_OVRDEN_1);
- EPHY_RREG(E56G__PMD_RXS2_OVRDEN_1);
- EPHY_XFLD(E56G__PMD_RXS2_OVRDEN_1, ovrd_en_rxs2_rx0_ctle_train_en_i) = 1;
- EPHY_XFLD(E56G__PMD_RXS2_OVRDEN_1, ovrd_en_rxs2_rx0_ctle_train_done_o) = 1;
- EPHY_WREG(E56G__PMD_RXS2_OVRDEN_1);
- EPHY_RREG(E56G__PMD_RXS3_OVRDEN_1);
- EPHY_XFLD(E56G__PMD_RXS3_OVRDEN_1, ovrd_en_rxs3_rx0_ctle_train_en_i) = 1;
- EPHY_XFLD(E56G__PMD_RXS3_OVRDEN_1, ovrd_en_rxs3_rx0_ctle_train_done_o) = 1;
- EPHY_WREG(E56G__PMD_RXS3_OVRDEN_1);
}
- return 0;
+ return status;
}
static inline int
@@ -1977,20 +3006,44 @@ txgbe_e56_cfg_temp(struct txgbe_hw *hw)
return 0;
}
-static int txgbe_e56_config_rx(struct txgbe_hw *hw, u32 speed)
+static int txgbe_e56_config_rx_40G(struct txgbe_hw *hw, u32 speed)
{
s32 status;
- status = txgbe_e56_rxs_calib_adapt_seq(hw, speed);
+ status = txgbe_e56_rxs_calib_adapt_seq_40G(hw, speed);
if (status)
return status;
/* Step 2 of 2.3.4 */
- txgbe_e56_set_rxs_ufine_le_max(hw, speed);
+ txgbe_e56_set_rxs_ufine_le_max_40g(hw, speed);
/* 2.3.4 RXS post CDR lock temperature tracking sequence */
- txgbe_temp_track_seq(hw, speed);
+ txgbe_temp_track_seq_40g(hw, speed);
+
+ hw->link_valid = true;
+
+ return 0;
+}
+
+static int txgbe_e56_config_rx(struct txgbe_hw *hw, u32 speed)
+{
+ s32 status;
+ if (speed == TXGBE_LINK_SPEED_40GB_FULL) {
+ status = txgbe_e56_config_rx_40G(hw, speed);
+ if (status)
+ return status;
+ } else {
+ status = txgbe_e56_rxs_calib_adapt_seq(hw, speed);
+ if (status)
+ return status;
+
+ /* Step 2 of 2.3.4 */
+ txgbe_e56_set_rxs_ufine_le_max(hw, speed);
+
+ /* 2.3.4 RXS post CDR lock temperature tracking sequence */
+ txgbe_temp_track_seq(hw, speed);
+ }
return 0;
}
@@ -2000,6 +3053,151 @@ static int txgbe_e56_config_rx(struct txgbe_hw *hw, u32 speed)
* Completion of RXS powerdown can be confirmed by
* observing ALIAS::PDIG::CTRL_FSM_RX_ST = POWERDN_ST
*/
+static int txgbe_e56_disable_rx40G(struct txgbe_hw *hw)
+{
+ int status = 0;
+ unsigned int rdata, timer;
+ unsigned int addr, temp;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ /* 1. Disable OVERRIDE on below aliases */
+ /* a. ALIAS::RXS::RANGE_SEL */
+ rdata = 0x0000;
+ addr = E56G__RXS0_ANA_OVRDEN_0_ADDR + (i * E56PHY_RXS_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_0, ovrd_en_ana_bbcdr_osc_range_sel_i) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__RXS0_ANA_OVRDEN_1_ADDR + (i * E56PHY_RXS_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ /* b. ALIAS::RXS::COARSE */
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_coarse_i) = 0;
+ /* c. ALIAS::RXS::FINE */
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_fine_i) = 0;
+ /* d. ALIAS::RXS::ULTRAFINE */
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_ultrafine_i) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ /* e. ALIAS::RXS::SAMP_CAL_DONE */
+ addr = E56G__PMD_RXS0_OVRDEN_0_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_0, ovrd_en_rxs0_rx0_samp_cal_done_o) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__PMD_RXS0_OVRDEN_2_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ /* f. ALIAS::RXS::ADC_OFST_ADAPT_EN */
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_2, ovrd_en_rxs0_rx0_adc_ofst_adapt_en_i) = 0;
+ /* g. ALIAS::RXS::ADC_GAIN_ADAPT_EN */
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_2, ovrd_en_rxs0_rx0_adc_gain_adapt_en_i) = 0;
+ /* j. ALIAS::RXS::ADC_INTL_ADAPT_EN */
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_2, ovrd_en_rxs0_rx0_adc_intl_adapt_en_i) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__PMD_RXS0_OVRDEN_1_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ /* h. ALIAS::RXS::ADC_INTL_CAL_EN */
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_adc_intl_cal_en_i) = 0;
+ /* i. ALIAS::RXS::ADC_INTL_CAL_DONE */
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_adc_intl_cal_done_o) = 0;
+ /* k. ALIAS::RXS::CDR_EN */
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_cdr_en_i) = 0;
+ /* l. ALIAS::RXS::VGA_TRAIN_EN */
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_vga_train_en_i) = 0;
+ /* m. ALIAS::RXS::CTLE_TRAIN_EN */
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_ctle_train_en_i) = 0;
+ /* p. ALIAS::RXS::RX_FETX_TRAIN_DONE */
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_txffe_train_done_o) = 0;
+ /* r. ALIAS::RXS::RX_TXFFE_COEFF_CHANGE */
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_txffe_coeff_change_o) = 0;
+ /* s. ALIAS::RXS::RX_TXFFE_TRAIN_ENACK */
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_txffe_train_enack_o) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__PMD_RXS0_OVRDEN_3_ADDR + (i * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ /* n. ALIAS::RXS::RX_FETX_MOD_TYPE */
+ /* o. ALIAS::RXS::RX_FETX_MOD_TYPE_UPDATE */
+ temp = EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_3, ovrd_en_rxs0_rx0_spareout_o);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_3, ovrd_en_rxs0_rx0_spareout_o) = temp & 0x8F;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__RXS0_DIG_OVRDEN_1_ADDR + (i * E56PHY_RXS_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ /* q. ALIAS::RXS::SLICER_THRESHOLD_OVRD_EN */
+ EPHY_XFLD(E56G__RXS0_DIG_OVRDEN_1, top_comp_th_ovrd_en) = 0;
+ EPHY_XFLD(E56G__RXS0_DIG_OVRDEN_1, mid_comp_th_ovrd_en) = 0;
+ EPHY_XFLD(E56G__RXS0_DIG_OVRDEN_1, bot_comp_th_ovrd_en) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ /* 2. Disable pattern checker */
+ addr = E56G__RXS0_DFT_1_ADDR + (i * E56PHY_RXS_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_DFT_1, ber_en) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ /* 3. Disable internal serial loopback mode */
+ addr = E56G__RXS0_ANA_OVRDEN_3_ADDR + (i * E56PHY_RXS_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_3, ovrd_en_ana_sel_lpbk_i) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ addr = E56G__RXS0_ANA_OVRDEN_2_ADDR + (i * E56PHY_RXS_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_2, ovrd_en_ana_en_adccal_lpbk_i) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ /* 4. Enable bypass of clock gates in RXS - */
+ addr = E56G__RXS0_RXS_CFG_0_ADDR + (i * E56PHY_RXS_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__RXS0_RXS_CFG_0, train_clk_gate_bypass_en) = 0x1FFF;
+ wr32_ephy(hw, addr, rdata);
+ }
+
+ /* 5. Disable KR training mode */
+ /* a. ALIAS::PDIG::KR_TRAINING_MODE = 0b0 */
+ addr = E56G__PMD_BASER_PMD_CONTROL_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__PMD_BASER_PMD_CONTROL, training_enable_ln0) = 0;
+ EPHY_XFLD(E56G__PMD_BASER_PMD_CONTROL, training_enable_ln1) = 0;
+ EPHY_XFLD(E56G__PMD_BASER_PMD_CONTROL, training_enable_ln2) = 0;
+ EPHY_XFLD(E56G__PMD_BASER_PMD_CONTROL, training_enable_ln3) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ /* 6. Disable RX to TX parallel loopback */
+ /* a. ALIAS::PDIG::RX_TO_TX_LPBK_EN = 0b0 */
+ addr = E56G__PMD_PMD_CFG_5_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__PMD_PMD_CFG_5, rx_to_tx_lpbk_en) = 0x0;
+ wr32_ephy(hw, addr, rdata);
+
+ /*
+ * The FSM to disable RXS is present in PDIG. The FSM disables the RXS when
+ * PDIG::PMD_CFG[0]::rx_en_cfg[<lane no.>] = 0b0
+ */
+ txgbe_e56_ephy_config(E56G__PMD_PMD_CFG_0, rx_en_cfg, 0);
+
+ /* Wait RX FSM to be POWERDN_ST */
+ timer = 0;
+
+ while (EPHY_XFLD(E56G__PMD_CTRL_FSM_RX_STAT_0, ctrl_fsm_rx0_st) != 0x21 ||
+ EPHY_XFLD(E56G__PMD_CTRL_FSM_RX_STAT_0, ctrl_fsm_rx1_st) != 0x21 ||
+ EPHY_XFLD(E56G__PMD_CTRL_FSM_RX_STAT_0, ctrl_fsm_rx2_st) != 0x21 ||
+ EPHY_XFLD(E56G__PMD_CTRL_FSM_RX_STAT_0, ctrl_fsm_rx3_st) != 0x21) {
+ rdata = 0;
+ addr = E56PHY_CTRL_FSM_RX_STAT_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ usec_delay(100);
+ if (timer++ > PHYINIT_TIMEOUT) {
+ DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!\n");
+ break;
+ }
+ }
+
+ return status;
+}
+
static int txgbe_e56_disable_rx(struct txgbe_hw *hw)
{
int status = 0;
@@ -2132,8 +3330,13 @@ int txgbe_e56_reconfig_rx(struct txgbe_hw *hw, u32 speed)
* 14. Do SEQ::RX_DISABLE to disable RXS. Poll ALIAS::PDIG::CTRL_FSM_RX_ST
* and confirm its value is POWERDN_ST
*/
- txgbe_e56_disable_rx(hw);
- status = txgbe_e56_config_rx(hw, speed);
+ if (hw->mac.type == txgbe_mac_aml40) {
+ txgbe_e56_disable_rx40G(hw);
+ status = txgbe_e56_config_rx_40G(hw, speed);
+ } else {
+ txgbe_e56_disable_rx(hw);
+ status = txgbe_e56_config_rx(hw, speed);
+ }
addr = E56PHY_INTR_0_ADDR;
wr32_ephy(hw, addr, E56PHY_INTR_0_IDLE_ENTRY1);
@@ -2200,6 +3403,86 @@ int txgbe_set_link_to_amlite(struct txgbe_hw *hw, u32 speed)
set_fields_e56(&value, 12, 12, 0);
wr32_epcs(hw, SR_AN_CTRL, value);
+ if (speed == TXGBE_LINK_SPEED_40GB_FULL) {
+ value = rd32_epcs(hw, SR_PCS_CTRL1);
+ set_fields_e56(&value, 5, 2, 0x3);
+ wr32_epcs(hw, SR_PCS_CTRL1, value);
+
+ value = rd32_epcs(hw, SR_PCS_CTRL2);
+ set_fields_e56(&value, 3, 0, 0x4);
+ wr32_epcs(hw, SR_PCS_CTRL2, value);
+
+ value = rd32_ephy(hw, ANA_OVRDVAL0);
+ set_fields_e56(&value, 29, 29, 0x1);
+ set_fields_e56(&value, 1, 1, 0x1);
+ wr32_ephy(hw, ANA_OVRDVAL0, value);
+
+ value = rd32_ephy(hw, ANA_OVRDVAL5);
+ set_fields_e56(&value, 24, 24, 0x1);
+ wr32_ephy(hw, ANA_OVRDVAL5, value);
+
+ value = rd32_ephy(hw, ANA_OVRDEN0);
+ set_fields_e56(&value, 1, 1, 0x1);
+ wr32_ephy(hw, ANA_OVRDEN0, value);
+
+ value = rd32_ephy(hw, ANA_OVRDEN1);
+ set_fields_e56(&value, 30, 30, 0x1);
+ set_fields_e56(&value, 25, 25, 0x1);
+ wr32_ephy(hw, ANA_OVRDEN1, value);
+
+ value = rd32_ephy(hw, PLL0_CFG0);
+ set_fields_e56(&value, 25, 24, 0x1);
+ set_fields_e56(&value, 17, 16, 0x3);
+ wr32_ephy(hw, PLL0_CFG0, value);
+
+ value = rd32_ephy(hw, PLL0_CFG2);
+ set_fields_e56(&value, 12, 8, 0x4);
+ wr32_ephy(hw, PLL0_CFG2, value);
+
+ value = rd32_ephy(hw, PLL1_CFG0);
+ set_fields_e56(&value, 25, 24, 0x1);
+ set_fields_e56(&value, 17, 16, 0x3);
+ wr32_ephy(hw, PLL1_CFG0, value);
+
+ value = rd32_ephy(hw, PLL1_CFG2);
+ set_fields_e56(&value, 12, 8, 0x8);
+ wr32_ephy(hw, PLL1_CFG2, value);
+
+ value = rd32_ephy(hw, PLL0_DIV_CFG0);
+ set_fields_e56(&value, 18, 8, 0x294);
+ set_fields_e56(&value, 4, 0, 0x8);
+ wr32_ephy(hw, PLL0_DIV_CFG0, value);
+
+ value = rd32_ephy(hw, DATAPATH_CFG0);
+ set_fields_e56(&value, 30, 28, 0x7);
+ set_fields_e56(&value, 26, 24, 0x5);
+ set_fields_e56(&value, 18, 16, 0x5);
+ set_fields_e56(&value, 14, 12, 0x5);
+ set_fields_e56(&value, 10, 8, 0x5);
+ wr32_ephy(hw, DATAPATH_CFG0, value);
+
+ value = rd32_ephy(hw, DATAPATH_CFG1);
+ set_fields_e56(&value, 26, 24, 0x5);
+ set_fields_e56(&value, 10, 8, 0x5);
+ set_fields_e56(&value, 18, 16, 0x5);
+ set_fields_e56(&value, 2, 0, 0x5);
+ wr32_ephy(hw, DATAPATH_CFG1, value);
+
+ value = rd32_ephy(hw, AN_CFG1);
+ set_fields_e56(&value, 4, 0, 0x2);
+ wr32_ephy(hw, AN_CFG1, value);
+
+ txgbe_e56_cfg_temp(hw);
+ txgbe_e56_cfg_40g(hw);
+
+ value = rd32_ephy(hw, PMD_CFG0);
+ set_fields_e56(&value, 21, 20, 0x3);
+ set_fields_e56(&value, 19, 12, 0xf);
+ set_fields_e56(&value, 8, 8, 0x0);
+ set_fields_e56(&value, 1, 1, 0x1);
+ wr32_ephy(hw, PMD_CFG0, value);
+ }
+
if (speed == TXGBE_LINK_SPEED_25GB_FULL) {
value = rd32_epcs(hw, SR_PCS_CTRL1);
set_fields_e56(&value, 5, 2, 5);
diff --git a/drivers/net/txgbe/base/txgbe_e56.h b/drivers/net/txgbe/base/txgbe_e56.h
index 96c95a414e..aeee0618a6 100644
--- a/drivers/net/txgbe/base/txgbe_e56.h
+++ b/drivers/net/txgbe/base/txgbe_e56.h
@@ -438,7 +438,12 @@ typedef union {
#define E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2 9, 8
#define E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_3 13, 12
-#define PHYINIT_TIMEOUT 1000 /* PHY initialization timeout value in 0.5ms unit */
+/* PHYINIT_TIMEOUT, a loop iteration counter, not a fixed time unit.
+ * The actual timeout duration depends on the usec_delay() or msleep()
+ * value used inside the polling loop. For example, when usec_delay(500)
+ * is used, the total timeout is approximately PHYINIT_TIMEOUT * 500 us.
+ */
+#define PHYINIT_TIMEOUT 1000
#define E56G__BASEADDR 0x0
@@ -1729,7 +1734,7 @@ typedef union {
void set_fields_e56(unsigned int *src_data, unsigned int bit_high,
unsigned int bit_low, unsigned int set_value);
-int txgbe_e56_rx_rd_second_code_40g(struct txgbe_hw *hw, int *SECOND_CODE, int lane);
+void txgbe_e56_rx_rd_second_code_40g(struct txgbe_hw *hw, int *SECOND_CODE, int lane);
void txgbe_e56_rx_rd_second_code(struct txgbe_hw *hw, int *SECOND_CODE);
u32 txgbe_e56_cfg_40g(struct txgbe_hw *hw);
u32 txgbe_e56_cfg_25g(struct txgbe_hw *hw);
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index b883a7b174..f432e6ce25 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2054,7 +2054,7 @@ txgbe_dev_stop(struct rte_eth_dev *dev)
PMD_INIT_FUNC_TRACE();
- if (hw->mac.type == txgbe_mac_aml)
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40)
rte_eal_alarm_cancel(txgbe_dev_setup_link_alarm_handler_aml, hw);
rte_eal_alarm_cancel(txgbe_dev_detect_sfp, dev);
@@ -3206,7 +3206,7 @@ txgbe_dev_setup_link_thread_handler(void *param)
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
rte_thread_detach(rte_thread_self());
- if (hw->mac.type == txgbe_mac_aml)
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40)
txgbe_dev_setup_link_alarm_handler_aml(hw);
else
txgbe_dev_setup_link_alarm_handler(dev);
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v7 14/21] net/txgbe: fix link stability for Amber-Lite backplane mode
From: Zaiyu Wang @ 2026-06-17 3:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617033400.376-1-zaiyuwang@trustnetic.com>
The link was previously configured via firmware, but this approach
resulted in unstable link behavior. To resolve the issue, re-add the
PHY configuration flow directly into the driver.
Fixes: ead3616f630d ("net/txgbe: support PHY configuration via SW-FW mailbox")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/meson.build | 1 +
drivers/net/txgbe/base/txgbe.h | 2 +
drivers/net/txgbe/base/txgbe_aml.c | 65 +-
drivers/net/txgbe/base/txgbe_aml40.c | 43 +-
drivers/net/txgbe/base/txgbe_e56.c | 22 +-
drivers/net/txgbe/base/txgbe_e56.h | 2 +
drivers/net/txgbe/base/txgbe_e56_bp.c | 2597 +++++++++++++++++++++++++
drivers/net/txgbe/base/txgbe_e56_bp.h | 3 +
drivers/net/txgbe/base/txgbe_hw.c | 6 +
drivers/net/txgbe/base/txgbe_hw.h | 4 +-
drivers/net/txgbe/base/txgbe_osdep.h | 4 +
drivers/net/txgbe/base/txgbe_phy.c | 21 +
drivers/net/txgbe/base/txgbe_phy.h | 22 +
drivers/net/txgbe/base/txgbe_type.h | 25 +-
drivers/net/txgbe/txgbe_ethdev.c | 109 +-
drivers/net/txgbe/txgbe_ethdev.h | 2 +-
16 files changed, 2898 insertions(+), 30 deletions(-)
create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.c
diff --git a/drivers/net/txgbe/base/meson.build b/drivers/net/txgbe/base/meson.build
index 305c0291e3..a9a02577ce 100644
--- a/drivers/net/txgbe/base/meson.build
+++ b/drivers/net/txgbe/base/meson.build
@@ -13,4 +13,5 @@ base_sources = files(
'txgbe_phy.c',
'txgbe_vf.c',
'txgbe_e56.c',
+ 'txgbe_e56_bp.c',
)
diff --git a/drivers/net/txgbe/base/txgbe.h b/drivers/net/txgbe/base/txgbe.h
index 673a299860..27c3e3be38 100644
--- a/drivers/net/txgbe/base/txgbe.h
+++ b/drivers/net/txgbe/base/txgbe.h
@@ -13,5 +13,7 @@
#include "txgbe_hw.h"
#include "txgbe_vf.h"
#include "txgbe_dcb.h"
+#include "txgbe_e56.h"
+#include "txgbe_e56_bp.h"
#endif /* _TXGBE_H_ */
diff --git a/drivers/net/txgbe/base/txgbe_aml.c b/drivers/net/txgbe/base/txgbe_aml.c
index 6388893bca..5d449a0bd9 100644
--- a/drivers/net/txgbe/base/txgbe_aml.c
+++ b/drivers/net/txgbe/base/txgbe_aml.c
@@ -13,6 +13,7 @@
#include "txgbe_hw.h"
#include "txgbe_aml.h"
#include "txgbe_e56.h"
+#include "txgbe_e56_bp.h"
void txgbe_init_ops_aml(struct txgbe_hw *hw)
{
@@ -84,6 +85,13 @@ s32 txgbe_check_mac_link_aml(struct txgbe_hw *hw, u32 *speed,
*speed = TXGBE_LINK_SPEED_UNKNOWN;
}
+ if (txgbe_xpcs_an_enabled(hw)) {
+ if (!hw->an_done) {
+ *link_up = false;
+ *speed = TXGBE_LINK_SPEED_UNKNOWN;
+ }
+ }
+
return 0;
}
@@ -95,23 +103,41 @@ s32 txgbe_get_link_capabilities_aml(struct txgbe_hw *hw,
*speed = TXGBE_LINK_SPEED_10GB_FULL |
TXGBE_LINK_SPEED_25GB_FULL;
*autoneg = true;
+ } else if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
+ hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1) {
+ if (hw->phy.fiber_suppport_speed ==
+ TXGBE_LINK_SPEED_10GB_FULL) {
+ hw->devarg.auto_neg = false;
+ *autoneg = false;
+ } else {
+ *autoneg = true;
+ }
+ *speed = hw->phy.fiber_suppport_speed;
} else if (hw->phy.sfp_type == txgbe_sfp_type_25g_sr_core0 ||
hw->phy.sfp_type == txgbe_sfp_type_25g_sr_core1 ||
hw->phy.sfp_type == txgbe_sfp_type_25g_lr_core0 ||
- hw->phy.sfp_type == txgbe_sfp_type_25g_lr_core1) {
+ hw->phy.sfp_type == txgbe_sfp_type_25g_lr_core1 ||
+ hw->phy.sfp_type == txgbe_sfp_type_25g_aoc_core0 ||
+ hw->phy.sfp_type == txgbe_sfp_type_25g_aoc_core1) {
*speed = TXGBE_LINK_SPEED_25GB_FULL;
*autoneg = false;
- } else if (hw->phy.sfp_type == txgbe_sfp_type_25g_aoc_core0 ||
- hw->phy.sfp_type == txgbe_sfp_type_25g_aoc_core1) {
- *speed = TXGBE_LINK_SPEED_25GB_FULL;
+ } else if (hw->phy.media_type == txgbe_media_type_backplane) {
+ /* Backplane */
+ *speed = TXGBE_LINK_SPEED_10GB_FULL |
+ TXGBE_LINK_SPEED_25GB_FULL;
+ /* Backplane supports autonegotiation */
+ *autoneg = hw->devarg.auto_neg;
+ } else if (hw->phy.media_type == txgbe_media_type_fiber) {
+ /* Fiber */
+ *speed = TXGBE_LINK_SPEED_10GB_FULL |
+ TXGBE_LINK_SPEED_25GB_FULL;
*autoneg = false;
} else {
- /* SFP */
- if (hw->phy.sfp_type == txgbe_sfp_type_not_present)
- *speed = TXGBE_LINK_SPEED_25GB_FULL;
- else
- *speed = TXGBE_LINK_SPEED_10GB_FULL;
- *autoneg = true;
+ /* Unknown */
+ *speed = TXGBE_LINK_SPEED_UNKNOWN;
+ *autoneg = false;
+ PMD_DRV_LOG(DEBUG, "GET link capabilities failed");
+ return TXGBE_ERR_LINK_SETUP;
}
return 0;
@@ -193,7 +219,7 @@ s32 txgbe_setup_phy_link_aml(struct txgbe_hw *hw,
*need_reset = false;
- if (hw->phy.sfp_type == txgbe_sfp_type_not_present) {
+ if (hw->phy.sfp_type == txgbe_sfp_type_not_present && !txgbe_is_backplane(hw)) {
DEBUGOUT("SFP not detected, skip setup mac link");
return 0;
}
@@ -216,6 +242,23 @@ s32 txgbe_setup_phy_link_aml(struct txgbe_hw *hw,
if (speed == TXGBE_LINK_SPEED_UNKNOWN)
return TXGBE_ERR_LINK_SETUP;
+ if (txgbe_xpcs_an_enabled(hw)) {
+ txgbe_e56_check_phy_link(hw, &link_speed, &link_up);
+ if (link_up && hw->an_done && !autoneg_wait_to_complete)
+ return status;
+ rte_spinlock_lock(&hw->phy_lock);
+ txgbe_e56_set_phy_link_mode(hw, speed, autoneg_wait_to_complete);
+ rte_spinlock_unlock(&hw->phy_lock);
+ return 0;
+ }
+
+ if (txgbe_is_backplane(hw) || txgbe_is_dac_cable(hw) ||
+ hw->phy.ffe_set) {
+ rte_spinlock_lock(&hw->phy_lock);
+ txgbe_e56_tx_ffe_cfg(hw, speed);
+ rte_spinlock_unlock(&hw->phy_lock);
+ }
+
if (txgbe_gpio_ext_check(hw, TXGBE_SFP1_MOD_ABS_LS |
TXGBE_SFP1_RX_LOS_LS)) {
DEBUGOUT("RX LOS");
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 09bc7ed58c..1098efe5e6 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -14,6 +14,7 @@
#include "txgbe_aml.h"
#include "txgbe_aml40.h"
#include "txgbe_e56.h"
+#include "txgbe_e56_bp.h"
void txgbe_init_ops_aml40(struct txgbe_hw *hw)
{
@@ -98,7 +99,10 @@ s32 txgbe_get_link_capabilities_aml40(struct txgbe_hw *hw,
if (hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core0 ||
hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core1) {
*speed = TXGBE_LINK_SPEED_40GB_FULL;
- *autoneg = false;
+ *autoneg = true;
+ } else if (txgbe_is_backplane(hw)) {
+ *speed = TXGBE_LINK_SPEED_40GB_FULL;
+ *autoneg = true;
} else {
/*
* Temporary workaround: set speed to 40G even if sfp not present
@@ -115,8 +119,22 @@ s32 txgbe_get_link_capabilities_aml40(struct txgbe_hw *hw,
u32 txgbe_get_media_type_aml40(struct txgbe_hw *hw)
{
- UNREFERENCED_PARAMETER(hw);
- return txgbe_media_type_fiber_qsfp;
+ u8 device_type = hw->subsystem_device_id & 0xF0;
+ enum txgbe_media_type media_type;
+
+ switch (device_type) {
+ case TXGBE_DEV_ID_KR_KX_KX4:
+ media_type = txgbe_media_type_backplane;
+ break;
+ case TXGBE_DEV_ID_SFP:
+ media_type = txgbe_media_type_fiber_qsfp;
+ break;
+ default:
+ media_type = txgbe_media_type_unknown;
+ break;
+ }
+
+ return media_type;
}
s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
@@ -135,7 +153,7 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
*need_reset = false;
- if (hw->phy.sfp_type == txgbe_sfp_type_not_present)
+ if (hw->phy.sfp_type == txgbe_sfp_type_not_present && !txgbe_is_backplane(hw))
hw->phy.identify_sfp(hw);
/* Check to see if speed passed in is supported. */
@@ -148,6 +166,23 @@ s32 txgbe_setup_phy_link_aml40(struct txgbe_hw *hw,
if (speed == TXGBE_LINK_SPEED_UNKNOWN)
return TXGBE_ERR_LINK_SETUP;
+ if (txgbe_xpcs_an_enabled(hw)) {
+ txgbe_e56_check_phy_link(hw, &link_speed, &link_up);
+ if (link_up && hw->an_done && !autoneg_wait_to_complete)
+ return status;
+ rte_spinlock_lock(&hw->phy_lock);
+ txgbe_e56_set_phy_link_mode(hw, 40, autoneg_wait_to_complete);
+ rte_spinlock_unlock(&hw->phy_lock);
+ return status;
+ }
+
+ if (txgbe_is_backplane(hw) || txgbe_is_dac_cable(hw) ||
+ hw->phy.ffe_set) {
+ rte_spinlock_lock(&hw->phy_lock);
+ txgbe_e56_tx_ffe_cfg(hw, speed);
+ rte_spinlock_unlock(&hw->phy_lock);
+ }
+
for (i = 0; i < 4; i++) {
txgbe_e56_check_phy_link(hw, &link_speed, &link_up);
if (link_up)
diff --git a/drivers/net/txgbe/base/txgbe_e56.c b/drivers/net/txgbe/base/txgbe_e56.c
index 3566d13426..0ac306387b 100644
--- a/drivers/net/txgbe/base/txgbe_e56.c
+++ b/drivers/net/txgbe/base/txgbe_e56.c
@@ -53,7 +53,7 @@ int txgbe_e56_int_cmp(const void *a, const void *b)
}
s32 txgbe_e56_check_phy_link(struct txgbe_hw *hw, u32 *speed,
- bool *link_up)
+ bool *link_up)
{
u32 rdata = 0;
u32 links_reg = 0;
@@ -101,7 +101,8 @@ u32 txgbe_e56_tx_ffe_cfg(struct txgbe_hw *hw, u32 speed)
post = S10G_TX_FFE_CFG_POST;
} else if (speed == TXGBE_LINK_SPEED_25GB_FULL) {
if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
- hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1) {
+ hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1 ||
+ txgbe_is_backplane(hw)) {
ffe_main = S25G_TX_FFE_CFG_DAC_MAIN;
pre1 = S25G_TX_FFE_CFG_DAC_PRE1;
pre2 = S25G_TX_FFE_CFG_DAC_PRE2;
@@ -119,7 +120,8 @@ u32 txgbe_e56_tx_ffe_cfg(struct txgbe_hw *hw, u32 speed)
post = S10G_TX_FFE_CFG_POST;
if (hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core0 ||
- hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core1) {
+ hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core1 ||
+ txgbe_is_backplane(hw)) {
ffe_main = S40G_TX_FFE_CFG_MAIN;
pre1 = S40G_TX_FFE_CFG_PRE1;
pre2 = S40G_TX_FFE_CFG_PRE2;
@@ -1508,7 +1510,7 @@ txgbe_e56_rxs_osc_init_for_temp_track_range(struct txgbe_hw *hw, u32 speed)
rdata = rd32_ephy(hw, addr);
if (timer++ > PHYINIT_TIMEOUT) {
- DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!\n");
+ DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!");
return -1;
}
}
@@ -1542,7 +1544,7 @@ txgbe_e56_rxs_osc_init_for_temp_track_range(struct txgbe_hw *hw, u32 speed)
if (((rdata >> (i * 8)) & 0x3f) == 0x21)
break;
if (timer++ > PHYINIT_TIMEOUT) {
- DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!\n");
+ DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!");
return -1;
}
}
@@ -1618,7 +1620,7 @@ txgbe_e56_rxs_osc_init_for_temp_track_range(struct txgbe_hw *hw, u32 speed)
addr = E56PHY_CTRL_FSM_RX_STAT_0_ADDR;
rdata = rd32_ephy(hw, addr);
if (timer++ > PHYINIT_TIMEOUT) {
- DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!\n");
+ DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!");
return -1;
}
}
@@ -1664,7 +1666,7 @@ txgbe_e56_rxs_osc_init_for_temp_track_range(struct txgbe_hw *hw, u32 speed)
if (((rdata >> (i * 8)) & 0x3f) == 0x21)
break;
if (timer++ > PHYINIT_TIMEOUT) {
- DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!\n");
+ DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!");
return -1;
}
}
@@ -1929,7 +1931,7 @@ int txgbe_temp_track_seq_40g(struct txgbe_hw *hw, u32 speed)
CMVAR_UFINE_FMIN_WRAP = S25G_CMVAR_UFINE_FMIN_WRAP;
CMVAR_FINE_FMIN_WRAP = S25G_CMVAR_FINE_FMIN_WRAP;
} else {
- DEBUGOUT("Error Speed\n");
+ DEBUGOUT("Error Speed");
return 0;
}
@@ -3190,7 +3192,7 @@ static int txgbe_e56_disable_rx40G(struct txgbe_hw *hw)
rdata = rd32_ephy(hw, addr);
usec_delay(100);
if (timer++ > PHYINIT_TIMEOUT) {
- DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!\n");
+ DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!");
break;
}
}
@@ -3296,7 +3298,7 @@ static int txgbe_e56_disable_rx(struct txgbe_hw *hw)
break;
usec_delay(100);
if (timer++ > PHYINIT_TIMEOUT) {
- DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!\n");
+ DEBUGOUT("ERROR: Wait E56PHY_CTRL_FSM_RX_STAT_0_ADDR Timeout!");
break;
}
}
diff --git a/drivers/net/txgbe/base/txgbe_e56.h b/drivers/net/txgbe/base/txgbe_e56.h
index aeee0618a6..feb4de0546 100644
--- a/drivers/net/txgbe/base/txgbe_e56.h
+++ b/drivers/net/txgbe/base/txgbe_e56.h
@@ -1744,6 +1744,8 @@ int txgbe_temp_track_seq(struct txgbe_hw *hw, u32 speed);
int txgbe_e56_get_temp(struct txgbe_hw *hw, int *temp);
int txgbe_set_link_to_amlite(struct txgbe_hw *hw, u32 speed);
int txgbe_e56_reconfig_rx(struct txgbe_hw *hw, u32 speed);
+s32 txgbe_e56_check_phy_link(struct txgbe_hw *hw, u32 *speed,
+ bool *link_up);
s32 txgbe_e56_fec_set(struct txgbe_hw *hw);
s32 txgbe_e56_fec_polling(struct txgbe_hw *hw, bool *link_up);
u32 txgbe_e56_tx_ffe_cfg(struct txgbe_hw *hw, u32 speed);
diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.c b/drivers/net/txgbe/base/txgbe_e56_bp.c
new file mode 100644
index 0000000000..1237b73914
--- /dev/null
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.c
@@ -0,0 +1,2597 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024-2026 Beijing WangXun Technology Co., Ltd.
+ */
+
+#include "txgbe_e56.h"
+#include "txgbe_hw.h"
+#include "txgbe_osdep.h"
+#include "txgbe_phy.h"
+#include "txgbe_e56_bp.h"
+#include "txgbe.h"
+#include "../txgbe_logs.h"
+
+static int
+txgbe_e56_set_rxs_ufine_le_max(struct txgbe_hw *hw, u32 speed)
+{
+ u32 rdata, addr;
+ u32 ULTRAFINE_CODE[4] = {0};
+ int lane_num = 0, lane_idx = 0;
+ u32 CMVAR_UFINE_MAX = 0;
+
+ switch (speed) {
+ case 10:
+ CMVAR_UFINE_MAX = S10G_CMVAR_UFINE_MAX;
+ lane_num = 1;
+ break;
+ case 40:
+ CMVAR_UFINE_MAX = S10G_CMVAR_UFINE_MAX;
+ lane_num = 4;
+ break;
+ case 25:
+ CMVAR_UFINE_MAX = S25G_CMVAR_UFINE_MAX;
+ lane_num = 1;
+ break;
+ default:
+ BP_LOG("%s %d :Invalid speed\n", __func__, __LINE__);
+ break;
+ }
+
+ for (lane_idx = 0; lane_idx < lane_num; lane_idx++) {
+ /* ii get rx ana_bbcdr_ultrafine_i[14, 12] per lane */
+ addr = E56G__RXS0_ANA_OVRDVAL_5_ADDR + (E56PHY_RXS_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ ULTRAFINE_CODE[lane_idx] = FIELD_GET_M(GENMASK(14, 12), rdata);
+ BP_LOG("ULTRAFINE_CODE[%d] = %d, CMVAR_UFINE_MAX: %x\n",
+ lane_idx, ULTRAFINE_CODE[lane_idx], CMVAR_UFINE_MAX);
+ }
+
+ for (lane_idx = 0; lane_idx < lane_num; lane_idx++) {
+ /* b. Perform the below logic sequence */
+ while (ULTRAFINE_CODE[lane_idx] > CMVAR_UFINE_MAX) {
+ ULTRAFINE_CODE[lane_idx] -= 1;
+ addr = E56G__RXS0_ANA_OVRDVAL_5_ADDR +
+ (E56PHY_RXS_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 14, 12, ULTRAFINE_CODE[lane_idx]);
+ wr32_ephy(hw, addr, rdata);
+
+ /* ovrd_en_ana_bbcdr_ultrafine=1 override ASIC value */
+ addr = E56G__RXS0_ANA_OVRDEN_1_ADDR +
+ (E56PHY_RXS_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ wr32_ephy(hw, addr, rdata | BIT(3));
+
+ /* Wait until 1milliseconds or greater */
+ usec_delay(1000);
+ }
+ }
+ return 0;
+}
+
+static int txgbe_e56_rxs_osc_init_for_temp_track_range(struct txgbe_hw *hw,
+ u32 speed)
+{
+ int OFFSET_CENTRE_RANGE_H[4] = {0}, OFFSET_CENTRE_RANGE_L[4] = {}, RANGE_FINAL[4] = {};
+ int RX_COARSE_MID_TD, CMVAR_RANGE_H = 0, CMVAR_RANGE_L = 0;
+ int status = 0, lane_num = 0;
+ int T = 40, lane_id = 0;
+ u32 addr, rdata;
+
+ /* Set CMVAR_RANGE_H/L based on the link speed mode */
+ switch (speed) {
+ case 10:
+ CMVAR_RANGE_H = S10G_CMVAR_RANGE_H;
+ CMVAR_RANGE_L = S10G_CMVAR_RANGE_L;
+ lane_num = 1;
+ break;
+ case 40:
+ CMVAR_RANGE_H = S10G_CMVAR_RANGE_H;
+ CMVAR_RANGE_L = S10G_CMVAR_RANGE_L;
+ lane_num = 4;
+ break;
+ case 25:
+ CMVAR_RANGE_H = S25G_CMVAR_RANGE_H;
+ CMVAR_RANGE_L = S25G_CMVAR_RANGE_L;
+ lane_num = 1;
+ break;
+ default:
+ BP_LOG("%s %d :Invalid speed\n", __func__, __LINE__);
+ break;
+ }
+
+ /* 1. Read the temperature T just before RXS is enabled. */
+ txgbe_e56_get_temp(hw, &T);
+
+ /* 2. Define software variable RX_COARSE_MID_TD */
+ if (T < -5)
+ RX_COARSE_MID_TD = 10;
+ else if (T < 30)
+ RX_COARSE_MID_TD = 9;
+ else if (T < 65)
+ RX_COARSE_MID_TD = 8;
+ else if (T < 100)
+ RX_COARSE_MID_TD = 7;
+ else
+ RX_COARSE_MID_TD = 6;
+
+ for (lane_id = 0; lane_id < lane_num; lane_id++) {
+ addr = 0x0b4 + (0x200 * lane_id);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 1, 0, CMVAR_RANGE_H);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x08c + (0x200 * lane_id);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 29, 29, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1540 + (0x02c * lane_id);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 22, 22, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1530 + (0x02c * lane_id);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 27, 27, 0x1);
+ wr32_ephy(hw, addr, rdata);
+ }
+ rdata = rd32_ephy(hw, 0x1400);
+ set_fields_e56(&rdata, 19, 16, GENMASK(lane_num - 1, 0));
+ wr32_ephy(hw, 0x1400, rdata);
+ status |= kr_read_poll(rd32_ephy, rdata,
+ (((rdata & 0x3f3f3f3f) & GENMASK(8 * lane_num - 1, 0))
+ == (0x09090909 & GENMASK(8 * lane_num - 1, 0))),
+ 100, 2000, hw,
+ E56PHY_CTRL_FSM_RX_STAT_0_ADDR);
+ if (status)
+ BP_LOG("Wait fsm_rx_sts 1 = %x : %d, Wait rx_sts %s.\n",
+ rdata, status, status ? "FAILED" : "SUCCESS");
+
+ for (lane_id = 0; lane_id < lane_num; lane_id++) {
+ addr = 0x0b4 + (0x0200 * lane_id);
+ rdata = rd32_ephy(hw, addr);
+ OFFSET_CENTRE_RANGE_H[lane_id] = (rdata >> 4) & 0xf;
+ if (OFFSET_CENTRE_RANGE_H[lane_id] > RX_COARSE_MID_TD)
+ OFFSET_CENTRE_RANGE_H[lane_id] = OFFSET_CENTRE_RANGE_H[lane_id] -
+ RX_COARSE_MID_TD;
+ else
+ OFFSET_CENTRE_RANGE_H[lane_id] = RX_COARSE_MID_TD -
+ OFFSET_CENTRE_RANGE_H[lane_id];
+ }
+
+ /* 7. Do SEQ::RX_DISABLE to disable RXS. */
+ rdata = rd32_ephy(hw, 0x1400);
+ set_fields_e56(&rdata, 19, 16, 0x0);
+ wr32_ephy(hw, 0x1400, rdata);
+ status |= kr_read_poll(rd32_ephy, rdata,
+ (((rdata & 0x3f3f3f3f) & GENMASK(8 * lane_num - 1, 0))
+ == (0x21212121 & GENMASK(8 * lane_num - 1, 0))),
+ 100, 2000, hw,
+ E56PHY_CTRL_FSM_RX_STAT_0_ADDR);
+ if (status)
+ BP_LOG("Wait fsm_rx_sts 2 = %x : %d, Wait rx_sts %s.\n",
+ rdata, status, status ? "FAILED" : "SUCCESS");
+ rdata = rd32_ephy(hw, 0x15ec);
+ wr32_ephy(hw, 0x15ec, rdata);
+
+ for (lane_id = 0; lane_id < lane_num; lane_id++) {
+ addr = 0x0b4 + (0x200 * lane_id);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 1, 0, CMVAR_RANGE_L);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x08c + (0x200 * lane_id);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 29, 29, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1540 + (0x02c * lane_id);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 22, 22, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1530 + (0x02c * lane_id);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 27, 27, 0x1);
+ wr32_ephy(hw, addr, rdata);
+ }
+ rdata = rd32_ephy(hw, 0x1400);
+ set_fields_e56(&rdata, 19, 16, 0xf);
+ wr32_ephy(hw, 0x1400, rdata);
+ status |= kr_read_poll(rd32_ephy, rdata,
+ (((rdata & 0x3f3f3f3f) & GENMASK(8 * lane_num - 1, 0))
+ == (0x09090909 & GENMASK(8 * lane_num - 1, 0))),
+ 100, 2000, hw,
+ E56PHY_CTRL_FSM_RX_STAT_0_ADDR);
+ if (status)
+ BP_LOG("Wait fsm_rx_sts 3 = %x : %d, Wait rx_sts %s.\n",
+ rdata, status, status ? "FAILED" : "SUCCESS");
+ for (lane_id = 0; lane_id < lane_num; lane_id++) {
+ addr = 0x0b4 + (0x0200 * lane_id);
+ rdata = rd32_ephy(hw, addr);
+ OFFSET_CENTRE_RANGE_L[lane_id] = (rdata >> 4) & 0xf;
+ if (OFFSET_CENTRE_RANGE_L[lane_id] > RX_COARSE_MID_TD)
+ OFFSET_CENTRE_RANGE_L[lane_id] = OFFSET_CENTRE_RANGE_L[lane_id] -
+ RX_COARSE_MID_TD;
+ else
+ OFFSET_CENTRE_RANGE_L[lane_id] = RX_COARSE_MID_TD -
+ OFFSET_CENTRE_RANGE_L[lane_id];
+ }
+ for (lane_id = 0; lane_id < lane_num; lane_id++) {
+ RANGE_FINAL[lane_id] = OFFSET_CENTRE_RANGE_L[lane_id] <
+ OFFSET_CENTRE_RANGE_H[lane_id] ?
+ CMVAR_RANGE_L : CMVAR_RANGE_H;
+ BP_LOG("lane_id:%d-RANGE_L:%x-RANGE_H:%x-RANGE_FINAL:%x\n",
+ lane_id, OFFSET_CENTRE_RANGE_L[lane_id],
+ OFFSET_CENTRE_RANGE_H[lane_id], RANGE_FINAL[lane_id]);
+ }
+
+ /* 7. Do SEQ::RX_DISABLE to disable RXS. */
+ rdata = rd32_ephy(hw, 0x1400);
+ set_fields_e56(&rdata, 19, 16, 0x0);
+ wr32_ephy(hw, 0x1400, rdata);
+ status |= kr_read_poll(rd32_ephy, rdata,
+ (((rdata & 0x3f3f3f3f) & GENMASK(8 * lane_num - 1, 0))
+ == (0x21212121 & GENMASK(8 * lane_num - 1, 0))),
+ 100, 2000, hw,
+ E56PHY_CTRL_FSM_RX_STAT_0_ADDR);
+ if (status)
+ BP_LOG("Wait fsm_rx_sts 4 = %x : %d, Wait rx_sts %s.\n",
+ rdata, status, status ? "FAILED" : "SUCCESS");
+ rdata = rd32_ephy(hw, 0x15ec);
+ wr32_ephy(hw, 0x15ec, rdata);
+
+ for (lane_id = 0; lane_id < lane_num; lane_id++) {
+ addr = 0x0b4 + (0x0200 * lane_id);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 1, 0, RANGE_FINAL[lane_id]);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = 0x1544 + (lane_id * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 25, 25, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1538 + (lane_id * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 0, 0, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1544 + (lane_id * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 28, 28, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1538 + (lane_id * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 3, 3, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = 0x1544 + (lane_id * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 16, 16, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1534 + (lane_id * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 23, 23, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1544 + (lane_id * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 17, 17, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1534 + (lane_id * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 24, 24, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1544 + (lane_id * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 31, 31, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1538 + (lane_id * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 6, 6, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1530 + (0x02c * lane_id);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 27, 27, 0x0);
+ wr32_ephy(hw, addr, rdata);
+ }
+
+ /* Do SEQ::RX_ENABLE */
+ rdata = rd32_ephy(hw, 0x1400);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_0_RX_EN_CFG, GENMASK(lane_num - 1, 0));
+ wr32_ephy(hw, 0x1400, rdata);
+
+ return status;
+}
+
+static int txgbe_e56_rxs_post_cdr_lock_temp_track_seq(struct txgbe_hw *hw,
+ u32 speed)
+{
+ int status = 0;
+ u32 rdata;
+ int SECOND_CODE;
+ int COARSE_CODE;
+ int FINE_CODE;
+ int ULTRAFINE_CODE;
+
+ int CMVAR_SEC_LOW_TH = 0;
+ int CMVAR_UFINE_MAX = 0;
+ int CMVAR_FINE_MAX = 0;
+ int CMVAR_UFINE_UMAX_WRAP = 0;
+ int CMVAR_COARSE_MAX = 0;
+ int CMVAR_UFINE_FMAX_WRAP = 0;
+ int CMVAR_FINE_FMAX_WRAP = 0;
+ int CMVAR_SEC_HIGH_TH = 0;
+ int CMVAR_UFINE_MIN = 0;
+ int CMVAR_FINE_MIN = 0;
+ int CMVAR_UFINE_UMIN_WRAP = 0;
+ int CMVAR_COARSE_MIN = 0;
+ int CMVAR_UFINE_FMIN_WRAP = 0;
+ int CMVAR_FINE_FMIN_WRAP = 0;
+
+ if (speed == 10) {
+ CMVAR_SEC_LOW_TH = S10G_CMVAR_SEC_LOW_TH;
+ CMVAR_UFINE_MAX = S10G_CMVAR_UFINE_MAX;
+ CMVAR_FINE_MAX = S10G_CMVAR_FINE_MAX;
+ CMVAR_UFINE_UMAX_WRAP = S10G_CMVAR_UFINE_UMAX_WRAP;
+ CMVAR_COARSE_MAX = S10G_CMVAR_COARSE_MAX;
+ CMVAR_UFINE_FMAX_WRAP = S10G_CMVAR_UFINE_FMAX_WRAP;
+ CMVAR_FINE_FMAX_WRAP = S10G_CMVAR_FINE_FMAX_WRAP;
+ CMVAR_SEC_HIGH_TH = S10G_CMVAR_SEC_HIGH_TH;
+ CMVAR_UFINE_MIN = S10G_CMVAR_UFINE_MIN;
+ CMVAR_FINE_MIN = S10G_CMVAR_FINE_MIN;
+ CMVAR_UFINE_UMIN_WRAP = S10G_CMVAR_UFINE_UMIN_WRAP;
+ CMVAR_COARSE_MIN = S10G_CMVAR_COARSE_MIN;
+ CMVAR_UFINE_FMIN_WRAP = S10G_CMVAR_UFINE_FMIN_WRAP;
+ CMVAR_FINE_FMIN_WRAP = S10G_CMVAR_FINE_FMIN_WRAP;
+ } else if (speed == 25) {
+ CMVAR_SEC_LOW_TH = S25G_CMVAR_SEC_LOW_TH;
+ CMVAR_UFINE_MAX = S25G_CMVAR_UFINE_MAX;
+ CMVAR_FINE_MAX = S25G_CMVAR_FINE_MAX;
+ CMVAR_UFINE_UMAX_WRAP = S25G_CMVAR_UFINE_UMAX_WRAP;
+ CMVAR_COARSE_MAX = S25G_CMVAR_COARSE_MAX;
+ CMVAR_UFINE_FMAX_WRAP = S25G_CMVAR_UFINE_FMAX_WRAP;
+ CMVAR_FINE_FMAX_WRAP = S25G_CMVAR_FINE_FMAX_WRAP;
+ CMVAR_SEC_HIGH_TH = S25G_CMVAR_SEC_HIGH_TH;
+ CMVAR_UFINE_MIN = S25G_CMVAR_UFINE_MIN;
+ CMVAR_FINE_MIN = S25G_CMVAR_FINE_MIN;
+ CMVAR_UFINE_UMIN_WRAP = S25G_CMVAR_UFINE_UMIN_WRAP;
+ CMVAR_COARSE_MIN = S25G_CMVAR_COARSE_MIN;
+ CMVAR_UFINE_FMIN_WRAP = S25G_CMVAR_UFINE_FMIN_WRAP;
+ CMVAR_FINE_FMIN_WRAP = S25G_CMVAR_FINE_FMIN_WRAP;
+ }
+
+ txgbe_e56_rx_rd_second_code(hw, &SECOND_CODE);
+
+ EPHY_RREG(E56G__RXS0_ANA_OVRDVAL_5);
+ COARSE_CODE = EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_coarse_i);
+ FINE_CODE = EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_fine_i);
+ ULTRAFINE_CODE = EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_ultrafine_i);
+
+ if (SECOND_CODE <= CMVAR_SEC_LOW_TH) {
+ if (ULTRAFINE_CODE < CMVAR_UFINE_MAX) {
+ txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_ultrafine_i,
+ ULTRAFINE_CODE + 1);
+ EPHY_RREG(E56G__RXS0_ANA_OVRDEN_1);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ EPHY_WREG(E56G__RXS0_ANA_OVRDEN_1);
+ } else if (FINE_CODE < CMVAR_FINE_MAX) {
+ EPHY_RREG(E56G__RXS0_ANA_OVRDVAL_5);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_ultrafine_i) = CMVAR_UFINE_UMAX_WRAP;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_fine_i) = FINE_CODE + 1;
+ EPHY_WREG(E56G__RXS0_ANA_OVRDVAL_5);
+ EPHY_RREG(E56G__RXS0_ANA_OVRDEN_1);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_fine_i) = 1;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ EPHY_WREG(E56G__RXS0_ANA_OVRDEN_1);
+ } else if (COARSE_CODE < CMVAR_COARSE_MAX) {
+ EPHY_RREG(E56G__RXS0_ANA_OVRDVAL_5);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_ultrafine_i) = CMVAR_UFINE_FMAX_WRAP;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_fine_i) = CMVAR_FINE_FMAX_WRAP;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_coarse_i) = COARSE_CODE + 1;
+ EPHY_WREG(E56G__RXS0_ANA_OVRDVAL_5);
+ EPHY_RREG(E56G__RXS0_ANA_OVRDEN_1);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_coarse_i) = 1;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_fine_i) = 1;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ EPHY_WREG(E56G__RXS0_ANA_OVRDEN_1);
+ } else {
+ BP_LOG("ERROR: (SECOND_CODE <= CMVAR_SEC_LOW_TH) temperature tracking occurs Error condition\n");
+ }
+ } else if (SECOND_CODE >= CMVAR_SEC_HIGH_TH) {
+ if (ULTRAFINE_CODE > CMVAR_UFINE_MIN) {
+ txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_ultrafine_i,
+ ULTRAFINE_CODE - 1);
+ EPHY_RREG(E56G__RXS0_ANA_OVRDEN_1);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ EPHY_WREG(E56G__RXS0_ANA_OVRDEN_1);
+ } else if (FINE_CODE > CMVAR_FINE_MIN) {
+ EPHY_RREG(E56G__RXS0_ANA_OVRDVAL_5);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_ultrafine_i) = CMVAR_UFINE_UMIN_WRAP;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_fine_i) = FINE_CODE - 1;
+ EPHY_WREG(E56G__RXS0_ANA_OVRDVAL_5);
+ EPHY_RREG(E56G__RXS0_ANA_OVRDEN_1);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_fine_i) = 1;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ EPHY_WREG(E56G__RXS0_ANA_OVRDEN_1);
+ } else if (COARSE_CODE > CMVAR_COARSE_MIN) {
+ EPHY_RREG(E56G__RXS0_ANA_OVRDVAL_5);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_ultrafine_i) = CMVAR_UFINE_FMIN_WRAP;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5,
+ ana_bbcdr_fine_i) = CMVAR_FINE_FMIN_WRAP;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDVAL_5, ana_bbcdr_coarse_i) = COARSE_CODE - 1;
+ EPHY_WREG(E56G__RXS0_ANA_OVRDVAL_5);
+ EPHY_RREG(E56G__RXS0_ANA_OVRDEN_1);
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_coarse_i) = 1;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_fine_i) = 1;
+ EPHY_XFLD(E56G__RXS0_ANA_OVRDEN_1, ovrd_en_ana_bbcdr_ultrafine_i) = 1;
+ EPHY_WREG(E56G__RXS0_ANA_OVRDEN_1);
+ } else {
+ BP_LOG("ERROR: (SECOND_CODE >= CMVAR_SEC_HIGH_TH) temperature tracking occurs Error condition\n");
+ }
+ }
+
+ return status;
+}
+
+static int txgbe_e56_ctle_bypass_seq(struct txgbe_hw *hw, u8 bp_link_mode)
+{
+ u32 rdata;
+
+ txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDVAL_0, ana_ctle_bypass_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDEN_0, ovrd_en_ana_ctle_bypass_i, 1);
+
+ txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDVAL_3, ana_ctle_cz_cstm_i, 0);
+ txgbe_e56_ephy_config(E56G__RXS0_ANA_OVRDEN_0, ovrd_en_ana_ctle_cz_cstm_i, 1);
+
+ EPHY_RREG(E56G__PMD_RXS0_OVRDVAL_1);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1, rxs0_rx0_ctle_train_en_i) = 0;
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1, rxs0_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS0_OVRDVAL_1);
+
+ EPHY_RREG(E56G__PMD_RXS0_OVRDEN_1);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_ctle_train_en_i) = 1;
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1, ovrd_en_rxs0_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS0_OVRDEN_1);
+
+ if (bp_link_mode == 40) {
+ txgbe_e56_ephy_config(E56G__RXS1_ANA_OVRDVAL_0, ana_ctle_bypass_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS1_ANA_OVRDEN_0, ovrd_en_ana_ctle_bypass_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS2_ANA_OVRDVAL_0, ana_ctle_bypass_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS2_ANA_OVRDEN_0, ovrd_en_ana_ctle_bypass_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS3_ANA_OVRDVAL_0, ana_ctle_bypass_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS3_ANA_OVRDEN_0, ovrd_en_ana_ctle_bypass_i, 1);
+
+ txgbe_e56_ephy_config(E56G__RXS1_ANA_OVRDVAL_3, ana_ctle_cz_cstm_i, 0);
+ txgbe_e56_ephy_config(E56G__RXS1_ANA_OVRDEN_0, ovrd_en_ana_ctle_cz_cstm_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS2_ANA_OVRDVAL_3, ana_ctle_cz_cstm_i, 0);
+ txgbe_e56_ephy_config(E56G__RXS2_ANA_OVRDEN_0, ovrd_en_ana_ctle_cz_cstm_i, 1);
+ txgbe_e56_ephy_config(E56G__RXS3_ANA_OVRDVAL_3, ana_ctle_cz_cstm_i, 0);
+ txgbe_e56_ephy_config(E56G__RXS3_ANA_OVRDEN_0, ovrd_en_ana_ctle_cz_cstm_i, 1);
+
+ EPHY_RREG(E56G__PMD_RXS1_OVRDVAL_1);
+ EPHY_XFLD(E56G__PMD_RXS1_OVRDVAL_1, rxs1_rx0_ctle_train_en_i) = 0;
+ EPHY_XFLD(E56G__PMD_RXS1_OVRDVAL_1, rxs1_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS1_OVRDVAL_1);
+ EPHY_RREG(E56G__PMD_RXS2_OVRDVAL_1);
+ EPHY_XFLD(E56G__PMD_RXS2_OVRDVAL_1, rxs2_rx0_ctle_train_en_i) = 0;
+ EPHY_XFLD(E56G__PMD_RXS2_OVRDVAL_1, rxs2_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS2_OVRDVAL_1);
+ EPHY_RREG(E56G__PMD_RXS3_OVRDVAL_1);
+ EPHY_XFLD(E56G__PMD_RXS3_OVRDVAL_1, rxs3_rx0_ctle_train_en_i) = 0;
+ EPHY_XFLD(E56G__PMD_RXS3_OVRDVAL_1, rxs3_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS3_OVRDVAL_1);
+
+ EPHY_RREG(E56G__PMD_RXS1_OVRDEN_1);
+ EPHY_XFLD(E56G__PMD_RXS1_OVRDEN_1, ovrd_en_rxs1_rx0_ctle_train_en_i) = 1;
+ EPHY_XFLD(E56G__PMD_RXS1_OVRDEN_1, ovrd_en_rxs1_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS1_OVRDEN_1);
+ EPHY_RREG(E56G__PMD_RXS2_OVRDEN_1);
+ EPHY_XFLD(E56G__PMD_RXS2_OVRDEN_1, ovrd_en_rxs2_rx0_ctle_train_en_i) = 1;
+ EPHY_XFLD(E56G__PMD_RXS2_OVRDEN_1, ovrd_en_rxs2_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS2_OVRDEN_1);
+ EPHY_RREG(E56G__PMD_RXS3_OVRDEN_1);
+ EPHY_XFLD(E56G__PMD_RXS3_OVRDEN_1, ovrd_en_rxs3_rx0_ctle_train_en_i) = 1;
+ EPHY_XFLD(E56G__PMD_RXS3_OVRDEN_1, ovrd_en_rxs3_rx0_ctle_train_done_o) = 1;
+ EPHY_WREG(E56G__PMD_RXS3_OVRDEN_1);
+ }
+ return 0;
+}
+
+static int txgbe_e56_rxs_adc_adapt_seq(struct txgbe_hw *hw, u32 bypass_ctle)
+{
+ int lane_num = 0, lane_idx = 0;
+ u32 rdata = 0, addr = 0;
+ int status = 0;
+
+ int timer = 0, j = 0;
+
+ switch (hw->bp_link_mode) {
+ case 10:
+ lane_num = 1;
+ break;
+ case 40:
+ lane_num = 4;
+ break;
+ case 25:
+ lane_num = 1;
+ break;
+ default:
+ BP_LOG("%s %d :Invalid speed\n", __func__, __LINE__);
+ break;
+ }
+
+ for (lane_idx = 0; lane_idx < lane_num; lane_idx++) {
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ /* Wait RXS0-3_OVRDVAL[1]::rxs0-3_rx0_cdr_rdy_o = 1 */
+ status = kr_read_poll(rd32_ephy, rdata, (rdata & BIT(12)),
+ 100, 2000, hw, 0x1544);
+ if (status)
+ BP_LOG("rxs%d_rx0_cdr_rdy_o = %x, %s.\n",
+ lane_idx, rdata,
+ status ? "FAILED" : "SUCCESS");
+ }
+
+ for (lane_idx = 0; lane_idx < lane_num; lane_idx++) {
+ /* 4. Disable VGA and CTLE training so they don't interfere with ADC calibration */
+ /* a. Set ALIAS::RXS::VGA_TRAIN_EN = 0b0 */
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 7, 7, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1534 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 14, 14, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ /* b. Set ALIAS::RXS::CTLE_TRAIN_EN = 0b0 */
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 9, 9, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1534 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 16, 16, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ /* 5. Perform ADC interleaver calibration */
+ /* a. Remove the OVERRIDE on ALIAS::RXS::ADC_INTL_CAL_DONE */
+ addr = 0x1534 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 24, 24, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 16, 16, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ /* Wait rxs0_rx0_adc_intl_cal_done_o bit17 = 1 */
+ status = kr_read_poll(rd32_ephy, rdata, (rdata & BIT(17)),
+ 100, 2000, hw, addr);
+ if (status)
+ BP_LOG("rxs0_rx0_adc_intl_cal_done_o = %x, %s.\n", rdata,
+ status ? "FAILED" : "SUCCESS");
+
+ /* 6. Perform ADC offset adaptation and ADC gain adaptation,
+ * repeat them a few times and after that keep it disabled.
+ */
+ for (j = 0; j < 16; j++) {
+ /* a. ALIAS::RXS::ADC_OFST_ADAPT_EN = 0b1 */
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 25, 25, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ /* b. Wait for 1ms or greater */
+ /* usec_delay(1000); */
+ /* set ovrd_en_rxs0_rx0_adc_ofst_adapt_done_o bit1=0 */
+ addr = 0x1538 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 1, 1, 0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ /* Wait rxs0_rx0_adc_ofst_adapt_done_o bit26 = 0 */
+ status = kr_read_poll(rd32_ephy, rdata,
+ !(rdata & BIT(26)),
+ 100, 2000, hw, addr);
+ if (status)
+ BP_LOG("rxs0_rx0_adc_ofst_adapt_done_o %d = %x, %s.\n",
+ j, rdata, status ? "FAILED" : "SUCCESS");
+
+ /* c. ALIAS::RXS::ADC_OFST_ADAPT_EN = 0b0 */
+ rdata = 0x0000;
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 25, 25, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ /* d. ALIAS::RXS::ADC_GAIN_ADAPT_EN = 0b1 */
+ rdata = 0x0000;
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 28, 28, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ /* e. Wait for 1ms or greater */
+ /* usec_delay(1000); */
+ /* set ovrd_en_rxs0_rx0_adc_ofst_adapt_done_o bit1=0 */
+ addr = 0x1538 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 1, 1, 0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ /* Wait rxs0_rx0_adc_gain_adapt_done_o bit29 = 0 */
+ status = kr_read_poll(rd32_ephy, rdata, !(rdata & BIT(29)),
+ 100, 2000, hw, addr);
+ if (status)
+ BP_LOG("rxs0_rx0_adc_gain_adapt_done_o %d = %x, %s.\n",
+ j, rdata, status ? "FAILED" : "SUCCESS");
+
+ /* f. ALIAS::RXS::ADC_GAIN_ADAPT_EN = 0b0 */
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 28, 28, 0x0);
+ wr32_ephy(hw, addr, rdata);
+ }
+ /* g. Repeat #a to #f total 16 times */
+
+ /* 7. Perform ADC interleaver adaptation for 10ms or greater,
+ * and after that disable it
+ */
+ /* a. ALIAS::RXS::ADC_INTL_ADAPT_EN = 0b1 */
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 31, 31, 0x1);
+ wr32_ephy(hw, addr, rdata);
+ /* b. Wait for 10ms or greater */
+ msleep(20);
+
+ /* c. ALIAS::RXS::ADC_INTL_ADAPT_EN = 0b0 */
+ /* set ovrd_en_rxs0_rx0_adc_intl_adapt_en_i=0 */
+ addr = 0x1538 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 6, 6, 0);
+ wr32_ephy(hw, addr, rdata);
+
+ /* 8. Now re-enable VGA and CTLE trainings, so that it continues
+ * to adapt tracking changes in temperature or voltage
+ * <1>Set ALIAS::RXS::VGA_TRAIN_EN = 0b1
+ */
+ /* set rxs0_rx0_vga_train_en_i=1 */
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 7, 7, 0x1);
+ if (bypass_ctle == 0)
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1, rxs0_rx0_ctle_train_en_i) = 1;
+ wr32_ephy(hw, addr, rdata);
+
+ /* <2>wait for ALIAS::RXS::VGA_TRAIN_DONE = 1 */
+ /* set ovrd_en_rxs0_rx0_vga_train_done_o = 0 */
+ addr = 0x1534 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 15, 15, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ /* Wait rxs0_rx0_vga_train_done_o bit8 = 0 */
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ status = kr_read_poll(rd32_ephy, rdata, (rdata & BIT(8)),
+ 100, 3000, hw, addr);
+ if (status)
+ BP_LOG("rxs0_rx0_vga_train_done_o = %x, %s.\n", rdata,
+ status ? "FAILED" : "SUCCESS");
+
+ if (bypass_ctle == 0) {
+ addr = 0x1534 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1,
+ ovrd_en_rxs0_rx0_ctle_train_done_o) = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0;
+ timer = 0;
+ addr = 0x1544 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ while (EPHY_XFLD(E56G__PMD_RXS0_OVRDVAL_1,
+ rxs0_rx0_ctle_train_done_o) != 1) {
+ rdata = rd32_ephy(hw, addr);
+ usec_delay(500);
+
+ if (timer++ > PHYINIT_TIMEOUT)
+ break;
+ }
+ }
+
+ /* a. Remove the OVERRIDE on ALIAS::RXS::VGA_TRAIN_EN */
+ addr = 0x1534 + (E56PHY_PMD_RX_OFFSET * lane_idx);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 15, 15, 0);
+ /* b. Remove the OVERRIDE on ALIAS::RXS::CTLE_TRAIN_EN */
+ if (bypass_ctle == 0)
+ EPHY_XFLD(E56G__PMD_RXS0_OVRDEN_1,
+ ovrd_en_rxs0_rx0_ctle_train_en_i) = 0;
+ wr32_ephy(hw, addr, rdata);
+ }
+
+ return status;
+}
+
+static int txgbe_e56_phy_rxs_calib_adapt_seq(struct txgbe_hw *hw,
+ u8 bp_link_mode, u32 bypass_ctle)
+{
+ int lane_num = 0, lane_idx = 0;
+ int status = 0;
+ u32 rdata, addr;
+
+ switch (bp_link_mode) {
+ case 10:
+ lane_num = 1;
+ break;
+ case 40:
+ lane_num = 4;
+ break;
+ case 25:
+ lane_num = 1;
+ break;
+ default:
+ BP_LOG("%s %d :Invalid speed\n", __func__, __LINE__);
+ break;
+ }
+
+ for (lane_idx = 0; lane_idx < lane_num; lane_idx++) {
+ rdata = 0x0000;
+ addr = 0x1544 + (lane_idx * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 25, 25, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1538 + (lane_idx * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 0, 0, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1544 + (lane_idx * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 28, 28, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1538 + (lane_idx * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 3, 3, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = 0x1544 + (lane_idx * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 16, 16, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1534 + (lane_idx * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 23, 23, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1544 + (lane_idx * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 17, 17, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1534 + (lane_idx * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 24, 24, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1544 + (lane_idx * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 31, 31, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x1538 + (lane_idx * E56PHY_PMD_RX_OFFSET);
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 6, 6, 0x1);
+ wr32_ephy(hw, addr, rdata);
+ }
+ if (bypass_ctle != 0)
+ status |= txgbe_e56_ctle_bypass_seq(hw, bp_link_mode);
+
+ status |= txgbe_e56_rxs_osc_init_for_temp_track_range(hw, bp_link_mode);
+
+ /* Wait an fsm_rx_sts 25G */
+ BP_LOG("Wait CTRL_FSM_RX_STAT[0]::ctrl_fsm_rx0_st to be ready ...\n");
+
+ status |= kr_read_poll(rd32_ephy, rdata,
+ (((rdata & 0x3f3f3f3f) & GENMASK(8 * lane_num - 1, 0))
+ == (0x1b1b1b1b & GENMASK(8 * lane_num - 1, 0))),
+ 1000, 300, hw,
+ E56PHY_CTRL_FSM_RX_STAT_0_ADDR);
+ BP_LOG("wait ctrl_fsm_rx0_st = %x, %s.\n",
+ rdata, status ? "FAILED" : "SUCCESS");
+
+ return status;
+}
+
+static int txgbe_e56_cms_cfg_for_temp_track_range(struct txgbe_hw *hw)
+{
+ int status = 0, T = 40;
+ u32 addr, rdata;
+
+ status = txgbe_e56_get_temp(hw, &T);
+ if (T < 40) {
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDEN_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_CMS_ANA_OVRDEN_0_OVRD_EN_ANA_LCPLL_HF_LPF_SETCODE_CALIB_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDVAL_2_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_CMS_ANA_OVRDVAL_2_ANA_LCPLL_HF_LPF_SETCODE_CALIB_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDEN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_CMS_ANA_OVRDEN_1_OVRD_EN_ANA_LCPLL_LF_LPF_SETCODE_CALIB_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDVAL_7_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_CMS_ANA_OVRDVAL_7_ANA_LCPLL_LF_LPF_SETCODE_CALIB_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+ } else if (T > 70) {
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDEN_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_CMS_ANA_OVRDEN_0_OVRD_EN_ANA_LCPLL_HF_LPF_SETCODE_CALIB_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDVAL_2_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_CMS_ANA_OVRDVAL_2_ANA_LCPLL_HF_LPF_SETCODE_CALIB_I, 0x3);
+ wr32_ephy(hw, addr, rdata);
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDEN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_CMS_ANA_OVRDEN_1_OVRD_EN_ANA_LCPLL_LF_LPF_SETCODE_CALIB_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDVAL_7_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_CMS_ANA_OVRDVAL_7_ANA_LCPLL_LF_LPF_SETCODE_CALIB_I, 0x3);
+ wr32_ephy(hw, addr, rdata);
+ } else {
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDEN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CMS_ANA_OVRDEN_1_OVRD_EN_ANA_LCPLL_HF_TEST_IN_I,
+ 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDVAL_4_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 24, 24, 0x1);
+ set_fields_e56(&rdata, 31, 29, 0x4);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDVAL_5_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 1, 0, 0x0);
+ wr32_ephy(hw, addr, rdata);
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDEN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CMS_ANA_OVRDEN_1_OVRD_EN_ANA_LCPLL_LF_TEST_IN_I,
+ 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDVAL_9_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 24, 24, 0x1);
+ set_fields_e56(&rdata, 31, 29, 0x4);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDVAL_10_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 1, 0, 0x0);
+ wr32_ephy(hw, addr, rdata);
+ }
+ return status;
+}
+
+static int txgbe_e56_bp_cfg_25g(struct txgbe_hw *hw)
+{
+ u32 addr, rdata;
+
+ rdata = 0x0000;
+ addr = E56PHY_CMS_PIN_OVRDVAL_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CMS_PIN_OVRDVAL_0_INT_PLL0_TX_SIGNAL_TYPE_I, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CMS_PIN_OVRDEN_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CMS_PIN_OVRDEN_0_OVRD_EN_PLL0_TX_SIGNAL_TYPE_I,
+ 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDVAL_2_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CMS_ANA_OVRDVAL_2_ANA_LCPLL_HF_VCO_SWING_CTRL_I,
+ 0xf);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDEN_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata,
+ E56PHY_CMS_ANA_OVRDEN_0_OVRD_EN_ANA_LCPLL_HF_VCO_SWING_CTRL_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDVAL_4_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 23, 0, 0x260000);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CMS_ANA_OVRDEN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CMS_ANA_OVRDEN_1_OVRD_EN_ANA_LCPLL_HF_TEST_IN_I,
+ 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_TXS_TXS_CFG_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_TXS_CFG_1_ADAPTATION_WAIT_CNT_X256, 0xf);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_TXS_WKUP_CNT_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_WKUP_CNTLDO_WKUP_CNT_X32, 0xff);
+ set_fields_e56(&rdata, E56PHY_TXS_WKUP_CNTDCC_WKUP_CNT_X32, 0xff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_TXS_PIN_OVRDVAL_6_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 27, 24, 0x5);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_TXS_PIN_OVRDEN_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_PIN_OVRDEN_0_OVRD_EN_TX0_EFUSE_BITS_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_TXS_ANA_OVRDVAL_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_ANA_OVRDVAL_1_ANA_TEST_DAC_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_TXS_ANA_OVRDEN_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_ANA_OVRDEN_0_OVRD_EN_ANA_TEST_DAC_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ txgbe_e56_tx_ffe_cfg(hw, TXGBE_LINK_SPEED_25GB_FULL);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_RXS_CFG_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_RXS_CFG_0_DSER_DATA_SEL, 0x0);
+ set_fields_e56(&rdata, E56PHY_RXS_RXS_CFG_0_TRAIN_CLK_GATE_BYPASS_EN, 0x1fff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_OSC_CAL_N_CDR_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_1_PREDIV1, 0x700);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_1_TARGET_CNT1, 0x2418);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_OSC_CAL_N_CDR_4_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_4_OSC_RANGE_SEL1, 0x1);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_4_VCO_CODE_INIT, 0x7fb);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_4_OSC_CURRENT_BOOST_EN1, 0x0);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_4_BBCDR_CURRENT_BOOST1, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_OSC_CAL_N_CDR_5_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_SDM_WIDTH, 0x3);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BB_CDR_PROP_STEP_PRELOCK,
+ 0xf);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BB_CDR_PROP_STEP_POSTLOCK,
+ 0x3);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BB_CDR_GAIN_CTRL_POSTLOCK,
+ 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BB_CDR_GAIN_CTRL_PRELOCK,
+ 0xf);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BBCDR_RDY_CNT, 0x3);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_OSC_CAL_N_CDR_6_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_6_PI_GAIN_CTRL_PRELOCK, 0x7);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_6_PI_GAIN_CTRL_POSTLOCK, 0x5);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_INTL_CONFIG_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_INTL_CONFIG_0_ADC_INTL2SLICE_DELAY1, 0x3333);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_INTL_CONFIG_2_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_INTL_CONFIG_2_INTERLEAVER_HBW_DISABLE1, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_TXFFE_TRAINING_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_0_ADC_DATA_PEAK_LTH, 0x56);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_0_ADC_DATA_PEAK_UTH, 0x6a);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_TXFFE_TRAINING_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_1_C1_LTH, 0x1f8);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_1_C1_UTH, 0xf0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_TXFFE_TRAINING_2_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_2_CM1_LTH, 0x100);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_2_CM1_UTH, 0xff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_TXFFE_TRAINING_3_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_3_CM2_LTH, 0x4);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_3_CM2_UTH, 0x37);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_3_TXFFE_TRAIN_MOD_TYPE, 0x38);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56G__RXS0_FOM_18__ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56G__RXS0_FOM_18__DFE_COEFFL_HINT__MSB,
+ E56G__RXS0_FOM_18__DFE_COEFFL_HINT__LSB, 0x0);
+ set_fields_e56(&rdata, E56G__RXS0_FOM_18__DFE_COEFFH_HINT__MSB,
+ E56G__RXS0_FOM_18__DFE_COEFFH_HINT__LSB, 0x0);
+ set_fields_e56(&rdata, E56G__RXS0_FOM_18__DFE_COEFF_HINT_LOAD__MSB,
+ E56G__RXS0_FOM_18__DFE_COEFF_HINT_LOAD__LSB, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_VGA_TRAINING_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_0_VGA_TARGET, 0x34);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_VGA_TRAINING_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_1_VGA1_CODE_INIT0, 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_1_VGA2_CODE_INIT0, 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_1_VGA1_CODE_INIT123, 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_1_VGA2_CODE_INIT123, 0xa);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_CTLE_TRAINING_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_0_CTLE_CODE_INIT0, 0x9);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_0_CTLE_CODE_INIT123, 0x9);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_CTLE_TRAINING_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_1_LFEQ_LUT, 0x1ffffea);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_CTLE_TRAINING_2_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_2_ISI_TH_FRAC_P1, 18);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_2_ISI_TH_FRAC_P2, 0);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_2_ISI_TH_FRAC_P3, 0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_CTLE_TRAINING_3_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_3_TAP_WEIGHT_P1, 1);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_3_TAP_WEIGHT_P2, 0);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_3_TAP_WEIGHT_P3, 0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_OFFSET_N_GAIN_CAL_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OFFSET_N_GAIN_CAL_0_ADC_SLICE_DATA_AVG_CNT,
+ 0x3);
+ set_fields_e56(&rdata, E56PHY_RXS_OFFSET_N_GAIN_CAL_0_ADC_DATA_AVG_CNT, 0x3);
+ set_fields_e56(&rdata, E56PHY_RXS_OFFSET_N_GAIN_CAL_0_FE_OFFSET_DAC_CLK_CNT_X8,
+ 0xc);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_OFFSET_N_GAIN_CAL_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OFFSET_N_GAIN_CAL_1_SAMP_ADAPT_CFG, 0x5);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_FFE_TRAINING_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_FFE_TRAINING_0_FFE_TAP_EN, 0xf9ff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_IDLE_DETECT_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MAX, 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MIN, 0x5);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x6cc;
+ rdata = 0x8020000;
+ wr32_ephy(hw, addr, rdata);
+ addr = 0x94;
+ rdata = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDVAL_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDVAL_0_ANA_EN_RTERM_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDEN_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_0_OVRD_EN_ANA_EN_RTERM_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDVAL_6_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 4, 0, 0x0);
+ set_fields_e56(&rdata, 14, 13, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDEN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_1_OVRD_EN_ANA_BBCDR_VCOFILT_BYP_I,
+ 0x1);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_1_OVRD_EN_ANA_TEST_BBCDR_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDVAL_15_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 2, 0, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDVAL_17_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDVAL_17_ANA_VGA2_BOOST_CSTM_I, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDEN_3_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_3_OVRD_EN_ANA_ANABS_CONFIG_I, 0x1);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_3_OVRD_EN_ANA_VGA2_BOOST_CSTM_I,
+ 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDVAL_14_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 13, 13, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDEN_4_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 13, 13, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_EYE_SCAN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_EYE_SCAN_1_EYE_SCAN_REF_TIMER, 0x400);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_RINGO_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 21, 12, 0x366);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_PMD_CFG_3_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_3_CTRL_FSM_TIMEOUT_X64K, 0x80);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_PMD_CFG_4_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_4_TRAIN_DC_ON_PERIOD_X64K, 0x18);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_4_TRAIN_DC_PERIOD_X512K, 0x3e);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_PMD_CFG_5_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_5_USE_RECENT_MARKER_OFFSET, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_0_CONT_ON_ADC_GAIN_CAL_ERR, 0x1);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_0_DO_RX_ADC_OFST_CAL, 0x3);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_0_RX_ERR_ACTION_EN, 0x40);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_1_TRAIN_ST0_WAIT_CNT_X4096, 0xff);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_1_TRAIN_ST1_WAIT_CNT_X4096, 0xff);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_1_TRAIN_ST2_WAIT_CNT_X4096, 0xff);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_1_TRAIN_ST3_WAIT_CNT_X4096, 0xff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_2_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_2_TRAIN_ST4_WAIT_CNT_X4096, 0x1);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_2_TRAIN_ST5_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_2_TRAIN_ST6_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_2_TRAIN_ST7_WAIT_CNT_X4096, 0x4);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_3_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_3_TRAIN_ST8_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_3_TRAIN_ST9_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_3_TRAIN_ST10_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_3_TRAIN_ST11_WAIT_CNT_X4096, 0x4);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_4_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_4_TRAIN_ST12_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_4_TRAIN_ST13_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_4_TRAIN_ST14_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_4_TRAIN_ST15_WAIT_CNT_X4096, 0x4);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_7_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_7_TRAIN_ST4_EN, 0x4bf);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_7_TRAIN_ST5_EN, 0xc4bf);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_8_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_8_TRAIN_ST7_EN, 0x47ff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_12_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_12_TRAIN_ST15_EN, 0x67ff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_13_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_13_TRAIN_ST0_DONE_EN, 0x8001);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_13_TRAIN_ST1_DONE_EN, 0x8002);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_14_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_14_TRAIN_ST3_DONE_EN, 0x8008);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_15_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_15_TRAIN_ST4_DONE_EN, 0x8004);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_17_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_17_TRAIN_ST8_DONE_EN, 0x20c0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_18_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_18_TRAIN_ST10_DONE_EN, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_29_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_29_TRAIN_ST15_DC_EN, 0x3f6d);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_33_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_33_TRAIN0_RATE_SEL, 0x8000);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_33_TRAIN1_RATE_SEL, 0x8000);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_34_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_34_TRAIN2_RATE_SEL, 0x8000);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_34_TRAIN3_RATE_SEL, 0x8000);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_KRT_TFSM_CFG_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_KRT_TFSM_CFGKRT_TFSM_MAX_WAIT_TIMER_X1000K, 0x49);
+ set_fields_e56(&rdata, E56PHY_KRT_TFSM_CFGKRT_TFSM_MAX_WAIT_TIMER_X8000K, 0x37);
+ set_fields_e56(&rdata, E56PHY_KRT_TFSM_CFGKRT_TFSM_HOLDOFF_TIMER_X256K, 0x2f);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2,
+ 0x2);
+ wr32_ephy(hw, addr, rdata);
+
+ return 0;
+}
+
+static int txgbe_e56_bp_cfg_10g(struct txgbe_hw *hw)
+{
+ u32 addr, rdata;
+
+ rdata = 0x0000;
+ addr = E56G__CMS_ANA_OVRDVAL_7_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ ((E56G__CMS_ANA_OVRDVAL_7 *)&rdata)->ana_lcpll_lf_vco_swing_ctrl_i = 0xf;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56G__CMS_ANA_OVRDEN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ ((E56G__CMS_ANA_OVRDEN_1 *)&rdata)->ovrd_en_ana_lcpll_lf_vco_swing_ctrl_i = 0x1;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56G__CMS_ANA_OVRDVAL_9_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 23, 0, 0x260000);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56G__CMS_ANA_OVRDEN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ ((E56G__CMS_ANA_OVRDEN_1 *)&rdata)->ovrd_en_ana_lcpll_lf_test_in_i = 0x1;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_TXS_TXS_CFG_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_TXS_CFG_1_ADAPTATION_WAIT_CNT_X256, 0xf);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_TXS_WKUP_CNT_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_WKUP_CNTLDO_WKUP_CNT_X32, 0xff);
+ set_fields_e56(&rdata, E56PHY_TXS_WKUP_CNTDCC_WKUP_CNT_X32, 0xff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_TXS_PIN_OVRDVAL_6_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 19, 16, 0x6);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_TXS_PIN_OVRDEN_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_PIN_OVRDEN_0_OVRD_EN_TX0_EFUSE_BITS_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_TXS_ANA_OVRDVAL_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_ANA_OVRDVAL_1_ANA_TEST_DAC_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_TXS_ANA_OVRDEN_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_TXS_ANA_OVRDEN_0_OVRD_EN_ANA_TEST_DAC_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ txgbe_e56_tx_ffe_cfg(hw, TXGBE_LINK_SPEED_10GB_FULL);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_RXS_CFG_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_RXS_CFG_0_DSER_DATA_SEL, 0x0);
+ set_fields_e56(&rdata, E56PHY_RXS_RXS_CFG_0_TRAIN_CLK_GATE_BYPASS_EN, 0x1fff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_OSC_CAL_N_CDR_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ ((E56G_RXS0_OSC_CAL_N_CDR_0 *)&rdata)->prediv0 = 0xfa0;
+ ((E56G_RXS0_OSC_CAL_N_CDR_0 *)&rdata)->target_cnt0 = 0x203a;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_OSC_CAL_N_CDR_4_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ ((E56G_RXS0_OSC_CAL_N_CDR_4 *)&rdata)->osc_range_sel0 = 0x2;
+ ((E56G_RXS0_OSC_CAL_N_CDR_4 *)&rdata)->vco_code_init = 0x7ff;
+ ((E56G_RXS0_OSC_CAL_N_CDR_4 *)&rdata)->osc_current_boost_en0 = 0x1;
+ ((E56G_RXS0_OSC_CAL_N_CDR_4 *)&rdata)->bbcdr_current_boost0 = 0x0;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_OSC_CAL_N_CDR_5_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_SDM_WIDTH, 0x3);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BB_CDR_PROP_STEP_PRELOCK,
+ 0xf);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BB_CDR_PROP_STEP_POSTLOCK,
+ 0xf);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BB_CDR_GAIN_CTRL_POSTLOCK,
+ 0xc);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BB_CDR_GAIN_CTRL_PRELOCK,
+ 0xf);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_5_BBCDR_RDY_CNT, 0x3);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_OSC_CAL_N_CDR_6_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_6_PI_GAIN_CTRL_PRELOCK, 0x7);
+ set_fields_e56(&rdata, E56PHY_RXS_OSC_CAL_N_CDR_6_PI_GAIN_CTRL_POSTLOCK, 0x5);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_INTL_CONFIG_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ ((E56G_RXS0_INTL_CONFIG_0 *)&rdata)->adc_intl2slice_delay0 = 0x5555;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_INTL_CONFIG_2_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ ((E56G_RXS0_INTL_CONFIG_2 *)&rdata)->interleaver_hbw_disable0 = 0x1;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_TXFFE_TRAINING_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_0_ADC_DATA_PEAK_LTH, 0x56);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_0_ADC_DATA_PEAK_UTH, 0x6a);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_TXFFE_TRAINING_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_1_C1_LTH, 0x1e8);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_1_C1_UTH, 0x78);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_TXFFE_TRAINING_2_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_2_CM1_LTH, 0x100);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_2_CM1_UTH, 0xff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_TXFFE_TRAINING_3_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_3_CM2_LTH, 0x4);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_3_CM2_UTH, 0x37);
+ set_fields_e56(&rdata, E56PHY_RXS_TXFFE_TRAINING_3_TXFFE_TRAIN_MOD_TYPE, 0x38);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_VGA_TRAINING_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_0_VGA_TARGET, 0x34);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_VGA_TRAINING_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_1_VGA1_CODE_INIT0, 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_1_VGA2_CODE_INIT0, 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_1_VGA1_CODE_INIT123, 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_VGA_TRAINING_1_VGA2_CODE_INIT123, 0xa);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_CTLE_TRAINING_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_0_CTLE_CODE_INIT0, 0x9);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_0_CTLE_CODE_INIT123, 0x9);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_CTLE_TRAINING_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_1_LFEQ_LUT, 0x1ffffea);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_CTLE_TRAINING_2_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_2_ISI_TH_FRAC_P1, 0x18);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_2_ISI_TH_FRAC_P2, 0);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_2_ISI_TH_FRAC_P3, 0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_CTLE_TRAINING_3_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_3_TAP_WEIGHT_P1, 1);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_3_TAP_WEIGHT_P2, 0);
+ set_fields_e56(&rdata, E56PHY_RXS_CTLE_TRAINING_3_TAP_WEIGHT_P3, 0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_OFFSET_N_GAIN_CAL_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OFFSET_N_GAIN_CAL_0_ADC_SLICE_DATA_AVG_CNT,
+ 0x3);
+ set_fields_e56(&rdata, E56PHY_RXS_OFFSET_N_GAIN_CAL_0_ADC_DATA_AVG_CNT, 0x3);
+ set_fields_e56(&rdata, E56PHY_RXS_OFFSET_N_GAIN_CAL_0_FE_OFFSET_DAC_CLK_CNT_X8,
+ 0xc);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_OFFSET_N_GAIN_CAL_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_OFFSET_N_GAIN_CAL_1_SAMP_ADAPT_CFG, 0x5);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_FFE_TRAINING_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_FFE_TRAINING_0_FFE_TAP_EN, 0xf9ff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_IDLE_DETECT_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MAX, 0xa);
+ set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MIN, 0x5);
+ wr32_ephy(hw, addr, rdata);
+
+ addr = 0x6cc;
+ rdata = 0x8020000;
+ wr32_ephy(hw, addr, rdata);
+ addr = 0x94;
+ rdata = 0;
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDVAL_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDVAL_0_ANA_EN_RTERM_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDEN_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_0_OVRD_EN_ANA_EN_RTERM_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDVAL_6_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 4, 0, 0x6);
+ set_fields_e56(&rdata, 14, 13, 0x2);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDEN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_1_OVRD_EN_ANA_BBCDR_VCOFILT_BYP_I,
+ 0x1);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_1_OVRD_EN_ANA_TEST_BBCDR_I, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDVAL_15_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 2, 0, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDVAL_17_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDVAL_17_ANA_VGA2_BOOST_CSTM_I, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDEN_3_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_3_OVRD_EN_ANA_ANABS_CONFIG_I, 0x1);
+ set_fields_e56(&rdata, E56PHY_RXS_ANA_OVRDEN_3_OVRD_EN_ANA_VGA2_BOOST_CSTM_I,
+ 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDVAL_14_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 13, 13, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_ANA_OVRDEN_4_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 13, 13, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_EYE_SCAN_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_RXS_EYE_SCAN_1_EYE_SCAN_REF_TIMER, 0x400);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_RXS_RINGO_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, 21, 12, 0x366);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_PMD_CFG_3_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_3_CTRL_FSM_TIMEOUT_X64K, 0x80);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_PMD_CFG_4_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_4_TRAIN_DC_ON_PERIOD_X64K, 0x18);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_4_TRAIN_DC_PERIOD_X512K, 0x3e);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_PMD_CFG_5_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_PMD_CFG_5_USE_RECENT_MARKER_OFFSET, 0x1);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_0_CONT_ON_ADC_GAIN_CAL_ERR, 0x1);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_0_DO_RX_ADC_OFST_CAL, 0x3);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_0_RX_ERR_ACTION_EN, 0x40);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_1_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_1_TRAIN_ST0_WAIT_CNT_X4096, 0xff);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_1_TRAIN_ST1_WAIT_CNT_X4096, 0xff);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_1_TRAIN_ST2_WAIT_CNT_X4096, 0xff);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_1_TRAIN_ST3_WAIT_CNT_X4096, 0xff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_2_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_2_TRAIN_ST4_WAIT_CNT_X4096, 0x1);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_2_TRAIN_ST5_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_2_TRAIN_ST6_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_2_TRAIN_ST7_WAIT_CNT_X4096, 0x4);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_3_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_3_TRAIN_ST8_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_3_TRAIN_ST9_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_3_TRAIN_ST10_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_3_TRAIN_ST11_WAIT_CNT_X4096, 0x4);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_4_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_4_TRAIN_ST12_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_4_TRAIN_ST13_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_4_TRAIN_ST14_WAIT_CNT_X4096, 0x4);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_4_TRAIN_ST15_WAIT_CNT_X4096, 0x4);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_7_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_7_TRAIN_ST4_EN, 0x4bf);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_7_TRAIN_ST5_EN, 0xc4bf);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_8_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_8_TRAIN_ST7_EN, 0x47ff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_12_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_12_TRAIN_ST15_EN, 0x67ff);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_13_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_13_TRAIN_ST0_DONE_EN, 0x8001);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_13_TRAIN_ST1_DONE_EN, 0x8002);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_14_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_14_TRAIN_ST3_DONE_EN, 0x8008);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_15_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_15_TRAIN_ST4_DONE_EN, 0x8004);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_17_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_17_TRAIN_ST8_DONE_EN, 0x20c0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_18_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_18_TRAIN_ST10_DONE_EN, 0x0);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_29_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_29_TRAIN_ST15_DC_EN, 0x3f6d);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_33_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_33_TRAIN0_RATE_SEL, 0x8000);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_33_TRAIN1_RATE_SEL, 0x8000);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_CTRL_FSM_CFG_34_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_34_TRAIN2_RATE_SEL, 0x8000);
+ set_fields_e56(&rdata, E56PHY_CTRL_FSM_CFG_34_TRAIN3_RATE_SEL, 0x8000);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_KRT_TFSM_CFG_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_KRT_TFSM_CFGKRT_TFSM_MAX_WAIT_TIMER_X1000K, 0x49);
+ set_fields_e56(&rdata, E56PHY_KRT_TFSM_CFGKRT_TFSM_MAX_WAIT_TIMER_X8000K, 0x37);
+ set_fields_e56(&rdata, E56PHY_KRT_TFSM_CFGKRT_TFSM_HOLDOFF_TIMER_X256K, 0x2f);
+ wr32_ephy(hw, addr, rdata);
+
+ rdata = 0x0000;
+ addr = E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR;
+ rdata = rd32_ephy(hw, addr);
+ set_fields_e56(&rdata, E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2,
+ 0x2);
+ wr32_ephy(hw, addr, rdata);
+
+ return 0;
+}
+
+static int txgbe_set_phy_link_mode(struct txgbe_hw *hw,
+ u8 bp_link_mode)
+{
+ int status = 0;
+ u32 rdata = 0;
+
+ u32 speed_select = 0;
+ u32 pcs_type_sel = 0;
+ u32 cns_en = 0;
+ u32 rsfec_en = 0;
+ u32 pma_type = 0;
+ u32 an0_rate_select = 0;
+
+ switch (bp_link_mode) {
+ case 10:
+ bp_link_mode = 10;
+ speed_select = 0; /* 10 Gb/s */
+ pcs_type_sel = 0; /* 10GBASE-R PCS Type */
+ cns_en = 0; /* CNS_EN disable */
+ rsfec_en = 0; /* RS-FEC disable */
+ pma_type = 0xb; /* 10GBASE-KR PMA/PMD type */
+ an0_rate_select = 2; /* 10G-KR */
+ break;
+ case 40:
+ bp_link_mode = 40;
+ speed_select = 3; /* 40 Gb/s */
+ pcs_type_sel = 4; /* 40GBASE-R PCS Type */
+ cns_en = 0; /* CNS_EN disable */
+ rsfec_en = 0; /* RS-FEC disable */
+ pma_type = 0b0100001; /* 40GBASE-CR PMA/PMD type */
+ an0_rate_select = 4; /* 40G-KR: 3 40G-CR: 4 */
+ break;
+ case 25:
+ bp_link_mode = 25;
+ speed_select = 5; /* 25 Gb/s */
+ pcs_type_sel = 7; /* 25GBASE-R PCS Type */
+ cns_en = 1; /* CNS_EN */
+ rsfec_en = 1; /* RS-FEC enable*/
+ pma_type = 0b0111001; /* 25GBASE-KR PMA/PMD type */
+ an0_rate_select = 9; /* 9/10/17 25GK/CR-S or 25GK/CR */
+ break;
+ default:
+ BP_LOG("%s %d :Invalid bp_link_mode\n", __func__, __LINE__);
+ break;
+ }
+
+ hw->curbp_link_mode = bp_link_mode;
+ /* To switch to the 40G mode Ethernet operation, complete the following steps:*/
+ /* 1. Initiate the vendor-specific software reset by programming
+ * the VR_RST field (bit [15]) of the VR_PCS_DIG_CTRL1 register to 1.
+ */
+ rdata = rd32_epcs(hw, 0x038000);
+ wr32_epcs(hw, 0x038000, rdata | BIT(15));
+
+ /* 2. Wait for the hardware to clear the value for the VR_RST
+ * field (bit [15]) of the VR_PCS_DIG_CTRL1 register.
+ */
+ BP_LOG("Wait for the bit [15] (VR_RST) to get cleared.\n");
+ status = kr_read_poll(rd32_ephy, rdata,
+ FIELD_GET_M(BIT(15), rdata) == 0, 100,
+ 2000, hw, 0x038000);
+ BP_LOG("Wait PHY VR_RST = %x, Wait VR_RST %s.\n",
+ rdata, status ? "FAILED" : "SUCCESS");
+
+ /* wait rx/tx/cm powerdn_st according pmd 50 2.0.5 */
+ status = kr_read_poll(rd32_ephy, rdata,
+ (rdata & GENMASK(3, 0)) == 0x9, 100,
+ 2000, hw, 0x14d4);
+ BP_LOG("wait ctrl_fsm_cm_st = %x, %s.\n",
+ rdata, status ? "FAILED" : "SUCCESS");
+
+ /* 3. Write 4'b0011 to bits [5:2] of the SR_PCS_CTRL1 register.
+ * 10G: 0 25G: 5 40G: 3
+ */
+ rdata = rd32_epcs(hw, 0x030000);
+ set_fields_e56(&rdata, 5, 2, speed_select);
+ wr32_epcs(hw, 0x030000, rdata);
+
+ /* 4. Write pcs mode sel to bits [3:0] of the SR_PCS_CTRL2 register.
+ * 10G: 0 25G: 4'b0111 40G: 4'b0100
+ */
+ rdata = rd32_epcs(hw, 0x030007);
+ set_fields_e56(&rdata, 3, 0, pcs_type_sel);
+ wr32_epcs(hw, 0x030007, rdata);
+
+ /* 0 1 1 1 0 0 1 : 25GBASE-KR or 25GBASE-KR-S PMA/PMD type
+ * 0 1 1 1 0 0 0 : 25GBASE-CR or 25GBASE-CR-S PMA/PMD type
+ * 0 1 0 0 0 0 1 : 40GBASE-CR4 PMA/PMD type
+ * 0 1 0 0 0 0 0 : 40GBASE-KR4 PMA/PMD type
+ * 0 0 0 1 0 1 1 : 10GBASE-KR PMA/PMD type
+ */
+ rdata = rd32_epcs(hw, 0x010007);
+ set_fields_e56(&rdata, 6, 0, pma_type);
+ wr32_epcs(hw, 0x010007, rdata);
+
+ /* 5. Write only 25g en to Bits [1:0] of VR_PCS_DIG_CTRL3 register. */
+ rdata = rd32_epcs(hw, 0x38003);
+ set_fields_e56(&rdata, 1, 0, cns_en);
+ wr32_epcs(hw, 0x38003, rdata);
+
+ /* 6. Program PCS_AM_CNT field of VR_PCS_AM_CNT register to 'd16383 to
+ * configure the alignment marker interval. To speed-up simulation,
+ * program a smaller value to this field.
+ */
+ if (bp_link_mode == 40)
+ wr32_epcs(hw, 0x38018, 16383);
+
+ /* 7. Program bit [2] of SR_PMA_RS_FEC_CTRL register to 0
+ * if previously 1 (as RS-FEC is supported in 25G Mode).
+ */
+
+ rdata = rd32_epcs(hw, 0x100c8);
+ set_fields_e56(&rdata, 2, 2, rsfec_en);
+ wr32_epcs(hw, 0x100c8, rdata);
+
+ /* 8. To enable BASE-R FEC (if desired), set bit [0].
+ * in SR_PMA_KR_FEC_CTRL register
+ */
+
+ /* 4. set phy an status to 0 */
+ rdata = rd32_ephy(hw, 0x1434);
+ set_fields_e56(&rdata, 7, 4, 0xe);
+ wr32_ephy(hw, 0x1434, rdata);
+
+ /* 9. Program Enterprise 56G PHY regs through its own APB interface:
+ * a. Program PHY registers as mentioned in Table 6-6 on page 1197 to
+ * configure the PHY to 40G
+ * Mode. For fast-simulation mode, additionally program,
+ * the registers shown in the Table 6-7 on page 1199
+ * b. Enable the PMD by setting pmd_en field in PMD_CFG[0] (0x1400)
+ * register
+ */
+
+ rdata = 0x0000;
+ rdata = rd32_ephy(hw, ANA_OVRDVAL0);
+ set_fields_e56(&rdata, 29, 29, 0x1);
+ set_fields_e56(&rdata, 1, 1, 0x1);
+ wr32_ephy(hw, ANA_OVRDVAL0, rdata);
+
+ rdata = 0x0000;
+ rdata = rd32_ephy(hw, ANA_OVRDVAL5);
+ set_fields_e56(&rdata, 24, 24, 0x1);
+ wr32_ephy(hw, ANA_OVRDVAL5, rdata);
+
+ rdata = 0x0000;
+ rdata = rd32_ephy(hw, ANA_OVRDEN0);
+ set_fields_e56(&rdata, 1, 1, 0x1);
+ wr32_ephy(hw, ANA_OVRDEN0, rdata);
+
+ rdata = 0x0000;
+ rdata = rd32_ephy(hw, ANA_OVRDEN1);
+ set_fields_e56(&rdata, 30, 30, 0x1);
+ set_fields_e56(&rdata, 25, 25, 0x1);
+ wr32_ephy(hw, ANA_OVRDEN1, rdata);
+
+ rdata = 0x0000;
+ rdata = rd32_ephy(hw, PLL0_CFG0);
+ set_fields_e56(&rdata, 25, 24, 0x1);
+ set_fields_e56(&rdata, 17, 16, 0x3);
+ wr32_ephy(hw, PLL0_CFG0, rdata);
+
+ rdata = 0x0000;
+ rdata = rd32_ephy(hw, PLL0_CFG2);
+ set_fields_e56(&rdata, 12, 8, 0x4);
+ wr32_ephy(hw, PLL0_CFG2, rdata);
+
+ rdata = 0x0000;
+ rdata = rd32_ephy(hw, PLL1_CFG0);
+ set_fields_e56(&rdata, 25, 24, 0x1);
+ set_fields_e56(&rdata, 17, 16, 0x3);
+ wr32_ephy(hw, PLL1_CFG0, rdata);
+
+ rdata = 0x0000;
+ rdata = rd32_ephy(hw, PLL1_CFG2);
+ set_fields_e56(&rdata, 12, 8, 0x8);
+ wr32_ephy(hw, PLL1_CFG2, rdata);
+
+ rdata = 0x0000;
+ rdata = rd32_ephy(hw, PLL0_DIV_CFG0);
+ set_fields_e56(&rdata, 18, 8, 0x294);
+ set_fields_e56(&rdata, 4, 0, 0x8);
+ wr32_ephy(hw, PLL0_DIV_CFG0, rdata);
+
+ rdata = 0x0000;
+ rdata = rd32_ephy(hw, DATAPATH_CFG0);
+ set_fields_e56(&rdata, 30, 28, 0x7);
+ set_fields_e56(&rdata, 26, 24, 0x5);
+ if (bp_link_mode == 10 || bp_link_mode == 40)
+ set_fields_e56(&rdata, 18, 16, 0x5);
+ else if (bp_link_mode == 25)
+ set_fields_e56(&rdata, 18, 16, 0x3);
+ set_fields_e56(&rdata, 14, 12, 0x5);
+ set_fields_e56(&rdata, 10, 8, 0x5);
+ wr32_ephy(hw, DATAPATH_CFG0, rdata);
+
+ rdata = 0x0000;
+ rdata = rd32_ephy(hw, DATAPATH_CFG1);
+ set_fields_e56(&rdata, 26, 24, 0x5);
+ set_fields_e56(&rdata, 10, 8, 0x5);
+ if (bp_link_mode == 10 || bp_link_mode == 40) {
+ set_fields_e56(&rdata, 18, 16, 0x5);
+ set_fields_e56(&rdata, 2, 0, 0x5);
+ } else if (bp_link_mode == 25) {
+ set_fields_e56(&rdata, 18, 16, 0x3);
+ set_fields_e56(&rdata, 2, 0, 0x3);
+ }
+ wr32_ephy(hw, DATAPATH_CFG1, rdata);
+
+ rdata = rd32_ephy(hw, AN_CFG1);
+ set_fields_e56(&rdata, 4, 0, an0_rate_select);
+ wr32_ephy(hw, AN_CFG1, rdata);
+
+ status = txgbe_e56_cms_cfg_for_temp_track_range(hw);
+
+ if (bp_link_mode == 10)
+ txgbe_e56_bp_cfg_10g(hw);
+ else if (bp_link_mode == 25)
+ txgbe_e56_bp_cfg_25g(hw);
+ else if (bp_link_mode == 40)
+ txgbe_e56_cfg_40g(hw);
+
+ return status;
+}
+
+int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
+ u8 bp_link_mode, u32 need_restart)
+{
+ int status = 0;
+ u32 rdata;
+
+ UNREFERENCED_PARAMETER(bp_link_mode);
+
+ hw->an_done = false;
+ if (hw->curbp_link_mode == 10 && !need_restart)
+ return 0;
+ BP_LOG("Setup to backplane mode ==========\n");
+
+ u32 backplane_mode = 0;
+ u32 fec_advertise = 0;
+
+ hw->an_done = false;
+ /* pcs + phy rst */
+ rdata = rd32(hw, 0x1000c);
+ if (hw->bus.lan_id == 1)
+ rdata |= BIT(16);
+ else
+ rdata |= BIT(19);
+ wr32(hw, 0x1000c, rdata);
+ msleep(20);
+
+ /* clear interrupt */
+ wr32_epcs(hw, 0x070000, 0);
+ wr32_epcs(hw, 0x030000, 0x8000);
+ rdata = rd32_epcs(hw, 0x070000);
+ set_fields_e56(&rdata, 12, 12, 0x1);
+ wr32_epcs(hw, 0x070000, rdata);
+ wr32_epcs(hw, 0x078002, 0x0000);
+ /* pcs case fec en to work around first */
+ wr32_epcs(hw, 0x100ab, 1);
+
+ if (txgbe_is_backplane(hw)) {
+ /* backplane 10G/25G/40G */
+ /* 10GKR:7-25KR:14/15-40GKR:8-40GCR:9 */
+ /* default all speed */
+ if ((hw->device_id & 0xFF) == 0x10) {
+ backplane_mode |= BIT(7);
+ fec_advertise |= TXGBE_10G_FEC_ABL;
+ } else if ((hw->device_id & 0xFF) == 0x25) {
+ backplane_mode |= BIT(14) | BIT(15);
+ fec_advertise |= TXGBE_25G_RS_FEC_REQ |
+ TXGBE_25G_BASE_FEC_REQ;
+ } else if ((hw->device_id & 0xFF) == 0x40) {
+ if (hw->phy.bp_capa == 0)
+ /* original configure: KR4 + CR4 */
+ backplane_mode |= BIT(9) | BIT(8);
+ else if (hw->phy.bp_capa == 1)
+ /* only 40GBASE-KR4 */
+ backplane_mode |= BIT(8);
+ else if (hw->phy.bp_capa == 2)
+ /* only 40GBASE-CR4 */
+ backplane_mode |= BIT(9);
+ fec_advertise |= TXGBE_10G_FEC_ABL;
+ BP_LOG("Advertised abilities: %d\n", backplane_mode);
+ }
+ } else {
+ if ((hw->phy.fiber_suppport_speed & TXGBE_LINK_SPEED_10GB_FULL)
+ == TXGBE_LINK_SPEED_10GB_FULL) {
+ backplane_mode |= 0x80;
+ fec_advertise |= TXGBE_10G_FEC_ABL;
+ }
+
+ if ((hw->phy.fiber_suppport_speed & TXGBE_LINK_SPEED_25GB_FULL)
+ == TXGBE_LINK_SPEED_25GB_FULL) {
+ backplane_mode |= 0xc000;
+ fec_advertise |= TXGBE_25G_RS_FEC_REQ |
+ TXGBE_25G_BASE_FEC_REQ;
+ }
+
+ if ((hw->phy.fiber_suppport_speed & TXGBE_LINK_SPEED_40GB_FULL)
+ == TXGBE_LINK_SPEED_40GB_FULL) {
+ backplane_mode |= BIT(9) | BIT(8);
+ fec_advertise |= TXGBE_10G_FEC_ABL;
+ }
+ }
+
+ wr32_epcs(hw, 0x070010, 0x0001);
+
+ /* 10GKR:7-25KR:14/15-40GKR:8-40GCR:9 */
+ wr32_epcs(hw, 0x070011, backplane_mode | 0x11);
+
+ /* BASE-R FEC */
+ rdata = rd32_epcs(hw, 0x70012);
+ wr32_epcs(hw, 0x70012, fec_advertise);
+
+ wr32_epcs(hw, 0x070016, 0x0000);
+ wr32_epcs(hw, 0x070017, 0x0);
+ wr32_epcs(hw, 0x070018, 0x0);
+
+ /* config timer */
+ wr32_epcs(hw, 0x078004, 0x003c);
+ wr32_epcs(hw, 0x078005, CL74_KRTR_TRAINNING_TIMEOUT);
+ wr32_epcs(hw, 0x078006, 25);
+ wr32_epcs(hw, 0x078000, 0x0008 | BIT(2));
+
+ BP_LOG("1.2 Wait 10G KR phy/pcs mode init ....\n");
+ status = txgbe_set_phy_link_mode(hw, 10);
+ BP_LOG("Wait 10g phy/pcs mode init = %x, %s.\n", rdata,
+ /* wait rx/tx/cm powerdn_st according pmd 50 2.0.5 */
+ status ? "FAILED" : "SUCCESS");
+
+ /* 5. CM_ENABLE */
+ rdata = rd32_ephy(hw, 0x1400);
+ set_fields_e56(&rdata, 21, 20, 0x3); /* pll en */
+ set_fields_e56(&rdata, 19, 12, 0x0); /* tx disable */
+ set_fields_e56(&rdata, 8, 8, 0x0); /* pmd mode */
+ set_fields_e56(&rdata, 1, 1, 0x1); /* pmd en */
+ wr32_ephy(hw, 0x1400, rdata);
+
+ /* 6, TX_ENABLE */
+ rdata = rd32_ephy(hw, 0x1400);
+ set_fields_e56(&rdata, 19, 12, 0x1); /* tx en */
+ wr32_ephy(hw, 0x1400, rdata);
+
+ BP_LOG("1.3 Wait 10G PHY RXS....\n");
+ status = txgbe_e56_rxs_osc_init_for_temp_track_range(hw, 10);
+ BP_LOG("Wait 10G PHY/RXS mode init = %x, %s.\n", rdata,
+ status ? "FAILED" : "SUCCESS");
+
+ /* Wait an 10g fsm_rx_sts */
+ status = kr_read_poll(rd32_ephy, rdata,
+ ((rdata & 0x3f) == 0xb), 1000,
+ 200, hw,
+ E56PHY_CTRL_FSM_RX_STAT_0_ADDR);
+ BP_LOG("Wait 10g fsm_rx_sts = %x, Wait rx_sts %s.\n", rdata,
+ status ? "FAILED" : "SUCCESS");
+ rdata = rd32_epcs(hw, 0x070000);
+ set_fields_e56(&rdata, 12, 12, 0x1);
+ wr32_epcs(hw, 0x070000, rdata);
+ BP_LOG("Setup the backplane mode========end ==\n");
+
+ return status;
+}
+
+static void txgbe_e56_print_page_status(struct txgbe_hw *hw,
+ struct txgbe_backplane_ability *local_ability,
+ struct txgbe_backplane_ability *lp_ability)
+{
+ u32 rdata = 0;
+
+ /* Read the local AN73 Base Page Ability Registers */
+ BP_LOG("Read the local Base Page Ability Registers\n");
+ rdata = rd32_epcs(hw, SR_AN_MMD_ADV_REG1);
+ local_ability->next_page = (rdata & BIT(15)) ? 1 : 0;
+ BP_LOG("\tread 70010 data %0x\n", rdata);
+ rdata = rd32_epcs(hw, SR_AN_MMD_ADV_REG2);
+ BP_LOG("\tread 70011 data %0x\n", rdata);
+ local_ability->link_ability = (rdata >> 5) & GENMASK(10, 0);
+ /* amber-lite only support 10GKR - 25GKR/CR - 25GKR-S/CR-S */
+ BP_LOG("\t10GKR : %x\t25GKR-S/CR-S: %x\t25GKR/CR : %x\n",
+ local_ability->link_ability & BIT(ABILITY_10GBASE_KR) ? 1 : 0,
+ local_ability->link_ability & BIT(ABILITY_25GBASE_KRCR_S) ? 1 : 0,
+ local_ability->link_ability & BIT(ABILITY_25GBASE_KRCR) ? 1 : 0);
+ BP_LOG("\t40GCR4 : %x\t40GKR4 : %x\n",
+ local_ability->link_ability & BIT(ABILITY_40GBASE_CR4) ? 1 : 0,
+ local_ability->link_ability & BIT(ABILITY_40GBASE_KR4) ? 1 : 0);
+ rdata = rd32_epcs(hw, SR_AN_MMD_ADV_REG3);
+ BP_LOG("\tF1:FEC Req\tF0:FEC Sup\tF3:25GFEC\tF2:25GRS\n");
+ BP_LOG("\tF1: %d\t\tF0: %d\t\tF3: %d\t\tF2: %d\n",
+ ((rdata >> 15) & 0x01), ((rdata >> 14) & 0x01),
+ ((rdata >> 13) & 0x01), ((rdata >> 12) & 0x01));
+ local_ability->fec_ability = rdata;
+ BP_LOG("\tread 70012 data %0x\n", rdata);
+
+ /* Read the link partner AN73 Base Page Ability Registers */
+ BP_LOG("Read the link partner Base Page Ability Registers\n");
+ rdata = rd32_epcs(hw, SR_AN_MMD_LP_ABL1);
+ lp_ability->next_page = (rdata & BIT(15)) ? 1 : 0;
+ BP_LOG("\tread 70013 data %0x\n", rdata);
+ rdata = rd32_epcs(hw, SR_AN_MMD_LP_ABL2);
+ lp_ability->link_ability = (rdata >> 5) & GENMASK(10, 0);
+ BP_LOG("\tread 70014 data %0x\n", rdata);
+ BP_LOG("\tKX : %x\tKX4 : %x\n",
+ lp_ability->link_ability & BIT(ABILITY_1000BASE_KX) ? 1 : 0,
+ lp_ability->link_ability & BIT(ABILITY_10GBASE_KX4) ? 1 : 0);
+ BP_LOG("\t10GKR : %x\t25GKR-S/CR-S: %x\t25GKR/CR : %x\n",
+ lp_ability->link_ability & BIT(ABILITY_10GBASE_KR) ? 1 : 0,
+ lp_ability->link_ability & BIT(ABILITY_25GBASE_KRCR_S) ? 1 : 0,
+ lp_ability->link_ability & BIT(ABILITY_25GBASE_KRCR) ? 1 : 0);
+ BP_LOG("\t40GCR4 : %x\t40GKR4 : %x\n",
+ lp_ability->link_ability & BIT(ABILITY_40GBASE_CR4) ? 1 : 0,
+ lp_ability->link_ability & BIT(ABILITY_40GBASE_KR4) ? 1 : 0);
+ rdata = rd32_epcs(hw, SR_AN_MMD_LP_ABL3);
+ BP_LOG("\tF1:FEC Req\tF0:FEC Sup\tF3:25GFEC\tF2:25GRS\n");
+ BP_LOG("\tF1: %d\t\tF0: %d\t\tF3: %d\t\tF2: %d\n",
+ ((rdata >> 15) & 0x01), ((rdata >> 14) & 0x01),
+ ((rdata >> 13) & 0x01), ((rdata >> 12) & 0x01));
+ lp_ability->fec_ability = rdata;
+
+ hw->phy.fec_mode = 0;
+ if (rdata & TXGBE_25G_RS_FEC_REQ)
+ hw->phy.fec_mode |= TXGBE_25G_RS_FEC_REQ;
+ if (rdata & TXGBE_25G_BASE_FEC_REQ)
+ hw->phy.fec_mode |= TXGBE_25G_BASE_FEC_REQ;
+ if (rdata & TXGBE_10G_FEC_ABL)
+ hw->phy.fec_mode |= TXGBE_10G_FEC_ABL;
+ if (rdata & TXGBE_10G_FEC_REQ)
+ hw->phy.fec_mode |= TXGBE_10G_FEC_REQ;
+ BP_LOG("\tread 70015 data %0x\n", rdata);
+
+ BP_LOG("\tread 70016 data %0x\n", rd32_epcs(hw, 0x70016));
+ BP_LOG("\tread 70017 data %0x\n", rd32_epcs(hw, 0x70017));
+ BP_LOG("\tread 70018 data %0x\n", rd32_epcs(hw, 0x70018));
+ BP_LOG("\tread 70019 data %0x\n", rd32_epcs(hw, 0x70019));
+ BP_LOG("\tread 7001a data %0x\n", rd32_epcs(hw, 0x7001a));
+ BP_LOG("\tread 7001b data %0x\n", rd32_epcs(hw, 0x7001b));
+}
+
+static int chk_bkp_ability(struct txgbe_hw *hw,
+ struct txgbe_backplane_ability local_ability,
+ struct txgbe_backplane_ability lp_ability)
+{
+ unsigned int com_link_ability;
+
+ BP_LOG("CheckBkpAn73Ability():\n");
+ /* Check the common link ability and take action based on the result*/
+ com_link_ability = local_ability.link_ability &
+ lp_ability.link_ability;
+ BP_LOG("comAbility= 0x%x, Ability= 0x%x, lpAbility= 0x%x\n",
+ com_link_ability, local_ability.link_ability,
+ lp_ability.link_ability);
+
+ if (com_link_ability == 0) {
+ hw->bp_link_mode = 0;
+ BP_LOG("Do not support any compatible speed mode!\n");
+ return -EINVAL;
+ } else if (com_link_ability & BIT(ABILITY_40GBASE_KR4)) {
+ BP_LOG("Link mode is [ABILITY_40GBASE_KR4].\n");
+ hw->bp_link_mode = 40;
+ } else if (com_link_ability & BIT(ABILITY_40GBASE_CR4)) {
+ BP_LOG("Link mode is [ABILITY_40GBASE_CR4].\n");
+ hw->bp_link_mode = 40;
+ } else if (com_link_ability & BIT(ABILITY_25GBASE_KRCR_S)) {
+ BP_LOG("Link mode is [ABILITY_25GBASE_KRCR_S].\n");
+ hw->fec_mode = TXGBE_25G_RS_FEC_REQ;
+ hw->bp_link_mode = 25;
+ } else if (com_link_ability & BIT(ABILITY_25GBASE_KRCR)) {
+ BP_LOG("Link mode is [ABILITY_25GBASE_KRCR].\n");
+ hw->bp_link_mode = 25;
+ } else if (com_link_ability & BIT(ABILITY_10GBASE_KR)) {
+ BP_LOG("Link mode is [ABILITY_10GBASE_KR].\n");
+ hw->bp_link_mode = 10;
+ } else if (com_link_ability & BIT(ABILITY_10GBASE_KX4)) {
+ BP_LOG("Link mode is [ABILITY_10GBASE_KX4].\n");
+ hw->bp_link_mode = 10;
+ } else if (com_link_ability & BIT(ABILITY_1000BASE_KX)) {
+ BP_LOG("Link mode is [ABILITY_1000BASE_KX].\n");
+ hw->bp_link_mode = 1;
+ } else {
+ BP_LOG("No compatible link mode found!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int txgbe_e56_exchange_page(struct txgbe_hw *hw)
+{
+ struct txgbe_backplane_ability local_ability = {0}, lp_ability = {0};
+ u32 an_int, base_page = 0;
+ int count = 0;
+
+ an_int = rd32_epcs(hw, 0x78002);
+ /* 500ms timeout */
+ if (!(an_int & VR_AN_INTR_PG_RCV))
+ return -EINVAL;
+
+ for (count = 0; count < 500; count++) {
+ u32 fsm = rd32_epcs(hw, 0x78010);
+ u32 rdata = rd32_epcs(hw, 0x78002);
+
+ BP_LOG("-----count----- %d - fsm: %x\n", count, fsm);
+ BP_LOG("read 78002 data %0x and clear pacv\n", rdata);
+ an_int = rdata;
+ set_fields_e56(&rdata, 2, 2, 0x0);
+ wr32_epcs(hw, 0x78002, rdata);
+ if (an_int & VR_AN_INTR_PG_RCV) {
+ u32 addr;
+
+ txgbe_e56_print_page_status(hw, &local_ability, &lp_ability);
+ addr = base_page == 0 ? 0x70013 : 0x70019;
+ rdata = rd32_epcs(hw, addr);
+ if (rdata & BIT(14)) {
+ if (rdata & BIT(15)) {
+ /* always set null message */
+ wr32_epcs(hw, 0x70016, 0x2001);
+ BP_LOG("write 70016 0x%0x\n",
+ 0x2001);
+ }
+ base_page = 1;
+ }
+ }
+ if ((fsm & 0x8) == 0x8) {
+ hw->fsm = 0x8;
+ goto check_ability;
+ }
+ usec_delay(100);
+ }
+
+check_ability:
+ return chk_bkp_ability(hw, local_ability, lp_ability);
+}
+
+static int txgbe_e56_cl72_trainning(struct txgbe_hw *hw)
+{
+ u32 bylinkmode = hw->bp_link_mode;
+ u8 bypass_ctle = hw->bypass_ctle;
+ int status = 0, temp_data = 0;
+ u32 lane_num = 0, lane_idx = 0;
+ u32 __rte_unused pmd_ctrl = 0, txffe = 0;
+ int ret = 0;
+ u32 rdata;
+
+ u8 pll_en_cfg = 0;
+ u8 pmd_mode = 0;
+
+ switch (bylinkmode) {
+ case 10:
+ bylinkmode = 10;
+ lane_num = 1;
+ pll_en_cfg = 3;
+ pmd_mode = 0;
+ break;
+ case 40:
+ bylinkmode = 40;
+ lane_num = 4;
+ pll_en_cfg = 0; /* pll_en_cfg : single link to 0 */
+ pmd_mode = 1; /* pmd mode : 1 - single link */
+ break;
+ case 25:
+ bylinkmode = 25;
+ lane_num = 1;
+ pll_en_cfg = 3;
+ pmd_mode = 0;
+ break;
+ default:
+ BP_LOG("%s %d :Invalid speed\n", __func__, __LINE__);
+ break;
+ }
+
+ BP_LOG("2.3 Wait %dG KR phy mode init ....\n", bylinkmode);
+ status = txgbe_set_phy_link_mode(hw, bylinkmode);
+
+ /* 13. set phy an status to 1 - AN_CFG[0]: 4-7 lane0-lane3 */
+ rdata = rd32_ephy(hw, 0x1434);
+ set_fields_e56(&rdata, 7, 4, GENMASK(lane_num - 1, 0));
+ wr32_ephy(hw, 0x1434, rdata);
+
+ /* 14 and 15. kr training: set BASER_PMD_CONTROL[0, 7] for lane0-4 */
+ rdata = rd32_ephy(hw, 0x1640);
+ set_fields_e56(&rdata, 7, 0, GENMASK(2 * lane_num - 1, 0));
+ wr32_ephy(hw, 0x1640, rdata);
+
+ /* 16. enable CMS and its internal PLL */
+ rdata = rd32_ephy(hw, 0x1400);
+ set_fields_e56(&rdata, 21, 20, pll_en_cfg);
+ set_fields_e56(&rdata, 19, 12, 0); /* tx/rx off */
+ set_fields_e56(&rdata, 8, 8, pmd_mode);
+ set_fields_e56(&rdata, 1, 1, 0x1); /* pmd en */
+ wr32_ephy(hw, 0x1400, rdata);
+
+ /* 17. tx enable PMD_CFG[0] */
+ rdata = rd32_ephy(hw, 0x1400);
+ set_fields_e56(&rdata, 15, 12, GENMASK(lane_num - 1, 0)); /* tx en */
+ wr32_ephy(hw, 0x1400, rdata);
+
+ /* 18 */
+ /* 19. rxs calibration and adaotation sequeence */
+ BP_LOG("2.4 Wait %dG RXS.... fsm: %x\n",
+ bylinkmode, rd32_epcs(hw, 0x78010));
+ status = txgbe_e56_phy_rxs_calib_adapt_seq(hw, bylinkmode, bypass_ctle);
+ ret |= status;
+ /* 20 */
+ BP_LOG("2.5 Wait %dG phy calibration.... fsm: %x\n",
+ bylinkmode, rd32_epcs(hw, 0x78010));
+ txgbe_e56_set_rxs_ufine_le_max(hw, bylinkmode);
+ status = txgbe_e56_get_temp(hw, &temp_data);
+ if (bylinkmode == 40)
+ status = txgbe_temp_track_seq_40g(hw, TXGBE_LINK_SPEED_40GB_FULL);
+ else
+ status = txgbe_e56_rxs_post_cdr_lock_temp_track_seq(hw, bylinkmode);
+ /* 21 */
+ BP_LOG("2.6 Wait %dG phy kr training check.... fsm: %x\n",
+ bylinkmode, rd32_epcs(hw, 0x78010));
+ status = kr_read_poll(rd32_ephy, rdata,
+ ((rdata & 0xe) & GENMASK(lane_num, 1)) ==
+ (0xe & GENMASK(lane_num, 1)), 100,
+ 10000, hw, 0x163c);
+ pmd_ctrl = rd32_ephy(hw, 0x1644);
+ BP_LOG("KR TRAINNING CHECK = %x, %s. pmd_ctrl:%lx-%lx-%lx-%lx\n",
+ rdata, status ? "FAILED" : "SUCCESS",
+ FIELD_GET_M(GENMASK(3, 0), pmd_ctrl),
+ FIELD_GET_M(GENMASK(7, 4), pmd_ctrl),
+ FIELD_GET_M(GENMASK(11, 8), pmd_ctrl),
+ FIELD_GET_M(GENMASK(15, 12), pmd_ctrl));
+ ret |= status;
+ BP_LOG("before: %x-%x-%x-%x\n",
+ rd32_ephy(hw, 0x141c), rd32_ephy(hw, 0x1420),
+ rd32_ephy(hw, 0x1424), rd32_ephy(hw, 0x1428));
+
+ for (lane_idx = 0; lane_idx < lane_num; lane_idx++) {
+ txffe = rd32_ephy(hw, 0x828 + lane_idx * 0x100);
+ BP_LOG("after[%x]: %lx-%lx-%lx-%lx\n", lane_idx,
+ FIELD_GET_M(GENMASK(6, 0), txffe),
+ FIELD_GET_M(GENMASK(21, 16), txffe),
+ FIELD_GET_M(GENMASK(29, 24), txffe),
+ FIELD_GET_M(GENMASK(13, 8), txffe));
+ }
+
+ /* 22 */
+ BP_LOG("2.7 Wait %dG phy Rx adc.... fsm:%x\n",
+ bylinkmode, rd32_epcs(hw, 0x78010));
+ status = txgbe_e56_rxs_adc_adapt_seq(hw, bypass_ctle);
+
+ return ret;
+}
+
+int handle_e56_bkp_an73_flow(struct txgbe_hw *hw)
+{
+ int status = 0;
+ u32 rdata;
+
+ BP_LOG("2.1 Wait page changed ....\n");
+ status = txgbe_e56_exchange_page(hw);
+ if (status) {
+ BP_LOG("Exchange page failed\n");
+ return status;
+ }
+
+ BP_LOG("2.2 Wait page changed ..done..\n");
+ wr32_epcs(hw, 0x100ab, 0);
+ if (AN_TRAINNING_MODE) {
+ rdata = rd32_epcs(hw, 0x70000);
+ BP_LOG("read 0x70000 data %0x\n", rdata);
+ wr32_epcs(hw, 0x70000, 0);
+ BP_LOG("write 0x70000 0x%0x\n", 0);
+ }
+
+ rdata = rd32_epcs(hw, 0x78002);
+ BP_LOG("read 78002 data %0x and clear page int\n", rdata);
+ set_fields_e56(&rdata, 2, 2, 0x0);
+ wr32_epcs(hw, 0x78002, rdata);
+
+ /* dis phy tx/rx lane */
+ rdata = rd32_ephy(hw, 0x1400);
+ set_fields_e56(&rdata, 19, 16, 0x0);
+ set_fields_e56(&rdata, 15, 12, 0x0);
+ set_fields_e56(&rdata, 1, 1, 0x0);
+ wr32_ephy(hw, 0x1400, rdata);
+ BP_LOG("Ephy Write A: 0x%x, D: 0x%x\n", 0x1400, rdata);
+
+ /* wait rx/tx/cm powerdn_st */
+ status = kr_read_poll(rd32_ephy, rdata,
+ (rdata & GENMASK(3, 0)) == 0x9, 100,
+ 2000, hw, 0x14d4);
+ BP_LOG("wait ctrl_fsm_cm_st = %x, %s.\n",
+ rdata, status ? "FAILED" : "SUCCESS");
+
+ if (hw->phy.fec_mode & TXGBE_25G_RS_FEC_REQ) {
+ wr32_epcs(hw, 0x180a3, 0x68c1);
+ wr32_epcs(hw, 0x180a4, 0x3321);
+ wr32_epcs(hw, 0x180a5, 0x973e);
+ wr32_epcs(hw, 0x180a6, 0xccde);
+
+ wr32_epcs(hw, 0x38018, 1024);
+ rdata = rd32_epcs(hw, 0x100c8);
+ set_fields_e56(&rdata, 2, 2, 1);
+ wr32_epcs(hw, 0x100c8, rdata);
+ BP_LOG("Advertised FEC modes : %s\n", "RS-FEC");
+ hw->cur_fec_link = TXGBE_PHY_FEC_RS;
+ } else if (hw->phy.fec_mode & TXGBE_25G_BASE_FEC_REQ) {
+ /* FEC: FC-FEC/BASE-R */
+ wr32_epcs(hw, 0x100ab, BIT(0));
+ BP_LOG("Epcs Write A: 0x%x, D: 0x%x\n", 0x100ab, 1);
+ PMD_DRV_LOG(INFO, "Advertised FEC modes : %s", "25GBASE-R");
+ hw->cur_fec_link = TXGBE_PHY_FEC_BASER;
+ } else if (hw->fec_mode & (TXGBE_10G_FEC_REQ)) {
+ /* FEC: FC-FEC/BASE-R */
+ wr32_epcs(hw, 0x100ab, BIT(0));
+ BP_LOG("Epcs Write A: 0x%x, D: 0x%x\n", 0x100ab, 1);
+ PMD_DRV_LOG(INFO, "Advertised FEC modes : %s", "BASE-R");
+ hw->cur_fec_link = TXGBE_PHY_FEC_BASER;
+ } else {
+ PMD_DRV_LOG(INFO, "Advertised FEC modes : %s", "NONE");
+ hw->cur_fec_link = TXGBE_PHY_FEC_OFF;
+ }
+
+ status = txgbe_e56_cl72_trainning(hw);
+
+ rdata = rd32_ephy(hw, E56PHY_RXS_IDLE_DETECT_1_ADDR);
+ set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MAX, 0x28);
+ set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MIN, 0xa);
+ wr32_ephy(hw, E56PHY_RXS_IDLE_DETECT_1_ADDR, rdata);
+ wr32_ephy(hw, E56PHY_INTR_0_ADDR, E56PHY_INTR_0_IDLE_ENTRY1);
+ wr32_ephy(hw, E56PHY_INTR_1_ADDR, E56PHY_INTR_1_IDLE_EXIT1);
+ wr32_ephy(hw, E56PHY_INTR_0_ENABLE_ADDR, E56PHY_INTR_0_IDLE_ENTRY1);
+ wr32_ephy(hw, E56PHY_INTR_1_ENABLE_ADDR, E56PHY_INTR_1_IDLE_EXIT1);
+
+ return status;
+}
diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.h b/drivers/net/txgbe/base/txgbe_e56_bp.h
index 97d5656cad..9329387334 100644
--- a/drivers/net/txgbe/base/txgbe_e56_bp.h
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.h
@@ -276,4 +276,7 @@ typedef union {
#define E56PHY_CMS_ANA_OVRDVAL_10_ADDR (E56PHY_CMS_BASE_ADDR + 0xD8)
#define E56PHY_CMS_ANA_OVRDVAL_7_ANA_LCPLL_LF_LPF_SETCODE_CALIB_I 8, 4
+int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
+ u8 bp_link_mode, u32 need_restart);
+int handle_e56_bkp_an73_flow(struct txgbe_hw *hw);
#endif
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index 7b6937b9ca..8b7cbd592a 100644
--- a/drivers/net/txgbe/base/txgbe_hw.c
+++ b/drivers/net/txgbe/base/txgbe_hw.c
@@ -4071,6 +4071,12 @@ s32 txgbe_reset_pipeline_raptor(struct txgbe_hw *hw)
return err;
}
+bool txgbe_is_backplane(struct txgbe_hw *hw)
+{
+ return hw->phy.get_media_type(hw) == txgbe_media_type_backplane ?
+ true : false;
+}
+
bool txgbe_gpio_ext_check(struct txgbe_hw *hw, u8 gpio_ext_mask)
{
u32 gpio_ext = rd32(hw, TXGBE_GPIOEXT);
diff --git a/drivers/net/txgbe/base/txgbe_hw.h b/drivers/net/txgbe/base/txgbe_hw.h
index bc34d639eb..b44190bc34 100644
--- a/drivers/net/txgbe/base/txgbe_hw.h
+++ b/drivers/net/txgbe/base/txgbe_hw.h
@@ -118,6 +118,6 @@ s32 txgbe_reinit_fdir_tables(struct txgbe_hw *hw);
bool txgbe_verify_lesm_fw_enabled_raptor(struct txgbe_hw *hw);
s32 txgbe_fmgr_cmd_op(struct txgbe_hw *hw, u32 cmd, u32 cmd_addr);
s32 txgbe_flash_read_dword(struct txgbe_hw *hw, u32 addr, u32 *data);
-s32 txgbe_e56_check_phy_link(struct txgbe_hw *hw, u32 *speed,
- bool *link_up);
+bool txgbe_is_backplane(struct txgbe_hw *hw);
+bool txgbe_gpio_ext_check(struct txgbe_hw *hw, u8 gpio_ext_mask);
#endif /* _TXGBE_HW_H_ */
diff --git a/drivers/net/txgbe/base/txgbe_osdep.h b/drivers/net/txgbe/base/txgbe_osdep.h
index f4282b3241..da069e94f6 100644
--- a/drivers/net/txgbe/base/txgbe_osdep.h
+++ b/drivers/net/txgbe/base/txgbe_osdep.h
@@ -162,6 +162,10 @@ static inline u64 REVERT_BIT_MASK64(u64 mask)
((mask & 0xFFFFFFFF00000000) >> 32);
}
+#define BITS_PER_LONG (__SIZEOF_LONG__ * 8)
+#define GENMASK(h, l) \
+ (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
+
#define IOMEM
#define BIT(nr) (1UL << (nr))
diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index bf7260a295..f3e3491b30 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -2503,6 +2503,27 @@ void txgbe_set_phy_temp(struct txgbe_hw *hw)
}
}
+int txgbe_is_dac_cable(struct txgbe_hw *hw)
+{
+ if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
+ hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1 ||
+ hw->phy.sfp_type == txgbe_sfp_type_da_act_lmt_core0 ||
+ hw->phy.sfp_type == txgbe_sfp_type_da_act_lmt_core1 ||
+ hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core0 ||
+ hw->phy.sfp_type == txgbe_qsfp_type_40g_cu_core1)
+ return true;
+
+ return false;
+}
+
+int txgbe_xpcs_an_enabled(struct txgbe_hw *hw)
+{
+ if (!(txgbe_is_dac_cable(hw) || txgbe_is_backplane(hw)))
+ return false;
+
+ return hw->devarg.auto_neg ? true : false;
+}
+
/**
* txgbe_kr_handle - Handle the interrupt of auto-negotiation
* @hw: pointer to hardware structure
diff --git a/drivers/net/txgbe/base/txgbe_phy.h b/drivers/net/txgbe/base/txgbe_phy.h
index c02be3cc34..93a5ad18c1 100644
--- a/drivers/net/txgbe/base/txgbe_phy.h
+++ b/drivers/net/txgbe/base/txgbe_phy.h
@@ -105,6 +105,8 @@
#define VR_AN_INTR_CMPLT MS16(0, 0x1)
#define VR_AN_INTR_LINK MS16(1, 0x1)
#define VR_AN_INTR_PG_RCV MS16(2, 0x1)
+#define TXGBE_E56_AN_TXDIS MS16(3, 0x1)
+#define TXGBE_E56_AN_PG_RCV MS16(4, 0x1)
#define VR_AN_KR_MODE_CL 0x078003
#define VR_AN_KR_MODE_CL_PDET MS16(0, 0x1)
#define VR_XS_OR_PCS_MMD_DIGI_CTL1 0x038000
@@ -428,6 +430,24 @@
#define TXGBE_BP_M_NAUTO 0
#define TXGBE_BP_M_AUTO 1
+#define kr_read_poll(op, val, cond, sleep_us, \
+ times, args...) \
+({ \
+ unsigned long __sleep_us = (sleep_us); \
+ u32 __times = (times); \
+ u32 i; \
+ int __cond = 0; \
+ for (i = 0; i < __times; i++) { \
+ (val) = op(args); \
+ if (cond) { \
+ __cond = 1; \
+ break; \
+ } \
+ usec_delay(__sleep_us);\
+ } \
+ (__cond) ? 0 : -1; \
+})
+
#ifndef CL72_KRTR_PRBS_MODE_EN
#define CL72_KRTR_PRBS_MODE_EN 0xFFFF /* open kr prbs check */
#endif
@@ -490,6 +510,8 @@ void txgbe_autoc_write(struct txgbe_hw *hw, u64 value);
void txgbe_bp_mode_set(struct txgbe_hw *hw);
void txgbe_set_phy_temp(struct txgbe_hw *hw);
void txgbe_bp_down_event(struct txgbe_hw *hw);
+int txgbe_is_dac_cable(struct txgbe_hw *hw);
+int txgbe_xpcs_an_enabled(struct txgbe_hw *hw);
s32 txgbe_kr_handle(struct txgbe_hw *hw);
#endif /* _TXGBE_PHY_H_ */
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index 7fb4bcc513..47629aa9e0 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -719,6 +719,7 @@ struct txgbe_phy_info {
u32 addr;
u32 id;
enum txgbe_sfp_type sfp_type;
+ u32 fiber_suppport_speed;
bool sfp_setup_needed;
u32 revision;
u32 media_type;
@@ -740,6 +741,7 @@ struct txgbe_phy_info {
u16 ffe_pre2;
u16 ffe_post;
u16 fec_mode;
+ u16 bp_capa;
};
#define TXGBE_DEVARG_BP_AUTO "auto_neg"
@@ -899,7 +901,28 @@ struct txgbe_hw {
u32 cur_fec_link;
int temperature;
u32 bp_link_mode;
-};
+ bool dac_sfp;
+ bool bypass_ctle;
+ u32 curbp_link_mode;
+ bool an_done;
+ u32 fsm;
+ u64 bp_event_interval;
+};
+
+typedef enum {
+ ABILITY_1000BASE_KX,
+ ABILITY_10GBASE_KX4,
+ ABILITY_10GBASE_KR,
+ ABILITY_40GBASE_KR4,
+ ABILITY_40GBASE_CR4,
+ ABILITY_100GBASE_CR10,
+ ABILITY_100GBASE_KP4,
+ ABILITY_100GBASE_KR4,
+ ABILITY_100GBASE_CR4,
+ ABILITY_25GBASE_KRCR_S,
+ ABILITY_25GBASE_KRCR,
+ ABILITY_MAX,
+} ability_filed_encding;
struct txgbe_backplane_ability {
u32 next_page; /* Next Page (bit0) */
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index f432e6ce25..f1119cf6f8 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2010,6 +2010,10 @@ txgbe_dev_start(struct rte_eth_dev *dev)
txgbe_l2_tunnel_conf(dev);
txgbe_filter_restore(dev);
+ hw->bp_event_interval = 100 * 1000;
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40)
+ rte_eal_alarm_set(hw->bp_event_interval, txgbe_dev_e56_check_bp_event, dev);
+
if (tm_conf->root && !tm_conf->committed)
PMD_DRV_LOG(WARNING,
"please call hierarchy_commit() "
@@ -2054,8 +2058,10 @@ txgbe_dev_stop(struct rte_eth_dev *dev)
PMD_INIT_FUNC_TRACE();
- if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40)
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40) {
+ rte_eal_alarm_cancel(txgbe_dev_e56_check_bp_event, dev);
rte_eal_alarm_cancel(txgbe_dev_setup_link_alarm_handler_aml, hw);
+ }
rte_eal_alarm_cancel(txgbe_dev_detect_sfp, dev);
rte_eal_alarm_cancel(txgbe_tx_queue_clear_error, dev);
@@ -2926,6 +2932,107 @@ txgbe_dev_supported_ptypes_get(struct rte_eth_dev *dev, size_t *no_of_elements)
return NULL;
}
+void txgbe_dev_e56_check_bp_event(void *param)
+{
+ struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+ struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
+ u32 an_int1 = 0, value = 0, fsm = 0;
+ u32 __rte_unused an_int = 0;
+ int ret = 0;
+ bool need_link_update = false;
+
+ if (!hw)
+ return;
+
+ if (!(txgbe_xpcs_an_enabled(hw)))
+ return;
+
+ if (!hw->devarg.auto_neg)
+ return;
+
+ /* only continue if link is down */
+ if (dev->data->dev_link.link_status)
+ goto out;
+
+ value = rd32_epcs(hw, VR_AN_INTR);
+ an_int = value;
+ if (value & 0xF)
+ hw->bp_event_interval = 100 * 1000;
+
+ if (value & VR_AN_INTR_CMPLT) {
+ hw->an_done = true;
+ need_link_update = true;
+ value &= ~VR_AN_INTR_CMPLT;
+ wr32_epcs(hw, VR_AN_INTR, value);
+ }
+
+ if (value & VR_AN_INTR_LINK) {
+ value &= ~VR_AN_INTR_LINK;
+ wr32_epcs(hw, VR_AN_INTR, value);
+ }
+
+ if (value & TXGBE_E56_AN_TXDIS) {
+ value &= ~TXGBE_E56_AN_TXDIS;
+ wr32_epcs(hw, VR_AN_INTR, value);
+ rte_spinlock_lock(&hw->phy_lock);
+ txgbe_e56_set_phy_link_mode(hw, 10, hw->bypass_ctle);
+ rte_spinlock_unlock(&hw->phy_lock);
+ goto an_status;
+ }
+
+ if (value & VR_AN_INTR_PG_RCV) {
+ BP_LOG("%d Enter training\n", hw->port_id);
+ ret = handle_e56_bkp_an73_flow(hw);
+ if (!AN_TRAINNING_MODE) {
+ fsm = rd32_epcs(hw, 0x78010);
+ if (fsm & 0x8)
+ goto an_status;
+ if (ret) {
+ BP_LOG("Training FAILED, do reset\n");
+ rte_spinlock_lock(&hw->phy_lock);
+ txgbe_e56_set_phy_link_mode(hw, 10, hw->bypass_ctle);
+ rte_spinlock_unlock(&hw->phy_lock);
+ } else {
+ BP_LOG("ALL SUCCEEDED\n");
+ }
+ } else {
+ if (ret) {
+ BP_LOG("Training FAILED, do reset\n");
+ rte_spinlock_lock(&hw->phy_lock);
+ txgbe_e56_set_phy_link_mode(hw, 10, hw->bypass_ctle);
+ rte_spinlock_unlock(&hw->phy_lock);
+ } else {
+ hw->an_done = true;
+ }
+ }
+ }
+
+an_status:
+ an_int1 = rd32_epcs(hw, 0x78002);
+ if (an_int1 & VR_AN_INTR_CMPLT) {
+ hw->an_done = true;
+ need_link_update = true;
+ }
+
+ BP_LOG("%d RLU:%x MLU:%x INT:%x-%x CTL:%x fsm:%x pmd_cfg0:%x an_done:%d\n",
+ hw->port_id, rd32_epcs(hw, 0x30001), rd32(hw, 0x14404),
+ an_int, an_int1,
+ rd32_epcs(hw, 0x70000),
+ rd32_epcs(hw, 0x78010),
+ rd32_ephy(hw, 0x1400),
+ hw->an_done);
+
+ if (need_link_update)
+ txgbe_dev_link_update(dev, 0);
+
+ if (dev->data->dev_link.link_status)
+ hw->bp_event_interval = 2000 * 1000;
+
+out:
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40)
+ rte_eal_alarm_set(hw->bp_event_interval, txgbe_dev_e56_check_bp_event, dev);
+}
+
static void
txgbe_dev_detect_sfp(void *param)
{
diff --git a/drivers/net/txgbe/txgbe_ethdev.h b/drivers/net/txgbe/txgbe_ethdev.h
index 1ec8e096cc..309db3bfe9 100644
--- a/drivers/net/txgbe/txgbe_ethdev.h
+++ b/drivers/net/txgbe/txgbe_ethdev.h
@@ -747,5 +747,5 @@ void txgbe_vlan_hw_strip_bitmap_set(struct rte_eth_dev *dev,
uint16_t queue, bool on);
void txgbe_config_vlan_strip_on_all_queues(struct rte_eth_dev *dev,
int mask);
-
+void txgbe_dev_e56_check_bp_event(void *param);
#endif /* _TXGBE_ETHDEV_H_ */
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v7 15/21] net/txgbe: fix FEC mode configuration on 25G NIC
From: Zaiyu Wang @ 2026-06-17 3:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617033400.376-1-zaiyuwang@trustnetic.com>
The 25G NIC offers off, RS, Base-R, and auto FEC modes. When
reconfiguring the PHY, the FEC mode must match on both sides;
otherwise, the link cannot come up. The current driver fails to
maintain this requirement, causing link instability.
Add proper FEC mode handling during PHY reconfiguration to
guarantee link establishment.
Fixes: fb6eb170dfa2 ("net/txgbe: add basic link configuration for Amber-Lite")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_aml.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/net/txgbe/base/txgbe_aml.c b/drivers/net/txgbe/base/txgbe_aml.c
index 5d449a0bd9..ac80d85f08 100644
--- a/drivers/net/txgbe/base/txgbe_aml.c
+++ b/drivers/net/txgbe/base/txgbe_aml.c
@@ -282,6 +282,14 @@ s32 txgbe_setup_phy_link_aml(struct txgbe_hw *hw,
!(hw->fec_mode & hw->cur_fec_link)))
goto out;
+ if (speed == TXGBE_LINK_SPEED_25GB_FULL &&
+ link_speed == TXGBE_LINK_SPEED_25GB_FULL) {
+ txgbe_e56_fec_polling(hw, &link_up);
+
+ if (link_up)
+ goto out;
+ }
+
rte_spinlock_lock(&hw->phy_lock);
ret_status = txgbe_set_link_to_amlite(hw, speed);
rte_spinlock_unlock(&hw->phy_lock);
@@ -360,7 +368,10 @@ static s32 txgbe_setup_mac_link_multispeed_fiber_aml(struct txgbe_hw *hw,
/* If we already have link at this speed, just jump out */
txgbe_e56_check_phy_link(hw, &link_speed, &link_up);
- if (link_speed == TXGBE_LINK_SPEED_25GB_FULL && link_up)
+ hw->cur_fec_link = txgbe_phy_fec_get(hw);
+
+ if (link_speed == TXGBE_LINK_SPEED_25GB_FULL && link_up &&
+ hw->fec_mode & hw->cur_fec_link)
goto out;
/* Allow module to change analog characteristics (10G -> 25G) */
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v7 16/21] net/txgbe: fix SFP module identification
From: Zaiyu Wang @ 2026-06-17 3:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617033400.376-1-zaiyuwang@trustnetic.com>
Some optical modules were not correctly recognized due to ambiguous
classification in the original detection flow. Rework the module
identification logic to cover all module types. Also narrow the
I2C lock scope to avoid potential race conditions during module
access.
Fixes: ab191e6d9189 ("net/txgbe: support new SFP/QSFP modules")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_hw.c | 2 -
drivers/net/txgbe/base/txgbe_phy.c | 341 ++++++++++------------------
drivers/net/txgbe/base/txgbe_phy.h | 18 +-
drivers/net/txgbe/base/txgbe_type.h | 2 +
4 files changed, 134 insertions(+), 229 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index 8b7cbd592a..c84656e206 100644
--- a/drivers/net/txgbe/base/txgbe_hw.c
+++ b/drivers/net/txgbe/base/txgbe_hw.c
@@ -2909,8 +2909,6 @@ s32 txgbe_init_ops_generic(struct txgbe_hw *hw)
phy->read_i2c_eeprom = txgbe_read_i2c_eeprom;
phy->write_i2c_eeprom = txgbe_write_i2c_eeprom;
phy->identify_sfp = txgbe_identify_module;
- phy->read_i2c_byte_unlocked = txgbe_read_i2c_byte_unlocked;
- phy->write_i2c_byte_unlocked = txgbe_write_i2c_byte_unlocked;
phy->check_overtemp = txgbe_check_overtemp;
phy->reset = txgbe_reset_phy;
phy->set_link_hostif = txgbe_hic_ephy_set_link;
diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c
index f3e3491b30..2fbe50e242 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -830,6 +830,10 @@ s32 txgbe_identify_sfp_module(struct txgbe_hw *hw)
return TXGBE_ERR_SFP_NOT_PRESENT;
}
+ err = hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
+ if (err)
+ return -EBUSY;
+
err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_IDENTIFIER,
&identifier);
if (err != 0) {
@@ -839,11 +843,13 @@ s32 txgbe_identify_sfp_module(struct txgbe_hw *hw)
hw->phy.id = 0;
hw->phy.type = txgbe_phy_unknown;
}
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
return TXGBE_ERR_SFP_NOT_PRESENT;
}
if (identifier != TXGBE_SFF_IDENTIFIER_SFP) {
hw->phy.type = txgbe_phy_sfp_unsupported;
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
return TXGBE_ERR_SFP_NOT_SUPPORTED;
}
@@ -888,7 +894,42 @@ s32 txgbe_identify_sfp_module(struct txgbe_hw *hw)
* 11 SFP_1g_sx_CORE0 - chip-specific
* 12 SFP_1g_sx_CORE1 - chip-specific
*/
- if (cable_tech & TXGBE_SFF_CABLE_DA_ACTIVE) {
+ if (cable_tech & TXGBE_SFF_CABLE_DA_PASSIVE) {
+ if (hw->bus.lan_id == 0)
+ hw->phy.sfp_type = txgbe_sfp_type_da_cu_core0;
+ else
+ hw->phy.sfp_type = txgbe_sfp_type_da_cu_core1;
+
+ if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
+ hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1) {
+ hw->dac_sfp = true;
+ }
+
+ if (comp_copper_len == TXGBE_SFF_COPPER_1M)
+ hw->bypass_ctle = true;
+ else
+ hw->bypass_ctle = false;
+
+ if (comp_codes_25g == TXGBE_SFF_25GBASECR_91FEC ||
+ comp_codes_25g == TXGBE_SFF_25GBASECR_74FEC ||
+ comp_codes_25g == TXGBE_SFF_25GBASECR_NOFEC) {
+ hw->phy.fiber_suppport_speed =
+ TXGBE_LINK_SPEED_25GB_FULL |
+ TXGBE_LINK_SPEED_10GB_FULL;
+ } else {
+ hw->phy.fiber_suppport_speed |=
+ TXGBE_LINK_SPEED_10GB_FULL;
+ }
+ } else if (comp_codes_25g == TXGBE_SFF_25GAUI_C2M_AOC_BER_5 ||
+ comp_codes_25g == TXGBE_SFF_25GAUI_C2M_ACC_BER_5 ||
+ comp_codes_25g == TXGBE_SFF_25GAUI_C2M_AOC_BER_12 ||
+ comp_codes_25g == TXGBE_SFF_25GAUI_C2M_ACC_BER_12) {
+ hw->dac_sfp = false;
+ hw->phy.sfp_type = (hw->bus.lan_id == 0
+ ? txgbe_sfp_type_25g_aoc_core0
+ : txgbe_sfp_type_25g_aoc_core1);
+ } else if (cable_tech & TXGBE_SFF_CABLE_DA_ACTIVE) {
+ hw->dac_sfp = false;
err = hw->phy.read_i2c_eeprom(hw,
TXGBE_SFF_CABLE_SPEC_COMP, &cable_spec);
if (err != 0)
@@ -1005,6 +1046,7 @@ s32 txgbe_identify_sfp_module(struct txgbe_hw *hw)
/* Allow any DA cable vendor */
if (cable_tech & (TXGBE_SFF_CABLE_DA_PASSIVE |
TXGBE_SFF_CABLE_DA_ACTIVE)) {
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
return 0;
}
@@ -1017,6 +1059,7 @@ s32 txgbe_identify_sfp_module(struct txgbe_hw *hw)
hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core0 ||
hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core1)) {
hw->phy.type = txgbe_phy_sfp_unsupported;
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
return TXGBE_ERR_SFP_NOT_SUPPORTED;
}
@@ -1031,9 +1074,11 @@ s32 txgbe_identify_sfp_module(struct txgbe_hw *hw)
hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core1)) {
DEBUGOUT("SFP+ module not supported");
hw->phy.type = txgbe_phy_sfp_unsupported;
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
return TXGBE_ERR_SFP_NOT_SUPPORTED;
}
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
return err;
}
@@ -1046,28 +1091,13 @@ s32 txgbe_identify_sfp_module(struct txgbe_hw *hw)
s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw)
{
s32 err = TXGBE_ERR_PHY_ADDR_INVALID;
- u32 vendor_oui = 0;
- enum txgbe_sfp_type stored_sfp_type = hw->phy.sfp_type;
- u8 identifier = 0;
- u8 comp_codes_1g = 0;
- u8 comp_codes_10g = 0;
- u8 oui_bytes[3] = {0, 0, 0};
- u16 enforce_sfp = 0;
- u8 connector = 0;
- u8 cable_length = 0;
- u8 device_tech = 0;
- bool active_cable = false;
+ u8 identifier = 0, transceiver_type = 0;
u32 value;
- if (hw->phy.media_type != txgbe_media_type_fiber_qsfp) {
- hw->phy.sfp_type = txgbe_sfp_type_not_present;
- err = TXGBE_ERR_SFP_NOT_PRESENT;
- goto out;
- }
+ /* config GPIO before read i2c */
+ wr32(hw, TXGBE_GPIODATA, TXGBE_GPIOBIT_1);
if (hw->mac.type == txgbe_mac_aml40) {
- /* config GPIO before read i2c */
- wr32(hw, TXGBE_GPIODATA, TXGBE_GPIOBIT_1);
value = rd32(hw, TXGBE_GPIOEXT);
if (value & TXGBE_SFP1_MOD_PRST_LS) {
hw->phy.sfp_type = txgbe_sfp_type_not_present;
@@ -1075,175 +1105,68 @@ s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw)
}
}
- err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_IDENTIFIER,
- &identifier);
-ERR_I2C:
- if (err != 0) {
+ if (hw->phy.media_type != txgbe_media_type_fiber_qsfp) {
hw->phy.sfp_type = txgbe_sfp_type_not_present;
- hw->phy.id = 0;
- hw->phy.type = txgbe_phy_unknown;
return TXGBE_ERR_SFP_NOT_PRESENT;
}
- if (identifier != TXGBE_SFF_IDENTIFIER_QSFP_PLUS) {
- hw->phy.type = txgbe_phy_sfp_unsupported;
- err = TXGBE_ERR_SFP_NOT_SUPPORTED;
- goto out;
- }
-
- hw->phy.id = identifier;
-
- err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_QSFP_10GBE_COMP,
- &comp_codes_10g);
+ err = hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
if (err != 0)
- goto ERR_I2C;
+ return -EBUSY;
- err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_QSFP_1GBE_COMP,
- &comp_codes_1g);
+ err = hw->phy.read_i2c_sff8636(hw, 0, TXGBE_SFF_IDENTIFIER,
+ &identifier);
if (err != 0)
- goto ERR_I2C;
+ goto err_read_i2c_eeprom;
- if (comp_codes_10g & TXGBE_SFF_QSFP_DA_PASSIVE_CABLE) {
- hw->phy.type = txgbe_phy_qsfp_unknown_passive;
- if (hw->mac.type == txgbe_mac_aml40) {
+ if (identifier != TXGBE_SFF_IDENTIFIER_QSFP &&
+ identifier != TXGBE_SFF_IDENTIFIER_QSFP_PLUS) {
+ PMD_INIT_LOG(ERR, "port[%d] QSFP module not supported, identifier = 0x%x",
+ hw->bus.lan_id, identifier);
+ hw->phy.type = txgbe_phy_sfp_unsupported;
+ err = TXGBE_ERR_SFP_NOT_SUPPORTED;
+ } else {
+ err = hw->phy.read_i2c_sff8636(hw, 0,
+ TXGBE_ETHERNET_COMP_OFFSET,
+ &transceiver_type);
+ if (err != 0)
+ goto err_read_i2c_eeprom;
+
+ if (transceiver_type & TXGBE_SFF_ETHERNET_40G_CR4) {
if (hw->bus.lan_id == 0)
hw->phy.sfp_type = txgbe_qsfp_type_40g_cu_core0;
else
hw->phy.sfp_type = txgbe_qsfp_type_40g_cu_core1;
- } else {
- if (hw->bus.lan_id == 0)
- hw->phy.sfp_type = txgbe_sfp_type_da_cu_core0;
- else
- hw->phy.sfp_type = txgbe_sfp_type_da_cu_core1;
- }
- } else if (comp_codes_10g & TXGBE_SFF_40GBASE_SR4) {
- if (hw->bus.lan_id == 0)
- hw->phy.sfp_type = txgbe_qsfp_type_40g_sr_core0;
- else
- hw->phy.sfp_type = txgbe_qsfp_type_40g_sr_core1;
- } else if (comp_codes_10g & TXGBE_SFF_40GBASE_LR4) {
- if (hw->bus.lan_id == 0)
- hw->phy.sfp_type = txgbe_qsfp_type_40g_lr_core0;
- else
- hw->phy.sfp_type = txgbe_qsfp_type_40g_lr_core1;
- } else if (comp_codes_10g & (TXGBE_SFF_10GBASESR_CAPABLE |
- TXGBE_SFF_10GBASELR_CAPABLE)) {
- if (hw->bus.lan_id == 0)
- hw->phy.sfp_type = txgbe_sfp_type_srlr_core0;
- else
- hw->phy.sfp_type = txgbe_sfp_type_srlr_core1;
- } else {
- if (comp_codes_10g & TXGBE_SFF_QSFP_DA_ACTIVE_CABLE)
- active_cable = true;
-
- if (!active_cable) {
- hw->phy.read_i2c_eeprom(hw,
- TXGBE_SFF_QSFP_CONNECTOR,
- &connector);
-
- hw->phy.read_i2c_eeprom(hw,
- TXGBE_SFF_QSFP_CABLE_LENGTH,
- &cable_length);
-
- hw->phy.read_i2c_eeprom(hw,
- TXGBE_SFF_QSFP_DEVICE_TECH,
- &device_tech);
-
- if (connector ==
- TXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE &&
- cable_length > 0 &&
- ((device_tech >> 4) ==
- TXGBE_SFF_QSFP_TRANSMITTER_850NM_VCSEL))
- active_cable = true;
+ hw->phy.fiber_suppport_speed =
+ TXGBE_LINK_SPEED_40GB_FULL |
+ TXGBE_LINK_SPEED_10GB_FULL;
}
- if (active_cable) {
- hw->phy.type = txgbe_phy_qsfp_unknown_active;
+ if (transceiver_type & TXGBE_SFF_ETHERNET_40G_SR4) {
if (hw->bus.lan_id == 0)
- hw->phy.sfp_type =
- txgbe_sfp_type_da_act_lmt_core0;
+ hw->phy.sfp_type = txgbe_qsfp_type_40g_sr_core0;
else
- hw->phy.sfp_type =
- txgbe_sfp_type_da_act_lmt_core1;
- } else {
- /* unsupported module type */
- hw->phy.type = txgbe_phy_sfp_unsupported;
- err = TXGBE_ERR_SFP_NOT_SUPPORTED;
- goto out;
+ hw->phy.sfp_type = txgbe_qsfp_type_40g_sr_core1;
}
- }
-
- if (hw->phy.sfp_type != stored_sfp_type)
- hw->phy.sfp_setup_needed = true;
-
- /* Determine if the QSFP+ PHY is dual speed or not. */
- hw->phy.multispeed_fiber = false;
- if (((comp_codes_1g & TXGBE_SFF_1GBASESX_CAPABLE) &&
- (comp_codes_10g & TXGBE_SFF_10GBASESR_CAPABLE)) ||
- ((comp_codes_1g & TXGBE_SFF_1GBASELX_CAPABLE) &&
- (comp_codes_10g & TXGBE_SFF_10GBASELR_CAPABLE)))
- hw->phy.multispeed_fiber = true;
-
- /* Determine PHY vendor for optical modules */
- if (comp_codes_10g & (TXGBE_SFF_10GBASESR_CAPABLE |
- TXGBE_SFF_10GBASELR_CAPABLE)) {
- err = hw->phy.read_i2c_eeprom(hw,
- TXGBE_SFF_QSFP_VENDOR_OUI_BYTE0,
- &oui_bytes[0]);
-
- if (err != 0)
- goto ERR_I2C;
-
- err = hw->phy.read_i2c_eeprom(hw,
- TXGBE_SFF_QSFP_VENDOR_OUI_BYTE1,
- &oui_bytes[1]);
-
- if (err != 0)
- goto ERR_I2C;
- err = hw->phy.read_i2c_eeprom(hw,
- TXGBE_SFF_QSFP_VENDOR_OUI_BYTE2,
- &oui_bytes[2]);
-
- if (err != 0)
- goto ERR_I2C;
-
- vendor_oui =
- ((oui_bytes[0] << 24) |
- (oui_bytes[1] << 16) |
- (oui_bytes[2] << 8));
-
- if (vendor_oui == TXGBE_SFF_VENDOR_OUI_INTEL)
- hw->phy.type = txgbe_phy_qsfp_intel;
- else
- hw->phy.type = txgbe_phy_qsfp_unknown;
-
- hw->mac.get_device_caps(hw, &enforce_sfp);
- if (!(enforce_sfp & TXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) {
- /* Make sure we're a supported PHY type */
- if (hw->phy.type == txgbe_phy_qsfp_intel) {
- err = 0;
- } else {
- if (hw->allow_unsupported_sfp) {
- DEBUGOUT("WARNING: Wangxun (R) Network Connections are quality tested using Wangxun (R) Ethernet Optics. "
- "Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. "
- "Wangxun Corporation is not responsible for any harm caused by using untested modules.");
- err = 0;
- } else {
- DEBUGOUT("QSFP module not supported");
- hw->phy.type =
- txgbe_phy_sfp_unsupported;
- err = TXGBE_ERR_SFP_NOT_SUPPORTED;
- }
- }
- } else {
- err = 0;
+ if (transceiver_type & TXGBE_SFF_ETHERNET_40G_LR4) {
+ if (hw->bus.lan_id == 0)
+ hw->phy.sfp_type = txgbe_qsfp_type_40g_lr_core0;
+ else
+ hw->phy.sfp_type = txgbe_qsfp_type_40g_lr_core1;
}
}
-out:
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
return err;
+
+err_read_i2c_eeprom:
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
+ hw->phy.sfp_type = txgbe_sfp_type_not_present;
+ hw->phy.id = 0;
+ hw->phy.type = txgbe_phy_unknown;
+ return TXGBE_ERR_SFP_NOT_PRESENT;
}
/**
@@ -1278,6 +1201,28 @@ s32 txgbe_read_i2c_sff8472(struct txgbe_hw *hw, u8 byte_offset,
sff8472_data);
}
+/**
+ * txgbe_read_i2c_sff8636 - Reads 8 bit word over I2C interface
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset at address 0xA2
+ * @eeprom_data: value read
+ *
+ * Performs byte read operation to SFP module's SFF-8472 data over I2C
+ **/
+s32 txgbe_read_i2c_sff8636(struct txgbe_hw *hw, u8 page, u8 byte_offset,
+ u8 *sff8636_data)
+{
+ s32 err = hw->phy.write_i2c_byte(hw, TXGBE_SFF_QSFP_PAGE_SELECT,
+ TXGBE_I2C_EEPROM_DEV_ADDR,
+ page);
+ if (err != 0)
+ return err;
+
+ return hw->phy.read_i2c_byte(hw, byte_offset,
+ TXGBE_I2C_EEPROM_DEV_ADDR,
+ sff8636_data);
+}
+
/**
* txgbe_write_i2c_eeprom - Writes 8 bit EEPROM word over I2C interface
* @hw: pointer to hardware structure
@@ -1295,7 +1240,7 @@ s32 txgbe_write_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
}
/**
- * txgbe_read_i2c_byte_unlocked - Reads 8 bit word over I2C
+ * txgbe_read_i2c_byte - Reads 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to read
* @dev_addr: address to read from
@@ -1304,7 +1249,7 @@ s32 txgbe_write_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
* Performs byte read operation to SFP module's EEPROM over I2C interface at
* a specified device address.
**/
-s32 txgbe_read_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset,
+s32 txgbe_read_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 *data)
{
txgbe_i2c_start(hw, dev_addr);
@@ -1334,30 +1279,7 @@ s32 txgbe_read_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset,
}
/**
- * txgbe_read_i2c_byte - Reads 8 bit word over I2C
- * @hw: pointer to hardware structure
- * @byte_offset: byte offset to read
- * @dev_addr: address to read from
- * @data: value read
- *
- * Performs byte read operation to SFP module's EEPROM over I2C interface at
- * a specified device address.
- **/
-s32 txgbe_read_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
- u8 dev_addr, u8 *data)
-{
- u32 swfw_mask = hw->phy.phy_semaphore_mask;
- int err = 0;
-
- if (hw->mac.acquire_swfw_sync(hw, swfw_mask))
- return TXGBE_ERR_SWFW_SYNC;
- err = txgbe_read_i2c_byte_unlocked(hw, byte_offset, dev_addr, data);
- hw->mac.release_swfw_sync(hw, swfw_mask);
- return err;
-}
-
-/**
- * txgbe_write_i2c_byte_unlocked - Writes 8 bit word over I2C
+ * txgbe_write_i2c_byte - Writes 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to write
* @dev_addr: address to write to
@@ -1366,54 +1288,29 @@ s32 txgbe_read_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
* Performs byte write operation to SFP module's EEPROM over I2C interface at
* a specified device address.
**/
-s32 txgbe_write_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset,
- u8 dev_addr, u8 data)
+s32 txgbe_write_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 data)
{
txgbe_i2c_start(hw, dev_addr);
/* wait tx empty */
if (!po32m(hw, TXGBE_I2CICR, TXGBE_I2CICR_TXEMPTY,
- TXGBE_I2CICR_TXEMPTY, NULL, 100, 100)) {
+ TXGBE_I2CICR_TXEMPTY, NULL, 100, 100))
return -TERR_TIMEOUT;
- }
- wr32(hw, TXGBE_I2CDATA, byte_offset | TXGBE_I2CDATA_STOP);
+ wr32(hw, TXGBE_I2CDATA, byte_offset);
wr32(hw, TXGBE_I2CDATA, data | TXGBE_I2CDATA_WRITE);
/* wait for write complete */
if (!po32m(hw, TXGBE_I2CICR, TXGBE_I2CICR_RXFULL,
- TXGBE_I2CICR_RXFULL, NULL, 100, 100)) {
+ TXGBE_I2CICR_RXFULL, NULL, 100, 100))
return -TERR_TIMEOUT;
- }
+
txgbe_i2c_stop(hw);
return 0;
}
-/**
- * txgbe_write_i2c_byte - Writes 8 bit word over I2C
- * @hw: pointer to hardware structure
- * @byte_offset: byte offset to write
- * @dev_addr: address to write to
- * @data: value to write
- *
- * Performs byte write operation to SFP module's EEPROM over I2C interface at
- * a specified device address.
- **/
-s32 txgbe_write_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
- u8 dev_addr, u8 data)
-{
- u32 swfw_mask = hw->phy.phy_semaphore_mask;
- int err = 0;
-
- if (hw->mac.acquire_swfw_sync(hw, swfw_mask))
- return TXGBE_ERR_SWFW_SYNC;
- err = txgbe_write_i2c_byte_unlocked(hw, byte_offset, dev_addr, data);
- hw->mac.release_swfw_sync(hw, swfw_mask);
-
- return err;
-}
-
/**
* txgbe_i2c_start - Sets I2C start condition
* @hw: pointer to hardware structure
diff --git a/drivers/net/txgbe/base/txgbe_phy.h b/drivers/net/txgbe/base/txgbe_phy.h
index 93a5ad18c1..20c80d9d88 100644
--- a/drivers/net/txgbe/base/txgbe_phy.h
+++ b/drivers/net/txgbe/base/txgbe_phy.h
@@ -261,7 +261,9 @@
#define TXGBE_SFF_SFF_8472_COMP 0x5E
#define TXGBE_SFF_SFF_8472_OSCB 0x6E
#define TXGBE_SFF_SFF_8472_ESCB 0x76
+#define TXGBE_SFF_QSFP_PAGE_SELECT 0x7F
+#define TXGBE_SFF_IDENTIFIER_QSFP 0x0C
#define TXGBE_SFF_IDENTIFIER_QSFP_PLUS 0x0D
#define TXGBE_SFF_QSFP_VENDOR_OUI_BYTE0 0xA5
#define TXGBE_SFF_QSFP_VENDOR_OUI_BYTE1 0xA6
@@ -289,6 +291,9 @@
#define TXGBE_SFF_4x10GBASESR_CAP 0x11
#define TXGBE_SFF_40GBASEPSM4_PARALLEL 0x12
#define TXGBE_SFF_40GBASE_SWMD4_CAP 0x1f
+#define TXGBE_SFF_COPPER_5M 0x5
+#define TXGBE_SFF_COPPER_3M 0x3
+#define TXGBE_SFF_COPPER_1M 0x1
#define TXGBE_SFF_DA_SPEC_ACTIVE_LIMITING 0x4
#define TXGBE_SFF_25GAUI_C2M_AOC_BER_5 0x1
@@ -296,6 +301,11 @@
#define TXGBE_SFF_25GAUI_C2M_AOC_BER_12 0x18
#define TXGBE_SFF_25GAUI_C2M_ACC_BER_12 0x19
+#define TXGBE_ETHERNET_COMP_OFFSET 0x83
+#define TXGBE_SFF_ETHERNET_40G_CR4 MS(3, 0x1)
+#define TXGBE_SFF_ETHERNET_40G_SR4 MS(2, 0x1)
+#define TXGBE_SFF_ETHERNET_40G_LR4 MS(1, 0x1)
+
#define TXGBE_SFF_SOFT_RS_SELECT_MASK 0x8
#define TXGBE_SFF_SOFT_RS_SELECT_10G 0x8
#define TXGBE_SFF_SOFT_RS_SELECT_1G 0x0
@@ -493,14 +503,12 @@ s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw);
s32 txgbe_check_overtemp(struct txgbe_hw *hw);
s32 txgbe_read_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 *data);
-s32 txgbe_read_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset,
- u8 dev_addr, u8 *data);
s32 txgbe_write_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 data);
-s32 txgbe_write_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset,
- u8 dev_addr, u8 data);
s32 txgbe_read_i2c_sff8472(struct txgbe_hw *hw, u8 byte_offset,
- u8 *sff8472_data);
+ u8 *sff8472_data);
+s32 txgbe_read_i2c_sff8636(struct txgbe_hw *hw, u8 page, u8 byte_offset,
+ u8 *sff8636_data);
s32 txgbe_read_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
u8 *eeprom_data);
s32 txgbe_write_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index 47629aa9e0..2e2d79e0e1 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -702,6 +702,8 @@ struct txgbe_phy_info {
u8 dev_addr, u8 data);
s32 (*read_i2c_sff8472)(struct txgbe_hw *hw, u8 byte_offset,
u8 *sff8472_data);
+ s32 (*read_i2c_sff8636)(struct txgbe_hw *hw, u8 page, u8 byte_offset,
+ u8 *sff8636_data);
s32 (*read_i2c_eeprom)(struct txgbe_hw *hw, u8 byte_offset,
u8 *eeprom_data);
s32 (*write_i2c_eeprom)(struct txgbe_hw *hw, u8 byte_offset,
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v7 17/21] net/txgbe: fix get module info operation
From: Zaiyu Wang @ 2026-06-17 3:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617033400.376-1-zaiyuwang@trustnetic.com>
The original I2C access flow in the module information retrieval
process was flawed. Correct the implementation to properly fetch
module info.
Fixes: abf042d32b39 ("net/txgbe: add Amber-Lite 25G/40G NICs")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_phy.h | 6 +-
drivers/net/txgbe/txgbe_ethdev.c | 118 +++++++++++++++++++++++------
2 files changed, 98 insertions(+), 26 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_phy.h b/drivers/net/txgbe/base/txgbe_phy.h
index 20c80d9d88..31bdceb35b 100644
--- a/drivers/net/txgbe/base/txgbe_phy.h
+++ b/drivers/net/txgbe/base/txgbe_phy.h
@@ -258,10 +258,14 @@
#define TXGBE_SFF_CABLE_DA_ACTIVE 0x8
#define TXGBE_SFF_CABLE_SPEC_COMP 0x3C
#define TXGBE_SFF_SFF_8472_SWAP 0x5C
+#define TXGBE_SFF_DDM_IMPLEMENTED 0x40
#define TXGBE_SFF_SFF_8472_COMP 0x5E
#define TXGBE_SFF_SFF_8472_OSCB 0x6E
#define TXGBE_SFF_SFF_8472_ESCB 0x76
-#define TXGBE_SFF_QSFP_PAGE_SELECT 0x7F
+#define TXGBE_SFF_SFF_REVISION_ADDR 0x01
+#define TXGBE_SFF_QSFP_PAGE_SELECT 0x7F
+
+#define TXGBE_MODULE_QSFP_MAX_LEN 640
#define TXGBE_SFF_IDENTIFIER_QSFP 0x0C
#define TXGBE_SFF_IDENTIFIER_QSFP_PLUS 0x0D
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index f1119cf6f8..c34635c50a 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -5348,41 +5348,109 @@ txgbe_get_module_info(struct rte_eth_dev *dev,
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
uint32_t status;
uint8_t sff8472_rev, addr_mode;
+ uint8_t identifier;
+ uint8_t sff8636_rev;
bool page_swap = false;
+ uint32_t value;
- /* Check whether we support SFF-8472 or not */
- status = hw->phy.read_i2c_eeprom(hw,
- TXGBE_SFF_SFF_8472_COMP,
- &sff8472_rev);
- if (status != 0)
- return -EIO;
+ if (hw->mac.type == txgbe_mac_aml40) {
+ value = rd32(hw, TXGBE_GPIOEXT);
+ if (value & TXGBE_SFP1_MOD_PRST_LS) {
+ PMD_DRV_LOG(WARNING, "QSFP module not present, cannot get module info.");
+ return -EINVAL;
+ }
+ }
+
+ if (hw->mac.type == txgbe_mac_aml) {
+ value = rd32(hw, TXGBE_GPIOEXT);
+ if (value & TXGBE_SFP1_MOD_ABS_LS) {
+ PMD_DRV_LOG(WARNING, "SFP module not present, cannot get module info.");
+ return -EINVAL;
+ }
+ }
- /* addressing mode is not supported */
- status = hw->phy.read_i2c_eeprom(hw,
- TXGBE_SFF_SFF_8472_SWAP,
- &addr_mode);
+ status = hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
if (status != 0)
- return -EIO;
+ return -EBUSY;
- if (addr_mode & TXGBE_SFF_ADDRESSING_MODE) {
- PMD_DRV_LOG(ERR,
- "Address change required to access page 0xA2, "
- "but not supported. Please report the module "
- "type to the driver maintainers.");
- page_swap = true;
+ if (hw->mac.type == txgbe_mac_aml40) {
+ status = hw->phy.read_i2c_sff8636(hw, 0,
+ TXGBE_SFF_IDENTIFIER,
+ &identifier);
+ } else {
+ status = hw->phy.read_i2c_eeprom(hw,
+ TXGBE_SFF_IDENTIFIER,
+ &identifier);
}
- if (sff8472_rev == TXGBE_SFF_SFF_8472_UNSUP || page_swap) {
- /* We have a SFP, but it does not support SFF-8472 */
- modinfo->type = RTE_ETH_MODULE_SFF_8079;
- modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8079_LEN;
- } else {
- /* We have a SFP which supports a revision of SFF-8472. */
- modinfo->type = RTE_ETH_MODULE_SFF_8472;
- modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8472_LEN;
+ if (status != 0)
+ goto ERROR_IO;
+
+ switch (identifier) {
+ case TXGBE_SFF_IDENTIFIER_SFP:
+ /* Check whether we support SFF-8472 or not */
+ status = hw->phy.read_i2c_eeprom(hw,
+ TXGBE_SFF_SFF_8472_COMP,
+ &sff8472_rev);
+ if (status != 0)
+ goto ERROR_IO;
+
+ /* addressing mode is not supported */
+ status = hw->phy.read_i2c_eeprom(hw,
+ TXGBE_SFF_SFF_8472_SWAP,
+ &addr_mode);
+ if (status != 0)
+ goto ERROR_IO;
+
+ if (addr_mode & TXGBE_SFF_ADDRESSING_MODE) {
+ PMD_DRV_LOG(ERR,
+ "Address change required to access page 0xA2, "
+ "but not supported. Please report the module "
+ "type to the driver maintainers.");
+ page_swap = true;
+ }
+
+ if (sff8472_rev == TXGBE_SFF_SFF_8472_UNSUP || page_swap ||
+ !(addr_mode & TXGBE_SFF_DDM_IMPLEMENTED)) {
+ /* We have a SFP, but it does not support SFF-8472 */
+ modinfo->type = RTE_ETH_MODULE_SFF_8079;
+ modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8079_LEN;
+ } else {
+ /* We have a SFP which supports a revision of SFF-8472. */
+ modinfo->type = RTE_ETH_MODULE_SFF_8472;
+ modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8472_LEN;
+ }
+ break;
+ case TXGBE_SFF_IDENTIFIER_QSFP:
+ case TXGBE_SFF_IDENTIFIER_QSFP_PLUS:
+ status = hw->phy.read_i2c_sff8636(hw, 0,
+ TXGBE_SFF_SFF_REVISION_ADDR,
+ &sff8636_rev);
+ if (status != 0)
+ goto ERROR_IO;
+ /* Check revision compliance */
+ if (sff8636_rev > 0x02) {
+ /* Module is SFF-8636 compliant */
+ modinfo->type = RTE_ETH_MODULE_SFF_8636;
+ modinfo->eeprom_len = TXGBE_MODULE_QSFP_MAX_LEN;
+ } else {
+ modinfo->type = RTE_ETH_MODULE_SFF_8436;
+ modinfo->eeprom_len = TXGBE_MODULE_QSFP_MAX_LEN;
+ }
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "SFF Module Type not recognized, identifier=0x%x", identifier);
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
+ return -EINVAL;
}
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
return 0;
+
+ERROR_IO:
+ PMD_DRV_LOG(ERR, "I2C IO ERROR.");
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
+ return -EIO;
}
static int
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v7 18/21] net/txgbe: fix get EEPROM operation
From: Zaiyu Wang @ 2026-06-17 3:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617033400.376-1-zaiyuwang@trustnetic.com>
The original I2C access flow in the module information retrieval
process was flawed. Correct the implementation to properly fetch
module info.
Fixes: abf042d32b39 ("net/txgbe: add Amber-Lite 25G/40G NICs")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_phy.h | 1 +
drivers/net/txgbe/txgbe_ethdev.c | 81 +++++++++++++++++++++++++++---
2 files changed, 76 insertions(+), 6 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_phy.h b/drivers/net/txgbe/base/txgbe_phy.h
index 31bdceb35b..a5df015a4d 100644
--- a/drivers/net/txgbe/base/txgbe_phy.h
+++ b/drivers/net/txgbe/base/txgbe_phy.h
@@ -245,6 +245,7 @@
/* EEPROM (dev_addr = 0xA0) */
#define TXGBE_I2C_EEPROM_DEV_ADDR 0xA0
#define TXGBE_SFF_IDENTIFIER 0x00
+#define TXGBE_SFF_8636_STATUS_OFFSET 0x02
#define TXGBE_SFF_IDENTIFIER_SFP 0x03
#define TXGBE_SFF_VENDOR_OUI_BYTE0 0x25
#define TXGBE_SFF_VENDOR_OUI_BYTE1 0x26
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index c34635c50a..7d431d85f5 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -5462,23 +5462,92 @@ txgbe_get_module_eeprom(struct rte_eth_dev *dev,
uint8_t databyte = 0xFF;
uint8_t *data = info->data;
uint32_t i = 0;
+ bool is_sfp = false;
+ uint32_t value;
+ uint8_t identifier = 0;
+ uint16_t offset;
+ uint8_t page = 0;
+ bool is_flat_mem = false;
+
+ if (hw->mac.type == txgbe_mac_aml40) {
+ value = rd32(hw, TXGBE_GPIOEXT);
+ if (value & TXGBE_SFP1_MOD_PRST_LS)
+ return -EIO;
+ }
+
+ if (hw->mac.type == txgbe_mac_aml) {
+ value = rd32(hw, TXGBE_GPIOEXT);
+ if (value & TXGBE_SFP1_MOD_ABS_LS)
+ return -EIO;
+ }
if (info->length == 0)
return -EINVAL;
- for (i = info->offset; i < info->offset + info->length; i++) {
- if (i < RTE_ETH_MODULE_SFF_8079_LEN)
- status = hw->phy.read_i2c_eeprom(hw, i, &databyte);
- else
- status = hw->phy.read_i2c_sff8472(hw, i, &databyte);
+ status = hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
+ if (status)
+ return -EBUSY;
+
+ status = hw->phy.read_i2c_eeprom(hw,
+ TXGBE_SFF_IDENTIFIER,
+ &identifier);
+ if (status != 0)
+ goto ERROR_IO;
+ if (identifier == TXGBE_SFF_IDENTIFIER_SFP) {
+ is_sfp = true;
+ } else {
+ uint8_t rdata = 0;
+
+ status = hw->phy.read_i2c_sff8636(hw, 0,
+ TXGBE_SFF_8636_STATUS_OFFSET,
+ &rdata);
if (status != 0)
- return -EIO;
+ goto ERROR_IO;
+ if (rdata & 0x4)
+ is_flat_mem = true;
+ }
+
+ memset(data, 0, info->length);
+
+ for (i = info->offset; i < info->offset + info->length; i++) {
+ databyte = 0;
+
+ if (is_sfp) {
+ if (i < RTE_ETH_MODULE_SFF_8079_LEN)
+ status = hw->phy.read_i2c_eeprom(hw, i,
+ &databyte);
+ else
+ status = hw->phy.read_i2c_sff8472(hw, i,
+ &databyte);
+
+ if (status != 0)
+ goto ERROR_IO;
+ } else {
+ offset = i;
+ page = 0;
+ while (offset >= RTE_ETH_MODULE_SFF_8436_LEN) {
+ offset -= RTE_ETH_MODULE_SFF_8436_LEN / 2;
+ page++;
+ }
+ if (page == 0 || !is_flat_mem) {
+ status = hw->phy.read_i2c_sff8636(hw, page, offset,
+ &databyte);
+ if (status != 0)
+ goto ERROR_IO;
+ }
+ }
data[i - info->offset] = databyte;
}
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
return 0;
+
+ERROR_IO:
+ PMD_DRV_LOG(ERR, "I2C IO ERROR.");
+ hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY);
+ return -EIO;
}
bool
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v7 19/21] net/txgbe: fix to reset Tx write-back pointer
From: Zaiyu Wang @ 2026-06-17 3:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617033400.376-1-zaiyuwang@trustnetic.com>
The write-back pointer was not reset when the Tx queue was reset. This
leads to the wrong Tx desc free logic. Move the resetting of pointer into
txq->ops->reset(txq).
Fixes: 8ada71d0bb7f ("net/txgbe: add Tx head write-back mode for Amber-Lite")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/txgbe_rxtx.c | 45 +++++++++++++----------
drivers/net/txgbe/txgbe_rxtx.h | 1 +
drivers/net/txgbe/txgbe_rxtx_vec_common.h | 7 ++++
3 files changed, 33 insertions(+), 20 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index 4611124b68..ed34b3a38c 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -2313,6 +2313,12 @@ txgbe_reset_tx_queue(struct txgbe_tx_queue *txq)
txq->tx_next_dd = (uint16_t)(txq->tx_free_thresh - 1);
txq->tx_tail = 0;
+ /* Zero out headwb_mem memory */
+ if (txq->headwb_mem) {
+ for (i = 0; i < txq->headwb_size; i++)
+ txq->headwb_mem[i] = 0;
+ }
+
/*
* Always allow 1 descriptor to be un-allocated to avoid
* a H/W race condition
@@ -2412,7 +2418,7 @@ txgbe_get_tx_port_offloads(struct rte_eth_dev *dev)
return tx_offload_capa;
}
-static int
+static void
txgbe_setup_headwb_resources(struct rte_eth_dev *dev,
void *tx_queue,
unsigned int socket_id)
@@ -2420,33 +2426,33 @@ txgbe_setup_headwb_resources(struct rte_eth_dev *dev,
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
const struct rte_memzone *headwb;
struct txgbe_tx_queue *txq = tx_queue;
- u8 i, headwb_size = 0;
+ u8 headwb_size = 0;
- if (hw->mac.type != txgbe_mac_aml && hw->mac.type != txgbe_mac_aml40) {
- txq->headwb_mem = NULL;
- return 0;
- }
+ if (hw->mac.type != txgbe_mac_aml && hw->mac.type != txgbe_mac_aml40)
+ goto out;
+
+ if (!hw->devarg.tx_headwb)
+ goto out;
- headwb_size = hw->devarg.tx_headwb_size;
+ headwb_size = txq->headwb_size;
headwb = rte_eth_dma_zone_reserve(dev, "tx_headwb_mem", txq->queue_id,
sizeof(u32) * headwb_size,
TXGBE_ALIGN, socket_id);
if (headwb == NULL) {
- DEBUGOUT("Fail to setup headwb resources: no mem");
- txgbe_tx_queue_release(txq);
- return -ENOMEM;
+ PMD_DRV_LOG(INFO,
+ "Failed to allocate headwb memory for Tx queue %u, change to SP mode",
+ txq->queue_id);
+ goto out;
}
txq->headwb = headwb;
txq->headwb_dma = TMZ_PADDR(headwb);
txq->headwb_mem = (uint32_t *)TMZ_VADDR(headwb);
+ return;
- /* Zero out headwb_mem memory */
- for (i = 0; i < headwb_size; i++)
- txq->headwb_mem[i] = 0;
-
- return 0;
+out:
+ txq->headwb_mem = NULL;
}
int __rte_cold
@@ -2542,6 +2548,7 @@ txgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
txq->offloads = offloads;
txq->ops = &def_txq_ops;
txq->tx_deferred_start = tx_conf->tx_deferred_start;
+ txq->headwb_size = hw->devarg.tx_headwb_size;
#ifdef RTE_LIB_SECURITY
txq->using_ipsec = !!(dev->data->dev_conf.txmode.offloads &
RTE_ETH_TX_OFFLOAD_SECURITY);
@@ -2577,8 +2584,7 @@ txgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
/* set up scalar TX function as appropriate */
txgbe_set_tx_function(dev, txq);
- if (hw->devarg.tx_headwb)
- err = txgbe_setup_headwb_resources(dev, txq, socket_id);
+ txgbe_setup_headwb_resources(dev, txq, socket_id);
txq->ops->reset(txq);
txq->desc_error = 0;
@@ -4755,15 +4761,14 @@ txgbe_dev_tx_init(struct rte_eth_dev *dev)
wr32(hw, TXGBE_TXRP(txq->reg_idx), 0);
wr32(hw, TXGBE_TXWP(txq->reg_idx), 0);
- if ((hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40) &&
- hw->devarg.tx_headwb) {
+ if (txq->headwb_mem) {
uint32_t txdctl;
wr32(hw, TXGBE_PX_TR_HEAD_ADDRL(txq->reg_idx),
(uint32_t)(txq->headwb_dma & BIT_MASK32));
wr32(hw, TXGBE_PX_TR_HEAD_ADDRH(txq->reg_idx),
(uint32_t)(txq->headwb_dma >> 32));
- if (hw->devarg.tx_headwb_size == 16)
+ if (txq->headwb_size == 16)
txdctl = TXGBE_PX_TR_CFG_HEAD_WB |
TXGBE_PX_TR_CFG_HEAD_WB_64BYTE;
else
diff --git a/drivers/net/txgbe/txgbe_rxtx.h b/drivers/net/txgbe/txgbe_rxtx.h
index 43c818cfbf..5d2e33a8d4 100644
--- a/drivers/net/txgbe/txgbe_rxtx.h
+++ b/drivers/net/txgbe/txgbe_rxtx.h
@@ -416,6 +416,7 @@ struct txgbe_tx_queue {
uint64_t desc_error;
bool resetting;
const struct rte_memzone *headwb;
+ uint16_t headwb_size;
uint64_t headwb_dma;
volatile uint32_t *headwb_mem;
};
diff --git a/drivers/net/txgbe/txgbe_rxtx_vec_common.h b/drivers/net/txgbe/txgbe_rxtx_vec_common.h
index 77d7ff785b..6e561aff30 100644
--- a/drivers/net/txgbe/txgbe_rxtx_vec_common.h
+++ b/drivers/net/txgbe/txgbe_rxtx_vec_common.h
@@ -252,6 +252,13 @@ _txgbe_reset_tx_queue_vec(struct txgbe_tx_queue *txq)
txq->tx_next_dd = (uint16_t)(txq->tx_free_thresh - 1);
txq->tx_tail = 0;
+
+ /* Zero out headwb_mem memory */
+ if (txq->headwb_mem) {
+ for (i = 0; i < txq->headwb_size; i++)
+ txq->headwb_mem[i] = 0;
+ }
+
/*
* Always allow 1 descriptor to be un-allocated to avoid
* a H/W race condition
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v7 20/21] net/txgbe: fix to enable Tx desc check
From: Zaiyu Wang @ 2026-06-17 3:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617033400.376-1-zaiyuwang@trustnetic.com>
Now lib security is enabled by default, and cannot be disabled if the
driver is intended to be used. So Tdm_desc_chk is always unable to enable.
Remove this restriction, and just enable the corresponding queue check.
Fixes: 0eabdfcd4af4 ("net/txgbe: enable Tx descriptor error interrupt")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/txgbe_rxtx.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index ed34b3a38c..8b277d3062 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -4761,6 +4761,12 @@ txgbe_dev_tx_init(struct rte_eth_dev *dev)
wr32(hw, TXGBE_TXRP(txq->reg_idx), 0);
wr32(hw, TXGBE_TXWP(txq->reg_idx), 0);
+#ifdef RTE_LIB_SECURITY
+ if (!txq->using_ipsec)
+#endif
+ wr32m(hw, TXGBE_TDM_DESC_CHK(txq->reg_idx / 32),
+ RTE_BIT32(txq->reg_idx % 32), RTE_BIT32(txq->reg_idx % 32));
+
if (txq->headwb_mem) {
uint32_t txdctl;
@@ -4778,11 +4784,6 @@ txgbe_dev_tx_init(struct rte_eth_dev *dev)
}
}
-#ifndef RTE_LIB_SECURITY
- for (i = 0; i < 4; i++)
- wr32(hw, TXGBE_TDM_DESC_CHK(i), 0xFFFFFFFF);
-#endif
-
/* Device configured with multiple TX queues. */
txgbe_dev_mq_tx_configure(dev);
}
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v7 21/21] net/txgbe: fix temperature track for AML NIC
From: Zaiyu Wang @ 2026-06-17 3:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617033400.376-1-zaiyuwang@trustnetic.com>
Previously, temperature tracking for the amlite NIC was handled by
firmware together with the hardware setup. However, the firmware-based
PHY configuration has proven to be unstable.
Re-add the temperature tracking function directly in the driver and
invoke it periodically to ensure the PHY remains calibrated. According
to the hardware recommendation, the tracking sequence should be run at
least every 100 ms to keep temperature drift within 5 °C. Considering
the software and hardware overhead, a 2-second interval is used as a
practical trade-off that still meets stability requirements while
minimizing performance impact.
The periodic tracking is implemented using a timer in the driver, and
the sequence itself is the same as the one originally performed during
link setup.
Fixes: fb6eb170dfa2 ("net/txgbe: add basic link configuration for Amber-Lite")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/txgbe_ethdev.c | 44 +++++++++++++++++++++++++++++++-
drivers/net/txgbe/txgbe_ethdev.h | 1 +
2 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 7d431d85f5..cc33437b88 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2011,8 +2011,10 @@ txgbe_dev_start(struct rte_eth_dev *dev)
txgbe_filter_restore(dev);
hw->bp_event_interval = 100 * 1000;
- if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40)
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40) {
rte_eal_alarm_set(hw->bp_event_interval, txgbe_dev_e56_check_bp_event, dev);
+ rte_eal_alarm_set(1000 * 1000 * 2, txgbe_dev_check_aml_temp_event, dev);
+ }
if (tm_conf->root && !tm_conf->committed)
PMD_DRV_LOG(WARNING,
@@ -2060,6 +2062,7 @@ txgbe_dev_stop(struct rte_eth_dev *dev)
if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40) {
rte_eal_alarm_cancel(txgbe_dev_e56_check_bp_event, dev);
+ rte_eal_alarm_cancel(txgbe_dev_check_aml_temp_event, dev);
rte_eal_alarm_cancel(txgbe_dev_setup_link_alarm_handler_aml, hw);
}
@@ -2932,6 +2935,45 @@ txgbe_dev_supported_ptypes_get(struct rte_eth_dev *dev, size_t *no_of_elements)
return NULL;
}
+void txgbe_dev_check_aml_temp_event(void *param)
+{
+ struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+ struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
+ uint32_t link_speed = 0, val = 0;
+ s32 status = 0;
+ int temp;
+
+ if (hw == NULL)
+ return;
+
+ status = txgbe_e56_get_temp(hw, &temp);
+ if (status)
+ temp = DEFAULT_TEMP;
+
+ if (!(temp - hw->temperature > 4 ||
+ hw->temperature - temp > 4))
+ goto out;
+
+ hw->temperature = temp;
+ val = rd32(hw, TXGBE_PORT);
+ if (val & TXGBE_AMLITE_LED_LINK_40G)
+ link_speed = TXGBE_LINK_SPEED_40GB_FULL;
+ else if (val & TXGBE_AMLITE_LED_LINK_25G)
+ link_speed = TXGBE_LINK_SPEED_25GB_FULL;
+ else
+ link_speed = TXGBE_LINK_SPEED_10GB_FULL;
+
+ rte_spinlock_lock(&hw->phy_lock);
+ if (hw->mac.type == txgbe_mac_aml)
+ txgbe_temp_track_seq(hw, link_speed);
+ else if (hw->mac.type == txgbe_mac_aml40)
+ txgbe_temp_track_seq_40g(hw, link_speed);
+ rte_spinlock_unlock(&hw->phy_lock);
+
+out:
+ rte_eal_alarm_set(1000 * 1000 * 2, txgbe_dev_check_aml_temp_event, dev);
+}
+
void txgbe_dev_e56_check_bp_event(void *param)
{
struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
diff --git a/drivers/net/txgbe/txgbe_ethdev.h b/drivers/net/txgbe/txgbe_ethdev.h
index 309db3bfe9..c32c61d8bf 100644
--- a/drivers/net/txgbe/txgbe_ethdev.h
+++ b/drivers/net/txgbe/txgbe_ethdev.h
@@ -747,5 +747,6 @@ void txgbe_vlan_hw_strip_bitmap_set(struct rte_eth_dev *dev,
uint16_t queue, bool on);
void txgbe_config_vlan_strip_on_all_queues(struct rte_eth_dev *dev,
int mask);
+void txgbe_dev_check_aml_temp_event(void *param);
void txgbe_dev_e56_check_bp_event(void *param);
#endif /* _TXGBE_ETHDEV_H_ */
--
2.21.0.windows.1
^ permalink raw reply related
* Re: [PATCH 0/2] ethdev: fix fast-path ops on a stopped port
From: fengchengwen @ 2026-06-17 4:02 UTC (permalink / raw)
To: Maxime Leroy, dev
In-Reply-To: <20260616094259.686555-1-maxime@leroys.fr>
Series-acked-by: Chengwen Feng <fengchengwen@huawei.com>
On 6/16/2026 5:42 PM, Maxime Leroy wrote:
> Two small fixes for fast-path ops on a stopped port:
> patch 1 stops rte_eth_rx_queue_count() from dereferencing NULL after a port
> stop, patch 2 makes the dummy queue count return 0 (empty queue) instead of
> -ENOTSUP.
>
> Maxime Leroy (2):
> ethdev: keep fast-path ops valid after port stop
> ethdev: return 0 from dummy queue count
>
> lib/ethdev/ethdev_driver.c | 2 +-
> lib/ethdev/ethdev_private.c | 7 +++++++
> 2 files changed, 8 insertions(+), 1 deletion(-)
>
^ permalink raw reply
* Re: [PATCH 0/6] net/dpaa2: RSS fixes and improvements
From: Hemant Agrawal @ 2026-06-17 5:33 UTC (permalink / raw)
To: Maxime Leroy, dev
In-Reply-To: <20260616104717.723087-1-maxime@leroys.fr>
[-- Attachment #1: Type: text/plain, Size: 793 bytes --]
On 16-06-2026 16:17, Maxime Leroy wrote:
> A set of RSS fixes and improvements for the dpaa2 PMD.
>
> Patches 1 and 2 fix the RSS hash key: the L4 destination port was never
> added (both extracts used the source port), and SCTP now uses the same L4
> port extraction as TCP/UDP. Both are tagged for stable.
>
> Patches 3 and 4 are small cleanups in the key builder (a dead num_extracts
> increment, and the unset PPPoE guard flag).
>
> Patch 5 honours RTE_ETH_RSS_LEVEL_INNERMOST so tunnelled traffic hashes on
> the inner IP header. Patch 6 implements reta_query / reta_update as an
> emulation over the HW distribution-size mechanism, since dpaa2 has no
> software-visible indirection table.
>
> Tested on LX2160A (lx2160acex7).
Series-
Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>
[-- Attachment #2: Type: text/html, Size: 1262 bytes --]
^ permalink raw reply
* [PATCH] common/cnxk: add bulk Rx queue enable/disable
From: Rakesh Kudurumalla @ 2026-06-17 5:49 UTC (permalink / raw)
To: Nithin Dabilpuram, Kiran Kumar K, Sunil Kumar Kori, Satha Rao,
Harman Kalra
Cc: dev, jerinj, Rakesh Kudurumalla
Add roc_nix_rq_multi_ena_dis() to batch RQ enable/disable mailbox
AQ operations and process them in a single mbox_process() call.
Skip mbox_process() when no messages were queued (e.g. all qid are
UINT16_MAX) by checking num_msgs and msg_size via mbox_nonempty_nolock().
Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
---
drivers/common/cnxk/roc_mbox_priv.h | 6 +-
drivers/common/cnxk/roc_nix.h | 2 +
drivers/common/cnxk/roc_nix_queue.c | 87 +++++++++++++++++++
.../common/cnxk/roc_platform_base_symbols.c | 1 +
4 files changed, 92 insertions(+), 4 deletions(-)
diff --git a/drivers/common/cnxk/roc_mbox_priv.h b/drivers/common/cnxk/roc_mbox_priv.h
index 354c8fa52a..e9da1959b6 100644
--- a/drivers/common/cnxk/roc_mbox_priv.h
+++ b/drivers/common/cnxk/roc_mbox_priv.h
@@ -113,14 +113,12 @@ mbox_rsp_init(uint16_t mbox_id, void *msghdr)
}
static inline bool
-mbox_nonempty(struct mbox *mbox, int devid)
+mbox_nonempty_nolock(struct mbox *mbox, int devid)
{
struct mbox_dev *mdev = &mbox->dev[devid];
bool ret;
- plt_spinlock_lock(&mdev->mbox_lock);
- ret = mdev->num_msgs != 0;
- plt_spinlock_unlock(&mdev->mbox_lock);
+ ret = mdev->num_msgs != 0 && mdev->msg_size != 0;
return ret;
}
diff --git a/drivers/common/cnxk/roc_nix.h b/drivers/common/cnxk/roc_nix.h
index 8ba8b3e0b6..f495e2a5ad 100644
--- a/drivers/common/cnxk/roc_nix.h
+++ b/drivers/common/cnxk/roc_nix.h
@@ -1094,6 +1094,8 @@ int __roc_api roc_nix_rq_modify(struct roc_nix *roc_nix, struct roc_nix_rq *rq,
bool ena);
int __roc_api roc_nix_rq_cman_config(struct roc_nix *roc_nix, struct roc_nix_rq *rq);
int __roc_api roc_nix_rq_ena_dis(struct roc_nix_rq *rq, bool enable);
+int __roc_api roc_nix_rq_multi_ena_dis(struct roc_nix *roc_nix, struct roc_nix_rq *rqs,
+ int nb_rx_queues, bool enable);
int __roc_api roc_nix_rq_is_sso_enable(struct roc_nix *roc_nix, uint32_t qid);
int __roc_api roc_nix_rq_fini(struct roc_nix_rq *rq);
int __roc_api roc_nix_cq_init(struct roc_nix *roc_nix, struct roc_nix_cq *cq);
diff --git a/drivers/common/cnxk/roc_nix_queue.c b/drivers/common/cnxk/roc_nix_queue.c
index ef9b651022..331e503e09 100644
--- a/drivers/common/cnxk/roc_nix_queue.c
+++ b/drivers/common/cnxk/roc_nix_queue.c
@@ -10,6 +10,32 @@
/* Default SQB slack per SQ */
#define ROC_NIX_SQB_SLACK_DFLT 24
+#define NIX_RQ_BULK_ENA_DIS_LOOP(REQ_TYPE, ALLOC_FN) \
+ do { \
+ for (i = 0; i < nb_rx_queues; i++) { \
+ REQ_TYPE *aq; \
+ if (rqs[i].qid == UINT16_MAX) \
+ continue; \
+ struct roc_nix_rq *rq = &rqs[i]; \
+ aq = ALLOC_FN(mbox); \
+ if (!aq) { \
+ rc = mbox_process(mbox); \
+ if (rc) \
+ goto exit; \
+ aq = ALLOC_FN(mbox); \
+ if (!aq) { \
+ rc = -ENOSPC; \
+ goto exit; \
+ } \
+ } \
+ aq->qidx = rq->qid; \
+ aq->ctype = NIX_AQ_CTYPE_RQ; \
+ aq->op = NIX_AQ_INSTOP_WRITE; \
+ aq->rq.ena = enable; \
+ aq->rq_mask.ena = ~(aq->rq_mask.ena); \
+ } \
+ } while (0)
+
static inline uint32_t
nix_qsize_to_val(enum nix_q_size qsize)
{
@@ -47,6 +73,30 @@ nix_rq_vwqe_flush(struct roc_nix_rq *rq, uint16_t vwqe_interval)
}
}
+static int
+nix_rq_bulk_ena_dis(struct nix *nix, struct roc_nix_rq *rqs, int nb_rx_queues, bool enable)
+{
+ struct mbox *mbox = mbox_get((&nix->dev)->mbox);
+ int rc = 0, i;
+
+ if (roc_model_is_cn9k())
+ NIX_RQ_BULK_ENA_DIS_LOOP(struct nix_aq_enq_req, mbox_alloc_msg_nix_aq_enq);
+
+ else if (roc_model_is_cn10k())
+ NIX_RQ_BULK_ENA_DIS_LOOP(struct nix_cn10k_aq_enq_req,
+ mbox_alloc_msg_nix_cn10k_aq_enq);
+
+ else /* CN20K */
+ NIX_RQ_BULK_ENA_DIS_LOOP(struct nix_cn20k_aq_enq_req,
+ mbox_alloc_msg_nix_cn20k_aq_enq);
+
+ if (mbox_nonempty_nolock(mbox, 0))
+ rc = mbox_process(mbox);
+exit:
+ mbox_put(mbox);
+ return rc;
+}
+
int
nix_rq_ena_dis(struct dev *dev, struct roc_nix_rq *rq, bool enable)
{
@@ -126,6 +176,43 @@ roc_nix_sq_ena_dis(struct roc_nix_sq *sq, bool enable)
return rc;
}
+int
+roc_nix_rq_multi_ena_dis(struct roc_nix *roc_nix, struct roc_nix_rq *rqs, int nb_rx_queues,
+ bool enable)
+{
+ struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+ struct roc_nix_rq *rq;
+ int rc, i;
+
+ rc = nix_rq_bulk_ena_dis(nix, rqs, nb_rx_queues, enable);
+ if (rc) {
+ plt_err("Failed to %s Rx queues rc=%d pf=%d vf=%d nb_rx_queues=%d",
+ enable ? "enable" : "disable", rc, nix->dev.pf, nix->dev.vf,
+ nb_rx_queues);
+ return rc;
+ }
+
+ for (i = 0; i < nb_rx_queues; i++) {
+ rq = &rqs[i];
+
+ if (rq->qid == UINT16_MAX)
+ continue;
+
+ nix_rq_vwqe_flush(rq, nix->vwqe_interval);
+
+ /* Check for meta aura if RQ is enabled */
+ if (enable && nix->need_meta_aura) {
+ rc = roc_nix_inl_meta_aura_check(rq->roc_nix, rq);
+ if (rc) {
+ plt_err("Failed meta aura check for rq=%u rc=%d pf=%d vf=%d",
+ rq->qid, rc, nix->dev.pf, nix->dev.vf);
+ return rc;
+ }
+ }
+ }
+ return 0;
+}
+
int
roc_nix_rq_ena_dis(struct roc_nix_rq *rq, bool enable)
{
diff --git a/drivers/common/cnxk/roc_platform_base_symbols.c b/drivers/common/cnxk/roc_platform_base_symbols.c
index ed34d4b05b..08b2f4c6f8 100644
--- a/drivers/common/cnxk/roc_platform_base_symbols.c
+++ b/drivers/common/cnxk/roc_platform_base_symbols.c
@@ -353,6 +353,7 @@ RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_ena_dis)
RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_is_sso_enable)
RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_init)
RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_modify)
+RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_multi_ena_dis)
RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_cman_config)
RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_rq_fini)
RTE_EXPORT_INTERNAL_SYMBOL(roc_nix_cq_init)
--
2.25.1
^ permalink raw reply related
* DPDK Release Status Meeting 2026-06-16
From: Mcnamara, John @ 2026-06-17 6:45 UTC (permalink / raw)
To: dev@dpdk.org; +Cc: Thomas Monjalon, David Marchand
[-- Attachment #1: Type: text/plain, Size: 2829 bytes --]
Release status meeting minutes 2026-06-16
=========================================
Agenda:
- Release Dates
- Subtrees
- Roadmaps
- LTS
- Defects
- Opens
Participants:
- Broadcom
- Debian
- Intel
- Marvell
- Nvidia
- Red Hat
- Stephen Hemminger
Release Dates
-------------
The following are the proposed working dates for 27.03:
| Date | Milestone | Description |
|-----------------|------------------|---------------------------------|
| 30 April 2026 | RFC/v1 patches | Proposal deadline |
| 11 June 2026 | 26.07-rc1 | API freeze |
| 25 June 2026 | 26.07-rc2 | PMD features freeze |
| 02 July 2026 | 26.07-rc3 | Builtin apps features freeze |
| 9 July 2026 | 26.07-rc4 | Documentation ready |
| 16 July 2026 | 26.07.0 | Release |
See https://core.dpdk.org/roadmap/
Subtrees
--------
- next-net
- 12 patches ready for main.
- 41 patches in review/waiting.
- next-net-intel
- 6 patches merged, ready for main
- Small backlog.
- next-net-mlx
- Has been pulled to main.
- next-broadcom
- No update.
- next-net-mvl
- No update.
- next-eventdev
- No update.
- next-baseband
- No update.
- next-virtio
- Working on some reported issues.
- next-crypto
- 2 patches in backlog.
- Planning to merge this week.
- next-dts
- No update.
- main
- Looking at bugzilla issue.
- Reviewing hot plug patches.
- DMA driver to review.
- Patches for BPF.
- RC1 released 11 June 2026.
Other
-----
- None.
LTS
---
See also: https://core.dpdk.org/roadmap/#stable
LTS versions ongoing/released:
- 25.11.3 - In progress.
- 24.11.7 - In progress.
- 23.11.8 - In progress.
Older releases:
- 20.11.10 - Will only be updated with CVE and critical fixes.
- 19.11.14 - Will only be updated with CVE and critical fixes.
- Distros
- Debian 13 contains DPDK v24.11
- Ubuntu 25.04 contains DPDK v24.11
- Ubuntu 24.04 LTS contains DPDK v23.11
- RHEL 9 contains DPDK 24.11
Defects
-------
- Bugzilla links, 'Bugs', added for hosted projects
- https://www.dpdk.org/hosted-projects/
DPDK Release Status Meetings
----------------------------
The DPDK Release Status Meeting is intended for DPDK Committers to discuss the
status of the main tree and sub-trees, and for project managers to track
progress or milestone dates.
The meeting occurs on every Tuesday at 14:30 DST over Jitsi on https://meet.jit.si/DPDK
You don't need an invite to join the meeting but if you want a calendar reminder just
send an email to "John McNamara <john.mcnamara@intel.com>" for the invite.
[-- Attachment #2: Type: text/html, Size: 22685 bytes --]
^ permalink raw reply
* [PATCH v8 00/21] Wangxun Fixes
From: Zaiyu Wang @ 2026-06-17 8:12 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang
In-Reply-To: <20260423034024.14404-1-zaiyuwang@trustnetic.com>
This series fixes several issues found on Wangxun Emerald, Sapphire and
Amber-lite NICs, with a focus on link-related problems.
---
v8:
- Fixed compilation error by replacing RTE_ETH_DEV_TO_PCI with RTE_CLASS_TO_BUS_DEVICE
---
v7:
- Fixed inverted semantics of is_flat_mem to match SFF8636
---
v6:
- Fixed more issues identified by AI review
---
v5:
- Fixed issues identified by AI review
---
v4:
- Fixed issues identified by devtools scripts
---
v3:
- Addressed Stephen's comments
---
v2:
- Fixed compilation error and code style issues
---
Zaiyu Wang (21):
net/txgbe: remove duplicate xstats counters
net/ngbe: remove duplicate xstats counters
net/ngbe: add missing CDR config for YT PHY
net/ngbe: fix VF promiscuous and allmulticast
net/txgbe: fix inaccuracy in Tx rate limiting
net/txgbe: fix link status check condition
net/txgbe: fix Tx desc free logic
net/txgbe: fix link flow control registers for Amber-Lite
net/txgbe: fix link flow control config for Sapphire
net/txgbe: fix a mass of unknown interrupts
net/txgbe: fix traffic class priority configuration
net/txgbe: fix link stability for 25G NIC
net/txgbe: fix link stability for 40G NIC
net/txgbe: fix link stability for Amber-Lite backplane mode
net/txgbe: fix FEC mode configuration on 25G NIC
net/txgbe: fix SFP module identification
net/txgbe: fix get module info operation
net/txgbe: fix get EEPROM operation
net/txgbe: fix to reset Tx write-back pointer
net/txgbe: fix to enable Tx desc check
net/txgbe: fix temperature track for AML NIC
drivers/net/ngbe/base/ngbe_phy_yt.c | 3 +
drivers/net/ngbe/ngbe_ethdev.c | 5 -
drivers/net/ngbe/ngbe_ethdev_vf.c | 11 +-
drivers/net/txgbe/base/meson.build | 2 +
drivers/net/txgbe/base/txgbe.h | 2 +
drivers/net/txgbe/base/txgbe_aml.c | 185 +-
drivers/net/txgbe/base/txgbe_aml.h | 6 +-
drivers/net/txgbe/base/txgbe_aml40.c | 114 +-
drivers/net/txgbe/base/txgbe_aml40.h | 6 +-
drivers/net/txgbe/base/txgbe_dcb_hw.c | 2 +-
drivers/net/txgbe/base/txgbe_e56.c | 3773 +++++++++++++++++++++
drivers/net/txgbe/base/txgbe_e56.h | 1753 ++++++++++
drivers/net/txgbe/base/txgbe_e56_bp.c | 2597 ++++++++++++++
drivers/net/txgbe/base/txgbe_e56_bp.h | 282 ++
drivers/net/txgbe/base/txgbe_hw.c | 54 +-
drivers/net/txgbe/base/txgbe_hw.h | 4 +-
drivers/net/txgbe/base/txgbe_osdep.h | 4 +
drivers/net/txgbe/base/txgbe_phy.c | 362 +-
drivers/net/txgbe/base/txgbe_phy.h | 46 +-
drivers/net/txgbe/base/txgbe_regs.h | 13 +-
drivers/net/txgbe/base/txgbe_type.h | 43 +-
drivers/net/txgbe/txgbe_ethdev.c | 472 ++-
drivers/net/txgbe/txgbe_ethdev.h | 7 +-
drivers/net/txgbe/txgbe_rxtx.c | 109 +-
drivers/net/txgbe/txgbe_rxtx.h | 36 +
drivers/net/txgbe/txgbe_rxtx_vec_common.h | 17 +-
26 files changed, 9464 insertions(+), 444 deletions(-)
create mode 100644 drivers/net/txgbe/base/txgbe_e56.c
create mode 100644 drivers/net/txgbe/base/txgbe_e56.h
create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.c
create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.h
--
2.21.0.windows.1
^ permalink raw reply
* [PATCH v8 02/21] net/ngbe: remove duplicate xstats counters
From: Zaiyu Wang @ 2026-06-17 8:12 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617081309.19124-1-zaiyuwang@trustnetic.com>
Remove four redundant counters (tx_xon_packets, rx_xon_packets,
tx_xoff_packets and rx_xoff_packets) from xstats, as they were duplicates
of tx_flow_control_xon_packets and others. Both sets were reading the same
registers but being output twice under different names. After removing
these entries, the flow control counters in DPDK now align with those in
our Linux kernel driver.
Fixes: 8b433d04adc9 ("net/ngbe: support device xstats")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/ngbe/ngbe_ethdev.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/net/ngbe/ngbe_ethdev.c b/drivers/net/ngbe/ngbe_ethdev.c
index f7b4a8b159..09bcd791ed 100644
--- a/drivers/net/ngbe/ngbe_ethdev.c
+++ b/drivers/net/ngbe/ngbe_ethdev.c
@@ -227,11 +227,6 @@ static const struct rte_ngbe_xstats_name_off rte_ngbe_stats_strings[] = {
HW_XSTAT(tx_size_1024_to_max_packets),
/* Flow Control */
- HW_XSTAT(tx_xon_packets),
- HW_XSTAT(rx_xon_packets),
- HW_XSTAT(tx_xoff_packets),
- HW_XSTAT(rx_xoff_packets),
-
HW_XSTAT_NAME(tx_xon_packets, "tx_flow_control_xon_packets"),
HW_XSTAT_NAME(rx_xon_packets, "rx_flow_control_xon_packets"),
HW_XSTAT_NAME(tx_xoff_packets, "tx_flow_control_xoff_packets"),
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v8 01/21] net/txgbe: remove duplicate xstats counters
From: Zaiyu Wang @ 2026-06-17 8:12 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu, Ferruh Yigit
In-Reply-To: <20260617081309.19124-1-zaiyuwang@trustnetic.com>
Remove four redundant counters (tx_xon_packets, rx_xon_packets,
tx_xoff_packets and rx_xoff_packets) from xstats, as they were duplicates
of tx_flow_control_xon_packets and others. Both sets were reading the same
registers but being output twice under different names. After removing
these entries, the flow control counters in DPDK now align with those in
our Linux kernel driver.
Fixes: 91fe49c87d76 ("net/txgbe: support device xstats")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/txgbe_ethdev.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 0f484dfe91..77870f3aee 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -261,11 +261,6 @@ static const struct rte_txgbe_xstats_name_off rte_txgbe_stats_strings[] = {
HW_XSTAT(tx_size_1024_to_max_packets),
/* Flow Control */
- HW_XSTAT(tx_xon_packets),
- HW_XSTAT(rx_xon_packets),
- HW_XSTAT(tx_xoff_packets),
- HW_XSTAT(rx_xoff_packets),
-
HW_XSTAT_NAME(tx_xon_packets, "tx_flow_control_xon_packets"),
HW_XSTAT_NAME(rx_xon_packets, "rx_flow_control_xon_packets"),
HW_XSTAT_NAME(tx_xoff_packets, "tx_flow_control_xoff_packets"),
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v8 03/21] net/ngbe: add missing CDR config for YT PHY
From: Zaiyu Wang @ 2026-06-17 8:12 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617081309.19124-1-zaiyuwang@trustnetic.com>
According to the PHY vendor, when YT8531S operates in UTP-to-Fiber or
RGMII-to-Fiber mode with auto-negotiation disabled (Force mode),
additional CDR (Clock Data Recovery) configuration is required to
improve link connectivity. Without this config, link may be unstable
or fail to establish.
Fixes: f1268369403d ("net/ngbe: support autoneg on/off for external PHY SFI mode")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/ngbe/base/ngbe_phy_yt.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/ngbe/base/ngbe_phy_yt.c b/drivers/net/ngbe/base/ngbe_phy_yt.c
index d110fbc8b2..ab0778d246 100644
--- a/drivers/net/ngbe/base/ngbe_phy_yt.c
+++ b/drivers/net/ngbe/base/ngbe_phy_yt.c
@@ -264,6 +264,9 @@ s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed,
value = YT_BCR_RESET | YT_BCR_ANE | YT_BCR_RESTART_AN |
YT_BCR_DUPLEX | YT_BCR_SPEED_SELECT1;
} else {
+ /* force mode need to config cdr */
+ ngbe_write_phy_reg_sds_ext_yt(hw, 0x3, 0, 0x1434);
+ ngbe_write_phy_reg_sds_ext_yt(hw, 0xe, 0, 0x163);
value = YT_BCR_RESET | YT_BCR_DUPLEX;
if (speed & NGBE_LINK_SPEED_1GB_FULL)
value |= YT_BCR_SPEED_SELECT1;
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v8 04/21] net/ngbe: fix VF promiscuous and allmulticast
From: Zaiyu Wang @ 2026-06-17 8:12 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617081309.19124-1-zaiyuwang@trustnetic.com>
The configuration of allmulti and promiscuous modes conflicts
together. For instance, if we enable promiscuous mode, then enable and
disable allmulti, then the promiscuous mode is wrongly disabled.
To resolve this, the following changes are made:
- do nothing when we set/unset allmulti if promiscuous mode is on
- restore the proper mode (none or allmulti) when we disable
promiscuous mode
Fixes: 7744e90805b5 ("net/ngbe: add promiscuous and allmulticast ops for VF device")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/ngbe/ngbe_ethdev_vf.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ngbe/ngbe_ethdev_vf.c b/drivers/net/ngbe/ngbe_ethdev_vf.c
index ea3a988df6..c440e02369 100644
--- a/drivers/net/ngbe/ngbe_ethdev_vf.c
+++ b/drivers/net/ngbe/ngbe_ethdev_vf.c
@@ -1196,9 +1196,13 @@ static int
ngbevf_dev_promiscuous_disable(struct rte_eth_dev *dev)
{
struct ngbe_hw *hw = ngbe_dev_hw(dev);
+ int mode = NGBEVF_XCAST_MODE_NONE;
int ret;
- switch (hw->mac.update_xcast_mode(hw, NGBEVF_XCAST_MODE_NONE)) {
+ if (dev->data->all_multicast)
+ mode = NGBEVF_XCAST_MODE_ALLMULTI;
+
+ switch (hw->mac.update_xcast_mode(hw, mode)) {
case 0:
ret = 0;
break;
@@ -1219,7 +1223,7 @@ ngbevf_dev_allmulticast_enable(struct rte_eth_dev *dev)
struct ngbe_hw *hw = ngbe_dev_hw(dev);
int ret;
- if (dev->data->promiscuous == 1)
+ if (dev->data->promiscuous)
return 0;
switch (hw->mac.update_xcast_mode(hw, NGBEVF_XCAST_MODE_ALLMULTI)) {
@@ -1243,6 +1247,9 @@ ngbevf_dev_allmulticast_disable(struct rte_eth_dev *dev)
struct ngbe_hw *hw = ngbe_dev_hw(dev);
int ret;
+ if (dev->data->promiscuous)
+ return 0;
+
switch (hw->mac.update_xcast_mode(hw, NGBEVF_XCAST_MODE_MULTI)) {
case 0:
ret = 0;
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v8 05/21] net/txgbe: fix inaccuracy in Tx rate limiting
From: Zaiyu Wang @ 2026-06-17 8:12 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617081309.19124-1-zaiyuwang@trustnetic.com>
Amber-lite NIC's TX rate limiting has large deviations for small
packets. To address this, the following changes are made:
1. Set TDM_RL_ADJ (0x1820c) to 21B (includes 7B Ethernet preamble,
1B SFD, 1B EFD, and 12B IPG).
2) Remove the rate offset in the driver (e.g., 105 / 100, a rough
compensation value from Linux kernel driver tests).
After these changes, accuracy deviation for 64B packets is within
~5%, while large packets show lower deviation.
Fixes: a309ab43acf3 ("net/txgbe: support Tx queue rate limiting for Amber-Lite")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_regs.h | 3 +++
drivers/net/txgbe/txgbe_ethdev.c | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/txgbe/base/txgbe_regs.h b/drivers/net/txgbe/base/txgbe_regs.h
index 95c585a025..3d1bc88430 100644
--- a/drivers/net/txgbe/base/txgbe_regs.h
+++ b/drivers/net/txgbe/base/txgbe_regs.h
@@ -1670,6 +1670,9 @@ enum txgbe_5tuple_protocol {
#define TXGBE_TDM_FACTOR_INT_SHIFT 16
#define TXGBE_TDM_FACTOR_FRA_SHIFT 2
+#define TXGBE_TDM_RL_ADJ 0x1820C
+ /* Ethernet framing overhead: 7B Ethernet preamble + 1B SFD + 1B EFD + 12B IPG */
+#define TXGBE_FRAME_OVERHEAD 21
#define TXGBE_TDM_RL_VM_IDX 0x018218
#define TXGBE_TDM_RL_VM_CFG 0x01821C
#define TXGBE_TDM_RL_CFG 0x018400
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 77870f3aee..c97a7f1a4e 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -4314,7 +4314,6 @@ txgbe_set_queue_rate_limit(struct rte_eth_dev *dev,
u16 frac;
link_speed = dev->data->dev_link.link_speed;
- tx_rate = tx_rate * 105 / 100;
/* Calculate the rate factor values to set */
factor_int = link_speed / tx_rate;
frac = (link_speed % tx_rate) * 10000 / tx_rate;
@@ -4324,6 +4323,7 @@ txgbe_set_queue_rate_limit(struct rte_eth_dev *dev,
factor_fra = 0;
}
+ wr32(hw, TXGBE_TDM_RL_ADJ, TXGBE_FRAME_OVERHEAD);
wr32(hw, TXGBE_TDM_RL_QUEUE_IDX, queue_idx);
wr32m(hw, TXGBE_TDM_RL_QUEUE_CFG,
TXGBE_TDM_FACTOR_INT_MASK, factor_int << TXGBE_TDM_FACTOR_INT_SHIFT);
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v8 06/21] net/txgbe: fix link status check condition
From: Zaiyu Wang @ 2026-06-17 8:12 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617081309.19124-1-zaiyuwang@trustnetic.com>
The original code incorrectly used 'if (link_up)' instead of
'if (*link_up)', causing the condition to always evaluate to true
because the pointer itself is non-NULL. This led to incorrect speed
assignment.
Fixes: fb6eb170dfa2 ("net/txgbe: add basic link configuration for Amber-Lite")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_aml.c | 2 +-
drivers/net/txgbe/base/txgbe_aml40.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_aml.c b/drivers/net/txgbe/base/txgbe_aml.c
index b376eca5b5..de9a1b1c93 100644
--- a/drivers/net/txgbe/base/txgbe_aml.c
+++ b/drivers/net/txgbe/base/txgbe_aml.c
@@ -67,7 +67,7 @@ s32 txgbe_check_mac_link_aml(struct txgbe_hw *hw, u32 *speed,
*link_up = false;
}
- if (link_up) {
+ if (*link_up) {
switch (links_reg & TXGBE_CFG_PORT_ST_AML_LINK_MASK) {
case TXGBE_CFG_PORT_ST_AML_LINK_25G:
*speed = TXGBE_LINK_SPEED_25GB_FULL;
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 733bbac13a..eefd7119fd 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -68,7 +68,7 @@ s32 txgbe_check_mac_link_aml40(struct txgbe_hw *hw, u32 *speed,
*link_up = false;
}
- if (link_up) {
+ if (*link_up) {
if ((links_reg & TXGBE_CFG_PORT_ST_AML_LINK_40G) ==
TXGBE_CFG_PORT_ST_AML_LINK_40G)
*speed = TXGBE_LINK_SPEED_40GB_FULL;
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v8 07/21] net/txgbe: fix Tx desc free logic
From: Zaiyu Wang @ 2026-06-17 8:12 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617081309.19124-1-zaiyuwang@trustnetic.com>
On some server environments, this driver caused TDM non-fatal errors
or PCIe request errors during Tx operation
In Amber-Lite NIC's Tx head write-back mode, the hardware periodically
writes back a head index pointing to the next descriptor it is adout
to process in Tx ring. All descriptors before the head are considered
processed by hardware and can be safely freed by the driver.
The root cause is that the driver can safely free a batch of descriptors
only when the hardware's write-back head pointer has advanced beyond all
descriptors in that batch, meaning they have all been processed by the
hardware. If the driver frees a descriptor before the hardware has
finished processing it, invalid memory access may occur, leading to the
observed bug.
To fix the issue, correct the boundary check in all three Tx cleanup
functions, each of which was missing the proper condition to prevent
freeing unprocessed descriptors.
Fixes: 8ada71d0bb7f ("net/txgbe: add Tx head write-back mode for Amber-Lite")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/txgbe_rxtx.c | 16 +++++------
drivers/net/txgbe/txgbe_rxtx.h | 35 +++++++++++++++++++++++
drivers/net/txgbe/txgbe_rxtx_vec_common.h | 10 +++----
3 files changed, 48 insertions(+), 13 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index e2cd9b8841..d6efb3b8cc 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -98,12 +98,11 @@ txgbe_tx_free_bufs(struct txgbe_tx_queue *txq)
if (tx_last_dd >= txq->nb_tx_desc)
tx_last_dd -= txq->nb_tx_desc;
- volatile uint16_t head = (uint16_t)*txq->headwb_mem;
+ uint32_t h = rte_atomic_load_explicit(txq->headwb_mem,
+ rte_memory_order_acquire);
+ const uint16_t head = (uint16_t)h;
- if (txq->tx_next_dd > head && head > tx_last_dd)
- return 0;
- else if (tx_last_dd > txq->tx_next_dd &&
- (head > tx_last_dd || head < txq->tx_next_dd))
+ if (!txgbe_tx_headwb_desc_done(head, tx_last_dd, txq->tx_next_dd))
return 0;
} else {
/* check DD bit on threshold descriptor */
@@ -645,12 +644,13 @@ txgbe_xmit_cleanup(struct txgbe_tx_queue *txq)
status = txr[desc_to_clean_to].dw3;
if (txq->headwb_mem) {
- u32 head = *txq->headwb_mem;
+ uint32_t h = rte_atomic_load_explicit(txq->headwb_mem,
+ rte_memory_order_acquire);
+ const uint16_t head = (uint16_t)h;
PMD_TX_FREE_LOG(DEBUG, "queue[%02d]: headwb_mem = %03d, desc_to_clean_to = %03d",
txq->reg_idx, head, desc_to_clean_to);
- /* we have caught up to head, no work left to do */
- if (desc_to_clean_to == head)
+ if (!txgbe_tx_headwb_desc_done(head, last_desc_cleaned, desc_to_clean_to))
return -(1);
} else {
if (!(status & rte_cpu_to_le_32(TXGBE_TXD_DD))) {
diff --git a/drivers/net/txgbe/txgbe_rxtx.h b/drivers/net/txgbe/txgbe_rxtx.h
index 02e2617cce..43c818cfbf 100644
--- a/drivers/net/txgbe/txgbe_rxtx.h
+++ b/drivers/net/txgbe/txgbe_rxtx.h
@@ -426,6 +426,41 @@ struct txgbe_txq_ops {
void (*reset)(struct txgbe_tx_queue *txq);
};
+/**
+ * Check whether Tx descriptors in the range (last, next] are done
+ * in Tx head write-back mode.
+ *
+ * In head write-back mode, the hardware periodically updates *headwb_mem
+ * with the index of the next descriptor it will process.
+ * All descriptors before the head are considered processed by hardware and can
+ * be safely freed. The descriptor pointed to by head itself is not yet processed.
+ *
+ * @param head
+ * Current hardware head index read from headwb_mem.
+ * @param last
+ * The highest-index descriptor cleaned in the previous round
+ * (exclusive: descriptors at or before this index are already freed).
+ * @param next
+ * The highest-index descriptor to be cleaned in this round
+ * (inclusive: this descriptor is the target of the current cleanup).
+ * @return
+ * true if all descriptors in the range (last, next] have been completed
+ * by hardware and can be freed, false otherwise.
+ */
+static inline bool
+txgbe_tx_headwb_desc_done(uint16_t head, uint16_t last, uint16_t next)
+{
+ if (next == head)
+ return false;
+ else if (next > head && head > last)
+ return false;
+ /* wrap case */
+ else if (last > next && (head > last || head < next))
+ return false;
+
+ return true;
+}
+
/* Takes an ethdev and a queue and sets up the tx function to be used based on
* the queue parameters. Used in tx_queue_setup by primary process and then
* in dev_init by secondary process when attaching to an existing ethdev.
diff --git a/drivers/net/txgbe/txgbe_rxtx_vec_common.h b/drivers/net/txgbe/txgbe_rxtx_vec_common.h
index 00847d087b..77d7ff785b 100644
--- a/drivers/net/txgbe/txgbe_rxtx_vec_common.h
+++ b/drivers/net/txgbe/txgbe_rxtx_vec_common.h
@@ -94,11 +94,11 @@ txgbe_tx_free_bufs(struct txgbe_tx_queue *txq)
txq->tx_next_dd - txq->tx_free_thresh;
if (tx_last_dd >= txq->nb_tx_desc)
tx_last_dd -= txq->nb_tx_desc;
- volatile uint16_t head = (uint16_t)*txq->headwb_mem;
- if (txq->tx_next_dd > head && head > tx_last_dd)
- return 0;
- else if (tx_last_dd > txq->tx_next_dd &&
- (head > tx_last_dd || head < txq->tx_next_dd))
+ uint32_t h = rte_atomic_load_explicit(txq->headwb_mem,
+ rte_memory_order_acquire);
+ const uint16_t head = (uint16_t)h;
+
+ if (!txgbe_tx_headwb_desc_done(head, tx_last_dd, txq->tx_next_dd))
return 0;
} else {
/* check DD bit on threshold descriptor */
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v8 08/21] net/txgbe: fix link flow control registers for Amber-Lite
From: Zaiyu Wang @ 2026-06-17 8:12 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260617081309.19124-1-zaiyuwang@trustnetic.com>
The flow control counter registers on AML NICs differ from those on SP
NICs. Update the register offsets accordingly to ensure the counters
work correctly.
Fixes: fb6eb170dfa2 ("net/txgbe: add basic link configuration for Amber-Lite")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_hw.c | 7 ++++++
drivers/net/txgbe/base/txgbe_regs.h | 2 ++
drivers/net/txgbe/base/txgbe_type.h | 4 ++++
drivers/net/txgbe/txgbe_ethdev.c | 34 +++++++++++++++++++----------
4 files changed, 36 insertions(+), 11 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index 0f3db3a1ad..0d3310e15c 100644
--- a/drivers/net/txgbe/base/txgbe_hw.c
+++ b/drivers/net/txgbe/base/txgbe_hw.c
@@ -394,6 +394,13 @@ s32 txgbe_clear_hw_cntrs(struct txgbe_hw *hw)
rd32(hw, TXGBE_PBTXLNKXON);
rd32(hw, TXGBE_PBTXLNKXOFF);
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40) {
+ wr32(hw, TXGBE_PBRXLNKXON_AML, 0);
+ wr32(hw, TXGBE_PBRXLNKXOFF_AML, 0);
+ hw->last_stats.rx_xon_packets = 0;
+ hw->last_stats.rx_xoff_packets = 0;
+ }
+
/* DMA Stats */
rd32(hw, TXGBE_DMARXPKT);
rd32(hw, TXGBE_DMATXPKT);
diff --git a/drivers/net/txgbe/base/txgbe_regs.h b/drivers/net/txgbe/base/txgbe_regs.h
index 3d1bc88430..22c46e3d56 100644
--- a/drivers/net/txgbe/base/txgbe_regs.h
+++ b/drivers/net/txgbe/base/txgbe_regs.h
@@ -1085,6 +1085,8 @@ enum txgbe_5tuple_protocol {
#define TXGBE_PBRXDROP 0x019068
#define TXGBE_PBRXLNKXOFF 0x011988
#define TXGBE_PBRXLNKXON 0x011E0C
+#define TXGBE_PBRXLNKXOFF_AML 0x011F80
+#define TXGBE_PBRXLNKXON_AML 0x011F84
#define TXGBE_PBRXUPXON(up) (0x011E30 + (up) * 4)
#define TXGBE_PBRXUPXOFF(up) (0x011E10 + (up) * 4)
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index ede780321f..505f598fb7 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -876,6 +876,10 @@ struct txgbe_hw {
u64 tx_qp_bytes;
u64 rx_qp_mc_packets;
} qp_last[TXGBE_MAX_QP];
+ struct {
+ u64 rx_xon_packets;
+ u64 rx_xoff_packets;
+ } last_stats;
rte_spinlock_t phy_lock;
/*amlite: new SW-FW mbox */
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index c97a7f1a4e..94ac89c7f6 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2264,16 +2264,18 @@ txgbe_dev_reset(struct rte_eth_dev *dev)
return ret;
}
+#define TXGBE_UPDATE_COUNTER_32BIT_GENERIC(reg, last, count, reset) \
+ do { \
+ uint32_t current = rd32(hw, reg); \
+ if ((current) < (last)) \
+ current += 0x100000000ULL; \
+ if (reset) \
+ (last) = current; \
+ (count) = (uint32_t)((current) - (last)); \
+ } while (0)
+
#define UPDATE_QP_COUNTER_32bit(reg, last_counter, counter) \
- { \
- uint32_t current_counter = rd32(hw, reg); \
- if (current_counter < last_counter) \
- current_counter += 0x100000000LL; \
- if (!hw->offset_loaded) \
- last_counter = current_counter; \
- counter = current_counter - last_counter; \
- counter &= 0xFFFFFFFFLL; \
- }
+ TXGBE_UPDATE_COUNTER_32BIT_GENERIC(reg, last_counter, counter, !hw->offset_loaded)
#define UPDATE_QP_COUNTER_36bit(reg_lsb, reg_msb, last_counter, counter) \
{ \
@@ -2331,8 +2333,18 @@ txgbe_read_stats_registers(struct txgbe_hw *hw,
hw_stats->up[i].rx_up_dropped +=
rd32(hw, TXGBE_PBRXMISS(i));
}
- hw_stats->rx_xon_packets += rd32(hw, TXGBE_PBRXLNKXON);
- hw_stats->rx_xoff_packets += rd32(hw, TXGBE_PBRXLNKXOFF);
+
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40) {
+ TXGBE_UPDATE_COUNTER_32BIT_GENERIC(TXGBE_PBRXLNKXON_AML,
+ hw->last_stats.rx_xon_packets,
+ hw_stats->rx_xon_packets, !hw->offset_loaded);
+ TXGBE_UPDATE_COUNTER_32BIT_GENERIC(TXGBE_PBRXLNKXOFF_AML,
+ hw->last_stats.rx_xoff_packets,
+ hw_stats->rx_xoff_packets, !hw->offset_loaded);
+ } else {
+ hw_stats->rx_xon_packets += rd32(hw, TXGBE_PBRXLNKXON);
+ hw_stats->rx_xoff_packets += rd32(hw, TXGBE_PBRXLNKXOFF);
+ }
hw_stats->tx_xon_packets += rd32(hw, TXGBE_PBTXLNKXON);
hw_stats->tx_xoff_packets += rd32(hw, TXGBE_PBTXLNKXOFF);
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v8 09/21] net/txgbe: fix link flow control config for Sapphire
From: Zaiyu Wang @ 2026-06-17 8:12 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu, Ferruh Yigit
In-Reply-To: <20260617081309.19124-1-zaiyuwang@trustnetic.com>
SP chips have a hardware bug preventing XON flow control support,
so the driver disables it.
Fixes: 69ce8c8a4ce3 ("net/txgbe: support flow control")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_hw.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index 0d3310e15c..db45c5c0ef 100644
--- a/drivers/net/txgbe/base/txgbe_hw.c
+++ b/drivers/net/txgbe/base/txgbe_hw.c
@@ -1037,8 +1037,10 @@ s32 txgbe_fc_enable(struct txgbe_hw *hw)
for (i = 0; i < TXGBE_DCB_TC_MAX; i++) {
if ((hw->fc.current_mode & txgbe_fc_tx_pause) &&
hw->fc.high_water[i]) {
- fcrtl = TXGBE_FCWTRLO_TH(hw->fc.low_water[i]) |
- TXGBE_FCWTRLO_XON;
+ fcrtl = TXGBE_FCWTRLO_TH(hw->fc.low_water[i]);
+ /* Only AML support XON */
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40)
+ fcrtl |= TXGBE_FCWTRLO_XON;
fcrth = TXGBE_FCWTRHI_TH(hw->fc.high_water[i]) |
TXGBE_FCWTRHI_XOFF;
} else {
--
2.21.0.windows.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox