[PATCH PoC 7/7] mmc-mq: async request support for blk-mq mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@xxxxxxxxxxx>
---
 drivers/mmc/card/block.c | 51 +++++++++--------------------------
 drivers/mmc/card/queue.c | 49 ++++++++++++++++++++++++++++++---
 drivers/mmc/card/queue.h | 36 +++++++++++++++++++++++++
 drivers/mmc/core/core.c  | 70 +++++++++++++++++++++++++++++++++++++-----------
 4 files changed, 148 insertions(+), 58 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9968623..8d73828 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -89,39 +89,6 @@ static int max_devices;
 static DEFINE_IDA(mmc_blk_ida);
 static DEFINE_SPINLOCK(mmc_blk_lock);
 
-/*
- * There is one mmc_blk_data per slot.
- */
-struct mmc_blk_data {
-	spinlock_t	lock;
-	struct gendisk	*disk;
-	struct mmc_queue queue;
-	struct list_head part;
-
-	unsigned int	flags;
-#define MMC_BLK_CMD23	(1 << 0)	/* Can do SET_BLOCK_COUNT for multiblock */
-#define MMC_BLK_REL_WR	(1 << 1)	/* MMC Reliable write support */
-#define MMC_BLK_PACKED_CMD	(1 << 2)	/* MMC packed command support */
-
-	unsigned int	usage;
-	unsigned int	read_only;
-	unsigned int	part_type;
-	unsigned int	reset_done;
-#define MMC_BLK_READ		BIT(0)
-#define MMC_BLK_WRITE		BIT(1)
-#define MMC_BLK_DISCARD		BIT(2)
-#define MMC_BLK_SECDISCARD	BIT(3)
-
-	/*
-	 * Only set in main mmc_blk_data associated
-	 * with mmc_card with dev_set_drvdata, and keeps
-	 * track of the current selected device partition.
-	 */
-	unsigned int	part_curr;
-	struct device_attribute force_ro;
-	struct device_attribute power_ro_lock;
-	int	area_type;
-};
 
 static DEFINE_MUTEX(open_lock);
 
@@ -1316,7 +1283,7 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req, struct
 	struct mmc_card *card = md->queue.card;
 	int ret = 0;
 
-	ret = mmc_flush_cache(card);
+////	ret = mmc_flush_cache(card);
 	if (ret)
 		ret = -EIO;
 
@@ -1528,7 +1495,7 @@ static int mmc_blk_packed_err_check(struct mmc_card *card,
 	return check;
 }
 
-static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
+void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
 			       struct mmc_card *card,
 			       int disable_multi,
 			       struct mmc_queue *mq)
@@ -2204,7 +2171,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
 	return 0;
 }
 
-static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req, struct mmc_queue_req *mqrq)
+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->data;
@@ -2216,7 +2183,9 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req, struct mm
 	BUG_ON(!req);
 
 	/* claim host only for the first request */
-	mmc_get_card(card);
+////	pr_info("%s: enter mq->qcnt=%d\n", __func__, mq->qcnt);
+	if (mq->qcnt == 1)
+		mmc_get_card(card);
 
 	blk_mq_start_request(req);
 
@@ -2248,7 +2217,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req, struct mm
 out:
 	/* Release host when there are no more requests */
 /////	mmc_put_card(card);
-//	pr_info("%s: exit (mq=%p md=%p)\n", __func__, mq, md);
+////	pr_info("%s: exit (mq=%p md=%p)\n", __func__, mq, md);
 	return ret;
 }
 
@@ -2624,6 +2593,8 @@ static const struct mmc_fixup blk_fixups[] =
 	END_FIXUP
 };
 
