serial: bfin_5xx: add missing spin_lock init
[deliverable/linux.git] / drivers / serial / bfin_5xx.c
index dfae22d47bf78f4addc059aea29c257e34fe2934..d7fcca18223bae42a5f37eac19ac1406b966419b 100644 (file)
@@ -330,6 +330,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
                /* Clear TFI bit */
                UART_PUT_LSR(uart, TFI);
 #endif
+               /* Anomaly notes:
+                *  05000215 -  we always clear ETBEI within last UART TX
+                *              interrupt to end a string. It is always set
+                *              when start a new tx.
+                */
                UART_CLEAR_IER(uart, ETBEI);
                return;
        }
@@ -415,6 +420,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
        set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
        set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
        set_dma_x_modify(uart->tx_dma_channel, 1);
+       SSYNC();
        enable_dma(uart->tx_dma_channel);
 
        UART_SET_IER(uart, ETBEI);
@@ -473,9 +479,9 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
 void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
 {
        int x_pos, pos;
-       unsigned long flags;
 
-       spin_lock_irqsave(&uart->port.lock, flags);
+       dma_disable_irq(uart->rx_dma_channel);
+       spin_lock_bh(&uart->port.lock);
 
        /* 2D DMA RX buffer ring is used. Because curr_y_count and
         * curr_x_count can't be read as an atomic operation,
@@ -489,7 +495,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
        uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
        x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
        uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
-       if (uart->rx_dma_nrows == DMA_RX_YCOUNT)
+       if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
                uart->rx_dma_nrows = 0;
        x_pos = DMA_RX_XCOUNT - x_pos;
        if (x_pos == DMA_RX_XCOUNT)
@@ -506,7 +512,8 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
                uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
        }
 
-       spin_unlock_irqrestore(&uart->port.lock, flags);
+       spin_unlock_bh(&uart->port.lock);
+       dma_enable_irq(uart->rx_dma_channel);
 
        mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
 }
@@ -527,6 +534,11 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
        if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
                disable_dma(uart->tx_dma_channel);
                clear_dma_irqstat(uart->tx_dma_channel);
+               /* Anomaly notes:
+                *  05000215 -  we always clear ETBEI within last UART TX
+                *              interrupt to end a string. It is always set
+                *              when start a new tx.
+                */
                UART_CLEAR_IER(uart, ETBEI);
                xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
                uart->port.icount.tx += uart->tx_count;
@@ -545,15 +557,16 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
 {
        struct bfin_serial_port *uart = dev_id;
        unsigned short irqstat;
-       int pos;
+       int x_pos, pos;
 
        spin_lock(&uart->port.lock);
        irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
        clear_dma_irqstat(uart->rx_dma_channel);
 
        uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
+       x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
        uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
-       if (uart->rx_dma_nrows == DMA_RX_YCOUNT)
+       if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
                uart->rx_dma_nrows = 0;
 
        pos = uart->rx_dma_nrows * DMA_RX_XCOUNT;
@@ -816,8 +829,16 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
                        __func__);
        }
 
-       if (termios->c_cflag & CSTOPB)
-               lcr |= STB;
+       /* Anomaly notes:
+        *  05000231 -  STOP bit is always set to 1 whatever the user is set.
+        */
+       if (termios->c_cflag & CSTOPB) {
+               if (ANOMALY_05000231)
+                       printk(KERN_WARNING "STOP bits other than 1 is not "
+                               "supported in case of anomaly 05000231.\n");
+               else
+                       lcr |= STB;
+       }
        if (termios->c_cflag & PARENB)
                lcr |= PEN;
        if (!(termios->c_cflag & PARODD))
@@ -967,6 +988,10 @@ static void bfin_serial_reset_irda(struct uart_port *port)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
+/* Anomaly notes:
+ *  05000099 -  Because we only use THRE in poll_put and DR in poll_get,
+ *             losing other bits of UART_LSR is not a problem here.
+ */
 static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr)
 {
        struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
@@ -1085,6 +1110,7 @@ static void __init bfin_serial_init_ports(void)
        bfin_serial_hw_init();
 
        for (i = 0; i < nr_active_ports; i++) {
+               spin_lock_init(&bfin_serial_ports[i].port.lock);
                bfin_serial_ports[i].port.uartclk   = get_sclk();
                bfin_serial_ports[i].port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
                bfin_serial_ports[i].port.ops       = &bfin_serial_pops;
This page took 0.02859 seconds and 5 git commands to generate.