Re: [PATCH V22 07/22] mmc: core: Support UHS-II card control and access

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

 



On Mon, Oct 7, 2024 at 11:36 PM Ulf Hansson <ulf.hansson@xxxxxxxxxx> wrote:
>
> On Fri, 13 Sept 2024 at 12:29, Victor Shih <victorshihgli@xxxxxxxxx> wrote:
> >
> > From: Victor Shih <victor.shih@xxxxxxxxxxxxxxxxxxx>
> >
> > Embed UHS-II access/control functionality into the MMC request
> > processing flow.
> >
> > Signed-off-by: Ulf Hansson <ulf.hansson@xxxxxxxxxx>
> > Signed-off-by: Jason Lai <jason.lai@xxxxxxxxxxxxxxxxxxx>
> > Signed-off-by: Victor Shih <victor.shih@xxxxxxxxxxxxxxxxxxx>
> > ---
> >
> > Updates in V16:
> >  - Separate the Error Recovery mechanism into a separate patch#8.
> >
> > Updates in V15:
> >  - Move struct uhs2_command uhs2_cmd to struct mmc_request and
> >    modify whatever other changers to make it work.
> >  - Refer the SD Host Controller Standard Specification Section 3.10
> >    to add Error Recovery mechanism to recover the command error.
> >
> > Updates in V13:
> >  - Separate __mmc_go_idle() into one patch for re-factorring the code.
> >  - Move mmc_decode_scr declaration to sd.h.
> >  - Ues uhs2_sd_tran to stead MMC_UHS2_SD_TRAN.
> >  - Drop unnecessary comment.
> >
> > Updates in V12:
> >  - Use mmc_op_multi() to check DCMD which supports multi read/write
> >    in mmc_uhs2_prepare_cmd().
> >
> > Updates in V10:
> >  - Move some definitions of PatchV9[02/23] to PatchV10[06/23].
> >  - Move some definitions of PatchV9[05/23] to PatchV10[06/23].
> >  - Drop do_multi in the mmc_blk_rw_rq_prep().
> >  - Use tmode_half_duplex to instead of uhs2_tmode0_flag.
> >  - Move entire control of the tmode into mmc_uhs2_prepare_cmd().
> >
> > Updates in V8:
> >  - Add MMC_UHS2_SUPPORT to be cleared in sd_uhs2_detect().
> >  - Modify return value in sd_uhs2_attach().
> >
> > Updates in V7:
> >  - Add mmc_uhs2_card_prepare_cmd helper function in sd_ops.h.
> >  - Drop uhs2_state in favor of ios->timing.
> >  - Remove unnecessary functions.
> >
> > ---
> >
> >  drivers/mmc/core/core.c    |    6 +-
> >  drivers/mmc/core/sd.c      |   10 +-
> >  drivers/mmc/core/sd.h      |    5 +
> >  drivers/mmc/core/sd_ops.c  |    9 +
> >  drivers/mmc/core/sd_ops.h  |   13 +
> >  drivers/mmc/core/sd_uhs2.c | 1100 ++++++++++++++++++++++++++++++++++--
> >  include/linux/mmc/core.h   |   17 +
> >  include/linux/mmc/host.h   |   15 +
> >  8 files changed, 1136 insertions(+), 39 deletions(-)
> >
> > diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> > index 8b8aff131f8b..1841a2190571 100644
> > --- a/drivers/mmc/core/core.c
> > +++ b/drivers/mmc/core/core.c
> > @@ -351,6 +351,8 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
> >         if (err)
> >                 return err;
> >
> > +       mmc_uhs2_card_prepare_cmd(host, mrq);
> > +
> >         led_trigger_event(host->led, LED_FULL);
> >         __mmc_start_request(host, mrq);
> >
> > @@ -450,6 +452,8 @@ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
> >         if (err)
> >                 goto out_err;
> >
> > +       mmc_uhs2_card_prepare_cmd(host, mrq);
> > +
> >         err = host->cqe_ops->cqe_request(host, mrq);
> >         if (err)
> >                 goto out_err;
> > @@ -1132,7 +1136,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
> >                 return 0;
> >         }
> >
> > -       if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) {
> > +       if (!mmc_card_uhs2(host) && host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) {
> >                 bit = ffs(ocr) - 1;
> >                 ocr &= 3 << bit;
> >                 mmc_power_cycle(host, ocr);
> > diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> > index 12fe282bea77..d5576a2f4435 100644
> > --- a/drivers/mmc/core/sd.c
> > +++ b/drivers/mmc/core/sd.c
> > @@ -194,7 +194,7 @@ static int mmc_decode_csd(struct mmc_card *card)
> >  /*
> >   * Given a 64-bit response, decode to our card SCR structure.
> >   */
> > -static int mmc_decode_scr(struct mmc_card *card)
> > +int mmc_decode_scr(struct mmc_card *card)
> >  {
> >         struct sd_scr *scr = &card->scr;
> >         unsigned int scr_struct;
> > @@ -894,7 +894,7 @@ int mmc_sd_get_csd(struct mmc_card *card)
> >         return 0;
> >  }
> >
> > -static int mmc_sd_get_ro(struct mmc_host *host)
> > +int mmc_sd_get_ro(struct mmc_host *host)
> >  {
> >         int ro;
> >
> > @@ -1623,7 +1623,7 @@ static void mmc_sd_detect(struct mmc_host *host)
> >         }
> >  }
> >
> > -static int sd_can_poweroff_notify(struct mmc_card *card)
> > +int sd_can_poweroff_notify(struct mmc_card *card)
> >  {
> >         return card->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY;
> >  }
> > @@ -1651,7 +1651,7 @@ static int sd_busy_poweroff_notify_cb(void *cb_data, bool *busy)
> >         return 0;
> >  }
> >
> > -static int sd_poweroff_notify(struct mmc_card *card)
> > +int sd_poweroff_notify(struct mmc_card *card)
> >  {
> >         struct sd_busy_data cb_data;
> >         u8 *reg_buf;
> > @@ -1699,7 +1699,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
> >         if (mmc_card_suspended(card))
> >                 goto out;
> >
> > -       if (sd_can_poweroff_notify(card))
> > +       if (mmc_sd_can_poweroff_notify(card))
>
> There is no need to change this. Please stick with sd_can_poweroff_notify().
>

Hi, Ulf

I will update it in the next version.

Thanks, Victor Shih

> >                 err = sd_poweroff_notify(card);
> >         else if (!mmc_host_is_spi(host))
> >                 err = mmc_deselect_cards(host);
> > diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
> > index fe6dd46927a4..49afaef269cd 100644
> > --- a/drivers/mmc/core/sd.h
> > +++ b/drivers/mmc/core/sd.h
> > @@ -11,10 +11,15 @@ struct mmc_card;
> >
> >  int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
> >  int mmc_sd_get_csd(struct mmc_card *card);
> > +int mmc_decode_scr(struct mmc_card *card);
> > +int mmc_sd_get_ro(struct mmc_host *host);
> >  void mmc_decode_cid(struct mmc_card *card);
> >  int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
> >         bool reinit);
> >  unsigned mmc_sd_get_max_clock(struct mmc_card *card);
> >  int mmc_sd_switch_hs(struct mmc_card *card);
> >
> > +int sd_can_poweroff_notify(struct mmc_card *card);
> > +int sd_poweroff_notify(struct mmc_card *card);
> > +
> >  #endif
> > diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
> > index f93c392040ae..5cd1216edf0d 100644
> > --- a/drivers/mmc/core/sd_ops.c
> > +++ b/drivers/mmc/core/sd_ops.c
> > @@ -41,6 +41,15 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
> >         if (WARN_ON(card && card->host != host))
> >                 return -EINVAL;
> >
> > +       /*
> > +        * UHS2 packet has APP bit so only set APP_CMD flag here.
> > +        * Will set the APP bit when assembling UHS2 packet.
> > +        */
> > +       if (host->uhs2_sd_tran) {
> > +               host->uhs2_app_cmd = true;
> > +               return 0;
> > +       }
> > +
> >         cmd.opcode = MMC_APP_CMD;
> >
> >         if (card) {
> > diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
> > index 7667fc223b74..e3af68a52de8 100644
> > --- a/drivers/mmc/core/sd_ops.h
> > +++ b/drivers/mmc/core/sd_ops.h
> > @@ -11,6 +11,7 @@
> >  #include <linux/types.h>
> >
> >  struct mmc_card;
> > +struct mmc_command;
> >  struct mmc_host;
> >
> >  int mmc_app_set_bus_width(struct mmc_card *card, int width);
> > @@ -21,6 +22,18 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
> >  int mmc_app_send_scr(struct mmc_card *card);
> >  int mmc_app_sd_status(struct mmc_card *card, void *ssr);
> >  int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
> > +void mmc_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq);
> > +
> > +static inline void mmc_uhs2_card_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq)
> > +{
> > +       if (host->uhs2_sd_tran)
> > +               mmc_uhs2_prepare_cmd(host, mrq);
> > +}
>
> Please remove this inline function and just check "host->uhs2_sd_tran"
> in mmc_start_request() and mmc_cqe_start_req(). If "uhs2_sd_tran" is
> set, then just call mmc_uhs2_prepare_cmd() directly.
>

