Commit 2c4967f7 authored by Sujit Reddy Thumma's avatar Sujit Reddy Thumma Committed by Chris Ball

mmc: core: Ensure clocks are always enabled before host interaction

Ensure clocks are always enabled before any interaction with the
host controller driver. This makes sure that there is no race
between host execution and the core layer turning off clocks
in different context with clock gating framework.
Signed-off-by: default avatarSujit Reddy Thumma <sthumma@codeaurora.org>
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Acked-by: default avatarPer Forlin <per.forlin@stericsson.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent b6bf30d9
...@@ -290,8 +290,11 @@ static void mmc_wait_for_req_done(struct mmc_host *host, ...@@ -290,8 +290,11 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
bool is_first_req) bool is_first_req)
{ {
if (host->ops->pre_req) if (host->ops->pre_req) {
mmc_host_clk_hold(host);
host->ops->pre_req(host, mrq, is_first_req); host->ops->pre_req(host, mrq, is_first_req);
mmc_host_clk_release(host);
}
} }
/** /**
...@@ -306,8 +309,11 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, ...@@ -306,8 +309,11 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
int err) int err)
{ {
if (host->ops->post_req) if (host->ops->post_req) {
mmc_host_clk_hold(host);
host->ops->post_req(host, mrq, err); host->ops->post_req(host, mrq, err);
mmc_host_clk_release(host);
}
} }
/** /**
...@@ -620,7 +626,9 @@ int mmc_host_enable(struct mmc_host *host) ...@@ -620,7 +626,9 @@ int mmc_host_enable(struct mmc_host *host)
int err; int err;
host->en_dis_recurs = 1; host->en_dis_recurs = 1;
mmc_host_clk_hold(host);
err = host->ops->enable(host); err = host->ops->enable(host);
mmc_host_clk_release(host);
host->en_dis_recurs = 0; host->en_dis_recurs = 0;
if (err) { if (err) {
...@@ -640,7 +648,9 @@ static int mmc_host_do_disable(struct mmc_host *host, int lazy) ...@@ -640,7 +648,9 @@ static int mmc_host_do_disable(struct mmc_host *host, int lazy)
int err; int err;
host->en_dis_recurs = 1; host->en_dis_recurs = 1;
mmc_host_clk_hold(host);
err = host->ops->disable(host, lazy); err = host->ops->disable(host, lazy);
mmc_host_clk_release(host);
host->en_dis_recurs = 0; host->en_dis_recurs = 0;
if (err < 0) { if (err < 0) {
...@@ -1203,8 +1213,11 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11 ...@@ -1203,8 +1213,11 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
host->ios.signal_voltage = signal_voltage; host->ios.signal_voltage = signal_voltage;
if (host->ops->start_signal_voltage_switch) if (host->ops->start_signal_voltage_switch) {
mmc_host_clk_hold(host);
err = host->ops->start_signal_voltage_switch(host, &host->ios); err = host->ops->start_signal_voltage_switch(host, &host->ios);
mmc_host_clk_release(host);
}
return err; return err;
} }
......
...@@ -14,27 +14,6 @@ ...@@ -14,27 +14,6 @@
int mmc_register_host_class(void); int mmc_register_host_class(void);
void mmc_unregister_host_class(void); void mmc_unregister_host_class(void);
#ifdef CONFIG_MMC_CLKGATE
void mmc_host_clk_hold(struct mmc_host *host);
void mmc_host_clk_release(struct mmc_host *host);
unsigned int mmc_host_clk_rate(struct mmc_host *host);
#else
static inline void mmc_host_clk_hold(struct mmc_host *host)
{
}
static inline void mmc_host_clk_release(struct mmc_host *host)
{
}
static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
{
return host->ios.clock;
}
#endif
void mmc_host_deeper_disable(struct work_struct *work); void mmc_host_deeper_disable(struct work_struct *work);
#endif #endif
......
...@@ -451,9 +451,11 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status) ...@@ -451,9 +451,11 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)
* information and let the hardware specific code * information and let the hardware specific code
* return what is possible given the options * return what is possible given the options
*/ */
mmc_host_clk_hold(card->host);
drive_strength = card->host->ops->select_drive_strength( drive_strength = card->host->ops->select_drive_strength(
card->sw_caps.uhs_max_dtr, card->sw_caps.uhs_max_dtr,
host_drv_type, card_drv_type); host_drv_type, card_drv_type);
mmc_host_clk_release(card->host);
err = mmc_sd_switch(card, 1, 2, drive_strength, status); err = mmc_sd_switch(card, 1, 2, drive_strength, status);
if (err) if (err)
...@@ -660,9 +662,12 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) ...@@ -660,9 +662,12 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
goto out; goto out;
/* SPI mode doesn't define CMD19 */ /* SPI mode doesn't define CMD19 */
if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {
mmc_host_clk_hold(card->host);
err = card->host->ops->execute_tuning(card->host, err = card->host->ops->execute_tuning(card->host,
MMC_SEND_TUNING_BLOCK); MMC_SEND_TUNING_BLOCK);
mmc_host_clk_release(card->host);
}
out: out:
kfree(status); kfree(status);
...@@ -850,8 +855,11 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, ...@@ -850,8 +855,11 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
if (!reinit) { if (!reinit) {
int ro = -1; int ro = -1;
if (host->ops->get_ro) if (host->ops->get_ro) {
mmc_host_clk_hold(card->host);
ro = host->ops->get_ro(host); ro = host->ops->get_ro(host);
mmc_host_clk_release(card->host);
}
if (ro < 0) { if (ro < 0) {
pr_warning("%s: host does not " pr_warning("%s: host does not "
...@@ -967,8 +975,11 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, ...@@ -967,8 +975,11 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
* Since initialization is now complete, enable preset * Since initialization is now complete, enable preset
* value registers for UHS-I cards. * value registers for UHS-I cards.
*/ */
if (host->ops->enable_preset_value) if (host->ops->enable_preset_value) {
mmc_host_clk_hold(card->host);
host->ops->enable_preset_value(host, true); host->ops->enable_preset_value(host, true);
mmc_host_clk_release(card->host);
}
} else { } else {
/* /*
* Attempt to change to high-speed (if supported) * Attempt to change to high-speed (if supported)
...@@ -1151,8 +1162,11 @@ int mmc_attach_sd(struct mmc_host *host) ...@@ -1151,8 +1162,11 @@ int mmc_attach_sd(struct mmc_host *host)
return err; return err;
/* Disable preset value enable if already set since last time */ /* Disable preset value enable if already set since last time */
if (host->ops->enable_preset_value) if (host->ops->enable_preset_value) {
mmc_host_clk_hold(host);
host->ops->enable_preset_value(host, false); host->ops->enable_preset_value(host, false);
mmc_host_clk_release(host);
}
err = mmc_send_app_op_cond(host, 0, &ocr); err = mmc_send_app_op_cond(host, 0, &ocr);
if (err) if (err)
......
...@@ -146,15 +146,21 @@ static int sdio_irq_thread(void *_host) ...@@ -146,15 +146,21 @@ static int sdio_irq_thread(void *_host)
} }
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (host->caps & MMC_CAP_SDIO_IRQ) if (host->caps & MMC_CAP_SDIO_IRQ) {
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 1); host->ops->enable_sdio_irq(host, 1);
mmc_host_clk_release(host);
}
if (!kthread_should_stop()) if (!kthread_should_stop())
schedule_timeout(period); schedule_timeout(period);
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
} while (!kthread_should_stop()); } while (!kthread_should_stop());
if (host->caps & MMC_CAP_SDIO_IRQ) if (host->caps & MMC_CAP_SDIO_IRQ) {
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 0); host->ops->enable_sdio_irq(host, 0);
mmc_host_clk_release(host);
}
pr_debug("%s: IRQ thread exiting with code %d\n", pr_debug("%s: IRQ thread exiting with code %d\n",
mmc_hostname(host), ret); mmc_hostname(host), ret);
......
...@@ -444,4 +444,23 @@ static inline int mmc_boot_partition_access(struct mmc_host *host) ...@@ -444,4 +444,23 @@ static inline int mmc_boot_partition_access(struct mmc_host *host)
return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC); return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC);
} }
#ifdef CONFIG_MMC_CLKGATE
void mmc_host_clk_hold(struct mmc_host *host);
void mmc_host_clk_release(struct mmc_host *host);
unsigned int mmc_host_clk_rate(struct mmc_host *host);
#else
static inline void mmc_host_clk_hold(struct mmc_host *host)
{
}
static inline void mmc_host_clk_release(struct mmc_host *host)
{
}
static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
{
return host->ios.clock;
}
#endif
#endif /* LINUX_MMC_HOST_H */ #endif /* LINUX_MMC_HOST_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment