Re: [PATCH V12 18/23] mmc: sdhci-uhs2: add request() and others

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

 



On Tue, Oct 3, 2023 at 8:15 PM Ulf Hansson <ulf.hansson@xxxxxxxxxx> wrote:
>
> On Fri, 15 Sept 2023 at 11:44, Victor Shih <victorshihgli@xxxxxxxxx> wrote:
> >
> > From: Victor Shih <victor.shih@xxxxxxxxxxxxxxxxxxx>
> >
> > This is a sdhci version of mmc's request operation.
> > It covers both UHS-I and UHS-II.
>
> Okay, but again, please elaborate on why we need/want this.
>

Hi, Ulf

I will try to update this in version 13.

Thanks, Victor Shih

> >
> > Signed-off-by: Ben Chuang <ben.chuang@xxxxxxxxxxxxxxxxxxx>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@xxxxxxxxxx>
> > Signed-off-by: Victor Shih <victor.shih@xxxxxxxxxxxxxxxxxxx>
> > ---
> >
> > Updates in V11:
> >  - Drop the check mmc_card_uhs2_hd_mode(host->mmc)
> >    in sdhci_uhs2_set_transfer_mode().
> >
> > Updates in V10:
> >  - Use tmode_half_duplex to instead of uhs2_tmode0_flag
> >    in sdhci_uhs2_set_transfer_mode().
> >
> > Updates in V9:
> >  - Modify the annotations in __sdhci_uhs2_send_command().
> >
> > Updates in V8:
> >  - Adjust the position of matching brackets in
> >    sdhci_uhs2_send_command_retry().
> >  - Modify CameCase definition in __sdhci_uhs2_finish_command().
> >  - Modify error message in __sdhci_uhs2_finish_command().
> >  - sdhci_uhs2_send_command_retry() to instead of sdhci_uhs2_send_command()
> >    in sdhci_uhs2_request().
> >  - Use sdhci_uhs2_mode() to simplify code in sdhci_uhs2_request_atomic().
> >  - Add forward declaration for sdhci_send_command().
> >
> > Updates in V7:
> >  - Cancel export state of some functions.
> >  - Remove unnecessary whitespace changes.
> >
> > Updates in V6:
> >  - Add uhs2_dev_cmd() to simplify code.
> >  - Remove unnecessary functions.
> >  - Cancel export state of some functions.
> >  - Drop use CONFIG_MMC_DEBUG().
> >  - Wrap at 100 columns in some functions.
> >
> > ---
> >
> >  drivers/mmc/host/sdhci-uhs2.c | 412 ++++++++++++++++++++++++++++++++++
> >  drivers/mmc/host/sdhci.c      |  49 ++--
> >  drivers/mmc/host/sdhci.h      |   8 +
> >  3 files changed, 454 insertions(+), 15 deletions(-)
> >
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 09b86fec9f7b..1f8d527424fd 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
>
> [...]
>
> > +
> > +static void __sdhci_uhs2_send_command(struct sdhci_host *host, struct mmc_command *cmd)
> > +{
> > +       int i, j;
> > +       int cmd_reg;
> > +
> > +       i = 0;
> > +       sdhci_writel(host,
> > +                    ((u32)cmd->uhs2_cmd->arg << 16) |
> > +                               (u32)cmd->uhs2_cmd->header,
> > +                    SDHCI_UHS2_CMD_PACKET + i);
> > +       i += 4;
> > +
> > +       /*
> > +        * Per spec, payload (config) should be MSB before sending out.
> > +        * But we don't need convert here because had set payload as
> > +        * MSB when preparing config read/write commands.
> > +        */
> > +       for (j = 0; j < cmd->uhs2_cmd->payload_len / sizeof(u32); j++) {
> > +               sdhci_writel(host, *(cmd->uhs2_cmd->payload + j), SDHCI_UHS2_CMD_PACKET + i);
> > +               i += 4;
> > +       }
> > +
> > +       for ( ; i < SDHCI_UHS2_CMD_PACK_MAX_LEN; i += 4)
> > +               sdhci_writel(host, 0, SDHCI_UHS2_CMD_PACKET + i);
> > +
> > +       DBG("UHS2 CMD packet_len = %d.\n", cmd->uhs2_cmd->packet_len);
> > +       for (i = 0; i < cmd->uhs2_cmd->packet_len; i++)
> > +               DBG("UHS2 CMD_PACKET[%d] = 0x%x.\n", i,
> > +                   sdhci_readb(host, SDHCI_UHS2_CMD_PACKET + i));
>
> We are ignoring what we just read. Isn't there something we need to verify?
>
> Moreover, the whole thing with i,j and the +4 thing above looks a bit
> odd to me. I am not sure whether the above can be simplified, but I
> leave that for you to have a second look at.
>

Hi, Ulf

Sorry, I don't have any ideas on this, could you please give me some ideas?

Thanks, Victor Shih

> > +
> > +       cmd_reg = FIELD_PREP(SDHCI_UHS2_CMD_PACK_LEN_MASK, cmd->uhs2_cmd->packet_len);
> > +       if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC)
> > +               cmd_reg |= SDHCI_UHS2_CMD_DATA;
> > +       if (cmd->opcode == MMC_STOP_TRANSMISSION)
> > +               cmd_reg |= SDHCI_UHS2_CMD_CMD12;
> > +
> > +       /* UHS2 Native ABORT */
> > +       if ((cmd->uhs2_cmd->header & UHS2_NATIVE_PACKET) &&
> > +           (uhs2_dev_cmd(cmd) == UHS2_DEV_CMD_TRANS_ABORT))
> > +               cmd_reg |= SDHCI_UHS2_CMD_TRNS_ABORT;
> > +
> > +       /* UHS2 Native DORMANT */
> > +       if ((cmd->uhs2_cmd->header & UHS2_NATIVE_PACKET) &&
> > +           (uhs2_dev_cmd(cmd) == UHS2_DEV_CMD_GO_DORMANT_STATE))
> > +               cmd_reg |= SDHCI_UHS2_CMD_DORMANT;
> > +
> > +       DBG("0x%x is set to UHS2 CMD register.\n", cmd_reg);
> > +
> > +       sdhci_writew(host, cmd_reg, SDHCI_UHS2_CMD);
> > +}
>
> [...]
>
> > +static bool sdhci_uhs2_send_command_retry(struct sdhci_host *host,
> > +                                         struct mmc_command *cmd,
> > +                                         unsigned long flags)
> > +       __releases(host->lock)
> > +       __acquires(host->lock)
> > +{
> > +       struct mmc_command *deferred_cmd = host->deferred_cmd;
> > +       int timeout = 10; /* Approx. 10 ms */
> > +       bool present;
>
> Why do we need a retry mechanism at this level? The mmc core sometimes
> retries commands when it seems reasonable, why isn't that sufficient?
>

Hi, Ulf

According to my testing experience, this function is sometimes called
to resend the command.

Thanks, Victor Shih

> > +
> > +       while (!sdhci_uhs2_send_command(host, cmd)) {
> > +               if (!timeout--) {
> > +                       pr_err("%s: Controller never released inhibit bit(s).\n",
> > +                              mmc_hostname(host->mmc));
> > +                       sdhci_dumpregs(host);
> > +                       cmd->error = -EIO;
> > +                       return false;
> > +               }
> > +
> > +               spin_unlock_irqrestore(&host->lock, flags);
> > +
> > +               usleep_range(1000, 1250);
> > +
> > +               present = host->mmc->ops->get_cd(host->mmc);
> > +
> > +               spin_lock_irqsave(&host->lock, flags);
> > +
> > +               /* A deferred command might disappear, handle that */
> > +               if (cmd == deferred_cmd && cmd != host->deferred_cmd)
> > +                       return true;
> > +
> > +               if (sdhci_present_error(host, cmd, present))
> > +                       return false;
> > +       }
>
> If the retry is needed, would it be possible to convert into using
> read_poll_timeout() for the above while loop instead? If so, please
> make that conversion.
>

Hi, Ulf

I have no idea how to use  read_poll_timeout() instead of while loop,
because there are still other functions running inside the while loop.
Can you give me some ideas?

Thanks, Victor Shih

> > +
> > +       if (cmd == host->deferred_cmd)
> > +               host->deferred_cmd = NULL;
> > +
> > +       return true;
> > +}
> > +
> > +static void __sdhci_uhs2_finish_command(struct sdhci_host *host)
> > +{
> > +       struct mmc_command *cmd = host->cmd;
> > +       u8 resp;
> > +       u8 ecode;
> > +       bool breada0 = 0;
>
> Nitpick: Maybe find some better variable names. Like error_code...
>

Hi, Ulf

I will update this in version 13.

Thanks, Victor Shih

> > +       int i;
> > +
> > +       if (host->mmc->flags & MMC_UHS2_SD_TRAN) {
> > +               resp = sdhci_readb(host, SDHCI_UHS2_RESPONSE + 2);
> > +               if (resp & UHS2_RES_NACK_MASK) {
> > +                       ecode = (resp >> UHS2_RES_ECODE_POS) & UHS2_RES_ECODE_MASK;
> > +                       pr_err("%s: NACK response, ECODE=0x%x.\n", mmc_hostname(host->mmc), ecode);
> > +               }
> > +               breada0 = 1;
> > +       }
> > +
> > +       if (cmd->uhs2_resp &&
> > +           cmd->uhs2_resp_len && cmd->uhs2_resp_len <= 20) {
> > +               /* Get whole response of some native CCMD, like
> > +                * DEVICE_INIT, ENUMERATE.
> > +                */
> > +               for (i = 0; i < cmd->uhs2_resp_len; i++)
> > +                       cmd->uhs2_resp[i] = sdhci_readb(host, SDHCI_UHS2_RESPONSE + i);
> > +       } else {
> > +               /* Get SD CMD response and Payload for some read
> > +                * CCMD, like INQUIRY_CFG.
> > +                */
> > +               /* Per spec (p136), payload field is divided into
> > +                * a unit of DWORD and transmission order within
> > +                * a DWORD is big endian.
> > +                */
> > +               if (!breada0)
> > +                       sdhci_readl(host, SDHCI_UHS2_RESPONSE);
> > +               for (i = 4; i < 20; i += 4) {
>
> Again we do sdhci_readl above but just ignore the data. I assume
> that's deliberate, as we are probably just interested in the remaining
> pieces.
>
> Moreover, the whole thing with +4 things continues to look a bit odd
> to me. I am not sure whether it can be simplified, but I leave that
> for you to have a second look at.
>

Hi, Ulf

Sorry, I don't have any ideas on this, could you please give me some ideas?

Thanks, Victor Shih

> > +                       cmd->resp[i / 4 - 1] =
> > +                               (sdhci_readb(host,
> > +                                            SDHCI_UHS2_RESPONSE + i) << 24) |
> > +                               (sdhci_readb(host,
> > +                                            SDHCI_UHS2_RESPONSE + i + 1)
> > +                                       << 16) |
> > +                               (sdhci_readb(host,
> > +                                            SDHCI_UHS2_RESPONSE + i + 2)
> > +                                       << 8) |
> > +                               sdhci_readb(host, SDHCI_UHS2_RESPONSE + i + 3);
> > +               }
> > +       }
> > +}
>
> [...]
>
> > +
> > +void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
>
> static void
>

