[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH] serial: transmit within the programmed baud rate
From: |
Paolo Bonzini |
Subject: |
[Qemu-devel] [PATCH] serial: transmit within the programmed baud rate |
Date: |
Fri, 8 Jan 2016 16:43:03 +0100 |
Code for throttling the serial port was removed by upstream commit fcfb4d6
("serial: add flow control to transmit", 2013-03-05). Add it back.
The only non-obvious change is that tsr_retry can now become nonzero
also in loopback mode, so the assignment is moved out of the "if".
Signed-off-by: Paolo Bonzini <address@hidden>
---
hw/char/serial.c | 47 ++++++++++++++++++++++++++++++++++++++++++-----
include/hw/char/serial.h | 1 +
2 files changed, 43 insertions(+), 5 deletions(-)
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 513d73c..d96ec4f 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -222,6 +222,7 @@ static void serial_update_msl(SerialState *s)
static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
{
SerialState *s = opaque;
+ uint64_t new_xmit_ts;
do {
assert(!(s->lsr & UART_LSR_TEMT));
@@ -244,6 +245,16 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition
cond, void *opaque)
}
}
+ new_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ /* Do not transmit faster than the desired baud rate. */
+ if (new_xmit_ts < s->last_xmit_ts + s->char_transmit_time) {
+ assert(s->tsr_retry <= 0);
+ s->tsr_retry++;
+ timer_mod(s->transmit_timer, s->last_xmit_ts +
s->char_transmit_time);
+ return FALSE;
+ }
+
if (s->mcr & UART_MCR_LOOP) {
/* in loopback mode, say that we just received a char */
serial_receive1(s, &s->tsr, 1);
@@ -254,21 +265,26 @@ static gboolean serial_xmit(GIOChannel *chan,
GIOCondition cond, void *opaque)
s->tsr_retry++;
return FALSE;
}
- s->tsr_retry = 0;
- } else {
- s->tsr_retry = 0;
}
+ s->tsr_retry = 0;
+ s->last_xmit_ts = new_xmit_ts;
+
/* Transmit another byte if it is already available. It is only
possible when FIFO is enabled and not empty. */
} while (!(s->lsr & UART_LSR_THRE));
- s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
s->lsr |= UART_LSR_TEMT;
-
return FALSE;
}
+static void serial_xmit_timer_cb(void *opaque)
+{
+ SerialState *s = opaque;
+
+ serial_xmit(NULL, G_IO_OUT, s);
+}
+
/* Setter for FCR.
is_load flag means, that value is set while loading VM state
@@ -688,6 +704,23 @@ static const VMStateDescription vmstate_serial_tsr = {
}
};
+static bool serial_xmit_timer_needed(void *opaque)
+{
+ SerialState *s = (SerialState *)opaque;
+ return timer_pending(s->transmit_timer);
+}
+
+static const VMStateDescription vmstate_serial_xmit_timer = {
+ .name = "serial/xmit_timer",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = serial_xmit_timer_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_TIMER_PTR(transmit_timer, SerialState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static bool serial_recv_fifo_needed(void *opaque)
{
SerialState *s = (SerialState *)opaque;
@@ -803,6 +836,7 @@ const VMStateDescription vmstate_serial = {
&vmstate_serial_fifo_timeout_timer,
&vmstate_serial_timeout_ipending,
&vmstate_serial_poll,
+ &vmstate_serial_xmit_timer,
NULL
}
};
@@ -828,6 +862,7 @@ static void serial_reset(void *opaque)
s->timeout_ipending = 0;
timer_del(s->fifo_timeout_timer);
timer_del(s->modem_status_poll);
+ timer_del(s->transmit_timer);
fifo8_reset(&s->recv_fifo);
fifo8_reset(&s->xmit_fifo);
@@ -852,6 +887,7 @@ void serial_realize_core(SerialState *s, Error **errp)
s->modem_status_poll = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *)
serial_update_msl, s);
s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *)
fifo_timeout_int, s);
+ s->transmit_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *)
serial_xmit_timer_cb, s);
qemu_register_reset(serial_reset, s);
qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
@@ -863,6 +899,7 @@ void serial_realize_core(SerialState *s, Error **errp)
void serial_exit_core(SerialState *s)
{
+ timer_del(s->transmit_timer);
qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
qemu_unregister_reset(serial_reset, s);
}
diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h
index 15beb6b..9949ad0 100644
--- a/include/hw/char/serial.h
+++ b/include/hw/char/serial.h
@@ -68,6 +68,7 @@ struct SerialState {
QEMUTimer *fifo_timeout_timer;
int timeout_ipending; /* timeout interrupt pending state */
+ QEMUTimer *transmit_timer;
uint64_t char_transmit_time; /* time to transmit a char in ticks */
int poll_msl;
--
2.5.0
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] [PATCH] serial: transmit within the programmed baud rate,
Paolo Bonzini <=