Commit 2c4967f741e87cdd63de7271b97807041dccbf3b
Committed by
Chris Ball
1 parent
b6bf30d912
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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 */ |