diff mbox

mmc: sleep notification

Message ID 1425980197-823-1-git-send-email-avi.shchislowski@sandisk.com (mailing list archive)
State New, archived
Headers show

Commit Message

Avi Shchislowski March 10, 2015, 9:36 a.m. UTC
This patch is implements the new additional state of
Power_Off_Notification – SLEEP_NOTIFICATION.
Until now, the implementation of Power_Off_Notification
supported only three modes – POWERED_ON (0x01),
POWER_OFF_SHORT (0x02) and POWER_OFF_LONG (0x03).

As part of eMMC5.0 before moving to Sleep state hosts may set the
POWER_OFF_NOTIFICATION byte to SLEEP_NOTIFICATION (0x04).
After setting SLEEP_NOTIFICATION, host should wait for
the busy line to be de-asserted.
The max timeout allowed for busy line de-assertion defined
in SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216].
HPI may interrupt the SLEEP_NOTIFICATION operation.
In that case POWER_OFF_NOTIFICATION byte will restore to POWERED_ON.

Signed-off-by: Alex Lemberg <alex.lemberg@sandisk.com>
Signed-off-by: Avi Shchislowski <avi.shchislowski@sandisk.com>
---
 drivers/mmc/card/block.c |   19 +++++-
 drivers/mmc/core/core.c  |   16 +++++-
 drivers/mmc/core/core.h  |    2 +
 drivers/mmc/core/mmc.c   |  143 +++++++++++++++++++++++++++++++++++++++++++---
 include/linux/mmc/card.h |    6 ++
 include/linux/mmc/host.h |    1 +
 include/linux/mmc/mmc.h  |    2 +
 7 files changed, 180 insertions(+), 9 deletions(-)

Comments

Ulf Hansson March 10, 2015, 12:07 p.m. UTC | #1
On 10 March 2015 at 10:36, Avi Shchislowski
<avi.shchislowski@sandisk.com> wrote:
> This patch is implements the new additional state of
> Power_Off_Notification – SLEEP_NOTIFICATION.
> Until now, the implementation of Power_Off_Notification
> supported only three modes – POWERED_ON (0x01),
> POWER_OFF_SHORT (0x02) and POWER_OFF_LONG (0x03).
>
> As part of eMMC5.0 before moving to Sleep state hosts may set the
> POWER_OFF_NOTIFICATION byte to SLEEP_NOTIFICATION (0x04).
> After setting SLEEP_NOTIFICATION, host should wait for
> the busy line to be de-asserted.
> The max timeout allowed for busy line de-assertion defined
> in SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216].
> HPI may interrupt the SLEEP_NOTIFICATION operation.
> In that case POWER_OFF_NOTIFICATION byte will restore to POWERED_ON.

Oh, just great! JEDEC has invented yet another way of how to send a
device to sleep state. I wonder what was wrong with the CMD5 option.

Anyway, thanks for looking into this.

>
> Signed-off-by: Alex Lemberg <alex.lemberg@sandisk.com>
> Signed-off-by: Avi Shchislowski <avi.shchislowski@sandisk.com>
> ---
>  drivers/mmc/card/block.c |   19 +++++-
>  drivers/mmc/core/core.c  |   16 +++++-
>  drivers/mmc/core/core.h  |    2 +
>  drivers/mmc/core/mmc.c   |  143 +++++++++++++++++++++++++++++++++++++++++++---
>  include/linux/mmc/card.h |    6 ++
>  include/linux/mmc/host.h |    1 +
>  include/linux/mmc/mmc.h  |    2 +
>  7 files changed, 180 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
> index 4409d79..f511ecc3 100644
> --- a/drivers/mmc/card/block.c
> +++ b/drivers/mmc/card/block.c
> @@ -2010,9 +2010,26 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
>         unsigned long flags;
>         unsigned int cmd_flags = req ? req->cmd_flags : 0;
>
> -       if (req && !mq->mqrq_prev->req)
> +       if (unlikely(req && mmc_card_mmc(card) &&
> +               (card->ext_csd.power_off_notification ==
> +               EXT_CSD_SLEEP_NOTIFICATION))) {
> +               /* restoring the power_off_notification
> +                * field's state to as it was before so
> +                * that the sleep notification will be
> +                * able to resume later
> +                */
> +               card->ext_csd.power_off_notification = EXT_CSD_POWER_ON;
> +       }
> +
> +       if (req && !mq->mqrq_prev->req) {
>                 /* claim host only for the first request */
>                 mmc_get_card(card);
> +               if (unlikely(req &&
> +                       mmc_card_doing_sleep_notify(card))) {
> +                       mmc_interrupt_hpi(card);
> +                       mmc_card_clr_sleep_notify(card);
> +               }
> +       }

Both above new added code blocks makes no sense to me. Why does the
mmc block layer need to care about this?

>
>         ret = mmc_blk_part_switch(card, md);
>         if (ret) {
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 5bda29b..a090593 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -271,7 +271,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
>
>         BUG_ON(!card);
>
> -       if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
> +       if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card) ||
> +               mmc_card_doing_sleep_notify(card))

We can't do BKOPS when the card is suspended (which is when the card
may be put in sleep state), so no need to protect for this.

>                 return;
>
>         err = mmc_read_bkops_status(card);
> @@ -2630,6 +2631,19 @@ int mmc_pm_notify(struct notifier_block *notify_block,
>                         err = host->bus_ops->pre_suspend(host);
>                 if (!err)
>                         break;
> +               if (host->card && host->bus_ops->suspend) {

Nope, this is the wrong place for this code. You should look into
mmc.c for adding this.

> +                       err = mmc_sleep_notify(host->card);
> +                       /* We assume that HPI was sent
> +                        * in case of -ETIMEDOUT error,
> +                        * so suspend flow can be continued
> +                        */
> +                       if (err && err != -ETIMEDOUT) {
> +                               pr_err("%s:sleep notify err=%d\n",
> +                                       __func__, err);
> +                               return -EBUSY;
> +                       }
> +                       break;
> +               }
>
>                 /* Calling bus_ops->remove() with a claimed host can deadlock */
>                 host->bus_ops->remove(host);
> diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
> index d76597c..b6b4431 100644
> --- a/drivers/mmc/core/core.h
> +++ b/drivers/mmc/core/core.h
> @@ -14,6 +14,7 @@
>  #include <linux/delay.h>
>
>  #define MMC_CMD_RETRIES        3
> +#define MMC_SLEEP_NOTIFY_MAX_TIME      0x17
>
>  struct mmc_bus_ops {
>         void (*remove)(struct mmc_host *);
> @@ -33,6 +34,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
>  void mmc_detach_bus(struct mmc_host *host);
>
>  void mmc_init_erase(struct mmc_card *card);
> +int mmc_sleep_notify(struct mmc_card *card);

If we need a separate function to deal with this, it should be static
function within mmc.c.

>
>  void mmc_set_chip_select(struct mmc_host *host, int mode);
>  void mmc_set_clock(struct mmc_host *host, unsigned int hz);
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 02ad792..1d97d24 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -57,6 +57,11 @@ static const unsigned int tacc_mant[] = {
>                 __res & __mask;                                         \
>         })
>
> +#define GET_SLEEP_NOTIFY_TIME(value) \
> +       (10 * (1 << (unsigned int)(value)))
> +#define GET_SLEEP_NOTIFY_TIME_MSEC(value) \
> +       (DIV_ROUND_UP(GET_SLEEP_NOTIFY_TIME(value), 1000))
> +
>  /*
>   * Given the decoded CSD structure, decode the raw CID to our CID structure.
>   */
> @@ -571,6 +576,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>                 card->ext_csd.ffu_capable =
>                         (ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) &&
>                         !(ext_csd[EXT_CSD_FW_CONFIG] & 0x1);
> +               card->ext_csd.sleep_notify_time =
> +                       ext_csd[EXT_CSD_SLEEP_NOTIFICATION_TIME];
>         }
>  out:
>         return err;
> @@ -1468,6 +1475,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                         card->ext_csd.hpi_en = 1;
>         }
>
> +       /* sleep notify enable/disable for eMMC 5.0 and above */
> +       if ((card->ext_csd.rev >= 7) &&  card->ext_csd.hpi_en &&

Why depend on ext_csd.hpi_en?

> +                       (card->host->caps2 & MMC_CAP2_SLEEP_NOTIFY) &&

Please don't add a new CAP for this. MMC_CAP2_FULL_PWR_CYCLE tells us
if the card can be fully power gated, I think we can use that
instead!?

> +                       card->ext_csd.sleep_notify_time > 0 &&
> +                       card->ext_csd.sleep_notify_time <=
> +                               MMC_SLEEP_NOTIFY_MAX_TIME) {
> +               card->can_sleep_notify = 1;

Instead of adding "can_sleep_notify", let's just encapsulate similar
code as above in a helper function which tells us if card supports
"sleep notification".

Compare how mmc_can_sleep() is implemented and used.

> +       }
> +
>         /*
>          * If cache size is higher than 0, this indicates
>          * the existence of cache and it can be turned on.
> @@ -1576,6 +1592,33 @@ static int mmc_sleep(struct mmc_host *host)
>         return err;
>  }
>
> +/*
> + * check if device is in program state (busy)
> + */
> +static bool mmc_device_prg_state(struct mmc_card *card)
> +{
> +       int rc;
> +       u32 status;
> +       bool state;
> +
> +       mmc_get_card(card);
> +       rc = mmc_send_status(card, &status);
> +       if (rc) {
> +               pr_err("%s: Get card status fail. rc=%d\n",
> +                       mmc_hostname(card->host), rc);
> +               state = false;
> +               goto out;
> +       }
> +
> +       if (R1_CURRENT_STATE(status) == R1_STATE_PRG)
> +               state =  true;
> +       else
> +               state =  false;
> +out:
> +       mmc_put_card(card);
> +       return state;
> +}
> +
>  static int mmc_can_poweroff_notify(const struct mmc_card *card)
>  {
>         return card &&
> @@ -1585,22 +1628,108 @@ static int mmc_can_poweroff_notify(const struct mmc_card *card)
>
>  static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
>  {
> -       unsigned int timeout = card->ext_csd.generic_cmd6_time;
> +       unsigned int timeout_ms = card->ext_csd.generic_cmd6_time;

What's reason to do a rename in this patch? If you want that as a
clarification of the code, please do that in a separate patch.

>         int err;
> +       bool use_busy_signal;
>
>         /* Use EXT_CSD_POWER_OFF_SHORT as default notification type. */
>         if (notify_type == EXT_CSD_POWER_OFF_LONG)
> -               timeout = card->ext_csd.power_off_longtime;
> +               timeout_ms = card->ext_csd.power_off_longtime;
> +       else if (notify_type == EXT_CSD_SLEEP_NOTIFICATION) {
> +               /* calculate the maximum timeout for the
> +                * switch command when notifying the device
> +                * that it is about to move to sleep */
> +               timeout_ms = GET_SLEEP_NOTIFY_TIME_MSEC(
> +                       card->ext_csd.sleep_notify_time);
> +       }
>
> +       /* do not wait on busy signal in case of
> +        * Sleep Notification - to let host get
> +        * another requests

At this point, there should be no other request. Or what am I missing?

> +        */
> +       use_busy_signal = (notify_type == EXT_CSD_SLEEP_NOTIFICATION) ?
> +                       false : true;
>         err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>                         EXT_CSD_POWER_OFF_NOTIFICATION,
> -                       notify_type, timeout, true, false, false);
> -       if (err)
> +                       notify_type, timeout_ms,
> +                       use_busy_signal, false, false);
> +       if (!err) {
> +               card->ext_csd.power_off_notification = notify_type;
> +       } else {
>                 pr_err("%s: Power Off Notification timed out, %u\n",
> -                      mmc_hostname(card->host), timeout);
> +                       mmc_hostname(card->host), timeout_ms);
> +       }
> +
> +       return err;
> +}
>
> -       /* Disable the power off notification after the switch operation. */
> -       card->ext_csd.power_off_notification = EXT_CSD_NO_POWER_NOTIFICATION;

