Upgrade to 4.4.50-rt62
[kvmfornfv.git] / kernel / drivers / tty / serial / samsung.c
index a0ae942..237ef55 100644 (file)
@@ -53,7 +53,6 @@
 #include "samsung.h"
 
 #if    defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
-       defined(CONFIG_DEBUG_LL) &&             \
        !defined(MODULE)
 
 extern void printascii(const char *);
@@ -295,15 +294,6 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
        if (ourport->tx_mode != S3C24XX_TX_DMA)
                enable_tx_dma(ourport);
 
-       while (xmit->tail & (dma_get_cache_alignment() - 1)) {
-               if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
-                       return 0;
-               wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-               count--;
-       }
-
        dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
        dma->tx_transfer_addr = dma->tx_addr + xmit->tail;
 
@@ -342,13 +332,15 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
                return;
        }
 
-       if (!ourport->dma || !ourport->dma->tx_chan || count < port->fifosize)
+       if (!ourport->dma || !ourport->dma->tx_chan ||
+           count < ourport->min_dma_size ||
+           xmit->tail & (dma_get_cache_alignment() - 1))
                s3c24xx_serial_start_tx_pio(ourport);
        else
                s3c24xx_serial_start_tx_dma(ourport, count);
 }
 
-void s3c24xx_serial_start_tx(struct uart_port *port)
+static void s3c24xx_serial_start_tx(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
        struct circ_buf *xmit = &port->state->xmit;
@@ -393,32 +385,6 @@ static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
        }
 }
 
-static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
-                                    unsigned long ufstat);
-
-static void uart_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
-{
-       struct uart_port *port = &ourport->port;
-       struct tty_port *tty = &port->state->port;
-       unsigned int ch, ufstat;
-       unsigned int count;
-
-       ufstat = rd_regl(port, S3C2410_UFSTAT);
-       count = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
-
-       if (!count)
-               return;
-
-       while (count-- > 0) {
-               ch = rd_regb(port, S3C2410_URXH);
-
-               ourport->port.icount.rx++;
-               tty_insert_flip_char(tty, ch, TTY_NORMAL);
-       }
-
-       tty_flip_buffer_push(tty);
-}
-
 static void s3c24xx_serial_stop_rx(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -581,7 +547,9 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
        ourport->rx_mode = S3C24XX_RX_PIO;
 }
 
-static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
+static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport);
+
+static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
 {
        unsigned int utrstat, ufstat, received;
        struct s3c24xx_uart_port *ourport = dev_id;
@@ -614,7 +582,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
                enable_rx_pio(ourport);
        }
 
-       uart_rx_drain_fifo(ourport);
+       s3c24xx_serial_rx_drain_fifo(ourport);
 
        if (tty) {
                tty_flip_buffer_push(t);
@@ -629,16 +597,12 @@ finish:
        return IRQ_HANDLED;
 }
 
-static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
+static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
 {
-       struct s3c24xx_uart_port *ourport = dev_id;
        struct uart_port *port = &ourport->port;
        unsigned int ufcon, ch, flag, ufstat, uerstat;
-       unsigned long flags;
        int max_count = port->fifosize;
 
-       spin_lock_irqsave(&port->lock, flags);
-
        while (max_count-- > 0) {
                ufcon = rd_regl(port, S3C2410_UFCON);
                ufstat = rd_regl(port, S3C2410_UFSTAT);
@@ -662,9 +626,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
                                        ufcon |= S3C2410_UFCON_RESETRX;
                                        wr_regl(port, S3C2410_UFCON, ufcon);
                                        rx_enabled(port) = 1;
-                                       spin_unlock_irqrestore(&port->lock,
-                                                       flags);
-                                       goto out;
+                                       return;
                                }
                                continue;
                        }
@@ -684,7 +646,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
                                dbg("break!\n");
                                port->icount.brk++;
                                if (uart_handle_break(port))
-                                       goto ignore_char;
+                                       continue; /* Ignore character */
                        }
 
                        if (uerstat & S3C2410_UERSTAT_FRAME)
@@ -704,19 +666,25 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
                }
 
                if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
+                       continue; /* Ignore character */
 
                uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
                                 ch, flag);
-
-ignore_char:
-               continue;
        }
 
-       spin_unlock_irqrestore(&port->lock, flags);
        tty_flip_buffer_push(&port->state->port);
+}
+
+static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
+{
+       struct s3c24xx_uart_port *ourport = dev_id;
+       struct uart_port *port = &ourport->port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       s3c24xx_serial_rx_drain_fifo(ourport);
+       spin_unlock_irqrestore(&port->lock, flags);
 
-out:
        return IRQ_HANDLED;
 }
 
