On Thu, 3 Aug 2023 at 23:56, Ryosuke Saito <[email protected]> wrote: > > The NETSEC GMAC occasionally falls into a weird state where > MAC_REG_DESC_SOFT_RST has never been cleared and shows errors like the > below when networking commands are issued: > > => ping 192.168.1.1 > ethernet@522d0000 Waiting for PHY auto negotiation to complete... done > netsec_wait_while_busy: timeout > Using ethernet@522d0000 device > > ARP Retry count exceeded; starting again > ping failed; host 192.168.1.1 is not alive > > It happens on not only 'ping' but also 'dhcp', 'tftp' and so on. > > Luckily, restarting the NETSEC GMAC and trying again seems to fix the > problematic state. So first ensure that we haven't entered the state by > checking MAC_REG_DESC_SOFT_RST to be cleared; otherwise, restarting > NETSEC/PHY and trying again would work as a workaround. > > Signed-off-by: Ryosuke Saito <[email protected]> > --- > drivers/net/sni_netsec.c | 50 ++++++++++++++++++++++++++++++++-------- > 1 file changed, 41 insertions(+), 9 deletions(-)
Tested-By: Masahisa Kojima <[email protected]> Overnight testing of 'dhcp->ping->reset' sequence works for me. Thank you for fixing the issue. Regards, Masahisa Kojima > > diff --git a/drivers/net/sni_netsec.c b/drivers/net/sni_netsec.c > index 9780f2092bd4..71afe78fd28a 100644 > --- a/drivers/net/sni_netsec.c > +++ b/drivers/net/sni_netsec.c > @@ -286,6 +286,8 @@ struct netsec_rx_pkt_info { > bool err_flag; > }; > > +static int netsec_reset_hardware(struct netsec_priv *priv, bool load_ucode); > + > static void netsec_write_reg(struct netsec_priv *priv, u32 reg_addr, u32 val) > { > writel(val, priv->ioaddr + reg_addr); > @@ -532,18 +534,11 @@ static int netsec_mac_update_to_phy_state(struct > netsec_priv *priv) > return 0; > } > > -static int netsec_start_gmac(struct netsec_priv *priv) > +static int netsec_reset_gmac(struct netsec_priv *priv) > { > u32 value = 0; > int ret; > > - if (priv->max_speed != SPEED_1000) > - value = (NETSEC_GMAC_MCR_REG_CST | > - NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON); > - > - if (netsec_set_mac_reg(priv, GMAC_REG_MCR, value)) > - return -ETIMEDOUT; > - > if (netsec_set_mac_reg(priv, GMAC_REG_BMR, > NETSEC_GMAC_BMR_REG_RESET)) > return -ETIMEDOUT; > @@ -558,10 +553,47 @@ static int netsec_start_gmac(struct netsec_priv *priv) > if (value & NETSEC_GMAC_BMR_REG_SWR) > return -EAGAIN; > > + /** > + * NETSEC GMAC sometimes shows the peculiar behaviour where > + * MAC_REG_DESC_SOFT_RST never been cleared, resulting in the loss of > + * sending packets. > + * > + * Workaround: > + * Restart NETSEC and PHY, retry again. > + */ > netsec_write_reg(priv, MAC_REG_DESC_SOFT_RST, 1); > - if (netsec_wait_while_busy(priv, MAC_REG_DESC_SOFT_RST, 1)) > + udelay(1000); > + if (netsec_read_reg(priv, MAC_REG_DESC_SOFT_RST)) { > + phy_shutdown(priv->phydev); > + netsec_reset_hardware(priv, false); > + phy_startup(priv->phydev); > + return -EAGAIN; > + } > + return 0; > +} > + > +static int netsec_start_gmac(struct netsec_priv *priv) > +{ > + u32 value = 0; > + u32 failure = 0; > + int ret; > + > + if (priv->max_speed != SPEED_1000) > + value = (NETSEC_GMAC_MCR_REG_CST | > + NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON); > + > + if (netsec_set_mac_reg(priv, GMAC_REG_MCR, value)) > return -ETIMEDOUT; > > + /* Reset GMAC */ > + while ((ret = netsec_reset_gmac(priv)) == -EAGAIN && ++failure < 3) > + ; > + > + if (ret) { > + pr_err("%s: failed to reset gmac(err=%d).\n", __func__, ret); > + return ret; > + } > + > netsec_write_reg(priv, MAC_REG_DESC_INIT, 1); > if (netsec_wait_while_busy(priv, MAC_REG_DESC_INIT, 1)) > return -ETIMEDOUT; > -- > 2.41.0 >