Why remove this?

> +int mmc_sleep_notify(struct mmc_card *card)

I don't understand the need for this function. From what scenarios do
we want to invoke it?

> +{
> +       int err = 0;
> +       bool is_busy = 0;
> +       unsigned long prg_wait = 0;
> +
> +       if (!card->can_sleep_notify || !mmc_can_poweroff_notify(card))
> +               return 0;
> +
> +       if (!mmc_card_doing_sleep_notify(card)) {
> +               mmc_get_card(card);
> +               mmc_card_set_sleep_notify(card);
> +               err = mmc_poweroff_notify(card,
> +                       EXT_CSD_SLEEP_NOTIFICATION);
> +               mmc_put_card(card);
> +               if (err) {
> +                       pr_err("%s: mmc_poweroff_notify failed with %d\n",
> +                              __func__, err);
> +                       goto out;
> +               }
> +
> +               prg_wait = jiffies +
> +                       msecs_to_jiffies(GET_SLEEP_NOTIFY_TIME_MSEC(
> +                       card->ext_csd.sleep_notify_time));
> +               }
> +
> +       /*
> +        * Loop will run until:
> +        * 1. Device is no more in Busy state
> +        * 2. Sleep notification is not interrupted by HPI & IO request
> +        */
> +       do {
> +               /* added some delay to avoid sending card status too often */
> +               msleep(20);
> +               err = 0;
> +               /* Stop polling in case sleep notification was HPIed already */
> +               if (!mmc_card_doing_sleep_notify(card)) {
> +                       is_busy = mmc_device_prg_state(card);
> +                       if (is_busy)
> +                               err = -EBUSY;
> +                       break;
> +               }
> +               is_busy = mmc_device_prg_state(card);
> +               if (is_busy && time_after(jiffies, prg_wait)) {
> +                       /*
> +                        * making sure we are still in busy before
> +                        * sending HPI due to timeout error
> +                        */
> +                       is_busy = mmc_device_prg_state(card);
> +                       if (is_busy) {
> +                               if (mmc_card_doing_sleep_notify(card)) {
> +                                       card->ext_csd.power_off_notification =
> +                                               EXT_CSD_POWER_ON;
> +                                       mmc_interrupt_hpi(card);
> +                               }
> +                               err = -ETIMEDOUT;
> +                               break;
> +                       }
> +               }
> +       } while (is_busy);
> +
> +out:
> +       mmc_card_clr_sleep_notify(card);
> +       if (err) {
> +               pr_err("%s: mmc_poweroff_notify for sleep failed with %d\n",
> +                      mmc_hostname(card->host), err);
> +       }
>
>         return err;
>  }
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 4d69c00..6998344 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -62,6 +62,7 @@ struct mmc_ext_csd {
>         unsigned int            sa_timeout;             /* Units: 100ns */
>         unsigned int            generic_cmd6_time;      /* Units: 10ms */
>         unsigned int            power_off_longtime;     /* Units: ms */
> +       unsigned int            sleep_notify_time;      /* Units: us */
>         u8                      power_off_notification; /* state */
>         unsigned int            hs_max_dtr;
>         unsigned int            hs200_max_dtr;
> @@ -262,6 +263,7 @@ struct mmc_card {
>  #define MMC_CARD_REMOVED       (1<<4)          /* card has been removed */
>  #define MMC_STATE_DOING_BKOPS  (1<<5)          /* card is doing BKOPS */
>  #define MMC_STATE_SUSPENDED    (1<<6)          /* card is suspended */
> +#define MMC_STATE_SLEEP_NOTIFY (1<<7)          /* card in sleep notify */

I think MMC_STATE_SUSPENDED should be enough, we don't need another
one specific for SLEEP_NOTIFY.

>         unsigned int            quirks;         /* card quirks */
>  #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
> @@ -309,6 +311,7 @@ struct mmc_card {
>         struct dentry           *debugfs_root;
>         struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
>         unsigned int    nr_parts;
> +       u8 can_sleep_notify;    /* sleep_notify on/off */

As stated, please remove.

>  };
>
>  /*
> @@ -427,6 +430,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
>  #define mmc_card_removed(c)    ((c) && ((c)->state & MMC_CARD_REMOVED))
>  #define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
>  #define mmc_card_suspended(c)  ((c)->state & MMC_STATE_SUSPENDED)
> +#define mmc_card_doing_sleep_notify(c) ((c)->state & MMC_STATE_SLEEP_NOTIFY)
>
>  #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
>  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
> @@ -437,6 +441,8 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
>  #define mmc_card_clr_doing_bkops(c)    ((c)->state &= ~MMC_STATE_DOING_BKOPS)
>  #define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
>  #define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
> +#define mmc_card_set_sleep_notify(c)   ((c)->state |= MMC_STATE_SLEEP_NOTIFY)
> +#define mmc_card_clr_sleep_notify(c)   ((c)->state &= ~MMC_STATE_SLEEP_NOTIFY)
>
>  /*
>   * Quirk add/remove for MMC products.
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 9f32270..4c0542a 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -291,6 +291,7 @@ struct mmc_host {
>                                  MMC_CAP2_HS400_1_2V)
>  #define MMC_CAP2_HSX00_1_2V    (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
>  #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
> +#define MMC_CAP2_SLEEP_NOTIFY  (1 << 18)       /* sleep notify supported */
>
>         mmc_pm_flag_t           pm_caps;        /* supported pm features */
>
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 49ad7a9..69bda9a 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -314,6 +314,7 @@ struct _mmc_csd {
>  #define EXT_CSD_PWR_CL_52_360          202     /* RO */
>  #define EXT_CSD_PWR_CL_26_360          203     /* RO */
>  #define EXT_CSD_SEC_CNT                        212     /* RO, 4 bytes */
> +#define EXT_CSD_SLEEP_NOTIFICATION_TIME        216     /* RO */
>  #define EXT_CSD_S_A_TIMEOUT            217     /* RO */
>  #define EXT_CSD_REL_WR_SEC_C           222     /* RO */
>  #define EXT_CSD_HC_WP_GRP_SIZE         221     /* RO */
> @@ -408,6 +409,7 @@ struct _mmc_csd {
>  #define EXT_CSD_POWER_ON               1
>  #define EXT_CSD_POWER_OFF_SHORT                2
>  #define EXT_CSD_POWER_OFF_LONG         3
> +#define EXT_CSD_SLEEP_NOTIFICATION     4
>
>  #define EXT_CSD_PWR_CL_8BIT_MASK       0xF0    /* 8 bit PWR CLS */
>  #define EXT_CSD_PWR_CL_4BIT_MASK       0x0F    /* 8 bit PWR CLS */
> --
> 1.7.9.5
>

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Adrian Hunter March 10, 2015, 1:36 p.m. UTC | #2
On 10/03/15 11:36, Avi Shchislowski wrote:
> This patch is implements the new additional state of
> Power_Off_Notification – SLEEP_NOTIFICATION.
> Until now, the implementation of Power_Off_Notification
> supported only three modes – POWERED_ON (0x01),
> POWER_OFF_SHORT (0x02) and POWER_OFF_LONG (0x03).
> 
> As part of eMMC5.0 before moving to Sleep state hosts may set the
> POWER_OFF_NOTIFICATION byte to SLEEP_NOTIFICATION (0x04).
> After setting SLEEP_NOTIFICATION, host should wait for
> the busy line to be de-asserted.
> The max timeout allowed for busy line de-assertion defined
> in SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216].
> HPI may interrupt the SLEEP_NOTIFICATION operation.
> In that case POWER_OFF_NOTIFICATION byte will restore to POWERED_ON.

Is it so that the point of SLEEP_NOTIFICATION is to notify that
VCC will be powered off after the device is put to sleep by CMD5?

At the moment, the card does not get put to sleep if there is
support for power-off-notification?

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alex Lemberg March 10, 2015, 2:32 p.m. UTC | #3
Hi Ulf,

Thanks for your review and comments!

> -----Original Message-----

> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]

> Sent: Tuesday, March 10, 2015 5:08 AM

> To: Avi Shchislowski

> Cc: linux-mmc; Chris Ball; Alex Lemberg

> Subject: Re: [PATCH] mmc: sleep notification

> 

> On 10 March 2015 at 10:36, Avi Shchislowski <avi.shchislowski@sandisk.com>

> wrote:

> > This patch is implements the new additional state of

> > Power_Off_Notification – SLEEP_NOTIFICATION.

> > Until now, the implementation of Power_Off_Notification supported only

> > three modes – POWERED_ON (0x01), POWER_OFF_SHORT (0x02) and

> > POWER_OFF_LONG (0x03).

> >

> > As part of eMMC5.0 before moving to Sleep state hosts may set the

> > POWER_OFF_NOTIFICATION byte to SLEEP_NOTIFICATION (0x04).

> > After setting SLEEP_NOTIFICATION, host should wait for the busy line

> > to be de-asserted.

> > The max timeout allowed for busy line de-assertion defined in

> > SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216].

> > HPI may interrupt the SLEEP_NOTIFICATION operation.

> > In that case POWER_OFF_NOTIFICATION byte will restore to POWERED_ON.

> 

> Oh, just great! JEDEC has invented yet another way of how to send a device to

> sleep state. I wonder what was wrong with the CMD5 option.


I think before adding sleep_notification, host has no way to notify device before sending
sleep command. Now device can better prepare itself for moving into the sleep state.

Also, I think we need to clarify one more point for this patch:
As was mentioned in commit message - Sleep_Notification can be interrupted by HPI.
This allows not blocking the host during the Sleep_Notification busy time and allows accepting 
requests coming during this stage. Thus, without having HPI supported, suspend/resume process
might be influenced by Sleep_Notification busy time, and this should not happen - suspend/resume
should be done in very fast and not blocking manner.


Thanks,
Alex
Alex Lemberg March 10, 2015, 4:32 p.m. UTC | #4
Hi Adrian,

> -----Original Message-----
> From: Adrian Hunter [mailto:adrian.hunter@intel.com]
> Sent: Tuesday, March 10, 2015 6:36 AM
> To: Avi Shchislowski; ulf.hansson@linaro.org
> Cc: linux-mmc@vger.kernel.org; chris@printf.net; Alex Lemberg
> Subject: Re: [PATCH] mmc: sleep notification
> 
> On 10/03/15 11:36, Avi Shchislowski wrote:
> > This patch is implements the new additional state of
> > Power_Off_Notification - SLEEP_NOTIFICATION.
> > Until now, the implementation of Power_Off_Notification supported only
> > three modes - POWERED_ON (0x01), POWER_OFF_SHORT (0x02) and
> > POWER_OFF_LONG (0x03).
> >
> > As part of eMMC5.0 before moving to Sleep state hosts may set the
> > POWER_OFF_NOTIFICATION byte to SLEEP_NOTIFICATION (0x04).
> > After setting SLEEP_NOTIFICATION, host should wait for the busy line
> > to be de-asserted.
> > The max timeout allowed for busy line de-assertion defined in
> > SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216].
> > HPI may interrupt the SLEEP_NOTIFICATION operation.
> > In that case POWER_OFF_NOTIFICATION byte will restore to POWERED_ON.
> 
> Is it so that the point of SLEEP_NOTIFICATION is to notify that VCC will be
> powered off after the device is put to sleep by CMD5?

