aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial
diff options
context:
space:
mode:
authorMike Frysinger <michael.frysinger@analog.com>2007-12-24 06:48:04 -0500
committerBryan Wu <cooloney@kernel.org>2007-12-24 06:48:04 -0500
commit8851c71eb97610f0f63121d62345c969f71201a2 (patch)
tree1c03ba69333fca895f061f3acfbe2618652c2890 /drivers/serial
parent0bcfd70ea11a5d6f2362be463513a60245a62baf (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')
-rw-r--r--drivers/serial/bfin_5xx.c66
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
210static void bfin_serial_rx_chars(struct bfin_serial_port *uart) 218static 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));