summaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/block.c13
-rw-r--r--drivers/mmc/core/core.c17
-rw-r--r--drivers/mmc/core/mmc_ops.c5
-rw-r--r--drivers/mmc/core/mmc_ops.h2
-rw-r--r--drivers/mmc/core/quirks.h14
-rw-r--r--drivers/mmc/core/sdio.c22
6 files changed, 53 insertions, 20 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 88114e576..a5d986c75 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -1470,6 +1470,8 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req)
blk_mq_requeue_request(req, true);
else
__blk_mq_end_request(req, BLK_STS_OK);
+ } else if (mq->in_recovery) {
+ blk_mq_requeue_request(req, true);
} else {
blk_mq_end_request(req, BLK_STS_OK);
}
@@ -1976,15 +1978,16 @@ static void mmc_blk_mq_poll_completion(struct mmc_queue *mq,
mmc_blk_urgent_bkops(mq, mqrq);
}
-static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, struct request *req)
+static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq,
+ struct request_queue *q,
+ enum mmc_issue_type issue_type)
{
- struct request_queue *q = req->q;
unsigned long flags;
bool put_card;
spin_lock_irqsave(q->queue_lock, flags);
- mq->in_flight[mmc_issue_type(mq, req)] -= 1;
+ mq->in_flight[issue_type] -= 1;
put_card = (mmc_tot_in_flight(mq) == 0);
@@ -1996,9 +1999,11 @@ static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, struct request *req)
static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req)
{
+ enum mmc_issue_type issue_type = mmc_issue_type(mq, req);
struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
struct mmc_request *mrq = &mqrq->brq.mrq;
struct mmc_host *host = mq->card->host;
+ struct request_queue *q = req->q;
mmc_post_req(host, mrq, 0);
@@ -2011,7 +2016,7 @@ static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req)
else
blk_mq_complete_request(req);
- mmc_blk_mq_dec_in_flight(mq, req);
+ mmc_blk_mq_dec_in_flight(mq, q, issue_type);
}
void mmc_blk_mq_recovery(struct mmc_queue *mq)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 6937f39fe..3399e8c47 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -567,22 +567,27 @@ int mmc_cqe_recovery(struct mmc_host *host)
host->cqe_ops->cqe_recovery_start(host);
memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = MMC_STOP_TRANSMISSION,
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC,
+ cmd.opcode = MMC_STOP_TRANSMISSION;
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
- cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
- mmc_wait_for_cmd(host, &cmd, 0);
+ cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT;
+ mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+
+ mmc_poll_for_busy(host->card, MMC_CQE_RECOVERY_TIMEOUT, true, true);
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = MMC_CMDQ_TASK_MGMT;
cmd.arg = 1; /* Discard entire queue */
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
- cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
- err = mmc_wait_for_cmd(host, &cmd, 0);
+ cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT;
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
host->cqe_ops->cqe_recovery_finish(host);
+ if (err)
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+
mmc_retune_release(host);
return err;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index c2187fc6d..2ed47f800 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -448,8 +448,8 @@ int mmc_switch_status(struct mmc_card *card)
return __mmc_switch_status(card, true);
}
-static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
- bool send_status, bool retry_crc_err)
+int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+ bool send_status, bool retry_crc_err)
{
struct mmc_host *host = card->host;
int err;
@@ -502,6 +502,7 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
return 0;
}
+EXPORT_SYMBOL_GPL(mmc_poll_for_busy);
/**
* __mmc_switch - modify EXT_CSD register
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 018a5e3f6..daf7ab867 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -35,6 +35,8 @@ int mmc_can_ext_csd(struct mmc_card *card);
int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
int mmc_switch_status(struct mmc_card *card);
int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
+int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+ bool send_status, bool retry_crc_err);
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, unsigned char timing,
bool use_busy_signal, bool send_status, bool retry_crc_err);
diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h
index d5bbe8e54..e35c204cd 100644
--- a/drivers/mmc/core/quirks.h
+++ b/drivers/mmc/core/quirks.h
@@ -91,6 +91,20 @@ static const struct mmc_fixup mmc_blk_fixups[] = {
MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
/*
+ * Kingston EMMC04G-M627 advertises TRIM but it does not seems to
+ * support being used to offload WRITE_ZEROES.
+ */
+ MMC_FIXUP("M62704", CID_MANFID_KINGSTON, 0x0100, add_quirk_mmc,
+ MMC_QUIRK_TRIM_BROKEN),
+
+ /*
+ * Micron MTFC4GACAJCN-1M advertises TRIM but it does not seems to
+ * support being used to offload WRITE_ZEROES.
+ */
+ MMC_FIXUP("Q2J54A", CID_MANFID_MICRON, 0x014e, add_quirk_mmc,
+ MMC_QUIRK_TRIM_BROKEN),
+
+ /*
* On Some Kingston eMMCs, performing trim can result in
* unrecoverable data conrruption occasionally due to a firmware bug.
*/
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 5f1ee88aa..4fdb5dd97 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -963,7 +963,11 @@ static int mmc_sdio_resume(struct mmc_host *host)
/* Basic card reinitialization. */
mmc_claim_host(host);
- /* Restore power if needed */
+ /*
+ * Restore power and reinitialize the card when needed. Note that a
+ * removable card is checked from a detect work later on in the resume
+ * process.
+ */
if (!mmc_card_keep_power(host)) {
mmc_power_up(host, host->card->ocr);
/*
@@ -977,14 +981,16 @@ static int mmc_sdio_resume(struct mmc_host *host)
pm_runtime_set_active(&host->card->dev);
pm_runtime_enable(&host->card->dev);
}
- }
-
- /* No need to reinitialize powered-resumed nonremovable cards */
- if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
- err = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
- } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
- /* We may have switched to 1-bit mode during suspend */
+ err = mmc_sdio_reinit_card(host, 0);
+ } else if (mmc_card_wake_sdio_irq(host)) {
+ /*
+ * We may have switched to 1-bit mode during suspend,
+ * need to hold retuning, because tuning only supprt
+ * 4-bit mode or 8 bit mode.
+ */
+ mmc_retune_hold_now(host);
err = sdio_enable_4bit_bus(host->card);
+ mmc_retune_release(host);
}
if (err)