Merge "mmc: Do not perform blocking BKOPS"
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index b748228..e515f51 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2110,9 +2110,12 @@
}
#endif
- if (req && !mq->mqrq_prev->req)
+ if (req && !mq->mqrq_prev->req) {
/* claim host only for the first request */
mmc_claim_host(card->host);
+ if (card->ext_csd.bkops_en)
+ mmc_stop_bkops(card);
+ }
ret = mmc_blk_part_switch(card, md);
if (ret) {
@@ -2150,9 +2153,12 @@
}
out:
- if (!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST))
+ if (!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) {
+ if (mmc_card_need_bkops(card))
+ mmc_start_bkops(card, false);
/* release host only when there are no more requests */
mmc_release_host(card->host);
+ }
return ret;
}
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 7b80dfb..dc27db6 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -89,17 +89,6 @@
spin_unlock_irq(q->queue_lock);
if (req || mq->mqrq_prev->req) {
- /*
- * If this is the first request, BKOPs might be in
- * progress and needs to be stopped before issuing the
- * request
- */
- if (card->ext_csd.bkops_en &&
- card->bkops_info.started_delayed_bkops) {
- card->bkops_info.started_delayed_bkops = false;
- mmc_stop_bkops(card);
- }
-
set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req);
if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 5a3db4f..6dd0b52 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -372,7 +372,6 @@
* it was removed from the queue work but not started yet
*/
card->bkops_info.cancel_delayed_work = false;
- card->bkops_info.started_delayed_bkops = true;
queue_delayed_work(system_nrt_wq, &card->bkops_info.dw,
msecs_to_jiffies(
card->bkops_info.delay_ms));
@@ -392,8 +391,6 @@
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)
@@ -414,43 +411,45 @@
goto out;
}
- err = mmc_read_bkops_status(card);
- if (err) {
- pr_err("%s: %s: Failed to read bkops status: %d\n",
- mmc_hostname(card->host), __func__, err);
+ if (from_exception && mmc_card_need_bkops(card))
goto out;
- }
-
- if (!card->ext_csd.raw_bkops_status)
- goto out;
-
- pr_info("%s: %s: card->ext_csd.raw_bkops_status = 0x%x\n",
- mmc_hostname(card->host), __func__,
- card->ext_csd.raw_bkops_status);
/*
- * If the function was called due to exception but there is no need
- * for urgent BKOPS, BKOPs will be performed by the delayed BKOPs
- * work, before going to suspend
+ * If the need BKOPS flag is set, there is no need to check if BKOPS
+ * is needed since we already know that it does
*/
- if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 &&
- from_exception) {
- pr_debug("%s: %s: Level 1 from exception, exit",
- mmc_hostname(card->host), __func__);
+ if (!mmc_card_need_bkops(card)) {
+ err = mmc_read_bkops_status(card);
+ if (err) {
+ pr_err("%s: %s: Failed to read bkops status: %d\n",
+ mmc_hostname(card->host), __func__, err);
+ goto out;
+ }
+
+ if (!card->ext_csd.raw_bkops_status)
+ goto out;
+
+ pr_info("%s: %s: raw_bkops_status=0x%x, from_exception=%d\n",
+ mmc_hostname(card->host), __func__,
+ card->ext_csd.raw_bkops_status,
+ from_exception);
+ }
+
+ /*
+ * If the function was called due to exception, BKOPS will be performed
+ * after handling the last pending request
+ */
+ if (from_exception) {
+ pr_debug("%s: %s: Level %d from exception, exit",
+ mmc_hostname(card->host), __func__,
+ card->ext_csd.raw_bkops_status);
+ mmc_card_set_need_bkops(card);
goto out;
}
-
- 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;
- }
+ pr_info("%s: %s: Starting bkops\n", mmc_hostname(card->host), __func__);
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BKOPS_START, 1, timeout,
- use_busy_signal, use_busy_signal);
+ EXT_CSD_BKOPS_START, 1, 0, false, false);
if (err) {
pr_warn("%s: %s: Error %d when starting bkops\n",
mmc_hostname(card->host), __func__, err);
@@ -458,19 +457,13 @@
}
MMC_UPDATE_STATS_BKOPS_SEVERITY_LEVEL(card->bkops_info.bkops_stats,
card->ext_csd.raw_bkops_status);
+ mmc_card_clr_need_bkops(card);
- /*
- * 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);
- pr_debug("%s: %s: starting the polling thread\n",
- mmc_hostname(card->host), __func__);
- queue_work(system_nrt_wq,
- &card->bkops_info.poll_for_completion);
- }
+ mmc_card_set_doing_bkops(card);
+ pr_debug("%s: %s: starting the polling thread\n",
+ mmc_hostname(card->host), __func__);
+ queue_work(system_nrt_wq,
+ &card->bkops_info.poll_for_completion);
out:
mmc_release_host(card->host);
@@ -524,7 +517,6 @@
pr_debug("%s: %s: completed BKOPs, exit polling\n",
mmc_hostname(card->host), __func__);
mmc_card_clr_doing_bkops(card);
- card->bkops_info.started_delayed_bkops = false;
goto out;
}
@@ -946,7 +938,9 @@
* 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.
+ * to avoid errors in servicing read/write requests.
+ *
+ * The function should be called with host claimed.
*/
int mmc_stop_bkops(struct mmc_card *card)
{
@@ -954,8 +948,6 @@
BUG_ON(!card);
- mmc_claim_host(card->host);
-
/*
* Notify the delayed work to be cancelled, in case it was already
* removed from the queue, but was not started yet
@@ -980,7 +972,6 @@
MMC_UPDATE_BKOPS_STATS_HPI(card->bkops_info.bkops_stats);
out:
- mmc_release_host(card->host);
return err;
}
EXPORT_SYMBOL(mmc_stop_bkops);
@@ -3254,7 +3245,9 @@
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
if (host->card && mmc_card_mmc(host->card)) {
+ mmc_claim_host(host);
err = mmc_stop_bkops(host->card);
+ mmc_release_host(host);
if (err) {
pr_err("%s: didn't stop bkops\n",
mmc_hostname(host));
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c160261..67e2a75 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -267,8 +267,6 @@
* @poll_for_completion: Poll on BKOPS completion
* @cancel_delayed_work: A flag to indicate if the delayed work
* should be cancelled
- * @started_delayed_bkops: A flag to indicate if the delayed
- * work was scheduled
* @sectors_changed: number of sectors written or
* discard since the last idle BKOPS were scheduled
*/
@@ -288,7 +286,6 @@
#define BKOPS_COMPLETION_POLLING_TIMEOUT_MS (4 * 60 * 1000) /* in ms */
#define BKOPS_COMPLETION_POLLING_INTERVAL_MS 1000 /* in ms */
bool cancel_delayed_work;
- bool started_delayed_bkops;
unsigned int sectors_changed;
/*
* Since canceling the delayed work might have significant effect on the
@@ -349,6 +346,7 @@
#define MMC_CARD_REMOVED (1<<7) /* card has been removed */
#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */
#define MMC_STATE_DOING_BKOPS (1<<10) /* card is doing BKOPS */
+#define MMC_STATE_NEED_BKOPS (1<<11) /* card needs to do BKOPS */
unsigned int quirks; /* card quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
@@ -523,6 +521,7 @@
#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS)
+#define mmc_card_need_bkops(c) ((c)->state & MMC_STATE_NEED_BKOPS)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -536,7 +535,8 @@
#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
#define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS)
#define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS)
-
+#define mmc_card_set_need_bkops(c) ((c)->state |= MMC_STATE_NEED_BKOPS)
+#define mmc_card_clr_need_bkops(c) ((c)->state &= ~MMC_STATE_NEED_BKOPS)
/*
* Quirk add/remove for MMC products.
*/