Commit 2c4967f741e87cdd63de7271b97807041dccbf3b

Authored by Sujit Reddy Thumma
Committed by Chris Ball
1 parent b6bf30d912

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: Sujit Reddy Thumma <sthumma@codeaurora.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Per Forlin <per.forlin@stericsson.com>
Signed-off-by: Chris Ball <cjb@laptop.org>

Showing 5 changed files with 61 additions and 30 deletions Side-by-side Diff

drivers/mmc/core/core.c
... ... @@ -290,8 +290,11 @@
290 290 static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
291 291 bool is_first_req)
292 292 {
293   - if (host->ops->pre_req)
  293 + if (host->ops->pre_req) {
  294 + mmc_host_clk_hold(host);
294 295 host->ops->pre_req(host, mrq, is_first_req);
  296 + mmc_host_clk_release(host);
  297 + }
295 298 }
296 299  
297 300 /**
298 301  
... ... @@ -306,8 +309,11 @@
306 309 static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
307 310 int err)
308 311 {
309   - if (host->ops->post_req)
  312 + if (host->ops->post_req) {
  313 + mmc_host_clk_hold(host);
310 314 host->ops->post_req(host, mrq, err);
  315 + mmc_host_clk_release(host);
  316 + }
311 317 }
312 318  
313 319 /**
314 320  
... ... @@ -620,7 +626,9 @@
620 626 int err;
621 627  
622 628 host->en_dis_recurs = 1;
  629 + mmc_host_clk_hold(host);
623 630 err = host->ops->enable(host);
  631 + mmc_host_clk_release(host);
624 632 host->en_dis_recurs = 0;
625 633  
626 634 if (err) {
627 635  
... ... @@ -640,7 +648,9 @@
640 648 int err;
641 649  
642 650 host->en_dis_recurs = 1;
  651 + mmc_host_clk_hold(host);
643 652 err = host->ops->disable(host, lazy);
  653 + mmc_host_clk_release(host);
644 654 host->en_dis_recurs = 0;
645 655  
646 656 if (err < 0) {
647 657  
... ... @@ -1203,8 +1213,11 @@
1203 1213  
1204 1214 host->ios.signal_voltage = signal_voltage;
1205 1215  
1206   - if (host->ops->start_signal_voltage_switch)
  1216 + if (host->ops->start_signal_voltage_switch) {
  1217 + mmc_host_clk_hold(host);
1207 1218 err = host->ops->start_signal_voltage_switch(host, &host->ios);
  1219 + mmc_host_clk_release(host);
  1220 + }
1208 1221  
1209 1222 return err;
1210 1223 }
drivers/mmc/core/host.h
... ... @@ -14,27 +14,6 @@
14 14  
15 15 int mmc_register_host_class(void);
16 16 void mmc_unregister_host_class(void);
17   -
18   -#ifdef CONFIG_MMC_CLKGATE
19   -void mmc_host_clk_hold(struct mmc_host *host);
20   -void mmc_host_clk_release(struct mmc_host *host);
21   -unsigned int mmc_host_clk_rate(struct mmc_host *host);
22   -
23   -#else
24   -static inline void mmc_host_clk_hold(struct mmc_host *host)
25   -{
26   -}
27   -
28   -static inline void mmc_host_clk_release(struct mmc_host *host)
29   -{
30   -}
31   -
32   -static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
33   -{
34   - return host->ios.clock;
35   -}
36   -#endif
37   -
38 17 void mmc_host_deeper_disable(struct work_struct *work);
39 18  
40 19 #endif
drivers/mmc/core/sd.c
... ... @@ -451,9 +451,11 @@
451 451 * information and let the hardware specific code
452 452 * return what is possible given the options
453 453 */
  454 + mmc_host_clk_hold(card->host);
454 455 drive_strength = card->host->ops->select_drive_strength(
455 456 card->sw_caps.uhs_max_dtr,
456 457 host_drv_type, card_drv_type);
  458 + mmc_host_clk_release(card->host);
457 459  
458 460 err = mmc_sd_switch(card, 1, 2, drive_strength, status);
459 461 if (err)
460 462  
... ... @@ -660,9 +662,12 @@
660 662 goto out;
661 663  
662 664 /* SPI mode doesn't define CMD19 */
663   - if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
  665 + if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {
  666 + mmc_host_clk_hold(card->host);
664 667 err = card->host->ops->execute_tuning(card->host,
665 668 MMC_SEND_TUNING_BLOCK);
  669 + mmc_host_clk_release(card->host);
  670 + }
666 671  
667 672 out:
668 673 kfree(status);
669 674  
... ... @@ -850,8 +855,11 @@
850 855 if (!reinit) {
851 856 int ro = -1;
852 857  
853   - if (host->ops->get_ro)
  858 + if (host->ops->get_ro) {
  859 + mmc_host_clk_hold(card->host);
854 860 ro = host->ops->get_ro(host);
  861 + mmc_host_clk_release(card->host);
  862 + }
855 863  
856 864 if (ro < 0) {
857 865 pr_warning("%s: host does not "
858 866  
... ... @@ -967,8 +975,11 @@
967 975 * Since initialization is now complete, enable preset
968 976 * value registers for UHS-I cards.
969 977 */
970   - if (host->ops->enable_preset_value)
  978 + if (host->ops->enable_preset_value) {
  979 + mmc_host_clk_hold(card->host);
971 980 host->ops->enable_preset_value(host, true);
  981 + mmc_host_clk_release(card->host);
  982 + }
972 983 } else {
973 984 /*
974 985 * Attempt to change to high-speed (if supported)
975 986  
... ... @@ -1151,8 +1162,11 @@
1151 1162 return err;
1152 1163  
1153 1164 /* Disable preset value enable if already set since last time */
1154   - if (host->ops->enable_preset_value)
  1165 + if (host->ops->enable_preset_value) {
  1166 + mmc_host_clk_hold(host);
1155 1167 host->ops->enable_preset_value(host, false);
  1168 + mmc_host_clk_release(host);
  1169 + }
1156 1170  
1157 1171 err = mmc_send_app_op_cond(host, 0, &ocr);
1158 1172 if (err)
drivers/mmc/core/sdio_irq.c
... ... @@ -146,15 +146,21 @@
146 146 }
147 147  
148 148 set_current_state(TASK_INTERRUPTIBLE);
149   - if (host->caps & MMC_CAP_SDIO_IRQ)
  149 + if (host->caps & MMC_CAP_SDIO_IRQ) {
  150 + mmc_host_clk_hold(host);
150 151 host->ops->enable_sdio_irq(host, 1);
  152 + mmc_host_clk_release(host);
  153 + }
151 154 if (!kthread_should_stop())
152 155 schedule_timeout(period);
153 156 set_current_state(TASK_RUNNING);
154 157 } while (!kthread_should_stop());
155 158  
156   - if (host->caps & MMC_CAP_SDIO_IRQ)
  159 + if (host->caps & MMC_CAP_SDIO_IRQ) {
  160 + mmc_host_clk_hold(host);
157 161 host->ops->enable_sdio_irq(host, 0);
  162 + mmc_host_clk_release(host);
  163 + }
158 164  
159 165 pr_debug("%s: IRQ thread exiting with code %d\n",
160 166 mmc_hostname(host), ret);
include/linux/mmc/host.h
... ... @@ -444,5 +444,24 @@
444 444 return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC);
445 445 }
446 446  
  447 +#ifdef CONFIG_MMC_CLKGATE
  448 +void mmc_host_clk_hold(struct mmc_host *host);
  449 +void mmc_host_clk_release(struct mmc_host *host);
  450 +unsigned int mmc_host_clk_rate(struct mmc_host *host);
  451 +
  452 +#else
  453 +static inline void mmc_host_clk_hold(struct mmc_host *host)
  454 +{
  455 +}
  456 +
  457 +static inline void mmc_host_clk_release(struct mmc_host *host)
  458 +{
  459 +}
  460 +
  461 +static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
  462 +{
  463 + return host->ios.clock;
  464 +}
  465 +#endif
447 466 #endif /* LINUX_MMC_HOST_H */