[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 40/47] serial: clean up THRE/TEMT handling
From: |
Paolo Bonzini |
Subject: |
[Qemu-devel] [PULL 40/47] serial: clean up THRE/TEMT handling |
Date: |
Mon, 15 Dec 2014 17:38:24 +0100 |
- assert TEMT is cleared before sending a character; we'll get one from
TSR if tsr_retry > 0, from the FIFO or THR otherwise
- assert THRE cleared and FIFO not empty (if enabled) before fetching a
character to send. This effectively reverts dffacd46, but the check
makes no sense and commit f702e62 (serial: change retry logic to avoid
concurrency, 2014-07-11) must have made it unnecessary. The commit
message for f702e62 talks about multiple calls to qemu_chr_fe_add_watch
triggering s->tsr_retry >= MAX_XMIT_RETRY, but other failures were
possible. For example, if you have multiple calls, the subsequent ones
will see s->tsr_retry == 0 and will find THRE and/or TEMT on entry.
- for clarity, raise THRI immediately after the code sets THRE
- check THRE to see if another character has to be sent. This makes
the assertions more obvious and also means TEMT has to be set as soon as
the loop ends. It makes the loop send both TSR and THR if flow-control
happens in non-FIFO mode. Previously, THR would be lost.
- clear TEMT together with THRE even in the non-FIFO case
The last two items are bugfixes, but they were just found by inspection
and do not squash known bugs.
Reviewed-by: Dr. David Alan Gilbert <address@hidden>
Signed-off-by: Paolo Bonzini <address@hidden>
---
hw/char/serial.c | 26 ++++++++++++--------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 8c42d03..9adb126 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -224,21 +224,23 @@ static gboolean serial_xmit(GIOChannel *chan,
GIOCondition cond, void *opaque)
SerialState *s = opaque;
do {
+ assert(!(s->lsr & UART_LSR_TEMT));
if (s->tsr_retry <= 0) {
+ assert(!(s->lsr & UART_LSR_THRE));
+
if (s->fcr & UART_FCR_FE) {
- if (fifo8_is_empty(&s->xmit_fifo)) {
- return FALSE;
- }
+ assert(!fifo8_is_empty(&s->xmit_fifo));
s->tsr = fifo8_pop(&s->xmit_fifo);
if (!s->xmit_fifo.num) {
s->lsr |= UART_LSR_THRE;
}
- } else if ((s->lsr & UART_LSR_THRE)) {
- return FALSE;
} else {
s->tsr = s->thr;
s->lsr |= UART_LSR_THRE;
- s->lsr &= ~UART_LSR_TEMT;
+ }
+ if ((s->lsr & UART_LSR_THRE) && !s->thr_ipending) {
+ s->thr_ipending = 1;
+ serial_update_irq(s);
}
}
@@ -256,17 +258,13 @@ static gboolean serial_xmit(GIOChannel *chan,
GIOCondition cond, void *opaque)
} else {
s->tsr_retry = 0;
}
+
/* Transmit another byte if it is already available. It is only
possible when FIFO is enabled and not empty. */
- } while ((s->fcr & UART_FCR_FE) && !fifo8_is_empty(&s->xmit_fifo));
+ } while (!(s->lsr & UART_LSR_THRE));
s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- if (s->lsr & UART_LSR_THRE) {
- s->lsr |= UART_LSR_TEMT;
- s->thr_ipending = 1;
- serial_update_irq(s);
- }
+ s->lsr |= UART_LSR_TEMT;
return FALSE;
}
@@ -323,10 +321,10 @@ static void serial_ioport_write(void *opaque, hwaddr
addr, uint64_t val,
fifo8_pop(&s->xmit_fifo);
}
fifo8_push(&s->xmit_fifo, s->thr);
- s->lsr &= ~UART_LSR_TEMT;
}
s->thr_ipending = 0;
s->lsr &= ~UART_LSR_THRE;
+ s->lsr &= ~UART_LSR_TEMT;
serial_update_irq(s);
if (s->tsr_retry <= 0) {
serial_xmit(NULL, G_IO_OUT, s);
--
1.8.3.1
- [Qemu-devel] [PULL 30/47] timer: introduce new QEMU_CLOCK_VIRTUAL_RT clock, (continued)
- [Qemu-devel] [PULL 30/47] timer: introduce new QEMU_CLOCK_VIRTUAL_RT clock, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 31/47] cpus: make icount warp behave well with respect to stop/cont, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 32/47] i386: do not cross the pages boundaries in replay mode, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 34/47] target-i386: add VME to all CPUs, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 33/47] pc: add 2.3 machine types, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 35/47] target-i386: add f16c and rdrand to Haswell and Broadwell, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 36/47] target-i386: add Ivy Bridge CPU model, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 38/47] linuxboot: fix loading old kernels, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 37/47] kvm/apic: fix 2.2->2.1 migration, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 39/47] serial: reset thri_pending on IER writes with THRI=0, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 40/47] serial: clean up THRE/TEMT handling,
Paolo Bonzini <=
- [Qemu-devel] [PULL 42/47] serial: only resample THR interrupt on rising edge of IER.THRI, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 41/47] serial: update LSR on enabling/disabling FIFOs, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 43/47] sdhci: Set a default frequency clock, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 44/47] sdhci: Remove class "virtual" methods, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 45/47] sdhci: Add "sysbus" to sdhci QOM types and methods, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 46/47] sdhci: Define SDHCI PCI ids, Paolo Bonzini, 2014/12/15
- [Qemu-devel] [PULL 47/47] sdhci: Support SDHCI devices on PCI, Paolo Bonzini, 2014/12/15
- Re: [Qemu-devel] [PULL 00/47] Patches for KVM, x86, SCSI, migration fixes (2014-12-15), Peter Maydell, 2014/12/16