Re: [PATCH V4 05/11] mmc: core: Add support for handling CQE requests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 21 July 2017 at 11:49, Adrian Hunter <adrian.hunter@xxxxxxxxx> wrote:
> Add core support for handling CQE requests, including starting, completing
> and recovering.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@xxxxxxxxx>
> ---
>  drivers/mmc/core/core.c  | 147 +++++++++++++++++++++++++++++++++++++++++++++--
>  include/linux/mmc/core.h |   5 ++
>  2 files changed, 147 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index b0af9db18eef..5a9d837599a1 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -266,7 +266,8 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
>         host->ops->request(host, mrq);
>  }
>
> -static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq)
> +static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq,
> +                            bool cqe)
>  {
>         if (mrq->sbc) {
>                 pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
> @@ -275,9 +276,12 @@ static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq)
>         }
>
>         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);
> +               pr_debug("%s: starting %sCMD%u arg %08x flags %08x\n",
> +                        mmc_hostname(host), cqe ? "CQE direct " : "",
> +                        mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags);
> +       } else if (cqe) {
> +               pr_debug("%s: starting CQE transfer for tag %d blkaddr %u\n",
> +                        mmc_hostname(host), mrq->tag, mrq->data->blk_addr);
>         }
>
>         if (mrq->data) {
> @@ -345,7 +349,7 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
>         if (mmc_card_removed(host->card))
>                 return -ENOMEDIUM;
>
> -       mmc_mrq_pr_debug(host, mrq);
> +       mmc_mrq_pr_debug(host, mrq, false);
>
>         WARN_ON(!host->claimed);
>
> @@ -485,6 +489,139 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
>  }
>  EXPORT_SYMBOL(mmc_wait_for_req_done);
>

As this is an exported function, could you please add some function
header information.

> +int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
> +{
> +       int err;
> +
> +       /* Caller must hold retuning while CQE is in use */

Would be nice to get some more clarification on *why* this is needed.
Can you please extend the comment a bit on that?

> +       err = mmc_retune(host);
> +       if (err)
> +               goto out_err;
> +
> +       mrq->host = host;
> +
> +       mmc_mrq_pr_debug(host, mrq, true);
> +
> +       err = mmc_mrq_prep(host, mrq);
> +       if (err)
> +               goto out_err;
> +
> +       err = host->cqe_ops->cqe_request(host, mrq);
> +       if (err)
> +               goto out_err;
> +
> +       trace_mmc_request_start(host, mrq);
> +
> +       return 0;
> +
> +out_err:
> +       if (mrq->cmd) {
> +               pr_debug("%s: failed to start CQE direct CMD%u, error %d\n",
> +                        mmc_hostname(host), mrq->cmd->opcode, err);
> +       } else {
> +               pr_debug("%s: failed to start CQE transfer for tag %d, error %d\n",
> +                        mmc_hostname(host), mrq->tag, err);
> +       }
> +       return err;
> +}
> +EXPORT_SYMBOL(mmc_cqe_start_req);
> +
> +static void __mmc_cqe_request_done(struct mmc_host *host,
> +                                  struct mmc_request *mrq)
> +{
> +       mmc_should_fail_request(host, mrq);
> +
> +       /* Flag re-tuning needed on CRC errors */
> +       if ((mrq->cmd && mrq->cmd->error == -EILSEQ) ||
> +           (mrq->data && mrq->data->error == -EILSEQ))
> +               mmc_retune_needed(host);
> +
> +       trace_mmc_request_done(host, mrq);
> +
> +       if (mrq->cmd) {
> +               pr_debug("%s: CQE req done (direct CMD%u): %d\n",
> +                        mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->error);
> +       } else {
> +               pr_debug("%s: CQE transfer done tag %d\n",
> +                        mmc_hostname(host), mrq->tag);
> +       }
> +
> +       if (mrq->data) {
> +               pr_debug("%s:     %d bytes transferred: %d\n",
> +                        mmc_hostname(host),
> +                        mrq->data->bytes_xfered, mrq->data->error);
> +       }
> +}
> +
> +/**
> + *     mmc_cqe_request_done - CQE has finished processing an MMC request
> + *     @host: MMC host which completed request
> + *     @mrq: MMC request which completed
> + *
> + *     CQE drivers should call this function when they have completed
> + *     their processing of a request.
> + */
> +void mmc_cqe_request_done(struct mmc_host *host, struct mmc_request *mrq)
> +{
> +       __mmc_cqe_request_done(host, mrq);
> +
> +       mrq->done(mrq);
> +}
> +EXPORT_SYMBOL(mmc_cqe_request_done);
> +
> +/**
> + *     mmc_cqe_post_req - CQE post process of a completed MMC request
> + *     @host: MMC host
> + *     @mrq: MMC request to be processed
> + */
> +void mmc_cqe_post_req(struct mmc_host *host, struct mmc_request *mrq)
> +{
> +       if (host->cqe_ops->cqe_post_req)
> +               host->cqe_ops->cqe_post_req(host, mrq);
> +}
> +EXPORT_SYMBOL(mmc_cqe_post_req);
> +
> +/* Arbitrary 1 second timeout */
> +#define MMC_CQE_RECOVERY_TIMEOUT       1000

