[Blackfin] serial driver: fix bug - cache the bits of the LSR on systems where the LSR is read-to-clear

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>
This commit is contained in:
Mike Frysinger 2007-12-24 19:40:05 +08:00 committed by Bryan Wu
parent 4c195ad88b
commit 0bcfd70ea1
6 changed files with 80 additions and 7 deletions

View 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) {

View 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;

View 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;

View 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;

View 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)

View 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;