From patchwork Thu Jul 7 09:35:51 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lucas Stach X-Patchwork-Id: 9218681 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 EA8B86048B for ; Thu, 7 Jul 2016 09:36:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DD90C287F0 for ; Thu, 7 Jul 2016 09:36:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D178A287F2; Thu, 7 Jul 2016 09:36:04 +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.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham 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 1DA8F287F0 for ; Thu, 7 Jul 2016 09:36:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933039AbcGGJgA (ORCPT ); Thu, 7 Jul 2016 05:36:00 -0400 Received: from metis.ext.4.pengutronix.de ([92.198.50.35]:46611 "EHLO metis.ext.4.pengutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933032AbcGGJf4 (ORCPT ); Thu, 7 Jul 2016 05:35:56 -0400 Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7] helo=dude.pengutronix.de.) by metis.ext.pengutronix.de with esmtp (Exim 4.80) (envelope-from ) id 1bL5is-0006I1-MO; Thu, 07 Jul 2016 11:35:54 +0200 From: Lucas Stach To: Vinod Koul Cc: dmaengine@vger.kernel.org, kernel@pengutronix.de, patchwork-lst@pengutronix.de Subject: [PATCH] dmaengine: imx-sdma: ack channel 0 IRQ in the interrupt handler Date: Thu, 7 Jul 2016 11:35:51 +0200 Message-Id: <1467884151-26667-1-git-send-email-l.stach@pengutronix.de> X-Mailer: git-send-email 2.8.1 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7 X-SA-Exim-Mail-From: l.stach@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: dmaengine@vger.kernel.org Sender: dmaengine-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: dmaengine@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Michael Olbrich Currently the handler ignores the channel 0 interrupt and thus doesn't ack it properly. This is done in order to allow sdma_run_channel0() to poll on the irq status bit, as this function may be called in atomic context, but needs to know when the channel has finished. This works mostly, as the polling happens under a spinlock, disabling IRQs on the local CPU, leaving only a very slight race window for a spurious IRQ to happen if the handler is executed on another CPU in an SMP system. Still this is clearly suboptimal. This behavior turns into a real problem on an RT system, where the spinlock doesn't disable IRQs on the local CPU. Not acking the IRQ in the handler in such a setup is very likely to drown the CPU in an IRQ storm, leaving it unable to make any progress in the polling loop, leading to the IRQ never being acked. Fix this by properly acknowledging the channel 0 IRQ in the handler. As the IRQ status bit can no longer be used to poll for the channel completion, switch over to using the SDMA_H_STATSTOP register for this purpose, where bit 0 is cleared by the hardware when the channel is done. Signed-off-by: Michael Olbrich Signed-off-by: Lucas Stach --- v2 lst: - use iopoll helper - rephrase commit message --- drivers/dma/imx-sdma.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 0f6fd42f55ca..ce865f68a8c7 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -571,28 +572,20 @@ static void sdma_enable_channel(struct sdma_engine *sdma, int channel) static int sdma_run_channel0(struct sdma_engine *sdma) { int ret; - unsigned long timeout = 500; + u32 reg; sdma_enable_channel(sdma, 0); - while (!(ret = readl_relaxed(sdma->regs + SDMA_H_INTR) & 1)) { - if (timeout-- <= 0) - break; - udelay(1); - } - - if (ret) { - /* Clear the interrupt status */ - writel_relaxed(ret, sdma->regs + SDMA_H_INTR); - } else { + ret = readl_relaxed_poll_timeout_atomic(sdma->regs + SDMA_H_STATSTOP, + reg, !(reg & 1), 1, 500); + if (ret) dev_err(sdma->dev, "Timeout waiting for CH0 ready\n"); - } /* Set bits of CONFIG register with dynamic context switching */ if (readl(sdma->regs + SDMA_H_CONFIG) == 0) writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG); - return ret ? 0 : -ETIMEDOUT; + return ret; } static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, @@ -727,9 +720,9 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id) unsigned long stat; stat = readl_relaxed(sdma->regs + SDMA_H_INTR); - /* not interested in channel 0 interrupts */ - stat &= ~1; writel_relaxed(stat, sdma->regs + SDMA_H_INTR); + /* channel 0 is special and not handled here, see run_channel0() */ + stat &= ~1; while (stat) { int channel = fls(stat) - 1;