From patchwork Tue Jun 28 05:32:33 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bhuvanchandra DV X-Patchwork-Id: 9201875 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 26D796075F for ; Tue, 28 Jun 2016 05:36:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 122DB285E6 for ; Tue, 28 Jun 2016 05:36:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 06232285EA; Tue, 28 Jun 2016 05:36:15 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAD_ENC_HEADER,BAYES_00, DKIM_SIGNED,RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 5999E285E6 for ; Tue, 28 Jun 2016 05:36:14 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bHlfX-0008EG-3m; Tue, 28 Jun 2016 05:34:43 +0000 Received: from mail-db5eur01on0105.outbound.protection.outlook.com ([104.47.2.105] helo=EUR01-DB5-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bHleg-0007cL-Dp for linux-arm-kernel@lists.infradead.org; Tue, 28 Jun 2016 05:33:51 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=toradex.onmicrosoft.com; s=selector1-toradex-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=RJPArwyCI1LlcIm/mXNHE2WdYixpd4HTmzAhyNrp0us=; b=olg/yZGCw4QkIdOTMYU0+wCxlG3EL7YZdFO+78lzSeJZRz/zNWJorDb4cC+TD9YwHfskKzLxFSTEtMFLJd0dTYT9mQVYMyHuFxSuQP0mflmC1DAxo7wuGhrLqnmHCPkqdLk/A5bHOtRa6Fh3x3vY0vMnBw/gMTZxE/vkvilCcTI= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=bhuvanchandra.dv@toradex.com; Received: from tdx-in-nb-0014.toradex.ext (115.115.243.34) by HE1PR0501MB2089.eurprd05.prod.outlook.com (10.167.246.9) with Microsoft SMTP Server (TLS) id 15.1.523.12; Tue, 28 Jun 2016 05:33:30 +0000 From: Bhuvanchandra DV To: Subject: [PATCH v2 7/9] tty: serial: fsl-lpuart: Use scatter/gather DMA for Tx Date: Tue, 28 Jun 2016 11:02:33 +0530 Message-ID: <20160628053235.5114-8-bhuvanchandra.dv@toradex.com> X-Mailer: git-send-email 2.9.0 In-Reply-To: <20160628053235.5114-1-bhuvanchandra.dv@toradex.com> References: <20160628053235.5114-1-bhuvanchandra.dv@toradex.com> MIME-Version: 1.0 X-Originating-IP: [115.115.243.34] X-ClientProxiedBy: BM1PR01CA0056.INDPRD01.PROD.OUTLOOK.COM (10.163.199.28) To HE1PR0501MB2089.eurprd05.prod.outlook.com (10.167.246.9) X-MS-Office365-Filtering-Correlation-Id: 946ebb78-e70e-4ddb-31db-08d39f15be4b X-Microsoft-Exchange-Diagnostics: 1; HE1PR0501MB2089; 2:0pFEm68X9X6vRVuNabkAAU0/PR/j8j4uQ7l01qZo/vLU/9kpJgxBqCgeYllq++1jncqNJ/0GU11u/LxugqXMriEdNgF7FuvqzICvgW9zTzPTtSqDmFeqS77NGnKY/OVMMeXZVftulldc/l5z/AJ96BNmmPKfcfcroWV+XGNNrSyPu6+hZ/lBT3CyVKicLdtC; 3:PAk1+3cgzJt+WOQRX/x5ZnDR+vgdh+PqkwTzCl349nTrgmZMtuhH8YJfbg3YB8aklwxoqMk0w+e9T0M0Wm7zA93N9XDxXWQjn2qJrysHiOpc1WdnJkw19gOEH3SNMJtR; 25:lhuOzd+cJ0pVUgD9OzkwhRY3lj6yQssRrFTILMQ1m0tp4cFlCMoxB+64ITwlwgcBpJ6QEtKo6ZUdUZnUvY/EDYGUzF5A+OOWknScXaTx2AtHjkW8rOk3LQZfQCArSYOa5ynvgdA+TarueH+E/NxxtZ2WsFKRCD2v45QtoDymU9p50lMxbJkomhyuUSiyVGYKheUQnES2ZjCrVgfbtX91H7a3OIjzGvx6NLXqBJc+mSkonHZSBpLrat4H7JQG8qdJUXj8y84RX0n4pEv3p2zjJd88KtSJqX1Axqj/6wxSQSlgFiD5bplnGtWLdl0hMktMShWnyVt0AejPDjMo+eMk6yVl+whlk/y9dQiP/B9WwmXf2iiUKtIdUFwGm56CfMGsrJYzeHZsmSool3bwesmrI74ckNg2QSXMjSjLoJGwz3g= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:HE1PR0501MB2089; X-Microsoft-Exchange-Diagnostics: 1; HE1PR0501MB2089; 20:yr1x6WXQUitcWMSHeXEvoMNTCDd50tFUfv+sW9xgNQg70WAXOO2z0r4a1nipAMGmHKtlGUjnFfKDFAtbUYk06n1cJjdesX3XEHn0Sc1/dzgfN5tmKs1nnoCGOepTftjo4gdpPT1kTCbbC7EaQTGqbrC7fSYVSjsfOg3zDpMTJ1RIwp+rCRe4c1c4OzvlimNVE3/bIp0ei3wUCnpEaDgTvmmW4I1zypwJ4kmGKWEQAyh7I2HlzvFN3+4dDpKUDxsTS/V7Urbs4TtznO+Jss/a/D1f9alP7EuPtHVAHMun/4umnKsrDaRXai+RJHPIrUOnr49ceblIBs6MozYYpQd9rg==; 4:U7MFaShN0bxjDwpDRgbg6VjMnWJo2CkOTLyyNWz/Z6Wu7PkiCzlFURyRNLVRUoYL+t9fbPVR+fE1rlo6DoRB/621g8t+QvkgmmTeX0fOT/YEbGnrRYtzCT8CBCuLCHIfj4a6eJ88zoHtr+8AKhm4EZ1u2wcS4wKSwVuVGRKQ6GzsFJYsLvO6szuIzYu6Apd+KCqcxTWO5sWs0FQzE4VVlWv7hlM+0VU/8+G7LlUiNFgoENNyQjRkXescgXEDCeM2hlT/Ij2sZNcvMywBC1lmw6dT0/VqHGA5dvHGylXH1ZEyYEDgfgOdJAosLKi/4CDI0FqiGCseEHiGwJuP4M/mWgT2d2FfLzY4vOjP5rDeN6H4UXmuvOaVA3UHMfwBKHhO X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(5005006)(8121501046)(10201501046)(3002001); SRVR:HE1PR0501MB2089; BCL:0; PCL:0; RULEID:; SRVR:HE1PR0501MB2089; X-Forefront-PRVS: 0987ACA2E2 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(4630300001)(6009001)(7916002)(22813001)(199003)(189002)(189998001)(50226002)(110136002)(107886002)(7846002)(47776003)(66066001)(36756003)(8676002)(101416001)(1076002)(48376002)(33646002)(6116002)(81166006)(92566002)(3846002)(50986999)(586003)(81156014)(50466002)(2351001)(2950100001)(77096005)(105586002)(229853001)(86362001)(76176999)(5003940100001)(68736007)(305945005)(106356001)(4326007)(7736002)(53416004)(4001430100002)(19580405001)(19580395003)(69596002)(42186005)(97736004)(2906002); DIR:OUT; SFP:1102; SCL:1; SRVR:HE1PR0501MB2089; H:tdx-in-nb-0014.toradex.ext; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: toradex.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; HE1PR0501MB2089; 23:ImK9srlUmtqIgoOS/Rji6S/STzrK5t9JtVH62sZ?= =?us-ascii?Q?c1nNkI1RuggFsQAAW6r/x/x+Vw5sppyAvOurx7OvY4gsZipBGH95tVkD1eFV?= =?us-ascii?Q?TQ0C1xGSAa3ei3i9ifdVoMzRewjvFi3Rjc7NxjHWUUB7hr74rOPFUZACiHvQ?= =?us-ascii?Q?7JZOWu1xFfjrd6s4cQWxK4u/VBjb+o2w/ol4JF8xqiMQxJfbeW5zE+MpDGFf?= =?us-ascii?Q?iBzD3m/PMaTAW9Nr/GcprtYWZ6QDsY4HTkwNpx0/bKJiKgjn7a/comytNbKM?= =?us-ascii?Q?23MuG/VFQjPTmNyoutfJDWduR7hAUbY8HORC47/x2Nna5oL791mOPwRLC9Ky?= =?us-ascii?Q?NB/2IuGDTct34+0N8LWVMP+WNEn1qWuKBCtF8d8K03QR9NZHkoVOQdLDMw3z?= =?us-ascii?Q?99A9yKkZtx99St8k/zFaeBC+3qcPffafXCr9WFvYzOlP2FSyBZW+PhdOXHZJ?= =?us-ascii?Q?svDbFHKr6uyAhRcFVus//OveK6wUfS+1hXtywl+o8EObgWMcwg/S8SxwrIpH?= =?us-ascii?Q?7Rd0coXK39b82TEGOc9Qp6WtxNEVfIKRKiyUvwB/G3jbEZy864T+F4f30aNm?= =?us-ascii?Q?GGdHVmSURogJZgyH8nioIOgAL/uz2/1ABxBMTUWQGiWEmwNtLMCVnmBYRdDG?= =?us-ascii?Q?9QqibCchIIwqqr8qbJfsXJeqzEB1wH2IQucubXmo39iUM08idUEzJ3+XduB9?= =?us-ascii?Q?W88rHyxDkCk2cVNKlhcg02MXBGcsK4HANfgqVKAtrlQJEZ51JNbZpffvdgSc?= =?us-ascii?Q?H24+nuD/CnuxilxDqU5kBAex0YmYfMTF0YG4bDOXKpl6Sa6AHDy+3q3oDaJw?= =?us-ascii?Q?k6KQm615FuwUN4L89ti7x56IlX7FEJV1CwmmAgmgIAa9CJgsLUGRA/Z2dmRv?= =?us-ascii?Q?pFYiow8Jl8n9VTg/tTJZtlOxKPN/8ggxEjZJ0S6PiXs/4WrpG2c85B7nv1iZ?= =?us-ascii?Q?DORg0wpJMshcfOer018PUJwuNU/fqUlZysM2syMNaxB6GQpUnCv/jjdFw4t+?= =?us-ascii?Q?DMuEF9wyz1rhiFaYsz4J5mkuHgfjrw8cLLHv/Dg/wAOafwc8z+JqAqdFiVWm?= =?us-ascii?Q?xM8AUpWuLY1PfR47EfYmtosYh0qf2ADk1o30nRf5wQkF7cwmRXEQDmXI/Ytm?= =?us-ascii?Q?WZER5if2aehthuItU8u5YCv7ExAYCFZJNEkoq/43xdlSZO/atjmbUyQafC2Q?= =?us-ascii?Q?ayl45lQdCXNwJs3XCw4+eAE5uaGF1Wu6HFqdj?= X-Microsoft-Exchange-Diagnostics: 1; HE1PR0501MB2089; 6:4kdtVyxuk2eXE4oykfdbEjpvcedxVMmeRcryzlLLpRf2TrmXsYyxV0Xy5BBTObOkWkNWebefuahfRqakSUYBU1N64DMkYCI+QpIUwLg5HDb7LrgS1+gvqtaBWyFhX5CPqo6eg9wtd3BZuUrm9H6lFYg5XoRfKqNIA4OeNbJkdlVBKHZ/6FBOGsnb0NdmkwIvuG4/xjsjHNRbYJbqFKR1wQvCo8ummC3hhfTK93QebZGqCYepvfOHVcEbOONqOpyBs/dA2lEgCmMvzbiskdilCPB8rnIXihTZPW8t33n3IC19Ccan4u2RUO2G7INsju0L; 5:0SqnB6hJ9CRC507UHA/bxoVNlriH6FkfdMNvVDUYgr6PHkyngTN/+jxJW1QwvGsxmsPWU/zM1Ol9fBjdFszzsgQqRhdEmVoGirxhicsQxRT3e6kQD1S/qvn18U4vFy7HMR088xaXb+jHME2G21yaHw==; 24:uRPSHvUyYk3VijF220Ks3BI0NUav/9LtnzFWlJCsyEhqqxaW3/fMNzOp2Q1pbQe11a1JoRTmvzMpD0ZaCP0YN6rjJ+B51VoL5s064TK6+HY=; 7:i+QcGimHWzoVE8gA0HLfBWVyLj4yJ3S8ZeqzJrx+3j2vzohVfYnI7QseaFcOxAwbpLpyQvvORduxIEw9TRD5/t+terl/iFhRdhm7ugdyL3eHiUVE9vI2ZSxFSerxs0Z+HHa9I8TxTXTePaDghnULBgZx7Y29k3OVpMWZutzj4Y+mQ9ZKyKKbDuRU6VUL+DcVM8TJpUM1ubCBOKGEnkvOfBgeOvzPnTli5F2Icy5O28jmJFvs3sK08cxvhGa4bh37ukaCZH7jVClTpNT2gi3FEA== SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: toradex.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 28 Jun 2016 05:33:30.1409 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: HE1PR0501MB2089 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160627_223350_672698_AD71C118 X-CRM114-Status: GOOD ( 14.99 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-serial@vger.kernel.org, mturquette@baylibre.com, sboyd@codeaurora.org, linux-kernel@vger.kernel.org, stefan@agner.ch, kernel@pengutronix.de, jslaby@suse.com, shawnguo@kernel.org, linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Bhuvanchandra DV Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Drop PIO to DMA switching and use scatter/gather DMA for Tx path to improve performance. Some part of the code is borrowed from imx serial driver. Signed-off-by: Bhuvanchandra DV --- drivers/tty/serial/fsl_lpuart.c | 257 ++++++++++++++++++---------------------- 1 file changed, 113 insertions(+), 144 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 51d2b5a..27687d5 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -244,18 +244,18 @@ struct lpuart_port { struct dma_chan *dma_rx_chan; struct dma_async_tx_descriptor *dma_tx_desc; struct dma_async_tx_descriptor *dma_rx_desc; - dma_addr_t dma_tx_buf_bus; dma_cookie_t dma_tx_cookie; dma_cookie_t dma_rx_cookie; - unsigned char *dma_tx_buf_virt; unsigned int dma_tx_bytes; unsigned int dma_rx_bytes; - int dma_tx_in_progress; + bool dma_tx_in_progress; unsigned int dma_rx_timeout; struct timer_list lpuart_timer; - struct scatterlist rx_sgl; + struct scatterlist rx_sgl, tx_sgl[2]; struct circ_buf rx_ring; int rx_dma_rng_buf_len; + unsigned int dma_tx_nents; + wait_queue_head_t dma_wait; }; static const struct of_device_id lpuart_dt_ids[] = { @@ -316,103 +316,118 @@ static void lpuart32_stop_rx(struct uart_port *port) lpuart32_write(temp & ~UARTCTRL_RE, port->membase + UARTCTRL); } -static void lpuart_pio_tx(struct lpuart_port *sport) +static void lpuart_dma_tx(struct lpuart_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock, flags); + struct scatterlist *sgl = sport->tx_sgl; + struct device *dev = sport->port.dev; + int ret; - while (!uart_circ_empty(xmit) && - readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) { - writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; - } + if (sport->dma_tx_in_progress) + return; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); + sport->dma_tx_bytes = uart_circ_chars_pending(xmit); - if (uart_circ_empty(xmit)) - writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS, - sport->port.membase + UARTCR5); + if (xmit->tail < xmit->head) { + sport->dma_tx_nents = 1; + sg_init_one(sgl, xmit->buf + xmit->tail, sport->dma_tx_bytes); + } else { + sport->dma_tx_nents = 2; + sg_init_table(sgl, 2); + sg_set_buf(sgl, xmit->buf + xmit->tail, + UART_XMIT_SIZE - xmit->tail); + sg_set_buf(sgl + 1, xmit->buf, xmit->head); + } - spin_unlock_irqrestore(&sport->port.lock, flags); -} + ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + if (!ret) { + dev_err(dev, "DMA mapping error for TX.\n"); + return; + } -static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - dma_addr_t tx_bus_addr; - - dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus, - UART_XMIT_SIZE, DMA_TO_DEVICE); - sport->dma_tx_bytes = count & ~(sport->txfifo_size - 1); - tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail; - sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan, - tx_bus_addr, sport->dma_tx_bytes, + sport->dma_tx_desc = dmaengine_prep_slave_sg(sport->dma_tx_chan, sgl, + sport->dma_tx_nents, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); - if (!sport->dma_tx_desc) { - dev_err(sport->port.dev, "Not able to get desc for tx\n"); - return -EIO; + dma_unmap_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + dev_err(dev, "Cannot prepare TX slave DMA!\n"); + return; } sport->dma_tx_desc->callback = lpuart_dma_tx_complete; sport->dma_tx_desc->callback_param = sport; - sport->dma_tx_in_progress = 1; + sport->dma_tx_in_progress = true; sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc); dma_async_issue_pending(sport->dma_tx_chan); - return 0; -} - -static void lpuart_prepare_tx(struct lpuart_port *sport) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - unsigned long count = CIRC_CNT_TO_END(xmit->head, - xmit->tail, UART_XMIT_SIZE); - - if (!count) - return; - - if (count < sport->txfifo_size) - writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS, - sport->port.membase + UARTCR5); - else { - writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS, - sport->port.membase + UARTCR5); - lpuart_dma_tx(sport, count); - } } static void lpuart_dma_tx_complete(void *arg) { struct lpuart_port *sport = arg; + struct scatterlist *sgl = &sport->tx_sgl[0]; struct circ_buf *xmit = &sport->port.state->xmit; unsigned long flags; - async_tx_ack(sport->dma_tx_desc); - spin_lock_irqsave(&sport->port.lock, flags); + dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1); - sport->dma_tx_in_progress = 0; + + sport->port.icount.tx += sport->dma_tx_bytes; + sport->dma_tx_in_progress = false; + spin_unlock_irqrestore(&sport->port.lock, flags); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); - lpuart_prepare_tx(sport); + if (waitqueue_active(&sport->dma_wait)) { + wake_up(&sport->dma_wait); + return; + } + + spin_lock_irqsave(&sport->port.lock, flags); + + if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) + lpuart_dma_tx(sport); spin_unlock_irqrestore(&sport->port.lock, flags); } +static int lpuart_dma_tx_request(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + struct dma_slave_config dma_tx_sconfig = {}; + int ret; + + dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR; + dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_tx_sconfig.dst_maxburst = 1; + dma_tx_sconfig.direction = DMA_MEM_TO_DEV; + ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig); + + if (ret) { + dev_err(sport->port.dev, + "DMA slave config failed, err = %d\n", ret); + return ret; + } + + return 0; +} + static void lpuart_flush_buffer(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + if (sport->lpuart_dma_tx_use) { + if (sport->dma_tx_in_progress) { + dma_unmap_sg(sport->port.dev, &sport->tx_sgl[0], + sport->dma_tx_nents, DMA_TO_DEVICE); + sport->dma_tx_in_progress = false; + } dmaengine_terminate_all(sport->dma_tx_chan); - sport->dma_tx_in_progress = 0; } } @@ -469,8 +484,8 @@ static void lpuart_start_tx(struct uart_port *port) writeb(temp | UARTCR2_TIE, port->membase + UARTCR2); if (sport->lpuart_dma_tx_use) { - if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress) - lpuart_prepare_tx(sport); + if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) + lpuart_dma_tx(sport); } else { if (readb(port->membase + UARTSR1) & UARTSR1_TDRE) lpuart_transmit_buffer(sport); @@ -489,6 +504,29 @@ static void lpuart32_start_tx(struct uart_port *port) lpuart32_transmit_buffer(sport); } +/* return TIOCSER_TEMT when transmitter is not busy */ +static unsigned int lpuart_tx_empty(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + unsigned char sr1 = readb(port->membase + UARTSR1); + unsigned char sfifo = readb(port->membase + UARTSFIFO); + + if (sport->dma_tx_in_progress) + return 0; + + if (sr1 & UARTSR1_TC && sfifo & UARTSFIFO_TXEMPT) + return TIOCSER_TEMT; + + return 0; +} + +static unsigned int lpuart32_tx_empty(struct uart_port *port) +{ + return (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TC) ? + TIOCSER_TEMT : 0; +} + static irqreturn_t lpuart_txint(int irq, void *dev_id) { struct lpuart_port *sport = dev_id; @@ -662,12 +700,8 @@ static irqreturn_t lpuart_int(int irq, void *dev_id) if (sts & UARTSR1_RDRF) lpuart_rxint(irq, dev_id); - if (sts & UARTSR1_TDRE) { - if (sport->lpuart_dma_tx_use) - lpuart_pio_tx(sport); - else - lpuart_txint(irq, dev_id); - } + if (sts & UARTSR1_TDRE) + lpuart_txint(irq, dev_id); return IRQ_HANDLED; } @@ -692,29 +726,6 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id) return IRQ_HANDLED; } -/* return TIOCSER_TEMT when transmitter is not busy */ -static unsigned int lpuart_tx_empty(struct uart_port *port) -{ - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); - unsigned char sr1 = readb(port->membase + UARTSR1); - unsigned char sfifo = readb(port->membase + UARTSFIFO); - - if (sport->dma_tx_in_progress) - return 0; - - if (sr1 & UARTSR1_TC && sfifo & UARTSFIFO_TXEMPT) - return TIOCSER_TEMT; - - return 0; -} - -static unsigned int lpuart32_tx_empty(struct uart_port *port) -{ - return (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TC) ? - TIOCSER_TEMT : 0; -} - static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) { struct tty_port *port = &sport->port.state->port; @@ -890,18 +901,6 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) return 0; } -static void lpuart_dma_tx_free(struct uart_port *port) -{ - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); - - dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus, - UART_XMIT_SIZE, DMA_TO_DEVICE); - - sport->dma_tx_buf_bus = 0; - sport->dma_tx_buf_virt = NULL; -} - static void lpuart_dma_rx_free(struct uart_port *port) { struct lpuart_port *sport = container_of(port, @@ -1061,44 +1060,6 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport) lpuart32_write(ctrl_saved, sport->port.membase + UARTCTRL); } -static int lpuart_dma_tx_request(struct uart_port *port) -{ - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); - struct dma_slave_config dma_tx_sconfig; - dma_addr_t dma_bus; - unsigned char *dma_buf; - int ret; - - dma_bus = dma_map_single(sport->dma_tx_chan->device->dev, - sport->port.state->xmit.buf, - UART_XMIT_SIZE, DMA_TO_DEVICE); - - if (dma_mapping_error(sport->dma_tx_chan->device->dev, dma_bus)) { - dev_err(sport->port.dev, "dma_map_single tx failed\n"); - return -ENOMEM; - } - - dma_buf = sport->port.state->xmit.buf; - dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR; - dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - dma_tx_sconfig.dst_maxburst = sport->txfifo_size; - dma_tx_sconfig.direction = DMA_MEM_TO_DEV; - ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig); - - if (ret < 0) { - dev_err(sport->port.dev, - "Dma slave config failed, err = %d\n", ret); - return ret; - } - - sport->dma_tx_buf_virt = dma_buf; - sport->dma_tx_buf_bus = dma_bus; - sport->dma_tx_in_progress = 0; - - return 0; -} - static void rx_dma_timer_init(struct lpuart_port *sport) { setup_timer(&sport->lpuart_timer, lpuart_timer_func, @@ -1151,6 +1112,7 @@ static int lpuart_startup(struct uart_port *port) } if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) { + init_waitqueue_head(&sport->dma_wait); sport->lpuart_dma_tx_use = true; temp = readb(port->membase + UARTCR5); writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5); @@ -1220,8 +1182,15 @@ static void lpuart_shutdown(struct uart_port *port) lpuart_dma_rx_free(&sport->port); } - if (sport->lpuart_dma_tx_use) - lpuart_dma_tx_free(&sport->port); + if (sport->lpuart_dma_tx_use) { + if (wait_event_interruptible(sport->dma_wait, + !sport->dma_tx_in_progress) != false) { + sport->dma_tx_in_progress = false; + dmaengine_terminate_all(sport->dma_tx_chan); + } + + lpuart_stop_tx(port); + } } static void lpuart32_shutdown(struct uart_port *port)