From the spec: 

the host should issue a power off notification (POWER_OFF_LONG, POWER_OFF_SHORT )
if it intends to turn off both VCC and VCCQ power supplies or it may use 
to a power off notification (SLEEP_NOTIFICATION ) if it intends to turn-off VCC
after moving the device to Sleep state.

> 
> At the moment, the card does not get put to sleep if there is support for power-
> off-notification?

Driver will send Sleep only if PON is not supported...

Thanks,
Alex
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson March 10, 2015, 5:22 p.m. UTC | #5
On 10 March 2015 at 17:32, Alex Lemberg <Alex.Lemberg@sandisk.com> wrote:
> Hi Adrian,
>
>> -----Original Message-----
>> From: Adrian Hunter [mailto:adrian.hunter@intel.com]
>> Sent: Tuesday, March 10, 2015 6:36 AM
>> To: Avi Shchislowski; ulf.hansson@linaro.org
>> Cc: linux-mmc@vger.kernel.org; chris@printf.net; Alex Lemberg
>> Subject: Re: [PATCH] mmc: sleep notification
>>
>> On 10/03/15 11:36, Avi Shchislowski wrote:
>> > This patch is implements the new additional state of
>> > Power_Off_Notification - SLEEP_NOTIFICATION.
>> > Until now, the implementation of Power_Off_Notification supported only
>> > three modes - POWERED_ON (0x01), POWER_OFF_SHORT (0x02) and
>> > POWER_OFF_LONG (0x03).
>> >
>> > As part of eMMC5.0 before moving to Sleep state hosts may set the
>> > POWER_OFF_NOTIFICATION byte to SLEEP_NOTIFICATION (0x04).
>> > After setting SLEEP_NOTIFICATION, host should wait for the busy line
>> > to be de-asserted.
>> > The max timeout allowed for busy line de-assertion defined in
>> > SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216].
>> > HPI may interrupt the SLEEP_NOTIFICATION operation.
>> > In that case POWER_OFF_NOTIFICATION byte will restore to POWERED_ON.
>>
>> Is it so that the point of SLEEP_NOTIFICATION is to notify that VCC will be
>> powered off after the device is put to sleep by CMD5?
>
> From the spec:
>
> the host should issue a power off notification (POWER_OFF_LONG, POWER_OFF_SHORT )
> if it intends to turn off both VCC and VCCQ power supplies or it may use
> to a power off notification (SLEEP_NOTIFICATION ) if it intends to turn-off VCC
> after moving the device to Sleep state.

Ah, so CMD5 will still need to be issued. Thanks for clarifying.

>
>>
>> At the moment, the card does not get put to sleep if there is support for power-
>> off-notification?
>
> Driver will send Sleep only if PON is not supported...

Nope, that's not entirely correct.

The MMC core requires PON to be supported by the card and the host to
have MMC_CAP2_FULL_PWR_CYCLE set. Else it will send sleep (CMD5)
instead.

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alex Lemberg March 10, 2015, 6:01 p.m. UTC | #6
> -----Original Message-----

> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]

> Sent: Tuesday, March 10, 2015 10:22 AM

> To: Alex Lemberg

> Cc: Adrian Hunter; Avi Shchislowski; linux-mmc@vger.kernel.org;

> chris@printf.net

> Subject: Re: [PATCH] mmc: sleep notification

> 

> On 10 March 2015 at 17:32, Alex Lemberg <Alex.Lemberg@sandisk.com>

> wrote:

> > Hi Adrian,

> >

> >> -----Original Message-----

> >> From: Adrian Hunter [mailto:adrian.hunter@intel.com]

> >> Sent: Tuesday, March 10, 2015 6:36 AM

> >> To: Avi Shchislowski; ulf.hansson@linaro.org

> >> Cc: linux-mmc@vger.kernel.org; chris@printf.net; Alex Lemberg

> >> Subject: Re: [PATCH] mmc: sleep notification

> >>

> >> On 10/03/15 11:36, Avi Shchislowski wrote:

> >> > This patch is implements the new additional state of

> >> > Power_Off_Notification - SLEEP_NOTIFICATION.

> >> > Until now, the implementation of Power_Off_Notification supported

> >> > only three modes - POWERED_ON (0x01), POWER_OFF_SHORT (0x02) and

> >> > POWER_OFF_LONG (0x03).

> >> >

> >> > As part of eMMC5.0 before moving to Sleep state hosts may set the

> >> > POWER_OFF_NOTIFICATION byte to SLEEP_NOTIFICATION (0x04).

> >> > After setting SLEEP_NOTIFICATION, host should wait for the busy

> >> > line to be de-asserted.

> >> > The max timeout allowed for busy line de-assertion defined in

> >> > SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216].

> >> > HPI may interrupt the SLEEP_NOTIFICATION operation.

> >> > In that case POWER_OFF_NOTIFICATION byte will restore to

> POWERED_ON.

> >>

> >> Is it so that the point of SLEEP_NOTIFICATION is to notify that VCC

> >> will be powered off after the device is put to sleep by CMD5?

> >

> > From the spec:

> >

> > the host should issue a power off notification (POWER_OFF_LONG,

> > POWER_OFF_SHORT ) if it intends to turn off both VCC and VCCQ power

> > supplies or it may use to a power off notification (SLEEP_NOTIFICATION

> > ) if it intends to turn-off VCC after moving the device to Sleep state.

> 

> Ah, so CMD5 will still need to be issued. Thanks for clarifying.

> 

> >

> >>

> >> At the moment, the card does not get put to sleep if there is support

> >> for power- off-notification?

> >

> > Driver will send Sleep only if PON is not supported...

> 

> Nope, that's not entirely correct.

> 

> The MMC core requires PON to be supported by the card and the host to have

> MMC_CAP2_FULL_PWR_CYCLE set. Else it will send sleep (CMD5) instead.

>


You are right - it requires both PON and MMC_CAP2_FULL_PWR_CYCLE to be set...
Thanks for mentioning this.

 
> Kind regards

> Uffe
Ulf Hansson March 11, 2015, 11:50 a.m. UTC | #7
On 10 March 2015 at 15:32, Alex Lemberg <Alex.Lemberg@sandisk.com> wrote:
> Hi Ulf,
>
> Thanks for your review and comments!
>
>> -----Original Message-----
>> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]
>> Sent: Tuesday, March 10, 2015 5:08 AM
>> To: Avi Shchislowski
>> Cc: linux-mmc; Chris Ball; Alex Lemberg
>> Subject: Re: [PATCH] mmc: sleep notification
>>
>> On 10 March 2015 at 10:36, Avi Shchislowski <avi.shchislowski@sandisk.com>
>> wrote:
>> > This patch is implements the new additional state of
>> > Power_Off_Notification – SLEEP_NOTIFICATION.
>> > Until now, the implementation of Power_Off_Notification supported only
>> > three modes – POWERED_ON (0x01), POWER_OFF_SHORT (0x02) and
>> > POWER_OFF_LONG (0x03).
>> >
>> > As part of eMMC5.0 before moving to Sleep state hosts may set the
>> > POWER_OFF_NOTIFICATION byte to SLEEP_NOTIFICATION (0x04).
>> > After setting SLEEP_NOTIFICATION, host should wait for the busy line
>> > to be de-asserted.
>> > The max timeout allowed for busy line de-assertion defined in
>> > SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216].
>> > HPI may interrupt the SLEEP_NOTIFICATION operation.
>> > In that case POWER_OFF_NOTIFICATION byte will restore to POWERED_ON.
>>
>> Oh, just great! JEDEC has invented yet another way of how to send a device to
>> sleep state. I wonder what was wrong with the CMD5 option.
>
> I think before adding sleep_notification, host has no way to notify device before sending
> sleep command. Now device can better prepare itself for moving into the sleep state.
>
> Also, I think we need to clarify one more point for this patch:
> As was mentioned in commit message - Sleep_Notification can be interrupted by HPI.
> This allows not blocking the host during the Sleep_Notification busy time and allows accepting
> requests coming during this stage. Thus, without having HPI supported, suspend/resume process
> might be influenced by Sleep_Notification busy time, and this should not happen - suspend/resume
> should be done in very fast and not blocking manner.

I fail to understand your comment here.

