ChangeSet 1.1675, 2005/06/05 11:53:57+01:00, kaf24@xxxxxxxxxxxxxxxxxxxx
ns16550 interrupt handler should not return until the IIR indicates
no pending interrupts. Also a few generic serial driver cleanups.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
ns16550.c | 17 ++++++++++++----
serial.c | 65 +++++++++++++++++++++++++++++++++++---------------------------
2 files changed, 50 insertions(+), 32 deletions(-)
diff -Nru a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
--- a/xen/drivers/char/ns16550.c 2005-06-05 07:02:39 -04:00
+++ b/xen/drivers/char/ns16550.c 2005-06-05 07:02:39 -04:00
@@ -49,7 +49,15 @@
#define IER_ELSI 0x04 /* rx line status */
#define IER_EMSI 0x08 /* MODEM status */
-/* FIFO control register */
+/* Interrupt Identification Register */
+#define IIR_NOINT 0x01 /* no interrupt pending */
+#define IIR_IMASK 0x06 /* interrupt identity: */
+#define IIR_LSI 0x06 /* - rx line status */
+#define IIR_RDAI 0x04 /* - rx data recv'd */
+#define IIR_THREI 0x02 /* - tx reg. empty */
+#define IIR_MSI 0x00 /* - MODEM status */
+
+/* FIFO Control Register */
#define FCR_ENABLE 0x01 /* enable FIFO */
#define FCR_CLRX 0x02 /* clear Rx FIFO */
#define FCR_CLTX 0x04 /* clear Tx FIFO */
@@ -59,7 +67,7 @@
#define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */
#define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */
-/* Line control register */
+/* Line Control Register */
#define LCR_DLAB 0x80 /* Divisor Latch Access */
/* Modem Control Register */
@@ -104,10 +112,11 @@
struct serial_port *port = dev_id;
struct ns16550 *uart = port->uart;
- if ( (ns_read_reg(uart, IIR) & 7) == 2 )
+ while ( !(ns_read_reg(uart, IIR) & IIR_NOINT) )
+ {
serial_tx_interrupt(port, regs);
- else
serial_rx_interrupt(port, regs);
+ }
}
static int ns16550_tx_empty(struct serial_port *port)
diff -Nru a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c
--- a/xen/drivers/char/serial.c 2005-06-05 07:02:39 -04:00
+++ b/xen/drivers/char/serial.c 2005-06-05 07:02:39 -04:00
@@ -22,20 +22,13 @@
void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
{
char c;
- serial_rx_fn fn;
+ serial_rx_fn fn = NULL;
unsigned long flags;
- BUG_ON(!port->driver);
- BUG_ON(!port->driver->getc);
+ spin_lock_irqsave(&port->lock, flags);
- for ( ; ; )
+ if ( port->driver->getc(port, &c) )
{
- spin_lock_irqsave(&port->lock, flags);
-
- if ( !port->driver->getc(port, &c) )
- break;
-
- fn = NULL;
if ( port->rx != NULL )
fn = port->rx;
else if ( (c & 0x80) && (port->rx_hi != NULL) )
@@ -44,16 +37,12 @@
fn = port->rx_lo;
else if ( (port->rxbufp - port->rxbufc) != SERIAL_RXBUFSZ )
port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufp++)] = c;
-
- spin_unlock_irqrestore(&port->lock, flags);
-
- if ( fn != NULL )
- (*fn)(c & 0x7f, regs);
-
- cpu_relax();
}
spin_unlock_irqrestore(&port->lock, flags);
+
+ if ( fn != NULL )
+ (*fn)(c & 0x7f, regs);
}
void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
@@ -61,18 +50,17 @@
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->driver->tx_empty(port) )
{
- if ( port->txbufc == port->txbufp )
- break;
- port->driver->putc(
- port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
+ 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);
@@ -146,8 +134,29 @@
void serial_puts(int handle, const char *s)
{
- while ( *s != '\0' )
- serial_putc(handle, *s++);
+ struct serial_port *port = &com[handle & SERHND_IDX];
+ unsigned long flags;
+ char c;
+
+ if ( (handle == -1) || !port->driver || !port->driver->putc )
+ return;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ while ( (c = *s++) != '\0' )
+ {
+ if ( (c == '\n') && (handle & SERHND_COOKED) )
+ __serial_putc(port, '\r');
+
+ if ( handle & SERHND_HI )
+ c |= 0x80;
+ else if ( handle & SERHND_LO )
+ c &= 0x7f;
+
+ __serial_putc(port, c);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
}
char serial_getc(int handle)
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|