[PATCH v8 5/6] serial: 8250: retire canceled RX DMA before reusing the receive buffer
James Hilliard
james.hilliard1 at gmail.com
Thu Oct 29 10:17:42 PDT 2026
On Thu, Oct 29, 2026 at 8:22 AM Andy Shevchenko
<andriy.shevchenko at linux.intel.com> wrote:
>
> On Thu, Oct 29, 2026 at 01:37:01AM -0600, James Hilliard wrote:
> > The generic RX timeout path pauses a transfer, copies its data and
> > terminates it asynchronously. Clearing rx_running at that point lets a
> > new receive reuse the buffer and cookie while the old callback has not
> > yet run. Inspecting the new cookie cannot distinguish that callback from
> > the completion of a new transfer.
> >
> > Reserve the receive buffer until a worker has drained the canceled
> > callbacks. Keep FIFO access separate from callback retirement: after a
> > successful pause and termination, clear rx_running while rx_terminating
> > prevents another descriptor from reusing the buffer. Deliver the paused
> > data before allowing the interrupt handler to drain the FIFO through PIO.
> > Normal retirement only releases ownership and leaves subsequent receive
> > handling to the UART interrupt.
> >
> > Preserve the normal completion-path LSR read and gate DMA resubmission on
> > the receive interrupt enable, so stop_rx() prevents another transfer while
> > the status read retains its existing side effects.
> >
> > Reject new flush work and PIO receive handling during shutdown, including
> > late Intel MID DMA timeouts. Stop and drain retirement work before freeing
> > the channels and buffer. Once RX has stopped, allow the idle flush used by
> > DesignWare LCR recovery during shutdown. Clear the shutdown guard before
> > startup configures the UART and tests its interrupts.
> >
> > Check pause failures before accessing the buffer. A successful pause is
> > the quiescence guarantee, even when a provider still reports IN_PROGRESS.
> > Also accept DMA_COMPLETE after a failed pause: completion can stop the
> > channel before its callback acquires the port lock, leaving nothing for
> > the provider to pause. Retire that completed transfer normally.
> >
> > A failed pause with an incomplete cookie is ambiguous: hardware may have
> > finished while its completion interrupt is still pending. Canceling that
> > descriptor can discard the entire completed receive buffer and switch
> > permanently to PIO. Retain the transfer and retry pause and status in the
> > worker, with receive interrupts masked to prevent a timeout interrupt
> > storm. The worker copies only after a successful pause or reported
> > completion, then terminates and drains the old callback before reuse.
> > The pending-pause guard keeps callbacks from copying or resubmitting the
> > transfer concurrently. Retries sleep outside the port lock and stop when
> > shutdown takes over. A provider which never pauses or completes retains
> > RX ownership until an error or shutdown; a timeout alone cannot establish
> > that discarding the buffer is safe.
> >
> > On DMA_ERROR or termination failure, let the worker stop DMA before
> > handing the FIFO to PIO. Keep the requested enables in the existing IER
> > shadow and filter hardware writes during pause retries and recovery,
> > including termios, RS485 and overrun-backoff changes. Apply the current
> > enables after retirement so stop_rx() and shutdown remain effective.
> > Hold a runtime PM reference around worker register accesses and keep RX
> > on PIO until reopen after a confirmed error.
> >
> > Abort the DesignWare idle sequence when RX cannot be stopped. Allow
> > the empty-FIFO timeout workaround once DMA has released the FIFO, including
> > while callbacks retire. Exclude FIFO resets during RX DMA recovery. If the
> > provider still cannot terminate the channel in process context, retain
> > its buffer and leave receive interrupts masked.
> >
> > For OMAP, publish the shutdown gate under the port lock before the final
> > RX flush and interrupt masking. Take the RX DMA lock inside the port lock
> > in the completion callback, and serialize the runtime-suspend flush with
> > the same order. Drain the UART IRQ before releasing DMA state so an
> > in-flight handler cannot retain up->dma across its release.
>
> Can this patch be split to smaller logically isolated (to some extent) pieces?
The OMAP shutdown and locking changes look like they can be split
out.
The generic RX changes are more tightly coupled: the retirement
state, worker, IER filtering and FIFO-access guards must agree about
whether DMA still owns the receive path. Splitting those mechanically
could leave intermediate commits allowing PIO or another descriptor
to access a buffer that has not been retired.
>
> ...
>
> > +++ b/drivers/tty/serial/8250/8250_dma.c
>
> > #include <linux/tty_flip.h>
> > #include <linux/serial_reg.h>
> > #include <linux/dma-mapping.h>
> > +#include <linux/delay.h>
>
> When adding a new header to an unsorted block, try to squeeze it the way that
> you get the longest ordered chain (yes, interleaved with some unsorted
> elements, but still).
>
> > #include "8250.h"
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
More information about the linux-arm-kernel
mailing list