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:
parent
4e21631010
commit
cac0580eeb
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue