mmc: core: interrupt Background Operations if it takes too long

Currently we have 4 mins timeout for the blocking BKOPs to complete
but we have seen instances where card is surprisingly taking even
longer time to complete background operations.

If card doesn't complete the BKOPs within specified timeout, we
will send the HPI command to interrupt the ongoing BKOPs.

Change-Id: I5df81bdfd9b19bee30a394ee0ff4390b292691d0
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
Subhash Jadavani 2012-12-19 19:06:38 +05:30 committed by Stephen Boyd
parent 0fb4feb83f
commit 24d7be0517
3 changed files with 29 additions and 4 deletions

View File

@ -456,7 +456,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
}
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal);
EXT_CSD_BKOPS_START, 1, timeout,
use_busy_signal, use_busy_signal);
if (err) {
pr_warn("%s: %s: Error %d when starting bkops\n",
mmc_hostname(card->host), __func__, err);
@ -689,6 +690,24 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
wait_for_completion_io(&mrq->completion);
cmd = mrq->cmd;
/*
* If host has timed out waiting for the blocking BKOPs
* to complete, card might be still in programming state
* so let's try to bring the card out of programming state.
*/
if (cmd->bkops_busy && cmd->error == -ETIMEDOUT) {
if (!mmc_interrupt_hpi(host->card)) {
pr_warning("%s: %s: Interrupted blocking bkops\n",
mmc_hostname(host), __func__);
cmd->error = 0;
break;
} else {
pr_err("%s: %s: Failed to interrupt blocking bkops\n",
mmc_hostname(host), __func__);
}
}
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card))
break;

View File

@ -404,11 +404,13 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
* @timeout_ms: timeout (ms) for operation performed by register write,
* timeout of zero implies maximum possible timeout
* @use_busy_signal: use the busy signal as response type
* @bkops_busy: set this to indicate that we are starting blocking bkops
*
* Modifies the EXT_CSD register for selected card.
*/
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, bool use_busy_signal)
unsigned int timeout_ms, bool use_busy_signal,
bool bkops_busy)
{
int err;
struct mmc_command cmd = {0};
@ -431,6 +433,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
cmd.cmd_timeout_ms = timeout_ms;
cmd.bkops_busy = bkops_busy;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
@ -477,7 +480,7 @@ EXPORT_SYMBOL_GPL(__mmc_switch);
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms)
{
return __mmc_switch(card, set, index, value, timeout_ms, true);
return __mmc_switch(card, set, index, value, timeout_ms, true, false);
}
EXPORT_SYMBOL_GPL(mmc_switch);

View File

@ -96,6 +96,8 @@ struct mmc_command {
*/
unsigned int cmd_timeout_ms; /* in milliseconds */
/* Set this flag only for blocking bkops request */
bool bkops_busy;
struct mmc_data *data; /* data segment associated with cmd */
struct mmc_request *mrq; /* associated request */
@ -153,7 +155,8 @@ extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
extern void mmc_start_delayed_bkops(struct mmc_card *card);
extern void mmc_start_idle_time_bkops(struct work_struct *work);
extern void mmc_bkops_completion_polling(struct work_struct *work);
extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool);
extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
bool);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);