Why 1 second?

Nitpick:
I am bit reluctant to use the terminology of "recovery". In then end
it's about a request timeout and then act by doing a graceful abort.

> +

Please add function header.

> +int mmc_cqe_recovery(struct mmc_host *host)
> +{
> +       struct mmc_command cmd;
> +       int err;
> +
> +       mmc_retune_hold_now(host);
> +
> +       /*
> +        * Recovery is expected seldom, if at all, but it reduces performance,
> +        * so make sure it is not completely silent.
> +        */
> +       pr_warn("%s: running CQE recovery\n", mmc_hostname(host));
> +
> +       host->cqe_ops->cqe_recovery_start(host);

What is expected to be done by the host from this callback?

I have been thinking about deploying a common data request timeout
behavior in the mmc core. In principle calling
wait_for_completion_timeout() instead of just wait_for_completion().
To deal with that, one would also need to invent a new host ops
callback to allow the host driver to restore its HW to a know state.
Very similar to what you also seems to need here for CQE.

I was just thinking that part of this code/callbacks could be re-used
for other non-CQE data requests that timeouts. Do you think that could
makes sense?

> +
> +       memset(&cmd, 0, sizeof(cmd));
> +       cmd.opcode       = MMC_STOP_TRANSMISSION,
> +       cmd.flags        = MMC_RSP_R1B | MMC_CMD_AC,
> +       cmd.flags       &= ~MMC_RSP_CRC; /* Ignore CRC */
> +       cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
> +       mmc_wait_for_cmd(host, &cmd, 0);
> +
> +       memset(&cmd, 0, sizeof(cmd));
> +       cmd.opcode       = MMC_CMDQ_TASK_MGMT;
> +       cmd.arg          = 1; /* Discard entire queue */
> +       cmd.flags        = MMC_RSP_R1B | MMC_CMD_AC;
> +       cmd.flags       &= ~MMC_RSP_CRC; /* Ignore CRC */
> +       cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
> +       err = mmc_wait_for_cmd(host, &cmd, 0);
> +
> +       host->cqe_ops->cqe_recovery_finish(host);
> +
> +       mmc_retune_release(host);
> +
> +       return err;
> +}
> +EXPORT_SYMBOL(mmc_cqe_recovery);
> +
>  /**
>   *     mmc_is_req_done - Determine if a 'cap_cmd_during_tfr' request is done
>   *     @host: MMC host
> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
> index bf1788a224e6..1974fcfd4284 100644
> --- a/include/linux/mmc/core.h
> +++ b/include/linux/mmc/core.h
> @@ -174,6 +174,11 @@ struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
>  int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd,
>                 int retries);
>
> +int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq);
> +void mmc_cqe_request_done(struct mmc_host *host, struct mmc_request *mrq);
> +void mmc_cqe_post_req(struct mmc_host *host, struct mmc_request *mrq);
> +int mmc_cqe_recovery(struct mmc_host *host);
> +
>  int mmc_hw_reset(struct mmc_host *host);
>  void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card);
>
> --
> 1.9.1
>

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux