ia64/xen-unstable

changeset 5326:fd6da43c07ab

bitkeeper revision 1.1675 (42a2d9c5PelbdNceuL1qXullGOrtHA)

ns16550 interrupt handler should not return until the IIR indicates
no pending interrupts. Also a few generic serial driver cleanups.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Sun Jun 05 10:53:57 2005 +0000 (2005-06-05)
parents 66803c3fa4fd
children 84ce09862452
files xen/drivers/char/ns16550.c xen/drivers/char/serial.c
line diff
     1.1 --- a/xen/drivers/char/ns16550.c	Sun Jun 05 10:11:05 2005 +0000
     1.2 +++ b/xen/drivers/char/ns16550.c	Sun Jun 05 10:53:57 2005 +0000
     1.3 @@ -49,7 +49,15 @@ static struct ns16550 {
     1.4  #define IER_ELSI        0x04    /* rx line status       */
     1.5  #define IER_EMSI        0x08    /* MODEM status         */
     1.6  
     1.7 -/* FIFO control register */
     1.8 +/* Interrupt Identification Register */
     1.9 +#define IIR_NOINT       0x01    /* no interrupt pending */
    1.10 +#define IIR_IMASK       0x06    /* interrupt identity:  */
    1.11 +#define IIR_LSI         0x06    /*  - rx line status    */
    1.12 +#define IIR_RDAI        0x04    /*  - rx data recv'd    */
    1.13 +#define IIR_THREI       0x02    /*  - tx reg. empty     */
    1.14 +#define IIR_MSI         0x00    /*  - MODEM status      */
    1.15 +
    1.16 +/* FIFO Control Register */
    1.17  #define FCR_ENABLE      0x01    /* enable FIFO          */
    1.18  #define FCR_CLRX        0x02    /* clear Rx FIFO        */
    1.19  #define FCR_CLTX        0x04    /* clear Tx FIFO        */
    1.20 @@ -59,7 +67,7 @@ static struct ns16550 {
    1.21  #define FCR_TRG8        0x80    /* Rx FIFO trig lev 8   */
    1.22  #define FCR_TRG14       0xc0    /* Rx FIFO trig lev 14  */
    1.23  
    1.24 -/* Line control register */
    1.25 +/* Line Control Register */
    1.26  #define LCR_DLAB        0x80    /* Divisor Latch Access */
    1.27  
    1.28  /* Modem Control Register */
    1.29 @@ -104,10 +112,11 @@ static void ns16550_interrupt(
    1.30      struct serial_port *port = dev_id;
    1.31      struct ns16550 *uart = port->uart;
    1.32  
    1.33 -    if ( (ns_read_reg(uart, IIR) & 7) == 2 )
    1.34 +    while ( !(ns_read_reg(uart, IIR) & IIR_NOINT) )
    1.35 +    {
    1.36          serial_tx_interrupt(port, regs);
    1.37 -    else
    1.38          serial_rx_interrupt(port, regs);
    1.39 +    }
    1.40  }
    1.41  
    1.42  static int ns16550_tx_empty(struct serial_port *port)
     2.1 --- a/xen/drivers/char/serial.c	Sun Jun 05 10:11:05 2005 +0000
     2.2 +++ b/xen/drivers/char/serial.c	Sun Jun 05 10:53:57 2005 +0000
     2.3 @@ -22,20 +22,13 @@ static struct serial_port com[2] = {
     2.4  void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
     2.5  {
     2.6      char c;
     2.7 -    serial_rx_fn fn;
     2.8 +    serial_rx_fn fn = NULL;
     2.9      unsigned long flags;
    2.10  
    2.11 -    BUG_ON(!port->driver);
    2.12 -    BUG_ON(!port->driver->getc);
    2.13 +    spin_lock_irqsave(&port->lock, flags);
    2.14  
    2.15 -    for ( ; ; )
    2.16 +    if ( port->driver->getc(port, &c) )
    2.17      {
    2.18 -        spin_lock_irqsave(&port->lock, flags);
    2.19 -
    2.20 -        if ( !port->driver->getc(port, &c) )
    2.21 -            break;
    2.22 -
    2.23 -        fn = NULL;
    2.24          if ( port->rx != NULL )
    2.25              fn = port->rx;
    2.26          else if ( (c & 0x80) && (port->rx_hi != NULL) )
    2.27 @@ -44,16 +37,12 @@ void serial_rx_interrupt(struct serial_p
    2.28              fn = port->rx_lo;
    2.29          else if ( (port->rxbufp - port->rxbufc) != SERIAL_RXBUFSZ )
    2.30              port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufp++)] = c;            
    2.31 -
    2.32 -        spin_unlock_irqrestore(&port->lock, flags);
    2.33 -
    2.34 -        if ( fn != NULL )
    2.35 -            (*fn)(c & 0x7f, regs);
    2.36 -
    2.37 -        cpu_relax();
    2.38      }
    2.39  
    2.40      spin_unlock_irqrestore(&port->lock, flags);
    2.41 +
    2.42 +    if ( fn != NULL )
    2.43 +        (*fn)(c & 0x7f, regs);
    2.44  }
    2.45  
    2.46  void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
    2.47 @@ -61,18 +50,17 @@ void serial_tx_interrupt(struct serial_p
    2.48      int i;
    2.49      unsigned long flags;
    2.50  
    2.51 -    BUG_ON(!port->driver);
    2.52 -    BUG_ON(!port->driver->tx_empty);
    2.53 -    BUG_ON(!port->driver->putc);
    2.54 -
    2.55      spin_lock_irqsave(&port->lock, flags);
    2.56  
    2.57 -    for ( i = 0; i < port->tx_fifo_size; i++ )
    2.58 +    if ( port->driver->tx_empty(port) )
    2.59      {
    2.60 -        if ( port->txbufc == port->txbufp )
    2.61 -            break;
    2.62 -        port->driver->putc(
    2.63 -            port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
    2.64 +        for ( i = 0; i < port->tx_fifo_size; i++ )
    2.65 +        {
    2.66 +            if ( port->txbufc == port->txbufp )
    2.67 +                break;
    2.68 +            port->driver->putc(
    2.69 +                port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
    2.70 +        }
    2.71      }
    2.72  
    2.73      spin_unlock_irqrestore(&port->lock, flags);
    2.74 @@ -146,8 +134,29 @@ void serial_putc(int handle, char c)
    2.75  
    2.76  void serial_puts(int handle, const char *s)
    2.77  {
    2.78 -    while ( *s != '\0' )
    2.79 -        serial_putc(handle, *s++);
    2.80 +    struct serial_port *port = &com[handle & SERHND_IDX];
    2.81 +    unsigned long flags;
    2.82 +    char c;
    2.83 +
    2.84 +    if ( (handle == -1) || !port->driver || !port->driver->putc )
    2.85 +        return;
    2.86 +
    2.87 +    spin_lock_irqsave(&port->lock, flags);
    2.88 +
    2.89 +    while ( (c = *s++) != '\0' )
    2.90 +    {
    2.91 +        if ( (c == '\n') && (handle & SERHND_COOKED) )
    2.92 +            __serial_putc(port, '\r');
    2.93 +
    2.94 +        if ( handle & SERHND_HI )
    2.95 +            c |= 0x80;
    2.96 +        else if ( handle & SERHND_LO )
    2.97 +            c &= 0x7f;
    2.98 +
    2.99 +        __serial_putc(port, c);
   2.100 +    }
   2.101 +
   2.102 +    spin_unlock_irqrestore(&port->lock, flags);
   2.103  }
   2.104  
   2.105  char serial_getc(int handle)