Please tell me at what point(s) your think it make sense to issue the
SLEEP_NOTIFICATION? If that is during the suspend phase, then a HPI
request can't be triggered.

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alex Lemberg March 11, 2015, 6:38 p.m. UTC | #8
SGkgVWxmLA0KDQo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IFVsZiBIYW5z
c29uIFttYWlsdG86dWxmLmhhbnNzb25AbGluYXJvLm9yZ10NCj4gU2VudDogV2VkbmVzZGF5LCBN
YXJjaCAxMSwgMjAxNSA0OjUwIEFNDQo+IFRvOiBBbGV4IExlbWJlcmcNCj4gQ2M6IEF2aSBTaGNo
aXNsb3dza2k7IGxpbnV4LW1tYzsgQ2hyaXMgQmFsbA0KPiBTdWJqZWN0OiBSZTogW1BBVENIXSBt
bWM6IHNsZWVwIG5vdGlmaWNhdGlvbg0KPiANCj4gT24gMTAgTWFyY2ggMjAxNSBhdCAxNTozMiwg
QWxleCBMZW1iZXJnIDxBbGV4LkxlbWJlcmdAc2FuZGlzay5jb20+DQo+IHdyb3RlOg0KPiA+IEhp
IFVsZiwNCj4gPg0KPiA+IFRoYW5rcyBmb3IgeW91ciByZXZpZXcgYW5kIGNvbW1lbnRzIQ0KPiA+
DQo+ID4+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+ID4+IEZyb206IFVsZiBIYW5zc29u
IFttYWlsdG86dWxmLmhhbnNzb25AbGluYXJvLm9yZ10NCj4gPj4gU2VudDogVHVlc2RheSwgTWFy
Y2ggMTAsIDIwMTUgNTowOCBBTQ0KPiA+PiBUbzogQXZpIFNoY2hpc2xvd3NraQ0KPiA+PiBDYzog
bGludXgtbW1jOyBDaHJpcyBCYWxsOyBBbGV4IExlbWJlcmcNCj4gPj4gU3ViamVjdDogUmU6IFtQ
QVRDSF0gbW1jOiBzbGVlcCBub3RpZmljYXRpb24NCj4gPj4NCj4gPj4gT24gMTAgTWFyY2ggMjAx
NSBhdCAxMDozNiwgQXZpIFNoY2hpc2xvd3NraQ0KPiA+PiA8YXZpLnNoY2hpc2xvd3NraUBzYW5k
aXNrLmNvbT4NCj4gPj4gd3JvdGU6DQo+ID4+ID4gVGhpcyBwYXRjaCBpcyBpbXBsZW1lbnRzIHRo
ZSBuZXcgYWRkaXRpb25hbCBzdGF0ZSBvZg0KPiA+PiA+IFBvd2VyX09mZl9Ob3RpZmljYXRpb24g
4oCTIFNMRUVQX05PVElGSUNBVElPTi4NCj4gPj4gPiBVbnRpbCBub3csIHRoZSBpbXBsZW1lbnRh
dGlvbiBvZiBQb3dlcl9PZmZfTm90aWZpY2F0aW9uIHN1cHBvcnRlZA0KPiA+PiA+IG9ubHkgdGhy
ZWUgbW9kZXMg4oCTIFBPV0VSRURfT04gKDB4MDEpLCBQT1dFUl9PRkZfU0hPUlQgKDB4MDIpDQo+
IGFuZA0KPiA+PiA+IFBPV0VSX09GRl9MT05HICgweDAzKS4NCj4gPj4gPg0KPiA+PiA+IEFzIHBh
cnQgb2YgZU1NQzUuMCBiZWZvcmUgbW92aW5nIHRvIFNsZWVwIHN0YXRlIGhvc3RzIG1heSBzZXQg
dGhlDQo+ID4+ID4gUE9XRVJfT0ZGX05PVElGSUNBVElPTiBieXRlIHRvIFNMRUVQX05PVElGSUNB
VElPTiAoMHgwNCkuDQo+ID4+ID4gQWZ0ZXIgc2V0dGluZyBTTEVFUF9OT1RJRklDQVRJT04sIGhv
c3Qgc2hvdWxkIHdhaXQgZm9yIHRoZSBidXN5DQo+ID4+ID4gbGluZSB0byBiZSBkZS1hc3NlcnRl
ZC4NCj4gPj4gPiBUaGUgbWF4IHRpbWVvdXQgYWxsb3dlZCBmb3IgYnVzeSBsaW5lIGRlLWFzc2Vy
dGlvbiBkZWZpbmVkIGluDQo+ID4+ID4gU0xFRVBfTk9USUZJQ0FUSU9OX1RJTUUgYnl0ZSBpbiBF
WFRfQ1NEIFsyMTZdLg0KPiA+PiA+IEhQSSBtYXkgaW50ZXJydXB0IHRoZSBTTEVFUF9OT1RJRklD
QVRJT04gb3BlcmF0aW9uLg0KPiA+PiA+IEluIHRoYXQgY2FzZSBQT1dFUl9PRkZfTk9USUZJQ0FU
SU9OIGJ5dGUgd2lsbCByZXN0b3JlIHRvDQo+IFBPV0VSRURfT04uDQo+ID4+DQo+ID4+IE9oLCBq
dXN0IGdyZWF0ISBKRURFQyBoYXMgaW52ZW50ZWQgeWV0IGFub3RoZXIgd2F5IG9mIGhvdyB0byBz
ZW5kIGENCj4gPj4gZGV2aWNlIHRvIHNsZWVwIHN0YXRlLiBJIHdvbmRlciB3aGF0IHdhcyB3cm9u
ZyB3aXRoIHRoZSBDTUQ1IG9wdGlvbi4NCj4gPg0KPiA+IEkgdGhpbmsgYmVmb3JlIGFkZGluZyBz
bGVlcF9ub3RpZmljYXRpb24sIGhvc3QgaGFzIG5vIHdheSB0byBub3RpZnkNCj4gPiBkZXZpY2Ug
YmVmb3JlIHNlbmRpbmcgc2xlZXAgY29tbWFuZC4gTm93IGRldmljZSBjYW4gYmV0dGVyIHByZXBh
cmUgaXRzZWxmDQo+IGZvciBtb3ZpbmcgaW50byB0aGUgc2xlZXAgc3RhdGUuDQo+ID4NCj4gPiBB
bHNvLCBJIHRoaW5rIHdlIG5lZWQgdG8gY2xhcmlmeSBvbmUgbW9yZSBwb2ludCBmb3IgdGhpcyBw
YXRjaDoNCj4gPiBBcyB3YXMgbWVudGlvbmVkIGluIGNvbW1pdCBtZXNzYWdlIC0gU2xlZXBfTm90
aWZpY2F0aW9uIGNhbiBiZSBpbnRlcnJ1cHRlZA0KPiBieSBIUEkuDQo+ID4gVGhpcyBhbGxvd3Mg
bm90IGJsb2NraW5nIHRoZSBob3N0IGR1cmluZyB0aGUgU2xlZXBfTm90aWZpY2F0aW9uIGJ1c3kN
Cj4gPiB0aW1lIGFuZCBhbGxvd3MgYWNjZXB0aW5nIHJlcXVlc3RzIGNvbWluZyBkdXJpbmcgdGhp
cyBzdGFnZS4gVGh1cywNCj4gPiB3aXRob3V0IGhhdmluZyBIUEkgc3VwcG9ydGVkLCBzdXNwZW5k
L3Jlc3VtZSBwcm9jZXNzIG1pZ2h0IGJlDQo+ID4gaW5mbHVlbmNlZCBieSBTbGVlcF9Ob3RpZmlj
YXRpb24gYnVzeSB0aW1lLCBhbmQgdGhpcyBzaG91bGQgbm90IGhhcHBlbiAtDQo+IHN1c3BlbmQv
cmVzdW1lIHNob3VsZCBiZSBkb25lIGluIHZlcnkgZmFzdCBhbmQgbm90IGJsb2NraW5nIG1hbm5l
ci4NCj4gDQo+IEkgZmFpbCB0byB1bmRlcnN0YW5kIHlvdXIgY29tbWVudCBoZXJlLg0KPiANCj4g
UGxlYXNlIHRlbGwgbWUgYXQgd2hhdCBwb2ludChzKSB5b3VyIHRoaW5rIGl0IG1ha2Ugc2Vuc2Ug
dG8gaXNzdWUgdGhlDQo+IFNMRUVQX05PVElGSUNBVElPTj8gSWYgdGhhdCBpcyBkdXJpbmcgdGhl
IHN1c3BlbmQgcGhhc2UsIHRoZW4gYSBIUEkgcmVxdWVzdA0KPiBjYW4ndCBiZSB0cmlnZ2VyZWQu
DQoNCkkgdGhpbmsgU0xFRVBfTk9USUZJQ0FUSU9OIHNob3VsZCBiZSBpc3N1ZWQgb24gbW1jX3Bt
X25vdGlmeSgpIGNhbGwsDQpvbiBQTV9TVVNQRU5EX1BSRVBBUkUgY2FzZS4NCiANCg0KPiBLaW5k
IHJlZ2FyZHMNCj4gVWZmZQ0K
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson March 12, 2015, 9:09 a.m. UTC | #9
[...]

>> > Also, I think we need to clarify one more point for this patch:
>> > As was mentioned in commit message - Sleep_Notification can be interrupted
>> by HPI.
>> > This allows not blocking the host during the Sleep_Notification busy
>> > time and allows accepting requests coming during this stage. Thus,
>> > without having HPI supported, suspend/resume process might be
>> > influenced by Sleep_Notification busy time, and this should not happen -
>> suspend/resume should be done in very fast and not blocking manner.
>>
>> I fail to understand your comment here.
>>
>> Please tell me at what point(s) your think it make sense to issue the
>> SLEEP_NOTIFICATION? If that is during the suspend phase, then a HPI request
>> can't be triggered.
>
> I think SLEEP_NOTIFICATION should be issued on mmc_pm_notify() call,
> on PM_SUSPEND_PREPARE case.

So, exactly why is that to prefer, comparing doing it in system PM
->suspend() callback?

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jaehoon Chung March 13, 2015, 11:46 a.m. UTC | #10
On 03/12/2015 06:09 PM, Ulf Hansson wrote:
> [...]
> 
>>>> Also, I think we need to clarify one more point for this patch:
>>>> As was mentioned in commit message - Sleep_Notification can be interrupted
>>> by HPI.
>>>> This allows not blocking the host during the Sleep_Notification busy
>>>> time and allows accepting requests coming during this stage. Thus,
>>>> without having HPI supported, suspend/resume process might be
>>>> influenced by Sleep_Notification busy time, and this should not happen -
>>> suspend/resume should be done in very fast and not blocking manner.
>>>
>>> I fail to understand your comment here.
>>>
>>> Please tell me at what point(s) your think it make sense to issue the
>>> SLEEP_NOTIFICATION? If that is during the suspend phase, then a HPI request
>>> can't be triggered.
>>
>> I think SLEEP_NOTIFICATION should be issued on mmc_pm_notify() call,
>> on PM_SUSPEND_PREPARE case.
> 
> So, exactly why is that to prefer, comparing doing it in system PM
> ->suspend() callback?

Actually, i didn't know the benefit of this feature.

