ethernet: reset ethernet when resume [1/1]
authorZhuo Wang <zhuo.wang@amlogic.com>
Tue, 2 Apr 2019 05:43:59 +0000 (13:43 +0800)
committerNick Xie <nick@khadas.com>
Mon, 5 Aug 2019 06:14:59 +0000 (14:14 +0800)
PD#SWPL-6608

Problem:
system will report tx error somethime after resume

Solution:
reset ethernet when resume

Verify:
verify on u200 board

Change-Id: I9863a8a50c08addd4e2d8c024f46a2e7568c28b4
Signed-off-by: Zhuo Wang <zhuo.wang@amlogic.com>
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

index 3e77065..d101263 100644 (file)
@@ -124,6 +124,15 @@ static void stmmac_exit_fs(struct net_device *dev);
 
 #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
 
+/*won't be valid unless enable amlogic priv code*/
+#ifdef CONFIG_AMLOGIC_ETH_PRIVE
+#undef TX_MONITOR
+#endif
+
+#ifdef TX_MONITOR
+static struct workqueue_struct *moniter_tx_wq;
+static struct delayed_work moniter_tx_worker;
+#endif
 /**
  * stmmac_verify_args - verify the driver parameters.
  * Description: it checks the driver parameters and set a default in case of
@@ -1874,7 +1883,9 @@ static int stmmac_open(struct net_device *dev)
 
        napi_enable(&priv->napi);
        netif_start_queue(dev);
-
+#ifdef TX_MONITOR
+       queue_delayed_work(moniter_tx_wq, &moniter_tx_worker, HZ);
+#endif
        return 0;
 
 lpiirq_error:
@@ -2717,12 +2728,18 @@ static int stmmac_poll(struct napi_struct *napi, int budget)
  *   netdev structure and arrange for the device to be reset to a sane state
  *   in order to transmit a new packet.
  */
+#ifdef TX_MONITOR
+unsigned int timeout_err;
+#endif
 static void stmmac_tx_timeout(struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
 
        /* Clear Tx resources and restart transmitting again */
        stmmac_tx_err(priv);
+#ifdef TX_MONITOR
+       timeout_err = 1;
+#endif
 }
 
 /**
@@ -3260,6 +3277,23 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
        return 0;
 }
 
+#ifdef TX_MONITOR
+struct stmmac_priv *priv_monitor;
+static void moniter_tx_handler(struct work_struct *work)
+{
+       if (priv_monitor) {
+               if (timeout_err) {
+                       pr_info("reset eth\n");
+                       stmmac_release(priv_monitor->dev);
+                       stmmac_open(priv_monitor->dev);
+                       timeout_err = 0;
+               }
+       } else {
+               pr_info("device not init yet!\n");
+       }
+       queue_delayed_work(moniter_tx_wq, &moniter_tx_worker, HZ);
+}
+#endif
 /**
  * stmmac_dvr_probe
  * @device: device pointer
@@ -3278,6 +3312,10 @@ int stmmac_dvr_probe(struct device *device,
        struct net_device *ndev = NULL;
        struct stmmac_priv *priv;
 
+#ifdef TX_MONITOR
+       moniter_tx_wq = create_singlethread_workqueue("eth_moniter_tx_wq");
+       INIT_DELAYED_WORK(&moniter_tx_worker, moniter_tx_handler);
+#endif
        ndev = alloc_etherdev(sizeof(struct stmmac_priv));
        if (!ndev)
                return -ENOMEM;
@@ -3429,6 +3467,9 @@ int stmmac_dvr_probe(struct device *device,
        ret = gmac_create_sysfs(
                mdiobus_get_phy(priv->mii, priv->plat->phy_addr), priv->ioaddr);
 #endif
+#ifdef TX_MONITOR
+       priv_monitor = priv;
+#endif
        return ret;
 
 error_netdev_register:
@@ -3499,6 +3540,9 @@ int stmmac_suspend(struct device *dev)
        struct stmmac_priv *priv = netdev_priv(ndev);
        unsigned long flags;
 
+#ifdef TX_MONITOR
+       cancel_delayed_work_sync(&moniter_tx_worker);
+#endif
        if (!ndev || !netif_running(ndev))
                return 0;
 
@@ -3604,7 +3648,6 @@ int stmmac_resume(struct device *dev)
 
        stmmac_init_tx_coalesce(priv);
        stmmac_set_rx_mode(ndev);
-
 #ifdef CONFIG_AMLOGIC_ETH_PRIVE
        netif_device_attach(ndev);
 #endif
@@ -3617,6 +3660,10 @@ int stmmac_resume(struct device *dev)
        if (priv->phydev)
                phy_start(priv->phydev);
 
+#ifdef TX_MONITOR
+       queue_delayed_work(moniter_tx_wq, &moniter_tx_worker, HZ);
+       timeout_err = 1;
+#endif
        return 0;
 }
 EXPORT_SYMBOL_GPL(stmmac_resume);