WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] Interrupt-driven serial transmit for 8250/16550 UARTs.

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] Interrupt-driven serial transmit for 8250/16550 UARTs.
From: BitKeeper Bot <riel@xxxxxxxxxxx>
Date: Sat, 04 Jun 2005 17:35:19 +0000
Delivery-date: Sat, 04 Jun 2005 18:01:16 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: Xen Development List <xen-devel@xxxxxxxxxxxxxxxxxxx>
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
ChangeSet 1.1670, 2005/06/04 18:35:19+01:00, kaf24@xxxxxxxxxxxxxxxxxxxx

        Interrupt-driven serial transmit for 8250/16550 UARTs.
        Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>



 arch/x86/cdb.c         |    5 +
 arch/x86/domain.c      |    4 +
 arch/x86/traps.c       |    1 
 drivers/char/console.c |   10 +++
 drivers/char/ns16550.c |   32 ++++++++----
 drivers/char/serial.c  |  126 +++++++++++++++++++++++++++++++++++++++++++++++--
 include/xen/console.h  |    3 +
 include/xen/serial.h   |   37 +++++++++++---
 8 files changed, 196 insertions(+), 22 deletions(-)


diff -Nru a/xen/arch/x86/cdb.c b/xen/arch/x86/cdb.c
--- a/xen/arch/x86/cdb.c        2005-06-04 14:02:05 -04:00
+++ b/xen/arch/x86/cdb.c        2005-06-04 14:02:05 -04:00
@@ -358,6 +358,7 @@
        local_irq_save(flags);
 
        watchdog_disable();
+       console_start_sync();
 
        /* Shouldn't really do this, but otherwise we stop for no
           obvious reason, which is Bad */
@@ -383,9 +384,13 @@
                        ASSERT(!local_irq_is_enabled());
                }
        }
+
+       console_end_sync();
        watchdog_enable();
        atomic_inc(&xendbg_running);
+
        local_irq_restore(flags);
+
        return 0;
 }
 
diff -Nru a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     2005-06-04 14:02:06 -04:00
+++ b/xen/arch/x86/domain.c     2005-06-04 14:02:06 -04:00
@@ -123,6 +123,9 @@
             safe_halt();
     }
 
+    watchdog_disable();
+    console_start_sync();
+
     local_irq_enable();
 
     /* Ensure we are the boot CPU. */
@@ -174,6 +177,7 @@
 void machine_halt(void)
 {
     watchdog_disable();
+    console_start_sync();
     smp_call_function(__machine_halt, NULL, 1, 0);
     __machine_halt(NULL);
 }
diff -Nru a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c      2005-06-04 14:02:05 -04:00
+++ b/xen/arch/x86/traps.c      2005-06-04 14:02:05 -04:00
@@ -205,6 +205,7 @@
     };
 
     watchdog_disable();
+    console_start_sync();
 
     show_registers(regs);
 
diff -Nru a/xen/drivers/char/console.c b/xen/drivers/char/console.c
--- a/xen/drivers/char/console.c        2005-06-04 14:02:05 -04:00
+++ b/xen/drivers/char/console.c        2005-06-04 14:02:05 -04:00
@@ -467,6 +467,16 @@
     spin_lock(&console_lock);
 }
 
+void console_start_sync(void)
+{
+    serial_start_sync(sercon_handle);
+}
+
+void console_end_sync(void)
+{
+    serial_end_sync(sercon_handle);
+}
+
 void console_putc(char c)
 {
     serial_putc(sercon_handle, c);
diff -Nru a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
--- a/xen/drivers/char/ns16550.c        2005-06-04 14:02:06 -04:00
+++ b/xen/drivers/char/ns16550.c        2005-06-04 14:02:06 -04:00
@@ -101,16 +101,24 @@
 static void ns16550_interrupt(
     int irq, void *dev_id, struct cpu_user_regs *regs)
 {
-    serial_rx_interrupt(dev_id, regs);
+    struct serial_port *port = dev_id;
+    struct ns16550 *uart = port->uart;
+
+    if ( (ns_read_reg(uart, IIR) & 7) == 2 )
+        serial_tx_interrupt(port, regs);
+    else
+        serial_rx_interrupt(port, regs);
 }
 
-static void ns16550_putc(struct serial_port *port, char c)
+static int ns16550_tx_empty(struct serial_port *port)
 {
     struct ns16550 *uart = port->uart;
+    return !!(ns_read_reg(uart, LSR) & LSR_THRE);
+}
 
-    while ( !(ns_read_reg(uart, LSR) & LSR_THRE) )
-        cpu_relax();
-
+static void ns16550_putc(struct serial_port *port, char c)
+{
+    struct ns16550 *uart = port->uart;
     ns_write_reg(uart, THR, c);
 }
 
@@ -150,6 +158,10 @@
 
     /* Enable and clear the FIFOs. Set a large trigger threshold. */
     ns_write_reg(uart, FCR, FCR_ENABLE | FCR_CLRX | FCR_CLTX | FCR_TRG14);
+
+    /* Check this really is a 16550+. Otherwise we have no FIFOs. */
+    if ( (ns_read_reg(uart, IIR) & 0xc0) == 0xc0 )
+        port->tx_fifo_size = 16;
 }
 
 static void ns16550_init_postirq(struct serial_port *port)
