summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Sanchez <carlos.sanchez@gecoinc.com>2007-07-31 00:38:59 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-31 15:39:41 -0700
commit6c1ead5e77c4e41d58ae6e6c3285ad38275df4a8 (patch)
treeb0928bdda2320b4ac81b4f350aed9d0006efc732
parent817794e0df5fea495396c18878804044436832be (diff)
downloadlinux-3.10-6c1ead5e77c4e41d58ae6e6c3285ad38275df4a8.tar.gz
linux-3.10-6c1ead5e77c4e41d58ae6e6c3285ad38275df4a8.tar.bz2
linux-3.10-6c1ead5e77c4e41d58ae6e6c3285ad38275df4a8.zip
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>
-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 00924feaf62..567fa789c5c 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -1363,8 +1363,6 @@ mpsc_start_rx(struct mpsc_port_info *pi)
{
pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line);
- /* Issue a Receive Abort to clear any receive errors */
- writel(MPSC_CHR_2_RA, pi->mpsc_base + MPSC_CHR_2);
if (pi->rcv_data) {
mpsc_enter_hunt(pi);
mpsc_sdma_cmd(pi, SDMA_SDCM_ERD);
@@ -1379,6 +1377,20 @@ mpsc_stop_rx(struct uart_port *port)
pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line);
+ if (pi->mirror_regs) {
+ writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_RA,
+ pi->mpsc_base + MPSC_CHR_2);
+ /* Erratum prevents reading CHR_2 so just delay for a while */
+ udelay(100);
+ }
+ else {
+ writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_RA,
+ pi->mpsc_base + MPSC_CHR_2);
+
+ while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_RA)
+ udelay(10);
+ }
+
mpsc_sdma_cmd(pi, SDMA_SDCM_AR);
return;
}