mmc: msm_sdcc: Add error handling while setting up clocks
The error checking is not performed when the clocks are enabled.
Add proper error checks while doing this.
The clock APIs dont return any error conditions while disabling
clocks. So no error checking is required when the clocks are disabled.
CRs-Fixed: 364226
Change-Id: I685ca70f9fbcbde327432e0263c3330a5fc9aa43
Signed-off-by: Pratibhasagar V <pratibha@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 4534cd8..c87afab 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1682,7 +1682,7 @@
msmsdcc_delay(host);
}
- if (!host->clks_on) {
+ if (!atomic_read(&host->clks_on)) {
pr_debug("%s: %s: SDIO async irq received\n",
mmc_hostname(host->mmc), __func__);
@@ -1992,7 +1992,8 @@
/*
* Don't start the request if SDCC is not in proper state to handle it
*/
- if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
+ 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);
@@ -2337,17 +2338,37 @@
* Any function calling msmsdcc_setup_clocks must
* acquire clk_mutex. May sleep.
*/
-static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
+static int msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
{
- if (enable) {
- if (!IS_ERR_OR_NULL(host->bus_clk))
- clk_prepare_enable(host->bus_clk);
- if (!IS_ERR(host->pclk))
- clk_prepare_enable(host->pclk);
- clk_prepare_enable(host->clk);
+ int rc = 0;
+
+ if (enable && !atomic_read(&host->clks_on)) {
+ if (!IS_ERR_OR_NULL(host->bus_clk)) {
+ rc = clk_prepare_enable(host->bus_clk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto out;
+ }
+ }
+ if (!IS_ERR(host->pclk)) {
+ rc = clk_prepare_enable(host->pclk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the pclk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto disable_bus;
+ }
+ }
+ rc = clk_prepare_enable(host->clk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the host-clk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto disable_pclk;
+ }
mb();
msmsdcc_delay(host);
- } else {
+ atomic_set(&host->clks_on, 1);
+ } else if (!enable && atomic_read(&host->clks_on)) {
mb();
msmsdcc_delay(host);
clk_disable_unprepare(host->clk);
@@ -2355,7 +2376,18 @@
clk_disable_unprepare(host->pclk);
if (!IS_ERR_OR_NULL(host->bus_clk))
clk_disable_unprepare(host->bus_clk);
+ atomic_set(&host->clks_on, 0);
}
+ goto out;
+
+disable_pclk:
+ if (!IS_ERR_OR_NULL(host->pclk))
+ clk_disable_unprepare(host->pclk);
+disable_bus:
+ if (!IS_ERR_OR_NULL(host->bus_clk))
+ clk_disable_unprepare(host->bus_clk);
+out:
+ return rc;
}
static inline unsigned int msmsdcc_get_sup_clk_rate(struct msmsdcc_host *host,
@@ -2888,18 +2920,16 @@
spin_lock_irqsave(&host->lock, flags);
if (ios->clock) {
- if (!host->clks_on) {
- spin_unlock_irqrestore(&host->lock, flags);
- msmsdcc_setup_clocks(host, true);
- spin_lock_irqsave(&host->lock, flags);
- host->clks_on = 1;
- writel_relaxed(host->mci_irqenable,
- host->base + MMCIMASK0);
- mb();
- msmsdcc_cfg_sdio_wakeup(host, false);
- }
-
+ spin_unlock_irqrestore(&host->lock, flags);
+ rc = msmsdcc_setup_clocks(host, true);
+ if (rc)
+ goto out;
+ spin_lock_irqsave(&host->lock, flags);
+ writel_relaxed(host->mci_irqenable, host->base + MMCIMASK0);
+ mb();
+ msmsdcc_cfg_sdio_wakeup(host, false);
clock = msmsdcc_get_sup_clk_rate(host, ios->clock);
+
/*
* For DDR50 mode, controller needs clock rate to be
* double than what is required on the SD card CLK pin.
@@ -2942,7 +2972,6 @@
msmsdcc_delay(host);
clk |= MCI_CLK_ENABLE;
}
-
if (ios->bus_width == MMC_BUS_WIDTH_8)
clk |= MCI_CLK_WIDEBUS_8;
else if (ios->bus_width == MMC_BUS_WIDTH_4)
@@ -2981,7 +3010,7 @@
clk |= IO_PAD_PWR_SWITCH;
/* Don't write into registers if clocks are disabled */
- if (host->clks_on) {
+ if (atomic_read(&host->clks_on)) {
if (readl_relaxed(host->base + MMCICLOCK) != clk) {
writel_relaxed(clk, host->base + MMCICLOCK);
msmsdcc_sync_reg_wr(host);
@@ -2993,7 +3022,7 @@
}
}
- if (!(clk & MCI_CLK_ENABLE) && host->clks_on) {
+ if (!(clk & MCI_CLK_ENABLE) && atomic_read(&host->clks_on)) {
msmsdcc_cfg_sdio_wakeup(host, true);
spin_unlock_irqrestore(&host->lock, flags);
/*
@@ -3002,11 +3031,10 @@
*/
msmsdcc_setup_clocks(host, false);
spin_lock_irqsave(&host->lock, flags);
- host->clks_on = 0;
}
if (host->tuning_in_progress)
- WARN(!host->clks_on,
+ WARN(!atomic_read(&host->clks_on),
"tuning_in_progress but SDCC clocks are OFF\n");
/* Let interrupts be disabled if the host is powered off */
@@ -3014,8 +3042,8 @@
enable_irq(host->core_irqres->start);
host->sdcc_irq_disabled = 0;
}
-
spin_unlock_irqrestore(&host->lock, flags);
+out:
mutex_unlock(&host->clk_mutex);
}
@@ -3088,14 +3116,14 @@
spin_lock_irqsave(&host->lock, flags);
if (enable) {
host->mci_irqenable |= MCI_SDIOINTOPERMASK;
- if (host->clks_on) {
+ if (atomic_read(&host->clks_on)) {
writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
mb();
}
} else {
host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
- if (host->clks_on) {
+ if (atomic_read(&host->clks_on)) {
writel_relaxed(readl_relaxed(host->base + MMCIMASK0) &
~MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
mb();
@@ -3217,20 +3245,14 @@
}
mutex_lock(&host->clk_mutex);
- spin_lock_irqsave(&host->lock, flags);
- if (!host->clks_on) {
- spin_unlock_irqrestore(&host->lock, flags);
- msmsdcc_setup_clocks(host, true);
- spin_lock_irqsave(&host->lock, flags);
- host->clks_on = 1;
- }
- spin_unlock_irqrestore(&host->lock, flags);
+ rc = msmsdcc_setup_clocks(host, true);
mutex_unlock(&host->clk_mutex);
out:
if (rc < 0) {
pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
__func__, rc);
+ msmsdcc_pm_qos_update_latency(host, 0);
return rc;
}
msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
@@ -3241,6 +3263,7 @@
{
struct msmsdcc_host *host = mmc_priv(mmc);
unsigned long flags;
+ int rc = 0;
msmsdcc_pm_qos_update_latency(host, 0);
@@ -3248,19 +3271,16 @@
goto out;
mutex_lock(&host->clk_mutex);
- spin_lock_irqsave(&host->lock, flags);
- if (host->clks_on) {
- spin_unlock_irqrestore(&host->lock, flags);
- msmsdcc_setup_clocks(host, false);
- spin_lock_irqsave(&host->lock, flags);
- host->clks_on = 0;
- }
- spin_unlock_irqrestore(&host->lock, flags);
+ rc = msmsdcc_setup_clocks(host, false);
mutex_unlock(&host->clk_mutex);
+ if (rc) {
+ msmsdcc_pm_qos_update_latency(host, 1);
+ return rc;
+ }
out:
msmsdcc_msm_bus_queue_work(host);
- return 0;
+ return rc;
}
#endif
@@ -3717,7 +3737,7 @@
spin_lock_irqsave(&host->lock, flags);
WARN(!host->pwr, "SDCC power is turned off\n");
- WARN(!host->clks_on, "SDCC clocks are turned off\n");
+ WARN(!atomic_read(&host->clks_on), "SDCC clocks are turned off\n");
WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
host->tuning_in_progress = 1;
@@ -4462,13 +4482,14 @@
pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
(host->pwr ? "ON" : "OFF"));
pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
- mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
+ mmc_hostname(host->mmc),
+ (atomic_read(&host->clks_on) ? "ON" : "OFF"),
(u32)clk_get_rate(host->clk));
pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
(host->sdcc_irq_disabled ? "disabled" : "enabled"));
/* Now dump SDCC registers. Don't print FIFO registers */
- if (host->clks_on)
+ if (atomic_read(&host->clks_on))
msmsdcc_print_regs("SDCC-CORE", host->base,
host->core_memres->start, 28);
@@ -4480,7 +4501,7 @@
mmc_hostname(host->mmc), host->dma.busy,
host->dma.channel, host->dma.crci);
else if (host->is_sps_mode) {
- if (host->sps.busy && host->clks_on)
+ if (host->sps.busy && atomic_read(&host->clks_on))
msmsdcc_print_regs("SDCC-DML", host->dml_base,
host->dml_memres->start,
16);
@@ -4891,7 +4912,7 @@
(1 + ((3 * USEC_PER_SEC) /
msmsdcc_get_min_sup_clk_rate(host)));
- host->clks_on = 1;
+ atomic_set(&host->clks_on, 1);
/* Apply Hard reset to SDCC to put it in power on default state */
msmsdcc_hard_reset(host);
@@ -5329,6 +5350,7 @@
{
struct msmsdcc_host *host = mmc_priv(mmc);
unsigned long flags;
+ int rc = 0;
mutex_lock(&host->clk_mutex);
spin_lock_irqsave(&host->lock, flags);
@@ -5341,13 +5363,9 @@
disable_irq_nosync(host->core_irqres->start);
host->sdcc_irq_disabled = 1;
}
-
- if (host->clks_on) {
- spin_unlock_irqrestore(&host->lock, flags);
- msmsdcc_setup_clocks(host, false);
- spin_lock_irqsave(&host->lock, flags);
- host->clks_on = 0;
- }
+ rc = msmsdcc_setup_clocks(host, false);
+ if (rc)
+ goto out;
if (host->plat->sdio_lpm_gpio_setup &&
!host->sdio_gpio_lpm) {
@@ -5363,6 +5381,10 @@
host->sdio_wakeupirq_disabled = 0;
}
} else {
+ rc = msmsdcc_setup_clocks(host, true);
+ if (rc)
+ goto out;
+
if (!host->sdio_wakeupirq_disabled) {
disable_irq_nosync(host->plat->sdiowakeup_irq);
host->sdio_wakeupirq_disabled = 1;
@@ -5377,14 +5399,7 @@
host->sdio_gpio_lpm = 0;
}
- if (!host->clks_on) {
- spin_unlock_irqrestore(&host->lock, flags);
- msmsdcc_setup_clocks(host, true);
- spin_lock_irqsave(&host->lock, flags);
- host->clks_on = 1;
- }
-
- if (host->sdcc_irq_disabled) {
+ if (host->sdcc_irq_disabled && atomic_read(&host->clks_on)) {
writel_relaxed(host->mci_irqenable,
host->base + MMCIMASK0);
mb();
@@ -5392,9 +5407,10 @@
host->sdcc_irq_disabled = 0;
}
}
+out:
spin_unlock_irqrestore(&host->lock, flags);
mutex_unlock(&host->clk_mutex);
- return 0;
+ return rc;
}
#else
int msmsdcc_sdio_al_lpm(struct mmc_host *mmc, bool enable)
@@ -5606,7 +5622,7 @@
* during suspend and not allowing TCXO.
*/
- if (host->clks_on && !host->plat->is_sdio_al_client) {
+ if (atomic_read(&host->clks_on) && !host->plat->is_sdio_al_client) {
pr_warn("%s: clocks are on after suspend, aborting system "
"suspend\n", mmc_hostname(mmc));
rc = -EAGAIN;
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 5531f06..dc32d1c 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -351,7 +351,7 @@
struct clk *clk; /* main MMC bus clock */
struct clk *pclk; /* SDCC peripheral bus clock */
struct clk *bus_clk; /* SDCC bus voter clock */
- unsigned int clks_on; /* set if clocks are enabled */
+ atomic_t clks_on; /* set if clocks are enabled */
unsigned int eject; /* eject state */