Backplane CR/KR link training on the E56 PHY is unreliable and does
not recover after a link event: the completion poll can block for a
second on a condition that never triggers, the page exchange is only
run once and its result is assumed to stay valid, and the FFE init
mode and calibration ordering are also wrong.
- Poll the AN FSM (0x78010, value 0x9) for CL72 completion with a
1 ms step and a 400 ms budget, replacing the ephy 0x163c mask-0xe
poll that tested the wrong condition; the per-lane TX-FFE dumps
move into txgbe_e56_get_txffe(), called once AN completes.
- Re-run the page exchange on every AN next-page interrupt from the
event handler (50 x 1 ms poll, explicit next-page handshake,
-ETIMEDOUT on expiry) and only enter training after it succeeds;
the inline exchange in the AN73 flow is removed and a CL72 failure
no longer aborts the flow, so every link event re-runs the
exchange instead of assuming the previous one is still valid.
- Initialize the FFE init mode bits in cfg_40g()/cfg_10g(), run
txgbe_e56_set_rxs_ufine_le_max() after the RXS osc init, and write
0x78001 = 0x7 in the AN programming sequence.
- Clear hw->bp_link_mode in txgbe_set_link_to_sfi() so a port that
trained on the backplane does not keep a stale backplane mode
after switching to SFI.
Fixes: 234ce0d1fa9d ("net/txgbe: fix link stability for Amber-Lite backplane
mode")
Cc: [email protected]
Signed-off-by: Zaiyu Wang <[email protected]>
---
drivers/net/txgbe/base/txgbe_e56.c | 3 +
drivers/net/txgbe/base/txgbe_e56.h | 1 +
drivers/net/txgbe/base/txgbe_e56_bp.c | 161 +++++++++++++++-----------
drivers/net/txgbe/base/txgbe_e56_bp.h | 2 +
drivers/net/txgbe/base/txgbe_phy.c | 3 +
drivers/net/txgbe/txgbe_ethdev.c | 28 ++++-
6 files changed, 129 insertions(+), 69 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_e56.c
b/drivers/net/txgbe/base/txgbe_e56.c
index 2711863f2c..8e986daf96 100644
--- a/drivers/net/txgbe/base/txgbe_e56.c
+++ b/drivers/net/txgbe/base/txgbe_e56.c
@@ -551,6 +551,7 @@ u32 txgbe_e56_cfg_40g(struct txgbe_hw *hw)
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_0, 0x2);
set_fields_e56(&rdata,
E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2, 0x2);
wr32_ephy(hw, addr, rdata);
@@ -1377,6 +1378,8 @@ txgbe_e56_cfg_10g(struct txgbe_hw *hw)
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_0,
+ 0x2);
set_fields_e56(&rdata,
E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_2,
0x2);
wr32_ephy(hw, addr, rdata);
diff --git a/drivers/net/txgbe/base/txgbe_e56.h
b/drivers/net/txgbe/base/txgbe_e56.h
index fe9a83ae01..32d95b61b9 100644
--- a/drivers/net/txgbe/base/txgbe_e56.h
+++ b/drivers/net/txgbe/base/txgbe_e56.h
@@ -435,6 +435,7 @@ typedef union {
#define E56PHY_KRT_TFSM_CFGKRT_TFSM_HOLDOFF_TIMER_X256K 23, 16
#define E56PHY_FETX_FFE_TRAIN_CFG_0_ADDR (E56PHY_PMD_BASE_ADDR + 0x2BC)
+#define E56PHY_FETX_FFE_TRAIN_CFG_0_KRT_FETX_INIT_FFE_CFG_0 1, 0
#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
diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.c
b/drivers/net/txgbe/base/txgbe_e56_bp.c
index d376d918df..f840e6b5dd 100644
--- a/drivers/net/txgbe/base/txgbe_e56_bp.c
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.c
@@ -813,6 +813,7 @@ static int txgbe_e56_phy_rxs_calib_adapt_seq(struct
txgbe_hw *hw,
status |= txgbe_e56_ctle_bypass_seq(hw, bp_link_mode);
status |= txgbe_e56_rxs_osc_init_for_temp_track_range(hw, bp_link_mode);
+ txgbe_e56_set_rxs_ufine_le_max(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");
@@ -2123,6 +2124,7 @@ int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
set_fields_e56(&rdata, 12, 12, 0x1);
wr32_epcs(hw, 0x070000, rdata);
wr32_epcs(hw, 0x078002, 0x0000);
+ wr32_epcs(hw, 0x78001, 0x7);
/* pcs case fec en to work around first */
wr32_epcs(hw, 0x100ab, 1);
@@ -2351,24 +2353,29 @@ static int chk_bkp_ability(struct txgbe_hw *hw,
return 0;
}
-static int txgbe_e56_exchange_page(struct txgbe_hw *hw)
+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;
+ int count = 0, count2 = 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++) {
+ /* 50ms timeout */
+ for (count = 0; count < 50; count++) {
u32 fsm = rd32_epcs(hw, 0x78010);
- u32 rdata = rd32_epcs(hw, 0x78002);
+ u32 next_page = 0;
+ u32 rdata;
+
+ count2++;
BP_LOG("-----count----- %d - fsm: %x\n", count, fsm);
- BP_LOG("read 78002 data %0x and clear pacv\n", rdata);
+ rdata = rd32_epcs(hw, 0x78002);
+ /* clear an pacv int */
an_int = rdata;
+ BP_LOG("read 78002 data %0x and clear pacv\n", rdata);
set_fields_e56(&rdata, 2, 2, 0x0);
wr32_epcs(hw, 0x78002, rdata);
if (an_int & VR_AN_INTR_PG_RCV) {
@@ -2383,31 +2390,84 @@ static int txgbe_e56_exchange_page(struct txgbe_hw *hw)
wr32_epcs(hw, 0x70016, 0x2001);
BP_LOG("write 70016 0x%0x\n",
0x2001);
+ next_page = 1;
+ count = 0; /* reset count to wait next
page */
+ } else {
+ next_page = 0;
}
base_page = 1;
}
}
- if ((fsm & 0x8) == 0x8) {
- hw->fsm = 0x8;
- goto check_ability;
+ if (!next_page) {
+ if ((fsm & 0x8) == 0x8) {
+ hw->fsm = 0x8;
+ goto check_ability;
+ }
}
- usec_delay(100);
+ usec_delay(1000);
}
check_ability:
+ if (count == 50) {
+ BP_LOG("Wait for next page timeout\n");
+ return -ETIMEDOUT;
+ }
+ BP_LOG("AN exchange page done in %d ms\n", count2);
return chk_bkp_ability(hw, local_ability, lp_ability);
}
+void txgbe_e56_get_txffe(struct txgbe_hw *hw)
+{
+ /* 21. read txffe to check kr training status */
+ u32 rdata = 0, pmd_ctrl = 0, lane_idx = 0, lane_num = 0, txffe = 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__);
+ return;
+ }
+
+ BP_LOG("%dG phy kr training check.... fsm: %x\n",
+ hw->bp_link_mode, rd32_epcs(hw, 0x78010));
+ rdata = rd32_ephy(hw, 0x163c) & GENMASK(lane_num, 1);
+ pmd_ctrl = rd32_ephy(hw, 0x1644);
+ BP_LOG("KR TRAINNING CHECK = %x. pmd_ctrl:%lx-%lx-%lx-%lx\n",
+ rdata,
+ 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));
+ 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));
+ }
+}
+
static int txgbe_e56_cl72_training(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;
+ u32 lane_num = 0;
+ u32 __rte_unused pmd_ctrl = 0;
int ret = 0;
u32 rdata;
-
u8 pll_en_cfg = 0;
u8 pmd_mode = 0;
@@ -2463,52 +2523,48 @@ static int txgbe_e56_cl72_training(struct txgbe_hw *hw)
/* 18 */
/* 19. rxs calibration and adaptation sequence */
- BP_LOG("2.4 Wait %dG RXS.... fsm: %x\n",
- bylinkmode, rd32_epcs(hw, 0x78010));
+ BP_LOG("2.4 Wait %dG RXS.... fsm: %x, an_int: %x\n",
+ bylinkmode, rd32_epcs(hw, 0x78010),
+ rd32_epcs(hw, 0x78002));
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);
+ BP_LOG("2.5 Wait %dG phy calibration.... fsm: %x, an_int: %x\n",
+ bylinkmode, rd32_epcs(hw, 0x78010),
+ rd32_epcs(hw, 0x78002));
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);
+
+ ret |= status;
/* 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);
+ BP_LOG("2.6 Wait %dG phy kr fsm check : %x, an_int: %x\n",
+ bylinkmode, rd32_epcs(hw, 0x78010),
+ rd32_epcs(hw, 0x78002));
+ status = kr_read_poll(rd32_epcs, rdata,
+ (rdata & 0x9) == 0x9, 1000,
+ 400, hw, 0x78010);
pmd_ctrl = rd32_ephy(hw, 0x1644);
- BP_LOG("KR TRAINING CHECK = %x, %s. pmd_ctrl:%lx-%lx-%lx-%lx\n",
+ BP_LOG("KR FSM 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));
+ BP_LOG("2.7 Wait %dG phy Rx adc.... fsm:%x, an_int: %x\n",
+ bylinkmode, rd32_epcs(hw, 0x78010),
+ rd32_epcs(hw, 0x78002));
status = txgbe_e56_rxs_adc_adapt_seq(hw, bypass_ctle);
+ BP_LOG("2.8 ===end ret : %d.... fsm:%x, an_int: %x\n",
+ ret, rd32_epcs(hw, 0x78010),
+ rd32_epcs(hw, 0x78002));
+
return ret;
}
@@ -2517,27 +2573,7 @@ int txgbe_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_TRAINING_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);
-
+ /* 10 RXS_DISABLE - TXS_DISABLE - CMS_DISABLE */
/* dis phy tx/rx lane */
rdata = rd32_ephy(hw, 0x1400);
set_fields_e56(&rdata, 19, 16, 0x0);
@@ -2583,11 +2619,6 @@ int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw)
}
status = txgbe_e56_cl72_training(hw);
- if (status) {
- BP_LOG("CL72 training failed, status = %d\n", status);
- return status;
- }
-
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);
diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.h
b/drivers/net/txgbe/base/txgbe_e56_bp.h
index d2c49c2fce..da0d02b79f 100644
--- a/drivers/net/txgbe/base/txgbe_e56_bp.h
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.h
@@ -279,4 +279,6 @@ typedef union {
int txgbe_e56_set_phy_link_mode(struct txgbe_hw *hw,
u8 bp_link_mode, u32 need_restart);
int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw);
+int txgbe_e56_exchange_page(struct txgbe_hw *hw);
+void txgbe_e56_get_txffe(struct txgbe_hw *hw);
#endif
diff --git a/drivers/net/txgbe/base/txgbe_phy.c
b/drivers/net/txgbe/base/txgbe_phy.c
index 8b653f0aeb..10df23afae 100644
--- a/drivers/net/txgbe/base/txgbe_phy.c
+++ b/drivers/net/txgbe/base/txgbe_phy.c
@@ -1947,6 +1947,9 @@ txgbe_set_link_to_sfi(struct txgbe_hw *hw,
s32 err = 0;
u32 value = 0;
+ /* Switching to SFI mode clears backplane link mode. */
+ hw->bp_link_mode = 0;
+
/* Set the module link speed */
hw->mac.set_rate_select_speed(hw, speed);
/* 1. Wait xpcs power-up good */
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index ef30e0c40a..269e0aadd9 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3025,6 +3025,7 @@ void txgbe_dev_e56_check_bp_event(void *param)
u32 __rte_unused an_int = 0;
int ret = 0;
bool need_link_update = false;
+ bool exchange_done = false;
if (!hw)
return;
@@ -3043,8 +3044,10 @@ void txgbe_dev_e56_check_bp_event(void *param)
hw->phy.sfp_type = txgbe_sfp_type_not_present;
}
- if (!(txgbe_xpcs_an_enabled(hw)))
+ if (!(txgbe_xpcs_an_enabled(hw))) {
+ BP_LOG("%s %d\n", __func__, __LINE__);
return;
+ }
if (!hw->devarg.auto_neg)
return;
@@ -3063,6 +3066,7 @@ void txgbe_dev_e56_check_bp_event(void *param)
need_link_update = true;
value &= ~VR_AN_INTR_CMPLT;
wr32_epcs(hw, VR_AN_INTR, value);
+ txgbe_e56_get_txffe(hw);
}
if (value & VR_AN_INTR_LINK) {
@@ -3080,7 +3084,21 @@ void txgbe_dev_e56_check_bp_event(void *param)
}
if (value & VR_AN_INTR_PG_RCV) {
- BP_LOG("%d Enter training\n", hw->port_id);
+ BP_LOG("%d 2.1 *** Wait page changed ....\n", hw->port_id);
+ ret = txgbe_e56_exchange_page(hw);
+ if (ret) {
+ BP_LOG("%d 2.2 *** Exchange page failed\n",
hw->port_id);
+ goto an_status;
+ } else {
+ BP_LOG("%d 2.2 *** Wait page changed ..done..\n",
+ hw->port_id);
+ wr32_epcs(hw, 0x100ab, 0);
+ exchange_done = true;
+ }
+ }
+
+ if (exchange_done) {
+ BP_LOG("%d 2.2.2 *** Enter training\n", hw->port_id);
ret = txgbe_handle_e56_bkp_an73_flow(hw);
if (!AN_TRAINING_MODE) {
fsm = rd32_epcs(hw, 0x78010);
@@ -3783,8 +3801,10 @@ txgbe_dev_interrupt_get_status(struct rte_eth_dev *dev,
if (eicr & TXGBE_ICRMISC_LSC)
intr->flags |= TXGBE_FLAG_NEED_LINK_UPDATE;
- if (eicr & TXGBE_ICRMISC_ANDONE)
- intr->flags |= TXGBE_FLAG_NEED_AN_CONFIG;
+ if (eicr & TXGBE_ICRMISC_ANDONE) {
+ PMD_DRV_LOG(DEBUG, "an int eicr=0x%08x", eicr);
+ intr->flags |= TXGBE_FLAG_NEED_AN_CONFIG;//aml40-to-do
+ }
if (eicr & TXGBE_ICRMISC_VFMBX)
intr->flags |= TXGBE_FLAG_MAILBOX;
--
2.55.0.windows.2