aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/mpsc.c
diff options
context:
space:
mode:
authorCarlos Sanchez <carlos.sanchez@gecoinc.com>2007-07-31 03:38:59 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-31 18:39:41 -0400
commit6c1ead5e77c4e41d58ae6e6c3285ad38275df4a8 (patch)
treeb0928bdda2320b4ac81b4f350aed9d0006efc732 /drivers/serial/mpsc.c
parent817794e0df5fea495396c18878804044436832be (diff)
serial: MPSC: Remove race between Rx stop & restart
The patch in commit ID f7232056bff5fe2d3bfeab35252a66ebaeb5bbde stops (aborts) the MPSC's receive engine just before restarting it. Unfortunately, it doesn't wait for the abort to complete before restarting it which creates a race between the abort and the restart. If the restart occurs first, the in-progress abort stops it again and the rx engine remains stopped. Instead, do the abort when the SDMA engine is being stopped. Make sure to wait for the abort to complete before continuing. Signed-off-by: Carlos Sanchez <carlos.sanchez@gecoinc.com> Signed-off-by: Mark A. Greer <mgreer@mvista.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/serial/mpsc.c')
-rw-r--r--drivers/serial/mpsc.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index 00924feaf621..567fa789c5c7 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -1363,8 +1363,6 @@ mpsc_start_rx(struct mpsc_port_info *pi)
1363{ 1363{
1364 pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line); 1364 pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line);
1365 1365
1366 /* Issue a Receive Abort to clear any receive errors */
1367 writel(MPSC_CHR_2_RA, pi->mpsc_base + MPSC_CHR_2);
1368 if (pi->rcv_data) { 1366 if (pi->rcv_data) {
1369 mpsc_enter_hunt(pi); 1367 mpsc_enter_hunt(pi);
1370 mpsc_sdma_cmd(pi, SDMA_SDCM_ERD); 1368 mpsc_sdma_cmd(pi, SDMA_SDCM_ERD);
@@ -1379,6 +1377,20 @@ mpsc_stop_rx(struct uart_port *port)
1379 1377
1380 pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line); 1378 pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line);
1381 1379
1380 if (pi->mirror_regs) {
1381 writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_RA,
1382 pi->mpsc_base + MPSC_CHR_2);
1383 /* Erratum prevents reading CHR_2 so just delay for a while */
1384 udelay(100);
1385 }
1386 else {
1387 writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_RA,
1388 pi->mpsc_base + MPSC_CHR_2);
1389
1390 while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_RA)
1391 udelay(10);
1392 }
1393
1382 mpsc_sdma_cmd(pi, SDMA_SDCM_AR); 1394 mpsc_sdma_cmd(pi, SDMA_SDCM_AR);
1383 return; 1395 return;
1384} 1396}