|
|
619821 |
From 7d2e8f9662feb64c0b15b6fd53e06e3c56921f27 Mon Sep 17 00:00:00 2001
|
|
|
619821 |
From: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
619821 |
Date: Fri, 9 Jun 2017 11:43:58 +0200
|
|
|
619821 |
Subject: [PATCH 3/6] serial: fixing vmstate for save/restore
|
|
|
619821 |
|
|
|
619821 |
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
619821 |
Message-id: <20170609114359.13036-3-pbonzini@redhat.com>
|
|
|
619821 |
Patchwork-id: 75567
|
|
|
619821 |
O-Subject: [RHEL7.4 qemu-kvm PATCH v2 2/3] serial: fixing vmstate for save/restore
|
|
|
619821 |
Bugzilla: 1452067
|
|
|
619821 |
RH-Acked-by: David Hildenbrand <david@redhat.com>
|
|
|
619821 |
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
|
|
619821 |
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
619821 |
|
|
|
619821 |
From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
|
|
|
619821 |
|
|
|
619821 |
Some fields were added to VMState by this patch to preserve correct
|
|
|
619821 |
loading of the serial port controller state.
|
|
|
619821 |
Updating FCR value while loading was also modified to disable generating
|
|
|
619821 |
an interrupt by loadvm.
|
|
|
619821 |
|
|
|
619821 |
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
|
|
|
619821 |
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
619821 |
(cherry picked from commit 7385b275d9ae8bdf3c012bc4e2ae9779fcea6312)
|
|
|
619821 |
|
|
|
619821 |
[RHEL: omit some subsections. thr_ipending can be reconstructed fairly
|
|
|
619821 |
reliably by serial_post_load. The others are features that are
|
|
|
619821 |
unlikely to be used in RHEL, respectively receive timeout (Linux
|
|
|
619821 |
does not even have the UART_IIR_CTI symbol in the driver) and
|
|
|
619821 |
physical serial ports connected to a modem]
|
|
|
619821 |
|
|
|
619821 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
619821 |
---
|
|
|
619821 |
hw/char/serial.c | 245 ++++++++++++++++++++++++++++++++++++++++++++++++-------
|
|
|
619821 |
1 file changed, 215 insertions(+), 30 deletions(-)
|
|
|
619821 |
|
|
|
619821 |
diff --git a/hw/char/serial.c b/hw/char/serial.c
|
|
|
619821 |
index 39de1ca..0518a6f 100644
|
|
|
619821 |
--- a/hw/char/serial.c
|
|
|
619821 |
+++ b/hw/char/serial.c
|
|
|
619821 |
@@ -275,6 +275,36 @@ static void serial_xmit(SerialState *s)
|
|
|
619821 |
s->lsr |= UART_LSR_TEMT;
|
|
|
619821 |
}
|
|
|
619821 |
|
|
|
619821 |
+/* Setter for FCR.
|
|
|
619821 |
+ is_load flag means, that value is set while loading VM state
|
|
|
619821 |
+ and interrupt should not be invoked */
|
|
|
619821 |
+static void serial_write_fcr(SerialState *s, uint8_t val)
|
|
|
619821 |
+{
|
|
|
619821 |
+ /* Set fcr - val only has the bits that are supposed to "stick" */
|
|
|
619821 |
+ s->fcr = val;
|
|
|
619821 |
+
|
|
|
619821 |
+ if (val & UART_FCR_FE) {
|
|
|
619821 |
+ s->iir |= UART_IIR_FE;
|
|
|
619821 |
+ /* Set recv_fifo trigger Level */
|
|
|
619821 |
+ switch (val & 0xC0) {
|
|
|
619821 |
+ case UART_FCR_ITL_1:
|
|
|
619821 |
+ s->recv_fifo_itl = 1;
|
|
|
619821 |
+ break;
|
|
|
619821 |
+ case UART_FCR_ITL_2:
|
|
|
619821 |
+ s->recv_fifo_itl = 4;
|
|
|
619821 |
+ break;
|
|
|
619821 |
+ case UART_FCR_ITL_3:
|
|
|
619821 |
+ s->recv_fifo_itl = 8;
|
|
|
619821 |
+ break;
|
|
|
619821 |
+ case UART_FCR_ITL_4:
|
|
|
619821 |
+ s->recv_fifo_itl = 14;
|
|
|
619821 |
+ break;
|
|
|
619821 |
+ }
|
|
|
619821 |
+ } else {
|
|
|
619821 |
+ s->iir &= ~UART_IIR_FE;
|
|
|
619821 |
+ }
|
|
|
619821 |
+}
|
|
|
619821 |
+
|
|
|
619821 |
static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|
|
619821 |
unsigned size)
|
|
|
619821 |
{
|
|
|
619821 |
@@ -351,21 +381,17 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|
|
619821 |
}
|
|
|
619821 |
break;
|
|
|
619821 |
case 2:
|
|
|
619821 |
- val = val & 0xFF;
|
|
|
619821 |
-
|
|
|
619821 |
- if (s->fcr == val)
|
|
|
619821 |
- break;
|
|
|
619821 |
-
|
|
|
619821 |
/* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
|
|
|
619821 |
- if ((val ^ s->fcr) & UART_FCR_FE)
|
|
|
619821 |
+ if ((val ^ s->fcr) & UART_FCR_FE) {
|
|
|
619821 |
val |= UART_FCR_XFR | UART_FCR_RFR;
|
|
|
619821 |
+ }
|
|
|
619821 |
|
|
|
619821 |
/* FIFO clear */
|
|
|
619821 |
|
|
|
619821 |
if (val & UART_FCR_RFR) {
|
|
|
619821 |
s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
|
|
|
619821 |
qemu_del_timer(s->fifo_timeout_timer);
|
|
|
619821 |
- s->timeout_ipending=0;
|
|
|
619821 |
+ s->timeout_ipending = 0;
|
|
|
619821 |
fifo8_reset(&s->recv_fifo);
|
|
|
619821 |
}
|
|
|
619821 |
|
|
|
619821 |
@@ -375,28 +401,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|
|
619821 |
fifo8_reset(&s->xmit_fifo);
|
|
|
619821 |
}
|
|
|
619821 |
|
|
|
619821 |
- if (val & UART_FCR_FE) {
|
|
|
619821 |
- s->iir |= UART_IIR_FE;
|
|
|
619821 |
- /* Set recv_fifo trigger Level */
|
|
|
619821 |
- switch (val & 0xC0) {
|
|
|
619821 |
- case UART_FCR_ITL_1:
|
|
|
619821 |
- s->recv_fifo_itl = 1;
|
|
|
619821 |
- break;
|
|
|
619821 |
- case UART_FCR_ITL_2:
|
|
|
619821 |
- s->recv_fifo_itl = 4;
|
|
|
619821 |
- break;
|
|
|
619821 |
- case UART_FCR_ITL_3:
|
|
|
619821 |
- s->recv_fifo_itl = 8;
|
|
|
619821 |
- break;
|
|
|
619821 |
- case UART_FCR_ITL_4:
|
|
|
619821 |
- s->recv_fifo_itl = 14;
|
|
|
619821 |
- break;
|
|
|
619821 |
- }
|
|
|
619821 |
- } else
|
|
|
619821 |
- s->iir &= ~UART_IIR_FE;
|
|
|
619821 |
-
|
|
|
619821 |
- /* Set fcr - or at least the bits in it that are supposed to "stick" */
|
|
|
619821 |
- s->fcr = val & 0xC9;
|
|
|
619821 |
+ serial_write_fcr(s, val & 0xC9);
|
|
|
619821 |
serial_update_irq(s);
|
|
|
619821 |
break;
|
|
|
619821 |
case 3:
|
|
|
619821 |
@@ -617,6 +622,14 @@ static void serial_pre_save(void *opaque)
|
|
|
619821 |
s->fcr_vmstate = s->fcr;
|
|
|
619821 |
}
|
|
|
619821 |
|
|
|
619821 |
+static int serial_pre_load(void *opaque)
|
|
|
619821 |
+{
|
|
|
619821 |
+ SerialState *s = opaque;
|
|
|
619821 |
+ s->thr_ipending = -1;
|
|
|
619821 |
+ s->poll_msl = -1;
|
|
|
619821 |
+ return 0;
|
|
|
619821 |
+}
|
|
|
619821 |
+
|
|
|
619821 |
static int serial_post_load(void *opaque, int version_id)
|
|
|
619821 |
{
|
|
|
619821 |
SerialState *s = opaque;
|
|
|
619821 |
@@ -628,17 +641,159 @@ static int serial_post_load(void *opaque, int version_id)
|
|
|
619821 |
s->tsr_retry = MAX_XMIT_RETRY;
|
|
|
619821 |
}
|
|
|
619821 |
|
|
|
619821 |
+ if (s->thr_ipending == -1) {
|
|
|
619821 |
+ s->thr_ipending = ((s->iir & UART_IIR_ID) == UART_IIR_THRI);
|
|
|
619821 |
+ }
|
|
|
619821 |
+ s->last_break_enable = (s->lcr >> 6) & 1;
|
|
|
619821 |
/* Initialize fcr via setter to perform essential side-effects */
|
|
|
619821 |
- serial_ioport_write(s, 0x02, s->fcr_vmstate, 1);
|
|
|
619821 |
+ serial_write_fcr(s, s->fcr_vmstate);
|
|
|
619821 |
serial_update_parameters(s);
|
|
|
619821 |
return 0;
|
|
|
619821 |
}
|
|
|
619821 |
|
|
|
619821 |
+static bool serial_thr_ipending_needed(void *opaque)
|
|
|
619821 |
+{
|
|
|
619821 |
+#if 0
|
|
|
619821 |
+ SerialState *s = opaque;
|
|
|
619821 |
+ bool expected_value = ((s->iir & UART_IIR_ID) == UART_IIR_THRI);
|
|
|
619821 |
+ return s->thr_ipending != expected_value;
|
|
|
619821 |
+#else
|
|
|
619821 |
+ /* for migration compatibility with RHEL <= 7.3 */
|
|
|
619821 |
+ return 0;
|
|
|
619821 |
+#endif
|
|
|
619821 |
+}
|
|
|
619821 |
+
|
|
|
619821 |
+const VMStateDescription vmstate_serial_thr_ipending = {
|
|
|
619821 |
+ .name = "serial/thr_ipending",
|
|
|
619821 |
+ .version_id = 1,
|
|
|
619821 |
+ .minimum_version_id = 1,
|
|
|
619821 |
+ .fields = (VMStateField[]) {
|
|
|
619821 |
+ VMSTATE_INT32(thr_ipending, SerialState),
|
|
|
619821 |
+ VMSTATE_END_OF_LIST()
|
|
|
619821 |
+ }
|
|
|
619821 |
+};
|
|
|
619821 |
+
|
|
|
619821 |
+static bool serial_tsr_needed(void *opaque)
|
|
|
619821 |
+{
|
|
|
619821 |
+ SerialState *s = (SerialState *)opaque;
|
|
|
619821 |
+ return s->tsr_retry != 0;
|
|
|
619821 |
+}
|
|
|
619821 |
+
|
|
|
619821 |
+const VMStateDescription vmstate_serial_tsr = {
|
|
|
619821 |
+ .name = "serial/tsr",
|
|
|
619821 |
+ .version_id = 1,
|
|
|
619821 |
+ .minimum_version_id = 1,
|
|
|
619821 |
+ .fields = (VMStateField[]) {
|
|
|
619821 |
+ VMSTATE_UINT32(tsr_retry, SerialState),
|
|
|
619821 |
+ VMSTATE_UINT8(thr, SerialState),
|
|
|
619821 |
+ VMSTATE_UINT8(tsr, SerialState),
|
|
|
619821 |
+ VMSTATE_END_OF_LIST()
|
|
|
619821 |
+ }
|
|
|
619821 |
+};
|
|
|
619821 |
+
|
|
|
619821 |
+static bool serial_recv_fifo_needed(void *opaque)
|
|
|
619821 |
+{
|
|
|
619821 |
+ SerialState *s = (SerialState *)opaque;
|
|
|
619821 |
+ return !fifo8_is_empty(&s->recv_fifo);
|
|
|
619821 |
+
|
|
|
619821 |
+}
|
|
|
619821 |
+
|
|
|
619821 |
+const VMStateDescription vmstate_serial_recv_fifo = {
|
|
|
619821 |
+ .name = "serial/recv_fifo",
|
|
|
619821 |
+ .version_id = 1,
|
|
|
619821 |
+ .minimum_version_id = 1,
|
|
|
619821 |
+ .fields = (VMStateField[]) {
|
|
|
619821 |
+ VMSTATE_STRUCT(recv_fifo, SerialState, 1, vmstate_fifo8, Fifo8),
|
|
|
619821 |
+ VMSTATE_END_OF_LIST()
|
|
|
619821 |
+ }
|
|
|
619821 |
+};
|
|
|
619821 |
+
|
|
|
619821 |
+static bool serial_xmit_fifo_needed(void *opaque)
|
|
|
619821 |
+{
|
|
|
619821 |
+ SerialState *s = (SerialState *)opaque;
|
|
|
619821 |
+ return !fifo8_is_empty(&s->xmit_fifo);
|
|
|
619821 |
+}
|
|
|
619821 |
+
|
|
|
619821 |
+const VMStateDescription vmstate_serial_xmit_fifo = {
|
|
|
619821 |
+ .name = "serial/xmit_fifo",
|
|
|
619821 |
+ .version_id = 1,
|
|
|
619821 |
+ .minimum_version_id = 1,
|
|
|
619821 |
+ .fields = (VMStateField[]) {
|
|
|
619821 |
+ VMSTATE_STRUCT(xmit_fifo, SerialState, 1, vmstate_fifo8, Fifo8),
|
|
|
619821 |
+ VMSTATE_END_OF_LIST()
|
|
|
619821 |
+ }
|
|
|
619821 |
+};
|
|
|
619821 |
+
|
|
|
619821 |
+static bool serial_fifo_timeout_timer_needed(void *opaque)
|
|
|
619821 |
+{
|
|
|
619821 |
+#if 0
|
|
|
619821 |
+ SerialState *s = (SerialState *)opaque;
|
|
|
619821 |
+ return timer_pending(s->fifo_timeout_timer);
|
|
|
619821 |
+#else
|
|
|
619821 |
+ /* for migration compatibility with RHEL <= 7.3 */
|
|
|
619821 |
+ return 0;
|
|
|
619821 |
+#endif
|
|
|
619821 |
+}
|
|
|
619821 |
+
|
|
|
619821 |
+const VMStateDescription vmstate_serial_fifo_timeout_timer = {
|
|
|
619821 |
+ .name = "serial/fifo_timeout_timer",
|
|
|
619821 |
+ .version_id = 1,
|
|
|
619821 |
+ .minimum_version_id = 1,
|
|
|
619821 |
+ .fields = (VMStateField[]) {
|
|
|
619821 |
+ VMSTATE_TIMER(fifo_timeout_timer, SerialState),
|
|
|
619821 |
+ VMSTATE_END_OF_LIST()
|
|
|
619821 |
+ }
|
|
|
619821 |
+};
|
|
|
619821 |
+
|
|
|
619821 |
+static bool serial_timeout_ipending_needed(void *opaque)
|
|
|
619821 |
+{
|
|
|
619821 |
+#if 0
|
|
|
619821 |
+ SerialState *s = (SerialState *)opaque;
|
|
|
619821 |
+ return s->timeout_ipending != 0;
|
|
|
619821 |
+#else
|
|
|
619821 |
+ /* for migration compatibility with RHEL <= 7.3 */
|
|
|
619821 |
+ return 0;
|
|
|
619821 |
+#endif
|
|
|
619821 |
+}
|
|
|
619821 |
+
|
|
|
619821 |
+const VMStateDescription vmstate_serial_timeout_ipending = {
|
|
|
619821 |
+ .name = "serial/timeout_ipending",
|
|
|
619821 |
+ .version_id = 1,
|
|
|
619821 |
+ .minimum_version_id = 1,
|
|
|
619821 |
+ .fields = (VMStateField[]) {
|
|
|
619821 |
+ VMSTATE_INT32(timeout_ipending, SerialState),
|
|
|
619821 |
+ VMSTATE_END_OF_LIST()
|
|
|
619821 |
+ }
|
|
|
619821 |
+};
|
|
|
619821 |
+
|
|
|
619821 |
+static bool serial_poll_needed(void *opaque)
|
|
|
619821 |
+{
|
|
|
619821 |
+#if 0
|
|
|
619821 |
+ SerialState *s = (SerialState *)opaque;
|
|
|
619821 |
+ return s->poll_msl >= 0;
|
|
|
619821 |
+#else
|
|
|
619821 |
+ /* for migration compatibility with RHEL <= 7.3 */
|
|
|
619821 |
+ return 0;
|
|
|
619821 |
+#endif
|
|
|
619821 |
+}
|
|
|
619821 |
+
|
|
|
619821 |
+const VMStateDescription vmstate_serial_poll = {
|
|
|
619821 |
+ .name = "serial/poll",
|
|
|
619821 |
+ .version_id = 1,
|
|
|
619821 |
+ .minimum_version_id = 1,
|
|
|
619821 |
+ .fields = (VMStateField[]) {
|
|
|
619821 |
+ VMSTATE_INT32(poll_msl, SerialState),
|
|
|
619821 |
+ VMSTATE_TIMER(modem_status_poll, SerialState),
|
|
|
619821 |
+ VMSTATE_END_OF_LIST()
|
|
|
619821 |
+ }
|
|
|
619821 |
+};
|
|
|
619821 |
+
|
|
|
619821 |
const VMStateDescription vmstate_serial = {
|
|
|
619821 |
.name = "serial",
|
|
|
619821 |
.version_id = 3,
|
|
|
619821 |
.minimum_version_id = 2,
|
|
|
619821 |
.pre_save = serial_pre_save,
|
|
|
619821 |
+ .pre_load = serial_pre_load,
|
|
|
619821 |
.post_load = serial_post_load,
|
|
|
619821 |
.fields = (VMStateField []) {
|
|
|
619821 |
VMSTATE_UINT16_V(divider, SerialState, 2),
|
|
|
619821 |
@@ -652,6 +807,32 @@ const VMStateDescription vmstate_serial = {
|
|
|
619821 |
VMSTATE_UINT8(scr, SerialState),
|
|
|
619821 |
VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3),
|
|
|
619821 |
VMSTATE_END_OF_LIST()
|
|
|
619821 |
+ },
|
|
|
619821 |
+ .subsections = (VMStateSubsection[]) {
|
|
|
619821 |
+ {
|
|
|
619821 |
+ .vmsd = &vmstate_serial_thr_ipending,
|
|
|
619821 |
+ .needed = &serial_thr_ipending_needed,
|
|
|
619821 |
+ } , {
|
|
|
619821 |
+ .vmsd = &vmstate_serial_tsr,
|
|
|
619821 |
+ .needed = &serial_tsr_needed,
|
|
|
619821 |
+ } , {
|
|
|
619821 |
+ .vmsd = &vmstate_serial_recv_fifo,
|
|
|
619821 |
+ .needed = &serial_recv_fifo_needed,
|
|
|
619821 |
+ } , {
|
|
|
619821 |
+ .vmsd = &vmstate_serial_xmit_fifo,
|
|
|
619821 |
+ .needed = &serial_xmit_fifo_needed,
|
|
|
619821 |
+ } , {
|
|
|
619821 |
+ .vmsd = &vmstate_serial_fifo_timeout_timer,
|
|
|
619821 |
+ .needed = &serial_fifo_timeout_timer_needed,
|
|
|
619821 |
+ } , {
|
|
|
619821 |
+ .vmsd = &vmstate_serial_timeout_ipending,
|
|
|
619821 |
+ .needed = &serial_timeout_ipending_needed,
|
|
|
619821 |
+ } , {
|
|
|
619821 |
+ .vmsd = &vmstate_serial_poll,
|
|
|
619821 |
+ .needed = &serial_poll_needed,
|
|
|
619821 |
+ } , {
|
|
|
619821 |
+ /* empty */
|
|
|
619821 |
+ }
|
|
|
619821 |
}
|
|
|
619821 |
};
|
|
|
619821 |
|
|
|
619821 |
@@ -678,6 +859,10 @@ static void serial_reset(void *opaque)
|
|
|
619821 |
s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10;
|
|
|
619821 |
s->poll_msl = 0;
|
|
|
619821 |
|
|
|
619821 |
+ s->timeout_ipending = 0;
|
|
|
619821 |
+ qemu_del_timer(s->fifo_timeout_timer);
|
|
|
619821 |
+ qemu_del_timer(s->modem_status_poll);
|
|
|
619821 |
+
|
|
|
619821 |
fifo8_reset(&s->recv_fifo);
|
|
|
619821 |
fifo8_reset(&s->xmit_fifo);
|
|
|
619821 |
|
|
|
619821 |
--
|
|
|
619821 |
1.8.3.1
|
|
|
619821 |
|