diff options
author | Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> | 2021-11-18 18:18:35 +0000 |
---|---|---|
committer | Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> | 2021-11-21 09:56:52 +0000 |
commit | 319e89cdc32096432b578152a47d0d156033b711 (patch) | |
tree | e86a96d22f3b5244d2d82a2c95fb90c94da891f0 /hw | |
parent | c29cd47e82df0bc7385cdd49a158d838314daa9e (diff) | |
download | qemu-319e89cdc32096432b578152a47d0d156033b711.zip qemu-319e89cdc32096432b578152a47d0d156033b711.tar.gz qemu-319e89cdc32096432b578152a47d0d156033b711.tar.bz2 |
escc: update the R_SPEC register SPEC_ALLSENT bit when writing to W_TXCTRL1
The ESCC datasheet states that SPEC_ALLSENT is always set in sync mode and set
in async mode once all characters have cleared the transmitter. Since writes to
SERIAL_DATA use a synchronous chardev API, the guest can never see the state when
transmission is in progress so it is possible to set SPEC_ALLSENT in the
R_SPEC register unconditionally.
This fixes a hang when using the Sun PROM as it attempts to enumerate the
onboard serial devices, and a similar hang in OpenBSD SPARC32 where in both cases
the boot process will not proceed until SPEC_ALLSENT has been set after writing
to W_TXCTRL1.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Message-Id: <20211118181835.18497-3-mark.cave-ayland@ilande.co.uk>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/char/escc.c | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/hw/char/escc.c b/hw/char/escc.c index a7d9050..8755d8d 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -586,6 +586,20 @@ static void escc_mem_write(void *opaque, hwaddr addr, s->wregs[s->reg] = val; break; case W_TXCTRL1: + s->wregs[s->reg] = val; + /* + * The ESCC datasheet states that SPEC_ALLSENT is always set in + * sync mode, and set in async mode when all characters have + * cleared the transmitter. Since writes to SERIAL_DATA use the + * blocking qemu_chr_fe_write_all() function to write each + * character, the guest can never see the state when async data + * is in the process of being transmitted so we can set this bit + * unconditionally regardless of the state of the W_TXCTRL1 mode + * bits. + */ + s->rregs[R_SPEC] |= SPEC_ALLSENT; + escc_update_parameters(s); + break; case W_TXCTRL2: s->wregs[s->reg] = val; escc_update_parameters(s); |