+//static int probe_done = 0;
+
 static int mmc_blk_probe(struct mmc_card *card)
 {
 	struct mmc_blk_data *md, *part_md;
@@ -2635,6 +2606,10 @@ static int mmc_blk_probe(struct mmc_card *card)
 	if (!(card->csd.cmdclass & CCC_BLOCK_READ))
 		return -ENODEV;
 
+//	if (probe_done)
+//		return -ENODEV;
+//	probe_done = 1;
+
 	mmc_fixup_device(card, blk_fixups);
 
 	md = mmc_blk_alloc(card);
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 038c01e..372ec0c2 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -78,7 +78,7 @@ struct mmc_queue_req *mmc_queue_req_find(struct mmc_queue *mq,
 
 ////	spin_lock_irq(req->q->queue_lock);
 	mqrq = &mq->mqrq[i];
-	WARN_ON(mqrq->testtag == 0);
+//	WARN_ON(mqrq->testtag == 0);
 	WARN_ON(mqrq->req || mq->qcnt >= mq->qdepth ||
 		test_bit(mqrq->task_id, &mq->qslots));
 	mqrq->req = req;
@@ -302,6 +302,16 @@ static void mmc_exit_request(void *data, struct request *rq,
 //	kfree(cmd->sense_buffer);
 }
 
+extern void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
+			       struct mmc_card *card,
+			       int disable_multi,
+			       struct mmc_queue *mq);
+
+extern void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
+		 bool is_first_req);
+
+static struct mmc_queue *probe_mq = NULL;
+
 static int mmc_queue_rq(struct blk_mq_hw_ctx *hctx,
 			 const struct blk_mq_queue_data *bd)
 {
@@ -311,15 +321,40 @@ static int mmc_queue_rq(struct blk_mq_hw_ctx *hctx,
 	struct mmc_queue_req *mqrq_cur;
 //	struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req);
 	int ret;
+	unsigned long flags = 0;
 
 	WARN_ON(req && req->cmd_type != REQ_TYPE_FS);
 
+	if (!probe_mq)
+		probe_mq = mq;
+
+	if (probe_mq && probe_mq != mq) {
+		return BLK_MQ_RQ_QUEUE_ERROR;
+	}
+
 	if (!mmc_queue_ready(q, mq))
 		return BLK_MQ_RQ_QUEUE_BUSY;
 
+	spin_lock_irqsave(&mq->async_lock, flags);
+////	pr_info("%s: enter mq->qcnt=%d\n", __func__, mq->qcnt);
 	mqrq_cur = mmc_queue_req_find(mq, req);
 	BUG_ON(!mqrq_cur);
-	mq->issue_fn(mq, req, mqrq_cur);
+	if (mq->qcnt == 2) {
+		if ((mqrq_cur->req->cmd_flags & (REQ_DISCARD | REQ_FLUSH)) == 0) {
+			struct mmc_blk_data *md = mq->data;
+			struct mmc_card *card = md->queue.card;
+			struct mmc_host *host = card->host;
+			struct mmc_async_req *areq;
+
+			mmc_blk_rw_rq_prep(mqrq_cur, card, 0, mq);
+			areq = &mqrq_cur->mmc_active;
+			mmc_pre_req(host, areq->mrq, 1);
+		}
+	}
+	if (mq->qcnt == 1)
+		mq->issue_fn(mq, req, mqrq_cur);
+////	pr_info("%s: exit mq->qcnt=%d\n", __func__, mq->qcnt);
+	spin_unlock_irqrestore(&mq->async_lock, flags);
 
 	return BLK_MQ_RQ_QUEUE_OK;
 }
@@ -333,6 +368,7 @@ static struct blk_mq_ops mmc_mq_ops = {
 	.exit_request	= mmc_exit_request,
 };
 
+//static int q_probe = 0;
 
 /**
  * mmc_init_queue - initialise a queue structure.
@@ -352,6 +388,10 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
 	bool bounce = false;
 	int ret = -ENOMEM;
 
+//	if (q_probe)
+//		return -ENOMEM;
+//	q_probe = 1;
+
 	if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
 		limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
 
@@ -361,7 +401,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
 //		return -ENOMEM;
 	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.queue_depth = 2;
 	mq->tag_set.numa_node = NUMA_NO_NODE;
 	mq->tag_set.flags =
 		BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE;
@@ -379,12 +419,13 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
 	}
 	mq->queue = q;
 
-	mq->qdepth = 1;
+	mq->qdepth = 2;
 	mq->mqrq = mmc_queue_alloc_mqrqs(mq, mq->qdepth);
 	if (!mq->mqrq)
 		goto blk_cleanup;
 	mq->testtag = 1;
 	mq->queue->queuedata = mq;
+	spin_lock_init(&mq->async_lock);
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index b67ac83..99dacb7 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -66,6 +66,42 @@ struct mmc_queue {
 
 	/* Block layer tags. */
 	struct blk_mq_tag_set	tag_set;
+
+	spinlock_t		async_lock;
+};
+
+/*
+ * There is one mmc_blk_data per slot.
+ */
+struct mmc_blk_data {
+	spinlock_t	lock;
+	struct gendisk	*disk;
+	struct mmc_queue queue;
+	struct list_head part;
+
+	unsigned int	flags;
+#define MMC_BLK_CMD23	(1 << 0)	/* Can do SET_BLOCK_COUNT for multiblock */
+#define MMC_BLK_REL_WR	(1 << 1)	/* MMC Reliable write support */
+#define MMC_BLK_PACKED_CMD	(1 << 2)	/* MMC packed command support */
+
+	unsigned int	usage;
+	unsigned int	read_only;
+	unsigned int	part_type;
+	unsigned int	reset_done;
+#define MMC_BLK_READ		BIT(0)
+#define MMC_BLK_WRITE		BIT(1)
+#define MMC_BLK_DISCARD		BIT(2)
+#define MMC_BLK_SECDISCARD	BIT(3)
+
+	/*
+	 * Only set in main mmc_blk_data associated
+	 * with mmc_card with dev_set_drvdata, and keeps
+	 * track of the current selected device partition.
+	 */
+	unsigned int	part_curr;
+	struct device_attribute force_ro;
+	struct device_attribute power_ro_lock;
+	int	area_type;
 };
 
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 64687f1..ebb6ed5 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -415,6 +415,9 @@ EXPORT_SYMBOL(mmc_start_bkops);
 static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
 			 int err);
 
