Skip to content

Commit 40b36da

Browse files
Alex WilliamsonLinus Torvalds
Alex Williamson
authored and
Linus Torvalds
committed
[PATCH] 8250 UART backup timer
The patch below works around a minor bug found in the UART of the remote management card used in many HP ia64 and parisc servers (aka the Diva UARTs). The problem is that the UART does not reassert the THRE interrupt if it has been previously cleared and the IIR THRI bit is re-enabled. This can produce a very annoying failure mode when used as a serial console, allowing a boot/reboot to hang indefinitely until an RX interrupt kicks it into working again (ie. an unattended reboot could stall). To solve this problem, a backup timer is introduced that runs alongside the standard interrupt driven mechanism. This timer wakes up periodically, checks for a hang condition and gets characters moving again. This backup mechanism is only enabled if the UART is detected as having this problem, so systems without these UARTs will have no additional overhead. This version of the patch incorporates previous comments from Pavel and removes races in the bug detection code. The test is now done before the irq linking to prevent races with interrupt handler clearing the THRE interrupt. Short delays and syncs are also added to ensure the device is able to update register state before the result is tested. Aristeu says: this was tested on the following HP machines and solved the problem: rx2600, rx2620, rx1600 and rx1620s. hpa says: I have seen this same bug in soft UART IP from "a major vendor." Signed-off-by: Alex Williamson <[email protected]> Cc: "H. Peter Anvin" <[email protected]> Cc: Russell King <[email protected]> Acked-by: Aristeu Sergio Rozanski Filho <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent ed8b4d4 commit 40b36da

File tree

1 file changed

+134
-44
lines changed

1 file changed

+134
-44
lines changed

drivers/serial/8250.c

Lines changed: 134 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,23 @@ serial_out(struct uart_8250_port *up, int offset, int value)
364364
}
365365
}
366366

367+
static void
368+
serial_out_sync(struct uart_8250_port *up, int offset, int value)
369+
{
370+
switch (up->port.iotype) {
371+
case UPIO_MEM:
372+
case UPIO_MEM32:
373+
#ifdef CONFIG_SERIAL_8250_AU1X00
374+
case UPIO_AU:
375+
#endif
376+
serial_out(up, offset, value);
377+
serial_in(up, UART_LCR); /* safe, no side-effects */
378+
break;
379+
default:
380+
serial_out(up, offset, value);
381+
}
382+
}
383+
367384
/*
368385
* We used to support using pause I/O for certain machines. We
369386
* haven't supported this for a while, but just in case it's badly
@@ -1045,7 +1062,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
10451062
#endif
10461063
serial_outp(up, UART_MCR, save_mcr);
10471064
serial8250_clear_fifos(up);
1048-
(void)serial_in(up, UART_RX);
1065+
serial_in(up, UART_RX);
10491066
if (up->capabilities & UART_CAP_UUE)
10501067
serial_outp(up, UART_IER, UART_IER_UUE);
10511068
else
@@ -1451,6 +1468,12 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
14511468
serial_do_unlink(i, up);
14521469
}
14531470

1471+
/* Base timer interval for polling */
1472+
static inline int poll_timeout(int timeout)
1473+
{
1474+
return timeout > 6 ? (timeout / 2 - 2) : 1;
1475+
}
1476+
14541477
/*
14551478
* This function is used to handle ports that do not have an
14561479
* interrupt. This doesn't work very well for 16450's, but gives
@@ -1460,16 +1483,51 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
14601483
static void serial8250_timeout(unsigned long data)
14611484
{
14621485
struct uart_8250_port *up = (struct uart_8250_port *)data;
1463-
unsigned int timeout;
14641486
unsigned int iir;
14651487

14661488
iir = serial_in(up, UART_IIR);
14671489
if (!(iir & UART_IIR_NO_INT))
14681490
serial8250_handle_port(up);
1491+
mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout));
1492+
}
1493+
1494+
static void serial8250_backup_timeout(unsigned long data)
1495+
{
1496+
struct uart_8250_port *up = (struct uart_8250_port *)data;
1497+
unsigned int iir, ier = 0;
1498+
1499+
/*
1500+
* Must disable interrupts or else we risk racing with the interrupt
1501+
* based handler.
1502+
*/
1503+
if (is_real_interrupt(up->port.irq)) {
1504+
ier = serial_in(up, UART_IER);
1505+
serial_out(up, UART_IER, 0);
1506+
}
14691507

1470-
timeout = up->port.timeout;
1471-
timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
1472-
mod_timer(&up->timer, jiffies + timeout);
1508+
iir = serial_in(up, UART_IIR);
1509+
1510+
/*
1511+
* This should be a safe test for anyone who doesn't trust the
1512+
* IIR bits on their UART, but it's specifically designed for
1513+
* the "Diva" UART used on the management processor on many HP
1514+
* ia64 and parisc boxes.
1515+
*/
1516+
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
1517+
(!uart_circ_empty(&up->port.info->xmit) || up->port.x_char) &&
1518+
(serial_in(up, UART_LSR) & UART_LSR_THRE)) {
1519+
iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
1520+
iir |= UART_IIR_THRI;
1521+
}
1522+
1523+
if (!(iir & UART_IIR_NO_INT))
1524+
serial8250_handle_port(up);
1525+
1526+
if (is_real_interrupt(up->port.irq))
1527+
serial_out(up, UART_IER, ier);
1528+
1529+
/* Standard timer interval plus 0.2s to keep the port running */
1530+
mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout) + HZ/5);
14731531
}
14741532