Hi, Ulf

I will update it in the next version.

Thanks, Victor Shih

> > +
> > +static inline int mmc_sd_can_poweroff_notify(struct mmc_card *card)
> > +{
> > +       return card->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY;
> > +}
>
> This function is a copy of sd_can_poweroff_notify(). Please use
> sd_can_poweroff_notify() and remove mmc_sd_can_poweroff_notify().
>

Hi, Ulf

I will update it in the next version.

Thanks, Victor Shih

> >
> >  #endif
> >
> > diff --git a/drivers/mmc/core/sd_uhs2.c b/drivers/mmc/core/sd_uhs2.c
> > index beb2541338ff..85939a2582dc 100644
> > --- a/drivers/mmc/core/sd_uhs2.c
> > +++ b/drivers/mmc/core/sd_uhs2.c
> > @@ -1,23 +1,51 @@
> >  // SPDX-License-Identifier: GPL-2.0-only
> >  /*
> >   * Copyright (C) 2021 Linaro Ltd
> > - *
> >   * Author: Ulf Hansson <ulf.hansson@xxxxxxxxxx>
> >   *
> > + * Copyright (C) 2014 Intel Corp, All Rights Reserved.
> > + * Author: Yi Sun <yi.y.sun@xxxxxxxxx>
> > + *
> > + * Copyright (C) 2020 Genesys Logic, Inc.
> > + * Authors: Ben Chuang <ben.chuang@xxxxxxxxxxxxxxxxxxx>
> > + *
> > + * Copyright (C) 2020 Linaro Limited
> > + * Author: AKASHI Takahiro <takahiro.akashi@xxxxxxxxxx>
> > + *
> > + * Copyright (C) 2022 Genesys Logic, Inc.
> > + * Authors: Jason Lai <jason.lai@xxxxxxxxxxxxxxxxxxx>
> > + *
> > + * Copyright (C) 2023 Genesys Logic, Inc.
> > + * Authors: Victor Shih <victor.shih@xxxxxxxxxxxxxxxxxxx>
> > + *
> >   * Support for SD UHS-II cards
> >   */
> >  #include <linux/err.h>
> > +#include <linux/pm_runtime.h>
> >
> >  #include <linux/mmc/host.h>
> >  #include <linux/mmc/card.h>
> > +#include <linux/mmc/mmc.h>
> > +#include <linux/mmc/sd.h>
> > +#include <linux/mmc/sd_uhs2.h>
> >
> > +#include "card.h"
> >  #include "core.h"
> >  #include "bus.h"
> >  #include "sd.h"
> > +#include "sd_ops.h"
> >  #include "mmc_ops.h"
> >
> > +#define UHS2_WAIT_CFG_COMPLETE_PERIOD_US  (1 * 1000)
> > +#define UHS2_WAIT_CFG_COMPLETE_TIMEOUT_MS 100
> > +
> >  static const unsigned int sd_uhs2_freqs[] = { 52000000, 26000000 };
> >
> > +struct sd_uhs2_wait_active_state_data {
> > +       struct mmc_host *host;
> > +       struct mmc_command *cmd;
> > +};
> > +
> >  static int sd_uhs2_power_up(struct mmc_host *host)
> >  {
> >         int err;
> > @@ -42,12 +70,46 @@ static int sd_uhs2_power_off(struct mmc_host *host)
> >
> >         host->ios.vdd = 0;
> >         host->ios.clock = 0;
> > -       host->ios.timing = MMC_TIMING_LEGACY;
> > +       /* Must set UHS2 timing to identify UHS2 mode */
> > +       host->ios.timing = MMC_TIMING_UHS2_SPEED_A;
>
> The only code that seems to check for MMC_TIMING_UHS2_SPEED_A is
> __sdhci_uhs2_set_ios() (that is added later in the series). Moreover
> that code only cares about MMC_TIMING_UHS2_SPEED_A if "ios->power_mode
> != MMC_POWER_OFF".
>
> In other words, I think it should be okay to keep MMC_TIMING_LEGACY here, right?
>

Hi, Ulf

I will update it in the next version.

Thanks, Victor Shih

> >         host->ios.power_mode = MMC_POWER_OFF;
> > +       host->uhs2_sd_tran = false;
> >
> >         return host->ops->uhs2_control(host, UHS2_SET_IOS);
> >  }
> >
>
> [...]
>
> >  /*
> >   * Allocate the data structure for the mmc_card and run the UHS-II specific
> >   * initialization sequence.
> >   */
> > -static int sd_uhs2_init_card(struct mmc_host *host)
> > +static int sd_uhs2_init_card(struct mmc_host *host, struct mmc_card *oldcard)
> >  {
> >         struct mmc_card *card;
> >         u32 node_id;
> > @@ -131,9 +818,14 @@ static int sd_uhs2_init_card(struct mmc_host *host)
> >         if (err)
> >                 return err;
> >
> > -       card = mmc_alloc_card(host, &sd_type);
> > -       if (IS_ERR(card))
> > -               return PTR_ERR(card);
> > +       if (oldcard) {
> > +               card = oldcard;
> > +       } else {
> > +               card = mmc_alloc_card(host, &sd_type);
> > +               if (IS_ERR(card))
> > +                       return PTR_ERR(card);
> > +       }
> > +       host->card = card;
>
> Why do you need to assign the host->card at this point, isn't it okay
> to do that later where it was originally?
>
> Anyway, there is a more important comment a few lines below that also
> relates to this.
>

Hi, Ulf

I will update it in the next version.

Thanks, Victor Shih

> >
> >         card->uhs2_config.node_id = node_id;
> >         card->type = MMC_TYPE_SD;
> > @@ -146,18 +838,189 @@ static int sd_uhs2_init_card(struct mmc_host *host)
> >         if (err)
> >                 goto err;
> >
> > -       host->card = card;
> > +       /* If change speed to Range B, need to GO_DORMANT_STATE */
> > +       if (host->ios.timing == MMC_TIMING_UHS2_SPEED_B ||
> > +           host->ios.timing == MMC_TIMING_UHS2_SPEED_B_HD) {
> > +               err = sd_uhs2_go_dormant_state(host, node_id);
> > +               if (err)
> > +                       goto err;
> > +       }
> > +
> > +       host->uhs2_sd_tran = true;
> > +
> >         return 0;
> >
> >  err:
> > -       mmc_remove_card(card);
> > +       if (!oldcard)
> > +               mmc_remove_card(card);
> > +       else
> > +               sd_uhs2_remove(host);
>
> This doesn't work. If there is an "oldcard", that's because we are
> trying to re-initialize the card during a resume. If we fail to
> re-initialize it we must not remove the oldcard in this path, but
> rather just return/propagate an error code.
>
> Instead, the oldcard should be removed from the mmc_rescan() work when
> it realizes that the call to "host->bus_ops->detect(host)" fails (and
> it must fail then).
>

Hi, Ulf

I will update it in the next version.

Thanks, Victor Shih

> >         return err;
> >  }
> >
> > -static void sd_uhs2_remove(struct mmc_host *host)
> > +/*
> > + * Initialize the UHS-II card through the SD-TRAN transport layer. This enables
> > + * commands/requests to be backwards compatible through the legacy SD protocol.
> > + * UHS-II cards has a specific power limit specified for VDD1/VDD2, that should
> > + * be set through a legacy CMD6. Note that, the power limit that becomes set,
> > + * survives a soft reset through the GO_DORMANT_STATE command.
> > + */
> > +static int sd_uhs2_legacy_init(struct mmc_host *host, struct mmc_card *card)
> >  {
> > -       mmc_remove_card(host->card);
> > -       host->card = NULL;
> > +       int err;
> > +       u32 cid[4];
> > +       u32 ocr;
> > +       u32 rocr;
> > +       u8  *status;
> > +       int ro;
> > +
> > +       /* Send CMD0 to reset SD card */
> > +       err = __mmc_go_idle(host);
> > +       if (err)
> > +               return err;
> > +
> > +       mmc_delay(1);
> > +
> > +       /* Send CMD8 to communicate SD interface operation condition */
> > +       err = mmc_send_if_cond(host, host->ocr_avail);
> > +       if (err) {
> > +               dev_warn(mmc_dev(host), "CMD8 error\n");
> > +               goto err;
> > +       }
> > +
> > +       /*
> > +        * Probe SD card working voltage.
> > +        */
> > +       err = mmc_send_app_op_cond(host, 0, &ocr);
> > +       if (err)
> > +               goto err;
> > +
> > +       card->ocr = ocr;
> > +
> > +       /*
> > +        * Some SD cards claims an out of spec VDD voltage range. Let's treat
> > +        * these bits as being in-valid and especially also bit7.
> > +        */
> > +       ocr &= ~0x7FFF;
> > +       rocr = mmc_select_voltage(host, ocr);
> > +       /*
> > +        * Some cards have zero value of rocr in UHS-II mode. Assign host's
> > +        * ocr value to rocr.
> > +        */
> > +       if (!rocr)
> > +               rocr = host->ocr_avail;
> > +
> > +       rocr |= (SD_OCR_CCS | SD_OCR_XPC);
> > +
> > +       /* Wait SD power on ready */
> > +       ocr = rocr;
> > +
> > +       err = mmc_send_app_op_cond(host, ocr, &rocr);
> > +       if (err)
> > +               goto err;
> > +
> > +       err = mmc_send_cid(host, cid);
> > +       if (err)
> > +               goto err;
> > +
> > +       memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
> > +       mmc_decode_cid(card);
> > +
> > +       /*
> > +        * For native busses:  get card RCA and quit open drain mode.
> > +        */
> > +       err = mmc_send_relative_addr(host, &card->rca);
> > +       if (err)
> > +               goto err;
> > +
> > +       err = mmc_sd_get_csd(card);
> > +       if (err)
> > +               goto err;
> > +
> > +       /*
> > +        * Select card, as all following commands rely on that.
> > +        */
> > +       err = mmc_select_card(card);
> > +       if (err)
> > +               goto err;
> > +
> > +       /*
> > +        * Fetch SCR from card.
> > +        */
> > +       err = mmc_app_send_scr(card);
> > +       if (err)
> > +               goto err;
> > +
> > +       err = mmc_decode_scr(card);
> > +       if (err)
> > +               goto err;
> > +
> > +       /*
> > +        * Switch to high power consumption mode.
> > +        * Even switch failed, sd card can still work at lower power consumption mode, but
> > +        * performance will be lower than high power consumption mode.
> > +        */
> > +       status = kmalloc(64, GFP_KERNEL);
> > +       if (!status)
> > +               return -ENOMEM;
> > +
> > +       if (!(card->csd.cmdclass & CCC_SWITCH)) {
> > +               pr_warn("%s: card lacks mandatory switch function, performance might suffer\n",
> > +                       mmc_hostname(card->host));
> > +       } else {
> > +               /* send CMD6 to set Maximum Power Consumption to get better performance */
> > +               err = mmc_sd_switch(card, 0, 3, SD4_SET_POWER_LIMIT_1_80W, status);
> > +               if (!err)
> > +                       err = mmc_sd_switch(card, 1, 3, SD4_SET_POWER_LIMIT_1_80W, status);
> > +
> > +               err = 0;
> > +       }
> > +
> > +       /*
> > +        * Check if read-only switch is active.
> > +        */
> > +       ro = mmc_sd_get_ro(host);
> > +       if (ro < 0) {
> > +               pr_warn("%s: host does not support read-only switch, assuming write-enable\n",
> > +                       mmc_hostname(host));
> > +       } else if (ro > 0) {
> > +               mmc_card_set_readonly(card);
> > +       }
>
> Some of the above commands in sd_uhs2_legacy_init() are only needed
> during the first initialization of the card. When re-initializing a
> card during a resume, we can skip several of these steps as they are
> simply unnecessary.
>
> However, to validate that it's the same card that remains inserted
> during re-initialization, we need to read the CID register and compare
> it against the CID register that we have stored earlier in
> card->raw_cid. Please have a look at mmc_sd_init_card() to see how
> this works for legacy SD cards.
>

Hi, Ulf

I will update it in the next version.

Thanks, Victor Shih

> > +
> > +       /*
> > +        * NOTE:
> > +        * Should we read Externsion Register to check power notification feature here?
> > +        */
>
> Yes, this is needed too.
>
> > +
> > +       kfree(status);
> > +
> > +       return 0;
> > +
> > +err:
> > +       sd_uhs2_remove(host);
>
> Again, this doesn't work if we are re-initializing the card during a
> resume. The card must only be removed if this is the first
> initialization of the card - otherwise the removal needs to be managed
> by the mmc_rescan() work.
>

Hi, Ulf

I will update it in the next version.

Thanks, Victor Shih

> > +       return err;
> > +}
> > +
> > +static int sd_uhs2_reinit(struct mmc_host *host)
> > +{
> > +       struct mmc_card *card = host->card;
> > +       int err;
> > +
> > +       sd_uhs2_power_up(host);
> > +       err = sd_uhs2_phy_init(host);
> > +       if (err)
> > +               return err;
> > +
> > +       err = sd_uhs2_init_card(host, card);
> > +       if (err)
> > +               return err;
> > +
> > +       err = sd_uhs2_legacy_init(host, card);
> > +       if (err)
> > +               return err;
> > +
> > +       mmc_card_set_present(card);
>
> Drop this, it's already managed when calling mmc_add_card() and that
> should be sufficient.
>

Hi, Ulf

I will update it in the next version.

Thanks, Victor Shih

> > +       return err;
> >  }
> >
> >  static int sd_uhs2_alive(struct mmc_host *host)
> > @@ -179,38 +1042,194 @@ static void sd_uhs2_detect(struct mmc_host *host)
> >                 mmc_claim_host(host);
> >                 mmc_detach_bus(host);
> >                 sd_uhs2_power_off(host);
> > +               /* Remove UHS2 timing to indicate the end of UHS2 mode */
> > +               host->ios.timing = MMC_TIMING_LEGACY;
>
> If my earlier comment for sd_uhs2_power_off() was correct, this part
> should be dropped too.
>

