619821
From 09ff2706109ce647d1fe59e99f44f96810d80b7c Mon Sep 17 00:00:00 2001
b28c64
From: Fam Zheng <famz@redhat.com>
619821
Date: Thu, 18 May 2017 09:21:24 +0200
b28c64
Subject: [PATCH 11/18] serial: reset thri_pending on IER writes with THRI=0
b28c64
b28c64
RH-Author: Fam Zheng <famz@redhat.com>
619821
Message-id: <20170518092131.16571-12-famz@redhat.com>
619821
Patchwork-id: 75302
619821
O-Subject: [RHEL-7.4 qemu-kvm PATCH v3 11/18] serial: reset thri_pending on IER writes with THRI=0
619821
Bugzilla: 1451470
b28c64
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
619821
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
b28c64
RH-Acked-by: Eduardo Habkost <ehabkost@redhat.com>
b28c64
b28c64
From: Paolo Bonzini <pbonzini@redhat.com>
b28c64
b28c64
This is responsible for failure of migration from 2.2 to 2.1, because
b28c64
thr_ipending is always one in practice.
b28c64
b28c64
serial.c is setting thr_ipending unconditionally.  However, thr_ipending
b28c64
is not used at all if THRI=0, and it will be overwritten again the next
b28c64
time THRE or THRI changes.  For that reason, we can set thr_ipending to
b28c64
zero every time THRI is reset.
b28c64
b28c64
There is disagreement on whether LSR.THRE should be resampled when IER.THRI
b28c64
goes from 1 to 1.  This patch does not touch the code, leaving that for
b28c64
QEMU 2.3+.
b28c64
b28c64
This has no semantic change and is enough to fix migration in the common
b28c64
case where the interrupt is not pending or is reported in IIR.  It does not
b28c64
change the migration format, so 2.2.0 -> 2.1 will remain broken but we
b28c64
can fix 2.2.1 -> 2.1 without breaking 2.2.1 <-> 2.2.0.
b28c64
b28c64
The case that remains broken (the one in which the subsection is strictly
b28c64
necessary) is when THRE=1, the THRI interrupt has *not* been acknowledged
b28c64
yet, and a higher-priority interrupt comes.  In this case, you need the
b28c64
subsection to tell the source that the lower-priority THRI interrupt is
b28c64
pending.  The subsection's breakage of migration, in this case, prevents
b28c64
continuing the VM on the destination with an invalid state.
b28c64
b28c64
Cc: qemu-stable@nongnu.org
b28c64
Reported-by: Igor Mammedov <imammedo@redhat.com>
b28c64
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
b28c64
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
b28c64
(cherry picked from commit 4e02b0fcf5c97579d0d3261c80c65abcf92870fe)
b28c64
Signed-off-by: Fam Zheng <famz@redhat.com>
b28c64
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
b28c64
---
b28c64
 hw/char/serial.c | 18 ++++++++++++++++--
b28c64
 1 file changed, 16 insertions(+), 2 deletions(-)
b28c64
b28c64
diff --git a/hw/char/serial.c b/hw/char/serial.c
b28c64
index 5ef9b95..15c628f 100644
b28c64
--- a/hw/char/serial.c
b28c64
+++ b/hw/char/serial.c
b28c64
@@ -320,10 +320,24 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
b28c64
                      s->poll_msl = 0;
b28c64
                 }
b28c64
             }
b28c64
-            if (s->lsr & UART_LSR_THRE) {
b28c64
+
b28c64
+            /* Turning on the THRE interrupt on IER can trigger the interrupt
b28c64
+             * if LSR.THRE=1, even if it had been masked before by reading IIR.
b28c64
+             * This is not in the datasheet, but Windows relies on it.  It is
b28c64
+             * unclear if THRE has to be resampled every time THRI becomes
b28c64
+             * 1, or only on the rising edge.  Bochs does the latter, and Windows
b28c64
+             * always toggles IER to all zeroes and back to all ones.  But for
b28c64
+             * now leave it as it has always been in QEMU.
b28c64
+             *
b28c64
+             * If IER.THRI is zero, thr_ipending is not used.  Set it to zero
b28c64
+             * so that the thr_ipending subsection is not migrated.
b28c64
+             */
b28c64
+            if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) {
b28c64
                 s->thr_ipending = 1;
b28c64
-                serial_update_irq(s);
b28c64
+            } else {
b28c64
+                s->thr_ipending = 0;
b28c64
             }
b28c64
+            serial_update_irq(s);
b28c64
         }
b28c64
         break;
b28c64
     case 2:
b28c64
-- 
b28c64
1.8.3.1
b28c64