[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] ns16550 interrupt handler should not return until the IIR indicates



ChangeSet 1.1675, 2005/06/05 11:53:57+01:00, kaf24@xxxxxxxxxxxxxxxxxxxx

        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@xxxxxxxxxxxxx>



 ns16550.c |   17 ++++++++++++----
 serial.c  |   65 +++++++++++++++++++++++++++++++++++---------------------------
 2 files changed, 50 insertions(+), 32 deletions(-)


diff -Nru a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
--- a/xen/drivers/char/ns16550.c        2005-06-05 07:02:39 -04:00
+++ b/xen/drivers/char/ns16550.c        2005-06-05 07:02:39 -04:00
@@ -49,7 +49,15 @@
 #define IER_ELSI        0x04    /* rx line status       */
 #define IER_EMSI        0x08    /* MODEM status         */
 
-/* FIFO control register */
+/* Interrupt Identification Register */
+#define IIR_NOINT       0x01    /* no interrupt pending */
+#define IIR_IMASK       0x06    /* interrupt identity:  */
+#define IIR_LSI         0x06    /*  - rx line status    */
+#define IIR_RDAI        0x04    /*  - rx data recv'd    */
+#define IIR_THREI       0x02    /*  - tx reg. empty     */
+#define IIR_MSI         0x00    /*  - MODEM status      */
+
+/* FIFO Control Register */
 #define FCR_ENABLE      0x01    /* enable FIFO          */
 #define FCR_CLRX        0x02    /* clear Rx FIFO        */
 #define FCR_CLTX        0x04    /* clear Tx FIFO        */
@@ -59,7 +67,7 @@
 #define FCR_TRG8        0x80    /* Rx FIFO trig lev 8   */
 #define FCR_TRG14       0xc0    /* Rx FIFO trig lev 14  */
 
-/* Line control register */
+/* Line Control Register */
 #define LCR_DLAB        0x80    /* Divisor Latch Access */
 
 /* Modem Control Register */
@@ -104,10 +112,11 @@
     struct serial_port *port = dev_id;
     struct ns16550 *uart = port->uart;
 
-    if ( (ns_read_reg(uart, IIR) & 7) == 2 )
+    while ( !(ns_read_reg(uart, IIR) & IIR_NOINT) )
+    {
         serial_tx_interrupt(port, regs);
-    else
         serial_rx_interrupt(port, regs);
+    }
 }
 
 static int ns16550_tx_empty(struct serial_port *port)
diff -Nru a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c
--- a/xen/drivers/char/serial.c 2005-06-05 07:02:39 -04:00
+++ b/xen/drivers/char/serial.c 2005-06-05 07:02:39 -04:00
@@ -22,20 +22,13 @@
 void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
 {
     char c;
-    serial_rx_fn fn;
+    serial_rx_fn fn = NULL;
     unsigned long flags;
 
-    BUG_ON(!port->driver);
-    BUG_ON(!port->driver->getc);
+    spin_lock_irqsave(&port->lock, flags);
 
-    for ( ; ; )
+    if ( port->driver->getc(port, &c) )
     {
-        spin_lock_irqsave(&port->lock, flags);
-
-        if ( !port->driver->getc(port, &c) )
-            break;
-
-        fn = NULL;
         if ( port->rx != NULL )
             fn = port->rx;
         else if ( (c & 0x80) && (port->rx_hi != NULL) )
@@ -44,16 +37,12 @@
             fn = port->rx_lo;
         else if ( (port->rxbufp - port->rxbufc) != SERIAL_RXBUFSZ )
             port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufp++)] = c;            
-
-        spin_unlock_irqrestore(&port->lock, flags);
-
-        if ( fn != NULL )
-            (*fn)(c & 0x7f, regs);
-
-        cpu_relax();
     }
 
     spin_unlock_irqrestore(&port->lock, flags);
+
+    if ( fn != NULL )
+        (*fn)(c & 0x7f, regs);
 }
 
 void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
@@ -61,18 +50,17 @@
     int i;
     unsigned long flags;
 
-    BUG_ON(!port->driver);
-    BUG_ON(!port->driver->tx_empty);
-    BUG_ON(!port->driver->putc);
-
     spin_lock_irqsave(&port->lock, flags);
 
-    for ( i = 0; i < port->tx_fifo_size; i++ )
+    if ( port->driver->tx_empty(port) )
     {
-        if ( port->txbufc == port->txbufp )
-            break;
-        port->driver->putc(
-            port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
+        for ( i = 0; i < port->tx_fifo_size; i++ )
+        {
+            if ( port->txbufc == port->txbufp )
+                break;
+            port->driver->putc(
+                port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
+        }
     }
 
     spin_unlock_irqrestore(&port->lock, flags);
@@ -146,8 +134,29 @@
 
 void serial_puts(int handle, const char *s)
 {
-    while ( *s != '\0' )
-        serial_putc(handle, *s++);
+    struct serial_port *port = &com[handle & SERHND_IDX];
+    unsigned long flags;
+    char c;
+
+    if ( (handle == -1) || !port->driver || !port->driver->putc )
+        return;
+
+    spin_lock_irqsave(&port->lock, flags);
+
+    while ( (c = *s++) != '\0' )
+    {
+        if ( (c == '\n') && (handle & SERHND_COOKED) )
+            __serial_putc(port, '\r');
+
+        if ( handle & SERHND_HI )
+            c |= 0x80;
+        else if ( handle & SERHND_LO )
+            c &= 0x7f;
+
+        __serial_putc(port, c);
+    }
+
+    spin_unlock_irqrestore(&port->lock, flags);
 }
 
 char serial_getc(int handle)

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.