Hi, Ulf

I will try to update this in version 13.

Thanks, Victor Shih

> > +{
> > +       struct sdhci_host *host = mmc_priv(mmc);
> > +       struct mmc_command *cmd;
> > +       unsigned long flags;
> > +       bool present;
> > +
> > +       if (!(sdhci_uhs2_mode(host))) {
> > +               sdhci_request(mmc, mrq);
> > +               return;
> > +       }
> > +
> > +       mrq->stop = NULL;
> > +       mrq->sbc = NULL;
> > +       if (mrq->data)
> > +               mrq->data->stop = NULL;
> > +
> > +       /* Firstly check card presence */
> > +       present = mmc->ops->get_cd(mmc);
> > +
> > +       spin_lock_irqsave(&host->lock, flags);
> > +
> > +       if (sdhci_present_error(host, mrq->cmd, present))
> > +               goto out_finish;
> > +
> > +       cmd = mrq->cmd;
> > +
> > +       if (!sdhci_uhs2_send_command_retry(host, cmd, flags))
> > +               goto out_finish;
> > +
> > +       spin_unlock_irqrestore(&host->lock, flags);
> > +
> > +       return;
> > +
> > +out_finish:
> > +       sdhci_finish_mrq(host, mrq);
> > +       spin_unlock_irqrestore(&host->lock, flags);
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_request);
>
> Drop this, it's not used outside this module.
>

