mgbe: Ensure UPHY is up before reporting link OK

Issue:
1) During switch reset, MGBE MAC generates a Local Link Fault
   common interrupt.
2) The interrupt routine triggers restart_lane_bring_up(),
   which schedules the link monitor timer inside the Ethernet
   Server.
3) As part of this routine, link status change interrupts
   (e.g., Local Fault, Remote Fault, Link OK) are disabled to
   avoid spurious triggers.
4) Meanwhile, if a PTP Tx packet is sitting in the MTL TX
   FIFO, it triggers a common interrupt.
5) The ISR for this common interrupt reads the status
   register. Since the Link OK flag is set, the server
   assumes the link is up.
6) This schedules the link monitor timer again (as in step 2).
7) Since the Link OK flag is already set, the monitor timer
   exits without calling OSI_CMD_SET_SPEED (which is
   responsible for UPHY lane bring-up).
8) As a result, when the switch reset is released, the UPHY
   lane is not brought up, and the Ethernet link remains
   broken.

Fix:
Check UPHY link status before giving link up.

Bug 5206852

Change-Id: I98c49f710e2570480583c40255cda912af6ab1b5
Signed-off-by: Bhadram Varka <vbhadram@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/kernel/nvethernetrm/+/3339051
Reviewed-by: svcacv <svcacv@nvidia.com>
Reviewed-by: Hareesh Kesireddy <hkesireddy@nvidia.com>
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: Srinivas Ramachandran <srinivasra@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com>
This commit is contained in:
Bhadram Varka
2025-04-11 17:00:26 +00:00
committed by mobile promotions
parent 280bf8b16d
commit ddab1dc9b4
3 changed files with 11 additions and 5 deletions

View File

@@ -207,6 +207,7 @@ fail:
nve32_t hw_set_speed(struct osi_core_priv_data *const osi_core, const nve32_t speed)
{
struct core_local *l_core = (struct core_local *)(void *)osi_core;
nveu32_t value;
nve32_t ret = 0;
void *base = osi_core->base;
@@ -216,6 +217,8 @@ nve32_t hw_set_speed(struct osi_core_priv_data *const osi_core, const nve32_t sp
MGBE_MAC_TMCR
};
l_core->lane_status = OSI_DISABLE;
if (((osi_core->mac == OSI_MAC_HW_EQOS) && (speed > OSI_SPEED_2500)) ||
(((osi_core->mac == OSI_MAC_HW_MGBE) ||
(osi_core->mac == OSI_MAC_HW_MGBE_T26X)) &&
@@ -310,6 +313,7 @@ nve32_t hw_set_speed(struct osi_core_priv_data *const osi_core, const nve32_t sp
}
}
l_core->lane_status = OSI_ENABLE;
osi_core->speed = speed;
fail:
return ret;

View File

@@ -3154,6 +3154,7 @@ static inline nveu32_t get_free_ts_idx(struct core_local *l_core)
static void mgbe_handle_link_change_and_fpe_intrs(struct osi_core_priv_data *osi_core,
nveu32_t mac_isr)
{
struct core_local *l_core = (struct core_local *)(void *)osi_core;
nveu32_t mac_ier = 0;
nveu8_t *base = (nveu8_t *)osi_core->base;
nveu32_t value = 0U;
@@ -3179,8 +3180,11 @@ static void mgbe_handle_link_change_and_fpe_intrs(struct osi_core_priv_data *osi
value &= ~MGBE_IMR_RGSMIIIE;
osi_writela(osi_core, value, (nveu8_t *)osi_core->base + MGBE_MAC_IER);
/* Mark that UPHY lane is down */
l_core->lane_status = OSI_DISABLE;
osi_core->osd_ops.restart_lane_bringup(osi_core->osd, OSI_DISABLE);
} else if ((mac_isr & MGBE_MAC_ISR_LS_MASK) == MGBE_MAC_ISR_LS_LINK_OK) {
} else if (((mac_isr & MGBE_MAC_ISR_LS_MASK) == MGBE_MAC_ISR_LS_LINK_OK) &&
(l_core->lane_status == OSI_ENABLE)) {
osi_core->osd_ops.restart_lane_bringup(osi_core->osd, OSI_ENABLE);
#ifdef HSI_SUPPORT
link_ok = 1;

View File

@@ -763,14 +763,12 @@ step10:
if (l_core->lane_status == OSI_ENABLE) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to get PCS block lock\n", 0ULL);
l_core->lane_status = OSI_DISABLE;
}
ret = -1;
goto fail;
} else {
OSI_CORE_INFO((osi_core->osd), (OSI_LOG_ARG_HW_FAIL),
("PCS block lock SUCCESS\n"), (0ULL));
l_core->lane_status = OSI_ENABLE;
OSI_CORE_INFO(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"PCS block lock SUCCESS\n", 0ULL);
}
fail:
return ret;