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

[Xen-changelog] [xen stable-4.5] xen/arm: Manage pl011 uart TX interrupt correctly



commit c93aa9bd457051dfda4890ca0af989889c3adfa1
Author:     Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
AuthorDate: Tue Dec 9 10:09:55 2014 +0530
Commit:     Ian Campbell <ian.campbell@xxxxxxxxxx>
CommitDate: Tue Jan 27 17:03:12 2015 +0000

    xen/arm: Manage pl011 uart TX interrupt correctly
    
    In pl011.c, when TX interrupt is received
    serial_tx_interrupt() is called to push next
    characters. If TX buffer is empty, serial_tx_interrupt()
    does not disable TX interrupt and hence pl011 UART
    irq handler pl011_interrupt() always sees TX interrupt
    status set in MIS register and cpu does not come out of
    UART irq handler.
    
    With this patch, mask TX interrupt by writing 0 to
    IMSC register when TX buffer is empty and unmask by
    writing 1 to IMSC register before sending characters.
    
    Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
    Reviewed-by: Tim Deegan <tim@xxxxxxx>
    (cherry picked from commit 20e297f84035da854ceb6a160981f78ed56a408b)
---
 xen/drivers/char/pl011.c  |   16 ++++++++++++++++
 xen/drivers/char/serial.c |   34 ++++++++++++++++++++++++++++++++++
 xen/include/xen/serial.h  |    4 ++++
 3 files changed, 54 insertions(+), 0 deletions(-)

diff --git a/xen/drivers/char/pl011.c b/xen/drivers/char/pl011.c
index dd19ce8..57274d9 100644
--- a/xen/drivers/char/pl011.c
+++ b/xen/drivers/char/pl011.c
@@ -197,6 +197,20 @@ static const struct vuart_info *pl011_vuart(struct 
serial_port *port)
     return &uart->vuart;
 }
 
+static void pl011_tx_stop(struct serial_port *port)
+{
+    struct pl011 *uart = port->uart;
+
+    pl011_write(uart, IMSC, pl011_read(uart, IMSC) & ~(TXI));
+}
+
+static void pl011_tx_start(struct serial_port *port)
+{
+    struct pl011 *uart = port->uart;
+
+    pl011_write(uart, IMSC, pl011_read(uart, IMSC) | (TXI));
+}
+
 static struct uart_driver __read_mostly pl011_driver = {
     .init_preirq  = pl011_init_preirq,
     .init_postirq = pl011_init_postirq,
@@ -207,6 +221,8 @@ static struct uart_driver __read_mostly pl011_driver = {
     .putc         = pl011_putc,
     .getc         = pl011_getc,
     .irq          = pl011_irq,
+    .start_tx     = pl011_tx_start,
+    .stop_tx      = pl011_tx_stop,
     .vuart_info   = pl011_vuart,
 };
 
diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c
index 44026b1..c583a48 100644
--- a/xen/drivers/char/serial.c
+++ b/xen/drivers/char/serial.c
@@ -31,6 +31,18 @@ static struct serial_port com[SERHND_IDX + 1] = {
 
 static bool_t __read_mostly post_irq;
 
+static inline void serial_start_tx(struct serial_port *port)
+{
+    if ( port->driver->start_tx != NULL )
+        port->driver->start_tx(port);
+}
+
+static inline void serial_stop_tx(struct serial_port *port)
+{
+    if ( port->driver->stop_tx != NULL )
+        port->driver->stop_tx(port);
+}
+
 void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
 {
     char c;
@@ -76,6 +88,18 @@ void serial_tx_interrupt(struct serial_port *port, struct 
cpu_user_regs *regs)
         cpu_relax();
     }
 
+    if ( port->txbufc == port->txbufp )
+    {
+        /* Disable TX. nothing to send */
+        serial_stop_tx(port);
+        spin_unlock(&port->tx_lock);
+        goto out;
+    }
+    else
+    {
+        if ( port->driver->tx_ready(port) )
+            serial_start_tx(port);
+    }
     for ( i = 0, n = port->driver->tx_ready(port); i < n; i++ )
     {
         if ( port->txbufc == port->txbufp )
@@ -117,6 +141,8 @@ static void __serial_putc(struct serial_port *port, char c)
                     cpu_relax();
                 if ( n > 0 )
                 {
+                    /* Enable TX before sending chars */
+                    serial_start_tx(port);
                     while ( n-- )
                         port->driver->putc(
                             port,
@@ -135,6 +161,8 @@ static void __serial_putc(struct serial_port *port, char c)
         if ( ((port->txbufp - port->txbufc) == 0) &&
              port->driver->tx_ready(port) > 0 )
         {
+            /* Enable TX before sending chars */
+            serial_start_tx(port);
             /* Buffer and UART FIFO are both empty, and port is available. */
             port->driver->putc(port, c);
         }
@@ -152,11 +180,16 @@ static void __serial_putc(struct serial_port *port, char 
c)
         while ( !(n = port->driver->tx_ready(port)) )
             cpu_relax();
         if ( n > 0 )
+        {
+            /* Enable TX before sending chars */
+            serial_start_tx(port);
             port->driver->putc(port, c);
+        }
     }
     else
     {
         /* Simple synchronous transmitter. */
+        serial_start_tx(port);
         port->driver->putc(port, c);
     }
 }
@@ -404,6 +437,7 @@ void serial_start_sync(int handle)
                 /* port is unavailable and might not come up until reenabled by
                    dom0, we can't really do proper sync */
                 break;
+            serial_start_tx(port);
             port->driver->putc(
                 port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
         }
diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h
index 9f4451b..71e6ade 100644
--- a/xen/include/xen/serial.h
+++ b/xen/include/xen/serial.h
@@ -81,6 +81,10 @@ struct uart_driver {
     int  (*getc)(struct serial_port *, char *);
     /* Get IRQ number for this port's serial line: returns -1 if none. */
     int  (*irq)(struct serial_port *);
+    /* Unmask TX interrupt */
+    void  (*start_tx)(struct serial_port *);
+    /* Mask TX interrupt */
+    void  (*stop_tx)(struct serial_port *);
     /* Get serial information */
     const struct vuart_info *(*vuart_info)(struct serial_port *);
 };
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.5

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
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®.