* [PATCH v4 0/2] riscv: char: Avoid dropped charecters
@ 2024-09-10 4:54 Alistair Francis
2024-09-10 4:54 ` [PATCH v4 1/2] hw/char: riscv_htif: Use blocking qemu_chr_fe_write_all Alistair Francis
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Alistair Francis @ 2024-09-10 4:54 UTC (permalink / raw)
To: qemu-devel, alex.bennee, peter.maydell
Cc: Bin Meng, palmer, liwei1518, zhiwei_liu, alistair23, qemu-riscv,
Alistair Francis, Paolo Bonzini, Marc-André Lureau, atishp,
dbarboza, Alistair Francis
This series fixes: https://gitlab.com/qemu-project/qemu/-/issues/2114
This converts the RISC-V charecter device callers of qemu_chr_fe_write()
to either use qemu_chr_fe_write_all() or to call qemu_chr_fe_write() async
and act on the return value.
v4:
- Drop the unused char_tx_time
- Update the migration in vmstate_sifive_uart
v3:
- Fixup spelling
v2:
- Use Fifo8 for the Sifive UART instead of a custom FIFO
Alistair Francis (2):
hw/char: riscv_htif: Use blocking qemu_chr_fe_write_all
hw/char: sifive_uart: Print uart characters async
include/hw/char/sifive_uart.h | 16 +++++-
hw/char/riscv_htif.c | 12 ++++-
hw/char/sifive_uart.c | 94 ++++++++++++++++++++++++++++++++---
3 files changed, 112 insertions(+), 10 deletions(-)
--
2.46.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 1/2] hw/char: riscv_htif: Use blocking qemu_chr_fe_write_all
2024-09-10 4:54 [PATCH v4 0/2] riscv: char: Avoid dropped charecters Alistair Francis
@ 2024-09-10 4:54 ` Alistair Francis
2024-09-10 7:16 ` Philippe Mathieu-Daudé
2024-09-10 4:54 ` [PATCH v4 2/2] hw/char: sifive_uart: Print uart characters async Alistair Francis
2024-10-17 13:22 ` [PATCH v4 0/2] riscv: char: Avoid dropped charecters Thomas Huth
2 siblings, 1 reply; 9+ messages in thread
From: Alistair Francis @ 2024-09-10 4:54 UTC (permalink / raw)
To: qemu-devel, alex.bennee, peter.maydell
Cc: Bin Meng, palmer, liwei1518, zhiwei_liu, alistair23, qemu-riscv,
Alistair Francis, Paolo Bonzini, Marc-André Lureau, atishp,
dbarboza, Alistair Francis, Thomas Huth
The current approach of using qemu_chr_fe_write() and ignoring the
return values results in dropped characters [1]. Ideally we want to
report FIFO status to the guest, but the HTIF isn't a real UART, so we
don't really have a way to do that.
Instead let's just use qemu_chr_fe_write_all() so at least we don't drop
characters.
1: https://gitlab.com/qemu-project/qemu/-/issues/2114
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
---
hw/char/riscv_htif.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c
index 9bef60def1..d40b542948 100644
--- a/hw/char/riscv_htif.c
+++ b/hw/char/riscv_htif.c
@@ -218,7 +218,11 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
tswap64(syscall[3]) == HTIF_CONSOLE_CMD_PUTC) {
uint8_t ch;
cpu_physical_memory_read(tswap64(syscall[2]), &ch, 1);
- qemu_chr_fe_write(&s->chr, &ch, 1);
+ /*
+ * XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks
+ */
+ qemu_chr_fe_write_all(&s->chr, &ch, 1);
resp = 0x100 | (uint8_t)payload;
} else {
qemu_log_mask(LOG_UNIMP,
@@ -237,7 +241,11 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
return;
} else if (cmd == HTIF_CONSOLE_CMD_PUTC) {
uint8_t ch = (uint8_t)payload;
- qemu_chr_fe_write(&s->chr, &ch, 1);
+ /*
+ * XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks
+ */
+ qemu_chr_fe_write_all(&s->chr, &ch, 1);
resp = 0x100 | (uint8_t)payload;
} else {
qemu_log("HTIF device %d: unknown command\n", device);
--
2.46.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 2/2] hw/char: sifive_uart: Print uart characters async
2024-09-10 4:54 [PATCH v4 0/2] riscv: char: Avoid dropped charecters Alistair Francis
2024-09-10 4:54 ` [PATCH v4 1/2] hw/char: riscv_htif: Use blocking qemu_chr_fe_write_all Alistair Francis
@ 2024-09-10 4:54 ` Alistair Francis
2024-09-10 7:16 ` Philippe Mathieu-Daudé
2024-09-10 20:34 ` Mark Cave-Ayland
2024-10-17 13:22 ` [PATCH v4 0/2] riscv: char: Avoid dropped charecters Thomas Huth
2 siblings, 2 replies; 9+ messages in thread
From: Alistair Francis @ 2024-09-10 4:54 UTC (permalink / raw)
To: qemu-devel, alex.bennee, peter.maydell
Cc: Bin Meng, palmer, liwei1518, zhiwei_liu, alistair23, qemu-riscv,
Alistair Francis, Paolo Bonzini, Marc-André Lureau, atishp,
dbarboza, Alistair Francis, Thomas Huth
The current approach of using qemu_chr_fe_write() and ignoring the
return values results in dropped characters [1].
Let's update the SiFive UART to use a async sifive_uart_xmit() function
to transmit the characters and apply back pressure to the guest with
the SIFIVE_UART_TXFIFO_FULL status.
This should avoid dropped characters and more realisticly model the
hardware.
1: https://gitlab.com/qemu-project/qemu/-/issues/2114
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Tested-by: Thomas Huth <thuth@redhat.com>
---
include/hw/char/sifive_uart.h | 16 +++++-
hw/char/sifive_uart.c | 94 ++++++++++++++++++++++++++++++++---
2 files changed, 102 insertions(+), 8 deletions(-)
diff --git a/include/hw/char/sifive_uart.h b/include/hw/char/sifive_uart.h
index 7f6c79f8bd..0846cf6218 100644
--- a/include/hw/char/sifive_uart.h
+++ b/include/hw/char/sifive_uart.h
@@ -24,6 +24,7 @@
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "qom/object.h"
+#include "qemu/fifo8.h"
enum {
SIFIVE_UART_TXFIFO = 0,
@@ -48,9 +49,13 @@ enum {
SIFIVE_UART_IP_RXWM = 2 /* Receive watermark interrupt pending */
};
+#define SIFIVE_UART_TXFIFO_FULL 0x80000000
+
#define SIFIVE_UART_GET_TXCNT(txctrl) ((txctrl >> 16) & 0x7)
#define SIFIVE_UART_GET_RXCNT(rxctrl) ((rxctrl >> 16) & 0x7)
+
#define SIFIVE_UART_RX_FIFO_SIZE 8
+#define SIFIVE_UART_TX_FIFO_SIZE 8
#define TYPE_SIFIVE_UART "riscv.sifive.uart"
OBJECT_DECLARE_SIMPLE_TYPE(SiFiveUARTState, SIFIVE_UART)
@@ -63,13 +68,20 @@ struct SiFiveUARTState {
qemu_irq irq;
MemoryRegion mmio;
CharBackend chr;
- uint8_t rx_fifo[SIFIVE_UART_RX_FIFO_SIZE];
- uint8_t rx_fifo_len;
+
+ uint32_t txfifo;
uint32_t ie;
uint32_t ip;
uint32_t txctrl;
uint32_t rxctrl;
uint32_t div;
+
+ uint8_t rx_fifo[SIFIVE_UART_RX_FIFO_SIZE];
+ uint8_t rx_fifo_len;
+
+ Fifo8 tx_fifo;
+
+ QEMUTimer *fifo_trigger_handle;
};
SiFiveUARTState *sifive_uart_create(MemoryRegion *address_space, hwaddr base,
diff --git a/hw/char/sifive_uart.c b/hw/char/sifive_uart.c
index 7fc6787f69..16a70c7ad7 100644
--- a/hw/char/sifive_uart.c
+++ b/hw/char/sifive_uart.c
@@ -64,6 +64,71 @@ static void sifive_uart_update_irq(SiFiveUARTState *s)
}
}
+static gboolean sifive_uart_xmit(void *do_not_use, GIOCondition cond,
+ void *opaque)
+{
+ SiFiveUARTState *s = opaque;
+ int ret;
+ const uint8_t *characters;
+ uint32_t numptr = 0;
+
+ /* instant drain the fifo when there's no back-end */
+ if (!qemu_chr_fe_backend_connected(&s->chr)) {
+ fifo8_reset(&s->tx_fifo);
+ return G_SOURCE_REMOVE;
+ }
+
+ if (fifo8_is_empty(&s->tx_fifo)) {
+ return G_SOURCE_REMOVE;
+ }
+
+ /* Don't pop the FIFO in case the write fails */
+ characters = fifo8_peek_bufptr(&s->tx_fifo,
+ fifo8_num_used(&s->tx_fifo), &numptr);
+ ret = qemu_chr_fe_write(&s->chr, characters, numptr);
+
+ if (ret >= 0) {
+ /* We wrote the data, actually pop the fifo */
+ fifo8_pop_bufptr(&s->tx_fifo, ret, NULL);
+ }
+
+ if (!fifo8_is_empty(&s->tx_fifo)) {
+ guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
+ sifive_uart_xmit, s);
+ if (!r) {
+ fifo8_reset(&s->tx_fifo);
+ return G_SOURCE_REMOVE;
+ }
+ }
+
+ /* Clear the TX Full bit */
+ if (!fifo8_is_full(&s->tx_fifo)) {
+ s->txfifo &= ~SIFIVE_UART_TXFIFO_FULL;
+ }
+
+ sifive_uart_update_irq(s);
+ return G_SOURCE_REMOVE;
+}
+
+static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, const uint8_t *buf,
+ int size)
+{
+ uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ if (size > fifo8_num_free(&s->tx_fifo)) {
+ size = fifo8_num_free(&s->tx_fifo);
+ qemu_log_mask(LOG_GUEST_ERROR, "sifive_uart: TX FIFO overflow");
+ }
+
+ fifo8_push_all(&s->tx_fifo, buf, size);
+
+ if (fifo8_is_full(&s->tx_fifo)) {
+ s->txfifo |= SIFIVE_UART_TXFIFO_FULL;
+ }
+
+ timer_mod(s->fifo_trigger_handle, current_time + 100);
+}
+
static uint64_t
sifive_uart_read(void *opaque, hwaddr addr, unsigned int size)
{
@@ -82,7 +147,7 @@ sifive_uart_read(void *opaque, hwaddr addr, unsigned int size)
return 0x80000000;
case SIFIVE_UART_TXFIFO:
- return 0; /* Should check tx fifo */
+ return s->txfifo;
case SIFIVE_UART_IE:
return s->ie;
case SIFIVE_UART_IP:
@@ -106,12 +171,10 @@ sifive_uart_write(void *opaque, hwaddr addr,
{
SiFiveUARTState *s = opaque;
uint32_t value = val64;
- unsigned char ch = value;
switch (addr) {
case SIFIVE_UART_TXFIFO:
- qemu_chr_fe_write(&s->chr, &ch, 1);
- sifive_uart_update_irq(s);
+ sifive_uart_write_tx_fifo(s, (uint8_t *) &value, 1);
return;
case SIFIVE_UART_IE:
s->ie = val64;
@@ -131,6 +194,13 @@ sifive_uart_write(void *opaque, hwaddr addr,
__func__, (int)addr, (int)value);
}
+static void fifo_trigger_update(void *opaque)
+{
+ SiFiveUARTState *s = opaque;
+
+ sifive_uart_xmit(NULL, G_IO_OUT, s);
+}
+
static const MemoryRegionOps sifive_uart_ops = {
.read = sifive_uart_read,
.write = sifive_uart_write,
@@ -197,6 +267,9 @@ static void sifive_uart_realize(DeviceState *dev, Error **errp)
{
SiFiveUARTState *s = SIFIVE_UART(dev);
+ s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ fifo_trigger_update, s);
+
qemu_chr_fe_set_handlers(&s->chr, sifive_uart_can_rx, sifive_uart_rx,
sifive_uart_event, sifive_uart_be_change, s,
NULL, true);
@@ -206,12 +279,18 @@ static void sifive_uart_realize(DeviceState *dev, Error **errp)
static void sifive_uart_reset_enter(Object *obj, ResetType type)
{
SiFiveUARTState *s = SIFIVE_UART(obj);
+
+ s->txfifo = 0;
s->ie = 0;
s->ip = 0;
s->txctrl = 0;
s->rxctrl = 0;
s->div = 0;
+
s->rx_fifo_len = 0;
+
+ memset(s->rx_fifo, 0, SIFIVE_UART_RX_FIFO_SIZE);
+ fifo8_create(&s->tx_fifo, SIFIVE_UART_TX_FIFO_SIZE);
}
static void sifive_uart_reset_hold(Object *obj, ResetType type)
@@ -222,8 +301,8 @@ static void sifive_uart_reset_hold(Object *obj, ResetType type)
static const VMStateDescription vmstate_sifive_uart = {
.name = TYPE_SIFIVE_UART,
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_UINT8_ARRAY(rx_fifo, SiFiveUARTState,
SIFIVE_UART_RX_FIFO_SIZE),
@@ -233,6 +312,9 @@ static const VMStateDescription vmstate_sifive_uart = {
VMSTATE_UINT32(txctrl, SiFiveUARTState),
VMSTATE_UINT32(rxctrl, SiFiveUARTState),
VMSTATE_UINT32(div, SiFiveUARTState),
+ VMSTATE_UINT32(txfifo, SiFiveUARTState),
+ VMSTATE_FIFO8(tx_fifo, SiFiveUARTState),
+ VMSTATE_TIMER_PTR(fifo_trigger_handle, SiFiveUARTState),
VMSTATE_END_OF_LIST()
},
};
--
2.46.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/2] hw/char: sifive_uart: Print uart characters async
2024-09-10 4:54 ` [PATCH v4 2/2] hw/char: sifive_uart: Print uart characters async Alistair Francis
@ 2024-09-10 7:16 ` Philippe Mathieu-Daudé
2024-09-10 20:34 ` Mark Cave-Ayland
1 sibling, 0 replies; 9+ messages in thread
From: Philippe Mathieu-Daudé @ 2024-09-10 7:16 UTC (permalink / raw)
To: Alistair Francis, qemu-devel, alex.bennee, peter.maydell
Cc: Bin Meng, palmer, liwei1518, zhiwei_liu, qemu-riscv,
Alistair Francis, Paolo Bonzini, Marc-André Lureau, atishp,
dbarboza, Thomas Huth
On 10/9/24 06:54, Alistair Francis wrote:
> The current approach of using qemu_chr_fe_write() and ignoring the
> return values results in dropped characters [1].
>
> Let's update the SiFive UART to use a async sifive_uart_xmit() function
> to transmit the characters and apply back pressure to the guest with
> the SIFIVE_UART_TXFIFO_FULL status.
>
> This should avoid dropped characters and more realisticly model the
> hardware.
>
> 1: https://gitlab.com/qemu-project/qemu/-/issues/2114
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> Tested-by: Thomas Huth <thuth@redhat.com>
> ---
> include/hw/char/sifive_uart.h | 16 +++++-
> hw/char/sifive_uart.c | 94 ++++++++++++++++++++++++++++++++---
> 2 files changed, 102 insertions(+), 8 deletions(-)
> +static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, const uint8_t *buf,
> + int size)
> +{
> + uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +
> + if (size > fifo8_num_free(&s->tx_fifo)) {
> + size = fifo8_num_free(&s->tx_fifo);
> + qemu_log_mask(LOG_GUEST_ERROR, "sifive_uart: TX FIFO overflow");
> + }
> +
> + fifo8_push_all(&s->tx_fifo, buf, size);
> +
> + if (fifo8_is_full(&s->tx_fifo)) {
> + s->txfifo |= SIFIVE_UART_TXFIFO_FULL;
> + }
> +
> + timer_mod(s->fifo_trigger_handle, current_time + 100);
Preferably using a #define instead of this magic '100' value (no
need to repost):
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> +}
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/2] hw/char: riscv_htif: Use blocking qemu_chr_fe_write_all
2024-09-10 4:54 ` [PATCH v4 1/2] hw/char: riscv_htif: Use blocking qemu_chr_fe_write_all Alistair Francis
@ 2024-09-10 7:16 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 9+ messages in thread
From: Philippe Mathieu-Daudé @ 2024-09-10 7:16 UTC (permalink / raw)
To: Alistair Francis, qemu-devel, alex.bennee, peter.maydell
Cc: Bin Meng, palmer, liwei1518, zhiwei_liu, qemu-riscv,
Alistair Francis, Paolo Bonzini, Marc-André Lureau, atishp,
dbarboza, Thomas Huth
On 10/9/24 06:54, Alistair Francis wrote:
> The current approach of using qemu_chr_fe_write() and ignoring the
> return values results in dropped characters [1]. Ideally we want to
> report FIFO status to the guest, but the HTIF isn't a real UART, so we
> don't really have a way to do that.
>
> Instead let's just use qemu_chr_fe_write_all() so at least we don't drop
> characters.
>
> 1: https://gitlab.com/qemu-project/qemu/-/issues/2114
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> Reviewed-by: Thomas Huth <thuth@redhat.com>
> ---
> hw/char/riscv_htif.c | 12 ++++++++++--
> 1 file changed, 10 insertions(+), 2 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/2] hw/char: sifive_uart: Print uart characters async
2024-09-10 4:54 ` [PATCH v4 2/2] hw/char: sifive_uart: Print uart characters async Alistair Francis
2024-09-10 7:16 ` Philippe Mathieu-Daudé
@ 2024-09-10 20:34 ` Mark Cave-Ayland
2024-09-11 1:53 ` Alistair Francis
1 sibling, 1 reply; 9+ messages in thread
From: Mark Cave-Ayland @ 2024-09-10 20:34 UTC (permalink / raw)
To: Alistair Francis, qemu-devel, alex.bennee, peter.maydell
Cc: Bin Meng, palmer, liwei1518, zhiwei_liu, qemu-riscv,
Alistair Francis, Paolo Bonzini, Marc-André Lureau, atishp,
dbarboza, Thomas Huth
On 10/09/2024 05:54, Alistair Francis wrote:
> The current approach of using qemu_chr_fe_write() and ignoring the
> return values results in dropped characters [1].
>
> Let's update the SiFive UART to use a async sifive_uart_xmit() function
> to transmit the characters and apply back pressure to the guest with
> the SIFIVE_UART_TXFIFO_FULL status.
>
> This should avoid dropped characters and more realisticly model the
> hardware.
Does the UART work reliably using the fifo8_*_bufptr() functions? One of the
motivations for my recent Fifo8 series is that these functions don't handle the
wraparound correctly, unlike the fifo8_*_buf() functions in my recent Fifo8 series
which do. This was the cause of Phil's async issue in
https://mail.gnu.org/archive/html/qemu-devel/2024-07/msg05028.html.
> 1: https://gitlab.com/qemu-project/qemu/-/issues/2114
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> Tested-by: Thomas Huth <thuth@redhat.com>
> ---
> include/hw/char/sifive_uart.h | 16 +++++-
> hw/char/sifive_uart.c | 94 ++++++++++++++++++++++++++++++++---
> 2 files changed, 102 insertions(+), 8 deletions(-)
>
> diff --git a/include/hw/char/sifive_uart.h b/include/hw/char/sifive_uart.h
> index 7f6c79f8bd..0846cf6218 100644
> --- a/include/hw/char/sifive_uart.h
> +++ b/include/hw/char/sifive_uart.h
> @@ -24,6 +24,7 @@
> #include "hw/qdev-properties.h"
> #include "hw/sysbus.h"
> #include "qom/object.h"
> +#include "qemu/fifo8.h"
>
> enum {
> SIFIVE_UART_TXFIFO = 0,
> @@ -48,9 +49,13 @@ enum {
> SIFIVE_UART_IP_RXWM = 2 /* Receive watermark interrupt pending */
> };
>
> +#define SIFIVE_UART_TXFIFO_FULL 0x80000000
> +
> #define SIFIVE_UART_GET_TXCNT(txctrl) ((txctrl >> 16) & 0x7)
> #define SIFIVE_UART_GET_RXCNT(rxctrl) ((rxctrl >> 16) & 0x7)
> +
> #define SIFIVE_UART_RX_FIFO_SIZE 8
> +#define SIFIVE_UART_TX_FIFO_SIZE 8
>
> #define TYPE_SIFIVE_UART "riscv.sifive.uart"
> OBJECT_DECLARE_SIMPLE_TYPE(SiFiveUARTState, SIFIVE_UART)
> @@ -63,13 +68,20 @@ struct SiFiveUARTState {
> qemu_irq irq;
> MemoryRegion mmio;
> CharBackend chr;
> - uint8_t rx_fifo[SIFIVE_UART_RX_FIFO_SIZE];
> - uint8_t rx_fifo_len;
> +
> + uint32_t txfifo;
> uint32_t ie;
> uint32_t ip;
> uint32_t txctrl;
> uint32_t rxctrl;
> uint32_t div;
> +
> + uint8_t rx_fifo[SIFIVE_UART_RX_FIFO_SIZE];
> + uint8_t rx_fifo_len;
> +
> + Fifo8 tx_fifo;
> +
> + QEMUTimer *fifo_trigger_handle;
> };
>
> SiFiveUARTState *sifive_uart_create(MemoryRegion *address_space, hwaddr base,
> diff --git a/hw/char/sifive_uart.c b/hw/char/sifive_uart.c
> index 7fc6787f69..16a70c7ad7 100644
> --- a/hw/char/sifive_uart.c
> +++ b/hw/char/sifive_uart.c
> @@ -64,6 +64,71 @@ static void sifive_uart_update_irq(SiFiveUARTState *s)
> }
> }
>
> +static gboolean sifive_uart_xmit(void *do_not_use, GIOCondition cond,
> + void *opaque)
> +{
> + SiFiveUARTState *s = opaque;
> + int ret;
> + const uint8_t *characters;
> + uint32_t numptr = 0;
> +
> + /* instant drain the fifo when there's no back-end */
> + if (!qemu_chr_fe_backend_connected(&s->chr)) {
> + fifo8_reset(&s->tx_fifo);
> + return G_SOURCE_REMOVE;
> + }
> +
> + if (fifo8_is_empty(&s->tx_fifo)) {
> + return G_SOURCE_REMOVE;
> + }
> +
> + /* Don't pop the FIFO in case the write fails */
> + characters = fifo8_peek_bufptr(&s->tx_fifo,
> + fifo8_num_used(&s->tx_fifo), &numptr);
> + ret = qemu_chr_fe_write(&s->chr, characters, numptr);
> +
> + if (ret >= 0) {
> + /* We wrote the data, actually pop the fifo */
> + fifo8_pop_bufptr(&s->tx_fifo, ret, NULL);
> + }
> +
> + if (!fifo8_is_empty(&s->tx_fifo)) {
> + guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
> + sifive_uart_xmit, s);
> + if (!r) {
> + fifo8_reset(&s->tx_fifo);
> + return G_SOURCE_REMOVE;
> + }
> + }
> +
> + /* Clear the TX Full bit */
> + if (!fifo8_is_full(&s->tx_fifo)) {
> + s->txfifo &= ~SIFIVE_UART_TXFIFO_FULL;
> + }
> +
> + sifive_uart_update_irq(s);
> + return G_SOURCE_REMOVE;
> +}
> +
> +static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, const uint8_t *buf,
> + int size)
> +{
> + uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +
> + if (size > fifo8_num_free(&s->tx_fifo)) {
> + size = fifo8_num_free(&s->tx_fifo);
> + qemu_log_mask(LOG_GUEST_ERROR, "sifive_uart: TX FIFO overflow");
> + }
> +
> + fifo8_push_all(&s->tx_fifo, buf, size);
> +
> + if (fifo8_is_full(&s->tx_fifo)) {
> + s->txfifo |= SIFIVE_UART_TXFIFO_FULL;
> + }
> +
> + timer_mod(s->fifo_trigger_handle, current_time + 100);
> +}
> +
> static uint64_t
> sifive_uart_read(void *opaque, hwaddr addr, unsigned int size)
> {
> @@ -82,7 +147,7 @@ sifive_uart_read(void *opaque, hwaddr addr, unsigned int size)
> return 0x80000000;
>
> case SIFIVE_UART_TXFIFO:
> - return 0; /* Should check tx fifo */
> + return s->txfifo;
> case SIFIVE_UART_IE:
> return s->ie;
> case SIFIVE_UART_IP:
> @@ -106,12 +171,10 @@ sifive_uart_write(void *opaque, hwaddr addr,
> {
> SiFiveUARTState *s = opaque;
> uint32_t value = val64;
> - unsigned char ch = value;
>
> switch (addr) {
> case SIFIVE_UART_TXFIFO:
> - qemu_chr_fe_write(&s->chr, &ch, 1);
> - sifive_uart_update_irq(s);
> + sifive_uart_write_tx_fifo(s, (uint8_t *) &value, 1);
> return;
> case SIFIVE_UART_IE:
> s->ie = val64;
> @@ -131,6 +194,13 @@ sifive_uart_write(void *opaque, hwaddr addr,
> __func__, (int)addr, (int)value);
> }
>
> +static void fifo_trigger_update(void *opaque)
> +{
> + SiFiveUARTState *s = opaque;
> +
> + sifive_uart_xmit(NULL, G_IO_OUT, s);
> +}
> +
> static const MemoryRegionOps sifive_uart_ops = {
> .read = sifive_uart_read,
> .write = sifive_uart_write,
> @@ -197,6 +267,9 @@ static void sifive_uart_realize(DeviceState *dev, Error **errp)
> {
> SiFiveUARTState *s = SIFIVE_UART(dev);
>
> + s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> + fifo_trigger_update, s);
> +
> qemu_chr_fe_set_handlers(&s->chr, sifive_uart_can_rx, sifive_uart_rx,
> sifive_uart_event, sifive_uart_be_change, s,
> NULL, true);
> @@ -206,12 +279,18 @@ static void sifive_uart_realize(DeviceState *dev, Error **errp)
> static void sifive_uart_reset_enter(Object *obj, ResetType type)
> {
> SiFiveUARTState *s = SIFIVE_UART(obj);
> +
> + s->txfifo = 0;
> s->ie = 0;
> s->ip = 0;
> s->txctrl = 0;
> s->rxctrl = 0;
> s->div = 0;
> +
> s->rx_fifo_len = 0;
> +
> + memset(s->rx_fifo, 0, SIFIVE_UART_RX_FIFO_SIZE);
> + fifo8_create(&s->tx_fifo, SIFIVE_UART_TX_FIFO_SIZE);
> }
>
> static void sifive_uart_reset_hold(Object *obj, ResetType type)
> @@ -222,8 +301,8 @@ static void sifive_uart_reset_hold(Object *obj, ResetType type)
>
> static const VMStateDescription vmstate_sifive_uart = {
> .name = TYPE_SIFIVE_UART,
> - .version_id = 1,
> - .minimum_version_id = 1,
> + .version_id = 2,
> + .minimum_version_id = 2,
> .fields = (const VMStateField[]) {
> VMSTATE_UINT8_ARRAY(rx_fifo, SiFiveUARTState,
> SIFIVE_UART_RX_FIFO_SIZE),
> @@ -233,6 +312,9 @@ static const VMStateDescription vmstate_sifive_uart = {
> VMSTATE_UINT32(txctrl, SiFiveUARTState),
> VMSTATE_UINT32(rxctrl, SiFiveUARTState),
> VMSTATE_UINT32(div, SiFiveUARTState),
> + VMSTATE_UINT32(txfifo, SiFiveUARTState),
> + VMSTATE_FIFO8(tx_fifo, SiFiveUARTState),
> + VMSTATE_TIMER_PTR(fifo_trigger_handle, SiFiveUARTState),
> VMSTATE_END_OF_LIST()
> },
> };
ATB,
Mark.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/2] hw/char: sifive_uart: Print uart characters async
2024-09-10 20:34 ` Mark Cave-Ayland
@ 2024-09-11 1:53 ` Alistair Francis
0 siblings, 0 replies; 9+ messages in thread
From: Alistair Francis @ 2024-09-11 1:53 UTC (permalink / raw)
To: Mark Cave-Ayland
Cc: qemu-devel, alex.bennee, peter.maydell, Bin Meng, palmer,
liwei1518, zhiwei_liu, qemu-riscv, Alistair Francis,
Paolo Bonzini, Marc-André Lureau, atishp, dbarboza,
Thomas Huth
On Wed, Sep 11, 2024 at 6:35 AM Mark Cave-Ayland
<mark.cave-ayland@ilande.co.uk> wrote:
>
> On 10/09/2024 05:54, Alistair Francis wrote:
>
> > The current approach of using qemu_chr_fe_write() and ignoring the
> > return values results in dropped characters [1].
> >
> > Let's update the SiFive UART to use a async sifive_uart_xmit() function
> > to transmit the characters and apply back pressure to the guest with
> > the SIFIVE_UART_TXFIFO_FULL status.
> >
> > This should avoid dropped characters and more realisticly model the
> > hardware.
>
> Does the UART work reliably using the fifo8_*_bufptr() functions? One of the
I haven't noticed any issues.
> motivations for my recent Fifo8 series is that these functions don't handle the
> wraparound correctly, unlike the fifo8_*_buf() functions in my recent Fifo8 series
> which do. This was the cause of Phil's async issue in
> https://mail.gnu.org/archive/html/qemu-devel/2024-07/msg05028.html.
I'm not sure if it matters here
characters = fifo8_peek_bufptr(&s->tx_fifo,
fifo8_num_used(&s->tx_fifo), &numptr);
ret = qemu_chr_fe_write(&s->chr, characters, numptr);
if (ret >= 0) {
/* We wrote the data, actually pop the fifo */
fifo8_pop_bufptr(&s->tx_fifo, ret, NULL);
}
I don't care how many characters are returned from
fifo8_peek_bufptr(), I'll just write them and then pop that number
with fifo8_pop_bufptr()
If fifo8_is_empty() isn't empty I re-add the watcher for qemu_chr_fe_add_watch()
Alistair
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 0/2] riscv: char: Avoid dropped charecters
2024-09-10 4:54 [PATCH v4 0/2] riscv: char: Avoid dropped charecters Alistair Francis
2024-09-10 4:54 ` [PATCH v4 1/2] hw/char: riscv_htif: Use blocking qemu_chr_fe_write_all Alistair Francis
2024-09-10 4:54 ` [PATCH v4 2/2] hw/char: sifive_uart: Print uart characters async Alistair Francis
@ 2024-10-17 13:22 ` Thomas Huth
2024-10-21 3:44 ` Alistair Francis
2 siblings, 1 reply; 9+ messages in thread
From: Thomas Huth @ 2024-10-17 13:22 UTC (permalink / raw)
To: Alistair Francis, qemu-devel, alex.bennee, peter.maydell
Cc: Bin Meng, palmer, liwei1518, zhiwei_liu, qemu-riscv,
Alistair Francis, Paolo Bonzini, Marc-André Lureau, atishp,
dbarboza
On 10/09/2024 06.54, Alistair Francis wrote:
> This series fixes: https://gitlab.com/qemu-project/qemu/-/issues/2114
>
> This converts the RISC-V charecter device callers of qemu_chr_fe_write()
> to either use qemu_chr_fe_write_all() or to call qemu_chr_fe_write() async
> and act on the return value.
>
> v4:
> - Drop the unused char_tx_time
> - Update the migration in vmstate_sifive_uart
> v3:
> - Fixup spelling
> v2:
> - Use Fifo8 for the Sifive UART instead of a custom FIFO
>
> Alistair Francis (2):
> hw/char: riscv_htif: Use blocking qemu_chr_fe_write_all
> hw/char: sifive_uart: Print uart characters async
Hi!
What's the status of these patches? Are they good to go, or do they still
need more work? (I'm asking because I'd like to convert
tests/avocado/riscv_opensbi.py to the functional test framework, but it
would be good to have the problem with the dropped characters fixed first)
Thanks,
Thomas
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 0/2] riscv: char: Avoid dropped charecters
2024-10-17 13:22 ` [PATCH v4 0/2] riscv: char: Avoid dropped charecters Thomas Huth
@ 2024-10-21 3:44 ` Alistair Francis
0 siblings, 0 replies; 9+ messages in thread
From: Alistair Francis @ 2024-10-21 3:44 UTC (permalink / raw)
To: Thomas Huth
Cc: qemu-devel, alex.bennee, peter.maydell, Bin Meng, palmer,
liwei1518, zhiwei_liu, qemu-riscv, Alistair Francis,
Paolo Bonzini, Marc-André Lureau, atishp, dbarboza
On Thu, Oct 17, 2024 at 11:22 PM Thomas Huth <thuth@redhat.com> wrote:
>
> On 10/09/2024 06.54, Alistair Francis wrote:
> > This series fixes: https://gitlab.com/qemu-project/qemu/-/issues/2114
> >
> > This converts the RISC-V charecter device callers of qemu_chr_fe_write()
> > to either use qemu_chr_fe_write_all() or to call qemu_chr_fe_write() async
> > and act on the return value.
> >
> > v4:
> > - Drop the unused char_tx_time
> > - Update the migration in vmstate_sifive_uart
> > v3:
> > - Fixup spelling
> > v2:
> > - Use Fifo8 for the Sifive UART instead of a custom FIFO
> >
> > Alistair Francis (2):
> > hw/char: riscv_htif: Use blocking qemu_chr_fe_write_all
> > hw/char: sifive_uart: Print uart characters async
>
> Hi!
>
> What's the status of these patches? Are they good to go, or do they still
> need more work? (I'm asking because I'd like to convert
> tests/avocado/riscv_opensbi.py to the functional test framework, but it
> would be good to have the problem with the dropped characters fixed first)
I think they are good to go
Applied to riscv-to-apply.next
Alistair
>
> Thanks,
> Thomas
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2024-10-21 3:46 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-10 4:54 [PATCH v4 0/2] riscv: char: Avoid dropped charecters Alistair Francis
2024-09-10 4:54 ` [PATCH v4 1/2] hw/char: riscv_htif: Use blocking qemu_chr_fe_write_all Alistair Francis
2024-09-10 7:16 ` Philippe Mathieu-Daudé
2024-09-10 4:54 ` [PATCH v4 2/2] hw/char: sifive_uart: Print uart characters async Alistair Francis
2024-09-10 7:16 ` Philippe Mathieu-Daudé
2024-09-10 20:34 ` Mark Cave-Ayland
2024-09-11 1:53 ` Alistair Francis
2024-10-17 13:22 ` [PATCH v4 0/2] riscv: char: Avoid dropped charecters Thomas Huth
2024-10-21 3:44 ` Alistair Francis
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).