lkml.org 
[lkml]   [2020]   [Jul]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 4.19 05/10] net: ethernet: ravb: exit if re-initialization fails in tx timeout
    Date
    From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>

    [ Upstream commit 015c5d5e6aa3523c758a70eb87b291cece2dbbb4 ]

    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: Dirk Behme <dirk.behme@de.bosch.com>
    Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
    Reviewed-by: Sergei Shtylyov <sergei.shtylyov@gmail.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/net/ethernet/renesas/ravb_main.c | 26 ++++++++++++++++++++++--
    1 file changed, 24 insertions(+), 2 deletions(-)

    diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
    index faaf74073a120..569e698b5c807 100644
    --- a/drivers/net/ethernet/renesas/ravb_main.c
    +++ b/drivers/net/ethernet/renesas/ravb_main.c
    @@ -1445,6 +1445,7 @@ 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;
    + int error;

    netif_tx_stop_all_queues(ndev);

    @@ -1453,15 +1454,36 @@ static void ravb_tx_timeout_work(struct work_struct *work)
    ravb_ptp_stop(ndev);

    /* 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_NC);

    /* 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);

    +out:
    /* Initialise PTP Clock driver */
    if (priv->chip_id == RCAR_GEN2)
    ravb_ptp_init(ndev, priv->pdev);
    --
    2.25.1
    \
     
     \ /
      Last update: 2020-07-28 01:27    [W:3.367 / U:0.304 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site