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:
parent
01f45d986f
commit
fcfb4d6aae
28
hw/serial.c
28
hw/serial.c
@ -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,
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user