From patchwork Mon Oct 29 09:10:53 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Song, Elen" X-Patchwork-Id: 1662511 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id C140A3FDDA for ; Mon, 29 Oct 2012 09:15:43 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TSlPq-0003j7-6M; Mon, 29 Oct 2012 09:13:51 +0000 Received: from casper.infradead.org ([2001:770:15f::2]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TSlPV-0003ZJ-4v for linux-arm-kernel@merlin.infradead.org; Mon, 29 Oct 2012 09:13:29 +0000 Received: from newsmtp5.atmel.com ([204.2.163.5] helo=sjogate2.atmel.com) by casper.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TSlPQ-0000cr-BO for linux-arm-kernel@lists.infradead.org; Mon, 29 Oct 2012 09:13:27 +0000 Received: from penbh01.corp.atmel.com ([10.168.5.31]) by sjogate2.atmel.com (8.13.6/8.13.6) with ESMTP id q9T987eK001656; Mon, 29 Oct 2012 02:08:09 -0700 (PDT) Received: from penmb01.corp.atmel.com ([10.168.5.33]) by penbh01.corp.atmel.com with Microsoft SMTPSVC(6.0.3790.3959); Mon, 29 Oct 2012 17:13:11 +0800 Received: from shaarm01.corp.atmel.com ([10.217.6.34]) by penmb01.corp.atmel.com with Microsoft SMTPSVC(6.0.3790.3959); Mon, 29 Oct 2012 17:13:09 +0800 From: Elen Song To: nicolas.ferre@atmel.com, patrice.vilchez@atmel.com, plagnioj@jcrosoft.com Subject: [PATCH 5/6] Serial: AT91: Request rx dma channel Date: Mon, 29 Oct 2012 17:10:53 +0800 Message-Id: <1351501853-15491-1-git-send-email-elen.song@atmel.com> X-Mailer: git-send-email 1.7.9.5 X-OriginalArrivalTime: 29 Oct 2012 09:13:10.0791 (UTC) FILETIME=[9DFCC970:01CDB5B5] X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121029_091325_104242_B7FE697D X-CRM114-Status: GOOD ( 13.82 ) X-Spam-Score: -2.5 (--) X-Spam-Report: SpamAssassin version 3.3.2 on casper.infradead.org summary: Content analysis details: (-2.5 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.6 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: jm.lin@atmel.com, linux@arm.linux.org.uk, elen.song@atmel.com, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Request a cyclic dma channel for rx dma use. Use cyclic transfer is to prevent receive data overrun Signed-off-by: Elen Song --- drivers/tty/serial/atmel_serial.c | 103 ++++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 352ef4a..8ee9023 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -130,7 +130,7 @@ struct atmel_uart_char { u16 ch; }; -#define ATMEL_SERIAL_RINGSIZE 1024 +#define ATMEL_SERIAL_RINGSIZE 4096 /* * We wrap our port structure around the generic uart_port. @@ -152,11 +152,16 @@ struct atmel_uart_port { struct atmel_dma_buffer pdc_tx; /* PDC transmitter */ spinlock_t lock_tx; /* port lock */ + spinlock_t lock_rx; /* port lock */ struct dma_chan *chan_tx; + struct dma_chan *chan_rx; struct dma_async_tx_descriptor *desc_tx; + struct dma_async_tx_descriptor *desc_rx; dma_cookie_t cookie_tx; + dma_cookie_t cookie_rx; struct scatterlist sg_tx; + struct scatterlist sg_rx; unsigned int sg_len_tx; struct tasklet_struct tasklet; @@ -783,6 +788,98 @@ static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port) } } +static void atmel_rx_dma_release(struct atmel_uart_port *atmel_port) +{ + struct dma_chan *chan = atmel_port->chan_rx; + struct uart_port *port = &(atmel_port->uart); + + atmel_port->desc_rx = NULL; + atmel_port->chan_rx = NULL; + atmel_port->cookie_rx = -EINVAL; + dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1, + DMA_DEV_TO_MEM); + if (chan) { + dmaengine_terminate_all(chan); + dma_release_channel(chan); + } +} + +static void atmel_rx_request_dma(struct atmel_uart_port *atmel_port) +{ + struct uart_port *port; + struct atmel_uart_data *pdata; + dma_cap_mask_t mask; + struct dma_chan *chan = NULL; + struct circ_buf *ring = &atmel_port->rx_ring; + struct dma_slave_config config; + int ret; + + if (atmel_port == NULL) + return; + + port = &(atmel_port->uart); + pdata = (struct atmel_uart_data *)port->private_data; + + if (!pdata) { + dev_notice(port->dev, "DMA not available, using PIO\n"); + return; + } + + dma_cap_zero(mask); + dma_cap_set(DMA_CYCLIC, mask); + + if (atmel_use_dma_rx(port) && pdata->dma_rx_slave) { + pdata->dma_rx_slave->rx_reg = port->mapbase + ATMEL_US_RHR; + chan = dma_request_channel(mask, filter, pdata->dma_rx_slave); + dev_dbg(port->dev, "%s: RX: got channel %x\n", + __func__, + chan->chan_id); + } + + if (chan) { + int nent; + + spin_lock_init(&atmel_port->lock_rx); + atmel_port->chan_rx = chan; + + sg_init_table(&atmel_port->sg_rx, 1); + /* UART circular tx buffer is an aligned page. */ + BUG_ON((int)ring->buf & ~PAGE_MASK); + sg_set_page(&atmel_port->sg_rx, + virt_to_page(ring->buf), + ATMEL_SERIAL_RINGSIZE, + (int)ring->buf & ~PAGE_MASK); + nent = dma_map_sg(port->dev, + &atmel_port->sg_rx, + 1, + DMA_DEV_TO_MEM); + + if (!nent) + dev_dbg(port->dev, "need to release resource of dma\n"); + else + dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", + __func__, + sg_dma_len(&atmel_port->sg_rx), + ring->buf, + sg_dma_address(&atmel_port->sg_rx)); + + ring->head = 0; + } + + /* Configure the slave DMA */ + memset(&config, 0, sizeof(config)); + config.direction = DMA_DEV_TO_MEM; + config.src_addr_width = pdata->dma_rx_slave->reg_width; + config.src_addr = pdata->dma_rx_slave->rx_reg; + + ret = dmaengine_device_control(chan, DMA_SLAVE_CONFIG, + (unsigned long)&config); + if (ret) { + dev_err(port->dev, "DMA rx slave configuration failed\n"); + return; + } +} + /* * receive interrupt handler. */ @@ -1200,6 +1297,8 @@ static int atmel_startup(struct uart_port *port) if (atmel_use_dma_tx(port)) atmel_tx_request_dma(atmel_port); + if (atmel_use_dma_rx(port)) + atmel_rx_request_dma(atmel_port); /* * If there is a specific "open" function (to register * control line interrupts) @@ -1276,6 +1375,8 @@ static void atmel_shutdown(struct uart_port *port) DMA_TO_DEVICE); } + if (atmel_use_dma_rx(port)) + atmel_rx_dma_release(atmel_port); if (atmel_use_dma_tx(port)) atmel_tx_dma_release(atmel_port);