On 07/29/2012 11:33 AM, Minchan Kim wrote: > On Tue, Jul 24, 2012 at 10:56 AM, Jaehoon Chung <jh80.chung@xxxxxxxxxxx> 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 <jh80.chung@xxxxxxxxxxx> >> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> >> Signed-off-by: Konstantin Dorfman <kdorfman@xxxxxxxxxxxxxx> >> Signed-off-by: Maya Erez <merez@xxxxxxxxxxxxxx> >> --- >> 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html