diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2016-06-14 14:46:51 +0200 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2016-06-29 14:03:47 +0200 |
commit | 9f34a35e0020b0b2b2e21c086a486d7dfd18df4f (patch) | |
tree | 71634306618e72cfa9bab75006c1fe03a07a73e9 /hw/char/serial.c | |
parent | a1df76da57aa8772a75e7c49f8e3829d07b4c46c (diff) |
serial: reinstate watch after migration
Otherwise, a serial port can get stuck if it is migrated while flow control
is in effect.
Tested-by: Bret Ketchum <bcketchum@gmail.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw/char/serial.c')
-rw-r--r-- | hw/char/serial.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/hw/char/serial.c b/hw/char/serial.c index af39e8f867..3442f47d36 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -644,8 +644,29 @@ static int serial_post_load(void *opaque, int version_id) if (s->thr_ipending == -1) { s->thr_ipending = ((s->iir & UART_IIR_ID) == UART_IIR_THRI); } - if (s->tsr_retry > MAX_XMIT_RETRY) { - s->tsr_retry = MAX_XMIT_RETRY; + + if (s->tsr_retry > 0) { + /* tsr_retry > 0 implies LSR.TEMT = 0 (transmitter not empty). */ + if (s->lsr & UART_LSR_TEMT) { + error_report("inconsistent state in serial device " + "(tsr empty, tsr_retry=%d", s->tsr_retry); + return -1; + } + + if (s->tsr_retry > MAX_XMIT_RETRY) { + s->tsr_retry = MAX_XMIT_RETRY; + } + + assert(s->watch_tag == 0); + s->watch_tag = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, + serial_watch_cb, s); + } else { + /* tsr_retry == 0 implies LSR.TEMT = 1 (transmitter empty). */ + if (!(s->lsr & UART_LSR_TEMT)) { + error_report("inconsistent state in serial device " + "(tsr not empty, tsr_retry=0"); + return -1; + } } s->last_break_enable = (s->lcr >> 6) & 1; |