serial: msm_serial_hs: Add extra delay during close with pending tx

In some cases the userspace can do a back to back write() followed by
close(). In such cases the tty framework does account for this by asking
the driver the status of the tx buffer and if not empty wait for a timeout
computed as a function of the current port baud rate.

However in some cases, this timeout doesn't seem sufficient, so when
checking the state of the tx buffer insert an extra delay if not empty
before returning to the framework. This will do a double wait at driver
and at framework, but this shouldn't adversely affect timing of usecases
and the flip side of having a pending byte in the tx buffer can result
in the peer hardware being left in a bad state.

Change-Id: I372e2e1c68f13f5d537ea33980eb63487f31d589
CRs-Fixed: 1044170
Signed-off-by: Girish Mahadevan <girishm@codeaurora.org>
This commit is contained in:
Girish Mahadevan 2016-07-21 16:03:08 -06:00
parent e94b446eac
commit d64c7bb096

View file

@ -44,6 +44,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
@ -1237,16 +1238,27 @@ static void msm_hs_set_termios(struct uart_port *uport,
unsigned int msm_hs_tx_empty(struct uart_port *uport) unsigned int msm_hs_tx_empty(struct uart_port *uport)
{ {
unsigned int data; unsigned int data;
unsigned int isr;
unsigned int ret = 0; unsigned int ret = 0;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
msm_hs_resource_vote(msm_uport); msm_hs_resource_vote(msm_uport);
data = msm_hs_read(uport, UART_DM_SR); data = msm_hs_read(uport, UART_DM_SR);
isr = msm_hs_read(uport, UART_DM_ISR);
msm_hs_resource_unvote(msm_uport); msm_hs_resource_unvote(msm_uport);
MSM_HS_DBG("%s(): SR Reg Read 0x%x", __func__, data); MSM_HS_INFO("%s(): SR:0x%x ISR:0x%x ", __func__, data, isr);
if (data & UARTDM_SR_TXEMT_BMSK) if (data & UARTDM_SR_TXEMT_BMSK) {
ret = TIOCSER_TEMT; ret = TIOCSER_TEMT;
} else
/*
* Add an extra sleep here because sometimes the framework's
* delay (based on baud rate) isn't good enough.
* Note that this won't happen during every port close, only
* on select occassions when the userspace does back to back
* write() and close().
*/
usleep_range(5000, 7000);
return ret; return ret;
} }