Hi, Ulf

I will update it in the next version.

Thanks, Victor Shih

> >                 mmc_release_host(host);
> >         }
> >  }
> >
> > +static int _sd_uhs2_suspend(struct mmc_host *host)
> > +{
> > +       struct mmc_card *card = host->card;
> > +       int err = 0;
> > +
> > +       mmc_claim_host(host);
> > +
> > +       if (mmc_card_suspended(card))
> > +               goto out;
> > +
> > +       if (mmc_sd_can_poweroff_notify(card))
>
> Use sd_can_poweroff_notify() instead.
>

Hi, Ulf

I will update it in the next version.

Thanks, Victor Shih

> > +               err = sd_poweroff_notify(card);
> > +
> > +       if (!err) {
> > +               sd_uhs2_power_off(host);
> > +               mmc_card_set_suspended(card);
> > +       }
> > +
> > +out:
> > +       mmc_release_host(host);
> > +       return err;
> > +}
> > +
>
> [...]
>
> >
> > @@ -237,7 +1256,7 @@ static int sd_uhs2_attach(struct mmc_host *host)
> >         if (err)
> >                 goto err;
> >
> > -       err = sd_uhs2_init_card(host);
> > +       err = sd_uhs2_init_card(host, NULL);
> >         if (err)
> >                 goto err;
> >
> > @@ -254,21 +1273,33 @@ static int sd_uhs2_attach(struct mmc_host *host)
> >                 goto remove_card;
> >
> >         mmc_claim_host(host);
> > +
> >         return 0;
> >
> >  remove_card:
> > -       mmc_remove_card(host->card);
> > -       host->card = NULL;
> > +       sd_uhs2_remove(host);
> >         mmc_claim_host(host);
> > -       mmc_detach_bus(host);
> > +
> >  err:
> > +       mmc_detach_bus(host);
> >         sd_uhs2_power_off(host);
> > +       /* Remove UHS2 timing to indicate the end of UHS2 mode */
> > +       host->ios.timing = MMC_TIMING_LEGACY;
>
> Again, see my earlier comment for sd_uhs2_power_off(). Can this part be dropped?
>

