Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / tty / serial / 8250 / 8250_port.c
index bdfa659..1731b98 100644 (file)
@@ -83,7 +83,8 @@ static const struct serial8250_config uart_config[] = {
                .name           = "16550A",
                .fifo_size      = 16,
                .tx_loadsz      = 16,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
+                                 UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
                .rxtrig_bytes   = {1, 4, 8, 14},
                .flags          = UART_CAP_FIFO,
        },
@@ -178,7 +179,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 +586,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 +620,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 +1403,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 +1413,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 +1424,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 +1432,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 +1469,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 +1478,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 +1871,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 +2007,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 +2184,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 +2538,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 +2546,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 +2583,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;