Subject: [PATCH 1/2] serial: Add flush_buffer() operation to uart_ops
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>
Wed, 16 Jul 2008 20:52:36 +0000 (21:52 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 21 Jul 2008 00:12:34 +0000 (17:12 -0700)
Serial drivers using DMA (like the atmel_serial driver) tend to get very
confused when the xmit buffer is flushed and nobody told them.  They
also tend to spew a lot of garbage since the DMA engine keeps running
after the buffer is flushed and possibly refilled with unrelated data.

This patch adds a new flush_buffer operation to the uart_ops struct,
along with a call to it from uart_flush_buffer() right after the xmit
buffer has been cleared. The driver can implement this in order to
syncronize its internal DMA state with the xmit buffer when the buffer
is flushed.

Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
Acked-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Documentation/serial/driver
drivers/serial/serial_core.c
include/linux/serial_core.h

index 88ad615dd338d75e2b282422c8f2d6f7f3af80b7..77ba0afbe4db2c227650441af43ab3c57f2e5a6f 100644 (file)
@@ -186,6 +186,17 @@ hardware.
        Locking: port_sem taken.
        Interrupts: caller dependent.
 
+  flush_buffer(port)
+       Flush any write buffers, reset any DMA state and stop any
+       ongoing DMA transfers.
+
+       This will be called whenever the port->info->xmit circular
+       buffer is cleared.
+
+       Locking: port->lock taken.
+       Interrupts: locally disabled.
+       This call must not sleep
+
   set_termios(port,termios,oldtermios)
        Change the port parameters, including word length, parity, stop
        bits.  Update read_status_mask and ignore_status_mask to indicate
index 42d2e108b67968406ebc1da8ac8b316d532f578a..9884bc9eecb1f322648cf621ad6c51cd04bbe3da 100644 (file)
@@ -573,6 +573,8 @@ static void uart_flush_buffer(struct tty_struct *tty)
 
        spin_lock_irqsave(&port->lock, flags);
        uart_circ_clear(&state->info->xmit);
+       if (port->ops->flush_buffer)
+               port->ops->flush_buffer(port);
        spin_unlock_irqrestore(&port->lock, flags);
        tty_wakeup(tty);
 }
index d8f31de632c5cb73e3d779086543ed100d8a736d..1d2faa6592aede261a4cdaf74c98959d4b722191 100644 (file)
@@ -190,6 +190,7 @@ struct uart_ops {
        void            (*break_ctl)(struct uart_port *, int ctl);
        int             (*startup)(struct uart_port *);
        void            (*shutdown)(struct uart_port *);
+       void            (*flush_buffer)(struct uart_port *);
        void            (*set_termios)(struct uart_port *, struct ktermios *new,
                                       struct ktermios *old);
        void            (*set_ldisc)(struct uart_port *);