|
@@ -832,9 +832,36 @@ unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
|
|
|
}
|
|
|
EXPORT_SYMBOL(mmc_align_data_size);
|
|
|
|
|
|
+/*
|
|
|
+ * Allow claiming an already claimed host if the context is the same or there is
|
|
|
+ * no context but the task is the same.
|
|
|
+ */
|
|
|
+static inline bool mmc_ctx_matches(struct mmc_host *host, struct mmc_ctx *ctx,
|
|
|
+ struct task_struct *task)
|
|
|
+{
|
|
|
+ return host->claimer == ctx ||
|
|
|
+ (!ctx && task && host->claimer->task == task);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void mmc_ctx_set_claimer(struct mmc_host *host,
|
|
|
+ struct mmc_ctx *ctx,
|
|
|
+ struct task_struct *task)
|
|
|
+{
|
|
|
+ if (!host->claimer) {
|
|
|
+ if (ctx)
|
|
|
+ host->claimer = ctx;
|
|
|
+ else
|
|
|
+ host->claimer = &host->default_ctx;
|
|
|
+ }
|
|
|
+ if (task)
|
|
|
+ host->claimer->task = task;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* __mmc_claim_host - exclusively claim a host
|
|
|
* @host: mmc host to claim
|
|
|
+ * @ctx: context that claims the host or NULL in which case the default
|
|
|
+ * context will be used
|
|
|
* @abort: whether or not the operation should be aborted
|
|
|
*
|
|
|
* Claim a host for a set of operations. If @abort is non null and
|
|
@@ -842,8 +869,10 @@ EXPORT_SYMBOL(mmc_align_data_size);
|
|
|
* that non-zero value without acquiring the lock. Returns zero
|
|
|
* with the lock held otherwise.
|
|
|
*/
|
|
|
-int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
|
|
|
+int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
|
|
|
+ atomic_t *abort)
|
|
|
{
|
|
|
+ struct task_struct *task = ctx ? NULL : current;
|
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
|
unsigned long flags;
|
|
|
int stop;
|
|
@@ -856,7 +885,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
|
|
|
while (1) {
|
|
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
|
stop = abort ? atomic_read(abort) : 0;
|
|
|
- if (stop || !host->claimed || host->claimer == current)
|
|
|
+ if (stop || !host->claimed || mmc_ctx_matches(host, ctx, task))
|
|
|
break;
|
|
|
spin_unlock_irqrestore(&host->lock, flags);
|
|
|
schedule();
|
|
@@ -865,7 +894,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
|
|
|
set_current_state(TASK_RUNNING);
|
|
|
if (!stop) {
|
|
|
host->claimed = 1;
|
|
|
- host->claimer = current;
|
|
|
+ mmc_ctx_set_claimer(host, ctx, task);
|
|
|
host->claim_cnt += 1;
|
|
|
if (host->claim_cnt == 1)
|
|
|
pm = true;
|
|
@@ -900,6 +929,7 @@ void mmc_release_host(struct mmc_host *host)
|
|
|
spin_unlock_irqrestore(&host->lock, flags);
|
|
|
} else {
|
|
|
host->claimed = 0;
|
|
|
+ host->claimer->task = NULL;
|
|
|
host->claimer = NULL;
|
|
|
spin_unlock_irqrestore(&host->lock, flags);
|
|
|
wake_up(&host->wq);
|
|
@@ -913,10 +943,10 @@ EXPORT_SYMBOL(mmc_release_host);
|
|
|
* This is a helper function, which fetches a runtime pm reference for the
|
|
|
* card device and also claims the host.
|
|
|
*/
|
|
|
-void mmc_get_card(struct mmc_card *card)
|
|
|
+void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx)
|
|
|
{
|
|
|
pm_runtime_get_sync(&card->dev);
|
|
|
- mmc_claim_host(card->host);
|
|
|
+ __mmc_claim_host(card->host, ctx, NULL);
|
|
|
}
|
|
|
EXPORT_SYMBOL(mmc_get_card);
|
|
|
|
|
@@ -924,9 +954,13 @@ EXPORT_SYMBOL(mmc_get_card);
|
|
|
* This is a helper function, which releases the host and drops the runtime
|
|
|
* pm reference for the card device.
|
|
|
*/
|
|
|
-void mmc_put_card(struct mmc_card *card)
|
|
|
+void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx)
|
|
|
{
|
|
|
- mmc_release_host(card->host);
|
|
|
+ struct mmc_host *host = card->host;
|
|
|
+
|
|
|
+ WARN_ON(ctx && host->claimer != ctx);
|
|
|
+
|
|
|
+ mmc_release_host(host);
|
|
|
pm_runtime_mark_last_busy(&card->dev);
|
|
|
pm_runtime_put_autosuspend(&card->dev);
|
|
|
}
|