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