diff options
author | Mike Frysinger <michael.frysinger@analog.com> | 2007-12-24 06:48:04 -0500 |
---|---|---|
committer | Bryan Wu <cooloney@kernel.org> | 2007-12-24 06:48:04 -0500 |
commit | 8851c71eb97610f0f63121d62345c969f71201a2 (patch) | |
tree | 1c03ba69333fca895f061f3acfbe2618652c2890 /drivers/serial/bfin_5xx.c | |
parent | 0bcfd70ea11a5d6f2362be463513a60245a62baf (diff) |
[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>
Diffstat (limited to 'drivers/serial/bfin_5xx.c')
-rw-r--r-- | drivers/serial/bfin_5xx.c | 66 |
1 files changed, 52 insertions, 14 deletions
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index af84984df775..50aa3b2a19b8 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c | |||
@@ -206,12 +206,20 @@ int kgdb_get_debug_char(void) | |||
206 | } | 206 | } |
207 | #endif | 207 | #endif |
208 | 208 | ||
209 | #if ANOMALY_05000230 && defined(CONFIG_SERIAL_BFIN_PIO) | ||
210 | # define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold) | ||
211 | # define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v)) | ||
212 | #else | ||
213 | # define UART_GET_ANOMALY_THRESHOLD(uart) 0 | ||
214 | # define UART_SET_ANOMALY_THRESHOLD(uart, v) | ||
215 | #endif | ||
216 | |||
209 | #ifdef CONFIG_SERIAL_BFIN_PIO | 217 | #ifdef CONFIG_SERIAL_BFIN_PIO |
210 | static void bfin_serial_rx_chars(struct bfin_serial_port *uart) | 218 | static void bfin_serial_rx_chars(struct bfin_serial_port *uart) |
211 | { | 219 | { |
212 | struct tty_struct *tty = uart->port.info->tty; | 220 | struct tty_struct *tty = uart->port.info->tty; |
213 | unsigned int status, ch, flg; | 221 | unsigned int status, ch, flg; |
214 | static int in_break = 0; | 222 | static struct timeval anomaly_start = { .tv_sec = 0 }; |
215 | #ifdef CONFIG_KGDB_UART | 223 | #ifdef CONFIG_KGDB_UART |
216 | struct pt_regs *regs = get_irq_regs(); | 224 | struct pt_regs *regs = get_irq_regs(); |
217 | #endif | 225 | #endif |
@@ -244,28 +252,56 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) | |||
244 | #endif | 252 | #endif |
245 | 253 | ||
246 | if (ANOMALY_05000230) { | 254 | if (ANOMALY_05000230) { |
247 | /* The BF533 family of processors have a nice misbehavior where | 255 | /* The BF533 (and BF561) family of processors have a nice anomaly |
248 | * they continuously generate characters for a "single" break. | 256 | * where they continuously generate characters for a "single" break. |
249 | * We have to basically ignore this flood until the "next" valid | 257 | * We have to basically ignore this flood until the "next" valid |
250 | * character comes across. All other Blackfin families operate | 258 | * character comes across. Due to the nature of the flood, it is |
251 | * properly though. | 259 | * not possible to reliably catch bytes that are sent too quickly |
260 | * after this break. So application code talking to the Blackfin | ||
261 | * which sends a break signal must allow at least 1.5 character | ||
262 | * times after the end of the break for things to stabilize. This | ||
263 | * timeout was picked as it must absolutely be larger than 1 | ||
264 | * character time +/- some percent. So 1.5 sounds good. All other | ||
265 | * Blackfin families operate properly. Woo. | ||
252 | * Note: While Anomaly 05000230 does not directly address this, | 266 | * Note: While Anomaly 05000230 does not directly address this, |
253 | * the changes that went in for it also fixed this issue. | 267 | * the changes that went in for it also fixed this issue. |
268 | * That anomaly was fixed in 0.5+ silicon. I like bunnies. | ||
254 | */ | 269 | */ |
255 | if (in_break) { | 270 | if (anomaly_start.tv_sec) { |
256 | if (ch != 0) { | 271 | struct timeval curr; |
257 | in_break = 0; | 272 | suseconds_t usecs; |
258 | ch = UART_GET_CHAR(uart); | 273 | |
259 | if (bfin_revid() < 5) | 274 | if ((~ch & (~ch + 1)) & 0xff) |
260 | return; | 275 | goto known_good_char; |
261 | } else | 276 | |
262 | return; | 277 | do_gettimeofday(&curr); |
278 | if (curr.tv_sec - anomaly_start.tv_sec > 1) | ||
279 | goto known_good_char; | ||
280 | |||
281 | usecs = 0; | ||
282 | if (curr.tv_sec != anomaly_start.tv_sec) | ||
283 | usecs += USEC_PER_SEC; | ||
284 | usecs += curr.tv_usec - anomaly_start.tv_usec; | ||
285 | |||
286 | if (usecs > UART_GET_ANOMALY_THRESHOLD(uart)) | ||
287 | goto known_good_char; | ||
288 | |||
289 | if (ch) | ||
290 | anomaly_start.tv_sec = 0; | ||
291 | else | ||
292 | anomaly_start = curr; | ||
293 | |||
294 | return; | ||
295 | |||
296 | known_good_char: | ||
297 | anomaly_start.tv_sec = 0; | ||
263 | } | 298 | } |
264 | } | 299 | } |
265 | 300 | ||
266 | if (status & BI) { | 301 | if (status & BI) { |
267 | if (ANOMALY_05000230) | 302 | if (ANOMALY_05000230) |
268 | in_break = 1; | 303 | if (bfin_revid() < 5) |
304 | do_gettimeofday(&anomaly_start); | ||
269 | uart->port.icount.brk++; | 305 | uart->port.icount.brk++; |
270 | if (uart_handle_break(&uart->port)) | 306 | if (uart_handle_break(&uart->port)) |
271 | goto ignore_char; | 307 | goto ignore_char; |
@@ -778,6 +814,8 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, | |||
778 | quot = uart_get_divisor(port, baud); | 814 | quot = uart_get_divisor(port, baud); |
779 | spin_lock_irqsave(&uart->port.lock, flags); | 815 | spin_lock_irqsave(&uart->port.lock, flags); |
780 | 816 | ||
817 | UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15); | ||
818 | |||
781 | do { | 819 | do { |
782 | lsr = UART_GET_LSR(uart); | 820 | lsr = UART_GET_LSR(uart); |
783 | } while (!(lsr & TEMT)); | 821 | } while (!(lsr & TEMT)); |