summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
authorGirish Mahadevan <girishm@codeaurora.org>2016-04-15 15:08:07 -0600
committerMukesh Kumar Savaliya <msavaliy@codeaurora.org>2016-07-12 19:41:59 +0530
commitb663776b59caf5b9ed14693fec01fa9a47a907b7 (patch)
treef4664b616ed29a4000217dd6674e93cda1f0a9c2 /drivers/tty
parent400520a6e2f06cc7c45e386e769a85d4aded565b (diff)
msm_serial_hs: Add defensive checks due to sudden port close
In certain scenarios, it is possible for a close to be called on the tty port while the rx thread is still processing. In certain scenarios a race between the 2 threads could lead to unexpected results such as making BAM API calls after the pipes are disconnected or the thread accessing the framework structures after they're freed. Add defensive checks to: - Check the state of the rx pipes and tty before running the rx work thread. - When closing the port, flush the rx work thread and wait till there are no pending buffers before forcing a close. Currently the shutdown waits on the flush state of the rx pipe to be in SHUTDOWN , but this only happens after the rx thread runs, kicks the runtime pm which puts it in the SHUTDOWN state. But since the port close calls the runtime pm suspend callback, just wait on the thread to finish the buffer. Change-Id: Ibf56e1aeb0c6811fec36f7618933d74c367ed305 Signed-off-by: Girish Mahadevan <girishm@codeaurora.org> Signed-off-by: Mukesh Kumar Savaliya <msavaliy@codeaurora.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/msm_serial_hs.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 6843711774b2..75cb4771d908 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1576,6 +1576,16 @@ static void flip_insert_work(struct work_struct *work)
struct tty_struct *tty = msm_uport->uport.state->port.tty;
spin_lock_irqsave(&msm_uport->uport.lock, flags);
+ if (!tty || msm_uport->rx.flush == FLUSH_SHUTDOWN) {
+ dev_err(msm_uport->uport.dev,
+ "%s:Invalid driver state flush %d\n",
+ __func__, msm_uport->rx.flush);
+ MSM_HS_ERR("%s:Invalid driver state flush %d\n",
+ __func__, msm_uport->rx.flush);
+ spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
+ return;
+ }
+
if (msm_uport->rx.buffer_pending == NONE_PENDING) {
MSM_HS_ERR("Error: No buffer pending in %s", __func__);
spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
@@ -1648,6 +1658,16 @@ static void msm_serial_hs_rx_work(struct kthread_work *work)
spin_lock_irqsave(&uport->lock, flags);
+ if (!tty || rx->flush == FLUSH_SHUTDOWN) {
+ dev_err(uport->dev, "%s:Invalid driver state flush %d\n",
+ __func__, rx->flush);
+ MSM_HS_ERR("%s:Invalid driver state flush %d\n",
+ __func__, rx->flush);
+ spin_unlock_irqrestore(&uport->lock, flags);
+ msm_hs_resource_unvote(msm_uport);
+ return;
+ }
+
/*
* Process all pending descs or if nothing is
* queued - called from termios
@@ -3582,12 +3602,12 @@ static void msm_hs_shutdown(struct uart_port *uport)
if (msm_uport->rx.flush != FLUSH_SHUTDOWN) {
/* disable and disconnect rx */
- msm_hs_disconnect_rx(uport);
ret = wait_event_timeout(msm_uport->rx.wait,
- msm_uport->rx.flush == FLUSH_SHUTDOWN, 500);
+ !msm_uport->rx.pending_flag, 500);
if (!ret)
MSM_HS_WARN("%s(): rx disconnect not complete",
__func__);
+ msm_hs_disconnect_rx(uport);
}
cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work);