#include <linux/random.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/wakelock.h>
+#define CREATE_TRACE_POINTS
#include <trace/events/mmc.h>
#include <linux/mmc/card.h>
#include "sd_ops.h"
#include "sdio_ops.h"
+EXPORT_TRACEPOINT_SYMBOL_GPL(mmc_blk_erase_start);
+EXPORT_TRACEPOINT_SYMBOL_GPL(mmc_blk_erase_end);
+EXPORT_TRACEPOINT_SYMBOL_GPL(mmc_blk_rw_start);
+EXPORT_TRACEPOINT_SYMBOL_GPL(mmc_blk_rw_end);
+
/* If the device is not responding */
#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
*/
#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 };
/*
bool use_spi_crc = 1;
module_param(use_spi_crc, bool, 0);
-/*
- * Internal function. Schedule delayed work in the MMC work queue.
- */
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);
-}
-
-/*
- * Internal function. Flush all scheduled work from the MMC work queue.
- */
-static void mmc_flush_scheduled_work(void)
-{
- flush_workqueue(workqueue);
+ /*
+ * We use the system_freezable_wq, because of two reasons.
+ * First, it allows several works (not the same work item) to be
+ * executed simultaneously. Second, the queue becomes frozen when
+ * userspace becomes frozen during system PM.
+ */
+ return queue_delayed_work(system_freezable_wq, work, delay);
}
#ifdef CONFIG_FAIL_MMC_REQUEST
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
host->ios.drv_type = 0;
+ host->ios.enhanced_strobe = false;
+
+ if ((host->caps2 & MMC_CAP2_HS400_ES) &&
+ host->ops->hs400_enhanced_strobe)
+ host->ops->hs400_enhanced_strobe(host, &host->ios);
mmc_set_ios(host);
}
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);
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.
mmc_claim_host(host);
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
- if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) {
- extend_wakelock = true;
+ if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
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);
}
host->rescan_disable = 1;
cancel_delayed_work_sync(&host->detect);
- mmc_flush_scheduled_work();
/* clear pm flags now and let card drivers set them as needed */
host->pm_flags = 0;
{
int ret;
- workqueue = alloc_ordered_workqueue("kmmcd", 0);
- 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;
+ return ret;
ret = mmc_register_host_class();
if (ret)
mmc_unregister_host_class();
unregister_bus:
mmc_unregister_bus();
-destroy_workqueue:
- destroy_workqueue(workqueue);
- wake_lock_destroy(&mmc_delayed_work_wake_lock);
-
return ret;
}
sdio_unregister_bus();
mmc_unregister_host_class();
mmc_unregister_bus();
- destroy_workqueue(workqueue);
- wake_lock_destroy(&mmc_delayed_work_wake_lock);
}
subsys_initcall(mmc_init);