Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 48318
b: refs/heads/master
c: 40b36da
h: refs/heads/master
v: v3
  • Loading branch information
Alex Williamson authored and Linus Torvalds committed Feb 14, 2007
1 parent 4f44bd8 commit 845680d
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 45 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ed8b4d4d7a31923db32f4684535944d69eb43677
refs/heads/master: 40b36daad0ac704e6d5c1b75789f371ef5b053c1
178 changes: 134 additions & 44 deletions trunk/drivers/serial/8250.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,23 @@ serial_out(struct uart_8250_port *up, int offset, int value)
}
}

static void
serial_out_sync(struct uart_8250_port *up, int offset, int value)
{
switch (up->port.iotype) {
case UPIO_MEM:
case UPIO_MEM32:
#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
#endif
serial_out(up, offset, value);
serial_in(up, UART_LCR); /* safe, no side-effects */
break;
default:
serial_out(up, offset, value);
}
}

/*
* We used to support using pause I/O for certain machines. We
* haven't supported this for a while, but just in case it's badly
Expand Down Expand Up @@ -1045,7 +1062,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
#endif
serial_outp(up, UART_MCR, save_mcr);
serial8250_clear_fifos(up);
(void)serial_in(up, UART_RX);
serial_in(up, UART_RX);
if (up->capabilities & UART_CAP_UUE)
serial_outp(up, UART_IER, UART_IER_UUE);
else
Expand Down Expand Up @@ -1451,6 +1468,12 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
serial_do_unlink(i, up);
}

/* Base timer interval for polling */
static inline int poll_timeout(int timeout)
{
return timeout > 6 ? (timeout / 2 - 2) : 1;
}

/*
* This function is used to handle ports that do not have an
* interrupt. This doesn't work very well for 16450's, but gives
Expand All @@ -1460,16 +1483,51 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
static void serial8250_timeout(unsigned long data)
{
struct uart_8250_port *up = (struct uart_8250_port *)data;
unsigned int timeout;
unsigned int iir;

iir = serial_in(up, UART_IIR);
if (!(iir & UART_IIR_NO_INT))
serial8250_handle_port(up);
mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout));
}

static void serial8250_backup_timeout(unsigned long data)
{
struct uart_8250_port *up = (struct uart_8250_port *)data;
unsigned int iir, ier = 0;

/*
* Must disable interrupts or else we risk racing with the interrupt
* based handler.
*/
if (is_real_interrupt(up->port.irq)) {
ier = serial_in(up, UART_IER);
serial_out(up, UART_IER, 0);
}

timeout = up->port.timeout;
timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
mod_timer(&up->timer, jiffies + timeout);
iir = serial_in(up, UART_IIR);

/*
* This should be a safe test for anyone who doesn't trust the
* IIR bits on their UART, but it's specifically designed for
* the "Diva" UART used on the management processor on many HP
* ia64 and parisc boxes.
*/
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)) {
iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
iir |= UART_IIR_THRI;
}

if (!(iir & UART_IIR_NO_INT))
serial8250_handle_port(up);

if (is_real_interrupt(up->port.irq))
serial_out(up, UART_IER, ier);

/* Standard timer interval plus 0.2s to keep the port running */
mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout) + HZ/5);
}

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

#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)

/*
* Wait for transmitter & holding register to empty
*/
static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
{
unsigned int status, tmout = 10000;

/* Wait up to 10ms for the character(s) to be sent. */
do {
status = serial_in(up, UART_LSR);

if (status & UART_LSR_BI)
up->lsr_break_flag = UART_LSR_BI;

if (--tmout == 0)
break;
udelay(1);
} while ((status & bits) != 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) {
udelay(1);
touch_nmi_watchdog();
}
}
}

static int serial8250_startup(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
Expand Down Expand Up @@ -1613,18 +1702,50 @@ static int serial8250_startup(struct uart_port *port)
serial_outp(up, UART_LCR, 0);
}

if (is_real_interrupt(up->port.irq)) {
/*
* Test for UARTs that do not reassert THRE when the
* transmitter is idle and the interrupt has already
* been cleared. Real 16550s should always reassert
* this interrupt whenever the transmitter is idle and
* the interrupt is enabled. Delays are necessary to
* allow register changes to become visible.
*/
spin_lock_irqsave(&up->port.lock, flags);

wait_for_xmitr(up, UART_LSR_THRE);
serial_out_sync(up, UART_IER, UART_IER_THRI);
udelay(1); /* allow THRE to set */
serial_in(up, UART_IIR);
serial_out(up, UART_IER, 0);
serial_out_sync(up, UART_IER, UART_IER_THRI);
udelay(1); /* allow a working UART time to re-assert THRE */
iir = serial_in(up, UART_IIR);
serial_out(up, UART_IER, 0);

spin_unlock_irqrestore(&up->port.lock, flags);

/*
* If the interrupt is not reasserted, setup a timer to
* kick the UART on a regular basis.
*/
if (iir & UART_IIR_NO_INT) {
pr_debug("ttyS%d - using backup timer\n", port->line);
up->timer.function = serial8250_backup_timeout;
up->timer.data = (unsigned long)up;
mod_timer(&up->timer, jiffies +
poll_timeout(up->port.timeout) + HZ/5);
}
}

/*
* If the "interrupt" for this port doesn't correspond with any
* hardware interrupt, we use a timer-based system. The original
* driver used to do this with IRQ0.
*/
if (!is_real_interrupt(up->port.irq)) {
unsigned int timeout = up->port.timeout;

timeout = timeout > 6 ? (timeout / 2 - 2) : 1;

up->timer.data = (unsigned long)up;
mod_timer(&up->timer, jiffies + timeout);
mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout));
} else {
retval = serial_link_irq_chain(up);
if (retval)
Expand Down Expand Up @@ -1740,9 +1861,9 @@ static void serial8250_shutdown(struct uart_port *port)
*/
(void) serial_in(up, UART_RX);

if (!is_real_interrupt(up->port.irq))
del_timer_sync(&up->timer);
else
del_timer_sync(&up->timer);
up->timer.function = serial8250_timeout;
if (is_real_interrupt(up->port.irq))
serial_unlink_irq_chain(up);
}

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

#ifdef CONFIG_SERIAL_8250_CONSOLE

#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)

/*
* Wait for transmitter & holding register to empty
*/
static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
{
unsigned int status, tmout = 10000;

/* Wait up to 10ms for the character(s) to be sent. */
do {
status = serial_in(up, UART_LSR);

if (status & UART_LSR_BI)
up->lsr_break_flag = UART_LSR_BI;

if (--tmout == 0)
break;
udelay(1);
} while ((status & bits) != 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) {
udelay(1);
touch_nmi_watchdog();
}
}
}

static void serial8250_console_putchar(struct uart_port *port, int ch)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
Expand Down

0 comments on commit 845680d

Please sign in to comment.