Commit 015c5d5e authored by Yoshihiro Shimoda's avatar Yoshihiro Shimoda Committed by David S. Miller

net: ethernet: ravb: exit if re-initialization fails in tx timeout

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 and/or rx queue
are operating. After that, ravb_config() in ravb_dmac_init() will fail,
and then any descriptors will be not allocaled anymore so that NULL
pointer dereference happens after that on ravb_start_xmit().

To fix the issue, the ravb_tx_timeout_work() should check
the return values of ravb_stop_dma() and ravb_dmac_init().
If ravb_stop_dma() fails, ravb_tx_timeout_work() re-enables TX and RX
and just exits. If ravb_dmac_init() fails, just exits.

[1]
https://lore.kernel.org/linux-renesas-soc/20200518045452.2390-1-dirk.behme@de.bosch.com/Reported-by: default avatarDirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: default avatarYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Reviewed-by: default avatarSergei Shtylyov <sergei.shtylyov@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ca673235
...@@ -1450,6 +1450,7 @@ static void ravb_tx_timeout_work(struct work_struct *work) ...@@ -1450,6 +1450,7 @@ static void ravb_tx_timeout_work(struct work_struct *work)
struct ravb_private *priv = container_of(work, struct ravb_private, struct ravb_private *priv = container_of(work, struct ravb_private,
work); work);
struct net_device *ndev = priv->ndev; struct net_device *ndev = priv->ndev;
int error;
netif_tx_stop_all_queues(ndev); netif_tx_stop_all_queues(ndev);
...@@ -1458,15 +1459,36 @@ static void ravb_tx_timeout_work(struct work_struct *work) ...@@ -1458,15 +1459,36 @@ static void ravb_tx_timeout_work(struct work_struct *work)
ravb_ptp_stop(ndev); ravb_ptp_stop(ndev);
/* Wait for DMA stopping */ /* Wait for DMA stopping */
ravb_stop_dma(ndev); if (ravb_stop_dma(ndev)) {
/* If ravb_stop_dma() fails, the hardware is still operating
* for TX and/or RX. So, this should not call the following
* functions because ravb_dmac_init() is possible to fail too.
* Also, this should not retry ravb_stop_dma() again and again
* here because it's possible to wait forever. So, this just
* re-enables the TX and RX and skip the following
* re-initialization procedure.
*/
ravb_rcv_snd_enable(ndev);
goto out;
}
ravb_ring_free(ndev, RAVB_BE); ravb_ring_free(ndev, RAVB_BE);
ravb_ring_free(ndev, RAVB_NC); ravb_ring_free(ndev, RAVB_NC);
/* Device init */ /* Device init */
ravb_dmac_init(ndev); error = ravb_dmac_init(ndev);
if (error) {
/* If ravb_dmac_init() fails, descriptors are freed. So, this
* should return here to avoid re-enabling the TX and RX in
* ravb_emac_init().
*/
netdev_err(ndev, "%s: ravb_dmac_init() failed, error %d\n",
__func__, error);
return;
}
ravb_emac_init(ndev); ravb_emac_init(ndev);
out:
/* Initialise PTP Clock driver */ /* Initialise PTP Clock driver */
if (priv->chip_id == RCAR_GEN2) if (priv->chip_id == RCAR_GEN2)
ravb_ptp_init(ndev, priv->pdev); ravb_ptp_init(ndev, priv->pdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment