debuggers.hg

changeset 20955:12fc55dffb6b

Handle bogus serial ports that appear normal, but don't generate
interrupts e.g. the "remote serial console" on Blades.

Authored-by: Gary Grebus <Gary.Grebus@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Feb 08 08:49:19 2010 +0000 (2010-02-08)
parents a06e9def02bb
children 5e49312fcb44
files xen/drivers/char/ns16550.c
line diff
     1.1 --- a/xen/drivers/char/ns16550.c	Mon Feb 08 08:48:40 2010 +0000
     1.2 +++ b/xen/drivers/char/ns16550.c	Mon Feb 08 08:49:19 2010 +0000
     1.3 @@ -39,6 +39,7 @@ static struct ns16550 {
     1.4      /* UART with no IRQ line: periodically-polled I/O. */
     1.5      struct timer timer;
     1.6      unsigned int timeout_ms;
     1.7 +    int probing, intr_works;
     1.8  } ns16550_com[2] = { { 0 } };
     1.9  
    1.10  /* Register offsets */
    1.11 @@ -127,6 +128,13 @@ static void ns16550_interrupt(
    1.12      struct serial_port *port = dev_id;
    1.13      struct ns16550 *uart = port->uart;
    1.14  
    1.15 +    if (uart->intr_works == 0)
    1.16 +    {
    1.17 +        uart->probing = 0;
    1.18 +        uart->intr_works = 1;
    1.19 +        stop_timer(&uart->timer);
    1.20 +    }
    1.21 +
    1.22      while ( !(ns_read_reg(uart, IIR) & IIR_NOINT) )
    1.23      {
    1.24          char lsr = ns_read_reg(uart, LSR);
    1.25 @@ -143,6 +151,15 @@ static void ns16550_poll(void *data)
    1.26      struct ns16550 *uart = port->uart;
    1.27      struct cpu_user_regs *regs = guest_cpu_user_regs();
    1.28  
    1.29 +    if ( uart->intr_works )
    1.30 +        return;     /* Interrupts work - no more polling */
    1.31 +
    1.32 +    if ( uart->probing ) {
    1.33 +        uart->probing = 0;
    1.34 +        if ( (ns_read_reg(uart, LSR) & 0xff) == 0xff )
    1.35 +            return;     /* All bits set - probably no UART present */
    1.36 +    }
    1.37 +
    1.38      while ( ns_read_reg(uart, LSR) & LSR_DR )
    1.39          serial_rx_interrupt(port, regs);
    1.40  
    1.41 @@ -230,15 +247,14 @@ static void __devinit ns16550_init_posti
    1.42  
    1.43      serial_async_transmit(port);
    1.44  
    1.45 +    init_timer(&uart->timer, ns16550_poll, port, 0);
    1.46 +    /* Calculate time to fill RX FIFO and/or empty TX FIFO for polling. */
    1.47 +    bits = uart->data_bits + uart->stop_bits + !!uart->parity;
    1.48 +    uart->timeout_ms = max_t(
    1.49 +        unsigned int, 1, (bits * port->tx_fifo_size * 1000) / uart->baud);
    1.50 +
    1.51      if ( uart->irq == 0 )
    1.52 -    {
    1.53 -        /* Polled mode. Calculate time to fill RX FIFO and/or empty TX FIFO. */
    1.54 -        bits = uart->data_bits + uart->stop_bits + !!uart->parity;
    1.55 -        uart->timeout_ms = max_t(
    1.56 -            unsigned int, 1, (bits * port->tx_fifo_size * 1000) / uart->baud);
    1.57 -        init_timer(&uart->timer, ns16550_poll, port, 0);
    1.58          set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
    1.59 -    }
    1.60      else
    1.61      {
    1.62          uart->irqaction.handler = ns16550_interrupt;
    1.63 @@ -252,6 +268,12 @@ static void __devinit ns16550_init_posti
    1.64  
    1.65          /* Enable receive and transmit interrupts. */
    1.66          ns_write_reg(uart, IER, IER_ERDAI | IER_ETHREI);
    1.67 +
    1.68 +        /* Do a timed write to make sure we are getting interrupts. */
    1.69 +        uart->probing = 1;
    1.70 +        uart->intr_works = 0;
    1.71 +        ns_write_reg(uart, THR, 0xff);
    1.72 +        set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
    1.73      }
    1.74  }
    1.75