From patchwork Thu Dec 6 15:18:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Brunet X-Patchwork-Id: 10716157 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 11F1218B8 for ; Thu, 6 Dec 2018 15:19:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 017B128A25 for ; Thu, 6 Dec 2018 15:19:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E97292E09E; Thu, 6 Dec 2018 15:19:03 +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=-7.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI 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 75AA728A25 for ; Thu, 6 Dec 2018 15:19:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726070AbeLFPSl (ORCPT ); Thu, 6 Dec 2018 10:18:41 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:39834 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725871AbeLFPSk (ORCPT ); Thu, 6 Dec 2018 10:18:40 -0500 Received: by mail-wr1-f66.google.com with SMTP id t27so857894wra.6 for ; Thu, 06 Dec 2018 07:18:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=IQ1pNjxAYQJEy/wzhy8LaXlzyI+EffZDKMSvsOZcQ9o=; b=acMyHwrt8WgUGbImx9XBPcsSw2WvrcbkjNowHm4RCMrQJ7XXJZ9LcOpXwNKXzOoXB+ QsQd2L97Ag48Goc5hiLqAq4RoklHafsgH26vd19mbEdTDx/sD1J5yb2UXZzhjl79pNQU Vawqbb1mvm6KUoh+nFgzlbgppYUIW7Bo0pOqNtyZSBBI1p9VmAzEkgOn6f9NdYDO3DWb VR5PqVvPcgZUVbTT1nVfSBolvwRzQm2UYbpfmCVtog01V4Hxc2WJL5ROpb3oKmM5ju1u 8iZse5p76cdHWXAMkM0VV0VPqL1UYWk819PXPt7XxQZ31VTHoHLM/UF05srG9VNBmuLC dE1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=IQ1pNjxAYQJEy/wzhy8LaXlzyI+EffZDKMSvsOZcQ9o=; b=SDf9pBZ+1c0F/meYXOIQLEz+DYRFIbt//lI1mBEXD8zfbNb4MTglVGwtvzQOkDLXxd 1WL7EP7fI2EGv6aFxtWodPvfNrd5okju9RyTpF6IvyhhZtFZjpNwlWzBWTiaDs7XmF2+ O2AI71Y/HVxNA0rKGe163WArzwV+Fa8fQO2Jq8tQYeJCGRmKp/2HcIHPMf9oGu+goBqt L+NQcCFjhvt+A2+/S6YeChT2RvzJoNs8o/WVdxmBIaWE+6LdfIkkjOTt67cojMs2vGIr 7fzXL9h0woKkYN/dhcM3q1TFe2Ud9iHF+MLUXxNLQZV72IbYWOqt4EAs9ZhHt3YaaJYy uYdg== X-Gm-Message-State: AA+aEWaP5mUc7w6MedUyQpev/aEK3hfRIQ0tbXczLEIl5PSfnLEtGeer XIQxfjrPS+tP8U4Zi99yTA5Z6Q== X-Google-Smtp-Source: AFSGD/U8nu1DsCPYsh2NpH8OPun8NLHb8LoJrqrEDBbNcqDltn6ibXdObfZSfShbSLcVoun+L/F78w== X-Received: by 2002:adf:ce86:: with SMTP id r6mr27113095wrn.257.1544109517755; Thu, 06 Dec 2018 07:18:37 -0800 (PST) Received: from boomer.local ([2a01:e34:eeb6:4690:106b:bae3:31ed:7561]) by smtp.googlemail.com with ESMTPSA id j33sm939652wre.91.2018.12.06.07.18.36 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 06 Dec 2018 07:18:37 -0800 (PST) From: Jerome Brunet To: Ulf Hansson , Carlo Caione , Kevin Hilman Cc: Jerome Brunet , linux-mmc@vger.kernel.org, linux-amlogic@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/4] mmc: meson-gx: make sure the descriptor is stopped on errors Date: Thu, 6 Dec 2018 16:18:25 +0100 Message-Id: <20181206151828.24417-2-jbrunet@baylibre.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181206151828.24417-1-jbrunet@baylibre.com> References: <20181206151828.24417-1-jbrunet@baylibre.com> MIME-Version: 1.0 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP On errors, if we don't stop the descriptor chain, it may continue to run and raise IRQ after we have called mmc_request_done(). This is bad because we won't be able to get cmd anymore and properly deal with the IRQ. This patch makes sure the descriptor chain is stopped before calling mmc_request_done() Fixes: 79ed05e329c3 ("mmc: meson-gx: add support for descriptor chain mode") Signed-off-by: Jerome Brunet --- drivers/mmc/host/meson-gx-mmc.c | 73 ++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index c201c378537e..fcb5d693c897 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -90,9 +91,11 @@ #define CFG_CLK_ALWAYS_ON BIT(18) #define CFG_CHK_DS BIT(20) #define CFG_AUTO_CLK BIT(23) +#define CFG_ERR_ABORT BIT(27) #define SD_EMMC_STATUS 0x48 #define STATUS_BUSY BIT(31) +#define STATUS_DESC_BUSY BIT(30) #define STATUS_DATI GENMASK(23, 16) #define SD_EMMC_IRQ_EN 0x4c @@ -928,6 +931,7 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd) cmd_cfg |= FIELD_PREP(CMD_CFG_CMD_INDEX_MASK, cmd->opcode); cmd_cfg |= CMD_CFG_OWNER; /* owned by CPU */ + cmd_cfg |= CMD_CFG_ERROR; /* stop in case of error */ meson_mmc_set_response_bits(cmd, &cmd_cfg); @@ -1022,6 +1026,17 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) u32 irq_en, status, raw_status; irqreturn_t ret = IRQ_NONE; + irq_en = readl(host->regs + SD_EMMC_IRQ_EN); + raw_status = readl(host->regs + SD_EMMC_STATUS); + status = raw_status & irq_en; + + if (!status) { + dev_dbg(host->dev, + "Unexpected IRQ! irq_en 0x%08x - status 0x%08x\n", + irq_en, raw_status); + return IRQ_NONE; + } + if (WARN_ON(!host) || WARN_ON(!host->cmd)) return IRQ_NONE; @@ -1029,22 +1044,18 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) cmd = host->cmd; data = cmd->data; - irq_en = readl(host->regs + SD_EMMC_IRQ_EN); - raw_status = readl(host->regs + SD_EMMC_STATUS); - status = raw_status & irq_en; - cmd->error = 0; if (status & IRQ_CRC_ERR) { dev_dbg(host->dev, "CRC Error - status 0x%08x\n", status); cmd->error = -EILSEQ; - ret = IRQ_HANDLED; + ret = IRQ_WAKE_THREAD; goto out; } if (status & IRQ_TIMEOUTS) { dev_dbg(host->dev, "Timeout - status 0x%08x\n", status); cmd->error = -ETIMEDOUT; - ret = IRQ_HANDLED; + ret = IRQ_WAKE_THREAD; goto out; } @@ -1069,17 +1080,49 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) /* ack all enabled interrupts */ writel(irq_en, host->regs + SD_EMMC_STATUS); + if (cmd->error) { + /* Stop desc in case of errors */ + u32 start = readl(host->regs + SD_EMMC_START); + + start &= ~START_DESC_BUSY; + writel(start, host->regs + SD_EMMC_START); + } + if (ret == IRQ_HANDLED) meson_mmc_request_done(host->mmc, cmd->mrq); - else if (ret == IRQ_NONE) - dev_warn(host->dev, - "Unexpected IRQ! status=0x%08x, irq_en=0x%08x\n", - raw_status, irq_en); spin_unlock(&host->lock); return ret; } +static int meson_mmc_wait_desc_stop(struct meson_host *host) +{ + int loop; + u32 status; + + /* + * It may sometimes take a while for it to actually halt. Here, we + * are giving it 5ms to comply + * + * If we don't confirm the descriptor is stopped, it might raise new + * IRQs after we have called mmc_request_done() which is bad. + */ + for (loop = 50; loop; loop--) { + status = readl(host->regs + SD_EMMC_STATUS); + if (status & (STATUS_BUSY | STATUS_DESC_BUSY)) + udelay(100); + else + break; + } + + if (status & (STATUS_BUSY | STATUS_DESC_BUSY)) { + dev_err(host->dev, "Timed out waiting for host to stop\n"); + return -ETIMEDOUT; + } + + return 0; +} + static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id) { struct meson_host *host = dev_id; @@ -1090,6 +1133,13 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id) if (WARN_ON(!cmd)) return IRQ_NONE; + if (cmd->error) { + meson_mmc_wait_desc_stop(host); + meson_mmc_request_done(host->mmc, cmd->mrq); + + return IRQ_HANDLED; + } + data = cmd->data; if (meson_mmc_bounce_buf_read(data)) { xfer_bytes = data->blksz * data->blocks; @@ -1130,6 +1180,9 @@ static void meson_mmc_cfg_init(struct meson_host *host) cfg |= FIELD_PREP(CFG_RC_CC_MASK, ilog2(SD_EMMC_CFG_CMD_GAP)); cfg |= FIELD_PREP(CFG_BLK_LEN_MASK, ilog2(SD_EMMC_CFG_BLK_SIZE)); + /* abort chain on R/W errors */ + cfg |= CFG_ERR_ABORT; + writel(cfg, host->regs + SD_EMMC_CFG); }