|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |