[Blackfin] serial driver: fix bug - cache the bits of the LSR on systems where the...
authorMike Frysinger <michael.frysinger@analog.com>
Mon, 24 Dec 2007 11:40:05 +0000 (19:40 +0800)
committerBryan Wu <cooloney@kernel.org>
Mon, 24 Dec 2007 11:40:05 +0000 (19:40 +0800)
Cache the bits of the LSR on systems where the LSR is read-to-clear
so that we can safely read the LSR in random places.  this fixes
older parts where break/framing/parity/overflow was not being detected
at all in PIO mode, and this fixes newer parts where
break/framing/parity/overflow was being reported all the time
without being cleared.

Signed-off-by: Mike Frysinger <michael.frysinger@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
drivers/serial/bfin_5xx.c
include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
include/asm-blackfin/mach-bf561/bfin_serial_5xx.h

index ca9ceaa113a24b3d685e67c5da1c8bb2bfaf3f77..af84984df775eb15bfd2c20171f75bac2ddf0ad0 100644 (file)
@@ -216,8 +216,10 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
        struct pt_regs *regs = get_irq_regs();
 #endif
 
-       ch = UART_GET_CHAR(uart);
        status = UART_GET_LSR(uart);
+       UART_CLEAR_LSR(uart);
+
+       ch = UART_GET_CHAR(uart);
        uart->port.icount.rx++;
 
 #ifdef CONFIG_KGDB_UART
@@ -335,7 +337,7 @@ static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
        struct bfin_serial_port *uart = dev_id;
 
        spin_lock(&uart->port.lock);
-       while ((UART_GET_IER(uart) & ERBFI) && (UART_GET_LSR(uart) & DR))
+       while (UART_GET_LSR(uart) & DR)
                bfin_serial_rx_chars(uart);
        spin_unlock(&uart->port.lock);
 
@@ -347,7 +349,7 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
        struct bfin_serial_port *uart = dev_id;
 
        spin_lock(&uart->port.lock);
-       if ((UART_GET_IER(uart) & ETBEI) && (UART_GET_LSR(uart) & THRE))
+       if (UART_GET_LSR(uart) & THRE)
                bfin_serial_tx_chars(uart);
        spin_unlock(&uart->port.lock);
 
@@ -428,6 +430,8 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
        int i, flg, status;
 
        status = UART_GET_LSR(uart);
