|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v1] xen/arm: Manage pl011 uart TX interrupt correctly
On Tue, 2014-12-09 at 10:09 +0530, vijay.kilari@xxxxxxxxx wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
>
> 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>
> ---
> xen/drivers/char/pl011.c | 16 ++++++++++++++++
> xen/drivers/char/serial.c | 34 ++++++++++++++++++++++++++++++++++
> xen/include/xen/serial.h | 4 ++++
These last two changes require that you cc the common serial maintainer,
not just the ARM maintainers. In this case that means Keir, who I have
CCd.
./scripts/get_maintainers.pl can help automate this.
> 3 files changed, 54 insertions(+)
>
> 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 *);
> };
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |