|
|
b28c64 |
From 9afba2b1b9f8c2af3165fb0d9b68888996fe2330 Mon Sep 17 00:00:00 2001
|
|
|
b28c64 |
From: Fam Zheng <famz@redhat.com>
|
|
|
b28c64 |
Date: Fri, 19 May 2017 00:35:17 +0200
|
|
|
b28c64 |
Subject: [PATCH 12/18] serial: clean up THRE/TEMT handling
|
|
|
b28c64 |
|
|
|
b28c64 |
RH-Author: Fam Zheng <famz@redhat.com>
|
|
|
b28c64 |
Message-id: <20170519003523.21163-13-famz@redhat.com>
|
|
|
b28c64 |
Patchwork-id: 75367
|
|
|
b28c64 |
O-Subject: [RHEL-7.3.z qemu-kvm PATCH 12/18] serial: clean up THRE/TEMT handling
|
|
|
b28c64 |
Bugzilla: 1452332
|
|
|
b28c64 |
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
b28c64 |
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
|
|
|
b28c64 |
RH-Acked-by: Eduardo Habkost <ehabkost@redhat.com>
|
|
|
b28c64 |
|
|
|
b28c64 |
From: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
b28c64 |
|
|
|
b28c64 |
- assert TEMT is cleared before sending a character; we'll get one from
|
|
|
b28c64 |
TSR if tsr_retry > 0, from the FIFO or THR otherwise
|
|
|
b28c64 |
|
|
|
b28c64 |
- assert THRE cleared and FIFO not empty (if enabled) before fetching a
|
|
|
b28c64 |
character to send. This effectively reverts dffacd46, but the check
|
|
|
b28c64 |
makes no sense and commit f702e62 (serial: change retry logic to avoid
|
|
|
b28c64 |
concurrency, 2014-07-11) must have made it unnecessary. The commit
|
|
|
b28c64 |
message for f702e62 talks about multiple calls to qemu_chr_fe_add_watch
|
|
|
b28c64 |
triggering s->tsr_retry >= MAX_XMIT_RETRY, but other failures were
|
|
|
b28c64 |
possible. For example, if you have multiple calls, the subsequent ones
|
|
|
b28c64 |
will see s->tsr_retry == 0 and will find THRE and/or TEMT on entry.
|
|
|
b28c64 |
|
|
|
b28c64 |
- for clarity, raise THRI immediately after the code sets THRE
|
|
|
b28c64 |
|
|
|
b28c64 |
- check THRE to see if another character has to be sent. This makes
|
|
|
b28c64 |
the assertions more obvious and also means TEMT has to be set as soon as
|
|
|
b28c64 |
the loop ends. It makes the loop send both TSR and THR if flow-control
|
|
|
b28c64 |
happens in non-FIFO mode. Previously, THR would be lost.
|
|
|
b28c64 |
|
|
|
b28c64 |
- clear TEMT together with THRE even in the non-FIFO case
|
|
|
b28c64 |
|
|
|
b28c64 |
The last two items are bugfixes, but they were just found by inspection
|
|
|
b28c64 |
and do not squash known bugs.
|
|
|
b28c64 |
|
|
|
b28c64 |
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
|
|
b28c64 |
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
b28c64 |
(cherry picked from commit 0d931d706266d6ada3bf22d3afca1afdc8d12fa9)
|
|
|
b28c64 |
Signed-off-by: Fam Zheng <famz@redhat.com>
|
|
|
b28c64 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
b28c64 |
|
|
|
b28c64 |
Conflicts:
|
|
|
b28c64 |
hw/char/serial.c
|
|
|
b28c64 |
|
|
|
b28c64 |
Contextual conflict because upstream has the new timer API
|
|
|
b28c64 |
qemu_clock_get_ns, but downstream still uses qemu_get_clock_ns.
|
|
|
b28c64 |
---
|
|
|
b28c64 |
hw/char/serial.c | 26 ++++++++++++--------------
|
|
|
b28c64 |
1 file changed, 12 insertions(+), 14 deletions(-)
|
|
|
b28c64 |
|
|
|
b28c64 |
diff --git a/hw/char/serial.c b/hw/char/serial.c
|
|
|
b28c64 |
index 15c628f..c2be4bd 100644
|
|
|
b28c64 |
--- a/hw/char/serial.c
|
|
|
b28c64 |
+++ b/hw/char/serial.c
|
|
|
b28c64 |
@@ -224,21 +224,23 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
|
|
|
b28c64 |
SerialState *s = opaque;
|
|
|
b28c64 |
|
|
|
b28c64 |
do {
|
|
|
b28c64 |
+ assert(!(s->lsr & UART_LSR_TEMT));
|
|
|
b28c64 |
if (s->tsr_retry <= 0) {
|
|
|
b28c64 |
+ assert(!(s->lsr & UART_LSR_THRE));
|
|
|
b28c64 |
+
|
|
|
b28c64 |
if (s->fcr & UART_FCR_FE) {
|
|
|
b28c64 |
- if (fifo8_is_empty(&s->xmit_fifo)) {
|
|
|
b28c64 |
- return FALSE;
|
|
|
b28c64 |
- }
|
|
|
b28c64 |
+ assert(!fifo8_is_empty(&s->xmit_fifo));
|
|
|
b28c64 |
s->tsr = fifo8_pop(&s->xmit_fifo);
|
|
|
b28c64 |
if (!s->xmit_fifo.num) {
|
|
|
b28c64 |
s->lsr |= UART_LSR_THRE;
|
|
|
b28c64 |
}
|
|
|
b28c64 |
- } else if ((s->lsr & UART_LSR_THRE)) {
|
|
|
b28c64 |
- return FALSE;
|
|
|
b28c64 |
} else {
|
|
|
b28c64 |
s->tsr = s->thr;
|
|
|
b28c64 |
s->lsr |= UART_LSR_THRE;
|
|
|
b28c64 |
- s->lsr &= ~UART_LSR_TEMT;
|
|
|
b28c64 |
+ }
|
|
|
b28c64 |
+ if ((s->lsr & UART_LSR_THRE) && !s->thr_ipending) {
|
|
|
b28c64 |
+ s->thr_ipending = 1;
|
|
|
b28c64 |
+ serial_update_irq(s);
|
|
|
b28c64 |
}
|
|
|
b28c64 |
}
|
|
|
b28c64 |
|
|
|
b28c64 |
@@ -256,17 +258,13 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
|
|
|
b28c64 |
} else {
|
|
|
b28c64 |
s->tsr_retry = 0;
|
|
|
b28c64 |
}
|
|
|
b28c64 |
+
|
|
|
b28c64 |
/* Transmit another byte if it is already available. It is only
|
|
|
b28c64 |
possible when FIFO is enabled and not empty. */
|
|
|
b28c64 |
- } while ((s->fcr & UART_FCR_FE) && !fifo8_is_empty(&s->xmit_fifo));
|
|
|
b28c64 |
+ } while (!(s->lsr & UART_LSR_THRE));
|
|
|
b28c64 |
|
|
|
b28c64 |
s->last_xmit_ts = qemu_get_clock_ns(vm_clock);
|
|
|
b28c64 |
-
|
|
|
b28c64 |
- if (s->lsr & UART_LSR_THRE) {
|
|
|
b28c64 |
- s->lsr |= UART_LSR_TEMT;
|
|
|
b28c64 |
- s->thr_ipending = 1;
|
|
|
b28c64 |
- serial_update_irq(s);
|
|
|
b28c64 |
- }
|
|
|
b28c64 |
+ s->lsr |= UART_LSR_TEMT;
|
|
|
b28c64 |
|
|
|
b28c64 |
return FALSE;
|
|
|
b28c64 |
}
|
|
|
b28c64 |
@@ -293,10 +291,10 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|
|
b28c64 |
fifo8_pop(&s->xmit_fifo);
|
|
|
b28c64 |
}
|
|
|
b28c64 |
fifo8_push(&s->xmit_fifo, s->thr);
|
|
|
b28c64 |
- s->lsr &= ~UART_LSR_TEMT;
|
|
|
b28c64 |
}
|
|
|
b28c64 |
s->thr_ipending = 0;
|
|
|
b28c64 |
s->lsr &= ~UART_LSR_THRE;
|
|
|
b28c64 |
+ s->lsr &= ~UART_LSR_TEMT;
|
|
|
b28c64 |
serial_update_irq(s);
|
|
|
b28c64 |
if (s->tsr_retry <= 0) {
|
|
|
b28c64 |
serial_xmit(NULL, G_IO_OUT, s);
|
|
|
b28c64 |
--
|
|
|
b28c64 |
1.8.3.1
|
|
|
b28c64 |
|