From 6d15d790dcc42b666cd33f99711f9bae55be9142 Mon Sep 17 00:00:00 2001 From: Vijay Viswanath Date: Wed, 2 Nov 2016 16:17:30 +0530 Subject: [PATCH] MMC : host: clear interrupt after halt in case of error During error scenario, if interrupt status of CQ controller is cleared before halting the controller, the CQ controller can send commands to card in the time delay between clearing of interrupt and halting. The response of card to these commands can overwrite the error information stored in Response Arg register. So, if an error is detected, the CQ must be halted first and then the interrupt must be cleared. Change-Id: Ief7039226b01b50fc71cf17a4eb625afd8c9bd06 Signed-off-by: Vijay Viswanath --- drivers/mmc/host/cmdq_hci.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 52427815722b..d69a25002c3c 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -781,7 +781,6 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) u32 dbr_set = 0; status = cmdq_readl(cq_host, CQIS); - cmdq_writel(cq_host, status, CQIS); if (!status && !err) return IRQ_NONE; @@ -802,6 +801,17 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) if (ret) pr_err("%s: %s: halt failed ret=%d\n", mmc_hostname(mmc), __func__, ret); + + /* + * Clear the CQIS after halting incase of error. This is done + * because if CQIS is cleared before halting, the CQ will + * continue with issueing commands for rest of requests with + * Doorbell rung. This will overwrite the Resp Arg register. + * So CQ must be halted first and then CQIS cleared incase + * of error + */ + cmdq_writel(cq_host, status, CQIS); + cmdq_dumpregs(cq_host); if (!err_info) { @@ -890,13 +900,16 @@ skip_cqterri: mrq->cmdq_req->resp_err = true; pr_err("%s: Response error (0x%08x) from card !!!", - mmc_hostname(mmc), status); + mmc_hostname(mmc), cmdq_readl(cq_host, CQCRA)); + } else { mrq->cmdq_req->resp_idx = cmdq_readl(cq_host, CQCRI); mrq->cmdq_req->resp_arg = cmdq_readl(cq_host, CQCRA); } cmdq_finish_data(mmc, tag); + } else { + cmdq_writel(cq_host, status, CQIS); } if (status & CQIS_TCC) {