| From 768dddfbe60ecc3a9a920101aa755804f8a5700e Mon Sep 17 00:00:00 2001 |
| From: Fam Zheng <famz@redhat.com> |
| Date: Thu, 18 May 2017 09:21:31 +0200 |
| Subject: [PATCH 18/18] serial: remove watch on reset |
| |
| RH-Author: Fam Zheng <famz@redhat.com> |
| Message-id: <20170518092131.16571-19-famz@redhat.com> |
| Patchwork-id: 75308 |
| O-Subject: [RHEL-7.4 qemu-kvm PATCH v3 18/18] serial: remove watch on reset |
| Bugzilla: 1451470 |
| RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com> |
| RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com> |
| RH-Acked-by: Eduardo Habkost <ehabkost@redhat.com> |
| |
| From: Paolo Bonzini <pbonzini@redhat.com> |
| |
| Otherwise, this can cause serial_xmit to be entered with LSR.TEMT=0, |
| which is invalid and causes an assertion failure. |
| |
| Reported-by: Bret Ketchum <bcketchum@gmail.com> |
| Tested-by: Bret Ketchum <bcketchum@gmail.com> |
| Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com> |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| (cherry picked from commit a1df76da57aa8772a75e7c49f8e3829d07b4c46c) |
| Signed-off-by: Fam Zheng <famz@redhat.com> |
| Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com> |
| |
| hw/char/serial.c | 16 ++++++++++++---- |
| include/hw/char/serial.h | 1 + |
| 2 files changed, 13 insertions(+), 4 deletions(-) |
| |
| diff --git a/hw/char/serial.c b/hw/char/serial.c |
| index 69fefb2..39de1ca 100644 |
| |
| |
| @@ -224,6 +224,7 @@ static gboolean serial_watch_cb(GIOChannel *chan, GIOCondition cond, |
| void *opaque) |
| { |
| SerialState *s = opaque; |
| + s->watch_tag = 0; |
| serial_xmit(s); |
| return FALSE; |
| } |
| @@ -254,10 +255,12 @@ static void serial_xmit(SerialState *s) |
| if (s->mcr & UART_MCR_LOOP) { |
| /* in loopback mode, say that we just received a char */ |
| serial_receive1(s, &s->tsr, 1); |
| - } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { |
| - if (s->tsr_retry < MAX_XMIT_RETRY && |
| - qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, |
| - serial_watch_cb, s) > 0) { |
| + } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1 && |
| + 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); |
| + if (s->watch_tag > 0) { |
| s->tsr_retry++; |
| return; |
| } |
| @@ -656,6 +659,11 @@ static void serial_reset(void *opaque) |
| { |
| SerialState *s = opaque; |
| |
| + if (s->watch_tag > 0) { |
| + g_source_remove(s->watch_tag); |
| + s->watch_tag = 0; |
| + } |
| + |
| s->rbr = 0; |
| s->ier = 0; |
| s->iir = UART_IIR_NO_INT; |
| diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h |
| index 2661f8c..19c7763 100644 |
| |
| |
| @@ -56,6 +56,7 @@ struct SerialState { |
| int it_shift; |
| int baudbase; |
| uint32_t tsr_retry; |
| + guint watch_tag; |
| uint32_t wakeup; |
| |
| /* Time when the last byte was successfully sent out of the tsr */ |
| -- |
| 1.8.3.1 |
| |