@@ -226,6 +226,28 @@ static void pl011_loopback_tx(PL011State *s, uint32_t value)
pl011_fifo_rx_put(s, value);
}
+static gboolean pl011_xmit(void *do_not_use, GIOCondition cond, void *opaque)
+{
+ PL011State *s = opaque;
+ int bytes_consumed;
+ uint8_t data;
+
+ data = fifo8_pop(&s->xmit_fifo);
+ bytes_consumed = 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, &data, bytes_consumed);
+ trace_pl011_fifo_tx_xmit(bytes_consumed);
+ s->int_level |= INT_TX;
+
+ pl011_update(s);
+
+ return G_SOURCE_REMOVE;
+}
+
static void pl011_write_txdata(PL011State *s, uint8_t data)
{
if (!(s->cr & CR_UARTEN)) {
@@ -235,12 +257,10 @@ static void pl011_write_txdata(PL011State *s, uint8_t data)
qemu_log_mask(LOG_GUEST_ERROR, "PL011 data written to disabled TX UART\n");
}
- /* XXX this blocks entire thread. Rewrite to use
- * qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(&s->chr, &data, 1);
+ trace_pl011_fifo_tx_put(data);
pl011_loopback_tx(s, data);
- s->int_level |= INT_TX;
- pl011_update(s);
+ fifo8_push(&s->xmit_fifo, data);
+ pl011_xmit(NULL, G_IO_OUT, s);
}
static uint32_t pl011_read_rxdata(PL011State *s)
@@ -60,6 +60,8 @@ pl011_write(uint32_t addr, uint32_t value, const char *regname) "addr 0x%03x val
pl011_can_receive(uint32_t lcr, int read_count, int r) "LCR 0x%08x read_count %d returning %d"
pl011_fifo_rx_put(uint32_t c, int read_count) "new char 0x%02x read_count now %d"
pl011_fifo_rx_full(void) "RX FIFO now full, RXFF set"
+pl011_fifo_tx_put(uint8_t byte) "TX FIFO push char [0x%02x]"
+pl011_fifo_tx_xmit(int count) "TX FIFO pop %d chars"
pl011_baudrate_change(unsigned int baudrate, uint64_t clock, uint32_t ibrd, uint32_t fbrd) "new baudrate %u (clk: %" PRIu64 "hz, ibrd: %" PRIu32 ", fbrd: %" PRIu32 ")"
# cmsdk-apb-uart.c
Extract pl011_xmit() from pl011_write_txdata(). Use the FIFO to pass the character to be transmitted. Implement it using the FEWatchFunc prototype, since we want to register it as GSource later. While the return value is not yet used, we return G_SOURCE_REMOVE meaning the GSource is removed from the main loop (because we only send one char). Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> --- hw/char/pl011.c | 30 +++++++++++++++++++++++++----- hw/char/trace-events | 2 ++ 2 files changed, 27 insertions(+), 5 deletions(-)