serial: add flow control to transmit

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Message-id: 2976f10d4e66ed4a34011f6f0d6937026d22be5f.1362505276.git.amit.shah@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Anthony Liguori 2013-03-05 23:21:33 +05:30
parent 01f45d986f
commit fcfb4d6aae
2 changed files with 11 additions and 19 deletions

View File

@ -256,16 +256,17 @@ static void serial_update_msl(SerialState *s)
qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100);
}
static void serial_xmit(void *opaque)
static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
{
SerialState *s = opaque;
uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock);
if (s->tsr_retry <= 0) {
if (s->fcr & UART_FCR_FE) {
s->tsr = fifo_get(s,XMIT_FIFO);
if (!s->xmit_fifo.count)
s->lsr |= UART_LSR_THRE;
} else if ((s->lsr & UART_LSR_THRE)) {
return FALSE;
} else {
s->tsr = s->thr;
s->lsr |= UART_LSR_THRE;
@ -277,30 +278,25 @@ static void serial_xmit(void *opaque)
/* in loopback mode, say that we just received a char */
serial_receive1(s, &s->tsr, 1);
} else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) {
if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) {
if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY &&
qemu_chr_fe_add_watch(s->chr, G_IO_OUT, serial_xmit, s) > 0) {
s->tsr_retry++;
qemu_mod_timer(s->transmit_timer, new_xmit_ts + s->char_transmit_time);
return;
} else if (s->poll_msl < 0) {
/* If we exceed MAX_XMIT_RETRY and the backend is not a real serial port, then
drop any further failed writes instantly, until we get one that goes through.
This is to prevent guests that log to unconnected pipes or pty's from stalling. */
s->tsr_retry = -1;
return FALSE;
}
}
else {
s->tsr_retry = 0;
} else {
s->tsr_retry = 0;
}
s->last_xmit_ts = qemu_get_clock_ns(vm_clock);
if (!(s->lsr & UART_LSR_THRE))
qemu_mod_timer(s->transmit_timer, s->last_xmit_ts + s->char_transmit_time);
if (s->lsr & UART_LSR_THRE) {
s->lsr |= UART_LSR_TEMT;
s->thr_ipending = 1;
serial_update_irq(s);
}
return FALSE;
}
@ -330,7 +326,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
s->lsr &= ~UART_LSR_THRE;
serial_update_irq(s);
}
serial_xmit(s);
serial_xmit(NULL, G_IO_OUT, s);
}
break;
case 1:
@ -684,8 +680,6 @@ void serial_init_core(SerialState *s)
s->modem_status_poll = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_update_msl, s);
s->fifo_timeout_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s);
s->transmit_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_xmit, s);
qemu_register_reset(serial_reset, s);
qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,

View File

@ -72,8 +72,6 @@ struct SerialState {
struct QEMUTimer *fifo_timeout_timer;
int timeout_ipending; /* timeout interrupt pending state */
struct QEMUTimer *transmit_timer;
uint64_t char_transmit_time; /* time to transmit a char in ticks */
int poll_msl;