@@ -726,8 +694,8 @@ static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)
        struct s3c24xx_uart_port *ourport = dev_id;
 
        if (ourport->dma && ourport->dma->rx_chan)
-               return s3c24xx_serial_rx_chars_dma(irq, dev_id);
-       return s3c24xx_serial_rx_chars_pio(irq, dev_id);
+               return s3c24xx_serial_rx_chars_dma(dev_id);
+       return s3c24xx_serial_rx_chars_pio(dev_id);
 }
 
 static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
@@ -736,15 +704,20 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
        struct uart_port *port = &ourport->port;
        struct circ_buf *xmit = &port->state->xmit;
        unsigned long flags;
-       int count;
+       int count, dma_count = 0;
 
        spin_lock_irqsave(&port->lock, flags);
 
        count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
 
-       if (ourport->dma && ourport->dma->tx_chan && count >= port->fifosize) {
-               s3c24xx_serial_start_tx_dma(ourport, count);
-               goto out;
+       if (ourport->dma && ourport->dma->tx_chan &&
+           count >= ourport->min_dma_size) {
+               int align = dma_get_cache_alignment() -
+                       (xmit->tail & (dma_get_cache_alignment() - 1));
+               if (count-align >= ourport->min_dma_size) {
+                       dma_count = count-align;
+                       count = align;
+               }
        }
 
        if (port->x_char) {
@@ -765,14 +738,24 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
 
        /* try and drain the buffer... */
 
-       count = port->fifosize;
-       while (!uart_circ_empty(xmit) && count-- > 0) {
+       if (count > port->fifosize) {
+               count = port->fifosize;
+               dma_count = 0;
+       }
+
+       while (!uart_circ_empty(xmit) && count > 0) {
                if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
                        break;
 
                wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
                port->icount.tx++;
+               count--;
+       }
+
+       if (!count && dma_count) {
+               s3c24xx_serial_start_tx_dma(ourport, dma_count);
+               goto out;
        }
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
@@ -1280,6 +1263,8 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
        /* check to see if we need  to change clock source */
 
        if (ourport->baudclk != clk) {
+               clk_prepare_enable(clk);
+
                s3c24xx_serial_setsource(port, clk_sel);
 
                if (!IS_ERR(ourport->baudclk)) {
@@ -1287,8 +1272,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
                        ourport->baudclk = ERR_PTR(-EINVAL);
                }
 
-               clk_prepare_enable(clk);
-
                ourport->baudclk = clk;
                ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
        }
@@ -1693,7 +1676,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
                return -ENODEV;
 
        if (port->mapbase != 0)
-               return 0;
+               return -EINVAL;
 
        /* setup info for port */
        port->dev       = &platdev->dev;
@@ -1747,22 +1730,25 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
                ourport->dma = devm_kzalloc(port->dev,
                                            sizeof(*ourport->dma),
                                            GFP_KERNEL);
-               if (!ourport->dma)
-                       return -ENOMEM;
+               if (!ourport->dma) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
        }
 
        ourport->clk    = clk_get(&platdev->dev, "uart");
        if (IS_ERR(ourport->clk)) {
                pr_err("%s: Controller clock not found\n",
                                dev_name(&platdev->dev));
-               return PTR_ERR(ourport->clk);
+               ret = PTR_ERR(ourport->clk);
+               goto err;
        }
 
        ret = clk_prepare_enable(ourport->clk);
        if (ret) {
                pr_err("uart: clock failed to prepare+enable: %d\n", ret);
                clk_put(ourport->clk);
-               return ret;
+               goto err;
        }
 
        /* Keep all interrupts masked and cleared */
@@ -1778,7 +1764,12 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
 
        /* reset the fifos (and setup the uart) */
        s3c24xx_serial_resetport(port, cfg);
+
        return 0;
+
+err:
+       port->mapbase = 0;
+       return ret;
 }
 
 /* Device driver serial port probe */
@@ -1838,6 +1829,13 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
        else if (ourport->info->fifosize)
                ourport->port.fifosize = ourport->info->fifosize;
 
+       /*
+        * DMA transfers must be aligned at least to cache line size,
+        * so find minimal transfer size suitable for DMA mode
+        */
+       ourport->min_dma_size = max_t(int, ourport->port.fifosize,
+                                   dma_get_cache_alignment());
+
        probe_index++;
 
        dbg("%s: initialising port %p...\n", __func__, ourport);
@@ -2337,7 +2335,7 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
 #define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL
 #endif
 
-static struct platform_device_id s3c24xx_serial_driver_ids[] = {
+static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
        {
                .name           = "s3c2410-uart",
                .driver_data    = S3C2410_SERIAL_DRV_DATA,