[PATCH/RFC] net: ethernet: ravb: Try to wake subqueue instead of stop on timeout

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



According to the report of [1], this driver is possible to cause
the following error in ravb_tx_timeout_work().

ravb e6800000.ethernet ethernet: failed to switch device to config mode

This error means that the hardware could not change the state
from "Operation" to "Configuration" while some tx queue is operating.
After that, ravb_config() in ravb_dmac_init() will fail, and then
any descriptors will be not allocaled anymore so that NULL porinter
dereference happens after that on ravb_start_xmit().

Such a case is possible to be caused because this driver supports
two queues (NC and BE) and the ravb_stop_dma() is possible to return
without any stopping process if TCCR or CSR register indicates
the hardware is operating for TX.

To fix the issue, just try to wake the subqueue on
ravb_tx_timeout_work() if the descriptors are not full instead
of stop all transfers (all queues of TX and RX).

[1]
https://lore.kernel.org/linux-renesas-soc/20200518045452.2390-1-dirk.behme@xxxxxxxxxxxx/

Reported-by: Dirk Behme <dirk.behme@xxxxxxxxxxxx>
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@xxxxxxxxxxx>
---
 I'm guessing that this issue is possible to happen if:
 - ravb_start_xmit() calls netif_stop_subqueue(), and
 - ravb_poll() will not be called with some reason, and
 - netif_wake_subqueue() will be not called, and then
 - dev_watchdog() in net/sched/sch_generic.c calls ndo_tx_timeout().

 However, unfortunately, I didn't reproduce the issue yet.
 To be honest, I'm also guessing other queues (SR) of this hardware
 which out-of tree driver manages are possible to reproduce this issue,
 but I didn't try such environment for now...

 So, I marked RFC on this patch now.

 drivers/net/ethernet/renesas/ravb.h      |  1 -
 drivers/net/ethernet/renesas/ravb_main.c | 48 ++++++++++----------------------
 2 files changed, 14 insertions(+), 35 deletions(-)

diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index 9f88b5d..42cf41a 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -1021,7 +1021,6 @@ struct ravb_private {
 	u32 cur_tx[NUM_TX_QUEUE];
 	u32 dirty_tx[NUM_TX_QUEUE];
 	struct napi_struct napi[NUM_RX_QUEUE];
-	struct work_struct work;
 	/* MII transceiver section. */
 	struct mii_bus *mii_bus;	/* MDIO bus control */
 	int link;
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 067ad25..45e1ecd 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1428,44 +1428,25 @@ static int ravb_open(struct net_device *ndev)
 static void ravb_tx_timeout(struct net_device *ndev, unsigned int txqueue)
 {
 	struct ravb_private *priv = netdev_priv(ndev);
+	unsigned long flags;
+	bool wake = false;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (priv->cur_tx[txqueue] - priv->dirty_tx[txqueue] <=
+	    (priv->num_tx_ring[txqueue] - 1) * priv->num_tx_desc)
+		wake = true;
 
 	netif_err(priv, tx_err, ndev,
-		  "transmit timed out, status %08x, resetting...\n",
-		  ravb_read(ndev, ISS));
+		  "transmit timed out (%d %d), status %08x %08x %08x\n",
+		  txqueue, wake, ravb_read(ndev, ISS), ravb_read(ndev, TCCR),
+		  ravb_read(ndev, CSR));
+
+	if (wake)
+		netif_wake_subqueue(ndev, txqueue);
 
 	/* tx_errors count up */
 	ndev->stats.tx_errors++;
-
-	schedule_work(&priv->work);
-}
-
-static void ravb_tx_timeout_work(struct work_struct *work)
-{
-	struct ravb_private *priv = container_of(work, struct ravb_private,
-						 work);
-	struct net_device *ndev = priv->ndev;
-
-	netif_tx_stop_all_queues(ndev);
-
-	/* Stop PTP Clock driver */
-	if (priv->chip_id == RCAR_GEN2)
-		ravb_ptp_stop(ndev);
-
-	/* Wait for DMA stopping */
-	ravb_stop_dma(ndev);
-
-	ravb_ring_free(ndev, RAVB_BE);
-	ravb_ring_free(ndev, RAVB_NC);
-
-	/* Device init */
-	ravb_dmac_init(ndev);
-	ravb_emac_init(ndev);
-
-	/* Initialise PTP Clock driver */
-	if (priv->chip_id == RCAR_GEN2)
-		ravb_ptp_init(ndev, priv->pdev);
-
-	netif_tx_start_all_queues(ndev);
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 /* Packet transmit function for Ethernet AVB */
@@ -2046,7 +2027,6 @@ static int ravb_probe(struct platform_device *pdev)
 	}
 
 	spin_lock_init(&priv->lock);
-	INIT_WORK(&priv->work, ravb_tx_timeout_work);
 
 	error = of_get_phy_mode(np, &priv->phy_interface);
 	if (error && error != -ENODEV)
-- 
2.7.4




[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux