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

[Xen-devel] [PATCH] ns16550: mask transmit holding register empty interrupt when tx is stopped



From: Chris Patterson <pattersonc@xxxxxxxxxxxx>

The uart generates an interrupt whenever the transmit holding register is
empty and UART_IER_ETHREI is set in UART_IER.  Currently, Xen's ns16550
driver does not currently mask this interrupt when transmit is stopped,
unlike other platforms such as Linux [1].

Toggle UART_IER_ETHREI flag in the UART_IER according to the state dictated
by stop_tx and start_tx hooks.

On the Tegra platform (forthcoming series), the reset via reading IIR does not
prevent re-assertion of THRE.  This causes Xen to hang in the interrupt
handler's while loop whenever there is no data to transmit.  This behavior 
(bug?)
is addressed by utilizing the start & stop tx hooks.

This has been tested on various x86 PCs for any obvious signs of regressions.

[1] 
http://lxr.free-electrons.com/source/drivers/tty/serial/8250/8250_port.c?v=4.7#L1518

Signed-off-by: Chris Patterson <pattersonc@xxxxxxxxxxxx>
---
 xen/drivers/char/ns16550.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
index b2b5f56..cae7f1b 100644
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -656,8 +656,8 @@ static void ns16550_setup_postirq(struct ns16550 *uart)
         ns_write_reg(uart,
                      UART_MCR, UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS);
 
-        /* Enable receive and transmit interrupts. */
-        ns_write_reg(uart, UART_IER, UART_IER_ERDAI | UART_IER_ETHREI);
+        /* Enable receive interrupts. */
+        ns_write_reg(uart, UART_IER, UART_IER_ERDAI);
     }
 
     if ( uart->irq >= 0 )
@@ -813,6 +813,26 @@ static int __init ns16550_irq(struct serial_port *port)
     return ((uart->irq > 0) ? uart->irq : -1);
 }
 
+static void ns16550_start_tx(struct serial_port *port)
+{
+    struct ns16550 *uart = port->uart;
+    unsigned int ier = ns_read_reg(uart, UART_IER);
+
+    /* unmask transmit holding register empty interrupt if currently masked */
+    if (!(ier & UART_IER_ETHREI))
+        ns_write_reg(uart, UART_IER, ier | UART_IER_ETHREI);
+}
+
+static void ns16550_stop_tx(struct serial_port *port)
+{
+    struct ns16550 *uart = port->uart;
+    unsigned int ier = ns_read_reg(uart, UART_IER);
+
+    /* mask off transmit holding register empty interrupt if currently 
unmasked */
+    if (ier & UART_IER_ETHREI)
+        ns_write_reg(uart, UART_IER, ier & ~UART_IER_ETHREI);
+}
+
 #ifdef CONFIG_ARM
 static const struct vuart_info *ns16550_vuart_info(struct serial_port *port)
 {
@@ -832,6 +852,8 @@ static struct uart_driver __read_mostly ns16550_driver = {
     .putc         = ns16550_putc,
     .getc         = ns16550_getc,
     .irq          = ns16550_irq,
+    .start_tx     = ns16550_start_tx,
+    .stop_tx      = ns16550_stop_tx,
 #ifdef CONFIG_ARM
     .vuart_info   = ns16550_vuart_info,
 #endif
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

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