diff options
Diffstat (limited to 'drivers/mmc/core/core.c')
-rw-r--r-- | drivers/mmc/core/core.c | 55 |
1 files changed, 53 insertions, 2 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 588fb7908642..29431493fd16 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -29,6 +29,9 @@ #include <linux/random.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/wakelock.h> + +#include <trace/events/mmc.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> @@ -56,6 +59,7 @@ #define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */ static struct workqueue_struct *workqueue; +static struct wake_lock mmc_delayed_work_wake_lock; static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; /* @@ -72,6 +76,7 @@ module_param(use_spi_crc, bool, 0); static int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay) { + wake_lock(&mmc_delayed_work_wake_lock); return queue_delayed_work(workqueue, work, delay); } @@ -167,6 +172,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) pr_debug("%s: %d bytes transferred: %d\n", mmc_hostname(host), mrq->data->bytes_xfered, mrq->data->error); + trace_mmc_blk_rw_end(cmd->opcode, cmd->arg, mrq->data); } if (mrq->stop) { @@ -575,8 +581,12 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, } } - if (!err && areq) + if (!err && areq) { + trace_mmc_blk_rw_start(areq->mrq->cmd->opcode, + areq->mrq->cmd->arg, + areq->mrq->data); start_err = __mmc_start_data_req(host, areq->mrq); + } if (host->areq) mmc_post_req(host, host->areq->mrq, 0); @@ -1970,8 +1980,13 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, struct mmc_command cmd = {0}; unsigned int qty = 0; unsigned long timeout; + unsigned int fr, nr; int err; + fr = from; + nr = to - from + 1; + trace_mmc_blk_erase_start(arg, fr, nr); + /* * qty is used to calculate the erase timeout which depends on how many * erase groups (or allocation units in SD terminology) are affected. @@ -2075,6 +2090,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, } while (!(cmd.resp[0] & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG)); out: + + trace_mmc_blk_erase_end(arg, fr, nr); return err; } @@ -2449,6 +2466,7 @@ void mmc_rescan(struct work_struct *work) struct mmc_host *host = container_of(work, struct mmc_host, detect.work); int i; + bool extend_wakelock = false; if (host->trigger_card_event && host->ops->card_event) { host->ops->card_event(host); @@ -2475,6 +2493,12 @@ void mmc_rescan(struct work_struct *work) host->detect_change = 0; + /* If the card was removed the bus will be marked + * as dead - extend the wakelock so userspace + * can respond */ + if (host->bus_dead) + extend_wakelock = 1; + /* * Let mmc_bus_put() free the bus/bus_ops if we've found that * the card is no longer present. @@ -2504,14 +2528,20 @@ void mmc_rescan(struct work_struct *work) mmc_claim_host(host); for (i = 0; i < ARRAY_SIZE(freqs); i++) { - if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) + if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) { + extend_wakelock = true; break; + } if (freqs[i] <= host->f_min) break; } mmc_release_host(host); out: + if (extend_wakelock) + wake_lock_timeout(&mmc_delayed_work_wake_lock, HZ / 2); + else + wake_unlock(&mmc_delayed_work_wake_lock); if (host->caps & MMC_CAP_NEEDS_POLL) mmc_schedule_delayed_work(&host->detect, HZ); } @@ -2709,6 +2739,22 @@ void mmc_init_context_info(struct mmc_host *host) init_waitqueue_head(&host->context_info.wait); } +#ifdef CONFIG_MMC_EMBEDDED_SDIO +void mmc_set_embedded_sdio_data(struct mmc_host *host, + struct sdio_cis *cis, + struct sdio_cccr *cccr, + struct sdio_embedded_func *funcs, + int num_funcs) +{ + host->embedded_sdio_data.cis = cis; + host->embedded_sdio_data.cccr = cccr; + host->embedded_sdio_data.funcs = funcs; + host->embedded_sdio_data.num_funcs = num_funcs; +} + +EXPORT_SYMBOL(mmc_set_embedded_sdio_data); +#endif + static int __init mmc_init(void) { int ret; @@ -2717,6 +2763,9 @@ static int __init mmc_init(void) if (!workqueue) return -ENOMEM; + wake_lock_init(&mmc_delayed_work_wake_lock, WAKE_LOCK_SUSPEND, + "mmc_delayed_work"); + ret = mmc_register_bus(); if (ret) goto destroy_workqueue; @@ -2737,6 +2786,7 @@ unregister_bus: mmc_unregister_bus(); destroy_workqueue: destroy_workqueue(workqueue); + wake_lock_destroy(&mmc_delayed_work_wake_lock); return ret; } @@ -2747,6 +2797,7 @@ static void __exit mmc_exit(void) mmc_unregister_host_class(); mmc_unregister_bus(); destroy_workqueue(workqueue); + wake_lock_destroy(&mmc_delayed_work_wake_lock); } subsys_initcall(mmc_init); |