Hi, Ulf

I will update it in the next version.

Thanks, Victor Shih

> >         return err;
> >  }
> >
> > +/**
> > + * mmc_attach_sd_uhs2 - select UHS2 interface
> > + * @host: MMC host
> > + *
> > + * Try to select UHS2 interface and initialize the bus for a given
> > + * frequency, @freq.
> > + *
> > + * Return:     0 on success, non-zero error on failure
> > + */
> >  int mmc_attach_sd_uhs2(struct mmc_host *host)
> >  {
> > -       int i, err = 0;
> > +       int i, err;
> >
> >         if (!(host->caps2 & MMC_CAP2_SD_UHS2))
> >                 return -EOPNOTSUPP;
> > @@ -283,6 +1314,9 @@ int mmc_attach_sd_uhs2(struct mmc_host *host)
> >          */
> >         for (i = 0; i < ARRAY_SIZE(sd_uhs2_freqs); i++) {
> >                 host->f_init = sd_uhs2_freqs[i];
> > +               pr_debug("%s: %s: trying to init UHS-II card at %u Hz\n",
> > +                        mmc_hostname(host), __func__, host->f_init);
> > +
>
> This looks like it belongs in patch 2 instead. I have amended patch 2
> with this before I applied it.
>
> >                 err = sd_uhs2_attach(host);
> >                 if (!err)
> >                         break;
>
> [...]
>
> Other than the above comments, I just wanted to highlight that I have
> just queued up a series from Avri that adds support for SD Ultra
> Capacity (SDUC) cards.
>
> There are some adjustments needed for your series for UHS-II to cope
> with SDUC, but I think those should be quite minor.
>
> Kind regards
> Uffe

Hi, Ulf

I will rebase the patches on the latest mmc/next branch.

Thanks, Victor Shih





[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