From patchwork Thu Jun 9 15:10:37 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bhuvanchandra DV X-Patchwork-Id: 9167313 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 B8D5560832 for ; Thu, 9 Jun 2016 15:28:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AA99128338 for ; Thu, 9 Jun 2016 15:28:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9F8362835A; Thu, 9 Jun 2016 15:28:10 +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=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E024928342 for ; Thu, 9 Jun 2016 15:28:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932686AbcFIP1v (ORCPT ); Thu, 9 Jun 2016 11:27:51 -0400 Received: from mail-db3on0132.outbound.protection.outlook.com ([157.55.234.132]:57054 "EHLO emea01-db3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S932662AbcFIP1s (ORCPT ); Thu, 9 Jun 2016 11:27:48 -0400 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=JUbld3pgiUO0FzNPmjYWIbaByn4UGUrePT2IAI3gVZI=; b=OA4jdumBDs4jzt+zNDipfW7tK3aAFfEIdUkU6/74f6vTW92h0Z+A6hOUTJnETOyc8vfZ90s3VtPFBEEwEE2uF9gONQ9JDWMNzcxXvGFGGF2tCV878PMIUODhk+1rYsqUkPaSRtlEdh1PphxwEPg1TdYfQVQdWumkwQ7VPMlg95o= 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 DB4PR05MB270.eurprd05.prod.outlook.com (10.242.158.24) with Microsoft SMTP Server (TLS) id 15.1.511.8; Thu, 9 Jun 2016 15:11:36 +0000 From: Bhuvanchandra DV To: CC: , , , , , , , , , , "Bhuvanchandra DV" Subject: [PATCH 6/8] tty: serial: fsl-lpuart: Use scatter/gather DMA for Tx Drop PIO to DMA switching and use scatter/gather DMA for Tx path to improve performance. Date: Thu, 9 Jun 2016 20:40:37 +0530 Message-ID: <20160609151039.20817-7-bhuvanchandra.dv@toradex.com> X-Mailer: git-send-email 2.8.3 In-Reply-To: <20160609151039.20817-1-bhuvanchandra.dv@toradex.com> References: <20160609151039.20817-1-bhuvanchandra.dv@toradex.com> MIME-Version: 1.0 X-Originating-IP: [115.115.243.34] X-ClientProxiedBy: SIXPR04CA0050.apcprd04.prod.outlook.com (10.162.171.40) To DB4PR05MB270.eurprd05.prod.outlook.com (10.242.158.24) X-MS-Office365-Filtering-Correlation-Id: 105eb759-0a77-48bb-1427-08d390785cad X-Microsoft-Exchange-Diagnostics: 1; DB4PR05MB270; 2:GO0CXh174qm/g+GVNSXteNlipArUrNgx1rCPckrer7VX+ytyYlwVsdKI0sSi5ycBFMhqFMnKNRoq9fFLbIddndyWrjoAAjbGH7yoju63OX9vrxck6f5ZYpQqc4L0kJXT66Rc6A2XZlmggf2kGB1Ar+6W9CcNvq7wpI+fKx8rvuCWEjwdnh4V42xiudmMXXni; 3:HHWifjyfLKzUOb7K0fRA+Xu6+cpXkIEhpB6NasPyOkByH4YtGDUq65CS4e6Cdm4OB1061Gq+CBM2a6rEGds1oXZj0p4qa6LqgBpYrblScZy6zgKRkwLom0gf0Ij/4xwP X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:DB4PR05MB270; X-Microsoft-Exchange-Diagnostics: 1; DB4PR05MB270; 25:NVTxtpEZa+AXs/PWveEePIVVqepbZ3DqHrr2lYTgvJgo5CipdvkExjd5U7rARLN0tPSdzkcK1f6/GgOcxngz2PVzp2M3bMi7z8EN8xWGHkHf1S0lg+16pC7CpG0HFojliFRZFRp8LkTnMfW2G2YE9OeAZQXNpMDZTEKUKTlyLeF04/TvEzxdFabXHcq0AbCHl3DNyj76OE/F3Tdxa/Bh/5t0TdpZ74jKtb4oSrDheeywFtTX7dkpsXL+r6a82AZ0y4xM8mFSxFx01IjmbWZh/I4/QQwzlTwp3iDdR0YRArkMeVDuofz2CPIMErv5tsxIUZQQlosqWjyKb82/0/nysBssPZiyx5PKLBApz7TVf7Uf3ui+x19sSb83qVH0a8Z+9Kg24PA+SJtNdkiE153JvsY4MaX47kbuTmTey/G5kc34QzFlZIToxz3Ci8egzSDLv0mdIo/SacH+1ASQhjjgVglYb4psCkDQ3/Twr+xQ8CaLulPNI4F4ellg7R8G9AxAyE+H1A9qTEnofnVDqHyj0uJrwRuI33TBIS9KK0hAeT9Ipmn1d8SzkglR8Mc+2ENLUk5fulHBP9MJkm1K0t71Zs74eZgcpnDVHrXEUKbK/lRADwj4qxDfVZkYIqBg+D1eGkKicc2yTojVL6eY3/2uyeuBBA6mutHHAR5Qjhg3KztKVU99Me9OkYM3laXip1rWVi/Wa6q7d8tY/br5BVqfGwJagfHUGwzDy3g7rJ0Pgcs= X-Microsoft-Exchange-Diagnostics: 1; DB4PR05MB270; 20:MCWjSEYrbGB/7kMabkK2sYLCfxEToERmKYi9z/zs+xCdxo/rvYn+1ZAqfFrlq0YebmO2CD6Fe8zNrVsBV8PJYBqc4Yf4AGBTiFydHKjF5mZIkqYxO2KYncICE4O9R2g7Pm+mOKeEVZKEDr/Mk4OdArCS+Ml6NU4eiDThmtZCXp/5BOnFlqUZLY7UAyUMpvZxG/HnNhsFjx9qEdiS2+rb02ykX8O3uQxycbleqrSZbhz7jzc57rcCtRX9vwqKBlDIwxPKbQOI7wX/2PjPmu0ss4xyvzcVuuUJn+rs6VgWAP6DFHFFh1uZaZo3qx2sbDAkw8JBGBcKsK4cten361IkNA==; 4:iuieYb3Xdx87SY8rlFplCQ3SxLPwC7YLsePIGFokAuPH87wXshiJyD7xcN32VekIzNgEXbbFzCXZwmeS7GgVkOQ2Iyg8hSMVtNZUnAP5eUycbRZUBHcpI1V+L24hHQyFJSbbPUPTiKUVi/FALuNdnrs0bRbMfPJqrCcFctuXOCjpRa9W7t98KNIW2aPUTVATb7YIFa+Yi55Tpm2IUSxsQltb+oWPQ9aiRqTwWZjEUzBAHr6T1QVhfPIwCSDzIKR+cwRcZbNzYpzXbIxZcqHEF3Vw7P/4EEc686nYj8uYPwyoq5TDwLWZr6jqe/vfsXDdrnANQ8McY96dgjb4VUvqNI5FOq7MQTxPbhhTut1Aeb+Nce67dS3fr5vGPxFMcoZl 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)(3002001)(10201501046); SRVR:DB4PR05MB270; BCL:0; PCL:0; RULEID:; SRVR:DB4PR05MB270; X-Forefront-PRVS: 0968D37274 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(4630300001)(6009001)(189002)(199003)(36756003)(50466002)(4001430100002)(42186005)(1076002)(86362001)(19580395003)(69596002)(48376002)(5008740100001)(81156014)(19580405001)(97736004)(4326007)(2906002)(77096005)(101416001)(81166006)(50226002)(2950100001)(33646002)(6116002)(68736007)(2351001)(3846002)(5003940100001)(107886002)(105586002)(110136002)(106356001)(53416004)(229853001)(50986999)(8676002)(189998001)(92566002)(5004730100002)(66066001)(586003)(76176999)(47776003); DIR:OUT; SFP:1102; SCL:1; SRVR:DB4PR05MB270; H:tdx-in-nb-0014.toradex.ext; FPR:; SPF:None; PTR:InfoNoRecords; MX:1; A: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; DB4PR05MB270; 23:Pduay5T2nKnJbeXxSbyuWmAUBBbmABvEHI49F/3Kql?= =?us-ascii?Q?Jge8tQfHknX88Blsxuxm3i3OzwUrqDoli9gpEC9VAUVgxGtLDiI5MCgLkscA?= =?us-ascii?Q?TX2OdmQg3rhgdqhRgRHnFts92xAl2ZMqQfefAnOgzm4PiDs9HAtSxn3HFB9C?= =?us-ascii?Q?B416N9sBYDnLoKPS/qkprVshaFszy/K9jCFmNxlSbcRlQl8MOQPscj4FftpL?= =?us-ascii?Q?9VBeKhceFl8cNMYb5jeJX0cMqxI6hxZrZSuJ5tmPZ1sNaKajy0B4YTyoKUIM?= =?us-ascii?Q?EauD8/G1WSWlE8O/JRGe1o7qi2Pb1/dm+wY+tsttW2tpubuHcEGHXXNNgstB?= =?us-ascii?Q?eiW6XI5BspNLnQVtM5RK3y2CejoC7V8465kWu+ex4uUDo4kYK1VIXTSlo1an?= =?us-ascii?Q?lHwca43itqc4PS8hQ6zrcVPnJCv1CYVqvs1qHrr2Mn9DViCIsUC998/v5uFf?= =?us-ascii?Q?feNetepFxJUKMvTNYggemfqL4Go5bFusWtqbGZAbOPqxRRrupfC64PnoOtsy?= =?us-ascii?Q?0CQgUFallQz2hGyOcOyAEzMBGzOS9/zb2SwTyGZmuQ/SdwmxmPduqzDTSY4O?= =?us-ascii?Q?J5fFpGt5mQChH5K8D8w7nPoFeuQNB3P12JwJIu2lyUe63nMyBiFY0RWdnAic?= =?us-ascii?Q?6Ot0U77h6dJPQHWMqlu3VUZRdE9ZCIbQ0GwJxEKNT9KYo1yPOyVHudI958Ky?= =?us-ascii?Q?PkNQtYel+0eGH8GR5OLr8JnvIoBZ9zlQJ7q/Zk4V9YqQvF2fDXZq07V/Ksmp?= =?us-ascii?Q?IbKfyZHgTmMOJOvNxYatOHlwQkX5/+PybmfF2FLl5WeZVd18HVTRSUieeaSC?= =?us-ascii?Q?FkxAnDKrm/q/SYZ7oDvWijfMw45pnkU/rEqxZmL9Ktm39cI90NmzqIhm4rHl?= =?us-ascii?Q?fGJtoiZadbsBD7URKdVkFf+zkJvkUQtUh+pi8ojV2aOV9zIAgsJg1QzNYRIq?= =?us-ascii?Q?N+tHTHSA6RuqhjC54EzhfiXalJbHPEkC4z7Q17uvE1dR2RC5Fu5Dfx/e6AXK?= =?us-ascii?Q?3k4Gg2ARCfQ/W7dMZ2uXURvwLsQgDOrQuxK/drhiWnuOmN5dgzLldsq+Iu46?= =?us-ascii?Q?HrS4CsY4Z+FmwYUvfWFOZZSoAGP8SJHhCjNUggZxMpc5cF59sEFXHACBKFRT?= =?us-ascii?Q?rSKBVadMRCHksx8IqAQYOnOXp5kEtm50i0beoqAn/wSLf4/xglDg=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1; DB4PR05MB270; 5:qwr+ncYCgiIJgWOMKHtmWBOYqWTNtkh2orpazNXcN4wK81w9jBvNgC2INhFgH3cijV8WJqo5dzNLIXYM2VTOl7roDJyZyuRa0xjme5ju2BtzBbQBYNANT2ubnY+92QErgvMVwSVVxXS7yGdhalGnAw==; 24:nrB/Ebf94G7kvu1AEfcjZxZQkgTzVPZvaYAcI76b4bTe21Wbv9PEpTFA9i++KITKmZxuwfvYUwqDpbo0uCnuE0dA6+br8tdnVYfOZZlbXJw=; 7:QON8dJeAnKAHpFUXjTmAyLUScImoKWRJKAE5a0KxOo8aOwRBKHaEIdF9R4E+r0lhhrhZzIIRvGlxQkH4KulY2vA0QSdYYrlOQ22W09i1wmOhPwM4kSXVEp4ihv1vA9WhsaV3Zby3TKVb/0DpD8WxqK3OYPSsiaCRtfBJBtDkyREwvbG+szWUh/3t3tTnX11L1/XdJnx66rcl8LjER8Zu5A== SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: toradex.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Jun 2016 15:11:36.5630 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB4PR05MB270 Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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)