Commit c284cf06 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tty-4.19-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty fixes from Greg KH:
 "Here are three small HVC tty driver fixes to resolve a reported
  regression from 4.19-rc1.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'tty-4.19-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  tty: hvc: hvc_write() fix break condition
  tty: hvc: hvc_poll() fix read loop batching
  tty: hvc: hvc_poll() fix read loop hang
parents 45d9ab8a 7f2bf784
...@@ -522,6 +522,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count ...@@ -522,6 +522,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
return -EIO; return -EIO;
while (count > 0) { while (count > 0) {
int ret = 0;
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
rsize = hp->outbuf_size - hp->n_outbuf; rsize = hp->outbuf_size - hp->n_outbuf;
...@@ -537,10 +539,13 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count ...@@ -537,10 +539,13 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
} }
if (hp->n_outbuf > 0) if (hp->n_outbuf > 0)
hvc_push(hp); ret = hvc_push(hp);
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
if (!ret)
break;
if (count) { if (count) {
if (hp->n_outbuf > 0) if (hp->n_outbuf > 0)
hvc_flush(hp); hvc_flush(hp);
...@@ -623,6 +628,15 @@ static int hvc_chars_in_buffer(struct tty_struct *tty) ...@@ -623,6 +628,15 @@ static int hvc_chars_in_buffer(struct tty_struct *tty)
#define MAX_TIMEOUT (2000) #define MAX_TIMEOUT (2000)
static u32 timeout = MIN_TIMEOUT; static u32 timeout = MIN_TIMEOUT;
/*
* Maximum number of bytes to get from the console driver if hvc_poll is
* called from driver (and can't sleep). Any more than this and we break
* and start polling with khvcd. This value was derived from from an OpenBMC
* console with the OPAL driver that results in about 0.25ms interrupts off
* latency.
*/
#define HVC_ATOMIC_READ_MAX 128
#define HVC_POLL_READ 0x00000001 #define HVC_POLL_READ 0x00000001
#define HVC_POLL_WRITE 0x00000002 #define HVC_POLL_WRITE 0x00000002
...@@ -669,8 +683,8 @@ static int __hvc_poll(struct hvc_struct *hp, bool may_sleep) ...@@ -669,8 +683,8 @@ static int __hvc_poll(struct hvc_struct *hp, bool may_sleep)
if (!hp->irq_requested) if (!hp->irq_requested)
poll_mask |= HVC_POLL_READ; poll_mask |= HVC_POLL_READ;
read_again:
/* Read data if any */ /* Read data if any */
count = tty_buffer_request_room(&hp->port, N_INBUF); count = tty_buffer_request_room(&hp->port, N_INBUF);
/* If flip is full, just reschedule a later read */ /* If flip is full, just reschedule a later read */
...@@ -717,9 +731,23 @@ static int __hvc_poll(struct hvc_struct *hp, bool may_sleep) ...@@ -717,9 +731,23 @@ static int __hvc_poll(struct hvc_struct *hp, bool may_sleep)
#endif /* CONFIG_MAGIC_SYSRQ */ #endif /* CONFIG_MAGIC_SYSRQ */
tty_insert_flip_char(&hp->port, buf[i], 0); tty_insert_flip_char(&hp->port, buf[i], 0);
} }
if (n == count) read_total += n;
poll_mask |= HVC_POLL_READ;
read_total = n; if (may_sleep) {
/* Keep going until the flip is full */
spin_unlock_irqrestore(&hp->lock, flags);
cond_resched();
spin_lock_irqsave(&hp->lock, flags);
goto read_again;
} else if (read_total < HVC_ATOMIC_READ_MAX) {
/* Break and defer if it's a large read in atomic */
goto read_again;
}
/*
* Latency break, schedule another poll immediately.
*/
poll_mask |= HVC_POLL_READ;
out: out:
/* Wakeup write queue if necessary */ /* Wakeup write queue if necessary */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment