From 8308fdf68db20a26d1f497999e0badfab808f8b6 Mon Sep 17 00:00:00 2001 From: liu chuansheng Date: Tue, 22 May 2012 23:50:50 +0800 Subject: [PATCH] mfd: Avoid access the hsu reg in !active state BZ: 37758 There is a rare case in function serial_hsu_stop_tx(), which will call pm_runtime_get() without sync, then access the hsu reg, it will cause fabric error. To fix it, like serial_hsu_stop_rx(), when in case of non-active runtime state, queue the stop tx command in qwork worker to do it. Change-Id: Id6aa540db20db532a2f4b56d770111b985b26756 Signed-off-by: liu chuansheng Reviewed-on: http://android.intel.com:8080/49633 Reviewed-by: Yang, Bin Reviewed-by: Du, Alek Tested-by: Tang, HaifengX Reviewed-by: buildbot Tested-by: buildbot --- drivers/tty/serial/mfd.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index 0dbc9bc..509917a 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c @@ -80,6 +80,7 @@ struct hsu_dma_chan { #define CMD_WB 2 #define CMD_TX 3 #define CMD_RX_STOP 4 +#define CMD_TX_STOP 5 /* to record the pin wakeup states */ #define PM_WAKEUP 1 @@ -561,10 +562,18 @@ static void serial_hsu_stop_tx(struct uart_port *port) struct uart_hsu_port *up = container_of(port, struct uart_hsu_port, port); struct hsu_dma_chan *txc = up->txc; + unsigned long flags; pm_runtime_get(up->dev); if (up->use_dma) { - chan_writel(txc, HSU_CH_CR, 0x0); + if (!hsu_port_is_active(up)) { + spin_lock_irqsave(&up->qlock, flags); + insert_q(up, CMD_TX_STOP, 0, 0); + spin_unlock_irqrestore(&up->qlock, flags); + schedule_work(&up->qwork); + } else { + chan_writel(txc, HSU_CH_CR, 0x0); + } up->dma_tx_on = 0; } else if (up->ier & UART_IER_THRI) { up->ier &= ~UART_IER_THRI; @@ -1762,6 +1771,9 @@ static void qwork(struct work_struct *work) case CMD_RX_STOP: chan_writel(up->rxc, HSU_CH_CR, 0x2); break; + case CMD_TX_STOP: + chan_writel(up->txc, HSU_CH_CR, 0x0); + break; default: dev_err(up->dev, "wrong queue cmd type!\n"); } -- 2.7.4