mmc: core: expose HPI capability to SWITCH commands

Some of the time consuming operations such as BKOPS, SANITIZE, CACHE
flush/off use the SWITCH command (CMD6) but as these operations don't
have card specification defined timeout for completion, we may see
timeout errors if card doesn't complete the operation within the SW
defined timeout. If SW defined timeout is hit, above operations are
considered to be failed and no real recovery mechanism is implemented
after timeout.

Most of the above operations (BKOPS/SANITIZE/CACHE flush/off) can be
interrupted by sending the HPI (High Priority Interrupt) command to card
if they taking longer than expected. This change adds the base support
which will these operations to be HPIed after timeout.

Change-Id: Ibd9061525756aaae656b1ceeeaed62e04fb80cce
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
Subhash Jadavani 2013-06-25 13:13:24 +05:30 committed by Stephen Boyd
parent 4e21631010
commit cac0580eeb
3 changed files with 23 additions and 24 deletions

View File

@ -785,25 +785,13 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
cmd = mrq->cmd;
/*
* If host has timed out waiting for the blocking BKOPs
* or sanitize to complete, card might be still in programming
* state so let's try to bring the card out of programming
* state.
* If host has timed out waiting for the commands which can be
* HPIed then let the caller handle the timeout error as it may
* want to send the HPI command to bring the card out of
* programming state.
*/
if ((cmd->bkops_busy || cmd->sanitize_busy) &&
cmd->error == -ETIMEDOUT) {
if (!mmc_interrupt_hpi(host->card)) {
pr_warning("%s: %s: Interrupted blocking bkops"
"or sanitize\n",
mmc_hostname(host), __func__);
cmd->error = 0;
break;
} else {
pr_err("%s: %s: Failed to interrupt blocking "
"bkops or sanitize\n",
mmc_hostname(host), __func__);
}
}
if (cmd->ignore_timeout && cmd->error == -ETIMEDOUT)
break;
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card))
@ -3486,7 +3474,7 @@ int mmc_flush_cache(struct mmc_card *card)
if (mmc_card_mmc(card) &&
(card->ext_csd.cache_size > 0) &&
(card->ext_csd.cache_ctrl & 1)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
err = mmc_switch_ignore_timeout(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_FLUSH_CACHE, 1, 0);
if (err)
pr_err("%s: cache flush error %d\n",
@ -3519,7 +3507,8 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
if (card->ext_csd.cache_ctrl ^ enable) {
timeout = enable ? card->ext_csd.generic_cmd6_time : 0;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
err = mmc_switch_ignore_timeout(card,
EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_CACHE_CTRL, enable, timeout);
if (err)
pr_err("%s: cache %s error %d\n",

View File

@ -404,13 +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
* @ignore_timeout: set this flag only for commands which can be HPIed
*
* 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,
bool bkops_busy)
bool ignore_timeout)
{
int err;
struct mmc_command cmd = {0};
@ -433,7 +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;
cmd.ignore_timeout = ignore_timeout;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
@ -484,6 +484,13 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
}
EXPORT_SYMBOL_GPL(mmc_switch);
int mmc_switch_ignore_timeout(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms)
{
return __mmc_switch(card, set, index, value, timeout_ms, true, true);
}
EXPORT_SYMBOL(mmc_switch_ignore_timeout);
int mmc_send_status(struct mmc_card *card, u32 *status)
{
int err;

View File

@ -65,10 +65,11 @@ struct mmc_command {
*/
unsigned int cmd_timeout_ms; /* in milliseconds */
/* Set this flag only for blocking bkops request */
bool bkops_busy;
/* Set this flag only for sanitize request */
bool sanitize_busy;
/* Set this flag only for commands which can be HPIed */
bool ignore_timeout;
struct mmc_data *data; /* data segment associated with cmd */
struct mmc_request *mrq; /* associated request */
@ -130,6 +131,8 @@ extern void mmc_bkops_completion_polling(struct work_struct *work);
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_switch_ignore_timeout(struct mmc_card *, u8, u8, u8,
unsigned int);
extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
#define MMC_ERASE_ARG 0x00000000