diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-09-12 16:55:48 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-09-12 16:55:49 +0100 |
commit | 2b31cd4e081389ec1688f58af27f9759bf221c1d (patch) | |
tree | c7f4f12971674da1b652b74f6d18773103c0cbdb /hw/char/serial.c | |
parent | 4c24f4004089a308c5de8ed720cf6bd1746aedd8 (diff) | |
parent | 462efe9e530e22b1b60aaf01716e1423cd94302c (diff) | |
download | hqemu-2b31cd4e081389ec1688f58af27f9759bf221c1d.zip hqemu-2b31cd4e081389ec1688f58af27f9759bf221c1d.tar.gz |
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
- Memory: improve error reporting and avoid crashes on hotplug
- Build: fixing block/iscsi.so and ranlib warnings on Mac OS X
- Migration fixes for x86
- The odd KVM patch.
# gpg: Signature made Thu 11 Sep 2014 11:21:10 BST using RSA key ID 9B4D86F2
# gpg: Good signature from "Paolo Bonzini <pbonzini@redhat.com>"
# gpg: aka "Paolo Bonzini <bonzini@gnu.org>"
* remotes/bonzini/tags/for-upstream: (21 commits)
gdbstub: init mon_chr through qemu_chr_alloc
pckbd: adding new fields to vmstate
mc146818rtc: add missed field to vmstate
piix: do not set irq while loading vmstate
serial: fixing vmstate for save/restore
parallel: adding vmstate for save/restore
fdc: adding vmstate for save/restore
cpu: init vmstate for ticks and clock offset
apic_common: vapic_paddr synchronization fix
vl: use QLIST_FOREACH_SAFE to visit change state handlers
exec: add parameter errp to gethugepagesize
exec: report error when memory < hpagesize
hostmem-ram: don't exit qemu if size of memory-backend-ram is way too big
memory: add parameter errp to memory_region_init_rom_device
memory: add parameter errp to memory_region_init_ram
exec: add parameter errp to qemu_ram_alloc and qemu_ram_alloc_from_ptr
rules.mak: Fix DSO build by pulling in archive symbols
util: Don't link host-utils.o if it's empty
util: Move general qemu_getauxval to util/getauxval.c
trace: Only link generated-tracers.o with "simple" backend
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/char/serial.c')
-rw-r--r-- | hw/char/serial.c | 225 |
1 files changed, 195 insertions, 30 deletions
diff --git a/hw/char/serial.c b/hw/char/serial.c index 764e184..a668249 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -272,6 +272,36 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) } +/* Setter for FCR. + is_load flag means, that value is set while loading VM state + and interrupt should not be invoked */ +static void serial_write_fcr(SerialState *s, uint8_t val) +{ + /* Set fcr - val only has the bits that are supposed to "stick" */ + s->fcr = val; + + if (val & UART_FCR_FE) { + s->iir |= UART_IIR_FE; + /* Set recv_fifo trigger Level */ + switch (val & 0xC0) { + case UART_FCR_ITL_1: + s->recv_fifo_itl = 1; + break; + case UART_FCR_ITL_2: + s->recv_fifo_itl = 4; + break; + case UART_FCR_ITL_3: + s->recv_fifo_itl = 8; + break; + case UART_FCR_ITL_4: + s->recv_fifo_itl = 14; + break; + } + } else { + s->iir &= ~UART_IIR_FE; + } +} + static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { @@ -327,20 +357,16 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, } break; case 2: - val = val & 0xFF; - - if (s->fcr == val) - break; - /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */ - if ((val ^ s->fcr) & UART_FCR_FE) + if ((val ^ s->fcr) & UART_FCR_FE) { val |= UART_FCR_XFR | UART_FCR_RFR; + } /* FIFO clear */ if (val & UART_FCR_RFR) { timer_del(s->fifo_timeout_timer); - s->timeout_ipending=0; + s->timeout_ipending = 0; fifo8_reset(&s->recv_fifo); } @@ -348,28 +374,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, fifo8_reset(&s->xmit_fifo); } - if (val & UART_FCR_FE) { - s->iir |= UART_IIR_FE; - /* Set recv_fifo trigger Level */ - switch (val & 0xC0) { - case UART_FCR_ITL_1: - s->recv_fifo_itl = 1; - break; - case UART_FCR_ITL_2: - s->recv_fifo_itl = 4; - break; - case UART_FCR_ITL_3: - s->recv_fifo_itl = 8; - break; - case UART_FCR_ITL_4: - s->recv_fifo_itl = 14; - break; - } - } else - s->iir &= ~UART_IIR_FE; - - /* Set fcr - or at least the bits in it that are supposed to "stick" */ - s->fcr = val & 0xC9; + serial_write_fcr(s, val & 0xC9); serial_update_irq(s); break; case 3: @@ -590,6 +595,14 @@ static void serial_pre_save(void *opaque) s->fcr_vmstate = s->fcr; } +static int serial_pre_load(void *opaque) +{ + SerialState *s = opaque; + s->thr_ipending = -1; + s->poll_msl = -1; + return 0; +} + static int serial_post_load(void *opaque, int version_id) { SerialState *s = opaque; @@ -597,17 +610,139 @@ static int serial_post_load(void *opaque, int version_id) if (version_id < 3) { s->fcr_vmstate = 0; } + if (s->thr_ipending == -1) { + s->thr_ipending = ((s->iir & UART_IIR_ID) == UART_IIR_THRI); + } + s->last_break_enable = (s->lcr >> 6) & 1; /* Initialize fcr via setter to perform essential side-effects */ - serial_ioport_write(s, 0x02, s->fcr_vmstate, 1); + serial_write_fcr(s, s->fcr_vmstate); serial_update_parameters(s); return 0; } +static bool serial_thr_ipending_needed(void *opaque) +{ + SerialState *s = opaque; + bool expected_value = ((s->iir & UART_IIR_ID) == UART_IIR_THRI); + return s->thr_ipending != expected_value; +} + +const VMStateDescription vmstate_serial_thr_ipending = { + .name = "serial/thr_ipending", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(thr_ipending, SerialState), + VMSTATE_END_OF_LIST() + } +}; + +static bool serial_tsr_needed(void *opaque) +{ + SerialState *s = (SerialState *)opaque; + return s->tsr_retry != 0; +} + +const VMStateDescription vmstate_serial_tsr = { + .name = "serial/tsr", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(tsr_retry, SerialState), + VMSTATE_UINT8(thr, SerialState), + VMSTATE_UINT8(tsr, SerialState), + VMSTATE_END_OF_LIST() + } +}; + +static bool serial_recv_fifo_needed(void *opaque) +{ + SerialState *s = (SerialState *)opaque; + return !fifo8_is_empty(&s->recv_fifo); + +} + +const VMStateDescription vmstate_serial_recv_fifo = { + .name = "serial/recv_fifo", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(recv_fifo, SerialState, 1, vmstate_fifo8, Fifo8), + VMSTATE_END_OF_LIST() + } +}; + +static bool serial_xmit_fifo_needed(void *opaque) +{ + SerialState *s = (SerialState *)opaque; + return !fifo8_is_empty(&s->xmit_fifo); +} + +const VMStateDescription vmstate_serial_xmit_fifo = { + .name = "serial/xmit_fifo", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(xmit_fifo, SerialState, 1, vmstate_fifo8, Fifo8), + VMSTATE_END_OF_LIST() + } +}; + +static bool serial_fifo_timeout_timer_needed(void *opaque) +{ + SerialState *s = (SerialState *)opaque; + return timer_pending(s->fifo_timeout_timer); +} + +const VMStateDescription vmstate_serial_fifo_timeout_timer = { + .name = "serial/fifo_timeout_timer", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_TIMER(fifo_timeout_timer, SerialState), + VMSTATE_END_OF_LIST() + } +}; + +static bool serial_timeout_ipending_needed(void *opaque) +{ + SerialState *s = (SerialState *)opaque; + return s->timeout_ipending != 0; +} + +const VMStateDescription vmstate_serial_timeout_ipending = { + .name = "serial/timeout_ipending", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(timeout_ipending, SerialState), + VMSTATE_END_OF_LIST() + } +}; + +static bool serial_poll_needed(void *opaque) +{ + SerialState *s = (SerialState *)opaque; + return s->poll_msl >= 0; +} + +const VMStateDescription vmstate_serial_poll = { + .name = "serial/poll", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(poll_msl, SerialState), + VMSTATE_TIMER(modem_status_poll, SerialState), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_serial = { .name = "serial", .version_id = 3, .minimum_version_id = 2, .pre_save = serial_pre_save, + .pre_load = serial_pre_load, .post_load = serial_post_load, .fields = (VMStateField[]) { VMSTATE_UINT16_V(divider, SerialState, 2), @@ -621,6 +756,32 @@ const VMStateDescription vmstate_serial = { VMSTATE_UINT8(scr, SerialState), VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3), VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection[]) { + { + .vmsd = &vmstate_serial_thr_ipending, + .needed = &serial_thr_ipending_needed, + } , { + .vmsd = &vmstate_serial_tsr, + .needed = &serial_tsr_needed, + } , { + .vmsd = &vmstate_serial_recv_fifo, + .needed = &serial_recv_fifo_needed, + } , { + .vmsd = &vmstate_serial_xmit_fifo, + .needed = &serial_xmit_fifo_needed, + } , { + .vmsd = &vmstate_serial_fifo_timeout_timer, + .needed = &serial_fifo_timeout_timer_needed, + } , { + .vmsd = &vmstate_serial_timeout_ipending, + .needed = &serial_timeout_ipending_needed, + } , { + .vmsd = &vmstate_serial_poll, + .needed = &serial_poll_needed, + } , { + /* empty */ + } } }; @@ -642,6 +803,10 @@ static void serial_reset(void *opaque) s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10; s->poll_msl = 0; + s->timeout_ipending = 0; + timer_del(s->fifo_timeout_timer); + timer_del(s->modem_status_poll); + fifo8_reset(&s->recv_fifo); fifo8_reset(&s->xmit_fifo); |