Best Regards,
Jaehoon Chung

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

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Avi Shchislowski March 15, 2015, 9:04 a.m. UTC | #11
>-----Original Message-----
>From: Adrian Hunter [mailto:adrian.hunter@intel.com]
>Sent: Tuesday, March 10, 2015 3:36 PM
>To: Avi Shchislowski; ulf.hansson@linaro.org
>Cc: linux-mmc@vger.kernel.org; chris@printf.net; Alex Lemberg
>Subject: Re: [PATCH] mmc: sleep notification
>
>On 10/03/15 11:36, Avi Shchislowski wrote:
>> This patch is implements the new additional state of
>> Power_Off_Notification - SLEEP_NOTIFICATION.
>> Until now, the implementation of Power_Off_Notification supported only
>> three modes - POWERED_ON (0x01), POWER_OFF_SHORT (0x02) and
>> POWER_OFF_LONG (0x03).
>>
>> As part of eMMC5.0 before moving to Sleep state hosts may set the
>> POWER_OFF_NOTIFICATION byte to SLEEP_NOTIFICATION (0x04).
>> After setting SLEEP_NOTIFICATION, host should wait for the busy line
>> to be de-asserted.
>> The max timeout allowed for busy line de-assertion defined in
>> SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216].
>> HPI may interrupt the SLEEP_NOTIFICATION operation.
>> In that case POWER_OFF_NOTIFICATION byte will restore to POWERED_ON.
>
>Is it so that the point of SLEEP_NOTIFICATION is to notify that VCC will be
>powered off after the device is put to sleep by CMD5?
The purpose of SLEEP_NOTIFICATION is to give the eMMC enough time to prepare itself before powered off.
Before the SLEEP_NOTIFICATION fetcher the eMMC did not know he will get into sleep but only when the sleep was issued
With this solution the device start to prepare itself during the sleep preparation

>
>At the moment, the card does not get put to sleep if there is support for
>power-off-notification?
 No, it will enter to sleep after the device will finish its "internal work"

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alex Lemberg March 16, 2015, 11:37 a.m. UTC | #12
SGkgVWxmLA0KDQo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IFVsZiBIYW5z
c29uIFttYWlsdG86dWxmLmhhbnNzb25AbGluYXJvLm9yZ10NCj4gU2VudDogVGh1cnNkYXksIE1h
cmNoIDEyLCAyMDE1IDExOjEwIEFNDQo+IFRvOiBBbGV4IExlbWJlcmcNCj4gQ2M6IEF2aSBTaGNo
aXNsb3dza2k7IGxpbnV4LW1tYzsgQ2hyaXMgQmFsbA0KPiBTdWJqZWN0OiBSZTogW1BBVENIXSBt
bWM6IHNsZWVwIG5vdGlmaWNhdGlvbg0KPiANCj4gWy4uLl0NCj4gDQo+ID4+ID4gQWxzbywgSSB0
aGluayB3ZSBuZWVkIHRvIGNsYXJpZnkgb25lIG1vcmUgcG9pbnQgZm9yIHRoaXMgcGF0Y2g6DQo+
ID4+ID4gQXMgd2FzIG1lbnRpb25lZCBpbiBjb21taXQgbWVzc2FnZSAtIFNsZWVwX05vdGlmaWNh
dGlvbiBjYW4gYmUNCj4gPj4gPiBpbnRlcnJ1cHRlZA0KPiA+PiBieSBIUEkuDQo+ID4+ID4gVGhp
cyBhbGxvd3Mgbm90IGJsb2NraW5nIHRoZSBob3N0IGR1cmluZyB0aGUgU2xlZXBfTm90aWZpY2F0
aW9uDQo+ID4+ID4gYnVzeSB0aW1lIGFuZCBhbGxvd3MgYWNjZXB0aW5nIHJlcXVlc3RzIGNvbWlu
ZyBkdXJpbmcgdGhpcyBzdGFnZS4NCj4gPj4gPiBUaHVzLCB3aXRob3V0IGhhdmluZyBIUEkgc3Vw
cG9ydGVkLCBzdXNwZW5kL3Jlc3VtZSBwcm9jZXNzIG1pZ2h0IGJlDQo+ID4+ID4gaW5mbHVlbmNl
ZCBieSBTbGVlcF9Ob3RpZmljYXRpb24gYnVzeSB0aW1lLCBhbmQgdGhpcyBzaG91bGQgbm90DQo+
ID4+ID4gaGFwcGVuIC0NCj4gPj4gc3VzcGVuZC9yZXN1bWUgc2hvdWxkIGJlIGRvbmUgaW4gdmVy
eSBmYXN0IGFuZCBub3QgYmxvY2tpbmcgbWFubmVyLg0KPiA+Pg0KPiA+PiBJIGZhaWwgdG8gdW5k
ZXJzdGFuZCB5b3VyIGNvbW1lbnQgaGVyZS4NCj4gPj4NCj4gPj4gUGxlYXNlIHRlbGwgbWUgYXQg
d2hhdCBwb2ludChzKSB5b3VyIHRoaW5rIGl0IG1ha2Ugc2Vuc2UgdG8gaXNzdWUgdGhlDQo+ID4+
IFNMRUVQX05PVElGSUNBVElPTj8gSWYgdGhhdCBpcyBkdXJpbmcgdGhlIHN1c3BlbmQgcGhhc2Us
IHRoZW4gYSBIUEkNCj4gPj4gcmVxdWVzdCBjYW4ndCBiZSB0cmlnZ2VyZWQuDQo+ID4NCj4gPiBJ
IHRoaW5rIFNMRUVQX05PVElGSUNBVElPTiBzaG91bGQgYmUgaXNzdWVkIG9uIG1tY19wbV9ub3Rp
ZnkoKSBjYWxsLA0KPiA+IG9uIFBNX1NVU1BFTkRfUFJFUEFSRSBjYXNlLg0KPiANCj4gU28sIGV4
YWN0bHkgd2h5IGlzIHRoYXQgdG8gcHJlZmVyLCBjb21wYXJpbmcgZG9pbmcgaXQgaW4gc3lzdGVt
IFBNDQo+IC0+c3VzcGVuZCgpIGNhbGxiYWNrPw0KDQpBc3N1bWluZyB0aGF0IFNMRUVQX05PVElG
SUNBVElPTiBtYXkgdGFrZSB0aW1lDQooZGVmaW5lZCBpbiBTTEVFUF9OT1RJRklDQVRJT05fVElN
RSBieXRlIGluIEVYVF9DU0QgWzIxNl0pLA0KSSB0aGluayBpdCBpcyBiZXR0ZXIgdG8gc2VuZCBp
dCBmcm9tIHBtIG5vdGlmaWVyIC0gbW1jX3BtX25vdGlmeSgpLg0KDQo+IA0KPiBLaW5kIHJlZ2Fy
ZHMNCj4gVWZmZQ0K
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson March 16, 2015, 1:34 p.m. UTC | #13
On 16 March 2015 at 12:37, Alex Lemberg <Alex.Lemberg@sandisk.com> wrote:
> Hi Ulf,
>
>> -----Original Message-----
>> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]
>> Sent: Thursday, March 12, 2015 11:10 AM
>> To: Alex Lemberg
>> Cc: Avi Shchislowski; linux-mmc; Chris Ball
>> Subject: Re: [PATCH] mmc: sleep notification
>>
>> [...]
>>
>> >> > Also, I think we need to clarify one more point for this patch:
>> >> > As was mentioned in commit message - Sleep_Notification can be
>> >> > interrupted
>> >> by HPI.
>> >> > This allows not blocking the host during the Sleep_Notification
>> >> > busy time and allows accepting requests coming during this stage.
>> >> > Thus, without having HPI supported, suspend/resume process might be
>> >> > influenced by Sleep_Notification busy time, and this should not
>> >> > happen -
>> >> suspend/resume should be done in very fast and not blocking manner.
>> >>
>> >> I fail to understand your comment here.
>> >>
>> >> Please tell me at what point(s) your think it make sense to issue the
>> >> SLEEP_NOTIFICATION? If that is during the suspend phase, then a HPI
>> >> request can't be triggered.
>> >
>> > I think SLEEP_NOTIFICATION should be issued on mmc_pm_notify() call,
>> > on PM_SUSPEND_PREPARE case.
>>
>> So, exactly why is that to prefer, comparing doing it in system PM
>> ->suspend() callback?
>
> Assuming that SLEEP_NOTIFICATION may take time
> (defined in SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216]),
> I think it is better to send it from pm notifier - mmc_pm_notify().

I assume you think that you will "earn" some milliseconds doing it in
this phase, but I am not so sure.

After the PM_SUSPEND_PREPARE notifier, we still have the mmc block
queue open and are ready to serve requests. Therefore I would expect
the SLEEP_NOTIFICATION to potentially be interrupted by using HPI.

Then we end up with the following sequence during the system PM sleep phase.
1. Issue SLEEP_NOTIFICATION.
2. Interrupt SLEEP_NOTIFICATION, using HPI.
3. Serve blk request
4. Issue SLEEP_NOTIFICATION.
5. Issue SLEEP (CMD5).

That seems like a bad idea to me.

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alex Lemberg March 16, 2015, 4:58 p.m. UTC | #14
> -----Original Message-----

> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]

> Sent: Monday, March 16, 2015 3:35 PM

> To: Alex Lemberg

> Cc: Avi Shchislowski; linux-mmc; Chris Ball

> Subject: Re: [PATCH] mmc: sleep notification

> 

> On 16 March 2015 at 12:37, Alex Lemberg <Alex.Lemberg@sandisk.com>

> wrote:

> > Hi Ulf,

> >

> >> -----Original Message-----

> >> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]

> >> Sent: Thursday, March 12, 2015 11:10 AM

> >> To: Alex Lemberg

> >> Cc: Avi Shchislowski; linux-mmc; Chris Ball

> >> Subject: Re: [PATCH] mmc: sleep notification

> >>

> >> [...]

> >>

> >> >> > Also, I think we need to clarify one more point for this patch:

> >> >> > As was mentioned in commit message - Sleep_Notification can be

> >> >> > interrupted

> >> >> by HPI.

> >> >> > This allows not blocking the host during the Sleep_Notification

> >> >> > busy time and allows accepting requests coming during this stage.

> >> >> > Thus, without having HPI supported, suspend/resume process might

> >> >> > be influenced by Sleep_Notification busy time, and this should

> >> >> > not happen -

> >> >> suspend/resume should be done in very fast and not blocking manner.

> >> >>

> >> >> I fail to understand your comment here.

> >> >>

> >> >> Please tell me at what point(s) your think it make sense to issue

> >> >> the SLEEP_NOTIFICATION? If that is during the suspend phase, then

> >> >> a HPI request can't be triggered.

> >> >

> >> > I think SLEEP_NOTIFICATION should be issued on mmc_pm_notify()

> >> > call, on PM_SUSPEND_PREPARE case.

> >>

> >> So, exactly why is that to prefer, comparing doing it in system PM

> >> ->suspend() callback?

> >

> > Assuming that SLEEP_NOTIFICATION may take time (defined in

> > SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216]), I think it is better

> > to send it from pm notifier - mmc_pm_notify().

> 

> I assume you think that you will "earn" some milliseconds doing it in this phase,

> but I am not so sure.


I was thinking mainly about how to prevent "blocking" during Sleep_Notification process.

> 

> After the PM_SUSPEND_PREPARE notifier, we still have the mmc block queue

> open and are ready to serve requests. Therefore I would expect the

> SLEEP_NOTIFICATION to potentially be interrupted by using HPI.


Right, and this was a reason for adding HPI support during the Sleep_Notification.

> 

> Then we end up with the following sequence during the system PM sleep phase.

> 1. Issue SLEEP_NOTIFICATION.

> 2. Interrupt SLEEP_NOTIFICATION, using HPI.

