summaryrefslogtreecommitdiff
path: root/drivers/serial/8250.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial/8250.c')
-rw-r--r--drivers/serial/8250.c118
1 files changed, 66 insertions, 52 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 616da2cc8121..48185a82a393 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -129,7 +129,16 @@ struct uart_8250_port {
unsigned char mcr;
unsigned char mcr_mask; /* mask of user bits */
unsigned char mcr_force; /* mask of forced bits */
- unsigned char lsr_break_flag;
+
+ /*
+ * Some bits in registers are cleared on a read, so they must
+ * be saved whenever the register is read but the bits will not
+ * be immediately processed.
+ */
+#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
+ unsigned char lsr_saved_flags;
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+ unsigned char msr_saved_flags;
/*
* We provide a per-port pm hook.
@@ -1243,6 +1252,7 @@ static void serial8250_start_tx(struct uart_port *port)
if (up->bugs & UART_BUG_TXEN) {
unsigned char lsr, iir;
lsr = serial_in(up, UART_LSR);
+ up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
iir = serial_in(up, UART_IIR) & 0x0f;
if ((up->port.type == PORT_RM9000) ?
(lsr & UART_LSR_THRE &&
@@ -1295,18 +1305,10 @@ receive_chars(struct uart_8250_port *up, unsigned int *status)
flag = TTY_NORMAL;
up->port.icount.rx++;
-#ifdef CONFIG_SERIAL_8250_CONSOLE
- /*
- * Recover the break flag from console xmit
- */
- if (up->port.line == up->port.cons->index) {
- lsr |= up->lsr_break_flag;
- up->lsr_break_flag = 0;
- }
-#endif
+ lsr |= up->lsr_saved_flags;
+ up->lsr_saved_flags = 0;
- if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
- UART_LSR_FE | UART_LSR_OE))) {
+ if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
/*
* For statistics only
*/
@@ -1402,6 +1404,8 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
{
unsigned int status = serial_in(up, UART_MSR);
+ status |= up->msr_saved_flags;
+ up->msr_saved_flags = 0;
if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
up->port.info != NULL) {
if (status & UART_MSR_TERI)
@@ -1601,7 +1605,8 @@ static void serial8250_timeout(unsigned long data)
static void serial8250_backup_timeout(unsigned long data)
{
struct uart_8250_port *up = (struct uart_8250_port *)data;
- unsigned int iir, ier = 0;
+ unsigned int iir, ier = 0, lsr;
+ unsigned long flags;
/*
* Must disable interrupts or else we risk racing with the interrupt
@@ -1620,9 +1625,13 @@ static void serial8250_backup_timeout(unsigned long data)
* the "Diva" UART used on the management processor on many HP
* ia64 and parisc boxes.
*/
+ spin_lock_irqsave(&up->port.lock, flags);
+ lsr = serial_in(up, UART_LSR);
+ up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
+ spin_unlock_irqrestore(&up->port.lock, flags);
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
(!uart_circ_empty(&up->port.info->xmit) || up->port.x_char) &&
- (serial_in(up, UART_LSR) & UART_LSR_THRE)) {
+ (lsr & UART_LSR_THRE)) {
iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
iir |= UART_IIR_THRI;
}
@@ -1641,13 +1650,14 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned long flags;
- unsigned int ret;
+ unsigned int lsr;
spin_lock_irqsave(&up->port.lock, flags);
- ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+ lsr = serial_in(up, UART_LSR);
+ up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
spin_unlock_irqrestore(&up->port.lock, flags);
- return ret;
+ return lsr & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
}
static unsigned int serial8250_get_mctrl(struct uart_port *port)
@@ -1718,8 +1728,7 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
do {
status = serial_in(up, UART_LSR);
- if (status & UART_LSR_BI)
- up->lsr_break_flag = UART_LSR_BI;
+ up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;
if (--tmout == 0)
break;
@@ -1728,8 +1737,12 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
- tmout = 1000000;
- while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
+ unsigned int tmout;
+ for (tmout = 1000000; tmout; tmout--) {
+ unsigned int msr = serial_in(up, UART_MSR);
+ up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
+ if (msr & UART_MSR_CTS)
+ break;
udelay(1);
touch_nmi_watchdog();
}
@@ -1899,6 +1912,18 @@ static int serial8250_startup(struct uart_port *port)
spin_unlock_irqrestore(&up->port.lock, flags);
/*
+ * Clear the interrupt registers again for luck, and clear the
+ * saved flags to avoid getting false values from polling
+ * routines or the previous session.
+ */
+ serial_inp(up, UART_LSR);
+ serial_inp(up, UART_RX);
+ serial_inp(up, UART_IIR);
+ serial_inp(up, UART_MSR);
+ up->lsr_saved_flags = 0;
+ up->msr_saved_flags = 0;
+
+ /*
* Finally, enable interrupts. Note: Modem status interrupts
* are set via set_termios(), which will be occurring imminently
* anyway, so we don't enable them here.
@@ -1916,14 +1941,6 @@ static int serial8250_startup(struct uart_port *port)
(void) inb_p(icp);
}
- /*
- * And clear the interrupt registers again for luck.
- */
- (void) serial_inp(up, UART_LSR);
- (void) serial_inp(up, UART_RX);
- (void) serial_inp(up, UART_IIR);
- (void) serial_inp(up, UART_MSR);
-
return 0;
}
@@ -2494,6 +2511,16 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
wait_for_xmitr(up, BOTH_EMPTY);
serial_out(up, UART_IER, ier);
+ /*
+ * The receive handling will happen properly because the
+ * receive ready bit will still be set; it is not cleared
+ * on read. However, modem control will not, we must
+ * call it if we have saved something in the saved flags
+ * while processing with interrupts off.
+ */
+ if (up->msr_saved_flags)
+ check_modem_status(up);
+
if (locked)
spin_unlock(&up->port.lock);
local_irq_restore(flags);
@@ -2524,12 +2551,18 @@ static int __init serial8250_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
+static int serial8250_console_early_setup(void)
+{
+ return serial8250_find_port_for_earlycon();
+}
+
static struct uart_driver serial8250_reg;
static struct console serial8250_console = {
.name = "ttyS",
.write = serial8250_console_write,
.device = uart_console_device,
.setup = serial8250_console_setup,
+ .early_setup = serial8250_console_early_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &serial8250_reg,
@@ -2543,7 +2576,7 @@ static int __init serial8250_console_init(void)
}
console_initcall(serial8250_console_init);
-static int __init find_port(struct uart_port *p)
+int serial8250_find_port(struct uart_port *p)
{
int line;
struct uart_port *port;
@@ -2556,26 +2589,6 @@ static int __init find_port(struct uart_port *p)
return -ENODEV;
}
-int __init serial8250_start_console(struct uart_port *port, char *options)
-{
- int line;
-
- line = find_port(port);
- if (line < 0)
- return -ENODEV;
-
- add_preferred_console("ttyS", line, options);
- printk("Adding console on ttyS%d at %s 0x%lx (options '%s')\n",
- line, port->iotype == UPIO_MEM ? "MMIO" : "I/O port",
- port->iotype == UPIO_MEM ? (unsigned long) port->mapbase :
- (unsigned long) port->iobase, options);
- if (!(serial8250_console.flags & CON_ENABLED)) {
- serial8250_console.flags &= ~CON_PRINTBUFFER;
- register_console(&serial8250_console);
- }
- return line;
-}
-
#define SERIAL8250_CONSOLE &serial8250_console
#else
#define SERIAL8250_CONSOLE NULL
@@ -2674,8 +2687,9 @@ static int __devinit serial8250_probe(struct platform_device *dev)
ret = serial8250_register_port(&port);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
- "(IO%lx MEM%lx IRQ%d): %d\n", i,
- p->iobase, p->mapbase, p->irq, ret);
+ "(IO%lx MEM%llx IRQ%d): %d\n", i,
+ p->iobase, (unsigned long long)p->mapbase,
+ p->irq, ret);
}
}
return 0;