Blame SOURCES/kvm-serial-only-resample-THR-interrupt-on-rising-edge-of.patch

619821
From 0c6d2ffcebff88c6cda738aa46fa77c09b93b78b Mon Sep 17 00:00:00 2001
b28c64
From: Fam Zheng <famz@redhat.com>
619821
Date: Thu, 18 May 2017 09:21:27 +0200
b28c64
Subject: [PATCH 14/18] serial: only resample THR interrupt on rising edge of
b28c64
 IER.THRI
b28c64
b28c64
RH-Author: Fam Zheng <famz@redhat.com>
619821
Message-id: <20170518092131.16571-15-famz@redhat.com>
619821
Patchwork-id: 75304
619821
O-Subject: [RHEL-7.4 qemu-kvm PATCH v3 14/18] serial: only resample THR interrupt on rising edge of IER.THRI
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
There is disagreement on whether LSR.THRE should be resampled when
b28c64
IER.THRI goes from 1 to 1.  Bochs only does it if IER.THRI goes from 0
b28c64
to 1; PCE does it even if IER.THRI is unchanged.  But the Windows driver
b28c64
seems to always go from 1 to 0 and back to 1, so do things in agreement
b28c64
with Bochs, because the handling of thr_ipending was reported in 2010
b28c64
(https://lists.gnu.org/archive/html/qemu-devel/2010-03/msg01914.html)
b28c64
as breaking DR-DOS Plus.
b28c64
b28c64
Reported-by: Roy Tam <roytam@gmail.com>
b28c64
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
b28c64
(cherry picked from commit 1645b8eee558ffe2389a081bf61d08a864c36d2c)
b28c64
Signed-off-by: Fam Zheng <famz@redhat.com>
b28c64
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
b28c64
---
b28c64
 hw/char/serial.c | 25 ++++++++++++++++---------
b28c64
 1 file changed, 16 insertions(+), 9 deletions(-)
b28c64
b28c64
diff --git a/hw/char/serial.c b/hw/char/serial.c
b28c64
index e0d29a8..9986adf 100644
b28c64
--- a/hw/char/serial.c
b28c64
+++ b/hw/char/serial.c
b28c64
@@ -306,10 +306,12 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
b28c64
             s->divider = (s->divider & 0x00ff) | (val << 8);
b28c64
             serial_update_parameters(s);
b28c64
         } else {
b28c64
+            uint8_t changed = (s->ier ^ val) & 0x0f;
b28c64
             s->ier = val & 0x0f;
b28c64
             /* If the backend device is a real serial port, turn polling of the modem
b28c64
-               status lines on physical port on or off depending on UART_IER_MSI state */
b28c64
-            if (s->poll_msl >= 0) {
b28c64
+             * status lines on physical port on or off depending on UART_IER_MSI state.
b28c64
+             */
b28c64
+            if ((changed & UART_IER_MSI) && s->poll_msl >= 0) {
b28c64
                 if (s->ier & UART_IER_MSI) {
b28c64
                      s->poll_msl = 1;
b28c64
                      serial_update_msl(s);
b28c64
@@ -324,18 +326,23 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
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
+             * always toggles IER to all zeroes and back to all ones, so do the
b28c64
+             * same.
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
-            } else {
b28c64
-                s->thr_ipending = 0;
b28c64
+            if (changed & UART_IER_THRI) {
b28c64
+                if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) {
b28c64
+                    s->thr_ipending = 1;
b28c64
+                } else {
b28c64
+                    s->thr_ipending = 0;
b28c64
+                }
b28c64
+            }
b28c64
+
b28c64
+            if (changed) {
b28c64
+                serial_update_irq(s);
b28c64
             }
b28c64
-            serial_update_irq(s);
b28c64
         }
b28c64
         break;
b28c64
     case 2:
b28c64
-- 
b28c64
1.8.3.1
b28c64