> 3. Serve blk request

> 4. Issue SLEEP_NOTIFICATION.

> 5. Issue SLEEP (CMD5).


Correct, this is a sequence that we see after adding the patch.

> That seems like a bad idea to me.


Could you please explain why?
Would you suggest to call Sleep_Notification from Suspend only?
What if Sleep_Notification will take several seconds?

> 

> Kind regards

> Uffe
Ulf Hansson March 17, 2015, 10:43 a.m. UTC | #15
On 16 March 2015 at 17:58, Alex Lemberg <Alex.Lemberg@sandisk.com> wrote:
>
>
>> -----Original Message-----
>> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]
>> Sent: Monday, March 16, 2015 3:35 PM
>> To: Alex Lemberg
>> Cc: Avi Shchislowski; linux-mmc; Chris Ball
>> Subject: Re: [PATCH] mmc: sleep notification
>>
>> On 16 March 2015 at 12:37, Alex Lemberg <Alex.Lemberg@sandisk.com>
>> wrote:
>> > Hi Ulf,
>> >
>> >> -----Original Message-----
>> >> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]
>> >> Sent: Thursday, March 12, 2015 11:10 AM
>> >> To: Alex Lemberg
>> >> Cc: Avi Shchislowski; linux-mmc; Chris Ball
>> >> Subject: Re: [PATCH] mmc: sleep notification
>> >>
>> >> [...]
>> >>
>> >> >> > Also, I think we need to clarify one more point for this patch:
>> >> >> > As was mentioned in commit message - Sleep_Notification can be
>> >> >> > interrupted
>> >> >> by HPI.
>> >> >> > This allows not blocking the host during the Sleep_Notification
>> >> >> > busy time and allows accepting requests coming during this stage.
>> >> >> > Thus, without having HPI supported, suspend/resume process might
>> >> >> > be influenced by Sleep_Notification busy time, and this should
>> >> >> > not happen -
>> >> >> suspend/resume should be done in very fast and not blocking manner.
>> >> >>
>> >> >> I fail to understand your comment here.
>> >> >>
>> >> >> Please tell me at what point(s) your think it make sense to issue
>> >> >> the SLEEP_NOTIFICATION? If that is during the suspend phase, then
>> >> >> a HPI request can't be triggered.
>> >> >
>> >> > I think SLEEP_NOTIFICATION should be issued on mmc_pm_notify()
>> >> > call, on PM_SUSPEND_PREPARE case.
>> >>
>> >> So, exactly why is that to prefer, comparing doing it in system PM
>> >> ->suspend() callback?
>> >
>> > Assuming that SLEEP_NOTIFICATION may take time (defined in
>> > SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216]), I think it is better
>> > to send it from pm notifier - mmc_pm_notify().
>>
>> I assume you think that you will "earn" some milliseconds doing it in this phase,
>> but I am not so sure.
>
> I was thinking mainly about how to prevent "blocking" during Sleep_Notification process.
>
>>
>> After the PM_SUSPEND_PREPARE notifier, we still have the mmc block queue
>> open and are ready to serve requests. Therefore I would expect the
>> SLEEP_NOTIFICATION to potentially be interrupted by using HPI.
>
> Right, and this was a reason for adding HPI support during the Sleep_Notification.
>
>>
>> Then we end up with the following sequence during the system PM sleep phase.
>> 1. Issue SLEEP_NOTIFICATION.
>> 2. Interrupt SLEEP_NOTIFICATION, using HPI.
>> 3. Serve blk request
>> 4. Issue SLEEP_NOTIFICATION.
>> 5. Issue SLEEP (CMD5).
>
> Correct, this is a sequence that we see after adding the patch.
>
>> That seems like a bad idea to me.
>
> Could you please explain why?
> Would you suggest to call Sleep_Notification from Suspend only?

Since otherwise we may end up issuing SLEEP_NOTIFICATION not only
once, but twice during a system PM sleep sequence. So then we actually
get an increased system PM suspend time.

> What if Sleep_Notification will take several seconds?

Yes, that horrible! You should tell your colleagues designing FTLs to
make sure that _never_ happens.

Also, this makes me wonder how this kind of feature ever could make it
into the JEDEC specification.

What we had earlier with "CMD5 only" should never have been changed.

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alex Lemberg March 27, 2015, 12:13 p.m. UTC | #16
Hi Ulf,

Sorry for the delay in response...

> -----Original Message-----

> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]

> Sent: Tuesday, March 17, 2015 12:44 PM

> To: Alex Lemberg

> Cc: Avi Shchislowski; linux-mmc; Chris Ball

> Subject: Re: [PATCH] mmc: sleep notification

> 

> On 16 March 2015 at 17:58, Alex Lemberg <Alex.Lemberg@sandisk.com>

> wrote:

> >

> >

> >> -----Original Message-----

> >> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]

> >> Sent: Monday, March 16, 2015 3:35 PM

> >> To: Alex Lemberg

> >> Cc: Avi Shchislowski; linux-mmc; Chris Ball

> >> Subject: Re: [PATCH] mmc: sleep notification

> >>

> >> On 16 March 2015 at 12:37, Alex Lemberg <Alex.Lemberg@sandisk.com>

> >> wrote:

> >> > Hi Ulf,

> >> >

> >> >> -----Original Message-----

> >> >> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]

> >> >> Sent: Thursday, March 12, 2015 11:10 AM

> >> >> To: Alex Lemberg

> >> >> Cc: Avi Shchislowski; linux-mmc; Chris Ball

> >> >> Subject: Re: [PATCH] mmc: sleep notification

> >> >>

> >> >> [...]

> >> >>

> >> >> >> > Also, I think we need to clarify one more point for this patch:

> >> >> >> > As was mentioned in commit message - Sleep_Notification can

> >> >> >> > be interrupted

> >> >> >> by HPI.

> >> >> >> > This allows not blocking the host during the

> >> >> >> > Sleep_Notification busy time and allows accepting requests coming

> during this stage.

> >> >> >> > Thus, without having HPI supported, suspend/resume process

> >> >> >> > might be influenced by Sleep_Notification busy time, and this

> >> >> >> > should not happen -

> >> >> >> suspend/resume should be done in very fast and not blocking manner.

> >> >> >>

> >> >> >> I fail to understand your comment here.

> >> >> >>

> >> >> >> Please tell me at what point(s) your think it make sense to

> >> >> >> issue the SLEEP_NOTIFICATION? If that is during the suspend

> >> >> >> phase, then a HPI request can't be triggered.

> >> >> >

> >> >> > I think SLEEP_NOTIFICATION should be issued on mmc_pm_notify()

> >> >> > call, on PM_SUSPEND_PREPARE case.

> >> >>

> >> >> So, exactly why is that to prefer, comparing doing it in system PM

> >> >> ->suspend() callback?

> >> >

> >> > Assuming that SLEEP_NOTIFICATION may take time (defined in

> >> > SLEEP_NOTIFICATION_TIME byte in EXT_CSD [216]), I think it is

> >> > better to send it from pm notifier - mmc_pm_notify().

> >>

> >> I assume you think that you will "earn" some milliseconds doing it in

> >> this phase, but I am not so sure.

> >

> > I was thinking mainly about how to prevent "blocking" during

> Sleep_Notification process.

> >

> >>

> >> After the PM_SUSPEND_PREPARE notifier, we still have the mmc block

> >> queue open and are ready to serve requests. Therefore I would expect

> >> the SLEEP_NOTIFICATION to potentially be interrupted by using HPI.

> >

> > Right, and this was a reason for adding HPI support during the

> Sleep_Notification.

> >

> >>

> >> Then we end up with the following sequence during the system PM sleep

> phase.

> >> 1. Issue SLEEP_NOTIFICATION.

> >> 2. Interrupt SLEEP_NOTIFICATION, using HPI.

> >> 3. Serve blk request

> >> 4. Issue SLEEP_NOTIFICATION.

> >> 5. Issue SLEEP (CMD5).

> >

> > Correct, this is a sequence that we see after adding the patch.

> >

> >> That seems like a bad idea to me.

> >

> > Could you please explain why?

> > Would you suggest to call Sleep_Notification from Suspend only?

> 

> Since otherwise we may end up issuing SLEEP_NOTIFICATION not only once, but

> twice during a system PM sleep sequence. So then we actually get an increased

> system PM suspend time.

> 

> > What if Sleep_Notification will take several seconds?

> 

> Yes, that horrible! You should tell your colleagues designing FTLs to make sure

> that _never_ happens.


Agree, but we need to consider and take care of all such cases in the driver side. 
Device might be busy with its internal garbage collection, and as spec allows, it
will complete it in a great manner after host sends PON command.
 
> 

> Also, this makes me wonder how this kind of feature ever could make it into the

> JEDEC specification.

> 

> What we had earlier with "CMD5 only" should never have been changed.

> 

> Kind regards

> Uffe
Ulf Hansson March 27, 2015, 12:57 p.m. UTC | #17
[...]

>> > What if Sleep_Notification will take several seconds?
>>
>> Yes, that horrible! You should tell your colleagues designing FTLs to make sure
>> that _never_ happens.
>
> Agree, but we need to consider and take care of all such cases in the driver side.
> Device might be busy with its internal garbage collection, and as spec allows, it
> will complete it in a great manner after host sends PON command.
>

Okay, so to me, I think the SLEEP notification needs to be sent as a
part of the system PM suspend phase. And more exactly from the
bus_ops->suspend() callback.

In addition to that, we should be able improve the situation by also
sending the SLEEP notification as part of an "idle operation". With
"idle operation" I mean the mmc block layer hasn’t received any new
request for a while (the framework for this is already implemented by
using runtime PM).

So if the SLEEP notification was sent during the "idle operation" and
no new request was needed during the system PM suspend phase we
wouldn't have to wake up the card again using HPI, but instead just
leave it "sleeping" and send CMD5.

Still, there would be no guarantees that "idle operations" is executed
before a system PM suspend phase starts. So there are no way we can
improve the worst case scenario.

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alex Lemberg March 31, 2015, 4:22 p.m. UTC | #18
Hi Ulf,

> -----Original Message-----

> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]

> Sent: Friday, March 27, 2015 3:57 PM

> To: Alex Lemberg

> Cc: Avi Shchislowski; linux-mmc; Chris Ball

> Subject: Re: [PATCH] mmc: sleep notification

> 

> [...]

> 

> >> > What if Sleep_Notification will take several seconds?

> >>

> >> Yes, that horrible! You should tell your colleagues designing FTLs to

> >> make sure that _never_ happens.

> >

> > Agree, but we need to consider and take care of all such cases in the driver

> side.

> > Device might be busy with its internal garbage collection, and as spec

> > allows, it will complete it in a great manner after host sends PON command.

> >

> 

> Okay, so to me, I think the SLEEP notification needs to be sent as a part of the

> system PM suspend phase. And more exactly from the

> bus_ops->suspend() callback.

> 


