lkml.org 
[lkml]   [2019]   [Feb]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.20 182/352] serial: sh-sci: Fix locking in sci_submit_rx()
    Date
    4.20-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    [ Upstream commit dd1f2250da95e87cb3e612858f94b14f99445a7c ]

    Some callers of sci_submit_rx() hold the port spinlock, others don't.
    During fallback to PIO, the driver needs to obtain the port spinlock.
    If the lock was already held, spinlock recursion is detected, causing a
    deadlock: BUG: spinlock recursion on CPU#0.

    Fix this by adding a flag parameter to sci_submit_rx() for the caller to
    indicate the port spinlock is already held, so spinlock recursion can be
    avoided.

    Move the spin_lock_irqsave() up, so all DMA disable steps are protected,
    which is safe as the recently introduced dmaengine_terminate_async() can
    be called in atomic context.

    Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
    Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/tty/serial/sh-sci.c | 16 +++++++++-------
    1 file changed, 9 insertions(+), 7 deletions(-)

    diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
    index cc56cb3b3eca..613007d7165e 100644
    --- a/drivers/tty/serial/sh-sci.c
    +++ b/drivers/tty/serial/sh-sci.c
    @@ -1331,7 +1331,7 @@ static void sci_tx_dma_release(struct sci_port *s)
    dma_release_channel(chan);
    }

    -static void sci_submit_rx(struct sci_port *s)
    +static void sci_submit_rx(struct sci_port *s, bool port_lock_held)
    {
    struct dma_chan *chan = s->chan_rx;
    struct uart_port *port = &s->port;
    @@ -1362,16 +1362,18 @@ static void sci_submit_rx(struct sci_port *s)
    return;

    fail:
    + /* Switch to PIO */
    + if (!port_lock_held)
    + spin_lock_irqsave(&port->lock, flags);
    if (i)
    dmaengine_terminate_async(chan);
    for (i = 0; i < 2; i++)
    s->cookie_rx[i] = -EINVAL;
    s->active_rx = -EINVAL;
    - /* Switch to PIO */
    - spin_lock_irqsave(&port->lock, flags);
    s->chan_rx = NULL;
    sci_start_rx(port);
    - spin_unlock_irqrestore(&port->lock, flags);
    + if (!port_lock_held)
    + spin_unlock_irqrestore(&port->lock, flags);
    }

    static void work_fn_tx(struct work_struct *work)
    @@ -1491,7 +1493,7 @@ static enum hrtimer_restart rx_timer_fn(struct hrtimer *t)
    }

    if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
    - sci_submit_rx(s);
    + sci_submit_rx(s, true);

    /* Direct new serial port interrupts back to CPU */
    scr = serial_port_in(port, SCSCR);
    @@ -1617,7 +1619,7 @@ static void sci_request_dma(struct uart_port *port)
    s->chan_rx_saved = s->chan_rx = chan;

    if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
    - sci_submit_rx(s);
    + sci_submit_rx(s, false);
    }
    }

    @@ -1667,7 +1669,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
    scr |= SCSCR_RDRQE;
    } else {
    scr &= ~SCSCR_RIE;
    - sci_submit_rx(s);
    + sci_submit_rx(s, false);
    }
    serial_port_out(port, SCSCR, scr);
    /* Clear current interrupt */
    --
    2.19.1


    \
     
     \ /
      Last update: 2019-02-11 17:01    [W:4.109 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site