diff mbox series

[1/1] net: sni_netsec: Add workaround for timeout error

Message ID 20230803145648.1023981-2-ryosuke.saito@linaro.org
State Accepted
Commit c5b42e3e9e757ab44da3006e713d8d02b65aa9fe
Headers show
Series Workaround for timeout error in NETSEC driver | expand

Commit Message

Ryosuke Saito Aug. 3, 2023, 2:56 p.m. UTC
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 <ryosuke.saito@linaro.org>
---
 drivers/net/sni_netsec.c | 50 ++++++++++++++++++++++++++++++++--------
 1 file changed, 41 insertions(+), 9 deletions(-)

Comments

Masahisa Kojima Aug. 6, 2023, 11:19 p.m. UTC | #1
On Thu, 3 Aug 2023 at 23:56, Ryosuke Saito <ryosuke.saito@linaro.org> 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 <ryosuke.saito@linaro.org>
> ---
>  drivers/net/sni_netsec.c | 50 ++++++++++++++++++++++++++++++++--------
>  1 file changed, 41 insertions(+), 9 deletions(-)

Tested-By: Masahisa Kojima <masahisa.kojima@linaro.org>

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
>
Tom Rini Sept. 22, 2023, 10:26 p.m. UTC | #2
On Thu, Aug 03, 2023 at 11:56:48PM +0900, Ryosuke Saito 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 <ryosuke.saito@linaro.org>
> Tested-By: Masahisa Kojima <masahisa.kojima@linaro.org>

Applied to u-boot/master, thanks!
diff mbox series

Patch

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;