diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2013-03-05 23:21:33 +0530 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2013-03-08 13:57:17 -0600 |
commit | fcfb4d6aae611d1f804d486d3c998000912c4c81 (patch) | |
tree | 1821cf5e78f99ae14e5cce17b25e8a039316da1e /hw/serial.c | |
parent | 01f45d986fb0b7c2d4f0466efe3cde9708f325be (diff) |
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>
Diffstat (limited to 'hw/serial.c')
-rw-r--r-- | hw/serial.c | 28 |
1 files changed, 11 insertions, 17 deletions
diff --git a/hw/serial.c b/hw/serial.c index f0ce9b0c15..eb38f2231d 100644 --- a/hw/serial.c +++ b/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, |