diff options
Diffstat (limited to 'drivers/tty/serial/8250/8250_port.c')
-rw-r--r-- | drivers/tty/serial/8250/8250_port.c | 81 |
1 files changed, 57 insertions, 24 deletions
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index bdfa659b9606..1bfb6fdbaa20 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -178,7 +178,7 @@ static const struct serial8250_config uart_config[] = { .fifo_size = 16, .tx_loadsz = 16, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, - .flags = UART_CAP_FIFO | UART_CAP_AFE, + .flags = UART_CAP_FIFO /* | UART_CAP_AFE */, }, [PORT_U6_16550A] = { .name = "U6_16550A", @@ -585,11 +585,11 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put); */ int serial8250_em485_init(struct uart_8250_port *p) { - if (p->em485 != NULL) + if (p->em485) return 0; p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC); - if (p->em485 == NULL) + if (!p->em485) return -ENOMEM; setup_timer(&p->em485->stop_tx_timer, @@ -619,7 +619,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_init); */ void serial8250_em485_destroy(struct uart_8250_port *p) { - if (p->em485 == NULL) + if (!p->em485) return; del_timer(&p->em485->start_tx_timer); @@ -1402,10 +1402,8 @@ static void serial8250_stop_rx(struct uart_port *port) static void __do_stop_tx_rs485(struct uart_8250_port *p) { - if (!p->em485) - return; - serial8250_em485_rts_after_send(p); + /* * Empty the RX FIFO, we are not interested in anything * received during the half-duplex transmission. @@ -1414,12 +1412,8 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p) if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) { serial8250_clear_fifos(p); - serial8250_rpm_get(p); - p->ier |= UART_IER_RLSI | UART_IER_RDI; serial_port_out(&p->port, UART_IER, p->ier); - - serial8250_rpm_put(p); } } @@ -1429,6 +1423,7 @@ static void serial8250_em485_handle_stop_tx(unsigned long arg) struct uart_8250_em485 *em485 = p->em485; unsigned long flags; + serial8250_rpm_get(p); spin_lock_irqsave(&p->port.lock, flags); if (em485 && em485->active_timer == &em485->stop_tx_timer) { @@ -1436,15 +1431,13 @@ static void serial8250_em485_handle_stop_tx(unsigned long arg) em485->active_timer = NULL; } spin_unlock_irqrestore(&p->port.lock, flags); + serial8250_rpm_put(p); } static void __stop_tx_rs485(struct uart_8250_port *p) { struct uart_8250_em485 *em485 = p->em485; - if (!em485) - return; - /* * __do_stop_tx_rs485 is going to set RTS according to config * AND flush RX FIFO if required. @@ -1475,7 +1468,7 @@ static inline void __stop_tx(struct uart_8250_port *p) unsigned char lsr = serial_in(p, UART_LSR); /* * To provide required timeing and allow FIFO transfer, - * __stop_tx_rs485 must be called only when both FIFO and + * __stop_tx_rs485() must be called only when both FIFO and * shift register are empty. It is for device driver to enable * interrupt on TEMT. */ @@ -1484,9 +1477,10 @@ static inline void __stop_tx(struct uart_8250_port *p) del_timer(&em485->start_tx_timer); em485->active_timer = NULL; + + __stop_tx_rs485(p); } __do_stop_tx(p); - __stop_tx_rs485(p); } static void serial8250_stop_tx(struct uart_port *port) @@ -1876,6 +1870,30 @@ static int exar_handle_irq(struct uart_port *port) return ret; } +/* + * Newer 16550 compatible parts such as the SC16C650 & Altera 16550 Soft IP + * have a programmable TX threshold that triggers the THRE interrupt in + * the IIR register. In this case, the THRE interrupt indicates the FIFO + * has space available. Load it up with tx_loadsz bytes. + */ +static int serial8250_tx_threshold_handle_irq(struct uart_port *port) +{ + unsigned long flags; + unsigned int iir = serial_port_in(port, UART_IIR); + + /* TX Threshold IRQ triggered so load up FIFO */ + if ((iir & UART_IIR_ID) == UART_IIR_THRI) { + struct uart_8250_port *up = up_to_u8250p(port); + + spin_lock_irqsave(&port->lock, flags); + serial8250_tx_chars(up); + spin_unlock_irqrestore(&port->lock, flags); + } + + iir = serial_port_in(port, UART_IIR); + return serial8250_handle_irq(port, iir); +} + static unsigned int serial8250_tx_empty(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); @@ -1988,6 +2006,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) if (--tmout == 0) break; udelay(1); + touch_nmi_watchdog(); } /* Wait up to 1s for flow control if necessary */ @@ -2164,6 +2183,25 @@ int serial8250_do_startup(struct uart_port *port) serial_port_out(port, UART_LCR, 0); } + /* + * For the Altera 16550 variants, set TX threshold trigger level. + */ + if (((port->type == PORT_ALTR_16550_F32) || + (port->type == PORT_ALTR_16550_F64) || + (port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) { + /* Bounds checking of TX threshold (valid 0 to fifosize-2) */ + if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) { + pr_err("ttyS%d TX FIFO Threshold errors, skipping\n", + serial_index(port)); + } else { + serial_port_out(port, UART_ALTR_AFR, + UART_ALTR_EN_TXFIFO_LW); + serial_port_out(port, UART_ALTR_TX_LOW, + port->fifosize - up->tx_loadsz); + port->handle_irq = serial8250_tx_threshold_handle_irq; + } + } + if (port->irq) { unsigned char iir1; /* @@ -2499,8 +2537,6 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - unsigned int tolerance = port->uartclk / 100; - /* * Ask the core to calculate the divisor for us. * Allow 1% tolerance at the upper limit so uart clks marginally @@ -2509,7 +2545,7 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, */ return uart_get_baud_rate(port, termios, old, port->uartclk / 16 / 0xffff, - (port->uartclk + tolerance) / 16); + port->uartclk); } void @@ -2546,12 +2582,9 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, /* * MCR-based auto flow control. When AFE is enabled, RTS will be * deasserted when the receive FIFO contains more characters than - * the trigger, or the MCR RTS bit is cleared. In the case where - * the remote UART is not using CTS auto flow control, we must - * have sufficient FIFO entries for the latency of the remote - * UART to respond. IOW, at least 32 bytes of FIFO. + * the trigger, or the MCR RTS bit is cleared. */ - if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { + if (up->capabilities & UART_CAP_AFE) { up->mcr &= ~UART_MCR_AFE; if (termios->c_cflag & CRTSCTS) up->mcr |= UART_MCR_AFE; |