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
Unified · Split
| @@ -522,6 +522,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count · 521 unmodified lines | ||
| 522 | 522 | return -EIO; |
| 523 | 523 | |
| 524 | 524 | while (count > 0) { |
| 525 | + int ret = 0; | |
| 526 | + | |
| 525 | 527 | spin_lock_irqsave(&hp->lock, flags); |
| 526 | 528 | |
| 527 | 529 | 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 · 9 unmodified lines | ||
| 537 | 539 | } |
| 538 | 540 | |
| 539 | 541 | if (hp->n_outbuf > 0) |
| 540 | − hvc_push(hp); | |
| 542 | + ret = hvc_push(hp); | |
| 541 | 543 | |
| 542 | 544 | spin_unlock_irqrestore(&hp->lock, flags); |
| 543 | 545 | |
| 546 | + if (!ret) | |
| 547 | + break; | |
| 548 | + | |
| 544 | 549 | if (count) { |
| 545 | 550 | if (hp->n_outbuf > 0) |
| 546 | 551 | hvc_flush(hp); |
| @@ -623,6 +628,15 @@ static int hvc_chars_in_buffer(struct tty_struct *tty) · 76 unmodified lines | ||
| 623 | 628 | #define MAX_TIMEOUT (2000) |
| 624 | 629 | static u32 timeout = MIN_TIMEOUT; |
| 625 | 630 | |
| 631 | +/* | |
| 632 | + * Maximum number of bytes to get from the console driver if hvc_poll is | |
| 633 | + * called from driver (and can't sleep). Any more than this and we break | |
| 634 | + * and start polling with khvcd. This value was derived from from an OpenBMC | |
| 635 | + * console with the OPAL driver that results in about 0.25ms interrupts off | |
| 636 | + * latency. | |
| 637 | + */ | |
| 638 | +#define HVC_ATOMIC_READ_MAX 128 | |
| 639 | + | |
| 626 | 640 | #define HVC_POLL_READ 0x00000001 |
| 627 | 641 | #define HVC_POLL_WRITE 0x00000002 |
| 628 | 642 | |
| @@ -669,8 +683,8 @@ static int __hvc_poll(struct hvc_struct *hp, bool may_sleep) · 40 unmodified lines | ||
| 669 | 683 | if (!hp->irq_requested) |
| 670 | 684 | poll_mask |= HVC_POLL_READ; |
| 671 | 685 | |
| 686 | + read_again: | |
| 672 | 687 | /* Read data if any */ |
| 673 | − | |
| 674 | 688 | count = tty_buffer_request_room(&hp->port, N_INBUF); |
| 675 | 689 | |
| 676 | 690 | /* If flip is full, just reschedule a later read */ |
| @@ -717,9 +731,23 @@ static int __hvc_poll(struct hvc_struct *hp, bool may_sleep) · 40 unmodified lines | ||
| 717 | 731 | #endif /* CONFIG_MAGIC_SYSRQ */ |
| 718 | 732 | tty_insert_flip_char(&hp->port, buf[i], 0); |
| 719 | 733 | } |
| 720 | − if (n == count) | |
| 721 | − poll_mask |= HVC_POLL_READ; | |
| 722 | − read_total = n; | |
| 734 | + read_total += n; | |
| 735 | + | |
| 736 | + if (may_sleep) { | |
| 737 | + /* Keep going until the flip is full */ | |
| 738 | + spin_unlock_irqrestore(&hp->lock, flags); | |
| 739 | + cond_resched(); | |
| 740 | + spin_lock_irqsave(&hp->lock, flags); | |
| 741 | + goto read_again; | |
| 742 | + } else if (read_total < HVC_ATOMIC_READ_MAX) { | |
| 743 | + /* Break and defer if it's a large read in atomic */ | |
| 744 | + goto read_again; | |
| 745 | + } | |
| 746 | + | |
| 747 | + /* | |
| 748 | + * Latency break, schedule another poll immediately. | |
| 749 | + */ | |
| 750 | + poll_mask |= HVC_POLL_READ; | |
| 723 | 751 | |
| 724 | 752 | out: |
| 725 | 753 | /* Wakeup write queue if necessary */ |