aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Pignat <marc.pignat@hevs.ch>2008-04-02 16:04:42 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-02 18:28:19 -0400
commit39d4c922b596633da86878b1a5cc881785b8e5fa (patch)
treec2100914ee0c73e3703905db1818c5f5fd04f97a
parentba0657ff0527bab83387e19eb98b423fcc290674 (diff)
atmel_serial: fix uart/console concurrent access
Strange chars appear on the serial port when a printk and a printf happens at the same time. This is caused by the pdc sending chars while atmel_console_write (called from printk) is executing Concurent access of uart and console to the same port leads to corrupted data to be transmitted, so disable tx dma (PDC) while writing to the console. Signed-off-by: Marc Pignat <marc.pignat@hevs.ch> Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/serial/atmel_serial.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index e99a28387505..430997e33fc4 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -107,6 +107,7 @@
107 107
108#define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR) 108#define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR)
109#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR) 109#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR)
110#define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR)
110 111
111static int (*atmel_open_hook)(struct uart_port *); 112static int (*atmel_open_hook)(struct uart_port *);
112static void (*atmel_close_hook)(struct uart_port *); 113static void (*atmel_close_hook)(struct uart_port *);
@@ -1275,6 +1276,7 @@ static void atmel_console_write(struct console *co, const char *s, u_int count)
1275{ 1276{
1276 struct uart_port *port = &atmel_ports[co->index].uart; 1277 struct uart_port *port = &atmel_ports[co->index].uart;
1277 unsigned int status, imr; 1278 unsigned int status, imr;
1279 unsigned int pdc_tx;
1278 1280
1279 /* 1281 /*
1280 * First, save IMR and then disable interrupts 1282 * First, save IMR and then disable interrupts
@@ -1282,6 +1284,10 @@ static void atmel_console_write(struct console *co, const char *s, u_int count)
1282 imr = UART_GET_IMR(port); 1284 imr = UART_GET_IMR(port);
1283 UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY); 1285 UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY);
1284 1286
1287 /* Store PDC transmit status and disable it */
1288 pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN;
1289 UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
1290
1285 uart_console_write(port, s, count, atmel_console_putchar); 1291 uart_console_write(port, s, count, atmel_console_putchar);
1286 1292
1287 /* 1293 /*
@@ -1291,6 +1297,11 @@ static void atmel_console_write(struct console *co, const char *s, u_int count)
1291 do { 1297 do {
1292 status = UART_GET_CSR(port); 1298 status = UART_GET_CSR(port);
1293 } while (!(status & ATMEL_US_TXRDY)); 1299 } while (!(status & ATMEL_US_TXRDY));
1300
1301 /* Restore PDC transmit status */
1302 if (pdc_tx)
1303 UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
1304
1294 /* set interrupts back the way they were */ 1305 /* set interrupts back the way they were */
1295 UART_PUT_IER(port, imr); 1306 UART_PUT_IER(port, imr);
1296} 1307}