From e4e8eed5539b8d0ed488e015d055eb3c251d47d5 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 5 Aug 2018 16:51:49 -0400 Subject: [PATCH] bnxt_en: Add PHY retry logic. During hotplug, the driver's open function can be called almost immediately after power on reset. The PHY may not be ready and the firmware may return failure when the driver tries to update PHY settings. Add retry logic fired from the driver's timer to retry the operation for 5 seconds. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 31 ++++++++++++++++++++++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 4 +++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d9fc905c59967..fd936c5e8760b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -6898,8 +6898,14 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) mutex_lock(&bp->link_lock); rc = bnxt_update_phy_setting(bp); mutex_unlock(&bp->link_lock); - if (rc) + if (rc) { netdev_warn(bp->dev, "failed to update phy settings\n"); + if (BNXT_SINGLE_PF(bp)) { + bp->link_info.phy_retry = true; + bp->link_info.phy_retry_expires = + jiffies + 5 * HZ; + } + } } if (irq_re_init) @@ -7583,6 +7589,16 @@ static void bnxt_timer(struct timer_list *t) set_bit(BNXT_FLOW_STATS_SP_EVENT, &bp->sp_event); bnxt_queue_sp_work(bp); } + + if (bp->link_info.phy_retry) { + if (time_after(jiffies, bp->link_info.phy_retry_expires)) { + bp->link_info.phy_retry = 0; + netdev_warn(bp->dev, "failed to update phy settings after maximum retries.\n"); + } else { + set_bit(BNXT_UPDATE_PHY_SP_EVENT, &bp->sp_event); + bnxt_queue_sp_work(bp); + } + } bnxt_restart_timer: mod_timer(&bp->timer, jiffies + bp->current_interval); } @@ -7670,6 +7686,19 @@ static void bnxt_sp_task(struct work_struct *work) netdev_err(bp->dev, "SP task can't update link (rc: %x)\n", rc); } + if (test_and_clear_bit(BNXT_UPDATE_PHY_SP_EVENT, &bp->sp_event)) { + int rc; + + mutex_lock(&bp->link_lock); + rc = bnxt_update_phy_setting(bp); + mutex_unlock(&bp->link_lock); + if (rc) { + netdev_warn(bp->dev, "update phy settings retry failed\n"); + } else { + bp->link_info.phy_retry = false; + netdev_info(bp->dev, "update phy settings retry succeeded\n"); + } + } if (test_and_clear_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event)) { mutex_lock(&bp->link_lock); bnxt_get_port_module_status(bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 0d49fe015ba90..47eec148e745e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -959,6 +959,9 @@ struct bnxt_link_info { u16 advertising; /* user adv setting */ bool force_link_chng; + bool phy_retry; + unsigned long phy_retry_expires; + /* a copy of phy_qcfg output used to report link * info to VF */ @@ -1344,6 +1347,7 @@ struct bnxt { #define BNXT_GENEVE_DEL_PORT_SP_EVENT 13 #define BNXT_LINK_SPEED_CHNG_SP_EVENT 14 #define BNXT_FLOW_STATS_SP_EVENT 15 +#define BNXT_UPDATE_PHY_SP_EVENT 16 struct bnxt_hw_resc hw_resc; struct bnxt_pf_info pf; -- 2.39.5