Hi Shawn, Is the intention in this patch to stop using MANUAL_BKOPS for all eMMC5.1+ devices, and only use AUTO_BKOPS? Please see several questions inline. On 6/6/16, 6:07 AM, "linux-mmc-owner@xxxxxxxxxxxxxxx on behalf of Shawn Lin" <linux-mmc-owner@xxxxxxxxxxxxxxx on behalf of shawn.lin@xxxxxxxxxxxxxx> wrote: >JEDEC eMMC v5.1 introduce an autonomously initiated method >for background operations. > >Host that wants to enable the device to perform background >operations during device idle time, should signal the device >by setting AUTO_EN in BKOPS_EN field EXT_CSD[163] to 1b. When >this bit is set, the device may start or stop background operations >whenever it sees fit, without any notification to the host. > >When AUTO_EN bit is set, the host should keep the device power >active. The host may set or clear this bit at any time based on >its power constraints or other considerations. > >Currently the manual bkops is only be used under the async req >circumstances and it's a bit complicated to be controlled as the >perfect method is that we should do some idle monitor just as rpm >and send HPI each time if receiving rd/wr req. But it will impact >performance significantly, especially for random iops since the >weight of executing HPI against r/w small piece of LBAs is >nonnegligible. > >So we now prefer to select the auto one unconditionally if supported >which makes it as simple as possible. It should really good enough >for devices to manage its internal policy for bkops rather than the >host, which makes us believe that we could achieve the best >performance for all the devices implementing auto bkops and the only >thing we should do is to disable it when cutting off the power. > >Signed-off-by: Shawn Lin <shawn.lin@xxxxxxxxxxxxxx> >--- > > drivers/mmc/core/core.c | 127 +++++++++++++++++++++++++++++++++++++---------- > drivers/mmc/core/mmc.c | 30 ++++++++++- > include/linux/mmc/card.h | 1 + > include/linux/mmc/core.h | 4 +- > include/linux/mmc/mmc.h | 1 + > 5 files changed, 133 insertions(+), 30 deletions(-) > >diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c >index e864187..c2e5a66 100644 >--- a/drivers/mmc/core/core.c >+++ b/drivers/mmc/core/core.c >@@ -297,24 +297,13 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) > return 0; > } > >-/** >- * mmc_start_bkops - start BKOPS for supported cards >- * @card: MMC card to start BKOPS >- * @form_exception: A flag to indicate if this function was >- * called due to an exception raised by the card >- * >- * Start background operations whenever requested. >- * When the urgent BKOPS bit is set in a R1 command response >- * then background operations should be started immediately. >-*/ >-void mmc_start_bkops(struct mmc_card *card, bool from_exception) >+static void mmc_start_man_bkops(struct mmc_card *card, >+ bool from_exception) > { > int err; > int timeout; > bool use_busy_signal; > >- BUG_ON(!card); >- > if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card)) > return; > >@@ -347,7 +336,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) > EXT_CSD_BKOPS_START, 1, timeout, > use_busy_signal, true, false); > if (err) { >- pr_warn("%s: Error %d starting bkops\n", >+ pr_warn("%s: Error %d starting manual bkops\n", > mmc_hostname(card->host), err); > mmc_retune_release(card->host); > goto out; >@@ -365,6 +354,55 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) > out: > mmc_release_host(card->host); > } >+ >+static void mmc_start_auto_bkops(struct mmc_card *card) >+{ >+ int err; >+ >+ /* If it's already enable auto_bkops, nothing to do */ >+ if (card->ext_csd.auto_bkops_en) >+ return; >+ >+ mmc_claim_host(card->host); >+ >+ mmc_retune_hold(card->host); >+ >+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, >+ EXT_CSD_BKOPS_EN, 2, >+ card->ext_csd.generic_cmd6_time); >+ if (err) >+ pr_warn("%s: Error %d starting auto bkops\n", >+ mmc_hostname(card->host), err); >+ >+ card->ext_csd.auto_bkops_en = true; >+ mmc_card_set_doing_bkops(card); >+ mmc_retune_release(card->host); >+ mmc_release_host(card->host); >+} >+ >+ >+/** >+ * mmc_start_bkops - start BKOPS for supported cards >+ * @card: MMC card to start BKOPS >+ * @form_exception: A flag to indicate if this function was >+ * called due to an exception raised by the card >+ * @is_auto: A flag to indicate if we should use auto bkops >+ * >+ * Start background operations whenever requested. >+ * When the urgent BKOPS bit is set in a R1 command response >+ * then background operations should be started immediately, which is >+ * only needed for man_bkops. >+*/ >+void mmc_start_bkops(struct mmc_card *card, bool from_exception, >+ bool is_auto) >+{ >+ BUG_ON(!card); >+ >+ if (is_auto) As far as I understand, the AUTO_BKOPS is enabled during “mmc_init_card()”. If its correct, why the “mmc_start_auto_bkops()” function is needed? >+ return mmc_start_auto_bkops(card); >+ else >+ return mmc_start_man_bkops(card, from_exception); >+} > EXPORT_SYMBOL(mmc_start_bkops); > > /* >@@ -610,7 +648,9 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, > if (areq) > mmc_post_req(host, areq->mrq, -EINVAL); > >- mmc_start_bkops(host->card, true); >+ /* Prefer to use auto bkops for eMMC 5.1 or later */ If the decision is to use AUTO_BKOPS for all eMMC5.1+ devices, why you need to enable AUTO_BKOPS bit on every R1_EXCEPTION_EVENT? AUTO_BKOPS should be enabled only once... >+ mmc_start_bkops(host->card, true, >+ host->card->ext_csd.rev >= 8); > > /* prepare the request again */ > if (areq) >@@ -751,20 +791,10 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries > > EXPORT_SYMBOL(mmc_wait_for_cmd); > >-/** >- * mmc_stop_bkops - stop ongoing BKOPS >- * @card: MMC card to check BKOPS >- * >- * Send HPI command to stop ongoing background operations to >- * allow rapid servicing of foreground operations, e.g. read/ >- * writes. Wait until the card comes out of the programming state >- * to avoid errors in servicing read/write requests. >- */ >-int mmc_stop_bkops(struct mmc_card *card) >+static int mmc_stop_man_bkops(struct mmc_card *card) > { > int err = 0; > >- BUG_ON(!card); > err = mmc_interrupt_hpi(card); > > /* >@@ -779,6 +809,51 @@ int mmc_stop_bkops(struct mmc_card *card) > > return err; > } >+ >+static int mmc_stop_auto_bkops(struct mmc_card *card) >+{ >+ int err = 0; >+ >+ if (!card->ext_csd.auto_bkops_en) >+ return 0; >+ Shouldn’t the BKOPS_STATUS be checked prior to disabling the BKOPS activity of the device? >+ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, >+ EXT_CSD_BKOPS_EN, 0, MMC_BKOPS_MAX_TIMEOUT, >+ true, true, false); >+ if (err) >+ pr_warn("%s: Error %d stoping auto bkops\n", >+ mmc_hostname(card->host), err); >+ >+ card->ext_csd.auto_bkops_en = false; >+ mmc_card_clr_doing_bkops(card); >+ mmc_retune_release(card->host); >+ >+ return err; >+} >+ >+/** >+ * mmc_stop_bkops - stop ongoing BKOPS >+ * @card: MMC card to check BKOPS >+ * @is_auto: A flag to indicate if we should use auto bkops >+ * >+ * Send HPI command to stop ongoing background operations to >+ * allow rapid servicing of foreground operations, e.g. read/ >+ * writes. Wait until the card comes out of the programming state >+ * to avoid errors in servicing read/write requests. >+ * >+ * But for auto bkops, we could only disable AUTO_EN instead of >+ * sending HPI. And the firmware could do it automatically. >+ * >+ */ >+int mmc_stop_bkops(struct mmc_card *card, bool is_auto) >+{ >+ BUG_ON(!card); >+ >+ if (is_auto) >+ return mmc_stop_auto_bkops(card); >+ else >+ return mmc_stop_man_bkops(card); >+} > EXPORT_SYMBOL(mmc_stop_bkops); > > int mmc_read_bkops_status(struct mmc_card *card) >diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c >index 61d6b34..c65bea7 100644 >--- a/drivers/mmc/core/mmc.c >+++ b/drivers/mmc/core/mmc.c >@@ -508,6 +508,13 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) > /* check whether the eMMC card supports BKOPS */ > if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) { > card->ext_csd.bkops = 1; >+ >+ /* for eMMC v5.1 or later, we could use auto_bkops */ >+ if (card->ext_csd.rev >= 8) >+ card->ext_csd.auto_bkops_en = >+ (ext_csd[EXT_CSD_BKOPS_EN] & >+ EXT_CSD_AUTO_BKOPS_MASK); >+ > card->ext_csd.man_bkops_en = > (ext_csd[EXT_CSD_BKOPS_EN] & > EXT_CSD_MANUAL_BKOPS_MASK); >@@ -516,6 +523,9 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) > if (!card->ext_csd.man_bkops_en) > pr_debug("%s: MAN_BKOPS_EN bit is not set\n", > mmc_hostname(card->host)); >+ if (!card->ext_csd.auto_bkops_en) >+ pr_debug("%s: AUTO_BKOPS_EN bit is not set\n", >+ mmc_hostname(card->host)); > } > > /* check whether the eMMC card supports HPI */ >@@ -1241,7 +1251,7 @@ static int mmc_select_hs400es(struct mmc_card *card) > } > > err = mmc_select_bus_width(card); >- if (IS_ERR_VALUE(err)) >+ if (err < 0) > goto out_err; > > /* Switch card to HS mode */ >@@ -1676,6 +1686,21 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, > mmc_select_powerclass(card); > > /* >+ * Enable auto bkops feature which is mandatory for >+ * eMMC v5.1 or later >+ */ >+ if (card->ext_csd.rev >= 8) { >+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, >+ EXT_CSD_BKOPS_EN, 2, >+ card->ext_csd.generic_cmd6_time); >+ if (err) >+ pr_warn("%s: Error %d starting auto bkops\n", >+ mmc_hostname(card->host), err); >+ >+ card->ext_csd.auto_bkops_en = true; >+ } >+ >+ /* > * Enable HPI feature (if supported) > */ > if (card->ext_csd.hpi) { >@@ -1898,7 +1923,8 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) > goto out; > > if (mmc_card_doing_bkops(host->card)) { >- err = mmc_stop_bkops(host->card); >+ err = mmc_stop_bkops(host->card, >+ host->card->ext_csd.rev >= 8); > if (err) > goto out; > } >diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h >index 22defc2..f82f9be 100644 >--- a/include/linux/mmc/card.h >+++ b/include/linux/mmc/card.h >@@ -84,6 +84,7 @@ struct mmc_ext_csd { > unsigned int hpi_cmd; /* cmd used as HPI */ > bool bkops; /* background support bit */ > bool man_bkops_en; /* manual bkops enable bit */ >+ bool auto_bkops_en; /* auto bkops enbale bit */ > unsigned int data_sector_size; /* 512 bytes or 4KB */ > unsigned int data_tag_unit_size; /* DATA TAG UNIT size */ > unsigned int boot_ro_lock; /* ro lock support */ >diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h >index b01e77d..45d53ef 100644 >--- a/include/linux/mmc/core.h >+++ b/include/linux/mmc/core.h >@@ -140,7 +140,7 @@ struct mmc_request { > struct mmc_card; > struct mmc_async_req; > >-extern int mmc_stop_bkops(struct mmc_card *); >+extern int mmc_stop_bkops(struct mmc_card *, bool); > extern int mmc_read_bkops_status(struct mmc_card *); > extern struct mmc_async_req *mmc_start_req(struct mmc_host *, > struct mmc_async_req *, int *); >@@ -150,7 +150,7 @@ extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); > extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *); > extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, > struct mmc_command *, int); >-extern void mmc_start_bkops(struct mmc_card *card, bool from_exception); >+extern void mmc_start_bkops(struct mmc_card *, bool, bool); > extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); > extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); > extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); >diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h >index c376209..a1cced9 100644 >--- a/include/linux/mmc/mmc.h >+++ b/include/linux/mmc/mmc.h >@@ -436,6 +436,7 @@ struct _mmc_csd { > * BKOPS modes > */ > #define EXT_CSD_MANUAL_BKOPS_MASK 0x01 >+#define EXT_CSD_AUTO_BKOPS_MASK 0x02 > > /* > * MMC_SWITCH access modes >-- >2.3.7 > > >-- >To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >the body of a message to majordomo@xxxxxxxxxxxxxxx >More majordomo info at http://vger.kernel.org/majordomo-info.html ��.n��������+%������w��{.n�����{��i��)��jg��������ݢj����G�������j:+v���w�m������w�������h�����٥