ia64/xen-unstable

changeset 8027:188a4fb5ea1f

Adds ac_timer based polling to the ns16550 UART driver. This is
useful when the interrupt line is not connected in hardware or the
mechanism to enable it is not readily available in the hypervisor.
Polling is only enabled when the UART IRQ is set to zero.

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Thu Nov 24 12:06:07 2005 +0100 (2005-11-24)
parents e1728d3c18ca
children dca4893b0b9f cbf7efa871ae
files xen/drivers/char/ns16550.c
line diff
     1.1 --- a/xen/drivers/char/ns16550.c	Thu Nov 24 11:17:20 2005 +0100
     1.2 +++ b/xen/drivers/char/ns16550.c	Thu Nov 24 12:06:07 2005 +0100
     1.3 @@ -29,7 +29,11 @@ static struct ns16550 {
     1.4      int baud, data_bits, parity, stop_bits, irq;
     1.5      unsigned long io_base;   /* I/O port or memory-mapped I/O address. */
     1.6      char *remapped_io_base;  /* Remapped virtual address of mmap I/O.  */ 
     1.7 +    /* UART with IRQ line: interrupt-driven I/O. */
     1.8      struct irqaction irqaction;
     1.9 +    /* UART with no IRQ line: periodically-polled I/O. */
    1.10 +    struct ac_timer timer;
    1.11 +    unsigned int timeout_ms;
    1.12  } ns16550_com[2] = { { 0 } };
    1.13  
    1.14  /* Register offsets */
    1.15 @@ -121,6 +125,21 @@ static void ns16550_interrupt(
    1.16      }
    1.17  }
    1.18  
    1.19 +static void ns16550_poll(void *data)
    1.20 +{
    1.21 +    struct serial_port *port = data;
    1.22 +    struct ns16550 *uart = port->uart;
    1.23 +    struct cpu_user_regs *regs = guest_cpu_user_regs();
    1.24 +
    1.25 +    while ( ns_read_reg(uart, LSR) & LSR_DR )
    1.26 +        serial_rx_interrupt(port, regs);
    1.27 +
    1.28 +    if ( ns_read_reg(uart, LSR) & LSR_THRE )
    1.29 +        serial_tx_interrupt(port, regs);
    1.30 +
    1.31 +    set_ac_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
    1.32 +}
    1.33 +
    1.34  static int ns16550_tx_empty(struct serial_port *port)
    1.35  {
    1.36      struct ns16550 *uart = port->uart;
    1.37 @@ -181,24 +200,35 @@ static void ns16550_init_preirq(struct s
    1.38  static void ns16550_init_postirq(struct serial_port *port)
    1.39  {
    1.40      struct ns16550 *uart = port->uart;
    1.41 -    int rc;
    1.42 +    int rc, bits;
    1.43  
    1.44 -    if ( uart->irq <= 0 )
    1.45 +    if ( uart->irq < 0 )
    1.46          return;
    1.47  
    1.48      serial_async_transmit(port);
    1.49  
    1.50 -    uart->irqaction.handler = ns16550_interrupt;
    1.51 -    uart->irqaction.name    = "ns16550";
    1.52 -    uart->irqaction.dev_id  = port;
    1.53 -    if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
    1.54 -        printk("ERROR: Failed to allocate na16550 IRQ %d\n", uart->irq);
    1.55 +    if ( uart->irq == 0 )
    1.56 +    {
    1.57 +        /* Polled mode. Calculate time to fill RX FIFO and/or empty TX FIFO. */
    1.58 +        bits = uart->data_bits + uart->stop_bits + !!uart->parity;
    1.59 +        uart->timeout_ms = (bits * port->tx_fifo_size * 1000) / uart->baud;
    1.60 +        init_ac_timer(&uart->timer, ns16550_poll, port, 0);
    1.61 +        set_ac_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
    1.62 +    }
    1.63 +    else
    1.64 +    {
    1.65 +        uart->irqaction.handler = ns16550_interrupt;
    1.66 +        uart->irqaction.name    = "ns16550";
    1.67 +        uart->irqaction.dev_id  = port;
    1.68 +        if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
    1.69 +            printk("ERROR: Failed to allocate na16550 IRQ %d\n", uart->irq);
    1.70  
    1.71 -    /* Master interrupt enable; also keep DTR/RTS asserted. */
    1.72 -    ns_write_reg(uart, MCR, MCR_OUT2 | MCR_DTR | MCR_RTS);
    1.73 +        /* Master interrupt enable; also keep DTR/RTS asserted. */
    1.74 +        ns_write_reg(uart, MCR, MCR_OUT2 | MCR_DTR | MCR_RTS);
    1.75  
    1.76 -    /* Enable receive and transmit interrupts. */
    1.77 -    ns_write_reg(uart, IER, IER_ERDAI | IER_ETHREI);
    1.78 +        /* Enable receive and transmit interrupts. */
    1.79 +        ns_write_reg(uart, IER, IER_ERDAI | IER_ETHREI);
    1.80 +    }
    1.81  }
    1.82  
    1.83  #ifdef CONFIG_X86