+int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req, struct mmc_queue_req *mqrq);
+int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq, struct mmc_queue_req *mqrq);
+
 /*
  * mmc_wait_done() - done callback for request
  * @mrq: done request
@@ -431,8 +434,18 @@ static void mmc_wait_done(struct mmc_request *mrq)
 //	struct mmc_queue_req *mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
 	struct mmc_command *cmd;
 	int err = 0, ret = 0;
+	unsigned long flags = 0;
+	struct mmc_queue *mq = NULL;
 
-//	pr_info("%s: enter\n", __func__);
+	if (mq_rq)
+		mq = mq_rq->req->q->queuedata;
+
+////	pr_info("%s: enter\n", __func__);
+
+	if (mq) {
+		spin_lock_irqsave(&mq->async_lock, flags);
+////		pr_info("%s: enter mq\n", __func__);
+	}
 
 	cmd = mrq->cmd;
 //	pr_info("%s: cmd->opcode=%d mq_rq=%p\n", __func__, cmd->opcode, mq_rq);
@@ -459,11 +472,28 @@ static void mmc_wait_done(struct mmc_request *mrq)
 		cmd->error = 0;
 		__mmc_start_request(host, mrq);
 //		goto out;
+		if (mq)
+			spin_unlock_irqrestore(&mq->async_lock, flags);
 		return;
 	}
 
 	mmc_retune_release(host);
 
+	if (mq && mq->qcnt == 2) {
+		struct mmc_queue_req *mq_rq2 = &mq->mqrq[!mq_rq->task_id];
+
+		if (mq_rq2 &&
+		    (mq_rq2->req->cmd_type == REQ_TYPE_FS) &&
+			(mq_rq2->req->cmd_flags & (REQ_DISCARD | REQ_FLUSH))) {
+			mmc_blk_issue_rq(mq, mq_rq2->req, mq_rq2);
+		} else {
+			struct mmc_async_req *areq;
+
+			areq = &mq_rq2->mmc_active;
+			__mmc_start_req(host, areq->mrq, mq_rq2);
+		}
+	}
+
 //	host->areq->pre_req_done = false;
 	if (mq_rq &&
 	    (mq_rq->req->cmd_type == REQ_TYPE_FS) &&
@@ -472,7 +502,7 @@ static void mmc_wait_done(struct mmc_request *mrq)
 	}
 
 	complete(&mrq->completion);
-BUG_ON(mq_rq && (mq_rq->req->cmd_type == REQ_TYPE_FS) && (mq_rq->req->cmd_flags & (REQ_DISCARD | REQ_FLUSH)));
+//BUG_ON(mq_rq && (mq_rq->req->cmd_type == REQ_TYPE_FS) && (mq_rq->req->cmd_flags & (REQ_DISCARD | REQ_FLUSH)));
 	if (mq_rq &&
 	    (mq_rq->req->cmd_type == REQ_TYPE_FS) &&
 	    ((mq_rq->req->cmd_flags & (REQ_DISCARD | REQ_FLUSH)) == 0)) {
@@ -487,7 +517,9 @@ BUG_ON(mq_rq && (mq_rq->req->cmd_type == REQ_TYPE_FS) && (mq_rq->req->cmd_flags
 		mmc_queue_bounce_post(mq_rq);
 
 		bytes = brq->data.bytes_xfered;
-		mmc_put_card(host->card);
+////		pr_info("%s: enter mq->qcnt=%d\n", __func__, mq->qcnt);
+		if (mq->qcnt == 1)
+			mmc_put_card(host->card);
 //		pr_info("%s: freeing mqrq\n", __func__); //
 		mmc_queue_req_free(req->q->queuedata, mq_rq); //
 //		ret = blk_end_request(req, 0, bytes);
@@ -496,7 +528,9 @@ BUG_ON(mq_rq && (mq_rq->req->cmd_type == REQ_TYPE_FS) && (mq_rq->req->cmd_flags
 			__blk_mq_end_request(req, 0);
 	}
 //out:
-//	pr_info("%s: exit (err=%d, ret=%d)\n", __func__, err, ret);
+////	pr_info("%s: exit (err=%d, ret=%d)\n", __func__, err, ret);
+	if (mq)
+		spin_unlock_irqrestore(&mq->async_lock, flags);
 }
 
 static inline void mmc_wait_ongoing_tfr_cmd(struct mmc_host *host)
@@ -521,7 +555,7 @@ static inline void mmc_wait_ongoing_tfr_cmd(struct mmc_host *host)
  * If an ongoing transfer is already in progress, wait for the command line
  * to become available before sending another command.
  */
