Commit 4e9f8fe5 authored by Adrian Hunter's avatar Adrian Hunter Committed by Ulf Hansson

mmc: sdhci: Allow for finishing multiple requests

In order to support commands during data transfer, there will have to be up
to two active requests (mrqs) at a time, instead of just one. That means
recording which request is finished.  Doing that obsoletes host->mrq which
is therefore removed.
Signed-off-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent d7422fb4
...@@ -938,6 +938,29 @@ static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq) ...@@ -938,6 +938,29 @@ static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
(host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))); (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)));
} }
static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
{
int i;
for (i = 0; i < SDHCI_MAX_MRQS; i++) {
if (host->mrqs_done[i] == mrq) {
WARN_ON(1);
return;
}
}
for (i = 0; i < SDHCI_MAX_MRQS; i++) {
if (!host->mrqs_done[i]) {
host->mrqs_done[i] = mrq;
break;
}
}
WARN_ON(i >= SDHCI_MAX_MRQS);
tasklet_schedule(&host->finish_tasklet);
}
static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
{ {
if (host->cmd && host->cmd->mrq == mrq) if (host->cmd && host->cmd->mrq == mrq)
...@@ -952,7 +975,7 @@ static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) ...@@ -952,7 +975,7 @@ static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
if (sdhci_needs_reset(host, mrq)) if (sdhci_needs_reset(host, mrq))
host->pending_reset = true; host->pending_reset = true;
tasklet_schedule(&host->finish_tasklet); __sdhci_finish_mrq(host, mrq);
} }
static void sdhci_finish_data(struct sdhci_host *host) static void sdhci_finish_data(struct sdhci_host *host)
...@@ -1440,8 +1463,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -1440,8 +1463,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
WARN_ON(host->mrq != NULL);
sdhci_led_activate(host); sdhci_led_activate(host);
/* /*
...@@ -1455,8 +1476,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -1455,8 +1476,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
} }
} }
host->mrq = mrq;
if (!present || host->flags & SDHCI_DEVICE_DEAD) { if (!present || host->flags & SDHCI_DEVICE_DEAD) {
mrq->cmd->error = -ENOMEDIUM; mrq->cmd->error = -ENOMEDIUM;
sdhci_finish_mrq(host, mrq); sdhci_finish_mrq(host, mrq);
...@@ -1993,13 +2012,13 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) ...@@ -1993,13 +2012,13 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
cmd.retries = 0; cmd.retries = 0;
cmd.data = NULL; cmd.data = NULL;
cmd.mrq = &mrq;
cmd.error = 0; cmd.error = 0;
if (tuning_loop_counter-- == 0) if (tuning_loop_counter-- == 0)
break; break;
mrq.cmd = &cmd; mrq.cmd = &cmd;
host->mrq = &mrq;
/* /*
* In response to CMD19, the card sends 64 bytes of tuning * In response to CMD19, the card sends 64 bytes of tuning
...@@ -2029,7 +2048,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) ...@@ -2029,7 +2048,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
sdhci_send_command(host, &cmd); sdhci_send_command(host, &cmd);
host->cmd = NULL; host->cmd = NULL;
host->mrq = NULL;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
/* Wait for Buffer Read Ready interrupt */ /* Wait for Buffer Read Ready interrupt */
...@@ -2230,26 +2248,26 @@ static const struct mmc_host_ops sdhci_ops = { ...@@ -2230,26 +2248,26 @@ static const struct mmc_host_ops sdhci_ops = {
* * * *
\*****************************************************************************/ \*****************************************************************************/
static void sdhci_tasklet_finish(unsigned long param) static bool sdhci_request_done(struct sdhci_host *host)
{ {
struct sdhci_host *host;
unsigned long flags; unsigned long flags;
struct mmc_request *mrq; struct mmc_request *mrq;
int i;
host = (struct sdhci_host*)param;
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
/* for (i = 0; i < SDHCI_MAX_MRQS; i++) {
* If this tasklet gets rescheduled while running, it will mrq = host->mrqs_done[i];
* be run again afterwards but without any active request. if (mrq) {
*/ host->mrqs_done[i] = NULL;
if (!host->mrq) { break;
spin_unlock_irqrestore(&host->lock, flags); }
return;
} }
mrq = host->mrq; if (!mrq) {
spin_unlock_irqrestore(&host->lock, flags);
return true;
}
sdhci_del_timer(host, mrq); sdhci_del_timer(host, mrq);
...@@ -2287,14 +2305,23 @@ static void sdhci_tasklet_finish(unsigned long param) ...@@ -2287,14 +2305,23 @@ static void sdhci_tasklet_finish(unsigned long param)
host->pending_reset = false; host->pending_reset = false;
} }
host->mrq = NULL; if (!sdhci_has_requests(host))
sdhci_led_deactivate(host);
sdhci_led_deactivate(host);
mmiowb(); mmiowb();
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
mmc_request_done(host->mmc, mrq); mmc_request_done(host->mmc, mrq);
return false;
}
static void sdhci_tasklet_finish(unsigned long param)
{
struct sdhci_host *host = (struct sdhci_host *)param;
while (!sdhci_request_done(host))
;
} }
static void sdhci_timeout_timer(unsigned long data) static void sdhci_timeout_timer(unsigned long data)
......
...@@ -314,6 +314,9 @@ struct sdhci_adma2_64_desc { ...@@ -314,6 +314,9 @@ struct sdhci_adma2_64_desc {
*/ */
#define SDHCI_MAX_SEGS 128 #define SDHCI_MAX_SEGS 128
/* Allow for a a command request and a data request at the same time */
#define SDHCI_MAX_MRQS 2
enum sdhci_cookie { enum sdhci_cookie {
COOKIE_UNMAPPED, COOKIE_UNMAPPED,
COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */ COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */
...@@ -465,7 +468,7 @@ struct sdhci_host { ...@@ -465,7 +468,7 @@ struct sdhci_host {
bool preset_enabled; /* Preset is enabled */ bool preset_enabled; /* Preset is enabled */
bool pending_reset; /* Cmd/data reset is pending */ bool pending_reset; /* Cmd/data reset is pending */
struct mmc_request *mrq; /* Current request */ struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */
struct mmc_command *cmd; /* Current command */ struct mmc_command *cmd; /* Current command */
struct mmc_command *data_cmd; /* Current data command */ struct mmc_command *data_cmd; /* Current data command */
struct mmc_data *data; /* Current data request */ struct mmc_data *data; /* Current data request */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment