From: Sasha Levin <sashal@kernel•org>
To: linux-kernel@vger•kernel.org, stable@vger•kernel.org
Cc: Sasha Levin <sashal@kernel•org>,
Ulf Hansson <ulf.hansson@linaro•org>,
linux-mmc@vger•kernel.org, linux-amlogic@lists•infradead.org,
linux-arm-kernel@lists•infradead.org,
Jerome Brunet <jbrunet@baylibre•com>
Subject: [PATCH AUTOSEL 4.19 068/219] mmc: meson-gx: make sure the descriptor is stopped on errors
Date: Fri, 22 Nov 2019 00:46:40 -0500 [thread overview]
Message-ID: <20191122054911.1750-61-sashal@kernel.org> (raw)
In-Reply-To: <20191122054911.1750-1-sashal@kernel.org>
From: Jerome Brunet <jbrunet@baylibre•com>
[ Upstream commit 18f92bc02f1739b5c4d5b70009fbb7eada45bca3 ]
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 <jbrunet@baylibre•com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro•org>
Signed-off-by: Sasha Levin <sashal@kernel•org>
---
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 ddd98cdd33bcd..72f34a58928ca 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <linux/device.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@@ -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
@@ -930,6 +933,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);
@@ -1024,6 +1028,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;
@@ -1031,22 +1046,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;
}
@@ -1071,17 +1082,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;
@@ -1092,6 +1135,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;
@@ -1132,6 +1182,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);
}
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists•infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2019-11-22 5:57 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-11-22 5:45 [PATCH AUTOSEL 4.19 008/219] ARM: dts: imx51: Fix memory node duplication Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 009/219] ARM: dts: imx53: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 010/219] ARM: dts: imx31: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 011/219] ARM: dts: imx35: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 012/219] ARM: dts: imx7: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 013/219] ARM: dts: imx6ul: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 014/219] ARM: dts: imx6sx: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 015/219] ARM: dts: imx6sl: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 016/219] ARM: dts: imx50: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 017/219] ARM: dts: imx23: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 018/219] ARM: dts: imx1: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 019/219] ARM: dts: imx27: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 020/219] ARM: dts: imx25: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 021/219] ARM: dts: imx53-voipac-dmm-668: " Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 025/219] arm64: mm: Prevent mismatched 52-bit VA support Sasha Levin
2019-11-22 5:45 ` [PATCH AUTOSEL 4.19 026/219] arm64: smp: Handle errors reported by the firmware Sasha Levin
2019-11-22 5:46 ` [PATCH AUTOSEL 4.19 029/219] ARM: OMAP1: fix USB configuration for device-only setups Sasha Levin
2019-11-22 5:46 ` [PATCH AUTOSEL 4.19 031/219] arm64: preempt: Fix big-endian when checking preempt count in assembly Sasha Levin
2019-12-14 2:14 ` Steven Rostedt
2019-12-16 9:45 ` Will Deacon
2019-12-18 15:38 ` Steven Rostedt
2019-12-18 20:11 ` Greg Kroah-Hartman
2019-12-18 15:40 ` Steven Rostedt
2019-12-18 16:03 ` Will Deacon
2019-11-22 5:46 ` [PATCH AUTOSEL 4.19 035/219] ARM: ks8695: fix section mismatch warning Sasha Levin
2019-11-22 5:46 ` Sasha Levin [this message]
2019-11-22 5:46 ` [PATCH AUTOSEL 4.19 069/219] mtd: rawnand: sunxi: Write pageprog related opcodes to WCMD_SET Sasha Levin
2019-11-22 5:47 ` [PATCH AUTOSEL 4.19 136/219] MIPS: BCM63XX: fix switch core reset on BCM6368 Sasha Levin
2019-11-22 5:47 ` [PATCH AUTOSEL 4.19 137/219] pwm: clps711x: Fix period calculation Sasha Levin
2019-11-22 5:47 ` [PATCH AUTOSEL 4.19 146/219] net: stmicro: fix a missing check of clk_prepare Sasha Levin
2019-11-22 5:48 ` [PATCH AUTOSEL 4.19 162/219] firmware: arm_sdei: fix wrong of_node_put() in init function Sasha Levin
2019-11-22 5:48 ` [PATCH AUTOSEL 4.19 163/219] firmware: arm_sdei: Fix DT platform device creation Sasha Levin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191122054911.1750-61-sashal@kernel.org \
--to=sashal@kernel$(echo .)org \
--cc=jbrunet@baylibre$(echo .)com \
--cc=linux-amlogic@lists$(echo .)infradead.org \
--cc=linux-arm-kernel@lists$(echo .)infradead.org \
--cc=linux-kernel@vger$(echo .)kernel.org \
--cc=linux-mmc@vger$(echo .)kernel.org \
--cc=stable@vger$(echo .)kernel.org \
--cc=ulf.hansson@linaro$(echo .)org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox