Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754463AbZCJJvV (ORCPT ); Tue, 10 Mar 2009 05:51:21 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753746AbZCJJvM (ORCPT ); Tue, 10 Mar 2009 05:51:12 -0400 Received: from nwd2mail11.analog.com ([137.71.25.57]:52025 "EHLO nwd2mail11.analog.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753488AbZCJJvL (ORCPT ); Tue, 10 Mar 2009 05:51:11 -0400 X-IronPort-AV: E=Sophos;i="4.38,335,1233550800"; d="scan'208";a="67624411" Subject: [PATCH 05/18] Blackfin Serial Driver: fix bug - serial port transfer big file from host to target would have more lines - v2 From: sonic zhang To: Alan Cox Cc: Bryan Wu , Linux Kernel Content-Type: text/plain Date: Tue, 10 Mar 2009 17:56:27 +0800 Message-Id: <1236678987.28294.11.camel@eight.analog.com> Mime-Version: 1.0 X-Mailer: Evolution 2.8.2 Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3237 Lines: 84 2D DMA RX buffer ring is used. Because curr_y_count and curr_x_count can't be read as an atomic operation, curr_y_count should be read before curr_x_count. When curr_x_count is read, curr_y_count may already indicate next buffer line. But, the position calculated here is still indicate the old line. The wrong position may be in the same line and smaller than current buffer tail, which causes garbages are received if it is not prohibit. Signed-off-by: Sonic Zhang Signed-off-by: Bryan Wu --- 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 8d34ccd..5a163f6 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -407,6 +407,15 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) spin_lock_irqsave(&uart->port.lock, flags); + /* 2D DMA RX buffer ring is used. Because curr_y_count and + * curr_x_count can't be read as an atomic operation, + * curr_y_count should be read before curr_x_count. When + * curr_x_count is read, curr_y_count may already indicate + * next buffer line. But, the position calculated here is + * still indicate the old line. The wrong position data may + * be smaller than current buffer tail, which cause garbages + * are received if it is not prohibit. + */ uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); x_pos = get_dma_curr_xcount(uart->rx_dma_channel); uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; @@ -417,7 +426,11 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) x_pos = 0; pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; - if (pos != uart->rx_dma_buf.tail) { + /* Ignore receiving data if new position is in the same line of + * current buffer tail and small. + */ + if (pos > uart->rx_dma_buf.tail || + uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { uart->rx_dma_buf.head = pos; bfin_serial_dma_rx_chars(uart); uart->rx_dma_buf.tail = uart->rx_dma_buf.head; @@ -455,11 +468,25 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; unsigned short irqstat; + int pos; spin_lock(&uart->port.lock); irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); clear_dma_irqstat(uart->rx_dma_channel); - bfin_serial_dma_rx_chars(uart); + + uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); + uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; + if (uart->rx_dma_nrows == DMA_RX_YCOUNT) + uart->rx_dma_nrows = 0; + + pos = uart->rx_dma_nrows * DMA_RX_XCOUNT; + if (pos > uart->rx_dma_buf.tail || + uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { + uart->rx_dma_buf.head = pos; + bfin_serial_dma_rx_chars(uart); + uart->rx_dma_buf.tail = uart->rx_dma_buf.head; + } + spin_unlock(&uart->port.lock); return IRQ_HANDLED; -- 1.6.0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/