Commit c284cf06 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+33 −5
Original line number Diff line number Diff line
@@ -522,6 +522,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
		return -EIO;

	while (count > 0) {
		int ret = 0;

		spin_lock_irqsave(&hp->lock, flags);

		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
		}

		if (hp->n_outbuf > 0)
			hvc_push(hp);
			ret = hvc_push(hp);

		spin_unlock_irqrestore(&hp->lock, flags);

		if (!ret)
			break;

		if (count) {
			if (hp->n_outbuf > 0)
				hvc_flush(hp);
@@ -623,6 +628,15 @@ static int hvc_chars_in_buffer(struct tty_struct *tty)
#define MAX_TIMEOUT		(2000)
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_WRITE	0x00000002

@@ -669,8 +683,8 @@ static int __hvc_poll(struct hvc_struct *hp, bool may_sleep)
	if (!hp->irq_requested)
		poll_mask |= HVC_POLL_READ;

 read_again:
	/* Read data if any */

	count = tty_buffer_request_room(&hp->port, N_INBUF);

	/* If flip is full, just reschedule a later read */
@@ -717,9 +731,23 @@ static int __hvc_poll(struct hvc_struct *hp, bool may_sleep)
#endif /* CONFIG_MAGIC_SYSRQ */
		tty_insert_flip_char(&hp->port, buf[i], 0);
	}
	if (n == count)
	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;
	read_total = n;

 out:
	/* Wakeup write queue if necessary */