+       UART_CLEAR_LSR(uart);
+
        uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);;
 
        if (status & BI) {
index 15dbc21eed8bd30c34da9f747ccf88bc1f92b347..233c585efc1ef055d2689e0c38df3323bfbeee68 100644 (file)
@@ -23,7 +23,6 @@
 #define UART_GET_DLH(uart)     bfin_read16(((uart)->port.membase + OFFSET_DLH))
 #define UART_GET_IIR(uart)      bfin_read16(((uart)->port.membase + OFFSET_IIR))
 #define UART_GET_LCR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LCR))
-#define UART_GET_LSR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LSR))
 #define UART_GET_GCTL(uart)     bfin_read16(((uart)->port.membase + OFFSET_GCTL))
 
 #define UART_PUT_CHAR(uart, v)   bfin_write16(((uart)->port.membase + OFFSET_THR), v)
@@ -58,6 +57,7 @@
 struct bfin_serial_port {
        struct uart_port port;
        unsigned int old_status;
+       unsigned int lsr;
 #ifdef CONFIG_SERIAL_BFIN_DMA
        int tx_done;
        int tx_count;
@@ -76,6 +76,23 @@ struct bfin_serial_port {
 #endif
 };
 
+/* The hardware clears the LSR bits upon read, so we need to cache
+ * some of the more fun bits in software so they don't get lost
+ * when checking the LSR in other code paths (TX).
+ */
+static inline unsigned int UART_GET_LSR(struct bfin_serial_port *uart)
+{
+       unsigned int lsr = bfin_read16(uart->port.membase + OFFSET_LSR);
+       uart->lsr |= (lsr & (BI|FE|PE|OE));
+       return lsr | uart->lsr;
+}
+
+static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
+{
+       uart->lsr = 0;
+       bfin_write16(uart->port.membase + OFFSET_LSR, -1);
+}
+
 struct bfin_serial_port bfin_serial_ports[NR_PORTS];
 struct bfin_serial_res {
        unsigned long uart_base_addr;
index 7871d4313f49b3d7751c4cbe779d5fa321ea789c..b619065ceeb0291cc05f65aad038ed4a9d82d732 100644 (file)
@@ -23,7 +23,6 @@
 #define UART_GET_DLH(uart)     bfin_read16(((uart)->port.membase + OFFSET_DLH))
 #define UART_GET_IIR(uart)      bfin_read16(((uart)->port.membase + OFFSET_IIR))
 #define UART_GET_LCR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LCR))
-#define UART_GET_LSR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LSR))
 #define UART_GET_GCTL(uart)     bfin_read16(((uart)->port.membase + OFFSET_GCTL))
 
 #define UART_PUT_CHAR(uart,v)   bfin_write16(((uart)->port.membase + OFFSET_THR),v)
@@ -46,6 +45,7 @@
 struct bfin_serial_port {
         struct uart_port        port;
         unsigned int            old_status;
+       unsigned int lsr;
 #ifdef CONFIG_SERIAL_BFIN_DMA
        int                     tx_done;
        int                     tx_count;
@@ -64,6 +64,23 @@ struct bfin_serial_port {
 #endif
 };
 
+/* The hardware clears the LSR bits upon read, so we need to cache
+ * some of the more fun bits in software so they don't get lost
+ * when checking the LSR in other code paths (TX).
+ */
+static inline unsigned int UART_GET_LSR(struct bfin_serial_port *uart)
+{
+       unsigned int lsr = bfin_read16(uart->port.membase + OFFSET_LSR);
+       uart->lsr |= (lsr & (BI|FE|PE|OE));
+       return lsr | uart->lsr;
+}
+
+static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
+{
+       uart->lsr = 0;
+       bfin_write16(uart->port.membase + OFFSET_LSR, -1);
+}
+
 struct bfin_serial_port bfin_serial_ports[NR_PORTS];
 struct bfin_serial_res {
        unsigned long   uart_base_addr;
index 86e45c3798389270f6feb33cfb40205ced3afc52..f18c517cc935909c34837a93fe5c41047e6b3dc3 100644 (file)
@@ -23,7 +23,6 @@
 #define UART_GET_DLH(uart)     bfin_read16(((uart)->port.membase + OFFSET_DLH))
 #define UART_GET_IIR(uart)      bfin_read16(((uart)->port.membase + OFFSET_IIR))
 #define UART_GET_LCR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LCR))
-#define UART_GET_LSR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LSR))
 #define UART_GET_GCTL(uart)     bfin_read16(((uart)->port.membase + OFFSET_GCTL))
 
 #define UART_PUT_CHAR(uart,v)   bfin_write16(((uart)->port.membase + OFFSET_THR),v)
@@ -58,6 +57,7 @@
 struct bfin_serial_port {
         struct uart_port        port;
         unsigned int            old_status;
+       unsigned int lsr;
 #ifdef CONFIG_SERIAL_BFIN_DMA
        int                     tx_done;
        int                     tx_count;
@@ -76,6 +76,23 @@ struct bfin_serial_port {
 #endif
 };
 
+/* The hardware clears the LSR bits upon read, so we need to cache
+ * some of the more fun bits in software so they don't get lost
+ * when checking the LSR in other code paths (TX).
+ */
+static inline unsigned int UART_GET_LSR(struct bfin_serial_port *uart)
+{
+       unsigned int lsr = bfin_read16(uart->port.membase + OFFSET_LSR);
+       uart->lsr |= (lsr & (BI|FE|PE|OE));
+       return lsr | uart->lsr;
+}
+
+static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
+{
+       uart->lsr = 0;
+       bfin_write16(uart->port.membase + OFFSET_LSR, -1);
+}
+
 struct bfin_serial_port bfin_serial_ports[NR_PORTS];
 struct bfin_serial_res {
        unsigned long   uart_base_addr;
index 3770aa38ee9f9f6b039316ca1714997e431933d3..8733d47747e561af71d8baecc54325fc9d7befd1 100644 (file)
@@ -32,6 +32,7 @@
 #define UART_PUT_DLH(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_DLH),v)
 #define UART_PUT_LSR(uart,v)   bfin_write16(((uart)->port.membase + OFFSET_LSR),v)
 #define UART_PUT_LCR(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_LCR),v)
+#define UART_CLEAR_LSR(uart)    bfin_write16(((uart)->port.membase + OFFSET_LSR), -1)
 #define UART_PUT_GCTL(uart,v)   bfin_write16(((uart)->port.membase + OFFSET_GCTL),v)
 
 #if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS)
index 7871d4313f49b3d7751c4cbe779d5fa321ea789c..b619065ceeb0291cc05f65aad038ed4a9d82d732 100644 (file)
@@ -23,7 +23,6 @@
 #define UART_GET_DLH(uart)     bfin_read16(((uart)->port.membase + OFFSET_DLH))
 #define UART_GET_IIR(uart)      bfin_read16(((uart)->port.membase + OFFSET_IIR))
 #define UART_GET_LCR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LCR))
-#define UART_GET_LSR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LSR))
 #define UART_GET_GCTL(uart)     bfin_read16(((uart)->port.membase + OFFSET_GCTL))
 
 #define UART_PUT_CHAR(uart,v)   bfin_write16(((uart)->port.membase + OFFSET_THR),v)
@@ -46,6 +45,7 @@
 struct bfin_serial_port {
         struct uart_port        port;
         unsigned int            old_status;
+       unsigned int lsr;
 #ifdef CONFIG_SERIAL_BFIN_DMA
        int                     tx_done;
        int                     tx_count;
@@ -64,6 +64,23 @@ struct bfin_serial_port {
 #endif
 };
 
+/* The hardware clears the LSR bits upon read, so we need to cache
+ * some of the more fun bits in software so they don't get lost
+ * when checking the LSR in other code paths (TX).
+ */
+static inline unsigned int UART_GET_LSR(struct bfin_serial_port *uart)
+{
+       unsigned int lsr = bfin_read16(uart->port.membase + OFFSET_LSR);
+       uart->lsr |= (lsr & (BI|FE|PE|OE));
+       return lsr | uart->lsr;
+}
+
+static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
+{
+       uart->lsr = 0;
+       bfin_write16(uart->port.membase + OFFSET_LSR, -1);
+}
+
 struct bfin_serial_port bfin_serial_ports[NR_PORTS];
 struct bfin_serial_res {
        unsigned long   uart_base_addr;