-static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq, struct mmc_queue_req *mqrq)
+int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq, struct mmc_queue_req *mqrq)
 {
 	int err;
 
@@ -675,7 +709,7 @@ EXPORT_SYMBOL(mmc_is_req_done);
  *	host prepare for the new request. Preparation of a request may be
  *	performed while another request is running on the host.
  */
-static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
+void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
 		 bool is_first_req)
 {
 	if (host->ops->pre_req)
@@ -797,9 +831,10 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
 	if (!mrq->cap_cmd_during_tfr) {
 //		mmc_wait_for_req_done(host, mrq);
 //		BUG(); //
-//		pr_info("%s: wait start\n", __func__);
-		wait_for_completion(&mrq->completion);
-//		pr_info("%s: wait done\n", __func__);
+////		pr_info("%s: wait start\n", __func__);
+		mdelay(500);
+		//wait_for_completion(&mrq->completion);
+////		pr_info("%s: wait done\n", __func__);
 	}
 
 //	pr_info("%s: exit\n", __func__);
@@ -1097,9 +1132,9 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
-	int stop;
+	int stop = 0; //
 	bool pm = false;
-
+#if 0
 	might_sleep();
 
 	add_wait_queue(&host->wq, &wait);
@@ -1114,17 +1149,20 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
 		spin_lock_irqsave(&host->lock, flags);
 	}
 	set_current_state(TASK_RUNNING);
+#endif
 	if (!stop) {
 		host->claimed = 1;
 		host->claimer = current;
 		host->claim_cnt += 1;
 		if (host->claim_cnt == 1)
 			pm = true;
+	}
+#if 0
 	} else
 		wake_up(&host->wq);
 	spin_unlock_irqrestore(&host->lock, flags);
 	remove_wait_queue(&host->wq, &wait);
-
+#endif
 	if (pm)
 		pm_runtime_get_sync(mmc_dev(host));
 
@@ -1145,15 +1183,15 @@ void mmc_release_host(struct mmc_host *host)
 
 	WARN_ON(!host->claimed);
 
-	spin_lock_irqsave(&host->lock, flags);
+//	spin_lock_irqsave(&host->lock, flags);
 	if (--host->claim_cnt) {
 		/* Release for nested claim */
-		spin_unlock_irqrestore(&host->lock, flags);
+//		spin_unlock_irqrestore(&host->lock, flags);
 	} else {
 		host->claimed = 0;
 		host->claimer = NULL;
-		spin_unlock_irqrestore(&host->lock, flags);
-		wake_up(&host->wq);
+//		spin_unlock_irqrestore(&host->lock, flags);
+//		wake_up(&host->wq);
 		pm_runtime_mark_last_busy(mmc_dev(host));
 		pm_runtime_put_autosuspend(mmc_dev(host));
 	}
-- 
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



[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux