mmc: msm_sdcc: always check sdcc state first
Currently bam is reset without checking the current state of sdcc clocks.
If clocks are not on when bam reset is attempted then this would lead to
a system crash due to unclocked register access.
In order to fix this, always check the state of the sdcc hardware before
starting any request. This way even if a new request comes in without the
clocks being on, it would not go through.
CRs-Fixed: 453099
Change-Id: I872aa60d615617bd448b977cdf06ffcf900e111e
Signed-off-by: Krishna Konda <kkonda@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index a8e5c97..9d18b8b 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -2198,6 +2198,7 @@
{
struct msmsdcc_host *host = mmc_priv(mmc);
unsigned long flags;
+ unsigned int error = 0;
int retries = 5;
/*
@@ -2207,6 +2208,18 @@
if (host->plat->is_sdio_al_client)
msmsdcc_sdio_al_lpm(mmc, false);
+ /*
+ * Don't start the request if SDCC is not in proper state to handle it
+ * BAM state is checked below if applicable
+ */
+ if (!host->pwr || !atomic_read(&host->clks_on) ||
+ host->sdcc_irq_disabled) {
+ WARN(1, "%s: %s: SDCC is in bad state. don't process new request (CMD%d)\n",
+ mmc_hostname(host->mmc), __func__, mrq->cmd->opcode);
+ error = EIO;
+ goto bad_state;
+ }
+
/* check if sps bam needs to be reset */
if (is_sps_mode(host) && host->sps.reset_bam) {
while (retries) {
@@ -2215,6 +2228,14 @@
pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
mmc_hostname(host->mmc), --retries);
}
+
+ /* check if BAM reset succeeded or not */
+ if (host->sps.reset_bam) {
+ pr_err("%s: bam reset failed. Not processing the new request (CMD%d)\n",
+ mmc_hostname(host->mmc), mrq->cmd->opcode);
+ error = EAGAIN;
+ goto bad_state;
+ }
}
/*
@@ -2233,33 +2254,9 @@
MMC_SEND_TUNING_BLOCK_HS200);
}
- spin_lock_irqsave(&host->lock, flags);
-
if (host->eject) {
- mrq->cmd->error = -ENOMEDIUM;
- spin_unlock_irqrestore(&host->lock, flags);
- mmc_request_done(mmc, mrq);
- return;
- }
-
- /*
- * Don't start the request if SDCC is not in proper state to handle it
- */
- if (!host->pwr || !atomic_read(&host->clks_on) ||
- host->sdcc_irq_disabled ||
- host->sps.reset_bam) {
- WARN(1, "%s: %s: SDCC is in bad state. don't process"
- " new request (CMD%d)\n", mmc_hostname(host->mmc),
- __func__, mrq->cmd->opcode);
- msmsdcc_dump_sdcc_state(host);
- mrq->cmd->error = -EIO;
- if (mrq->data) {
- mrq->data->error = -EIO;
- mrq->data->bytes_xfered = 0;
- }
- spin_unlock_irqrestore(&host->lock, flags);
- mmc_request_done(mmc, mrq);
- return;
+ error = ENOMEDIUM;
+ goto card_ejected;
}
WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
@@ -2267,6 +2264,8 @@
mmc_hostname(host->mmc), __func__,
mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
+ spin_lock_irqsave(&host->lock, flags);
+
/*
* Set timeout value to 10 secs (or more in case of buggy cards)
*/
@@ -2305,8 +2304,18 @@
}
msmsdcc_request_start(host, mrq);
-
spin_unlock_irqrestore(&host->lock, flags);
+ return;
+
+bad_state:
+ msmsdcc_dump_sdcc_state(host);
+card_ejected:
+ mrq->cmd->error = -error;
+ if (mrq->data) {
+ mrq->data->error = -error;
+ mrq->data->bytes_xfered = 0;
+ }
+ mmc_request_done(mmc, mrq);
}
static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,