@@ -157,20 +169,19 @@
     struct ns16550 *uart = port->uart;
     int rc;
 
+    serial_async_transmit(port);
+
     uart->irqaction.handler = ns16550_interrupt;
     uart->irqaction.name    = "ns16550";
     uart->irqaction.dev_id  = port;
     if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
         printk("ERROR: Failed to allocate na16550 IRQ %d\n", uart->irq);
 
-    /* For sanity, clear the receive FIFO. */
-    ns_write_reg(uart, FCR, FCR_ENABLE | FCR_CLRX | FCR_TRG14);
-
     /* Master interrupt enable; also keep DTR/RTS asserted. */
     ns_write_reg(uart, MCR, MCR_OUT2 | MCR_DTR | MCR_RTS);
 
-    /* Enable receive interrupts. */
-    ns_write_reg(uart, IER, IER_ERDAI);
+    /* Enable receive and transmit interrupts. */
+    ns_write_reg(uart, IER, IER_ERDAI | IER_ETHREI);
 }
 
 #ifdef CONFIG_X86
@@ -188,6 +199,7 @@
     .init_preirq  = ns16550_init_preirq,
     .init_postirq = ns16550_init_postirq,
     .endboot      = ns16550_endboot,
+    .tx_empty     = ns16550_tx_empty,
     .putc         = ns16550_putc,
     .getc         = ns16550_getc
 };
diff -Nru a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c
--- a/xen/drivers/char/serial.c 2005-06-04 14:02:06 -04:00
+++ b/xen/drivers/char/serial.c 2005-06-04 14:02:06 -04:00
@@ -42,8 +42,8 @@
             fn = port->rx_hi;
         else if ( !(c & 0x80) && (port->rx_lo != NULL) )
             fn = port->rx_lo;
-        else if ( (port->rxbufp - port->rxbufc) != RXBUFSZ )
-            port->rxbuf[MASK_RXBUF_IDX(port->rxbufp++)] = c;            
+        else if ( (port->rxbufp - port->rxbufc) != SERIAL_RXBUFSZ )
+            port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufp++)] = c;            
 
         spin_unlock_irqrestore(&port->lock, flags);
 
@@ -56,6 +56,71 @@
     spin_unlock_irqrestore(&port->lock, flags);
 }
 
+void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
+{
+    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->txbufc == port->txbufp )
+            break;
+        port->driver->putc(
+            port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
+    }
+
+    spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void __serial_putc(struct serial_port *port, char c)
+{
+    int i;
+
+    if ( (port->txbuf != NULL) && !port->sync )
+    {
+        /* Interrupt-driven (asynchronous) transmitter. */
+        if ( (port->txbufp - port->txbufc) == SERIAL_TXBUFSZ )
+        {
+            /* Buffer is full: we spin, but could alternatively drop chars. */
+            while ( !port->driver->tx_empty(port) )
+                cpu_relax();
+            for ( i = 0; i < port->tx_fifo_size; i++ )
+                port->driver->putc(
+                    port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
+            port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
+        }
+        else if ( ((port->txbufp - port->txbufc) == 0) &&
+                  port->driver->tx_empty(port) )
+        {
+            /* Buffer and UART FIFO are both empty. */
+            port->driver->putc(port, c);
+        }
+        else
+        {
+            /* Normal case: buffer the character. */
+            port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
+        }
+    }
+    else if ( port->driver->tx_empty )
+    {
+        /* Synchronous finite-capacity transmitter. */
+        while ( !port->driver->tx_empty(port) )
+            cpu_relax();
+        port->driver->putc(port, c);
+    }
+    else
+    {
+        /* Simple synchronous transmitter. */
+        port->driver->putc(port, c);
+    }
+}
+
 void serial_putc(int handle, char c)
 {
     struct serial_port *port = &com[handle & SERHND_IDX];
@@ -67,14 +132,14 @@
     spin_lock_irqsave(&port->lock, flags);
 
     if ( (c == '\n') && (handle & SERHND_COOKED) )
-        port->driver->putc(port, '\r');
+        __serial_putc(port, '\r');
 
     if ( handle & SERHND_HI )
         c |= 0x80;
     else if ( handle & SERHND_LO )

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] Interrupt-driven serial transmit for 8250/16550 UARTs., BitKeeper Bot <=