aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core/block.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core/block.c')
-rw-r--r--drivers/mmc/core/block.c92
1 files changed, 82 insertions, 10 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index c0ffe0817fd4..eda8e848615a 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -180,6 +180,13 @@ static DEFINE_MUTEX(open_lock);
module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
+/*
+ * Allow quirks to be overridden for the current card
+ */
+static char *card_quirks;
+module_param(card_quirks, charp, 0644);
+MODULE_PARM_DESC(card_quirks, "Force the use of the indicated quirks (a bitfield)");
+
static inline int mmc_blk_part_switch(struct mmc_card *card,
unsigned int part_type);
static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
@@ -889,7 +896,10 @@ static int mmc_blk_part_switch_pre(struct mmc_card *card,
if ((part_type & mask) == rpmb) {
if (card->ext_csd.cmdq_en) {
- ret = mmc_cmdq_disable(card);
+ if (mmc_card_sd(card))
+ ret = mmc_sd_cmdq_disable(card);
+ else
+ ret = mmc_cmdq_disable(card);
if (ret)
return ret;
}
@@ -908,8 +918,12 @@ static int mmc_blk_part_switch_post(struct mmc_card *card,
if ((part_type & mask) == rpmb) {
mmc_retune_unpause(card->host);
- if (card->reenable_cmdq && !card->ext_csd.cmdq_en)
- ret = mmc_cmdq_enable(card);
+ if (card->reenable_cmdq && !card->ext_csd.cmdq_en) {
+ if (mmc_card_sd(card))
+ ret = mmc_sd_cmdq_enable(card);
+ else
+ ret = mmc_cmdq_enable(card);
+ }
}
return ret;
@@ -1120,7 +1134,10 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
switch (mq_rq->drv_op) {
case MMC_DRV_OP_IOCTL:
if (card->ext_csd.cmdq_en) {
- ret = mmc_cmdq_disable(card);
+ if (mmc_card_sd(card))
+ ret = mmc_sd_cmdq_disable(card);
+ else
+ ret = mmc_cmdq_disable(card);
if (ret)
break;
}
@@ -1138,8 +1155,12 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
/* Always switch back to main area after RPMB access */
if (rpmb_ioctl)
mmc_blk_part_switch(card, 0);
- else if (card->reenable_cmdq && !card->ext_csd.cmdq_en)
- mmc_cmdq_enable(card);
+ else if (card->reenable_cmdq && !card->ext_csd.cmdq_en) {
+ if (mmc_card_sd(card))
+ mmc_sd_cmdq_enable(card);
+ else
+ mmc_cmdq_enable(card);
+ }
break;
case MMC_DRV_OP_BOOT_WP:
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
@@ -1181,12 +1202,26 @@ static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req,
sector_t from;
int err = 0;
blk_status_t status = BLK_STS_OK;
+ bool restart_cmdq = false;
if (!mmc_card_can_erase(card)) {
status = BLK_STS_NOTSUPP;
goto fail;
}
+ /*
+ * Only Discard ops are supported with SD cards in CQ mode
+ * (SD Physical Spec v9.00 4.19.2)
+ */
+ if (mmc_card_sd(card) && card->ext_csd.cmdq_en && erase_arg != SD_DISCARD_ARG) {
+ restart_cmdq = true;
+ err = mmc_sd_cmdq_disable(card);
+ if (err) {
+ status = BLK_STS_IOERR;
+ goto fail;
+ }
+ }
+
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
@@ -1207,6 +1242,11 @@ static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req,
status = BLK_STS_IOERR;
else
mmc_blk_reset_success(md, type);
+
+ if (restart_cmdq)
+ err = mmc_sd_cmdq_enable(card);
+ if (err)
+ status = BLK_STS_IOERR;
fail:
blk_mq_end_request(req, status);
}
@@ -1529,6 +1569,7 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req)
struct request_queue *q = req->q;
struct mmc_host *host = mq->card->host;
enum mmc_issue_type issue_type = mmc_issue_type(mq, req);
+ bool write = req_op(req) == REQ_OP_WRITE;
unsigned long flags;
bool put_card;
int err;
@@ -1560,6 +1601,8 @@ static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req)
spin_lock_irqsave(&mq->lock, flags);
+ if (write)
+ mq->pending_writes--;
mq->in_flight[issue_type] -= 1;
put_card = (mmc_tot_in_flight(mq) == 0);
@@ -1972,7 +2015,7 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req)
return;
}
- if (rq_data_dir(req) == READ && brq->data.blocks >
+ if (0 && rq_data_dir(req) == READ && brq->data.blocks >
queue_physical_block_size(mq->queue) >> 9) {
/* Read one (native) sector at a time */
mmc_blk_read_single(mq, req);
@@ -2080,6 +2123,8 @@ static void mmc_blk_mq_complete_rq(struct mmc_queue *mq, struct request *req)
struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
unsigned int nr_bytes = mqrq->brq.data.bytes_xfered;
+ if (req_op(req) == REQ_OP_WRITE)
+ mq->pending_writes--;
if (nr_bytes) {
if (blk_update_request(req, BLK_STS_OK, nr_bytes))
blk_mq_requeue_request(req, true);
@@ -2174,13 +2219,17 @@ 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, enum mmc_issue_type issue_type)
+static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type,
+ bool write)
{
unsigned long flags;
bool put_card;
spin_lock_irqsave(&mq->lock, flags);
+ if (write)
+ mq->pending_writes--;
+
mq->in_flight[issue_type] -= 1;
put_card = (mmc_tot_in_flight(mq) == 0);
@@ -2195,6 +2244,7 @@ static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req,
bool can_sleep)
{
enum mmc_issue_type issue_type = mmc_issue_type(mq, req);
+ bool write = req_op(req) == REQ_OP_WRITE;
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;
@@ -2214,7 +2264,7 @@ static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req,
blk_mq_complete_request(req);
}
- mmc_blk_mq_dec_in_flight(mq, issue_type);
+ mmc_blk_mq_dec_in_flight(mq, issue_type, write);
}
void mmc_blk_mq_recovery(struct mmc_queue *mq)
@@ -3265,6 +3315,8 @@ static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md;
int ret = 0;
+ char quirk_str[24];
+ char cap_str[10];
/*
* Check that the card supports the command class(es) we need.
@@ -3272,7 +3324,16 @@ static int mmc_blk_probe(struct mmc_card *card)
if (!(card->csd.cmdclass & CCC_BLOCK_READ))
return -ENODEV;
- mmc_fixup_device(card, mmc_blk_fixups);
+ if (card_quirks) {
+ unsigned long quirks;
+ if (kstrtoul(card_quirks, 0, &quirks) == 0)
+ card->quirks = (unsigned int)quirks;
+ else
+ pr_err("mmc_block: Invalid card_quirks parameter '%s'\n",
+ card_quirks);
+ }
+ else
+ mmc_fixup_device(card, mmc_blk_fixups);
card->complete_wq = alloc_workqueue("mmc_complete",
WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
@@ -3287,6 +3348,17 @@ static int mmc_blk_probe(struct mmc_card *card)
goto out_free;
}
+ string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2,
+ cap_str, sizeof(cap_str));
+ if (card->quirks)
+ snprintf(quirk_str, sizeof(quirk_str),
+ " (quirks 0x%08x)", card->quirks);
+ else
+ quirk_str[0] = '\0';
+ pr_info("%s: %s %s %s%s%s\n",
+ md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
+ cap_str, md->read_only ? " (ro)" : "", quirk_str);
+
ret = mmc_blk_alloc_parts(card, md);
if (ret)
goto out;