Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@xxxxxxxxxxx> --- drivers/mmc/core/block.c | 104 ++++++++++++++++++++++++++++---------- drivers/mmc/core/block.h | 3 +- drivers/mmc/core/bus.c | 3 +- drivers/mmc/core/core.c | 120 +++++++++++++++++++++++++++++++++++++++++--- drivers/mmc/core/mmc_test.c | 16 +++--- drivers/mmc/core/queue.c | 114 +++++++++++++++++++++++++++++++++++++---- drivers/mmc/core/queue.h | 5 ++ include/linux/mmc/core.h | 12 +++++ 8 files changed, 327 insertions(+), 50 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index d87b613..38a4321 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -27,6 +27,7 @@ #include <linux/errno.h> #include <linux/hdreg.h> #include <linux/kdev_t.h> +#include <linux/blk-mq.h> #include <linux/blkdev.h> #include <linux/mutex.h> #include <linux/scatterlist.h> @@ -131,9 +132,13 @@ static inline int mmc_blk_part_switch(struct mmc_card *card, static void mmc_blk_requeue(struct request_queue *q, struct request *req) { - spin_lock_irq(q->queue_lock); - blk_requeue_request(q, req); - spin_unlock_irq(q->queue_lock); + if (mmc_use_blk_mq()) + blk_mq_requeue_request(req, false); + else { + spin_lock_irq(q->queue_lock); + blk_requeue_request(q, req); + spin_unlock_irq(q->queue_lock); + } } static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) @@ -1150,7 +1155,8 @@ int mmc_access_rpmb(struct mmc_queue *mq) return false; } -static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) +static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req, + struct mmc_queue_req *mqrq) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; @@ -1188,13 +1194,19 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) goto retry; if (!err) mmc_blk_reset_success(md, type); - blk_end_request(req, err, blk_rq_bytes(req)); + if (mmc_use_blk_mq()) { + mmc_put_card(card); + mmc_queue_req_free(mq, mqrq); + blk_mq_end_request(req, err); + } else + blk_end_request(req, err, blk_rq_bytes(req)); return err ? 0 : 1; } static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, - struct request *req) + struct request *req, + struct mmc_queue_req *mqrq) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; @@ -1255,12 +1267,18 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, if (!err) mmc_blk_reset_success(md, type); out: - blk_end_request(req, err, blk_rq_bytes(req)); + if (mmc_use_blk_mq()) { + mmc_put_card(card); + mmc_queue_req_free(mq, mqrq); + blk_mq_end_request(req, err); + } else + blk_end_request(req, err, blk_rq_bytes(req)); return err ? 0 : 1; } -static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) +static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req, + struct mmc_queue_req *mqrq) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; @@ -1270,7 +1288,12 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) if (ret) ret = -EIO; - blk_end_request_all(req, ret); + if (mmc_use_blk_mq()) { + mmc_put_card(card); + mmc_queue_req_free(mq, mqrq); + blk_mq_end_request(req, ret); + } else + blk_end_request_all(req, ret); return ret ? 0 : 1; } @@ -1368,6 +1391,11 @@ static enum mmc_blk_status mmc_blk_err_check(struct mmc_card *card, gen_err = true; } + if (mmc_use_blk_mq()) { + mdelay(100); + pr_info("%s: mdelay(100)\n", __func__); + return MMC_BLK_SUCCESS; + } err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, false, req, &gen_err); if (err) @@ -1600,7 +1628,8 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, return ret; } -static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) +static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc, + struct mmc_queue_req *mqrq) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; @@ -1612,7 +1641,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) struct request *req; struct mmc_async_req *areq; - if (rqc) { + if (mmc_use_blk_mq()) + mqrq_cur = mqrq; + + if (!mmc_use_blk_mq() && rqc) { mqrq_cur = mmc_queue_req_find(mq, rqc); if (!mqrq_cur) { WARN_ON(1); @@ -1644,9 +1676,15 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) areq = &mqrq_cur->mmc_active; } else areq = NULL; - areq = mmc_start_req(card->host, areq, &status); + if (mmc_use_blk_mq()) + areq = mmc_mq_start_req(card->host, areq, + &status, mqrq); + else + areq = mmc_start_req(card->host, areq, &status); if (!areq) return 0; + if (mmc_use_blk_mq()) + goto out_mq; mq_rq = container_of(areq, struct mmc_queue_req, mmc_active); brq = &mq_rq->brq; @@ -1745,6 +1783,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) mmc_queue_req_free(mq, mq_rq); + out_mq: return 1; cmd_abort: @@ -1772,20 +1811,33 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) return 0; } -int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) +int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req, + struct mmc_queue_req *mqrq) { int ret; struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; - if (req && !mq->qcnt) + if (mmc_use_blk_mq()) { /* claim host only for the first request */ mmc_get_card(card); + blk_mq_start_request(req); + } else { + if (req && !mq->qcnt) + /* claim host only for the first request */ + mmc_get_card(card); + } + ret = mmc_blk_part_switch(card, md); if (ret) { if (req) { - blk_end_request_all(req, -EIO); + if (mmc_use_blk_mq()) { + mmc_put_card(card); + mmc_queue_req_free(req->q->queuedata, mqrq); + blk_mq_end_request(req, -EIO); + } else + blk_end_request_all(req, -EIO); } ret = 0; goto out; @@ -1793,26 +1845,26 @@ int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) if (req && req_op(req) == REQ_OP_DISCARD) { /* complete ongoing async transfer before issuing discard */ - if (mq->qcnt) - mmc_blk_issue_rw_rq(mq, NULL); - ret = mmc_blk_issue_discard_rq(mq, req); + if (!mmc_use_blk_mq() && mq->qcnt) + mmc_blk_issue_rw_rq(mq, NULL, NULL); + ret = mmc_blk_issue_discard_rq(mq, req, mqrq); } else if (req && req_op(req) == REQ_OP_SECURE_ERASE) { /* complete ongoing async transfer before issuing secure erase*/ - if (mq->qcnt) - mmc_blk_issue_rw_rq(mq, NULL); - ret = mmc_blk_issue_secdiscard_rq(mq, req); + if (!mmc_use_blk_mq() && mq->qcnt) + mmc_blk_issue_rw_rq(mq, NULL, NULL); + ret = mmc_blk_issue_secdiscard_rq(mq, req, mqrq); } else if (req && req_op(req) == REQ_OP_FLUSH) { /* complete ongoing async transfer before issuing flush */ - if (mq->qcnt) - mmc_blk_issue_rw_rq(mq, NULL); - ret = mmc_blk_issue_flush(mq, req); + if (!mmc_use_blk_mq() && mq->qcnt) + mmc_blk_issue_rw_rq(mq, NULL, NULL); + ret = mmc_blk_issue_flush(mq, req, mqrq); } else { - ret = mmc_blk_issue_rw_rq(mq, req); + ret = mmc_blk_issue_rw_rq(mq, req, mqrq); } out: /* Release host when there are no more requests */ - if (!mq->qcnt) + if (!mmc_use_blk_mq() && !mq->qcnt) mmc_put_card(card); return ret; } diff --git a/drivers/mmc/core/block.h b/drivers/mmc/core/block.h index cdabb2e..5a32a62 100644 --- a/drivers/mmc/core/block.h +++ b/drivers/mmc/core/block.h @@ -1 +1,2 @@ -int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req); +int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req, + struct mmc_queue_req *mqrq); \ No newline at end of file diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index c64266f..485215c 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -346,7 +346,8 @@ int mmc_add_card(struct mmc_card *card) #ifdef CONFIG_DEBUG_FS mmc_add_card_debugfs(card); #endif - mmc_init_context_info(card->host); + if (!mmc_use_blk_mq()) + mmc_init_context_info(card->host); card->dev.of_node = mmc_of_find_child_device(card->host, 0); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 1076b9d..a152941 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -29,6 +29,8 @@ #include <linux/random.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/kernel.h> +#include <linux/blk-mq.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> @@ -44,6 +46,7 @@ #include "host.h" #include "sdio_bus.h" #include "pwrseq.h" +#include "queue.h" #include "mmc_ops.h" #include "sd_ops.h" @@ -420,6 +423,78 @@ static void mmc_wait_done(struct mmc_request *mrq) complete(&mrq->completion); } +static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, + int err); + +/* + * mmc_wait_done() - done callback for request + * @mrq: done request + * + * Wakes up mmc context, passed as a callback to host controller driver + */ +static void mmc_mq_wait_done(struct mmc_request *mrq) +{ + struct mmc_host *host = mrq->host; + struct mmc_queue_req *mq_rq = mrq->mqrq; + struct mmc_async_req *areq = NULL; + struct mmc_command *cmd; + int err = 0, ret = 0; + + cmd = mrq->cmd; + + if (mq_rq) + areq = &mq_rq->mmc_active; + + if (!cmd->error || !cmd->retries || + mmc_card_removed(host->card)) { + if (mq_rq && + mq_rq->req->cmd_type == REQ_TYPE_FS && + req_op(mq_rq->req) != REQ_OP_DISCARD && + req_op(mq_rq->req) != REQ_OP_FLUSH) { + err = areq->err_check(host->card, areq); + BUG_ON(err != MMC_BLK_SUCCESS); + } + } else { + mmc_retune_recheck(host); + pr_info("%s: req failed (CMD%u): %d, retrying...\n", + mmc_hostname(host), + cmd->opcode, cmd->error); + cmd->retries--; + cmd->error = 0; + __mmc_start_request(host, mrq); + return; + } + + mmc_retune_release(host); + + if (mq_rq && + mq_rq->req->cmd_type == REQ_TYPE_FS && + req_op(mq_rq->req) != REQ_OP_DISCARD && + req_op(mq_rq->req) != REQ_OP_FLUSH) { + mmc_post_req(host, mrq, 0); + } + + complete(&mrq->completion); + + if (mq_rq && + mq_rq->req->cmd_type == REQ_TYPE_FS && + req_op(mq_rq->req) != REQ_OP_DISCARD && + req_op(mq_rq->req) != REQ_OP_FLUSH) { + struct mmc_blk_request *brq = &mq_rq->brq; + struct request *req = mq_rq->req; + int bytes; + + mmc_queue_bounce_post(mq_rq); + + bytes = brq->data.bytes_xfered; + mmc_put_card(host->card); + mmc_queue_req_free(req->q->queuedata, mq_rq); + ret = blk_update_request(req, 0, bytes); + if (!ret) + __blk_mq_end_request(req, 0); + } +} + static inline void mmc_wait_ongoing_tfr_cmd(struct mmc_host *host) { struct mmc_request *ongoing_mrq = READ_ONCE(host->ongoing_mrq); @@ -463,14 +538,20 @@ static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq) return err; } -static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) +static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq, + struct mmc_queue_req *mqrq) { int err; mmc_wait_ongoing_tfr_cmd(host); init_completion(&mrq->completion); - mrq->done = mmc_wait_done; + if (mmc_use_blk_mq()) { + mrq->done = mmc_mq_wait_done; + mrq->host = host; + mrq->mqrq = mqrq; + } else + mrq->done = mmc_wait_done; init_completion(&mrq->cmd_completion); @@ -478,7 +559,10 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) if (err) { mrq->cmd->error = err; mmc_complete_cmd(mrq); - complete(&mrq->completion); + if (mmc_use_blk_mq()) + mmc_mq_wait_done(mrq); + else + complete(&mrq->completion); } return err; @@ -591,7 +675,7 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) */ bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq) { - if (host->areq) + if (!mmc_use_blk_mq() && host->areq) return host->context_info.is_done_rcv; else return completion_done(&mrq->completion); @@ -709,6 +793,24 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, } EXPORT_SYMBOL(mmc_start_req); +struct mmc_async_req *mmc_mq_start_req(struct mmc_host *host, + struct mmc_async_req *areq, + enum mmc_blk_status *ret_stat, + struct mmc_queue_req *mqrq) +{ + int start_err = 0; + + mmc_pre_req(host, areq->mrq); + + start_err = __mmc_start_req(host, areq->mrq, mqrq); + + if (ret_stat) + *ret_stat = MMC_BLK_SUCCESS; + + return areq; +} +EXPORT_SYMBOL(mmc_mq_start_req); + /** * mmc_wait_for_req - start a request and wait for completion * @host: MMC host to start command @@ -723,10 +825,14 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, */ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) { - __mmc_start_req(host, mrq); + __mmc_start_req(host, mrq, NULL); - if (!mrq->cap_cmd_during_tfr) - mmc_wait_for_req_done(host, mrq); + if (!mrq->cap_cmd_during_tfr) { + if (mmc_use_blk_mq()) + wait_for_completion(&mrq->completion); + else + mmc_wait_for_req_done(host, mrq); + } } EXPORT_SYMBOL(mmc_wait_for_req); diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 3ab6e52..6d2b62a 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -2436,12 +2436,16 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test, } while (repeat_cmd && R1_CURRENT_STATE(status) != R1_STATE_TRAN); /* Wait for data request to complete */ - if (use_areq) { - mmc_start_req(host, NULL, &blkstat); - if (blkstat != MMC_BLK_SUCCESS) - ret = RESULT_FAIL; - } else { - mmc_wait_for_req_done(test->card->host, mrq); + if (mmc_use_blk_mq()) + wait_for_completion(&mrq->completion); + else { + if (use_areq) { + mmc_start_req(host, NULL, &blkstat); + if (blkstat != MMC_BLK_SUCCESS) + ret = RESULT_FAIL; + } else { + mmc_wait_for_req_done(test->card->host, mrq); + } } /* diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 6284101..5e7e515 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -9,6 +9,7 @@ */ #include <linux/slab.h> #include <linux/module.h> +#include <linux/blk-mq.h> #include <linux/blkdev.h> #include <linux/freezer.h> #include <linux/kthread.h> @@ -47,6 +48,21 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) return BLKPREP_OK; } +static int mmc_mq_queue_ready(struct request_queue *q, struct mmc_queue *mq) +{ + unsigned int busy; + + busy = atomic_inc_return(&mq->device_busy) - 1; + + if (busy >= mq->qdepth) + goto out_dec; + + return 1; +out_dec: + atomic_dec(&mq->device_busy); + return 0; +} + struct mmc_queue_req *mmc_queue_req_find(struct mmc_queue *mq, struct request *req) { @@ -74,6 +90,8 @@ void mmc_queue_req_free(struct mmc_queue *mq, mqrq->req = NULL; mq->qcnt -= 1; __clear_bit(mqrq->task_id, &mq->qslots); + if (mmc_use_blk_mq()) + atomic_dec(&mq->device_busy); } static int mmc_queue_thread(void *d) @@ -108,7 +126,7 @@ static int mmc_queue_thread(void *d) if (req || mq->qcnt) { set_current_state(TASK_RUNNING); - mmc_blk_issue_rq(mq, req); + mmc_blk_issue_rq(mq, req, NULL); cond_resched(); } else { if (kthread_should_stop()) { @@ -282,6 +300,44 @@ static struct mmc_queue_req *mmc_queue_alloc_mqrqs(int qdepth) return mqrq; } +static int mmc_init_request(void *data, struct request *rq, + unsigned int hctx_idx, unsigned int request_idx, + unsigned int numa_node) +{ + return 0; +} + +static void mmc_exit_request(void *data, struct request *rq, + unsigned int hctx_idx, unsigned int request_idx) +{ +} + +static int mmc_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) +{ + struct request *req = bd->rq; + struct request_queue *q = req->q; + struct mmc_queue *mq = q->queuedata; + struct mmc_queue_req *mqrq_cur; + + WARN_ON(req && req->cmd_type != REQ_TYPE_FS); + + if (!mmc_mq_queue_ready(q, mq)) + return BLK_MQ_RQ_QUEUE_BUSY; + + mqrq_cur = mmc_queue_req_find(mq, req); + BUG_ON(!mqrq_cur); + mmc_blk_issue_rq(mq, req, mqrq_cur); + + return BLK_MQ_RQ_QUEUE_OK; +} + +static struct blk_mq_ops mmc_mq_ops = { + .queue_rq = mmc_queue_rq, + .init_request = mmc_init_request, + .exit_request = mmc_exit_request, +}; + /** * mmc_init_queue - initialise a queue structure. * @mq: mmc queue @@ -295,6 +351,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock, const char *subname) { struct mmc_host *host = card->host; + struct request_queue *q; u64 limit = BLK_BOUNCE_HIGH; bool bounce = false; int ret = -ENOMEM; @@ -303,11 +360,36 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT; mq->card = card; - mq->queue = blk_init_queue(mmc_request_fn, lock); - if (!mq->queue) - return -ENOMEM; + if (!mmc_use_blk_mq()) { + mq->queue = blk_init_queue(mmc_request_fn, lock); + if (!mq->queue) + return -ENOMEM; + + mq->qdepth = 2; + } else { + memset(&mq->tag_set, 0, sizeof(mq->tag_set)); + mq->tag_set.ops = &mmc_mq_ops; + mq->tag_set.queue_depth = 1; + mq->tag_set.numa_node = NUMA_NO_NODE; + mq->tag_set.flags = + BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE; + mq->tag_set.nr_hw_queues = 1; + mq->tag_set.cmd_size = sizeof(struct mmc_queue_req); + + ret = blk_mq_alloc_tag_set(&mq->tag_set); + if (ret) + goto out; + + q = blk_mq_init_queue(&mq->tag_set); + if (IS_ERR(q)) { + ret = PTR_ERR(q); + goto cleanup_tag_set; + } + mq->queue = q; + + mq->qdepth = 1; + } - mq->qdepth = 2; mq->mqrq = mmc_queue_alloc_mqrqs(mq->qdepth); if (!mq->mqrq) goto blk_cleanup; @@ -359,6 +441,9 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, goto cleanup_queue; } + if (mmc_use_blk_mq()) + return 0; + sema_init(&mq->thread_sem, 1); mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s", @@ -377,6 +462,10 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, mq->mqrq = NULL; blk_cleanup: blk_cleanup_queue(mq->queue); +cleanup_tag_set: + if (mmc_use_blk_mq()) + blk_mq_free_tag_set(&mq->tag_set); +out: return ret; } @@ -388,8 +477,10 @@ void mmc_cleanup_queue(struct mmc_queue *mq) /* Make sure the queue isn't suspended, as that will deadlock */ mmc_queue_resume(mq); - /* Then terminate our worker thread */ - kthread_stop(mq->thread); + if (!mmc_use_blk_mq()) { + /* Then terminate our worker thread */ + kthread_stop(mq->thread); + } /* Empty the queue */ spin_lock_irqsave(q->queue_lock, flags); @@ -401,6 +492,9 @@ void mmc_cleanup_queue(struct mmc_queue *mq) kfree(mq->mqrq); mq->mqrq = NULL; + if (mmc_use_blk_mq()) + blk_mq_free_tag_set(&mq->tag_set); + mq->card = NULL; } EXPORT_SYMBOL(mmc_cleanup_queue); @@ -425,7 +519,8 @@ void mmc_queue_suspend(struct mmc_queue *mq) blk_stop_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); - down(&mq->thread_sem); + if (!mmc_use_blk_mq()) + down(&mq->thread_sem); } } @@ -441,7 +536,8 @@ void mmc_queue_resume(struct mmc_queue *mq) if (mq->flags & MMC_QUEUE_SUSPENDED) { mq->flags &= ~MMC_QUEUE_SUSPENDED; - up(&mq->thread_sem); + if (!mmc_use_blk_mq()) + up(&mq->thread_sem); spin_lock_irqsave(q->queue_lock, flags); blk_start_queue(q); diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index 95ca330..732007e 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -46,6 +46,11 @@ struct mmc_queue { int qdepth; int qcnt; unsigned long qslots; + + atomic_t device_busy; + + /* Block layer tags. */ + struct blk_mq_tag_set tag_set; }; extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *, diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index e33cc74..9cb2195 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -141,6 +141,7 @@ struct mmc_data { }; struct mmc_host; +struct mmc_queue_req; struct mmc_request { struct mmc_command *sbc; /* SET_BLOCK_COUNT for multiblock */ struct mmc_command *cmd; @@ -154,6 +155,8 @@ struct mmc_request { /* Allow other commands during this ongoing data transfer or busy wait */ bool cap_cmd_during_tfr; + + struct mmc_queue_req *mqrq; }; struct mmc_card; @@ -164,6 +167,10 @@ struct mmc_request { extern struct mmc_async_req *mmc_start_req(struct mmc_host *, struct mmc_async_req *, enum mmc_blk_status *); +extern struct mmc_async_req *mmc_mq_start_req(struct mmc_host *, + struct mmc_async_req *, + enum mmc_blk_status *, + struct mmc_queue_req *); extern int mmc_interrupt_hpi(struct mmc_card *); extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *); extern void mmc_wait_for_req_done(struct mmc_host *host, @@ -234,4 +241,9 @@ static inline void mmc_claim_host(struct mmc_host *host) extern u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max); extern int mmc_of_parse_voltage(struct device_node *np, u32 *mask); +static inline bool mmc_use_blk_mq(void) +{ + return 1; +} + #endif /* LINUX_MMC_CORE_H */ -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html