From: Evgeny Iakovlev <eiakovlev@linux.microsoft.com>
To: qemu-arm@nongnu.org
Cc: qemu-devel@nongnu.org, marcandre.lureau@redhat.com,
pbonzini@redhat.com, peter.maydell@linaro.org
Subject: [PATCH 1/2] hw/char/pl011: better handling of FIFO flags on LCR reset
Date: Fri, 6 Jan 2023 18:28:50 +0100 [thread overview]
Message-ID: <20230106172851.2430-2-eiakovlev@linux.microsoft.com> (raw)
In-Reply-To: <20230106172851.2430-1-eiakovlev@linux.microsoft.com>
Current FIFO handling code does not reset RXFE/RXFF flags when guest
resets FIFO by writing to UARTLCR register, although internal FIFO state
is reset to 0 read count. Actual flag update will happen only on next
read or write to UART. As a result of that any guest that expects RXFE
flag to be set (and RXFF to be cleared) after resetting FIFO will just
hang.
Correctly reset FIFO flags on FIFO reset. Also, clean up some FIFO
depth handling code based on current FIFO mode.
Signed-off-by: Evgeny Iakovlev <eiakovlev@linux.microsoft.com>
---
hw/char/pl011.c | 35 +++++++++++++++++++++--------------
include/hw/char/pl011.h | 5 ++++-
2 files changed, 25 insertions(+), 15 deletions(-)
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index c076813423..9108ed2be9 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -81,6 +81,18 @@ static void pl011_update(PL011State *s)
}
}
+static inline unsigned pl011_get_fifo_depth(PL011State *s)
+{
+ return s->lcr & 0x10 ? PL011_FIFO_DEPTH : 1;
+}
+
+static inline void pl011_reset_pipe(PL011State *s)
+{
+ s->read_count = 0;
+ s->read_pos = 0;
+ s->flags = PL011_FLAG_RXFE | PL011_FLAG_TXFE;
+}
+
static uint64_t pl011_read(void *opaque, hwaddr offset,
unsigned size)
{
@@ -94,7 +106,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset,
c = s->read_fifo[s->read_pos];
if (s->read_count > 0) {
s->read_count--;
- if (++s->read_pos == 16)
+ if (++s->read_pos == PL011_FIFO_DEPTH)
s->read_pos = 0;
}
if (s->read_count == 0) {
@@ -229,8 +241,7 @@ static void pl011_write(void *opaque, hwaddr offset,
case 11: /* UARTLCR_H */
/* Reset the FIFO state on FIFO enable or disable */
if ((s->lcr ^ value) & 0x10) {
- s->read_count = 0;
- s->read_pos = 0;
+ pl011_reset_pipe(s);
}
if ((s->lcr ^ value) & 0x1) {
int break_enable = value & 0x1;
@@ -273,11 +284,7 @@ static int pl011_can_receive(void *opaque)
PL011State *s = (PL011State *)opaque;
int r;
- if (s->lcr & 0x10) {
- r = s->read_count < 16;
- } else {
- r = s->read_count < 1;
- }
+ r = s->read_count < pl011_get_fifo_depth(s);
trace_pl011_can_receive(s->lcr, s->read_count, r);
return r;
}
@@ -286,15 +293,15 @@ static void pl011_put_fifo(void *opaque, uint32_t value)
{
PL011State *s = (PL011State *)opaque;
int slot;
+ unsigned pipe_depth;
- slot = s->read_pos + s->read_count;
- if (slot >= 16)
- slot -= 16;
+ pipe_depth = pl011_get_fifo_depth(s);
+ slot = (s->read_pos + s->read_count) % pipe_depth;
s->read_fifo[slot] = value;
s->read_count++;
s->flags &= ~PL011_FLAG_RXFE;
trace_pl011_put_fifo(value, s->read_count);
- if (!(s->lcr & 0x10) || s->read_count == 16) {
+ if (s->read_count == pipe_depth) {
trace_pl011_put_fifo_full();
s->flags |= PL011_FLAG_RXFF;
}
@@ -359,7 +366,7 @@ static const VMStateDescription vmstate_pl011 = {
VMSTATE_UINT32(dmacr, PL011State),
VMSTATE_UINT32(int_enabled, PL011State),
VMSTATE_UINT32(int_level, PL011State),
- VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
+ VMSTATE_UINT32_ARRAY(read_fifo, PL011State, PL011_FIFO_DEPTH),
VMSTATE_UINT32(ilpr, PL011State),
VMSTATE_UINT32(ibrd, PL011State),
VMSTATE_UINT32(fbrd, PL011State),
@@ -399,7 +406,7 @@ static void pl011_init(Object *obj)
s->read_trigger = 1;
s->ifl = 0x12;
s->cr = 0x300;
- s->flags = 0x90;
+ pl011_reset_pipe(s);
s->id = pl011_id_arm;
}
diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h
index dc2c90eedc..926322e242 100644
--- a/include/hw/char/pl011.h
+++ b/include/hw/char/pl011.h
@@ -27,6 +27,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(PL011State, PL011)
/* This shares the same struct (and cast macro) as the base pl011 device */
#define TYPE_PL011_LUMINARY "pl011_luminary"
+/* Depth of UART FIFO in bytes, when FIFO mode is enabled (else depth == 1) */
+#define PL011_FIFO_DEPTH 16
+
struct PL011State {
SysBusDevice parent_obj;
@@ -39,7 +42,7 @@ struct PL011State {
uint32_t dmacr;
uint32_t int_enabled;
uint32_t int_level;
- uint32_t read_fifo[16];
+ uint32_t read_fifo[PL011_FIFO_DEPTH];
uint32_t ilpr;
uint32_t ibrd;
uint32_t fbrd;
--
2.34.1
next prev parent reply other threads:[~2023-01-06 17:29 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-01-06 17:28 [PATCH 0/2] Series of fixes for PL011 char device Evgeny Iakovlev
2023-01-06 17:28 ` Evgeny Iakovlev [this message]
2023-01-17 15:24 ` [PATCH 1/2] hw/char/pl011: better handling of FIFO flags on LCR reset Peter Maydell
2023-01-17 15:54 ` Evgeny Iakovlev
2023-01-17 16:02 ` Peter Maydell
2023-01-17 22:06 ` eiakovlev
2023-01-06 17:28 ` [PATCH 2/2] hw/char/pl011: check if UART is enabled before RX or TX operation Evgeny Iakovlev
2023-01-17 15:38 ` Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230106172851.2430-2-eiakovlev@linux.microsoft.com \
--to=eiakovlev@linux.microsoft.com \
--cc=marcandre.lureau@redhat.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).