diff options
author | Tian Fang <tfang@fb.com> | 2016-04-13 01:49:31 +0100 |
---|---|---|
committer | Javier Jardón <jjardon@gnome.org> | 2016-04-13 01:50:31 +0100 |
commit | 3842b07578ca8c7473e5d96e0bd2000629540426 (patch) | |
tree | 9df2e875b6355b1d7f32a33a00797785a85584d7 /drivers/serial | |
parent | 1812494d7169dd66ffd0a70132361416f4005963 (diff) | |
download | linux-stable-3842b07578ca8c7473e5d96e0bd2000629540426.tar.gz |
Linux snapshot of OpenBMC f926614
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/8250.c | 58 |
1 files changed, 46 insertions, 12 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index f16da5982358..d01c1c7152e2 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -127,6 +127,11 @@ static unsigned long probe_rsa[PORT_RSA_MAX]; static unsigned int probe_rsa_count; #endif /* CONFIG_SERIAL_8250_RSA */ +struct rs485_wait_state { + int gpio; + int waiting; +}; + struct uart_8250_port { struct uart_port port; struct timer_list timer; /* "no irq" timer */ @@ -156,6 +161,8 @@ struct uart_8250_port { */ void (*pm)(struct uart_port *port, unsigned int state, unsigned int old); + + struct rs485_wait_state rs485_wait_state; }; struct irq_info { @@ -169,6 +176,9 @@ struct irq_info { static struct hlist_head irq_lists[NR_IRQ_HASH]; static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */ +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) +static void wait_for_xmitr(struct uart_8250_port *up, int bits); + /* * Here we define the default xmit fifo size used for each type of UART. */ @@ -530,6 +540,31 @@ static void serial_dl_write(struct uart_8250_port *up, int value) #define serial_dl_write(up, value) _serial_dl_write(up, value) #endif +// unfortunately it seems the gpio switch for RS485 can be late even with the +// wait queue based wakeup of the task waiting on its completion, so we *have* +// to do the gpio switch in the interrupt handler. +static void rs485_wait_end(struct uart_8250_port *up) { + struct rs485_wait_state *rs485_wait_state = + &up->rs485_wait_state; + if (rs485_wait_state->waiting) { + int status; + status = serial_in(up, UART_LSR); + // no interrupt will be fire for shift register (TEMT) so we have to spin + // on it. + if (status & UART_LSR_THRE) { + wait_for_xmitr(up, BOTH_EMPTY); + // turn off RS485 DE pin + if (rs485_wait_state->gpio) + gpio_set_value(rs485_wait_state->gpio, 0); + // grab any phantom char seen on RX when transceiver switches + (void) serial_inp(up, UART_RX); + // enable read + up->port.ignore_status_mask &= ~UART_LSR_DR; + rs485_wait_state->waiting = 0; + } + } +} + /* * For the 16C950 */ @@ -1235,6 +1270,7 @@ static inline void __stop_tx(struct uart_8250_port *p) p->ier &= ~UART_IER_THRI; serial_out(p, UART_IER, p->ier); } + uart_write_wakeup(&p->port); } static void serial8250_stop_tx(struct uart_port *port) @@ -1436,7 +1472,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up) if (status & UART_MSR_DCTS) uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - wake_up_interruptible(&up->port.info->delta_msr_wait); + wake_up_interruptible(&up->port.info->delta_msr_wait); } return status; @@ -1462,6 +1498,7 @@ static void serial8250_handle_port(struct uart_8250_port *up) if (status & UART_LSR_THRE) transmit_chars(up); + rs485_wait_end(up); spin_unlock_irqrestore(&up->port.lock, flags); } @@ -1777,8 +1814,6 @@ 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 */ @@ -2539,8 +2574,13 @@ static int serial8250_ioctl(struct uart_port *port, unsigned int cmd, unsigned l int ret = -ENOIOCTLCMD; // kernel-space RS485 drain-and-switch hack if (cmd == TIOCSERWAITTEMT) { - // wait for kernel buffers and UART FIFO to both empty struct circ_buf *xmit = &up->port.info->xmit; + spin_lock_irqsave(&up->port.lock, flags); + up->rs485_wait_state.gpio = arg; + up->rs485_wait_state.waiting = 1; + spin_unlock_irqrestore(&up->port.lock, flags); + + // wait for kernel buffers and UART FIFO to both empty wait_event_interruptible( thre_wait, uart_circ_empty(xmit) && @@ -2548,14 +2588,6 @@ static int serial8250_ioctl(struct uart_port *port, unsigned int cmd, unsigned l // spin until TEMT (transmit shift register empty) spin_lock_irqsave(&up->port.lock, flags); wait_for_xmitr(up, BOTH_EMPTY); - if (arg != 0) { - // turn off RS485 DE pin - gpio_set_value(arg, 0); - } - // grab any phantom char seen on RX when transceiver switches - (void) serial_inp(up, UART_RX); - // enable read - up->port.ignore_status_mask &= ~UART_LSR_DR; spin_unlock_irqrestore(&up->port.lock, flags); return 0; } @@ -2607,6 +2639,8 @@ static void __init serial8250_isa_init_ports(void) init_timer(&up->timer); up->timer.function = serial8250_timeout; + up->rs485_wait_state.waiting = 0; + up->rs485_wait_state.gpio = 0; /* * ALPHA_KLUDGE_MCR needs to be killed. |