diff options
author | Sonic Zhang <sonic.zhang@analog.com> | 2009-06-11 08:38:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-11 11:51:04 -0400 |
commit | 8516c568f25666a012ec4c859e640a76fc9b6ec0 (patch) | |
tree | f2d72c684c5f8c726f752643bdd88268df836b5b /drivers/serial/bfin_5xx.c | |
parent | 4328e3e5ef1ae3427a4f6863aa65916a68ec2dd9 (diff) |
Blackfin Serial Driver: fix error while transferring large files
Ignore receiving data if new position is in the same line of current
buffer tail and is small. This should decrease overruns.
Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/serial/bfin_5xx.c')
-rw-r--r-- | drivers/serial/bfin_5xx.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index d86123e03391..65a4c07f6199 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c | |||
@@ -477,6 +477,15 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) | |||
477 | 477 | ||
478 | spin_lock_irqsave(&uart->port.lock, flags); | 478 | spin_lock_irqsave(&uart->port.lock, flags); |
479 | 479 | ||
480 | /* 2D DMA RX buffer ring is used. Because curr_y_count and | ||
481 | * curr_x_count can't be read as an atomic operation, | ||
482 | * curr_y_count should be read before curr_x_count. When | ||
483 | * curr_x_count is read, curr_y_count may already indicate | ||
484 | * next buffer line. But, the position calculated here is | ||
485 | * still indicate the old line. The wrong position data may | ||
486 | * be smaller than current buffer tail, which cause garbages | ||
487 | * are received if it is not prohibit. | ||
488 | */ | ||
480 | uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); | 489 | uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); |
481 | x_pos = get_dma_curr_xcount(uart->rx_dma_channel); | 490 | x_pos = get_dma_curr_xcount(uart->rx_dma_channel); |
482 | uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; | 491 | uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; |
@@ -487,7 +496,11 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) | |||
487 | x_pos = 0; | 496 | x_pos = 0; |
488 | 497 | ||
489 | pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; | 498 | pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; |
490 | if (pos != uart->rx_dma_buf.tail) { | 499 | /* Ignore receiving data if new position is in the same line of |
500 | * current buffer tail and small. | ||
501 | */ | ||
502 | if (pos > uart->rx_dma_buf.tail || | ||
503 | uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { | ||
491 | uart->rx_dma_buf.head = pos; | 504 | uart->rx_dma_buf.head = pos; |
492 | bfin_serial_dma_rx_chars(uart); | 505 | bfin_serial_dma_rx_chars(uart); |
493 | uart->rx_dma_buf.tail = uart->rx_dma_buf.head; | 506 | uart->rx_dma_buf.tail = uart->rx_dma_buf.head; |
@@ -532,11 +545,25 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) | |||
532 | { | 545 | { |
533 | struct bfin_serial_port *uart = dev_id; | 546 | struct bfin_serial_port *uart = dev_id; |
534 | unsigned short irqstat; | 547 | unsigned short irqstat; |
548 | int pos; | ||
535 | 549 | ||
536 | spin_lock(&uart->port.lock); | 550 | spin_lock(&uart->port.lock); |
537 | irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); | 551 | irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); |
538 | clear_dma_irqstat(uart->rx_dma_channel); | 552 | clear_dma_irqstat(uart->rx_dma_channel); |
539 | bfin_serial_dma_rx_chars(uart); | 553 | |
554 | uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); | ||
555 | uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; | ||
556 | if (uart->rx_dma_nrows == DMA_RX_YCOUNT) | ||
557 | uart->rx_dma_nrows = 0; | ||
558 | |||
559 | pos = uart->rx_dma_nrows * DMA_RX_XCOUNT; | ||
560 | if (pos > uart->rx_dma_buf.tail || | ||
561 | uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { | ||
562 | uart->rx_dma_buf.head = pos; | ||
563 | bfin_serial_dma_rx_chars(uart); | ||
564 | uart->rx_dma_buf.tail = uart->rx_dma_buf.head; | ||
565 | } | ||
566 | |||
540 | spin_unlock(&uart->port.lock); | 567 | spin_unlock(&uart->port.lock); |
541 | 568 | ||
542 | return IRQ_HANDLED; | 569 | return IRQ_HANDLED; |