On Tue, Oct 16, 2018 at 3:24 PM Geert Uytterhoeven
<[email protected]> wrote:
> When submitting a DMA request fails, the driver is supposed to fall back
> to PIO. However, this never really worked due to various reasons
> (sh-sci driver issues and dmaengine framework limitations).
>
> There are three places where DMA submission can fail, and the driver
> should fall back to PIO:
> 1. sci_dma_rx_complete(),
> 2. sci_submit_rx(),
> 3. work_fn_tx().
>
> This RFC fixes fallback to PIO in the receive path (cases 1 and 2).
> Fallback to PIO in the transmit path (case 3) already works fine.
>
> Case 1: sci_dma_rx_complete()
>
> A. PIO cannot take over on SCIF if any DMA transactions are pending,
> hence they must be terminated first.
>
> B. The active cookies must be invalidated, else rx_timer_fn() may
> trigger a NULL pointer dereference.
>
> C. Restarting the port is not needed, as it is already running, but
> serial port interrupts must be directed back from the DMA engine to
> the CPU.
>
> Case 2: sci_submit_rx()
>
> D. 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.
>
> E. When falling back to PIO, active_rx must be set to a different
> value than cookie_rx[i], else sci_dma_rx_find_active() will
> incorrectly find a match, leading to a NULL pointer dereference in
> rx_timer_fn() later.
>
> F. On (H)SCIF, sci_submit_rx() is called in the receive interrupt
> handler. Hence if DMA submission fails, the interrupt handler
> should handle reception using PIO.
>
> Signed-off-by: Geert Uytterhoeven <[email protected]>
> ---
> Against tty/next + "serial: sh-sci: Fix receive on SCIFA/SCIFB variants
> with DMA".
>
> All testing was done on r8a7791/koelsch using SCIF1 on debug serial 1,
> and SCIFA3 on EXIO-B, by introducing random failures in DMA submission
> code.
>
> Thanks for your comments!
>
> v2:
> - Fix fallback in sci_dma_rx_complete(),
> - Fallback in the transmit path already works fine,
> - Widen audience, but keep RFC.
> ---
> drivers/tty/serial/sh-sci.c | 34 +++++++++++++++++++++++++---------
> 1 file changed, 25 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
> index 3aad48e64b9b71ff..30b2728c20d6e982 100644
> --- a/drivers/tty/serial/sh-sci.c
> +++ b/drivers/tty/serial/sh-sci.c
> @@ -1272,6 +1272,7 @@ static void sci_dma_rx_complete(void *arg)
> struct dma_async_tx_descriptor *desc;
> unsigned long flags;
> int active, count = 0;
> + unsigned int i;
Oops, there's a "u16 scr;" missing here.
>
> dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line,
> s->active_rx);
> @@ -1309,12 +1310,22 @@ static void sci_dma_rx_complete(void *arg)
> return;
>
> fail:
> + dmaengine_terminate_async(chan);
> spin_unlock_irqrestore(&port->lock, flags);
> dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
> /* Switch to PIO */
> spin_lock_irqsave(&port->lock, flags);
> + for (i = 0; i < 2; i++)
> + s->cookie_rx[i] = -EINVAL;
> + s->active_rx = 0;
> s->chan_rx = NULL;
> - sci_start_rx(port);
> + /* Direct new serial port interrupts back to CPU */
> + scr = serial_port_in(port, SCSCR);
> + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
> + scr &= ~SCSCR_RDRQE;
> + enable_irq(s->irqs[SCIx_RXI_IRQ]);
> + }
> + serial_port_out(port, SCSCR, scr | SCSCR_RIE);
> spin_unlock_irqrestore(&port->lock, flags);
> }
>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds