[Blackfin] serial driver: rework break flood anomaly handling to be more robust/realistic about what we can actually work around

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:48:04 +08:00 committed by Bryan Wu
parent 0bcfd70ea1
commit 8851c71eb9
3 changed files with 58 additions and 14 deletions

View File

@ -206,12 +206,20 @@ int kgdb_get_debug_char(void)
} }
#endif #endif
#if ANOMALY_05000230 && defined(CONFIG_SERIAL_BFIN_PIO)
# define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold)
# define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v))
#else
# define UART_GET_ANOMALY_THRESHOLD(uart) 0
# define UART_SET_ANOMALY_THRESHOLD(uart, v)
#endif
#ifdef CONFIG_SERIAL_BFIN_PIO #ifdef CONFIG_SERIAL_BFIN_PIO
static void bfin_serial_rx_chars(struct bfin_serial_port *uart) static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{ {
struct tty_struct *tty = uart->port.info->tty; struct tty_struct *tty = uart->port.info->tty;
unsigned int status, ch, flg; unsigned int status, ch, flg;
static int in_break = 0; static struct timeval anomaly_start = { .tv_sec = 0 };
#ifdef CONFIG_KGDB_UART #ifdef CONFIG_KGDB_UART
struct pt_regs *regs = get_irq_regs(); struct pt_regs *regs = get_irq_regs();
#endif #endif
@ -244,28 +252,56 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
#endif #endif
if (ANOMALY_05000230) { if (ANOMALY_05000230) {
/* The BF533 family of processors have a nice misbehavior where /* The BF533 (and BF561) family of processors have a nice anomaly
* they continuously generate characters for a "single" break. * where they continuously generate characters for a "single" break.
* We have to basically ignore this flood until the "next" valid * We have to basically ignore this flood until the "next" valid
* character comes across. All other Blackfin families operate * character comes across. Due to the nature of the flood, it is
* properly though. * not possible to reliably catch bytes that are sent too quickly
* after this break. So application code talking to the Blackfin
* which sends a break signal must allow at least 1.5 character
* times after the end of the break for things to stabilize. This
* timeout was picked as it must absolutely be larger than 1
* character time +/- some percent. So 1.5 sounds good. All other
* Blackfin families operate properly. Woo.
* Note: While Anomaly 05000230 does not directly address this, * Note: While Anomaly 05000230 does not directly address this,
* the changes that went in for it also fixed this issue. * the changes that went in for it also fixed this issue.
* That anomaly was fixed in 0.5+ silicon. I like bunnies.
*/ */
if (in_break) { if (anomaly_start.tv_sec) {
if (ch != 0) { struct timeval curr;
in_break = 0; suseconds_t usecs;
ch = UART_GET_CHAR(uart);
if (bfin_revid() < 5) if ((~ch & (~ch + 1)) & 0xff)
return; goto known_good_char;
} else
do_gettimeofday(&curr);
if (curr.tv_sec - anomaly_start.tv_sec > 1)
goto known_good_char;
usecs = 0;
if (curr.tv_sec != anomaly_start.tv_sec)
usecs += USEC_PER_SEC;
usecs += curr.tv_usec - anomaly_start.tv_usec;
if (usecs > UART_GET_ANOMALY_THRESHOLD(uart))
goto known_good_char;
if (ch)
anomaly_start.tv_sec = 0;
else
anomaly_start = curr;
return; return;
known_good_char:
anomaly_start.tv_sec = 0;
} }
} }
if (status & BI) { if (status & BI) {
if (ANOMALY_05000230) if (ANOMALY_05000230)
in_break = 1; if (bfin_revid() < 5)
do_gettimeofday(&anomaly_start);
uart->port.icount.brk++; uart->port.icount.brk++;
if (uart_handle_break(&uart->port)) if (uart_handle_break(&uart->port))
goto ignore_char; goto ignore_char;
@ -778,6 +814,8 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
quot = uart_get_divisor(port, baud); quot = uart_get_divisor(port, baud);
spin_lock_irqsave(&uart->port.lock, flags); spin_lock_irqsave(&uart->port.lock, flags);
UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
do { do {
lsr = UART_GET_LSR(uart); lsr = UART_GET_LSR(uart);
} while (!(lsr & TEMT)); } while (!(lsr & TEMT));

View File

@ -57,6 +57,9 @@ struct bfin_serial_port {
struct work_struct tx_dma_workqueue; struct work_struct tx_dma_workqueue;
#else #else
struct work_struct cts_workqueue; struct work_struct cts_workqueue;
# if ANOMALY_05000230
unsigned int anomaly_threshold;
# endif
#endif #endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS #ifdef CONFIG_SERIAL_BFIN_CTSRTS
int cts_pin; int cts_pin;

View File

@ -57,6 +57,9 @@ struct bfin_serial_port {
struct work_struct tx_dma_workqueue; struct work_struct tx_dma_workqueue;
#else #else
struct work_struct cts_workqueue; struct work_struct cts_workqueue;
# if ANOMALY_05000230
unsigned int anomaly_threshold;
# endif
#endif #endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS #ifdef CONFIG_SERIAL_BFIN_CTSRTS
int cts_pin; int cts_pin;