msm: tty: update receive room just before writing data to the ldisc
There is a corner case in the tty driver where the value of tty->receive_room is not being updated before writing data to the line discipline. When this happens, data is lost because of failure to re-submit any remaining data to the ldisc. This fix is dependent on a new tty flag that is set only when the tty driver is used for efs sync betweem the mdm modem and the applications processor. CRs-Fixed: 358868 Change-Id: I0ba02980504b4d8187b8c83111c2c883d194efa2 Signed-off-by: Joel King <joelking@codeaurora.org>
This commit is contained in:
@@ -418,6 +418,8 @@ static void flush_to_ldisc(struct work_struct *work)
|
|||||||
int count;
|
int count;
|
||||||
char *char_buf;
|
char *char_buf;
|
||||||
unsigned char *flag_buf;
|
unsigned char *flag_buf;
|
||||||
|
unsigned int left = 0;
|
||||||
|
unsigned int max_space;
|
||||||
|
|
||||||
count = head->commit - head->read;
|
count = head->commit - head->read;
|
||||||
if (!count) {
|
if (!count) {
|
||||||
@@ -432,10 +434,33 @@ static void flush_to_ldisc(struct work_struct *work)
|
|||||||
line discipline as we want to empty the queue */
|
line discipline as we want to empty the queue */
|
||||||
if (test_bit(TTY_FLUSHPENDING, &tty->flags))
|
if (test_bit(TTY_FLUSHPENDING, &tty->flags))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* update receive room */
|
||||||
|
spin_lock(&tty->read_lock);
|
||||||
|
if (tty->update_room_in_ldisc) {
|
||||||
|
if ((tty->read_cnt == N_TTY_BUF_SIZE - 1) &&
|
||||||
|
(tty->receive_room ==
|
||||||
|
N_TTY_BUF_SIZE - 1))
|
||||||
|
tty->rr_bug++;
|
||||||
|
left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
|
||||||
|
}
|
||||||
|
spin_unlock(&tty->read_lock);
|
||||||
|
|
||||||
if (!tty->receive_room)
|
if (!tty->receive_room)
|
||||||
break;
|
break;
|
||||||
if (count > tty->receive_room)
|
|
||||||
count = tty->receive_room;
|
if (tty->update_room_in_ldisc && !left) {
|
||||||
|
schedule_work(&tty->buf.work);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tty->update_room_in_ldisc)
|
||||||
|
max_space = min(left, tty->receive_room);
|
||||||
|
else
|
||||||
|
max_space = tty->receive_room;
|
||||||
|
|
||||||
|
if (count > max_space)
|
||||||
|
count = max_space;
|
||||||
char_buf = head->char_buf_ptr + head->read;
|
char_buf = head->char_buf_ptr + head->read;
|
||||||
flag_buf = head->flag_buf_ptr + head->read;
|
flag_buf = head->flag_buf_ptr + head->read;
|
||||||
head->read += count;
|
head->read += count;
|
||||||
|
|||||||
@@ -495,6 +495,7 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||||||
/* explicitly set the driver mode to raw */
|
/* explicitly set the driver mode to raw */
|
||||||
tty->raw = 1;
|
tty->raw = 1;
|
||||||
tty->real_raw = 1;
|
tty->real_raw = 1;
|
||||||
|
tty->update_room_in_ldisc = 1;
|
||||||
|
|
||||||
set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
|
set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
|
||||||
dbg("%s", __func__);
|
dbg("%s", __func__);
|
||||||
|
|||||||
@@ -282,8 +282,10 @@ struct tty_struct {
|
|||||||
struct winsize winsize; /* termios mutex */
|
struct winsize winsize; /* termios mutex */
|
||||||
unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
|
unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
|
||||||
unsigned char low_latency:1, warned:1;
|
unsigned char low_latency:1, warned:1;
|
||||||
|
unsigned char update_room_in_ldisc:1;
|
||||||
unsigned char ctrl_status; /* ctrl_lock */
|
unsigned char ctrl_status; /* ctrl_lock */
|
||||||
unsigned int receive_room; /* Bytes free for queue */
|
unsigned int receive_room; /* Bytes free for queue */
|
||||||
|
unsigned int rr_bug;
|
||||||
|
|
||||||
struct tty_struct *link;
|
struct tty_struct *link;
|
||||||
struct fasync_struct *fasync;
|
struct fasync_struct *fasync;
|
||||||
|
|||||||
Reference in New Issue
Block a user