diff options
Diffstat (limited to 'drivers/mmc/core/block.c')
| -rw-r--r-- | drivers/mmc/core/block.c | 92 |
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; |
