# HG changeset patch # User kfraser@localhost.localdomain # Node ID c33272c2571c7bab7056d8228490700d1df405f9 # Parent b3d94f4ddffefed8a5cb8dd65a60da9491d460e7 [HVM] Fix Qemu-dm serial issues: 1. Retry transmit via a polling timer if a byte cannot be written immediately to its destination. 2. Turn off output processing of raw serial lines. Signed-off-by: Xiaowei Yang Signed-off-by: Yunhong Jiang Signed-off-by: Keir Fraser Index: ioemu/vl.c =================================================================== --- ioemu.orig/vl.c 2007-05-03 10:09:02.000000000 +0100 +++ ioemu/vl.c 2007-05-03 10:09:02.000000000 +0100 @@ -1740,7 +1740,7 @@ tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|IGNCR|ICRNL|IXON); - tty.c_oflag |= OPOST; + tty.c_oflag &= ~OPOST; /* no output mangling of raw serial stream */ tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS); switch(data_bits) { Index: ioemu/hw/serial.c =================================================================== --- ioemu.orig/hw/serial.c 2007-05-03 10:09:02.000000000 +0100 +++ ioemu/hw/serial.c 2007-05-03 10:09:02.000000000 +0100 @@ -73,6 +73,11 @@ #define UART_LSR_OE 0x02 /* Overrun error indicator */ #define UART_LSR_DR 0x01 /* Receiver data ready */ +/* Maximum retries for a single byte transmit. */ +#define WRITE_MAX_SINGLE_RETRIES 3 +/* Maximum retries for a sequence of back-to-back unsuccessful transmits. */ +#define WRITE_MAX_TOTAL_RETRIES 10 + struct SerialState { uint8_t divider; uint8_t rbr; /* receive register */ @@ -93,6 +98,19 @@ int last_break_enable; target_ulong base; int it_shift; + + /* + * If a character transmitted via UART cannot be written to its + * destination immediately we remember it here and retry a few times via + * a polling timer. + * - write_single_retries: Number of write retries for current byte. + * - write_total_retries: Number of write retries for back-to-back + * unsuccessful transmits. + */ + int write_single_retries; + int write_total_retries; + char write_chr; + QEMUTimer *write_retry_timer; }; static void serial_update_irq(SerialState *s) @@ -204,10 +222,37 @@ tokens_avail--; } +static void serial_chr_write(void *opaque) +{ + SerialState *s = opaque; + + /* Cancel any outstanding retry if this is a new byte. */ + qemu_del_timer(s->write_retry_timer); + + /* Retry every 100ms for 300ms total. */ + if (qemu_chr_write(s->chr, &s->write_chr, 1) == -1) { + s->write_total_retries++; + if (s->write_single_retries++ >= WRITE_MAX_SINGLE_RETRIES) + fprintf(stderr, "serial: write error\n"); + else if (s->write_total_retries <= WRITE_MAX_TOTAL_RETRIES) { + qemu_mod_timer(s->write_retry_timer, + qemu_get_clock(vm_clock) + ticks_per_sec / 10); + return; + } + } else { + s->write_total_retries = 0; /* if successful then reset counter */ + } + + /* Success: Notify guest that THR is empty. */ + s->thr_ipending = 1; + s->lsr |= UART_LSR_THRE; + s->lsr |= UART_LSR_TEMT; + serial_update_irq(s); +} + static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) { SerialState *s = opaque; - unsigned char ch; addr &= 7; #ifdef DEBUG_SERIAL @@ -223,12 +268,9 @@ s->thr_ipending = 0; s->lsr &= ~UART_LSR_THRE; serial_update_irq(s); - ch = val; - 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); + s->write_chr = val; + s->write_single_retries = 0; + serial_chr_write(s); } break; case 1: @@ -424,6 +466,7 @@ s->lsr = UART_LSR_TEMT | UART_LSR_THRE; s->iir = UART_IIR_NO_INT; s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; + s->write_retry_timer = qemu_new_timer(vm_clock, serial_chr_write, s); register_savevm("serial", base, 1, serial_save, serial_load, s); @@ -511,6 +554,7 @@ s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; s->base = base; s->it_shift = it_shift; + s->write_retry_timer = qemu_new_timer(vm_clock, serial_chr_write, s); register_savevm("serial", base, 1, serial_save, serial_load, s);