PM suspend phase is a right place for PON Sleep_Notification,
but it also the critical one and need to be completed as fast as possible.

If I'm not mistaken, during the PM Suspend, the user space is freezing.
Is it OK to let PON Sleep_Notification to be called at that stage?

Calling from the notifier_call (mmc_pm_notify()) will allow to complete 
Sleep_Notification process before entering to the critical part - the Suspend.
Isn't it?

> In addition to that, we should be able improve the situation by also sending the

> SLEEP notification as part of an "idle operation". With "idle operation" I mean

> the mmc block layer hasn’t received any new request for a while (the

> framework for this is already implemented by using runtime PM).


OK, sounds like a good approach. 
In case runtime PM is supported, we can call PON Sleep_Notification from 
mmc_runtime_suspend() during the "idle operation",
and then call it again during PM Suspend.

> 

> So if the SLEEP notification was sent during the "idle operation" and no new

> request was needed during the system PM suspend phase we wouldn't have to

> wake up the card again using HPI, but instead just leave it "sleeping" and send

> CMD5.

> 

> Still, there would be no guarantees that "idle operations" is executed before a

> system PM suspend phase starts. So there are no way we can improve the

> worst case scenario.

> 

> Kind regards

> Uffe
Ulf Hansson April 1, 2015, 11:46 a.m. UTC | #19
[...]

>> Okay, so to me, I think the SLEEP notification needs to be sent as a part of the
>> system PM suspend phase. And more exactly from the
>> bus_ops->suspend() callback.
>>
>
> PM suspend phase is a right place for PON Sleep_Notification,
> but it also the critical one and need to be completed as fast as possible.
>
> If I'm not mistaken, during the PM Suspend, the user space is freezing.
> Is it OK to let PON Sleep_Notification to be called at that stage?

Of course we shall strive in minimizing the system PM suspend time.
Though to me, I think the system PM _resume_ time is of more
importance.

In this case we don't have any option. We need to issue the sleep
notification as part of the the system PM suspend phase and that will
unfortunate and likely increase the total system PM suspend time.

>
> Calling from the notifier_call (mmc_pm_notify()) will allow to complete
> Sleep_Notification process before entering to the critical part - the Suspend.
> Isn't it?

Why is mmc_pm_notify() a less critical part?

More importantly as stated several times, we can still get I/O
requests after the mmc_pm_notify() phase and then the sleep
notification needs to be interrupted and re-issued anyway.

>
>> In addition to that, we should be able improve the situation by also sending the
>> SLEEP notification as part of an "idle operation". With "idle operation" I mean
>> the mmc block layer hasn’t received any new request for a while (the
>> framework for this is already implemented by using runtime PM).
>
> OK, sounds like a good approach.
> In case runtime PM is supported, we can call PON Sleep_Notification from
> mmc_runtime_suspend() during the "idle operation",
> and then call it again during PM Suspend.

Yes.

If you plan to send a new version of $subject patch, please split into
at least two patches. One which adds the system PM part and one which
adds the "idle operation" part.

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alex Lemberg April 6, 2015, 1:44 p.m. UTC | #20
Hi Ulf,

> -----Original Message-----

> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]

> Sent: Wednesday, April 01, 2015 2:46 PM

> To: Alex Lemberg

> Cc: Avi Shchislowski; linux-mmc; Chris Ball

> Subject: Re: [PATCH] mmc: sleep notification

> 

> [...]

> 

> >> Okay, so to me, I think the SLEEP notification needs to be sent as a

> >> part of the system PM suspend phase. And more exactly from the

> >> bus_ops->suspend() callback.

> >>

> >

> > PM suspend phase is a right place for PON Sleep_Notification, but it

> > also the critical one and need to be completed as fast as possible.

> >

> > If I'm not mistaken, during the PM Suspend, the user space is freezing.

> > Is it OK to let PON Sleep_Notification to be called at that stage?

> 

> Of course we shall strive in minimizing the system PM suspend time.

> Though to me, I think the system PM _resume_ time is of more importance.

> 

> In this case we don't have any option. We need to issue the sleep notification as

> part of the the system PM suspend phase and that will unfortunate and likely

> increase the total system PM suspend time.

> 

> >

> > Calling from the notifier_call (mmc_pm_notify()) will allow to

> > complete Sleep_Notification process before entering to the critical part - the

> Suspend.

> > Isn't it?

> 

> Why is mmc_pm_notify() a less critical part?

> 

> More importantly as stated several times, we can still get I/O requests after

> the mmc_pm_notify() phase and then the sleep notification needs to be

> interrupted and re-issued anyway.


You are right - the sleep_notification might be re-issued several times,
but in case of mmc_pm_notify() the user space is not frozen yet, and 
system will not stuck until sleep_notification completion, like in case of 
PM suspend.

> 

> >

> >> In addition to that, we should be able improve the situation by also

> >> sending the SLEEP notification as part of an "idle operation". With

> >> "idle operation" I mean the mmc block layer hasn’t received any new

> >> request for a while (the framework for this is already implemented by using

> runtime PM).

> >

> > OK, sounds like a good approach.

> > In case runtime PM is supported, we can call PON Sleep_Notification

> > from

> > mmc_runtime_suspend() during the "idle operation", and then call it

> > again during PM Suspend.

> 

> Yes.

> 

> If you plan to send a new version of $subject patch, please split into at least two

> patches. One which adds the system PM part and one which adds the "idle

> operation" part.


As far as I see, the same _mmc_suspend() function is used in both cases - 
PM Suspend and "idle operation".
The _mmc_suspend() is called from both  - mmc_suspend() and
mmc_runtime_suspend().
In case we decide to go with PM Suspend and "idle operation",
should we just add the sleep_notification support to _mmc_suspend() for
covering both cases?

> 

> Kind regards

> Uffe
Ulf Hansson April 8, 2015, 9:49 a.m. UTC | #21
On 6 April 2015 at 15:44, Alex Lemberg <Alex.Lemberg@sandisk.com> wrote:
> Hi Ulf,
>
>> -----Original Message-----
>> From: Ulf Hansson [mailto:ulf.hansson@linaro.org]
>> Sent: Wednesday, April 01, 2015 2:46 PM
>> To: Alex Lemberg
>> Cc: Avi Shchislowski; linux-mmc; Chris Ball
>> Subject: Re: [PATCH] mmc: sleep notification
>>
>> [...]
>>
>> >> Okay, so to me, I think the SLEEP notification needs to be sent as a
>> >> part of the system PM suspend phase. And more exactly from the
>> >> bus_ops->suspend() callback.
>> >>
>> >
>> > PM suspend phase is a right place for PON Sleep_Notification, but it
>> > also the critical one and need to be completed as fast as possible.
>> >
>> > If I'm not mistaken, during the PM Suspend, the user space is freezing.
>> > Is it OK to let PON Sleep_Notification to be called at that stage?
>>
>> Of course we shall strive in minimizing the system PM suspend time.
>> Though to me, I think the system PM _resume_ time is of more importance.
>>
>> In this case we don't have any option. We need to issue the sleep notification as
>> part of the the system PM suspend phase and that will unfortunate and likely
>> increase the total system PM suspend time.
>>
>> >
>> > Calling from the notifier_call (mmc_pm_notify()) will allow to
>> > complete Sleep_Notification process before entering to the critical part - the
>> Suspend.
>> > Isn't it?
>>
>> Why is mmc_pm_notify() a less critical part?
>>
>> More importantly as stated several times, we can still get I/O requests after
>> the mmc_pm_notify() phase and then the sleep notification needs to be
>> interrupted and re-issued anyway.
>
> You are right - the sleep_notification might be re-issued several times,
> but in case of mmc_pm_notify() the user space is not frozen yet, and
> system will not stuck until sleep_notification completion, like in case of
> PM suspend.
>
>>
>> >
>> >> In addition to that, we should be able improve the situation by also
>> >> sending the SLEEP notification as part of an "idle operation". With
>> >> "idle operation" I mean the mmc block layer hasn’t received any new
>> >> request for a while (the framework for this is already implemented by using
>> runtime PM).
>> >
>> > OK, sounds like a good approach.
>> > In case runtime PM is supported, we can call PON Sleep_Notification
>> > from
>> > mmc_runtime_suspend() during the "idle operation", and then call it
>> > again during PM Suspend.
>>
>> Yes.
>>
>> If you plan to send a new version of $subject patch, please split into at least two
>> patches. One which adds the system PM part and one which adds the "idle
>> operation" part.
>
> As far as I see, the same _mmc_suspend() function is used in both cases -
> PM Suspend and "idle operation".
> The _mmc_suspend() is called from both  - mmc_suspend() and
> mmc_runtime_suspend().
> In case we decide to go with PM Suspend and "idle operation",
> should we just add the sleep_notification support to _mmc_suspend() for
> covering both cases?

That works as a start.

Though, it would mean MMC_CAP_AGGRESSIVE_PM is needed to enable "idle
operations" for this case. It might be good enough. If not, we need to
send the sleep notification from mmc_runtime_suspend() as well.

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

Patch

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 4409d79..f511ecc3 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2010,9 +2010,26 @@  static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 	unsigned long flags;
 	unsigned int cmd_flags = req ? req->cmd_flags : 0;
 
-	if (req && !mq->mqrq_prev->req)
+	if (unlikely(req && mmc_card_mmc(card) &&
+		(card->ext_csd.power_off_notification ==
+		EXT_CSD_SLEEP_NOTIFICATION))) {
+		/* restoring the power_off_notification
+		 * field's state to as it was before so
+		 * that the sleep notification will be
+		 * able to resume later
+		 */
+		card->ext_csd.power_off_notification = EXT_CSD_POWER_ON;
+	}
+
+	if (req && !mq->mqrq_prev->req) {
 		/* claim host only for the first request */
 		mmc_get_card(card);
+		if (unlikely(req &&
+			mmc_card_doing_sleep_notify(card))) {
+			mmc_interrupt_hpi(card);
+			mmc_card_clr_sleep_notify(card);
+		}
+	}
 
 	ret = mmc_blk_part_switch(card, md);
 	if (ret) {
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 5bda29b..a090593 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -271,7 +271,8 @@  void mmc_start_bkops(struct mmc_card *card, bool from_exception)
 
 	BUG_ON(!card);
 
-	if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
+	if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card) ||
+		mmc_card_doing_sleep_notify(card))
 		return;
 
 	err = mmc_read_bkops_status(card);
@@ -2630,6 +2631,19 @@  int mmc_pm_notify(struct notifier_block *notify_block,
 			err = host->bus_ops->pre_suspend(host);
 		if (!err)
 			break;
+		if (host->card && host->bus_ops->suspend) {
+			err = mmc_sleep_notify(host->card);
+			/* We assume that HPI was sent
+			 * in case of -ETIMEDOUT error,
+			 * so suspend flow can be continued
+			 */
+			if (err && err != -ETIMEDOUT) {
+				pr_err("%s:sleep notify err=%d\n",
+					__func__, err);
+				return -EBUSY;
+			}
+			break;
+		}
 
 		/* Calling bus_ops->remove() with a claimed host can deadlock */
 		host->bus_ops->remove(host);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index d76597c..b6b4431 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -14,6 +14,7 @@ 
 #include <linux/delay.h>
 
 #define MMC_CMD_RETRIES        3
+#define MMC_SLEEP_NOTIFY_MAX_TIME	0x17
 
 struct mmc_bus_ops {
 	void (*remove)(struct mmc_host *);
@@ -33,6 +34,7 @@  void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
 void mmc_detach_bus(struct mmc_host *host);
 
 void mmc_init_erase(struct mmc_card *card);
+int mmc_sleep_notify(struct mmc_card *card);
 
 void mmc_set_chip_select(struct mmc_host *host, int mode);
 void mmc_set_clock(struct mmc_host *host, unsigned int hz);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 02ad792..1d97d24 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -57,6 +57,11 @@  static const unsigned int tacc_mant[] = {
 		__res & __mask;						\
 	})
 
+#define GET_SLEEP_NOTIFY_TIME(value) \
+	(10 * (1 << (unsigned int)(value)))
+#define GET_SLEEP_NOTIFY_TIME_MSEC(value) \
+	(DIV_ROUND_UP(GET_SLEEP_NOTIFY_TIME(value), 1000))
+
 /*
  * Given the decoded CSD structure, decode the raw CID to our CID structure.
  */
@@ -571,6 +576,8 @@  static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
 		card->ext_csd.ffu_capable =
 			(ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) &&
 			!(ext_csd[EXT_CSD_FW_CONFIG] & 0x1);
+		card->ext_csd.sleep_notify_time =
+			ext_csd[EXT_CSD_SLEEP_NOTIFICATION_TIME];
 	}
 out:
 	return err;
@@ -1468,6 +1475,15 @@  static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			card->ext_csd.hpi_en = 1;
 	}
 
+	/* sleep notify enable/disable for eMMC 5.0 and above */
+	if ((card->ext_csd.rev >= 7) &&  card->ext_csd.hpi_en &&
+			(card->host->caps2 & MMC_CAP2_SLEEP_NOTIFY) &&
+			card->ext_csd.sleep_notify_time > 0 &&
+			card->ext_csd.sleep_notify_time <=
+				MMC_SLEEP_NOTIFY_MAX_TIME) {
+		card->can_sleep_notify = 1;
+	}
+
 	/*
 	 * If cache size is higher than 0, this indicates
 	 * the existence of cache and it can be turned on.
@@ -1576,6 +1592,33 @@  static int mmc_sleep(struct mmc_host *host)
 	return err;
 }
 
+/*
+ * check if device is in program state (busy)
+ */
+static bool mmc_device_prg_state(struct mmc_card *card)
+{
+	int rc;
+	u32 status;
+	bool state;
+
+	mmc_get_card(card);
+	rc = mmc_send_status(card, &status);
+	if (rc) {
+		pr_err("%s: Get card status fail. rc=%d\n",
+			mmc_hostname(card->host), rc);
+		state = false;
+		goto out;
+	}
+
+	if (R1_CURRENT_STATE(status) == R1_STATE_PRG)
+		state =  true;
+	else
+		state =  false;
+out:
+	mmc_put_card(card);
+	return state;
+}
+
 static int mmc_can_poweroff_notify(const struct mmc_card *card)
 {
 	return card &&
@@ -1585,22 +1628,108 @@  static int mmc_can_poweroff_notify(const struct mmc_card *card)
 
 static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
 {
-	unsigned int timeout = card->ext_csd.generic_cmd6_time;
+	unsigned int timeout_ms = card->ext_csd.generic_cmd6_time;
 	int err;
+	bool use_busy_signal;
 
 	/* Use EXT_CSD_POWER_OFF_SHORT as default notification type. */
 	if (notify_type == EXT_CSD_POWER_OFF_LONG)
-		timeout = card->ext_csd.power_off_longtime;
+		timeout_ms = card->ext_csd.power_off_longtime;
+	else if (notify_type == EXT_CSD_SLEEP_NOTIFICATION) {
+		/* calculate the maximum timeout for the
+		 * switch command when notifying the device
+		 * that it is about to move to sleep */
+		timeout_ms = GET_SLEEP_NOTIFY_TIME_MSEC(
+			card->ext_csd.sleep_notify_time);
+	}
 
+	/* do not wait on busy signal in case of
+	 * Sleep Notification - to let host get
+	 * another requests
+	 */
+	use_busy_signal = (notify_type == EXT_CSD_SLEEP_NOTIFICATION) ?
+			false : true;
 	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 			EXT_CSD_POWER_OFF_NOTIFICATION,
-			notify_type, timeout, true, false, false);
-	if (err)
+			notify_type, timeout_ms,
+			use_busy_signal, false, false);
+	if (!err) {
+		card->ext_csd.power_off_notification = notify_type;
+	} else {
 		pr_err("%s: Power Off Notification timed out, %u\n",
-		       mmc_hostname(card->host), timeout);
+			mmc_hostname(card->host), timeout_ms);
+	}
+
+	return err;
+}
 
-	/* Disable the power off notification after the switch operation. */
-	card->ext_csd.power_off_notification = EXT_CSD_NO_POWER_NOTIFICATION;
+int mmc_sleep_notify(struct mmc_card *card)
+{
+	int err = 0;
+	bool is_busy = 0;
+	unsigned long prg_wait = 0;
+
+	if (!card->can_sleep_notify || !mmc_can_poweroff_notify(card))
+		return 0;
+
+	if (!mmc_card_doing_sleep_notify(card)) {
+		mmc_get_card(card);
+		mmc_card_set_sleep_notify(card);
+		err = mmc_poweroff_notify(card,
+			EXT_CSD_SLEEP_NOTIFICATION);
+		mmc_put_card(card);
+		if (err) {
+			pr_err("%s: mmc_poweroff_notify failed with %d\n",
+			       __func__, err);
+			goto out;
+		}
+
+		prg_wait = jiffies +
+			msecs_to_jiffies(GET_SLEEP_NOTIFY_TIME_MSEC(
+			card->ext_csd.sleep_notify_time));
+		}
+
+	/*
+	 * Loop will run until:
+	 * 1. Device is no more in Busy state
+	 * 2. Sleep notification is not interrupted by HPI & IO request
+	 */
+	do {
+		/* added some delay to avoid sending card status too often */
+		msleep(20);
+		err = 0;
+		/* Stop polling in case sleep notification was HPIed already */
+		if (!mmc_card_doing_sleep_notify(card)) {
+			is_busy = mmc_device_prg_state(card);
+			if (is_busy)
+				err = -EBUSY;
+			break;
+		}
+		is_busy = mmc_device_prg_state(card);
+		if (is_busy && time_after(jiffies, prg_wait)) {
+			/*
+			 * making sure we are still in busy before
+			 * sending HPI due to timeout error
+			 */
+			is_busy = mmc_device_prg_state(card);
+			if (is_busy) {
+				if (mmc_card_doing_sleep_notify(card)) {
+					card->ext_csd.power_off_notification =
+						EXT_CSD_POWER_ON;
+					mmc_interrupt_hpi(card);
+				}
+				err = -ETIMEDOUT;
+				break;
+			}
+		}
+	} while (is_busy);
+
+out:
+	mmc_card_clr_sleep_notify(card);
+	if (err) {
+		pr_err("%s: mmc_poweroff_notify for sleep failed with %d\n",
+		       mmc_hostname(card->host), err);
+	}
 
 	return err;
 }
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 4d69c00..6998344 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -62,6 +62,7 @@  struct mmc_ext_csd {
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		generic_cmd6_time;	/* Units: 10ms */
 	unsigned int            power_off_longtime;     /* Units: ms */
+	unsigned int		sleep_notify_time;	/* Units: us */
 	u8			power_off_notification;	/* state */
 	unsigned int		hs_max_dtr;
 	unsigned int		hs200_max_dtr;
@@ -262,6 +263,7 @@  struct mmc_card {
 #define MMC_CARD_REMOVED	(1<<4)		/* card has been removed */
 #define MMC_STATE_DOING_BKOPS	(1<<5)		/* card is doing BKOPS */
 #define MMC_STATE_SUSPENDED	(1<<6)		/* card is suspended */
+#define MMC_STATE_SLEEP_NOTIFY (1<<7)		/* card in sleep notify */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -309,6 +311,7 @@  struct mmc_card {
 	struct dentry		*debugfs_root;
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
 	unsigned int    nr_parts;
+	u8 can_sleep_notify;	/* sleep_notify on/off */
 };
 
 /*
@@ -427,6 +430,7 @@  static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
 #define mmc_card_suspended(c)	((c)->state & MMC_STATE_SUSPENDED)
+#define mmc_card_doing_sleep_notify(c) ((c)->state & MMC_STATE_SLEEP_NOTIFY)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -437,6 +441,8 @@  static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_clr_doing_bkops(c)	((c)->state &= ~MMC_STATE_DOING_BKOPS)
 #define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
 #define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
+#define mmc_card_set_sleep_notify(c)	((c)->state |= MMC_STATE_SLEEP_NOTIFY)
+#define mmc_card_clr_sleep_notify(c)	((c)->state &= ~MMC_STATE_SLEEP_NOTIFY)
 
 /*
  * Quirk add/remove for MMC products.
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 9f32270..4c0542a 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -291,6 +291,7 @@  struct mmc_host {
 				 MMC_CAP2_HS400_1_2V)
 #define MMC_CAP2_HSX00_1_2V	(MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
 #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
+#define MMC_CAP2_SLEEP_NOTIFY	(1 << 18)	/* sleep notify supported */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 49ad7a9..69bda9a 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -314,6 +314,7 @@  struct _mmc_csd {
 #define EXT_CSD_PWR_CL_52_360		202	/* RO */
 #define EXT_CSD_PWR_CL_26_360		203	/* RO */
 #define EXT_CSD_SEC_CNT			212	/* RO, 4 bytes */
+#define EXT_CSD_SLEEP_NOTIFICATION_TIME	216	/* RO */
 #define EXT_CSD_S_A_TIMEOUT		217	/* RO */
 #define EXT_CSD_REL_WR_SEC_C		222	/* RO */
 #define EXT_CSD_HC_WP_GRP_SIZE		221	/* RO */
@@ -408,6 +409,7 @@  struct _mmc_csd {
 #define EXT_CSD_POWER_ON		1
 #define EXT_CSD_POWER_OFF_SHORT		2
 #define EXT_CSD_POWER_OFF_LONG		3
+#define EXT_CSD_SLEEP_NOTIFICATION	4
 
 #define EXT_CSD_PWR_CL_8BIT_MASK	0xF0	/* 8 bit PWR CLS */
 #define EXT_CSD_PWR_CL_4BIT_MASK	0x0F	/* 8 bit PWR CLS */