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? ... > +++ 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
