[PATCH 04/12] mmc: core: add tlp request handler for SD4.0

micky_ching
2015-04-29T01:34:29Z

when card is work in SD4.0 mode, we should send tlp instead of cmd.
add this function to handle tlp request.

Signed-off-by: Micky Ching <micky_ching@realsil.com.cn>
Signed-off-by: Wei Wang <wei_wang@realsil.com.cn>
---
drivers/mmc/core/core.c | 111 +++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 104 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c296bc0..ebb6fea 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -45,6 +45,7 @@
#include "mmc_ops.h"
#include "sd_ops.h"
#include "sdio_ops.h"
+#include "sd.h"

/* If the device is not responding */
#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
@@ -131,7 +132,42 @@ static inline void mmc_should_fail_request(struct mmc_host *host,
void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
{
struct mmc_command *cmd = mrq->cmd;
- int err = cmd->error;
+ struct mmc_tlp *tlp = mrq->tlp;
+ int err;
+
+ if (tlp && cmd)
+ pr_debug("%s: cmd and native tlp conflict, done native tlp\n",
+ mmc_hostname(host));
+
+ if (tlp) {
+ err = tlp->error;
+ if (err && tlp->retries && !mmc_card_removed(host->card)) {
+ /*
+ * Request starter must handle retries - see
+ * mmc_wait_for_req_done().
+ */
+ if (mrq->done)
+ mrq->done(mrq);
+ } else {
+ led_trigger_event(host->led, LED_OFF);
+
+ pr_debug("%s: native TLP req done(%d) %04x %04x %08x %08x %08x %08x\n",
+ mmc_hostname(host), err,
+ tlp->tlp_back->header, tlp->tlp_back->argument,
+ tlp->tlp_back->payload[0],
+ tlp->tlp_back->payload[1],
+ tlp->tlp_back->payload[2],
+ tlp->tlp_back->payload[3]);
+
+ if (mrq->done)
+ mrq->done(mrq);
+
+ mmc_host_clk_release(host);
+ }
+ return;
+ }
+
+ err = cmd->error;

if (err && cmd->retries && mmc_host_is_spi(host)) {
if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
@@ -201,9 +237,18 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->sbc->arg, mrq->sbc->flags);
}

- pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
- mmc_hostname(host), mrq->cmd->opcode,
- mrq->cmd->arg, mrq->cmd->flags);
+ if (mrq->tlp && mrq->cmd)
+ pr_debug("%s: cmd and native tlp conflict, start native tlp\n",
+ mmc_hostname(host));
+
+ if (mrq->tlp)
+ pr_debug("%s: starting native TLP header %04x argument %04x\n",
+ mmc_hostname(host), mrq->tlp->tlp_send->header,
+ mrq->tlp->tlp_send->argument);
+ else if (mrq->cmd)
+ pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
+ mmc_hostname(host), mrq->cmd->opcode,
+ mrq->cmd->arg, mrq->cmd->flags);

if (mrq->data) {
pr_debug("%s: blksz %d blocks %d flags %08x "
@@ -221,6 +266,8 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
}

WARN_ON(!host->claimed);
+ if (!mrq->cmd)
+ goto start;

mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
@@ -250,6 +297,25 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->stop->mrq = mrq;
}
}
+
+ if (mmc_card_uhsii(host->card)) {
+ mrq->cmd->use_tlp = true;
+ if (mrq->data)
+ mmc_sd_tran_pack_dcmd(host->card, mrq->cmd);
+ else
+ mmc_sd_tran_pack_ccmd(host->card, mrq->cmd);
+
+ if (mrq->sbc) {
+ mrq->sbc->use_tlp = true;
+ mmc_sd_tran_pack_ccmd(host->card, mrq->sbc);
+ }
+ if (mrq->stop) {
+ mrq->stop->use_tlp = true;
+ mmc_sd_tran_pack_ccmd(host->card, mrq->stop);
+ }
+ }
+
+start:
mmc_host_clk_hold(host);
led_trigger_event(host->led, LED_FULL);
host->ops->request(host, mrq);
@@ -356,7 +422,7 @@ static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq)

err = mmc_start_request(host, mrq);
if (err) {
- mrq->cmd->error = err;
+ mmc_set_mrq_error_code(mrq, err);
mmc_wait_data_done(mrq);
}

@@ -372,7 +438,7 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)

err = mmc_start_request(host, mrq);
if (err) {
- mrq->cmd->error = err;
+ mmc_set_mrq_error_code(mrq, err);
complete(&mrq->completion);
}

@@ -436,7 +502,7 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
return err;
}

-static void mmc_wait_for_req_done(struct mmc_host *host,
+static void mmc_wait_for_cmd_req_done(struct mmc_host *host,
struct mmc_request *mrq)
{
struct mmc_command *cmd;
@@ -475,6 +541,37 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
}
}

+static void mmc_wait_for_tlp_req_done(struct mmc_host *host,
+ struct mmc_request *mrq)
+{
+ struct mmc_tlp *tlp;
+
+ while (1) {
+ wait_for_completion(&mrq->completion);
+
+ tlp = mrq->tlp;
+
+ if (!tlp->error || !tlp->retries ||
+ mmc_card_removed(host->card))
+ break;
+
+ pr_debug("%s: native TLP req failed: %d, retrying...\n",
+ mmc_hostname(host), tlp->error);
+ tlp->retries--;
+ tlp->error = 0;
+ host->ops->request(host, mrq);
+ }
+}
+
+static void mmc_wait_for_req_done(struct mmc_host *host,
+ struct mmc_request *mrq)
+{
+ if (mrq->cmd)
+ mmc_wait_for_cmd_req_done(host, mrq);
+ else
+ mmc_wait_for_tlp_req_done(host, mrq);
+}
+
/**
* mmc_pre_req - Prepare for a new request
* @host: MMC host to prepare command
--
1.9.1