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 <[email protected]>
---
Documentation/serial/driver | 11 +++++++++++
drivers/serial/serial_core.c | 2 ++
include/linux/serial_core.h | 1 +
3 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/Documentation/serial/driver b/Documentation/serial/driver
index 88ad615..77ba0af 100644
--- a/Documentation/serial/driver
+++ b/Documentation/serial/driver
@@ -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
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index c9b64e7..799f739 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -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);
}
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index d8f31de..1d2faa6 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -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 *);
--
1.5.5.4
Avoid dumping garbage to the serial port when the tty is flushed. This
tends to happen when rebooting from a serial console.
Signed-off-by: Haavard Skinnemoen <[email protected]>
---
drivers/serial/atmel_serial.c | 15 +++++++++++++++
1 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 42be8b0..7691f42 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -956,6 +956,20 @@ static void atmel_shutdown(struct uart_port *port)
}
/*
+ * Flush any TX data submitted for DMA. Called when the TX circular
+ * buffer is reset.
+ */
+static void atmel_flush_buffer(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ if (atmel_use_dma_tx(port)) {
+ UART_PUT_TCR(port, 0);
+ atmel_port->pdc_tx.ofs = 0;
+ }
+}
+
+/*
* Power / Clock management.
*/
static void atmel_serial_pm(struct uart_port *port, unsigned int state,
@@ -1189,6 +1203,7 @@ static struct uart_ops atmel_pops = {
.break_ctl = atmel_break_ctl,
.startup = atmel_startup,
.shutdown = atmel_shutdown,
+ .flush_buffer = atmel_flush_buffer,
.set_termios = atmel_set_termios,
.type = atmel_type,
.release_port = atmel_release_port,
--
1.5.5.4
On Mon, 30 Jun 2008 12:24:21 +0200
Haavard Skinnemoen <[email protected]> wrote:
> Avoid dumping garbage to the serial port when the tty is flushed. This
> tends to happen when rebooting from a serial console.
>
> Signed-off-by: Haavard Skinnemoen <[email protected]>
Acked-by: Alan Cox <[email protected]>
On Mon, 30 Jun 2008 12:24:20 +0200
Haavard Skinnemoen <[email protected]> wrote:
> 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 <[email protected]>
Acked-by: Alan Cox <[email protected]>