From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Jsly8-0005Xz-P9 for qemu-devel@nongnu.org; Sun, 04 May 2008 17:42:04 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Jsly8-0005Wt-0Y for qemu-devel@nongnu.org; Sun, 04 May 2008 17:42:04 -0400 Received: from [199.232.76.173] (port=40759 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Jsly7-0005WZ-SC for qemu-devel@nongnu.org; Sun, 04 May 2008 17:42:03 -0400 Received: from savannah.gnu.org ([199.232.41.3] helo=sv.gnu.org) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1Jsly7-00030B-Gi for qemu-devel@nongnu.org; Sun, 04 May 2008 17:42:03 -0400 Received: from cvs.savannah.gnu.org ([199.232.41.69]) by sv.gnu.org with esmtp (Exim 4.63) (envelope-from ) id 1Jsly6-0006Bt-5f for qemu-devel@nongnu.org; Sun, 04 May 2008 21:42:02 +0000 Received: from aurel32 by cvs.savannah.gnu.org with local (Exim 4.63) (envelope-from ) id 1Jsly5-0006BH-C9 for qemu-devel@nongnu.org; Sun, 04 May 2008 21:42:01 +0000 MIME-Version: 1.0 Errors-To: aurel32 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Aurelien Jarno Message-Id: Date: Sun, 04 May 2008 21:42:01 +0000 Subject: [Qemu-devel] [4335] 8250: throttle TX-completion IRQs Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Revision: 4335 http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=4335 Author: aurel32 Date: 2008-05-04 21:42:00 +0000 (Sun, 04 May 2008) Log Message: ----------- 8250: throttle TX-completion IRQs (Jan Kiszka) Modified Paths: -------------- trunk/hw/serial.c Modified: trunk/hw/serial.c =================================================================== --- trunk/hw/serial.c 2008-05-04 20:11:44 UTC (rev 4334) +++ trunk/hw/serial.c 2008-05-04 21:42:00 UTC (rev 4335) @@ -25,6 +25,7 @@ #include "qemu-char.h" #include "isa.h" #include "pc.h" +#include "qemu-timer.h" //#define DEBUG_SERIAL @@ -73,6 +74,13 @@ #define UART_LSR_OE 0x02 /* Overrun error indicator */ #define UART_LSR_DR 0x01 /* Receiver data ready */ +/* + * Delay TX IRQ after sending as much characters as the given interval would + * contain on real hardware. This avoids overloading the guest if it processes + * its output buffer in a loop inside the TX IRQ handler. + */ +#define THROTTLE_TX_INTERVAL 10 /* ms */ + struct SerialState { uint16_t divider; uint8_t rbr; /* receive register */ @@ -91,6 +99,8 @@ int last_break_enable; target_phys_addr_t base; int it_shift; + QEMUTimer *tx_timer; + int tx_burst; }; static void serial_receive_byte(SerialState *s, int ch); @@ -111,6 +121,28 @@ } } +static void serial_tx_done(void *opaque) +{ + SerialState *s = opaque; + + if (s->tx_burst < 0) { + uint16_t divider; + + if (s->divider) + divider = s->divider; + else + divider = 1; + + /* We assume 10 bits/char, OK for this purpose. */ + s->tx_burst = THROTTLE_TX_INTERVAL * 1000 / + (1000000 * 10 / (115200 / divider)); + } + s->thr_ipending = 1; + s->lsr |= UART_LSR_THRE; + s->lsr |= UART_LSR_TEMT; + serial_update_irq(s); +} + static void serial_update_parameters(SerialState *s) { int speed, parity, data_bits, stop_bits; @@ -166,15 +198,18 @@ if (!(s->mcr & UART_MCR_LOOP)) { /* when not in loopback mode, send the char */ qemu_chr_write(s->chr, &ch, 1); - } - s->thr_ipending = 1; - s->lsr |= UART_LSR_THRE; - s->lsr |= UART_LSR_TEMT; - serial_update_irq(s); - if (s->mcr & UART_MCR_LOOP) { + } else { /* in loopback mode, say that we just received a char */ serial_receive_byte(s, ch); } + if (s->tx_burst > 0) { + s->tx_burst--; + serial_tx_done(s); + } else if (s->tx_burst == 0) { + s->tx_burst--; + qemu_mod_timer(s->tx_timer, qemu_get_clock(vm_clock) + + ticks_per_sec * THROTTLE_TX_INTERVAL / 1000); + } } break; case 1: @@ -387,6 +422,10 @@ return NULL; s->irq = irq; + s->tx_timer = qemu_new_timer(vm_clock, serial_tx_done, s); + if (!s->tx_timer) + return NULL; + qemu_register_reset(serial_reset, s); serial_reset(s); @@ -486,6 +525,10 @@ s->base = base; s->it_shift = it_shift; + s->tx_timer = qemu_new_timer(vm_clock, serial_tx_done, s); + if (!s->tx_timer) + return NULL; + qemu_register_reset(serial_reset, s); serial_reset(s);