Hi, Ulf

I will try to update this in version 13.

Thanks, Victor Shih

> > +
> > +int sdhci_uhs2_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq)
>
> This function is entirely unused. Did you actually test this with an
> hsq enabled host? Or perhaps you have just added this for
> completeness?
>

Hi, Ulf

I will drop this in version 13.

Thanks, Victor Shih

> > +{
> > +       struct sdhci_host *host = mmc_priv(mmc);
> > +       struct mmc_command *cmd;
> > +       unsigned long flags;
> > +       int ret = 0;
> > +
> > +       if (!sdhci_uhs2_mode(host))
> > +               return sdhci_request_atomic(mmc, mrq);
> > +
> > +       spin_lock_irqsave(&host->lock, flags);
> > +
> > +       if (sdhci_present_error(host, mrq->cmd, true)) {
> > +               sdhci_finish_mrq(host, mrq);
> > +               goto out_finish;
> > +       }
> > +
> > +       cmd = mrq->cmd;
> > +
> > +       /*
> > +        * The HSQ may send a command in interrupt context without polling
> > +        * the busy signaling, which means we should return BUSY if controller
> > +        * has not released inhibit bits to allow HSQ trying to send request
> > +        * again in non-atomic context. So we should not finish this request
> > +        * here.
> > +        */
> > +       if (!sdhci_uhs2_send_command(host, cmd))
> > +               ret = -EBUSY;
> > +
> > +out_finish:
> > +       spin_unlock_irqrestore(&host->lock, flags);
> > +       return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_request_atomic);
> > +
>
> [...]
>
> Kind regards
> Uffe





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

  Powered by Linux