On 07/29/2012 11:33 AM, Minchan Kim wrote:
> On Tue, Jul 24, 2012 at 10:56 AM, Jaehoon Chung <[email protected]>
> wrote:
>> Enable eMMC background operations (BKOPS) feature.
>>
>> If URGENT_BKOPS is set after a response, note that BKOPS
>> are required. Immediately run BKOPS if required.
>> read/write operations should be requested during BKOPS(LEVEL-1),
>> then issue HPI to interrupt the ongoing BKOPS
>> and service the foreground operation.
>> (This patch is only control the LEVEL2/3.)
>>
>> When repeating the writing 1GB data, at a certain time, performance is
>> decreased.
>> At that time, card is also triggered the Level-3 or Level-2.
>> After running bkops, performance is recovered.
>>
>> Future considerations
>> * Check BKOPS_LEVEL=1 and start BKOPS in a preventive manner.
>> * Interrupt ongoing BKOPS before powering off the card.
>> * How get BKOPS_STATUS value.(periodically send ext_csd command?)
>> * If use periodic bkops, also consider runtime_pm control.
>>
>> Signed-off-by: Jaehoon Chung <[email protected]>
>> Signed-off-by: Kyungmin Park <[email protected]>
>> Signed-off-by: Konstantin Dorfman <[email protected]>
>> Signed-off-by: Maya Erez <[email protected]>
>> ---
>> Changelog v11:
>> - removed the MMC_CAP2_BKOPS.
>> : if card support and enable bkops, then use it.
>> Changelog v10:
>> - Based on latest mmc-next
>> - Only control the level-2/3.
>> : If triggered upper than level2, immediately start bkops.
>> - Remove the BKOPS_CAP2_INIT_BKOPS (move into mmc-util)
>> - change use_busy_signal instead of waiting_for_prog_done for
>> __mmc_switch
>> - Remove the useless code.
>> - Add the from_exception to prepare the periodic bkops.
>> Changelog V9:
>> - Rebased on patch-v7.
>> - Added Konstantin and Maya's patch
>> : mmc:core: Define synchronous BKOPS timeout
>> : mmc:core: eMMC4.5 BKOPS fixes
>> - Removed periodic bkops
>> : This feature will do in future work
>> - Add __mmc_switch() for waiting_for_prod_done.
>>
>> Changelog V8:
>> - Remove host->lock spin lock reviewed by Adrian
>> - Support periodic start bkops
>> - when bkops_status is level-3, if timeout is set to 0, send hpi.
>> - Move the start-bkops point
>> Changelog V7:
>> - Use HPI command when issued URGENT_BKOPS
>> - Recheck until clearing the bkops-status bit.
>> Changelog V6:
>> - Add the flag of check-bkops-status.
>> (For fixing async_req problem)
>> - Add the capability for MMC_CAP2_INIT_BKOPS.
>> (When unset the bkops_en bit in ext_csd register)
>> - modify the wrong condition.
>> Changelog V5:
>> - Rebase based on the latest mmc-next.
>> - modify codes based-on Chris's comment
>> Changelog V4:
>> - Add mmc_read_bkops_status
>> - When URGENT_BKOPS(level2-3), didn't use HPI command.
>> - In mmc_switch(), use R1B/R1 according to level.
>> Changelog V3:
>> - move the bkops setting's location in mmc_blk_issue_rw_rq
>> - modify condition checking
>> - bkops_en is assigned ext_csd[EXT_CSD_BKOPS_EN] instead of "1"
>> - remove the unused code
>> - change pr_debug instead of pr_warn in mmc_send_hpi_cmd
>> - Add the Future consideration suggested by Per
>> Changelog V2:
>> - Use EXCEPTION_STATUS instead of URGENT_BKOPS
>> - Add function to check Exception_status(for eMMC4.5)
>> ---
>> drivers/mmc/core/core.c | 145
>> +++++++++++++++++++++++++++++++++++++++++++-
>> drivers/mmc/core/mmc.c | 11 +++
>> drivers/mmc/core/mmc_ops.c | 26 +++++++-
>> include/linux/mmc/card.h | 8 +++
>> include/linux/mmc/core.h | 4 +
>> include/linux/mmc/mmc.h | 19 ++++++
>> 6 files changed, 207 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> index 8ac5246..ed2cc93 100644
>> --- a/drivers/mmc/core/core.c
>> +++ b/drivers/mmc/core/core.c
>> @@ -41,6 +41,12 @@
>> #include "sd_ops.h"
>> #include "sdio_ops.h"
>>
>> +/*
>> + * The Background operation can take a long time, depends on the house
>> keeping
>> + * operations the card has to peform
>> + */
>> +#define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */
>> +
>> static struct workqueue_struct *workqueue;
>> static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
>>
>> @@ -245,6 +251,70 @@ mmc_start_request(struct mmc_host *host, struct
>> mmc_request *mrq)
>> host->ops->request(host, mrq);
>> }
>>
>> +/**
>> + * mmc_start_bkops - start BKOPS for supported cards
>> + * @card: MMC card to start BKOPS
>> + * @form_exception: A flags 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)
>> +{
>> + int err;
>> + int timeout;
>> + bool use_busy_signal;
>> +
>> + BUG_ON(!card);
>> +
>> + if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
>> + return;
>> +
>> + err = mmc_read_bkops_status(card);
>> + if (err) {
>> + pr_err("%s: Didn't read bkops status : %d\n",
>> + mmc_hostname(card->host), err);
>> + return;
>> + }
>> +
>> + if (!card->ext_csd.raw_bkops_status)
>> + return;
>> +
>> + if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2
>> + && (from_exception))
>> + return;
>> +
>> + mmc_claim_host(card->host);
>> + if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
>> + timeout = MMC_BKOPS_MAX_TIMEOUT;
>> + use_busy_signal = true;
>> + } else {
>> + timeout = 0;
>> + use_busy_signal = false;
>> + }
>> +
>> + err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> + EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal);
>> + if (err) {
>> + pr_warn("%s: error %d starting bkops\n",
>> + mmc_hostname(card->host), err);
>> + goto out;
>> + }
>> +
>> + /*
>> + * For urgent bkops status (LEVEL_2 and more)
>> + * bkops executed synchronously, otherwise
>> + * the operation is in progress
>> + */
>> + if (!use_busy_signal)
>> + mmc_card_set_doing_bkops(card);
>> +out:
>> + mmc_release_host(card->host);
>> +}
>> +EXPORT_SYMBOL(mmc_start_bkops);
>> +
>> static void mmc_wait_done(struct mmc_request *mrq)
>> {
>> complete(&mrq->completion);
>> @@ -354,6 +424,14 @@ struct mmc_async_req *mmc_start_req(struct mmc_host
>> *host,
>> if (host->areq) {
>> mmc_wait_for_req_done(host, host->areq->mrq);
>> err = host->areq->err_check(host->card, host->areq);
>> + /*
>> + * Check BKOPS urgency for each R1 response
>> + */
>> + if (host->card && mmc_card_mmc(host->card) &&
>> + ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
>> + (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
>> + (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT))
>> + mmc_start_bkops(host->card, true);
>> }
>>
>> if (!err && areq)
>> @@ -489,6 +567,53 @@ 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)
>> +{
>> + int err = 0;
>> +
>> + BUG_ON(!card);
>> + err = mmc_interrupt_hpi(card);
>> +
>> + /*
>> + * if err is EINVAL, it's status that can't issue HPI.
>> + * it should complete the BKOPS.
>> + */
>> + if (!err || (err == -EINVAL)) {
>> + mmc_card_clr_doing_bkops(card);
>> + err = 0;
>> + }
>> +
>> + return err;
>> +}
>> +EXPORT_SYMBOL(mmc_stop_bkops);
>> +
>> +int mmc_read_bkops_status(struct mmc_card *card)
>> +{
>> + int err;
>> + u8 ext_csd[512];
>
> 512 byte stack? Isn't it really a problem?
How about this?
+int mmc_read_bkops_status(struct mmc_card *card)
+{
+ int err;
+ u8 *ext_csd;
+
+ ext_csd = kmalloc(512, GFP_KERNEL);
+ if (!ext_csd) {
+ pr_err("%s: could not allocate a buffer to "
+ "receive the ext_csd.\n", mmc_hostname(card->host));
+ return -ENOMEM;
+ }
+
+ mmc_claim_host(card->host);
+ err = mmc_send_ext_csd(card, ext_csd);
+ mmc_release_host(card->host);
+ if (err)
+ goto out;
+
+ card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS];
+ card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS];
+out:
+ kfree(ext_csd);
+ return err;
+}
+EXPORT_SYMBOL(mmc_read_bkops_status);
Best Regards,
Jaehoon Chung
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html