14751533
static unsigned int serial8250_tx_empty(struct uart_port *port)
@@ -1540,6 +1598,37 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
15401598
spin_unlock_irqrestore(&up->port.lock, flags);
15411599
}
15421600

1601+
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
1602+
1603+
/*
1604+
* Wait for transmitter & holding register to empty
1605+
*/
1606+
static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
1607+
{
1608+
unsigned int status, tmout = 10000;
1609+
1610+
/* Wait up to 10ms for the character(s) to be sent. */
1611+
do {
1612+
status = serial_in(up, UART_LSR);
1613+
1614+
if (status & UART_LSR_BI)
1615+
up->lsr_break_flag = UART_LSR_BI;
1616+
1617+
if (--tmout == 0)
1618+
break;
1619+
udelay(1);
1620+
} while ((status & bits) != bits);
1621+
1622+
/* Wait up to 1s for flow control if necessary */
1623+
if (up->port.flags & UPF_CONS_FLOW) {
1624+
tmout = 1000000;
1625+
while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
1626+
udelay(1);
1627+
touch_nmi_watchdog();
1628+
}
1629+
}
1630+
}
1631+
15431632
static int serial8250_startup(struct uart_port *port)
15441633
{
15451634
struct uart_8250_port *up = (struct uart_8250_port *)port;
@@ -1613,18 +1702,50 @@ static int serial8250_startup(struct uart_port *port)
16131702
serial_outp(up, UART_LCR, 0);
16141703
}
16151704

1705+
if (is_real_interrupt(up->port.irq)) {
1706+
/*
1707+
* Test for UARTs that do not reassert THRE when the
1708+
* transmitter is idle and the interrupt has already
1709+
* been cleared. Real 16550s should always reassert
1710+
* this interrupt whenever the transmitter is idle and
1711+
* the interrupt is enabled. Delays are necessary to
1712+
* allow register changes to become visible.
1713+
*/
1714+
spin_lock_irqsave(&up->port.lock, flags);
1715+
1716+
wait_for_xmitr(up, UART_LSR_THRE);
1717+
serial_out_sync(up, UART_IER, UART_IER_THRI);
1718+
udelay(1); /* allow THRE to set */
1719+
serial_in(up, UART_IIR);
1720+
serial_out(up, UART_IER, 0);
1721+
serial_out_sync(up, UART_IER, UART_IER_THRI);
1722+
udelay(1); /* allow a working UART time to re-assert THRE */
1723+
iir = serial_in(up, UART_IIR);
1724+
serial_out(up, UART_IER, 0);
1725+
1726+
spin_unlock_irqrestore(&up->port.lock, flags);
1727+
1728+
/*
1729+
* If the interrupt is not reasserted, setup a timer to
1730+
* kick the UART on a regular basis.
1731+
*/
1732+
if (iir & UART_IIR_NO_INT) {
1733+
pr_debug("ttyS%d - using backup timer\n", port->line);
1734+
up->timer.function = serial8250_backup_timeout;
1735+
up->timer.data = (unsigned long)up;
1736+
mod_timer(&up->timer, jiffies +
1737+
poll_timeout(up->port.timeout) + HZ/5);
1738+
}
1739+
}
1740+
16161741
/*
16171742
* If the "interrupt" for this port doesn't correspond with any
16181743
* hardware interrupt, we use a timer-based system. The original
16191744
* driver used to do this with IRQ0.
16201745
*/
16211746
if (!is_real_interrupt(up->port.irq)) {
1622-
unsigned int timeout = up->port.timeout;
1623-
1624-
timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
1625-
16261747
up->timer.data = (unsigned long)up;
1627-
mod_timer(&up->timer, jiffies + timeout);
1748+
mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout));
16281749
} else {
16291750
retval = serial_link_irq_chain(up);
16301751
if (retval)
@@ -1740,9 +1861,9 @@ static void serial8250_shutdown(struct uart_port *port)
17401861
*/
17411862
(void) serial_in(up, UART_RX);
17421863

1743-
if (!is_real_interrupt(up->port.irq))
1744-
del_timer_sync(&up->timer);
1745-
else
1864+
del_timer_sync(&up->timer);
1865+
up->timer.function = serial8250_timeout;
1866+
if (is_real_interrupt(up->port.irq))
17461867
serial_unlink_irq_chain(up);
17471868
}
17481869

@@ -2212,37 +2333,6 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
22122333

22132334
#ifdef CONFIG_SERIAL_8250_CONSOLE
22142335

2215-
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
2216-
2217-
/*
2218-
* Wait for transmitter & holding register to empty
2219-
*/
2220-
static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
2221-
{
2222-
unsigned int status, tmout = 10000;
2223-
2224-
/* Wait up to 10ms for the character(s) to be sent. */
2225-
do {
2226-
status = serial_in(up, UART_LSR);
2227-
2228-
if (status & UART_LSR_BI)
2229-
up->lsr_break_flag = UART_LSR_BI;
2230-
2231-
if (--tmout == 0)
2232-
break;
2233-
udelay(1);
2234-
} while ((status & bits) != bits);
2235-
2236-
/* Wait up to 1s for flow control if necessary */
2237-
if (up->port.flags & UPF_CONS_FLOW) {
2238-
tmout = 1000000;
2239-
while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
2240-
udelay(1);
2241-
touch_nmi_watchdog();
2242-
}
2243-
}
2244-
}
2245-
22462336
static void serial8250_console_putchar(struct uart_port *port, int ch)
22472337
{
22482338
struct uart_8250_port *up = (struct uart_8250_port *)port;

0 commit comments

Comments
 (0)