From patchwork Mon Oct 25 13:42:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Erwan LE RAY X-Patchwork-Id: 12581879 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 73B73C433F5 for ; Mon, 25 Oct 2021 13:44:19 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3CD6D60E05 for ; Mon, 25 Oct 2021 13:44:19 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 3CD6D60E05 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=foss.st.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=dAqevfM5pFaBItI/CMo5QMlZIAEkh0dbwGGQvDHbGlY=; b=FuUQtlAPs6UKVt vwlg1VXMF6OhV2XjMkJIZ5FAs+QVYbQLn/u84+E3p83q/sMsFiIaFN5KZ8OR8bcxSSyo+kolVmMB/ pWDiHZXa9sfi/ZP8nYNlYGlvUktGZlNLDa7HcQQh8b2LkYeIK3xnFwbxiE9fkHpMVkQNQ3P48LOO7 ZP7Erxe/VlowUiJgUuI8Y+hGz7wjoc2KZsndJNWzvy0iFcKuIO2NULkAO2d0LY3CHOuLUfUCYj8g3 xgpcAlOByHrXh9AKMUPOM0Sfr2rkW3kcgKGHT+gW3m8I07xOT+33oPfEEhP6xSCCh+2xzt8hOgNp0 Muegg18h0LgcAsWYmdGA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mf0Ff-00GYrh-Nx; Mon, 25 Oct 2021 13:42:59 +0000 Received: from mx07-00178001.pphosted.com ([185.132.182.106]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mf0FQ-00GYon-G9 for linux-arm-kernel@lists.infradead.org; Mon, 25 Oct 2021 13:42:46 +0000 Received: from pps.filterd (m0046668.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 19P8D6SK003402; Mon, 25 Oct 2021 15:42:35 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=selector1; bh=hR+h0mj9eAIHJV+3ilRJChIbgb6EPcNV71c8l1Q/vvM=; b=yDL3uWZJXZl0T5Zw23sTZJNBLrYKn2jeSEHxxqCqoYTZDdfsUJ2oDtgVnI3Zb5pe+4sQ jkThkutudBiFG+JfxvSlIcYGE9Zt13K7sYGMpUopc7uI/2iaHculeJn2gO5QYtMxp5ZT 0DyJnX5wx1FG29neF7BxVZSbwXyKlZl6mL78vc2Wfkj/gCDRqmXa4Bk86cIyHnnyT/jt pftVa8UytSjfBOtrbIiCQZSoJXN4U4uSpJ1uhaGGN/UOkmH/JuwBaR+LVQw6pwUi5+QU HDoBiu5yqEicz6yJWIJLaJT1YChISv7ikw5wQ0QZCzvJcHUYiiUF79P9hvpAb/fIph+2 yA== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 3bwrvj1t9h-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 25 Oct 2021 15:42:35 +0200 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 31024100034; Mon, 25 Oct 2021 15:42:35 +0200 (CEST) Received: from Webmail-eu.st.com (sfhdag2node2.st.com [10.75.127.5]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 2903F2309DF; Mon, 25 Oct 2021 15:42:35 +0200 (CEST) Received: from localhost (10.75.127.44) by SFHDAG2NODE2.st.com (10.75.127.5) with Microsoft SMTP Server (TLS) id 15.0.1497.18; Mon, 25 Oct 2021 15:42:34 +0200 From: Erwan Le Ray To: Greg Kroah-Hartman , Jiri Slaby , Maxime Coquelin , Alexandre Torgue CC: , , , , Erwan Le Ray , Fabrice Gasnier , Valentin Caron , Amelie Delaunay Subject: [PATCH 1/3] serial: stm32: rework RX dma initialization and release Date: Mon, 25 Oct 2021 15:42:27 +0200 Message-ID: <20211025134229.8456-2-erwan.leray@foss.st.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211025134229.8456-1-erwan.leray@foss.st.com> References: <20211025134229.8456-1-erwan.leray@foss.st.com> MIME-Version: 1.0 X-Originating-IP: [10.75.127.44] X-ClientProxiedBy: SFHDAG2NODE2.st.com (10.75.127.5) To SFHDAG2NODE2.st.com (10.75.127.5) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.182.1,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.0.607.475 definitions=2021-10-25_05,2021-10-25_02,2020-04-07_01 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211025_064245_031516_A54736FE X-CRM114-Status: GOOD ( 21.50 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org The RX DMA channel is kept active forever (from the probe). That prevents going to low power mode when it is used. This change moves the DMA configuration and enabling procedures to startup routine to allow transition to low power mode. The DMA disabling procedure is implemented in stop_rx routine as this ops has to stop characters reception, and DMA transation in shutdown. Clean useless dma_async_tx_descriptor initialization to NULL value. Signed-off-by: Valentin Caron Signed-off-by: Erwan Le Ray diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 7fd192e1e15d..ee3495c0abbb 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -761,6 +761,10 @@ static void stm32_usart_stop_rx(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + /* Disable DMA request line. */ + if (stm32_port->rx_ch) + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); if (stm32_port->cr3_irq) stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); @@ -777,6 +781,7 @@ static int stm32_usart_startup(struct uart_port *port) const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; const struct stm32_usart_config *cfg = &stm32_port->info->cfg; const char *name = to_platform_device(port->dev)->name; + struct dma_async_tx_descriptor *desc; u32 val; int ret; @@ -797,6 +802,33 @@ static int stm32_usart_startup(struct uart_port *port) if (ofs->rqr != UNDEF_REG) writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr); + if (stm32_port->rx_ch) { + stm32_port->last_res = RX_BUF_L; + /* Prepare a DMA cyclic transaction */ + desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, + stm32_port->rx_dma_buf, + RX_BUF_L, RX_BUF_P, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(port->dev, "rx dma prep cyclic failed\n"); + ret = -ENODEV; + goto err; + } + + desc->callback = stm32_usart_rx_dma_complete; + desc->callback_param = port; + + /* Push current DMA transaction in the pending queue */ + ret = dma_submit_error(dmaengine_submit(desc)); + if (ret) { + dmaengine_terminate_sync(stm32_port->rx_ch); + goto err; + } + + /* Issue pending DMA requests */ + dma_async_issue_pending(stm32_port->rx_ch); + } /* * DMA request line not re-enabled at resume when port is throttled. * It will be re-enabled by unthrottle ops. @@ -809,6 +841,11 @@ static int stm32_usart_startup(struct uart_port *port) stm32_usart_set_bits(port, ofs->cr1, val); return 0; + +err: + free_irq(port->irq, port); + + return ret; } static void stm32_usart_shutdown(struct uart_port *port) @@ -836,6 +873,10 @@ static void stm32_usart_shutdown(struct uart_port *port) if (ret) dev_err(port->dev, "Transmission is not complete\n"); + /* Disable RX DMA. */ + if (stm32_port->rx_ch) + dmaengine_terminate_async(stm32_port->rx_ch); + /* flush RX & TX FIFO */ if (ofs->rqr != UNDEF_REG) writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ, @@ -1304,7 +1345,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, struct uart_port *port = &stm32port->port; struct device *dev = &pdev->dev; struct dma_slave_config config; - struct dma_async_tx_descriptor *desc = NULL; int ret; /* @@ -1332,32 +1372,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, return ret; } - /* Prepare a DMA cyclic transaction */ - desc = dmaengine_prep_dma_cyclic(stm32port->rx_ch, - stm32port->rx_dma_buf, - RX_BUF_L, RX_BUF_P, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); - if (!desc) { - dev_err(dev, "rx dma prep cyclic failed\n"); - stm32_usart_of_dma_rx_remove(stm32port, pdev); - return -ENODEV; - } - - /* Set DMA callback */ - desc->callback = stm32_usart_rx_dma_complete; - desc->callback_param = port; - - /* Push current DMA transaction in the pending queue */ - ret = dma_submit_error(dmaengine_submit(desc)); - if (ret) { - dmaengine_terminate_sync(stm32port->rx_ch); - stm32_usart_of_dma_rx_remove(stm32port, pdev); - return ret; - } - - /* Issue pending DMA requests */ - dma_async_issue_pending(stm32port->rx_ch); - return 0; } @@ -1535,7 +1549,6 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) } if (stm32_port->rx_ch) { - dmaengine_terminate_async(stm32_port->rx_ch); stm32_usart_of_dma_rx_remove(stm32_port, pdev); dma_release_channel(stm32_port->rx_ch); } From patchwork Mon Oct 25 13:42:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Erwan LE RAY X-Patchwork-Id: 12581885 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 54896C433EF for ; Mon, 25 Oct 2021 13:44:34 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 20C0E60F46 for ; Mon, 25 Oct 2021 13:44:34 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 20C0E60F46 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=foss.st.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=d5cykNmQ9KE0MYr/7A1FNLMGu+CRQZaclj2A7QEJV50=; b=c+h8t9ha6rF6ZN 5kHO1w/6Og/GnRyemvrP9xAK7fMFsROjmu0WWvIxi+sekB8ojCE5ziHzaXta+PoNVSZeHOidnrt5U dpyPFeWe+90yn7aAO+xDA1+/WT53Ypa9lSevze4OqdDs0mkxi/AgxsffkJkUVYKKqZa33GS1iaXh2 DYqtHSo1fHDMM7+KVe0eBZGiaDRjvoUCwnTInnjfivL4R6wNuaX6j2IM5GQ9XjydsBiv7jd8XgrYD Zy9wYN42u0oMLqnCpjepI3O/MAX4US/0rOEJJgUeqyyUGkLdDFhi5gGl+eOKHH2+neq5PaMQwSZ9p 1HD98TMwq9+g9kPOJJUw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mf0G0-00GYwG-Sg; Mon, 25 Oct 2021 13:43:21 +0000 Received: from mx07-00178001.pphosted.com ([185.132.182.106]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mf0FQ-00GYoo-Nh for linux-arm-kernel@lists.infradead.org; Mon, 25 Oct 2021 13:42:47 +0000 Received: from pps.filterd (m0046668.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 19P8CwEa003297; Mon, 25 Oct 2021 15:42:36 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=selector1; bh=W0oRgchsCYcZpiV/Ypg4RY1iam19qKNxv3BV3g4lEeQ=; b=Jt8nAda2jTrXfhLQUtgIlVCFHCD40C/H7KynBrxtqOftqI6Q5X+UvzmLlNYR/E46jJR+ YGtVG3ne0CuL/uiCwxfQItlgbGtF8d8qQ4dAYXpqhO5WuKx71cSV+y3+vjJ6QEBR06oL DAhIGMnX32kDiqHj+0qk/7ER1BOMtH8FAvQ+Ef+JGmclF6spV3jzaza4qYSYHqgN5VTl kWJT2HnJrT2Lj0Q4DSBzBgchEHxDQS2NtwZfyeQ1ldgS4hcyXu9HPm3ngGvkGmp6+MEa cfIet8unQfDxxQsXt2n8K8IqGSuTB0414KzR5LlmtxTo62GcWzN1xaYxVDL/3P996GlE DQ== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 3bwrvj1t9k-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 25 Oct 2021 15:42:36 +0200 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 06976100038; Mon, 25 Oct 2021 15:42:36 +0200 (CEST) Received: from Webmail-eu.st.com (sfhdag2node2.st.com [10.75.127.5]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id F09282309DF; Mon, 25 Oct 2021 15:42:35 +0200 (CEST) Received: from localhost (10.75.127.45) by SFHDAG2NODE2.st.com (10.75.127.5) with Microsoft SMTP Server (TLS) id 15.0.1497.18; Mon, 25 Oct 2021 15:42:35 +0200 From: Erwan Le Ray To: Greg Kroah-Hartman , Jiri Slaby , Maxime Coquelin , Alexandre Torgue CC: , , , , Erwan Le Ray , Fabrice Gasnier , Valentin Caron , Amelie Delaunay Subject: [PATCH 2/3] serial: stm32: terminate / restart DMA transfer at suspend / resume Date: Mon, 25 Oct 2021 15:42:28 +0200 Message-ID: <20211025134229.8456-3-erwan.leray@foss.st.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211025134229.8456-1-erwan.leray@foss.st.com> References: <20211025134229.8456-1-erwan.leray@foss.st.com> MIME-Version: 1.0 X-Originating-IP: [10.75.127.45] X-ClientProxiedBy: SFHDAG1NODE3.st.com (10.75.127.3) To SFHDAG2NODE2.st.com (10.75.127.5) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.182.1,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.0.607.475 definitions=2021-10-25_05,2021-10-25_02,2020-04-07_01 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211025_064245_147199_2A3AF435 X-CRM114-Status: GOOD ( 25.26 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DMA prevents the system to suspend when an UART RX wake-up source is using DMA. DMA can't suspend while DMA channels are still active. Terminate DMA transfer at suspend, and restart a new DMA transfer at resume. Create stm32_usart_start_rx_dma_cyclic function to factorize dma RX initialization. Move RX DMA code related to wakeup into stm32_usart_serial_en_wakeup() routine to ease further improvements on wakeup from low power modes. Don't enable/disable wakeup on uninitialized port. There may be data residue in the RX FIFO while suspending. Flush it at suspend time. Receiver timeout interrupt won't trigger later in low power mode, so call stm32_usart_receive_chars() in case there's data to handle. Signed-off-by: Valentin Caron Signed-off-by: Erwan Le Ray diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index ee3495c0abbb..4b5b0748790c 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -775,13 +775,54 @@ static void stm32_usart_break_ctl(struct uart_port *port, int break_state) { } +static int stm32_usart_start_rx_dma_cyclic(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct dma_async_tx_descriptor *desc; + int ret; + + stm32_port->last_res = RX_BUF_L; + /* Prepare a DMA cyclic transaction */ + desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, + stm32_port->rx_dma_buf, + RX_BUF_L, RX_BUF_P, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(port->dev, "rx dma prep cyclic failed\n"); + return -ENODEV; + } + + desc->callback = stm32_usart_rx_dma_complete; + desc->callback_param = port; + + /* Push current DMA transaction in the pending queue */ + ret = dma_submit_error(dmaengine_submit(desc)); + if (ret) { + dmaengine_terminate_sync(stm32_port->rx_ch); + return ret; + } + + /* Issue pending DMA requests */ + dma_async_issue_pending(stm32_port->rx_ch); + + /* + * DMA request line not re-enabled at resume when port is throttled. + * It will be re-enabled by unthrottle ops. + */ + if (!stm32_port->throttled) + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); + + return 0; +} + static int stm32_usart_startup(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; const struct stm32_usart_config *cfg = &stm32_port->info->cfg; const char *name = to_platform_device(port->dev)->name; - struct dma_async_tx_descriptor *desc; u32 val; int ret; @@ -803,49 +844,18 @@ static int stm32_usart_startup(struct uart_port *port) writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr); if (stm32_port->rx_ch) { - stm32_port->last_res = RX_BUF_L; - /* Prepare a DMA cyclic transaction */ - desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, - stm32_port->rx_dma_buf, - RX_BUF_L, RX_BUF_P, - DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); - if (!desc) { - dev_err(port->dev, "rx dma prep cyclic failed\n"); - ret = -ENODEV; - goto err; - } - - desc->callback = stm32_usart_rx_dma_complete; - desc->callback_param = port; - - /* Push current DMA transaction in the pending queue */ - ret = dma_submit_error(dmaengine_submit(desc)); + ret = stm32_usart_start_rx_dma_cyclic(port); if (ret) { - dmaengine_terminate_sync(stm32_port->rx_ch); - goto err; + free_irq(port->irq, port); + return ret; } - - /* Issue pending DMA requests */ - dma_async_issue_pending(stm32_port->rx_ch); } - /* - * DMA request line not re-enabled at resume when port is throttled. - * It will be re-enabled by unthrottle ops. - */ - if (!stm32_port->throttled) - stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); /* RX enabling */ val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit); stm32_usart_set_bits(port, ofs->cr1, val); return 0; - -err: - free_irq(port->irq, port); - - return ret; } static void stm32_usart_shutdown(struct uart_port *port) @@ -1661,14 +1671,16 @@ static struct uart_driver stm32_usart_driver = { .cons = STM32_SERIAL_CONSOLE, }; -static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, - bool enable) +static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, + bool enable) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct tty_port *tport = &port->state->port; + int ret; - if (!stm32_port->wakeup_src) - return; + if (!stm32_port->wakeup_src || !tty_port_initialized(tport)) + return 0; /* * Enable low-power wake-up and wake-up irq if argument is set to @@ -1677,20 +1689,45 @@ static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, if (enable) { stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM); stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE); + + /* + * When DMA is used for reception, it must be disabled before + * entering low-power mode and re-enabled when exiting from + * low-power mode. + */ + if (stm32_port->rx_ch) { + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + dmaengine_terminate_sync(stm32_port->rx_ch); + } + + /* Poll data from RX FIFO if any */ + stm32_usart_receive_chars(port, false); } else { + if (stm32_port->rx_ch) { + ret = stm32_usart_start_rx_dma_cyclic(port); + if (ret) + return ret; + } + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM); stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); } + + return 0; } static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + int ret; uart_suspend_port(&stm32_usart_driver, port); - if (device_may_wakeup(dev) || device_wakeup_path(dev)) - stm32_usart_serial_en_wakeup(port, true); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + ret = stm32_usart_serial_en_wakeup(port, true); + if (ret) + return ret; + } /* * When "no_console_suspend" is enabled, keep the pinctrl default state @@ -1711,11 +1748,15 @@ static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) static int __maybe_unused stm32_usart_serial_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + int ret; pinctrl_pm_select_default_state(dev); - if (device_may_wakeup(dev) || device_wakeup_path(dev)) - stm32_usart_serial_en_wakeup(port, false); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + ret = stm32_usart_serial_en_wakeup(port, false); + if (ret) + return ret; + } return uart_resume_port(&stm32_usart_driver, port); } From patchwork Mon Oct 25 13:42:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Erwan LE RAY X-Patchwork-Id: 12581883 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 66572C433F5 for ; Mon, 25 Oct 2021 13:44:26 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3585F60F46 for ; Mon, 25 Oct 2021 13:44:26 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 3585F60F46 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=foss.st.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=RctTHwtUOnldXadQdXoE0GM8ma6+CdN6ARdX0VhZnnE=; b=3hV1vAbNdF+BaQ bQGq0R2+u0mATGZ09MJB1fnecEgI5X5Fks4INSkQ0QpN2teXM0x56ntNHczr5Qg6SFax55hc0OLUV Alqk48YMwTBG7g87XzphRy3HNriiC3ehM8GhtcSBKbHe5AWvV4g5xZB34uP7mSpfh99opGQdc7I43 KPJfUFbwClXfgOOFOjRxGxBC8OS1AdhIi1IP6Qsq5JY620XOrvrMaxcPISZmIFN7nr4R7g9OajvqD l/IbNeCIsRAi4RFfTtwrnU8+CFfhap/vFq7/wcayXqCSo0mWyvYDP+R/yw4geyW2Kvqjd36NLprMr Otp6c5sSNhsqhiYFI0QQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mf0Fq-00GYtj-3f; Mon, 25 Oct 2021 13:43:10 +0000 Received: from mx07-00178001.pphosted.com ([185.132.182.106]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mf0FQ-00GYop-FQ for linux-arm-kernel@lists.infradead.org; Mon, 25 Oct 2021 13:42:47 +0000 Received: from pps.filterd (m0241204.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 19PCL7sI012711; Mon, 25 Oct 2021 15:42:37 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=selector1; bh=7U0Zv2sNxlzWwOzOAADIvrklLXlL08SzxW07I/R4P/U=; b=mE+dhylOoG1/Nr05EWhqsMDC7D7tU2EPVYfSnghyecSpqLd7n77crSmKeAUueENze8Kd zwBCZ5c2tfLjimJf4jaDPRmfZaOw6nPDcwu5u+CnhVUcIMCTm0L2CdvJJKV2bRMPO8h5 e2eCxCoc/WD7ldPiBSBf61X8v+w6MUGnFVbSwFgRAxZ/TmkDATmTYJ12wdltQtNhKYcC F7bQf4DebumINB/eL1uIHTa0fpJb3//DrCvqPJcvEVSBeJWZteahd1x8Es8Rg6lHF8g9 C2d4CG7/0Uog+HukLfbIyDSJLXnXOku39xD2C1Kw8t6jDPh/OCLwK5YJn6Ygg7uHxO4q rw== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 3bwqpsjafd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 25 Oct 2021 15:42:37 +0200 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 92F3E10002A; Mon, 25 Oct 2021 15:42:36 +0200 (CEST) Received: from Webmail-eu.st.com (sfhdag2node2.st.com [10.75.127.5]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 8A9CA2309DF; Mon, 25 Oct 2021 15:42:36 +0200 (CEST) Received: from localhost (10.75.127.46) by SFHDAG2NODE2.st.com (10.75.127.5) with Microsoft SMTP Server (TLS) id 15.0.1497.18; Mon, 25 Oct 2021 15:42:36 +0200 From: Erwan Le Ray To: Greg Kroah-Hartman , Jiri Slaby , Maxime Coquelin , Alexandre Torgue CC: , , , , Erwan Le Ray , Fabrice Gasnier , Valentin Caron , Amelie Delaunay Subject: [PATCH 3/3] serial: stm32: push DMA RX data before suspending Date: Mon, 25 Oct 2021 15:42:29 +0200 Message-ID: <20211025134229.8456-4-erwan.leray@foss.st.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211025134229.8456-1-erwan.leray@foss.st.com> References: <20211025134229.8456-1-erwan.leray@foss.st.com> MIME-Version: 1.0 X-Originating-IP: [10.75.127.46] X-ClientProxiedBy: SFHDAG2NODE2.st.com (10.75.127.5) To SFHDAG2NODE2.st.com (10.75.127.5) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.182.1,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.0.607.475 definitions=2021-10-25_05,2021-10-25_02,2020-04-07_01 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211025_064245_028703_4177875B X-CRM114-Status: GOOD ( 25.41 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Data may be stored in DMA RX buffer, when suspending. The data needs to be pushed to the upper layer. We can't rely on the timeout IRQ (RTOR) that can't be triggered into low power state. So safely clear DMA request (DMAR), force the DMA reception routines to push RX buffer content, before disabling RX DMA. This way, handover to pio mode is safe. Only call tty_flip_buffer_push() when there is RX data to handle. Move the locking outside of stm32_usart_receive_chars() to prevent a race condition, when disabling DMA request upon suspend / pm_runtime_suspend. Data may be received under IRQ and pushed before stm32_usart_receive_chars() has pushed older data from DMA rx_buf upon suspend. The sequence in suspend routine needs proper locking to avoid this. Signed-off-by: Fabrice Gasnier Signed-off-by: Erwan Le Ray diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 4b5b0748790c..3244e7f6818c 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -210,11 +210,12 @@ static unsigned long stm32_usart_get_char_pio(struct uart_port *port) return c; } -static void stm32_usart_receive_chars_pio(struct uart_port *port) +static unsigned int stm32_usart_receive_chars_pio(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long c; + unsigned int size = 0; u32 sr; char flag; @@ -239,6 +240,7 @@ static void stm32_usart_receive_chars_pio(struct uart_port *port) c = stm32_usart_get_char_pio(port); port->icount.rx++; + size++; if (sr & USART_SR_ERR_MASK) { if (sr & USART_SR_ORE) { port->icount.overrun++; @@ -271,6 +273,8 @@ static void stm32_usart_receive_chars_pio(struct uart_port *port) continue; uart_insert_char(port, sr, USART_SR_ORE, c, flag); } + + return size; } static void stm32_usart_push_buffer_dma(struct uart_port *port, unsigned int dma_size) @@ -300,50 +304,48 @@ static void stm32_usart_push_buffer_dma(struct uart_port *port, unsigned int dma stm32_port->last_res = RX_BUF_L; } -static void stm32_usart_receive_chars_dma(struct uart_port *port) +static unsigned int stm32_usart_receive_chars_dma(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - unsigned int dma_size; + unsigned int dma_size, size = 0; /* DMA buffer is configured in cyclic mode and handles the rollback of the buffer. */ if (stm32_port->rx_dma_state.residue > stm32_port->last_res) { /* Conditional first part: from last_res to end of DMA buffer */ dma_size = stm32_port->last_res; stm32_usart_push_buffer_dma(port, dma_size); + size = dma_size; } dma_size = stm32_port->last_res - stm32_port->rx_dma_state.residue; stm32_usart_push_buffer_dma(port, dma_size); + size += dma_size; + + return size; } -static void stm32_usart_receive_chars(struct uart_port *port, bool irqflag) +static unsigned int stm32_usart_receive_chars(struct uart_port *port, bool force_dma_flush) { - struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; enum dma_status rx_dma_status; - unsigned long flags; u32 sr; + unsigned int size = 0; - if (irqflag) - spin_lock_irqsave(&port->lock, flags); - else - spin_lock(&port->lock); - - if (stm32_usart_rx_dma_enabled(port)) { + if (stm32_usart_rx_dma_enabled(port) || force_dma_flush) { rx_dma_status = dmaengine_tx_status(stm32_port->rx_ch, stm32_port->rx_ch->cookie, &stm32_port->rx_dma_state); if (rx_dma_status == DMA_IN_PROGRESS) { /* Empty DMA buffer */ - stm32_usart_receive_chars_dma(port); + size = stm32_usart_receive_chars_dma(port); sr = readl_relaxed(port->membase + ofs->isr); if (sr & USART_SR_ERR_MASK) { /* Disable DMA request line */ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); /* Switch to PIO mode to handle the errors */ - stm32_usart_receive_chars_pio(port); + size += stm32_usart_receive_chars_pio(port); /* Switch back to DMA mode */ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); @@ -354,18 +356,13 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool irqflag) stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); /* Fall back to interrupt mode */ dev_dbg(port->dev, "DMA error, fallback to irq mode\n"); - stm32_usart_receive_chars_pio(port); + size = stm32_usart_receive_chars_pio(port); } } else { - stm32_usart_receive_chars_pio(port); + size = stm32_usart_receive_chars_pio(port); } - if (irqflag) - uart_unlock_and_check_sysrq_irqrestore(port, irqflag); - else - uart_unlock_and_check_sysrq(port); - - tty_flip_buffer_push(tport); + return size; } static void stm32_usart_tx_dma_complete(void *arg) @@ -403,8 +400,15 @@ static void stm32_usart_tx_interrupt_enable(struct uart_port *port) static void stm32_usart_rx_dma_complete(void *arg) { struct uart_port *port = arg; + struct tty_port *tport = &port->state->port; + unsigned int size; + unsigned long flags; - stm32_usart_receive_chars(port, true); + spin_lock_irqsave(&port->lock, flags); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); } static void stm32_usart_tx_interrupt_disable(struct uart_port *port) @@ -557,6 +561,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; u32 sr; + unsigned int size; sr = readl_relaxed(port->membase + ofs->isr); @@ -580,7 +585,11 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) if (!stm32_port->throttled) { if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_enabled(port)) || ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_enabled(port))) { - stm32_usart_receive_chars(port, false); + spin_lock(&port->lock); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq(port); + if (size) + tty_flip_buffer_push(tport); } } @@ -599,11 +608,19 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); + unsigned int size; + unsigned long flags; /* Receiver timeout irq for DMA RX */ - if (!stm32_port->throttled) - stm32_usart_receive_chars(port, false); + if (!stm32_port->throttled) { + spin_lock_irqsave(&port->lock, flags); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); + } return IRQ_HANDLED; } @@ -1678,6 +1695,8 @@ static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct tty_port *tport = &port->state->port; int ret; + unsigned int size; + unsigned long flags; if (!stm32_port->wakeup_src || !tty_port_initialized(tport)) return 0; @@ -1696,8 +1715,15 @@ static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, * low-power mode. */ if (stm32_port->rx_ch) { + spin_lock_irqsave(&port->lock, flags); + /* Avoid race with RX IRQ when DMAR is cleared */ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); - dmaengine_terminate_sync(stm32_port->rx_ch); + /* Poll data from DMA RX buffer if any */ + size = stm32_usart_receive_chars(port, true); + dmaengine_terminate_async(stm32_port->rx_ch); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); } /* Poll data from RX FIFO if any */