Linux MultiMedia Card development
 help / color / mirror / Atom feed
* [PATCH V7 14/25] mmc: core: Export mmc_retune_hold() and mmc_retune_release()
From: Adrian Hunter @ 2016-11-25 10:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
	Jaehoon Chung, Dong Aisheng, Das Asutosh, Zhangfei Gao,
	Dorfman Konstantin, David Griego, Sahitya Tummala, Harjani Ritesh,
	Venu Byravarasu, Linus Walleij
In-Reply-To: <1480068442-5169-1-git-send-email-adrian.hunter@intel.com>

Re-tuning can only be done when the Command Queue is empty, when means
holding and releasing re-tuning from the block driver, so export those
functions.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/core/host.c  | 2 ++
 drivers/mmc/core/host.h  | 2 --
 include/linux/mmc/core.h | 3 +++
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 98f25ffb4258..878405e28bdb 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -112,6 +112,7 @@ void mmc_retune_hold(struct mmc_host *host)
 		host->retune_now = 1;
 	host->hold_retune += 1;
 }
+EXPORT_SYMBOL(mmc_retune_hold);
 
 void mmc_retune_release(struct mmc_host *host)
 {
@@ -120,6 +121,7 @@ void mmc_retune_release(struct mmc_host *host)
 	else
 		WARN_ON(1);
 }
+EXPORT_SYMBOL(mmc_retune_release);
 
 int mmc_retune(struct mmc_host *host)
 {
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index 992bf5397633..0787b3002481 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -17,8 +17,6 @@
 
 void mmc_retune_enable(struct mmc_host *host);
 void mmc_retune_disable(struct mmc_host *host);
-void mmc_retune_hold(struct mmc_host *host);
-void mmc_retune_release(struct mmc_host *host);
 int mmc_retune(struct mmc_host *host);
 
 #endif
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index d045b06fc7ea..d8f46e1ae7f2 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -220,6 +220,9 @@ extern int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
 
 extern int mmc_detect_card_removed(struct mmc_host *host);
 
+extern void mmc_retune_hold(struct mmc_host *host);
+extern void mmc_retune_release(struct mmc_host *host);
+
 /**
  *	mmc_claim_host - exclusively claim a host
  *	@host: mmc host to claim
-- 
1.9.1


^ permalink raw reply related

* [PATCH V7 15/25] mmc: block: Factor out mmc_blk_requeue()
From: Adrian Hunter @ 2016-11-25 10:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
	Jaehoon Chung, Dong Aisheng, Das Asutosh, Zhangfei Gao,
	Dorfman Konstantin, David Griego, Sahitya Tummala, Harjani Ritesh,
	Venu Byravarasu, Linus Walleij
In-Reply-To: <1480068442-5169-1-git-send-email-adrian.hunter@intel.com>

The same code is used in a couple of places.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/card/block.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 157d1b3d58d6..35e8d01b3013 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1319,6 +1319,13 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 	return ret ? 0 : 1;
 }
 
+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);
+}
+
 /*
  * Reformat current write as a reliable write, supporting
  * both legacy and the enhanced reliable write MMC cards.
@@ -1835,11 +1842,8 @@ static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
 		reqs++;
 	} while (1);
 
-	if (put_back) {
-		spin_lock_irq(q->queue_lock);
-		blk_requeue_request(q, next);
-		spin_unlock_irq(q->queue_lock);
-	}
+	if (put_back)
+		mmc_blk_requeue(q, next);
 
 	if (reqs > 0) {
 		list_add(&req->queuelist, &mqrq->packed->list);
@@ -2018,9 +2022,7 @@ static void mmc_blk_revert_packed_req(struct mmc_queue *mq,
 		prq = list_entry_rq(packed->list.prev);
 		if (prq->queuelist.prev != &packed->list) {
 			list_del_init(&prq->queuelist);
-			spin_lock_irq(q->queue_lock);
-			blk_requeue_request(mq->queue, prq);
-			spin_unlock_irq(q->queue_lock);
+			mmc_blk_requeue(q, prq);
 		} else {
 			list_del_init(&prq->queuelist);
 		}
-- 
1.9.1


^ permalink raw reply related

* [PATCH V7 16/25] mmc: block: Fix 4K native sector check
From: Adrian Hunter @ 2016-11-25 10:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
	Jaehoon Chung, Dong Aisheng, Das Asutosh, Zhangfei Gao,
	Dorfman Konstantin, David Griego, Sahitya Tummala, Harjani Ritesh,
	Venu Byravarasu, Linus Walleij
In-Reply-To: <1480068442-5169-1-git-send-email-adrian.hunter@intel.com>

The 4K native sector check does not allow for the 'do' loop nor the
variables used after the 'cmd_abort' label.

'brq' and 'req' get reassigned in the 'do' loop, so the check must not
assume what their values are. After the 'cmd_abort' label, 'mq_rq' and
'req' are used, but 'rqc' must be NULL otherwise it can be started again.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/card/block.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 35e8d01b3013..f9d2bcf998fb 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2035,11 +2035,11 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 {
 	struct mmc_blk_data *md = mq->blkdata;
 	struct mmc_card *card = md->queue.card;
-	struct mmc_blk_request *brq = &mq->mqrq_cur->brq;
+	struct mmc_blk_request *brq;
 	int ret = 1, disable_multi = 0, retry = 0, type, retune_retry_done = 0;
 	enum mmc_blk_status status;
 	struct mmc_queue_req *mq_rq;
-	struct request *req = rqc;
+	struct request *req;
 	struct mmc_async_req *areq;
 	const u8 packed_nr = 2;
 	u8 reqs = 0;
@@ -2059,8 +2059,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 			if (mmc_large_sector(card) &&
 				!IS_ALIGNED(blk_rq_sectors(rqc), 8)) {
 				pr_err("%s: Transfer size is not 4KB sector size aligned\n",
-					req->rq_disk->disk_name);
+					rqc->rq_disk->disk_name);
 				mq_rq = mq->mqrq_cur;
+				req = rqc;
+				rqc = NULL;
 				goto cmd_abort;
 			}
 
-- 
1.9.1


^ permalink raw reply related

* [PATCH V7 17/25] mmc: block: Use local var for mqrq_cur
From: Adrian Hunter @ 2016-11-25 10:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
	Jaehoon Chung, Dong Aisheng, Das Asutosh, Zhangfei Gao,
	Dorfman Konstantin, David Griego, Sahitya Tummala, Harjani Ritesh,
	Venu Byravarasu, Linus Walleij
In-Reply-To: <1480068442-5169-1-git-send-email-adrian.hunter@intel.com>

A subsequent patch will remove 'mq->mqrq_cur'. Prepare for that by
assigning it to a local variable.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/card/block.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index f9d2bcf998fb..c1745f2270ba 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2038,6 +2038,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 	struct mmc_blk_request *brq;
 	int ret = 1, disable_multi = 0, retry = 0, type, retune_retry_done = 0;
 	enum mmc_blk_status status;
+	struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
 	struct mmc_queue_req *mq_rq;
 	struct request *req;
 	struct mmc_async_req *areq;
@@ -2060,18 +2061,18 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 				!IS_ALIGNED(blk_rq_sectors(rqc), 8)) {
 				pr_err("%s: Transfer size is not 4KB sector size aligned\n",
 					rqc->rq_disk->disk_name);
-				mq_rq = mq->mqrq_cur;
+				mq_rq = mqrq_cur;
 				req = rqc;
 				rqc = NULL;
 				goto cmd_abort;
 			}
 
 			if (reqs >= packed_nr)
-				mmc_blk_packed_hdr_wrq_prep(mq->mqrq_cur,
+				mmc_blk_packed_hdr_wrq_prep(mqrq_cur,
 							    card, mq);
 			else
-				mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
-			areq = &mq->mqrq_cur->mmc_active;
+				mmc_blk_rw_rq_prep(mqrq_cur, card, 0, mq);
+			areq = &mqrq_cur->mmc_active;
 		} else
 			areq = NULL;
 		areq = mmc_start_req(card->host, areq, &status);
@@ -2213,12 +2214,12 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 			/*
 			 * If current request is packed, it needs to put back.
 			 */
-			if (mmc_packed_cmd(mq->mqrq_cur->cmd_type))
-				mmc_blk_revert_packed_req(mq, mq->mqrq_cur);
+			if (mmc_packed_cmd(mqrq_cur->cmd_type))
+				mmc_blk_revert_packed_req(mq, mqrq_cur);
 
-			mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+			mmc_blk_rw_rq_prep(mqrq_cur, card, 0, mq);
 			mmc_start_req(card->host,
-				      &mq->mqrq_cur->mmc_active, NULL);
+				      &mqrq_cur->mmc_active, NULL);
 		}
 	}
 
-- 
1.9.1


^ permalink raw reply related

* [PATCH V7 18/25] mmc: block: Pass mqrq to mmc_blk_prep_packed_list()
From: Adrian Hunter @ 2016-11-25 10:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
	Jaehoon Chung, Dong Aisheng, Das Asutosh, Zhangfei Gao,
	Dorfman Konstantin, David Griego, Sahitya Tummala, Harjani Ritesh,
	Venu Byravarasu, Linus Walleij
In-Reply-To: <1480068442-5169-1-git-send-email-adrian.hunter@intel.com>

A subsequent patch will remove 'mq->mqrq_cur'. Prepare for that by
passing mqrq to mmc_blk_prep_packed_list().

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/card/block.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index c1745f2270ba..ebc5d2ff8f32 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1741,13 +1741,14 @@ static inline u8 mmc_calc_packed_hdr_segs(struct request_queue *q,
 	return nr_segs;
 }
 
-static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
+static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq,
+				   struct mmc_queue_req *mqrq)
 {
 	struct request_queue *q = mq->queue;
 	struct mmc_card *card = mq->card;
+	struct request *req = mqrq->req;
 	struct request *cur = req, *next = NULL;
 	struct mmc_blk_data *md = mq->blkdata;
-	struct mmc_queue_req *mqrq = mq->mqrq_cur;
 	bool en_rel_wr = card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN;
 	unsigned int req_sectors = 0, phys_segments = 0;
 	unsigned int max_blk_count, max_phys_segs;
@@ -2048,8 +2049,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 	if (!rqc && !mq->mqrq_prev->req)
 		return 0;
 
-	if (rqc)
-		reqs = mmc_blk_prep_packed_list(mq, rqc);
+	if (mqrq_cur)
+		reqs = mmc_blk_prep_packed_list(mq, mqrq_cur);
 
 	do {
 		if (rqc) {
-- 
1.9.1


^ permalink raw reply related

* [PATCH V7 19/25] mmc: block: Introduce queue semantics
From: Adrian Hunter @ 2016-11-25 10:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
	Jaehoon Chung, Dong Aisheng, Das Asutosh, Zhangfei Gao,
	Dorfman Konstantin, David Griego, Sahitya Tummala, Harjani Ritesh,
	Venu Byravarasu, Linus Walleij
In-Reply-To: <1480068442-5169-1-git-send-email-adrian.hunter@intel.com>

Change from viewing the requests in progress as 'current' and 'previous',
to viewing them as a queue. The current request is allocated to the first
free slot. The presence of incomplete requests is determined from the
count (mq->qcnt) of entries in the queue. Non-read-write requests (i.e.
discards and flushes) are not added to the queue at all and require no
special handling. Also no special handling is needed for the
MMC_BLK_NEW_REQUEST case.

As well as allowing an arbitrarily sized queue, the queue thread function
is significantly simpler.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/card/block.c | 42 ++++++++++++++------------
 drivers/mmc/card/queue.c | 76 ++++++++++++++++++++++++++++++------------------
 drivers/mmc/card/queue.h | 10 +++++--
 3 files changed, 78 insertions(+), 50 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index ebc5d2ff8f32..54a018d38cc9 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2039,14 +2039,23 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 	struct mmc_blk_request *brq;
 	int ret = 1, disable_multi = 0, retry = 0, type, retune_retry_done = 0;
 	enum mmc_blk_status status;
-	struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
+	struct mmc_queue_req *mqrq_cur = NULL;
 	struct mmc_queue_req *mq_rq;
 	struct request *req;
 	struct mmc_async_req *areq;
 	const u8 packed_nr = 2;
 	u8 reqs = 0;
 
-	if (!rqc && !mq->mqrq_prev->req)
+	if (rqc) {
+		mqrq_cur = mmc_queue_req_find(mq, rqc);
+		if (!mqrq_cur) {
+			WARN_ON(1);
+			mmc_blk_requeue(mq->queue, rqc);
+			rqc = NULL;
+		}
+	}
+
+	if (!mq->qcnt)
 		return 0;
 
 	if (mqrq_cur)
@@ -2077,11 +2086,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 		} else
 			areq = NULL;
 		areq = mmc_start_req(card->host, areq, &status);
-		if (!areq) {
-			if (status == MMC_BLK_NEW_REQUEST)
-				mq->flags |= MMC_QUEUE_NEW_REQUEST;
+		if (!areq)
 			return 0;
-		}
 
 		mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
 		brq = &mq_rq->brq;
@@ -2193,6 +2199,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 		}
 	} while (ret);
 
+	mmc_queue_req_free(mq, mq_rq);
+
 	return 1;
 
  cmd_abort:
@@ -2211,6 +2219,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 		if (mmc_card_removed(card)) {
 			rqc->cmd_flags |= REQ_QUIET;
 			blk_end_request_all(rqc, -EIO);
+			mmc_queue_req_free(mq, mqrq_cur);
 		} else {
 			/*
 			 * If current request is packed, it needs to put back.
@@ -2224,6 +2233,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 		}
 	}
 
+	mmc_queue_req_free(mq, mq_rq);
+
 	return 0;
 }
 
@@ -2232,9 +2243,8 @@ int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 	int ret;
 	struct mmc_blk_data *md = mq->blkdata;
 	struct mmc_card *card = md->queue.card;
-	bool req_is_special = mmc_req_is_special(req);
 
-	if (req && !mq->mqrq_prev->req)
+	if (req && !mq->qcnt)
 		/* claim host only for the first request */
 		mmc_get_card(card);
 
@@ -2247,20 +2257,19 @@ int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 		goto out;
 	}
 
-	mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
 	if (req && req_op(req) == REQ_OP_DISCARD) {
 		/* complete ongoing async transfer before issuing discard */
-		if (card->host->areq)
+		if (mq->qcnt)
 			mmc_blk_issue_rw_rq(mq, NULL);
 		ret = mmc_blk_issue_discard_rq(mq, req);
 	} else if (req && req_op(req) == REQ_OP_SECURE_ERASE) {
 		/* complete ongoing async transfer before issuing secure erase*/
-		if (card->host->areq)
+		if (mq->qcnt)
 			mmc_blk_issue_rw_rq(mq, NULL);
 		ret = mmc_blk_issue_secdiscard_rq(mq, req);
 	} else if (req && req_op(req) == REQ_OP_FLUSH) {
 		/* complete ongoing async transfer before issuing flush */
-		if (card->host->areq)
+		if (mq->qcnt)
 			mmc_blk_issue_rw_rq(mq, NULL);
 		ret = mmc_blk_issue_flush(mq, req);
 	} else {
@@ -2268,13 +2277,8 @@ int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 	}
 
 out:
-	if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) || req_is_special)
-		/*
-		 * Release host when there are no more requests
-		 * and after special request(discard, flush) is done.
-		 * In case sepecial request, there is no reentry to
-		 * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
-		 */
+	/* Release host when there are no more requests */
+	if (!mq->qcnt)
 		mmc_put_card(card);
 	return ret;
 }
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 50d7bf074887..2570b813c25a 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -49,6 +49,35 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
 	return BLKPREP_OK;
 }
 
+struct mmc_queue_req *mmc_queue_req_find(struct mmc_queue *mq,
+					 struct request *req)
+{
+	struct mmc_queue_req *mqrq;
+	int i = ffz(mq->qslots);
+
+	if (i >= mq->qdepth)
+		return NULL;
+
+	mqrq = &mq->mqrq[i];
+	WARN_ON(mqrq->req || mq->qcnt >= mq->qdepth ||
+		test_bit(mqrq->task_id, &mq->qslots));
+	mqrq->req = req;
+	mq->qcnt += 1;
+	__set_bit(mqrq->task_id, &mq->qslots);
+
+	return mqrq;
+}
+
+void mmc_queue_req_free(struct mmc_queue *mq,
+			struct mmc_queue_req *mqrq)
+{
+	WARN_ON(!mqrq->req || mq->qcnt < 1 ||
+		!test_bit(mqrq->task_id, &mq->qslots));
+	mqrq->req = NULL;
+	mq->qcnt -= 1;
+	__clear_bit(mqrq->task_id, &mq->qslots);
+}
+
 static int mmc_queue_thread(void *d)
 {
 	struct mmc_queue *mq = d;
@@ -59,7 +88,7 @@ static int mmc_queue_thread(void *d)
 
 	down(&mq->thread_sem);
 	do {
-		struct request *req = NULL;
+		struct request *req;
 
 		spin_lock_irq(q->queue_lock);
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -72,38 +101,17 @@ static int mmc_queue_thread(void *d)
 			 * Dispatch queue is empty so set flags for
 			 * mmc_request_fn() to wake us up.
 			 */
-			if (mq->mqrq_prev->req)
+			if (mq->qcnt)
 				cntx->is_waiting_last_req = true;
 			else
 				mq->asleep = true;
 		}
-		mq->mqrq_cur->req = req;
 		spin_unlock_irq(q->queue_lock);
 
-		if (req || mq->mqrq_prev->req) {
-			bool req_is_special = mmc_req_is_special(req);
-
+		if (req || mq->qcnt) {
 			set_current_state(TASK_RUNNING);
 			mmc_blk_issue_rq(mq, req);
 			cond_resched();
-			if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
-				mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
-				continue; /* fetch again */
-			}
-
-			/*
-			 * Current request becomes previous request
-			 * and vice versa.
-			 * In case of special requests, current request
-			 * has been finished. Do not assign it to previous
-			 * request.
-			 */
-			if (req_is_special)
-				mq->mqrq_cur->req = NULL;
-
-			mq->mqrq_prev->brq.mrq.data = NULL;
-			mq->mqrq_prev->req = NULL;
-			swap(mq->mqrq_prev, mq->mqrq_cur);
 		} else {
 			if (kthread_should_stop()) {
 				set_current_state(TASK_RUNNING);
@@ -186,6 +194,21 @@ static void mmc_queue_setup_discard(struct request_queue *q,
 		queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q);
 }
 
+static struct mmc_queue_req *mmc_queue_alloc_mqrqs(struct mmc_queue *mq,
+						   int qdepth)
+{
+	struct mmc_queue_req *mqrq;
+	int i;
+
+	mqrq = kcalloc(qdepth, sizeof(*mqrq), GFP_KERNEL);
+	if (mqrq) {
+		for (i = 0; i < mq->qdepth; i++)
+			mqrq[i].task_id = i;
+	}
+
+	return mqrq;
+}
+
 static bool mmc_queue_alloc_bounce_bufs(struct mmc_queue *mq,
 					unsigned int bouncesz)
 {
@@ -286,12 +309,9 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
 		return -ENOMEM;
 
 	mq->qdepth = 2;
-	mq->mqrq = kcalloc(mq->qdepth, sizeof(struct mmc_queue_req),
-			   GFP_KERNEL);
+	mq->mqrq = mmc_queue_alloc_mqrqs(mq, mq->qdepth);
 	if (!mq->mqrq)
 		goto blk_cleanup;
-	mq->mqrq_cur = &mq->mqrq[0];
-	mq->mqrq_prev = &mq->mqrq[1];
 	mq->queue->queuedata = mq;
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index f17f5e505059..f7bc0ca0b27f 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -49,6 +49,7 @@ struct mmc_queue_req {
 	struct mmc_async_req	mmc_active;
 	enum mmc_packed_type	cmd_type;
 	struct mmc_packed	*packed;
+	int			task_id;
 };
 
 struct mmc_queue {
@@ -57,14 +58,13 @@ struct mmc_queue {
 	struct semaphore	thread_sem;
 	unsigned int		flags;
 #define MMC_QUEUE_SUSPENDED	(1 << 0)
-#define MMC_QUEUE_NEW_REQUEST	(1 << 1)
 	bool			asleep;
 	struct mmc_blk_data	*blkdata;
 	struct request_queue	*queue;
 	struct mmc_queue_req	*mqrq;
-	struct mmc_queue_req	*mqrq_cur;
-	struct mmc_queue_req	*mqrq_prev;
 	int			qdepth;
+	int			qcnt;
+	unsigned long		qslots;
 };
 
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
@@ -80,4 +80,8 @@ extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
 
 extern int mmc_access_rpmb(struct mmc_queue *);
 
+extern struct mmc_queue_req *mmc_queue_req_find(struct mmc_queue *,
+						struct request *);
+extern void mmc_queue_req_free(struct mmc_queue *, struct mmc_queue_req *);
+
 #endif
-- 
1.9.1


^ permalink raw reply related

* [PATCH V7 20/25] mmc: queue: Share mmc request array between partitions
From: Adrian Hunter @ 2016-11-25 10:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
	Jaehoon Chung, Dong Aisheng, Das Asutosh, Zhangfei Gao,
	Dorfman Konstantin, David Griego, Sahitya Tummala, Harjani Ritesh,
	Venu Byravarasu, Linus Walleij
In-Reply-To: <1480068442-5169-1-git-send-email-adrian.hunter@intel.com>

eMMC can have multiple internal partitions that are represented as separate
disks / queues. However the card has only 1 command queue which must be
empty when switching partitions. Consequently the array of mmc requests
that are queued can be shared between partitions saving memory.

Keep a pointer to the mmc request queue on the card, and use that instead
of allocating a new one for each partition. Use a reference count to keep
track of when to free it.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/card/block.c |  6 ++++++
 drivers/mmc/card/queue.c | 37 +++++++++++++++++++++++++++++++------
 include/linux/mmc/card.h |  4 ++++
 3 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 54a018d38cc9..bbc4a34dcee5 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1480,6 +1480,9 @@ static int mmc_packed_init(struct mmc_queue *mq, struct mmc_card *card)
 	if (mq->qdepth != 2)
 		return -EINVAL;
 
+	if (mqrq_cur->packed)
+		goto out;
+
 	mqrq_cur->packed = kzalloc(sizeof(struct mmc_packed), GFP_KERNEL);
 	if (!mqrq_cur->packed) {
 		pr_warn("%s: unable to allocate packed cmd for mqrq_cur\n",
@@ -1510,6 +1513,9 @@ static void mmc_packed_clean(struct mmc_queue *mq)
 	struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
 	struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
 
+	if (mq->card->mqrq_ref_cnt > 1)
+		return;
+
 	kfree(mqrq_cur->packed);
 	mqrq_cur->packed = NULL;
 	kfree(mqrq_prev->packed);
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 2570b813c25a..7c329141f4ad 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -200,10 +200,17 @@ static struct mmc_queue_req *mmc_queue_alloc_mqrqs(struct mmc_queue *mq,
 	struct mmc_queue_req *mqrq;
 	int i;
 
+	if (mq->card->mqrq) {
+		mq->card->mqrq_ref_cnt += 1;
+		return mq->card->mqrq;
+	}
+
 	mqrq = kcalloc(qdepth, sizeof(*mqrq), GFP_KERNEL);
 	if (mqrq) {
 		for (i = 0; i < mq->qdepth; i++)
 			mqrq[i].task_id = i;
+		mq->card->mqrq = mqrq;
+		mq->card->mqrq_ref_cnt = 1;
 	}
 
 	return mqrq;
@@ -214,6 +221,9 @@ static bool mmc_queue_alloc_bounce_bufs(struct mmc_queue *mq,
 {
 	int i;
 
+	if (mq->card->mqrq_ref_cnt > 1)
+		return !!mq->mqrq[0].bounce_buf;
+
 	for (i = 0; i < mq->qdepth; i++) {
 		mq->mqrq[i].bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
 		if (!mq->mqrq[i].bounce_buf)
@@ -237,6 +247,9 @@ static int mmc_queue_alloc_bounce_sgs(struct mmc_queue *mq,
 {
 	int i, ret;
 
+	if (mq->card->mqrq_ref_cnt > 1)
+		return 0;
+
 	for (i = 0; i < mq->qdepth; i++) {
 		mq->mqrq[i].sg = mmc_alloc_sg(1, &ret);
 		if (ret)
@@ -254,6 +267,9 @@ static int mmc_queue_alloc_sgs(struct mmc_queue *mq, int max_segs)
 {
 	int i, ret;
 
+	if (mq->card->mqrq_ref_cnt > 1)
+		return 0;
+
 	for (i = 0; i < mq->qdepth; i++) {
 		mq->mqrq[i].sg = mmc_alloc_sg(max_segs, &ret);
 		if (ret)
@@ -283,6 +299,19 @@ static void mmc_queue_reqs_free_bufs(struct mmc_queue *mq)
 		mmc_queue_req_free_bufs(&mq->mqrq[i]);
 }
 
+static void mmc_queue_free_mqrqs(struct mmc_queue *mq)
+{
+	if (!mq->mqrq)
+		return;
+
+	if (!--mq->card->mqrq_ref_cnt) {
+		mmc_queue_reqs_free_bufs(mq);
+		kfree(mq->card->mqrq);
+		mq->card->mqrq = NULL;
+	}
+	mq->mqrq = NULL;
+}
+
 /**
  * mmc_init_queue - initialise a queue structure.
  * @mq: mmc queue
@@ -373,9 +402,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
 	return 0;
 
  cleanup_queue:
-	mmc_queue_reqs_free_bufs(mq);
-	kfree(mq->mqrq);
-	mq->mqrq = NULL;
+	mmc_queue_free_mqrqs(mq);
 blk_cleanup:
 	blk_cleanup_queue(mq->queue);
 	return ret;
@@ -398,9 +425,7 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
 	blk_start_queue(q);
 	spin_unlock_irqrestore(q->queue_lock, flags);
 
-	mmc_queue_reqs_free_bufs(mq);
-	kfree(mq->mqrq);
-	mq->mqrq = NULL;
+	mmc_queue_free_mqrqs(mq);
 
 	mq->card = NULL;
 }
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 5ac2243bc5a9..c0f36b9e832e 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -207,6 +207,7 @@ struct sdio_cis {
 struct mmc_ios;
 struct sdio_func;
 struct sdio_func_tuple;
+struct mmc_queue_req;
 
 #define SDIO_MAX_FUNCS		7
 
@@ -308,6 +309,9 @@ struct mmc_card {
 	struct dentry		*debugfs_root;
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
 	unsigned int    nr_parts;
+
+	struct mmc_queue_req	*mqrq;		/* Shared queue structure */
+	int			mqrq_ref_cnt;	/* Shared queue ref. count */
 };
 
 /*
-- 
1.9.1


^ permalink raw reply related

* [PATCH V7 21/25] mmc: queue: Add a function to control wake-up on new requests
From: Adrian Hunter @ 2016-11-25 10:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
	Jaehoon Chung, Dong Aisheng, Das Asutosh, Zhangfei Gao,
	Dorfman Konstantin, David Griego, Sahitya Tummala, Harjani Ritesh,
	Venu Byravarasu, Linus Walleij
In-Reply-To: <1480068442-5169-1-git-send-email-adrian.hunter@intel.com>

Add a function to control wake-up on new requests. This will enable
Software Command Queuing to choose whether or not to queue new
requests immediately or wait for the current task to complete.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/card/queue.c | 16 ++++++++++++++++
 drivers/mmc/card/queue.h |  2 ++
 2 files changed, 18 insertions(+)

diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 7c329141f4ad..4847748fac2b 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -97,6 +97,7 @@ static int mmc_queue_thread(void *d)
 		cntx->is_waiting_last_req = false;
 		cntx->is_new_req = false;
 		if (!req) {
+			mq->is_new_req = false;
 			/*
 			 * Dispatch queue is empty so set flags for
 			 * mmc_request_fn() to wake us up.
@@ -147,6 +148,8 @@ static void mmc_request_fn(struct request_queue *q)
 		return;
 	}
 
+	mq->is_new_req = true;
+
 	cntx = &mq->card->host->context_info;
 
 	if (cntx->is_waiting_last_req) {
@@ -158,6 +161,19 @@ static void mmc_request_fn(struct request_queue *q)
 		wake_up_process(mq->thread);
 }
 
+void mmc_queue_set_wake(struct mmc_queue *mq, bool wake_me)
+{
+	struct mmc_context_info *cntx = &mq->card->host->context_info;
+	struct request_queue *q = mq->queue;
+
+	if (cntx->is_waiting_last_req != wake_me) {
+		spin_lock_irq(q->queue_lock);
+		cntx->is_waiting_last_req = wake_me;
+		cntx->is_new_req = wake_me && mq->is_new_req;
+		spin_unlock_irq(q->queue_lock);
+	}
+}
+
 static struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
 {
 	struct scatterlist *sg;
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index f7bc0ca0b27f..1bc3f71b9008 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -59,6 +59,7 @@ struct mmc_queue {
 	unsigned int		flags;
 #define MMC_QUEUE_SUSPENDED	(1 << 0)
 	bool			asleep;
+	bool			is_new_req;
 	struct mmc_blk_data	*blkdata;
 	struct request_queue	*queue;
 	struct mmc_queue_req	*mqrq;
@@ -83,5 +84,6 @@ extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
 extern struct mmc_queue_req *mmc_queue_req_find(struct mmc_queue *,
 						struct request *);
 extern void mmc_queue_req_free(struct mmc_queue *, struct mmc_queue_req *);
+extern void mmc_queue_set_wake(struct mmc_queue *, bool);
 
 #endif
-- 
1.9.1


^ permalink raw reply related

* [PATCH V7 22/25] mmc: block: Add Software Command Queuing
From: Adrian Hunter @ 2016-11-25 10:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
	Jaehoon Chung, Dong Aisheng, Das Asutosh, Zhangfei Gao,
	Dorfman Konstantin, David Griego, Sahitya Tummala, Harjani Ritesh,
	Venu Byravarasu, Linus Walleij
In-Reply-To: <1480068442-5169-1-git-send-email-adrian.hunter@intel.com>

eMMC Command Queuing is a feature added in version 5.1.  The card maintains
a queue of up to 32 data transfers.  Commands CMD45/CMD45 are sent to queue
up transfers in advance, and then one of the transfers is selected to
"execute" by CMD46/CMD47 at which point data transfer actually begins.

The advantage of command queuing is that the card can prepare for transfers
in advance. That makes a big difference in the case of random reads because
the card can start reading into its cache in advance.

A v5.1 host controller can manage the command queue itself, but it is also
possible for software to manage the queue using an non-v5.1 host controller
- that is what Software Command Queuing is.

Refer to the JEDEC (http://www.jedec.org/) eMMC v5.1 Specification for more
information about Command Queuing.

Two important aspects of Command Queuing that affect the implementation
are:
 - only read/write requests are queued
 - the queue must be empty to send other commands, including re-tuning

To support Software Command Queuing a separate function is provided to
issue read/write requests (i.e. mmc_swcmdq_issue_rw_rq()) and the
mmc_blk_request structure amended to cater for additional commands CMD44
and CMD45. There is a separate function (mmc_swcmdq_prep()) to prepare the
needed commands, but transfers are started by mmc_start_req() like normal.

mmc_swcmdq_issue_rw_rq() enqueues the new request and then executes tasks
until the queue is empty or mmc_swcmdq_execute() asks for a new request.
This puts mmc_swcmdq_execute() in control of the decision whether to queue
more requests or wait for the active one.

Recovery is invoked if anything goes wrong. Recovery has 2 options:
 1. Discard the queue and re-queue all requests. If that fails, fall back
    to option 2.
 2. Reset and re-queue all requests. If that fails, error out all the
    requests.
In either case, re-tuning will be done if needed after the queue becomes
empty because re-tuning is released at that point.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/card/block.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/mmc/card/queue.c |   6 +-
 drivers/mmc/card/queue.h |  11 +-
 include/linux/mmc/core.h |   1 +
 4 files changed, 606 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index bbc4a34dcee5..0e573f60e3bb 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -112,6 +112,7 @@ struct mmc_blk_data {
 #define MMC_BLK_WRITE		BIT(1)
 #define MMC_BLK_DISCARD		BIT(2)
 #define MMC_BLK_SECDISCARD	BIT(3)
+#define MMC_BLK_SWCMDQ		BIT(4)
 
 	/*
 	 * Only set in main mmc_blk_data associated
@@ -2038,7 +2039,584 @@ static void mmc_blk_revert_packed_req(struct mmc_queue *mq,
 	mmc_blk_clear_packed(mq_rq);
 }
 
-static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+static enum mmc_blk_status mmc_swcmdq_err_check(struct mmc_card *card,
+						struct mmc_async_req *areq)
+{
+	struct mmc_queue_req *mqrq = container_of(areq, struct mmc_queue_req,
+						  mmc_active);
+	struct mmc_blk_request *brq = &mqrq->brq;
+	struct request *req = mqrq->req;
+	int err;
+
+	err = brq->data.error;
+	/* In the case of data errors, send stop */
+	if (err)
+		mmc_wait_for_cmd(card->host, &brq->stop, 0);
+	else
+		err = brq->cmd.error;
+
+	/* In the case of CRC errors when re-tuning is needed, retry */
+	if (err == -EILSEQ && card->host->need_retune)
+		return MMC_BLK_RETRY;
+
+	/* For other errors abort */
+	if (err)
+		return MMC_BLK_ABORT;
+
+	if (blk_rq_bytes(req) != brq->data.bytes_xfered)
+		return MMC_BLK_PARTIAL;
+
+	return MMC_BLK_SUCCESS;
+}
+
+static void mmc_swcmdq_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
+{
+	struct mmc_blk_data *md = mq->blkdata;
+	struct mmc_card *card = md->queue.card;
+	struct mmc_blk_request *brq = &mqrq->brq;
+	struct request *req = mqrq->req;
+	bool do_data_tag;
+
+	/*
+	 * Reliable writes are used to implement Forced Unit Access and
+	 * are supported only on MMCs.
+	 */
+	bool do_rel_wr = (req->cmd_flags & REQ_FUA) &&
+		(rq_data_dir(req) == WRITE) &&
+		(md->flags & MMC_BLK_REL_WR);
+
+	memset(brq, 0, sizeof(struct mmc_blk_request));
+	brq->mrq.cmd = &brq->cmd;
+	brq->mrq.data = &brq->data;
+	brq->mrq.cap_cmd_during_tfr = true;
+
+	if (rq_data_dir(req) == READ) {
+		brq->cmd.opcode = MMC_EXECUTE_READ_TASK;
+		brq->data.flags = MMC_DATA_READ;
+		brq->stop.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	} else {
+		brq->cmd.opcode = MMC_EXECUTE_WRITE_TASK;
+		brq->data.flags = MMC_DATA_WRITE;
+		brq->stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+	}
+	brq->cmd.arg = mqrq->task_id << 16;
+	brq->cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	brq->data.blksz = 512;
+	brq->data.blocks = blk_rq_sectors(req);
+
+	brq->stop.opcode = MMC_STOP_TRANSMISSION;
+	brq->stop.arg = 0;
+
+	/*
+	 * The block layer doesn't support all sector count
+	 * restrictions, so we need to be prepared for too big
+	 * requests.
+	 */
+	if (brq->data.blocks > card->host->max_blk_count)
+		brq->data.blocks = card->host->max_blk_count;
+
+	if (do_rel_wr)
+		mmc_apply_rel_rw(brq, card, req);
+
+	/*
+	 * Data tag is used only during writing meta data to speed
+	 * up write and any subsequent read of this meta data
+	 */
+	do_data_tag = (card->ext_csd.data_tag_unit_size) &&
+		(req->cmd_flags & REQ_META) &&
+		(rq_data_dir(req) == WRITE) &&
+		((brq->data.blocks * brq->data.blksz) >=
+		 card->ext_csd.data_tag_unit_size);
+
+	brq->cmd44.opcode = MMC_QUE_TASK_PARAMS;
+	brq->cmd44.arg = brq->data.blocks |
+			 (do_rel_wr ? (1 << 31) : 0) |
+			 ((rq_data_dir(req) == READ) ? (1 << 30) : 0) |
+			 (do_data_tag ? (1 << 29) : 0) |
+			 mqrq->task_id << 16;
+	brq->cmd44.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	brq->cmd45.opcode = MMC_QUE_TASK_ADDR;
+	brq->cmd45.arg = blk_rq_pos(req);
+
+	mmc_set_data_timeout(&brq->data, card);
+
+	brq->data.sg = mqrq->sg;
+	brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
+
+	/*
+	 * Adjust the sg list so it is the same size as the
+	 * request.
+	 */
+	if (brq->data.blocks != blk_rq_sectors(req)) {
+		int i, data_size = brq->data.blocks << 9;
+		struct scatterlist *sg;
+
+		for_each_sg(brq->data.sg, sg, brq->data.sg_len, i) {
+			data_size -= sg->length;
+			if (data_size <= 0) {
+				sg->length += data_size;
+				i++;
+				break;
+			}
+		}
+		brq->data.sg_len = i;
+	}
+
+	mqrq->mmc_active.mrq = &brq->mrq;
+	mqrq->mmc_active.err_check = mmc_swcmdq_err_check;
+
+	mmc_queue_bounce_pre(mqrq);
+}
+
+static int mmc_swcmdq_blk_err(struct mmc_card *card, int err)
+{
+	/* Re-try after CRC errors when re-tuning is needed */
+	if (err == -EILSEQ && card->host->need_retune)
+		return MMC_BLK_RETRY;
+
+	if (err)
+		return MMC_BLK_ABORT;
+
+	return 0;
+}
+
+#define SWCMDQ_ENQUEUE_ERR (	\
+	R1_OUT_OF_RANGE |	\
+	R1_ADDRESS_ERROR |	\
+	R1_BLOCK_LEN_ERROR |	\
+	R1_WP_VIOLATION |	\
+	R1_CC_ERROR |		\
+	R1_ERROR |		\
+	R1_COM_CRC_ERROR |	\
+	R1_ILLEGAL_COMMAND)
+
+static int __mmc_swcmdq_enqueue(struct mmc_queue *mq,
+				struct mmc_queue_req *mqrq)
+{
+	struct mmc_card *card = mq->card;
+	int err;
+
+	mmc_swcmdq_prep(mq, mqrq);
+
+	err = mmc_wait_for_cmd(card->host, &mqrq->brq.cmd44, 0);
+	if (err)
+		goto out;
+
+	err = mmc_wait_for_cmd(card->host, &mqrq->brq.cmd45, 0);
+	if (err)
+		goto out;
+
+	/*
+	 * Don't assume the task is queued if there are any error bits set in
+	 * the response.
+	 */
+	if (mqrq->brq.cmd45.resp[0] & SWCMDQ_ENQUEUE_ERR)
+		return MMC_BLK_ABORT;
+out:
+	return mmc_swcmdq_blk_err(card, err);
+}
+
+static int mmc_swcmdq_enqueue(struct mmc_queue *mq, struct request *req)
+{
+	struct mmc_queue_req *mqrq;
+
+	mqrq = mmc_queue_req_find(mq, req);
+	if (!mqrq) {
+		WARN_ON(1);
+		mmc_blk_requeue(mq->queue, req);
+		return 0;
+	}
+
+	/* Need to hold re-tuning so long as the queue is not empty */
+	if (mq->qcnt == 1)
+		mmc_retune_hold(mq->card->host);
+
+	return __mmc_swcmdq_enqueue(mq, mqrq);
+}
+
+static struct mmc_async_req *mmc_swcmdq_next(struct mmc_queue *mq)
+{
+	int i = __ffs(mq->qsr);
+
+	__clear_bit(i, &mq->qsr);
+
+	if (i >= mq->qdepth)
+		return NULL;
+
+	return &mq->mqrq[i].mmc_active;
+}
+
+static int mmc_get_qsr(struct mmc_card *card, u32 *qsr)
+{
+	struct mmc_command cmd = {0};
+	int err, retries = 3;
+
+	cmd.opcode = MMC_SEND_STATUS;
+	cmd.arg = card->rca << 16 | 1 << 15;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	err = mmc_wait_for_cmd(card->host, &cmd, retries);
+	if (err)
+		return err;
+
+	*qsr = cmd.resp[0];
+
+	return 0;
+}
+
+static int mmc_await_qsr(struct mmc_card *card, u32 *qsr)
+{
+	unsigned long timeout;
+	u32 status = 0;
+	int err;
+
+	timeout = jiffies + msecs_to_jiffies(10 * 1000);
+	while (!status) {
+		err = mmc_get_qsr(card, &status);
+		if (err)
+			return err;
+		if (time_after(jiffies, timeout)) {
+			pr_err("%s: Card stuck with queued tasks\n",
+			       mmc_hostname(card->host));
+			return -ETIMEDOUT;
+		}
+	}
+
+	*qsr = status;
+
+	return 0;
+}
+
+static int mmc_swcmdq_await_qsr(struct mmc_queue *mq, struct mmc_card *card,
+				bool wait)
+{
+	struct mmc_queue_req *mqrq;
+	u32 qsr;
+	int err;
+
+	if (wait)
+		err = mmc_await_qsr(card, &qsr);
+	else
+		err = mmc_get_qsr(card, &qsr);
+	if (err)
+		goto out_err;
+
+	mq->qsr = qsr;
+
+	if (card->host->areq) {
+		/*
+		 * The active request remains in the QSR until completed. Remove
+		 * it so that mq->qsr only contains ones that are ready but not
+		 * executed.
+		 */
+		mqrq = container_of(card->host->areq, struct mmc_queue_req,
+				    mmc_active);
+		__clear_bit(mqrq->task_id, &mq->qsr);
+	}
+
+	if (mq->qsr)
+		mq->qsr_err = false;
+out_err:
+	if (err) {
+		/* Don't repeatedly retry if no progress is made */
+		if (mq->qsr_err)
+			return MMC_BLK_ABORT;
+		mq->qsr_err = true;
+	}
+
+	return mmc_swcmdq_blk_err(card, err);
+}
+
+static int mmc_swcmdq_execute(struct mmc_queue *mq, bool flush, bool requeuing,
+			      bool new_req)
+{
+	struct mmc_card *card = mq->card;
+	struct mmc_async_req *next = NULL, *prev;
+	struct mmc_blk_request *brq;
+	struct mmc_queue_req *mqrq;
+	enum mmc_blk_status status;
+	struct request *req;
+	int active = card->host->areq ? 1 : 0;
+	int ret;
+
+	if (mq->prepared_areq) {
+		/*
+		 * A request that has been prepared before (i.e. passed to
+		 * mmc_start_req()) but not started because another new request
+		 * turned up.
+		 */
+		next = mq->prepared_areq;
+	} else if (requeuing) {
+		/* Just finish the active request */
+		next = NULL;
+	} else if (mq->qsr) {
+		/* Get the next task from the Queue Status Register */
+		next = mmc_swcmdq_next(mq);
+	} else if (mq->qcnt > active) {
+		/*
+		 * There are queued tasks so read the Queue Status Register to
+		 * see if any are ready. Wait for a ready task only if there is
+		 * no active request and no new request.
+		 */
+		ret = mmc_swcmdq_await_qsr(mq, card, !active && !new_req);
+		if (ret)
+			return ret;
+		if (mq->qsr)
+			next = mmc_swcmdq_next(mq);
+	}
+
+	if (next) {
+		/*
+		 * Don't wake for a new request when waiting for the active
+		 * request if there is another request ready to start.
+		 */
+		if (active)
+			mmc_queue_set_wake(mq, false);
+	} else {
+		if (!active)
+			return 0;
+		/*
+		 * Don't wake for a new request when flushing or the queue is
+		 * full.
+		 */
+		if (flush || mq->qcnt == mq->qdepth)
+			mmc_queue_set_wake(mq, false);
+		else
+			mmc_queue_set_wake(mq, true);
+	}
+
+	prev = mmc_start_req(card->host, next, &status);
+
+	if (status == MMC_BLK_NEW_REQUEST) {
+		mq->prepared_areq = next;
+		return status;
+	}
+
+	mq->prepared_areq = NULL;
+
+	if (!prev)
+		return 0;
+
+	mqrq = container_of(prev, struct mmc_queue_req, mmc_active);
+	brq = &mqrq->brq;
+	req = mqrq->req;
+
+	mmc_queue_bounce_post(mqrq);
+
+	switch (status) {
+	case MMC_BLK_SUCCESS:
+	case MMC_BLK_PARTIAL:
+	case MMC_BLK_SUCCESS_ERR:
+		mmc_blk_reset_success(mq->blkdata, MMC_BLK_SWCMDQ);
+		ret = blk_end_request(req, 0, brq->data.bytes_xfered);
+		if (ret) {
+			if (!requeuing)
+				return __mmc_swcmdq_enqueue(mq, mqrq);
+			return 0;
+		}
+		break;
+	case MMC_BLK_NEW_REQUEST:
+		return status;
+	default:
+		if (mqrq->retry_cnt++) {
+			blk_end_request_all(req, -EIO);
+			break;
+		}
+		return status;
+	}
+
+	mmc_queue_req_free(mq, mqrq);
+
+	/* Release re-tuning when queue is empty */
+	if (!mq->qcnt)
+		mmc_retune_release(card->host);
+
+	return 0;
+}
+
+static enum mmc_blk_status mmc_swcmdq_requeue_check(struct mmc_card *card,
+				    struct mmc_async_req *areq)
+{
+	enum mmc_blk_status ret = mmc_swcmdq_err_check(card, areq);
+
+	/*
+	 * In the case of success, prevent mmc_start_req() from starting
+	 * another request by returning MMC_BLK_SUCCESS_ERR.
+	 */
+	return ret == MMC_BLK_SUCCESS ? MMC_BLK_SUCCESS_ERR : ret;
+}
+
+static int mmc_swcmdq_await_active(struct mmc_queue *mq)
+{
+	struct mmc_async_req *areq = mq->card->host->areq;
+	int err;
+
+	if (!areq)
+		return 0;
+
+	areq->err_check = mmc_swcmdq_requeue_check;
+
+	err = mmc_swcmdq_execute(mq, true, true, false);
+
+	/* The request will be requeued anyway, so ignore 'retry' */
+	if (err == MMC_BLK_RETRY)
+		err = 0;
+
+	return err;
+}
+
+static int mmc_swcmdq_discard_queue(struct mmc_queue *mq)
+{
+	struct mmc_command cmd = {0};
+
+	if (!mq->qcnt)
+		return 0;
+
+	mq->qsr = 0;
+
+	cmd.opcode = MMC_CMDQ_TASK_MGMT;
+	cmd.arg = 1; /* Discard entire queue */
+	cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+	/* This is for recovery and the response is not needed, so ignore CRC */
+	cmd.flags &= ~MMC_RSP_CRC;
+
+	return mmc_wait_for_cmd(mq->card->host, &cmd, 0);
+}
+
+static int __mmc_swcmdq_requeue(struct mmc_queue *mq)
+{
+	unsigned long i, qslots = mq->qslots;
+	int err;
+
+	if (qslots) {
+		/* Cause re-tuning before next command, if needed */
+		mmc_retune_release(mq->card->host);
+		mmc_retune_hold(mq->card->host);
+	}
+
+	while (qslots) {
+		i = __ffs(qslots);
+		err = __mmc_swcmdq_enqueue(mq, &mq->mqrq[i]);
+		if (err)
+			return err;
+		__clear_bit(i, &qslots);
+	}
+
+	return 0;
+}
+
+static void __mmc_swcmdq_error_out(struct mmc_queue *mq)
+{
+	unsigned long i, qslots = mq->qslots;
+	struct request *req;
+
+	if (qslots)
+		mmc_retune_release(mq->card->host);
+
+	while (qslots) {
+		i = __ffs(qslots);
+		req = mq->mqrq[i].req;
+		blk_end_request_all(req, -EIO);
+		mq->mqrq[i].req = NULL;
+		__clear_bit(i, &qslots);
+	}
+
+	mq->qslots = 0;
+	mq->qcnt = 0;
+}
+
+static int mmc_swcmdq_requeue(struct mmc_queue *mq)
+{
+	int err;
+
+	/* Wait for active request */
+	err = mmc_swcmdq_await_active(mq);
+	if (err)
+		return err;
+
+	err = mmc_swcmdq_discard_queue(mq);
+	if (err)
+		return err;
+
+	return __mmc_swcmdq_requeue(mq);
+}
+
+static void mmc_swcmdq_reset(struct mmc_queue *mq)
+{
+	/* Wait for active request ignoring errors */
+	mmc_swcmdq_await_active(mq);
+
+	/* Ensure the queue is discarded */
+	mmc_swcmdq_discard_queue(mq);
+
+	/* Reset and requeue else error out all requests */
+	if (mmc_blk_reset(mq->blkdata, mq->card->host, MMC_BLK_SWCMDQ) ||
+	    __mmc_swcmdq_requeue(mq))
+		__mmc_swcmdq_error_out(mq);
+}
+
+/*
+ * Recovery has 2 options:
+ * 1. Discard the queue and re-queue all requests. If that fails, fall back to
+ *    option 2.
+ * 2. Reset and re-queue all requests. If that fails, error out all the
+ *    requests.
+ * In either case, re-tuning will be done if needed after the queue becomes
+ * empty because re-tuning is released at that point.
+ */
+static void mmc_swcmdq_recovery(struct mmc_queue *mq, int err)
+{
+	switch (err) {
+	case MMC_BLK_RETRY:
+		err = mmc_swcmdq_requeue(mq);
+		if (!err)
+			break;
+		/* Fall through */
+	default:
+		mmc_swcmdq_reset(mq);
+	}
+}
+
+static int mmc_swcmdq_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+{
+	struct mmc_context_info *cntx = &mq->card->host->context_info;
+	bool flush = !req && !cntx->is_waiting_last_req;
+	int err;
+
+	/* Enqueue new requests */
+	if (req) {
+		err = mmc_swcmdq_enqueue(mq, req);
+		if (err)
+			mmc_swcmdq_recovery(mq, err);
+	}
+
+	/*
+	 * Keep executing queued requests until the queue is empty or
+	 * mmc_swcmdq_execute() asks for new requests by returning
+	 * MMC_BLK_NEW_REQUEST.
+	 */
+	while (mq->qcnt) {
+		/*
+		 * Re-tuning can only be done when the queue is empty. Recovery
+		 * for MMC_BLK_RETRY will discard the queue and re-queue all
+		 * requests. At the point the queue is empty, re-tuning is
+		 * released and will be done automatically before the next
+		 * mmc_request.
+		 */
+		if (mq->card->host->need_retune)
+			mmc_swcmdq_recovery(mq, MMC_BLK_RETRY);
+		err = mmc_swcmdq_execute(mq, flush, false, !!req);
+		if (err == MMC_BLK_NEW_REQUEST)
+			return 0;
+		if (err)
+			mmc_swcmdq_recovery(mq, err);
+	}
+
+	return 0;
+}
+
+static int __mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 {
 	struct mmc_blk_data *md = mq->blkdata;
 	struct mmc_card *card = md->queue.card;
@@ -2244,6 +2822,17 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 	return 0;
 }
 
+static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+{
+	struct mmc_blk_data *md = mq->blkdata;
+	struct mmc_card *card = md->queue.card;
+
+	if (card->ext_csd.cmdq_en)
+		return mmc_swcmdq_issue_rw_rq(mq, req);
+	else
+		return __mmc_blk_issue_rw_rq(mq, req);
+}
+
 int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 {
 	int ret;
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 4847748fac2b..b292109c82ea 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -64,6 +64,7 @@ struct mmc_queue_req *mmc_queue_req_find(struct mmc_queue *mq,
 	mqrq->req = req;
 	mq->qcnt += 1;
 	__set_bit(mqrq->task_id, &mq->qslots);
+	mqrq->retry_cnt = 0;
 
 	return mqrq;
 }
@@ -353,7 +354,10 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
 	if (!mq->queue)
 		return -ENOMEM;
 
-	mq->qdepth = 2;
+	if (card->ext_csd.cmdq_en)
+		mq->qdepth = card->ext_csd.cmdq_depth;
+	else
+		mq->qdepth = 2;
 	mq->mqrq = mmc_queue_alloc_mqrqs(mq, mq->qdepth);
 	if (!mq->mqrq)
 		goto blk_cleanup;
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 1bc3f71b9008..a2005153b315 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -15,9 +15,13 @@ static inline bool mmc_req_is_special(struct request *req)
 
 struct mmc_blk_request {
 	struct mmc_request	mrq;
-	struct mmc_command	sbc;
+	union {
+		struct mmc_command	sbc;
+		struct mmc_command	cmd44;
+	};
 	struct mmc_command	cmd;
 	struct mmc_command	stop;
+	struct mmc_command	cmd45;
 	struct mmc_data		data;
 	int			retune_retry_done;
 };
@@ -50,6 +54,7 @@ struct mmc_queue_req {
 	enum mmc_packed_type	cmd_type;
 	struct mmc_packed	*packed;
 	int			task_id;
+	unsigned int		retry_cnt;
 };
 
 struct mmc_queue {
@@ -66,6 +71,10 @@ struct mmc_queue {
 	int			qdepth;
 	int			qcnt;
 	unsigned long		qslots;
+	/* Following are defined for Software Command Queuing */
+	unsigned long		qsr;
+	struct mmc_async_req	*prepared_areq;
+	bool			qsr_err;
 };
 
 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 d8f46e1ae7f2..03a013c83e31 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -25,6 +25,7 @@ enum mmc_blk_status {
 	MMC_BLK_ECC_ERR,
 	MMC_BLK_NOMEDIUM,
 	MMC_BLK_NEW_REQUEST,
+	MMC_BLK_SUCCESS_ERR, /* Success but prevent starting another request */
 };
 
 struct mmc_command {
-- 
1.9.1


^ permalink raw reply related

* [PATCH V7 23/25] mmc: mmc: Enable Software Command Queuing
From: Adrian Hunter @ 2016-11-25 10:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
	Jaehoon Chung, Dong Aisheng, Das Asutosh, Zhangfei Gao,
	Dorfman Konstantin, David Griego, Sahitya Tummala, Harjani Ritesh,
	Venu Byravarasu, Linus Walleij
In-Reply-To: <1480068442-5169-1-git-send-email-adrian.hunter@intel.com>

Enable the Command Queue if the host controller supports Software Command
Queuing. It is not compatible with Packed Commands, so do not enable that
at the same time.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/core/mmc.c   | 17 ++++++++++++++++-
 include/linux/mmc/host.h |  1 +
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e310a60ef859..6a31a7a614be 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1754,6 +1754,20 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		}
 	}
 
+	/* Enable Command Queue if supported */
+	card->ext_csd.cmdq_en = false;
+	if (card->ext_csd.cmdq_support && host->caps & MMC_CAP_SWCMDQ) {
+		err = mmc_cmdq_enable(card);
+		if (err && err != -EBADMSG)
+			goto free_card;
+		if (err) {
+			pr_warn("%s: Enabling CMDQ failed\n",
+				mmc_hostname(card->host));
+			card->ext_csd.cmdq_support = false;
+			card->ext_csd.cmdq_depth = 0;
+			err = 0;
+		}
+	}
 	/*
 	 * In some cases (e.g. RPMB or mmc_test), the Command Queue must be
 	 * disabled for a time, so a flag is needed to indicate to re-enable the
@@ -1767,7 +1781,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	if (card->ext_csd.max_packed_writes >= 3 &&
 	    card->ext_csd.max_packed_reads >= 5 &&
-	    host->caps2 & MMC_CAP2_PACKED_CMD) {
+	    host->caps2 & MMC_CAP2_PACKED_CMD &&
+	    !card->ext_csd.cmdq_en) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				EXT_CSD_EXP_EVENTS_CTRL,
 				EXT_CSD_PACKED_EVENT_EN,
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index fa44aa93505a..ea514470c0c1 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -279,6 +279,7 @@ struct mmc_host {
 #define MMC_CAP_DRIVER_TYPE_A	(1 << 23)	/* Host supports Driver Type A */
 #define MMC_CAP_DRIVER_TYPE_C	(1 << 24)	/* Host supports Driver Type C */
 #define MMC_CAP_DRIVER_TYPE_D	(1 << 25)	/* Host supports Driver Type D */
+#define MMC_CAP_SWCMDQ		(1 << 28)	/* Software Command Queue */
 #define MMC_CAP_CMD_DURING_TFR	(1 << 29)	/* Commands during data transfer */
 #define MMC_CAP_CMD23		(1 << 30)	/* CMD23 supported. */
 #define MMC_CAP_HW_RESET	(1 << 31)	/* Hardware reset */
-- 
1.9.1


^ permalink raw reply related

* [PATCH V7 24/25] mmc: sdhci-pci: Enable Software Command Queuing for some Intel controllers
From: Adrian Hunter @ 2016-11-25 10:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
	Jaehoon Chung, Dong Aisheng, Das Asutosh, Zhangfei Gao,
	Dorfman Konstantin, David Griego, Sahitya Tummala, Harjani Ritesh,
	Venu Byravarasu, Linus Walleij
In-Reply-To: <1480068442-5169-1-git-send-email-adrian.hunter@intel.com>

Set MMC_CAP_SWCMDQ for Intel BYT and related eMMC host controllers.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci-pci-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 2d20fb60ce83..6c643b09f358 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -362,7 +362,7 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
 {
 	slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
 				 MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
-				 MMC_CAP_CMD_DURING_TFR |
+				 MMC_CAP_CMD_DURING_TFR | MMC_CAP_SWCMDQ |
 				 MMC_CAP_WAIT_WHILE_BUSY;
 	slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
 	slot->hw_reset = sdhci_pci_int_hw_reset;
-- 
1.9.1


^ permalink raw reply related

* [PATCH V7 25/25] mmc: sdhci-acpi: Enable Software Command Queuing for some Intel controllers
From: Adrian Hunter @ 2016-11-25 10:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
	Jaehoon Chung, Dong Aisheng, Das Asutosh, Zhangfei Gao,
	Dorfman Konstantin, David Griego, Sahitya Tummala, Harjani Ritesh,
	Venu Byravarasu, Linus Walleij
In-Reply-To: <1480068442-5169-1-git-send-email-adrian.hunter@intel.com>

Set MMC_CAP_SWCMDQ for Intel BYT and related eMMC host controllers.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci-acpi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index 81d4dc034793..95fc4de05c54 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -274,7 +274,7 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev,
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
 	.chip    = &sdhci_acpi_chip_int,
 	.caps    = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
-		   MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
+		   MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | MMC_CAP_SWCMDQ |
 		   MMC_CAP_CMD_DURING_TFR | MMC_CAP_WAIT_WHILE_BUSY,
 	.caps2   = MMC_CAP2_HC_ERASE_SZ,
 	.flags   = SDHCI_ACPI_RUNTIME_PM,
-- 
1.9.1


^ permalink raw reply related

* Re: [PATCH 6/10] mmc: sdhci-xenon: Add Marvell Xenon SDHC core functionality
From: Ulf Hansson @ 2016-11-25 13:01 UTC (permalink / raw)
  To: Ziji Hu
  Cc: Adrian Hunter, Gregory CLEMENT,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Jason Cooper,
	Andrew Lunn, Sebastian Hesselbarth, Rob Herring,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Thomas Petazzoni,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	Jimmy Xu, Jisheng Zhang, Nadav Haklai, Ryan Gao, Doug Jones,
	Victor Gu, Wei(SOCP) Liu, Wilson Ding
In-Reply-To: <76ce72f8-4b86-3b83-544f-b9a7ef871393-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>

[...]

>>
>> Moreover, we have ->enable_sdio_irq() ops that deals with this.
>>
>    Yes. I mean the SDIO irqs on DAT1 line in async mode.
>    This field enables our host to recognize the async SDIO irq from SDIO device.
>    It controls our host side behavior, other than the SDIO device.
>
>    I think ->enable_sdio_irq() is a more reasonable place to put this workraound.
>    I will export sdhci_enable_sdio_irq() and implement out host own
>    enable_sdio_irq() calling sdhci_enable_sdio)irq() plus this workaround.
>    Does it sound reasonable to you?

Yes.

[...]

>>
>> Got it. Although I think we can cope with that fine just by using the
>> different SD/eMMC speed modes settings defined in DT (or from the
>> SDHCI caps register)
>>
>     In my very opinion, I'm not sure if there is any corner case that driver cannot
>     determine the eMMC card type from DT and SDHC caps.
>
>>>    Unfortunately, MMC driver cannot determine the card type yet when eMMC voltage
>>>    setting should be executed.
>>>    Thus an flag is required here to tell driver to execute eMMC voltage setting.
>>>
>>>    Besides, additional eMMC specific settings might be implemented in future, besides
>>>    voltage setting. Most of them should be completed before MMC driver recognizes the
>>>    card type. Thus I have to keep this flag to indicate current SDHC is for eMMC.
>>
>> I doubt you will need a generic "eMMC" flag, but let's see when we go forward.
>>
>> Currently it's clear you don't need such a flag, so I will submit a
>> change adding a DT binding for "mmc-ddr-3_3v" then we can take it from
>> there, to see if it suits your needs.
>>
>
>     Actually, our eMMC is usually fixed as 1.8V.
>
>     The pair "no-sd" + "no-sdio" can provide the similar information.
>     But I'm not sure if it is proper to use those two property in such a way.

Well, potentially those could be used like that.

The point of why we added them was to allow hosts that don't support
the different protocols (which is somewhat true for your case, because
of signal voltage issues) to tell the mmc core about it. That instead
of having to all kind of crazy hacks in the drives, that in then
didn't work out so well.

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 6/10] mmc: sdhci-xenon: Add Marvell Xenon SDHC core functionality
From: Ulf Hansson @ 2016-11-25 13:06 UTC (permalink / raw)
  To: Ziji Hu
  Cc: Adrian Hunter, Gregory CLEMENT, linux-mmc@vger.kernel.org,
	Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Rob Herring,
	devicetree@vger.kernel.org, Thomas Petazzoni,
	linux-arm-kernel@lists.infradead.org, Jimmy Xu, Jisheng Zhang,
	Nadav Haklai, Ryan Gao, Doug Jones, Victor Gu, Wei(SOCP) Liu,
	Wilson Ding
In-Reply-To: <07e71ce4-a78e-750c-6325-0a88891519d5@marvell.com>

[...]

>>>>>> +
>>>>>> +       /*
>>>>>> +        * Xenon Specific property:
>>>>>> +        * emmc: explicitly indicate whether this slot is for eMMC
>>>>>> +        * slotno: the index of slot. Refer to SDHC_SYS_CFG_INFO register
>>>>>> +        * tun-count: the interval between re-tuning
>>>>>> +        * PHY type: "sdhc phy", "emmc phy 5.0" or "emmc phy 5.1"
>>>>>> +        */
>>>>>> +       if (of_property_read_bool(np, "marvell,xenon-emmc"))
>>>>>> +               priv->emmc_slot = true;
>>>>>
>>>>> So, you need this because of the eMMC voltage switch behaviour, right?
>>>>>
>>>>> Then I would rather like to describe this a generic DT bindings for
>>>>> the eMMC voltage level support. There have acutally been some earlier
>>>>> discussions for this, but we haven't yet made some changes.
>>>>>
>>>>> I think what is missing is a mmc-ddr-3_3v DT binding, which when set,
>>>>> allows the host driver to accept I/O voltage switches to 3.3V. If not
>>>>> supported the  ->start_signal_voltage_switch() ops may return -EINVAL.
>>>>> This would inform the mmc core to move on to the next supported
>>>>> voltage level. There might be some minor additional changes to the mmc
>>>>> card initialization sequence, but those should be simple.
>>>>>
>>>>> I can help out to look into this, unless you want to do it yourself of course!?
>>>>>
>>>>    Yes. One of the reasons is to provide eMMC specific voltage setting.
>>>>    But in my very own opinion, it should be irrelevant to voltage level.
>>>>    The eMMC voltage setting on our SDHC is different from SD/SDIO voltage switch.
>>>>    It will become more complex with different SOC implementation details.
>>>
>>> Got it. Although I think we can cope with that fine just by using the
>>> different SD/eMMC speed modes settings defined in DT (or from the
>>> SDHCI caps register)
>>>
>>     In my very opinion, I'm not sure if there is any corner case that driver cannot
>>     determine the eMMC card type from DT and SDHC caps.
>>
>>>>    Unfortunately, MMC driver cannot determine the card type yet when eMMC voltage
>>>>    setting should be executed.
>>>>    Thus an flag is required here to tell driver to execute eMMC voltage setting.
>>>>
>>>>    Besides, additional eMMC specific settings might be implemented in future, besides
>>>>    voltage setting. Most of them should be completed before MMC driver recognizes the
>>>>    card type. Thus I have to keep this flag to indicate current SDHC is for eMMC.
>>>
>>> I doubt you will need a generic "eMMC" flag, but let's see when we go forward.
>>>
>>> Currently it's clear you don't need such a flag, so I will submit a
>>> change adding a DT binding for "mmc-ddr-3_3v" then we can take it from
>>> there, to see if it suits your needs.
>>>
>
>     Another reason for a special "xenon-emmc" property is that our host IP usually can
>     support both eMMC and SD. Whether a host is used as eMMC or SD depends on the
>     final implementation of the actual product.
>     Thus our host driver needs to know whether current SDHC is fixed as eMMC or SD.
>     So far, It can only get the information from DT.

As a matter of fact for mounted non-removable cards, such as eMMC, we
already have the option to describe some of their characteristics in
DT. Perhaps that's what you need?

Please have a look at:
Documentation/devicetree/bindings/mmc/mmc-card.txt

>
>     After out host driver get the card type information from DT, it can prepare eMMC
>     specific voltage, set eMMC specific mmc->caps/caps2 flags and do other
>     vendor specific init, before card init procedure.
>     Otherwise, our host driver has to wait until card type is determined in mmc_rescan().
>
>     A generic "eMMC" flag is unnecessary. I just require a private property,
>     which is only used in our host driver and DT.
>
>     Thank you.
>
> Best regards,
> Hu Ziji
>
>>
>>     Actually, our eMMC is usually fixed as 1.8V.
>>
>>     The pair "no-sd" + "no-sdio" can provide the similar information.
>>     But I'm not sure if it is proper to use those two property in such a way.
>>
>>     Thank you.
>>
>> Best regards
>> Hu Ziji
>>
>>> [...]
>>>
>>> Kind regards
>>> Uffe
>>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>

Kind regards
Uffe

^ permalink raw reply

* Re: [PATCH v3] mmc: block: delete packed command support
From: Ulf Hansson @ 2016-11-25 13:30 UTC (permalink / raw)
  To: Linus Walleij
  Cc: linux-mmc@vger.kernel.org, Chunyan Zhang, Baolin Wang,
	Namjae Jeon, Maya Erez
In-Reply-To: <1480066500-4983-1-git-send-email-linus.walleij@linaro.org>

On 25 November 2016 at 10:35, Linus Walleij <linus.walleij@linaro.org> wrote:
> I've had it with this code now.
>
> The packed command support is a complex hurdle in the MMC/SD block
> layer, around 500+ lines of code which was introduced in 2013 in
> commits
>
> ce39f9d17c14 ("mmc: support packed write command for eMMC4.5 devices")
> abd9ac144947 ("mmc: add packed command feature of eMMC4.5")
>
> ...and since then it has been rotting. The original author of the
> code has disappeared from the community and the mail address is
> bouncing.
>
> For the code to be exercised the host must flag that it supports
> packed commands, so in mmc_blk_prep_packed_list() which is called for
> every single request, the following construction appears:
>
> u8 max_packed_rw = 0;
>
> if ((rq_data_dir(cur) == WRITE) &&
>     mmc_host_packed_wr(card->host))
>         max_packed_rw = card->ext_csd.max_packed_writes;
>
> if (max_packed_rw == 0)
>     goto no_packed;
>
> This has the following logical deductions:
>
> - Only WRITE commands can really be packed, so the solution is
>   only half-done: we support packed WRITE but not packed READ.
>   The packed command support has not been finalized by supporting
>   reads in three years!
>
> - mmc_host_packed_wr() is just a static inline that checks
>   host->caps2 & MMC_CAP2_PACKED_WR. The problem with this is
>   that NO upstream host sets this capability flag! No driver
>   in the kernel is using it, and we can't test it. Packed
>   command may be supported in out-of-tree code, but I doubt
>   it. I doubt that the code is even working anymore due to
>   other refactorings in the MMC block layer, who would
>   notice if patches affecting it broke packed commands?
>   No one.
>
> - There is no Device Tree binding or code to mark a host as
>   supporting packed read or write commands, just this flag
>   in caps2, so for sure there are not any DT systems using
>   it either.
>
> It has other problems as well: mmc_blk_prep_packed_list() is
> speculatively picking requests out of the request queue with
> blk_fetch_request() making the MMC/SD stack harder to convert
> to the multiqueue block layer. By this we get rid of an
> obstacle.
>
> The way I see it this is just cruft littering the MMC/SD
> stack.
>
> Cc: Namjae Jeon <namjae.jeon@samsung.com>
> Cc: Maya Erez <qca_merez@qca.qualcomm.com>
> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

Thanks, applied for next!

Kind regards
Uffe


> ---
> ChangeLog v2->v3:
> - Remove unused "reqs" variable, found by the build robot.
> ChangeLog v1->v2:
> - Rebased on Ulf's next branch
> - Added Jaehoon's ACK
> ---
>  drivers/mmc/card/block.c | 483 ++---------------------------------------------
>  drivers/mmc/card/queue.c |  53 +-----
>  drivers/mmc/card/queue.h |  19 --
>  include/linux/mmc/host.h |   5 -
>  4 files changed, 20 insertions(+), 540 deletions(-)
>
> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
> index 6618126fcb9f..86ff28f84698 100644
> --- a/drivers/mmc/card/block.c
> +++ b/drivers/mmc/card/block.c
> @@ -66,9 +66,6 @@ MODULE_ALIAS("mmc:block");
>
>  #define mmc_req_rel_wr(req)    ((req->cmd_flags & REQ_FUA) && \
>                                   (rq_data_dir(req) == WRITE))
> -#define PACKED_CMD_VER 0x01
> -#define PACKED_CMD_WR  0x02
> -
>  static DEFINE_MUTEX(block_mutex);
>
>  /*
> @@ -102,7 +99,6 @@ struct mmc_blk_data {
>         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;
> @@ -126,12 +122,6 @@ struct mmc_blk_data {
>
>  static DEFINE_MUTEX(open_lock);
>
> -enum {
> -       MMC_PACKED_NR_IDX = -1,
> -       MMC_PACKED_NR_ZERO,
> -       MMC_PACKED_NR_SINGLE,
> -};
> -
>  module_param(perdev_minors, int, 0444);
>  MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
>
> @@ -139,17 +129,6 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
>                                       struct mmc_blk_data *md);
>  static int get_card_status(struct mmc_card *card, u32 *status, int retries);
>
> -static inline void mmc_blk_clear_packed(struct mmc_queue_req *mqrq)
> -{
> -       struct mmc_packed *packed = mqrq->packed;
> -
> -       mqrq->cmd_type = MMC_PACKED_NONE;
> -       packed->nr_entries = MMC_PACKED_NR_ZERO;
> -       packed->idx_failure = MMC_PACKED_NR_IDX;
> -       packed->retries = 0;
> -       packed->blocks = 0;
> -}
> -
>  static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
>  {
>         struct mmc_blk_data *md;
> @@ -1420,111 +1399,12 @@ static enum mmc_blk_status mmc_blk_err_check(struct mmc_card *card,
>         if (!brq->data.bytes_xfered)
>                 return MMC_BLK_RETRY;
>
> -       if (mmc_packed_cmd(mq_mrq->cmd_type)) {
> -               if (unlikely(brq->data.blocks << 9 != brq->data.bytes_xfered))
> -                       return MMC_BLK_PARTIAL;
> -               else
> -                       return MMC_BLK_SUCCESS;
> -       }
> -
>         if (blk_rq_bytes(req) != brq->data.bytes_xfered)
>                 return MMC_BLK_PARTIAL;
>
>         return MMC_BLK_SUCCESS;
>  }
>
> -static int mmc_packed_init(struct mmc_queue *mq, struct mmc_card *card)
> -{
> -       struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
> -       struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
> -       int ret = 0;
> -
> -
> -       mqrq_cur->packed = kzalloc(sizeof(struct mmc_packed), GFP_KERNEL);
> -       if (!mqrq_cur->packed) {
> -               pr_warn("%s: unable to allocate packed cmd for mqrq_cur\n",
> -                       mmc_card_name(card));
> -               ret = -ENOMEM;
> -               goto out;
> -       }
> -
> -       mqrq_prev->packed = kzalloc(sizeof(struct mmc_packed), GFP_KERNEL);
> -       if (!mqrq_prev->packed) {
> -               pr_warn("%s: unable to allocate packed cmd for mqrq_prev\n",
> -                       mmc_card_name(card));
> -               kfree(mqrq_cur->packed);
> -               mqrq_cur->packed = NULL;
> -               ret = -ENOMEM;
> -               goto out;
> -       }
> -
> -       INIT_LIST_HEAD(&mqrq_cur->packed->list);
> -       INIT_LIST_HEAD(&mqrq_prev->packed->list);
> -
> -out:
> -       return ret;
> -}
> -
> -static void mmc_packed_clean(struct mmc_queue *mq)
> -{
> -       struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
> -       struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
> -
> -       kfree(mqrq_cur->packed);
> -       mqrq_cur->packed = NULL;
> -       kfree(mqrq_prev->packed);
> -       mqrq_prev->packed = NULL;
> -}
> -
> -static enum mmc_blk_status mmc_blk_packed_err_check(struct mmc_card *card,
> -                                                   struct mmc_async_req *areq)
> -{
> -       struct mmc_queue_req *mq_rq = container_of(areq, struct mmc_queue_req,
> -                       mmc_active);
> -       struct request *req = mq_rq->req;
> -       struct mmc_packed *packed = mq_rq->packed;
> -       enum mmc_blk_status status, check;
> -       int err;
> -       u8 *ext_csd;
> -
> -       packed->retries--;
> -       check = mmc_blk_err_check(card, areq);
> -       err = get_card_status(card, &status, 0);
> -       if (err) {
> -               pr_err("%s: error %d sending status command\n",
> -                      req->rq_disk->disk_name, err);
> -               return MMC_BLK_ABORT;
> -       }
> -
> -       if (status & R1_EXCEPTION_EVENT) {
> -               err = mmc_get_ext_csd(card, &ext_csd);
> -               if (err) {
> -                       pr_err("%s: error %d sending ext_csd\n",
> -                              req->rq_disk->disk_name, err);
> -                       return MMC_BLK_ABORT;
> -               }
> -
> -               if ((ext_csd[EXT_CSD_EXP_EVENTS_STATUS] &
> -                    EXT_CSD_PACKED_FAILURE) &&
> -                   (ext_csd[EXT_CSD_PACKED_CMD_STATUS] &
> -                    EXT_CSD_PACKED_GENERIC_ERROR)) {
> -                       if (ext_csd[EXT_CSD_PACKED_CMD_STATUS] &
> -                           EXT_CSD_PACKED_INDEXED_ERROR) {
> -                               packed->idx_failure =
> -                                 ext_csd[EXT_CSD_PACKED_FAILURE_INDEX] - 1;
> -                               check = MMC_BLK_PARTIAL;
> -                       }
> -                       pr_err("%s: packed cmd failed, nr %u, sectors %u, "
> -                              "failure index: %d\n",
> -                              req->rq_disk->disk_name, packed->nr_entries,
> -                              packed->blocks, packed->idx_failure);
> -               }
> -               kfree(ext_csd);
> -       }
> -
> -       return check;
> -}
> -
>  static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
>                                struct mmc_card *card,
>                                int disable_multi,
> @@ -1685,222 +1565,6 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
>         mmc_queue_bounce_pre(mqrq);
>  }
>
> -static inline u8 mmc_calc_packed_hdr_segs(struct request_queue *q,
> -                                         struct mmc_card *card)
> -{
> -       unsigned int hdr_sz = mmc_large_sector(card) ? 4096 : 512;
> -       unsigned int max_seg_sz = queue_max_segment_size(q);
> -       unsigned int len, nr_segs = 0;
> -
> -       do {
> -               len = min(hdr_sz, max_seg_sz);
> -               hdr_sz -= len;
> -               nr_segs++;
> -       } while (hdr_sz);
> -
> -       return nr_segs;
> -}
> -
> -static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
> -{
> -       struct request_queue *q = mq->queue;
> -       struct mmc_card *card = mq->card;
> -       struct request *cur = req, *next = NULL;
> -       struct mmc_blk_data *md = mq->blkdata;
> -       struct mmc_queue_req *mqrq = mq->mqrq_cur;
> -       bool en_rel_wr = card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN;
> -       unsigned int req_sectors = 0, phys_segments = 0;
> -       unsigned int max_blk_count, max_phys_segs;
> -       bool put_back = true;
> -       u8 max_packed_rw = 0;
> -       u8 reqs = 0;
> -
> -       /*
> -        * We don't need to check packed for any further
> -        * operation of packed stuff as we set MMC_PACKED_NONE
> -        * and return zero for reqs if geting null packed. Also
> -        * we clean the flag of MMC_BLK_PACKED_CMD to avoid doing
> -        * it again when removing blk req.
> -        */
> -       if (!mqrq->packed) {
> -               md->flags &= (~MMC_BLK_PACKED_CMD);
> -               goto no_packed;
> -       }
> -
> -       if (!(md->flags & MMC_BLK_PACKED_CMD))
> -               goto no_packed;
> -
> -       if ((rq_data_dir(cur) == WRITE) &&
> -           mmc_host_packed_wr(card->host))
> -               max_packed_rw = card->ext_csd.max_packed_writes;
> -
> -       if (max_packed_rw == 0)
> -               goto no_packed;
> -
> -       if (mmc_req_rel_wr(cur) &&
> -           (md->flags & MMC_BLK_REL_WR) && !en_rel_wr)
> -               goto no_packed;
> -
> -       if (mmc_large_sector(card) &&
> -           !IS_ALIGNED(blk_rq_sectors(cur), 8))
> -               goto no_packed;
> -
> -       mmc_blk_clear_packed(mqrq);
> -
> -       max_blk_count = min(card->host->max_blk_count,
> -                           card->host->max_req_size >> 9);
> -       if (unlikely(max_blk_count > 0xffff))
> -               max_blk_count = 0xffff;
> -
> -       max_phys_segs = queue_max_segments(q);
> -       req_sectors += blk_rq_sectors(cur);
> -       phys_segments += cur->nr_phys_segments;
> -
> -       if (rq_data_dir(cur) == WRITE) {
> -               req_sectors += mmc_large_sector(card) ? 8 : 1;
> -               phys_segments += mmc_calc_packed_hdr_segs(q, card);
> -       }
> -
> -       do {
> -               if (reqs >= max_packed_rw - 1) {
> -                       put_back = false;
> -                       break;
> -               }
> -
> -               spin_lock_irq(q->queue_lock);
> -               next = blk_fetch_request(q);
> -               spin_unlock_irq(q->queue_lock);
> -               if (!next) {
> -                       put_back = false;
> -                       break;
> -               }
> -
> -               if (mmc_large_sector(card) &&
> -                   !IS_ALIGNED(blk_rq_sectors(next), 8))
> -                       break;
> -
> -               if (mmc_req_is_special(next))
> -                       break;
> -
> -               if (rq_data_dir(cur) != rq_data_dir(next))
> -                       break;
> -
> -               if (mmc_req_rel_wr(next) &&
> -                   (md->flags & MMC_BLK_REL_WR) && !en_rel_wr)
> -                       break;
> -
> -               req_sectors += blk_rq_sectors(next);
> -               if (req_sectors > max_blk_count)
> -                       break;
> -
> -               phys_segments +=  next->nr_phys_segments;
> -               if (phys_segments > max_phys_segs)
> -                       break;
> -
> -               list_add_tail(&next->queuelist, &mqrq->packed->list);
> -               cur = next;
> -               reqs++;
> -       } while (1);
> -
> -       if (put_back) {
> -               spin_lock_irq(q->queue_lock);
> -               blk_requeue_request(q, next);
> -               spin_unlock_irq(q->queue_lock);
> -       }
> -
> -       if (reqs > 0) {
> -               list_add(&req->queuelist, &mqrq->packed->list);
> -               mqrq->packed->nr_entries = ++reqs;
> -               mqrq->packed->retries = reqs;
> -               return reqs;
> -       }
> -
> -no_packed:
> -       mqrq->cmd_type = MMC_PACKED_NONE;
> -       return 0;
> -}
> -
> -static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
> -                                       struct mmc_card *card,
> -                                       struct mmc_queue *mq)
> -{
> -       struct mmc_blk_request *brq = &mqrq->brq;
> -       struct request *req = mqrq->req;
> -       struct request *prq;
> -       struct mmc_blk_data *md = mq->blkdata;
> -       struct mmc_packed *packed = mqrq->packed;
> -       bool do_rel_wr, do_data_tag;
> -       __le32 *packed_cmd_hdr;
> -       u8 hdr_blocks;
> -       u8 i = 1;
> -
> -       mqrq->cmd_type = MMC_PACKED_WRITE;
> -       packed->blocks = 0;
> -       packed->idx_failure = MMC_PACKED_NR_IDX;
> -
> -       packed_cmd_hdr = packed->cmd_hdr;
> -       memset(packed_cmd_hdr, 0, sizeof(packed->cmd_hdr));
> -       packed_cmd_hdr[0] = cpu_to_le32((packed->nr_entries << 16) |
> -               (PACKED_CMD_WR << 8) | PACKED_CMD_VER);
> -       hdr_blocks = mmc_large_sector(card) ? 8 : 1;
> -
> -       /*
> -        * Argument for each entry of packed group
> -        */
> -       list_for_each_entry(prq, &packed->list, queuelist) {
> -               do_rel_wr = mmc_req_rel_wr(prq) && (md->flags & MMC_BLK_REL_WR);
> -               do_data_tag = (card->ext_csd.data_tag_unit_size) &&
> -                       (prq->cmd_flags & REQ_META) &&
> -                       (rq_data_dir(prq) == WRITE) &&
> -                       blk_rq_bytes(prq) >= card->ext_csd.data_tag_unit_size;
> -               /* Argument of CMD23 */
> -               packed_cmd_hdr[(i * 2)] = cpu_to_le32(
> -                       (do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
> -                       (do_data_tag ? MMC_CMD23_ARG_TAG_REQ : 0) |
> -                       blk_rq_sectors(prq));
> -               /* Argument of CMD18 or CMD25 */
> -               packed_cmd_hdr[((i * 2)) + 1] = cpu_to_le32(
> -                       mmc_card_blockaddr(card) ?
> -                       blk_rq_pos(prq) : blk_rq_pos(prq) << 9);
> -               packed->blocks += blk_rq_sectors(prq);
> -               i++;
> -       }
> -
> -       memset(brq, 0, sizeof(struct mmc_blk_request));
> -       brq->mrq.cmd = &brq->cmd;
> -       brq->mrq.data = &brq->data;
> -       brq->mrq.sbc = &brq->sbc;
> -       brq->mrq.stop = &brq->stop;
> -
> -       brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
> -       brq->sbc.arg = MMC_CMD23_ARG_PACKED | (packed->blocks + hdr_blocks);
> -       brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
> -
> -       brq->cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
> -       brq->cmd.arg = blk_rq_pos(req);
> -       if (!mmc_card_blockaddr(card))
> -               brq->cmd.arg <<= 9;
> -       brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
> -
> -       brq->data.blksz = 512;
> -       brq->data.blocks = packed->blocks + hdr_blocks;
> -       brq->data.flags = MMC_DATA_WRITE;
> -
> -       brq->stop.opcode = MMC_STOP_TRANSMISSION;
> -       brq->stop.arg = 0;
> -       brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
> -
> -       mmc_set_data_timeout(&brq->data, card);
> -
> -       brq->data.sg = mqrq->sg;
> -       brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
> -
> -       mqrq->mmc_active.mrq = &brq->mrq;
> -       mqrq->mmc_active.err_check = mmc_blk_packed_err_check;
> -
> -       mmc_queue_bounce_pre(mqrq);
> -}
> -
>  static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
>                            struct mmc_blk_request *brq, struct request *req,
>                            int ret)
> @@ -1923,79 +1587,10 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
>                 if (blocks != (u32)-1) {
>                         ret = blk_end_request(req, 0, blocks << 9);
>                 }
> -       } else {
> -               if (!mmc_packed_cmd(mq_rq->cmd_type))
> -                       ret = blk_end_request(req, 0, brq->data.bytes_xfered);
> -       }
> -       return ret;
> -}
> -
> -static int mmc_blk_end_packed_req(struct mmc_queue_req *mq_rq)
> -{
> -       struct request *prq;
> -       struct mmc_packed *packed = mq_rq->packed;
> -       int idx = packed->idx_failure, i = 0;
> -       int ret = 0;
> -
> -       while (!list_empty(&packed->list)) {
> -               prq = list_entry_rq(packed->list.next);
> -               if (idx == i) {
> -                       /* retry from error index */
> -                       packed->nr_entries -= idx;
> -                       mq_rq->req = prq;
> -                       ret = 1;
> -
> -                       if (packed->nr_entries == MMC_PACKED_NR_SINGLE) {
> -                               list_del_init(&prq->queuelist);
> -                               mmc_blk_clear_packed(mq_rq);
> -                       }
> -                       return ret;
> -               }
> -               list_del_init(&prq->queuelist);
> -               blk_end_request(prq, 0, blk_rq_bytes(prq));
> -               i++;
>         }
> -
> -       mmc_blk_clear_packed(mq_rq);
>         return ret;
>  }
>
> -static void mmc_blk_abort_packed_req(struct mmc_queue_req *mq_rq)
> -{
> -       struct request *prq;
> -       struct mmc_packed *packed = mq_rq->packed;
> -
> -       while (!list_empty(&packed->list)) {
> -               prq = list_entry_rq(packed->list.next);
> -               list_del_init(&prq->queuelist);
> -               blk_end_request(prq, -EIO, blk_rq_bytes(prq));
> -       }
> -
> -       mmc_blk_clear_packed(mq_rq);
> -}
> -
> -static void mmc_blk_revert_packed_req(struct mmc_queue *mq,
> -                                     struct mmc_queue_req *mq_rq)
> -{
> -       struct request *prq;
> -       struct request_queue *q = mq->queue;
> -       struct mmc_packed *packed = mq_rq->packed;
> -
> -       while (!list_empty(&packed->list)) {
> -               prq = list_entry_rq(packed->list.prev);
> -               if (prq->queuelist.prev != &packed->list) {
> -                       list_del_init(&prq->queuelist);
> -                       spin_lock_irq(q->queue_lock);
> -                       blk_requeue_request(mq->queue, prq);
> -                       spin_unlock_irq(q->queue_lock);
> -               } else {
> -                       list_del_init(&prq->queuelist);
> -               }
> -       }
> -
> -       mmc_blk_clear_packed(mq_rq);
> -}
> -
>  static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
>  {
>         struct mmc_blk_data *md = mq->blkdata;
> @@ -2006,15 +1601,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
>         struct mmc_queue_req *mq_rq;
>         struct request *req = rqc;
>         struct mmc_async_req *areq;
> -       const u8 packed_nr = 2;
> -       u8 reqs = 0;
>
>         if (!rqc && !mq->mqrq_prev->req)
>                 return 0;
>
> -       if (rqc)
> -               reqs = mmc_blk_prep_packed_list(mq, rqc);
> -
>         do {
>                 if (rqc) {
>                         /*
> @@ -2029,11 +1619,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
>                                 goto cmd_abort;
>                         }
>
> -                       if (reqs >= packed_nr)
> -                               mmc_blk_packed_hdr_wrq_prep(mq->mqrq_cur,
> -                                                           card, mq);
> -                       else
> -                               mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
> +                       mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
>                         areq = &mq->mqrq_cur->mmc_active;
>                 } else
>                         areq = NULL;
> @@ -2058,13 +1644,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
>                          */
>                         mmc_blk_reset_success(md, type);
>
> -                       if (mmc_packed_cmd(mq_rq->cmd_type)) {
> -                               ret = mmc_blk_end_packed_req(mq_rq);
> -                               break;
> -                       } else {
> -                               ret = blk_end_request(req, 0,
> -                                               brq->data.bytes_xfered);
> -                       }
> +                       ret = blk_end_request(req, 0,
> +                                       brq->data.bytes_xfered);
>
>                         /*
>                          * If the blk_end_request function returns non-zero even
> @@ -2101,8 +1682,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
>                         err = mmc_blk_reset(md, card->host, type);
>                         if (!err)
>                                 break;
> -                       if (err == -ENODEV ||
> -                               mmc_packed_cmd(mq_rq->cmd_type))
> +                       if (err == -ENODEV)
>                                 goto cmd_abort;
>                         /* Fall through */
>                 }
> @@ -2133,23 +1713,14 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
>                 }
>
>                 if (ret) {
> -                       if (mmc_packed_cmd(mq_rq->cmd_type)) {
> -                               if (!mq_rq->packed->retries)
> -                                       goto cmd_abort;
> -                               mmc_blk_packed_hdr_wrq_prep(mq_rq, card, mq);
> -                               mmc_start_req(card->host,
> -                                             &mq_rq->mmc_active, NULL);
> -                       } else {
> -
> -                               /*
> -                                * In case of a incomplete request
> -                                * prepare it again and resend.
> -                                */
> -                               mmc_blk_rw_rq_prep(mq_rq, card,
> -                                               disable_multi, mq);
> -                               mmc_start_req(card->host,
> -                                               &mq_rq->mmc_active, NULL);
> -                       }
> +                       /*
> +                        * In case of a incomplete request
> +                        * prepare it again and resend.
> +                        */
> +                       mmc_blk_rw_rq_prep(mq_rq, card,
> +                                       disable_multi, mq);
> +                       mmc_start_req(card->host,
> +                                       &mq_rq->mmc_active, NULL);
>                         mq_rq->brq.retune_retry_done = retune_retry_done;
>                 }
>         } while (ret);
> @@ -2157,15 +1728,11 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
>         return 1;
>
>   cmd_abort:
> -       if (mmc_packed_cmd(mq_rq->cmd_type)) {
> -               mmc_blk_abort_packed_req(mq_rq);
> -       } else {
> -               if (mmc_card_removed(card))
> -                       req->cmd_flags |= REQ_QUIET;
> -               while (ret)
> -                       ret = blk_end_request(req, -EIO,
> -                                       blk_rq_cur_bytes(req));
> -       }
> +       if (mmc_card_removed(card))
> +               req->cmd_flags |= REQ_QUIET;
> +       while (ret)
> +               ret = blk_end_request(req, -EIO,
> +                               blk_rq_cur_bytes(req));
>
>   start_new_req:
>         if (rqc) {
> @@ -2173,12 +1740,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
>                         rqc->cmd_flags |= REQ_QUIET;
>                         blk_end_request_all(rqc, -EIO);
>                 } else {
> -                       /*
> -                        * If current request is packed, it needs to put back.
> -                        */
> -                       if (mmc_packed_cmd(mq->mqrq_cur->cmd_type))
> -                               mmc_blk_revert_packed_req(mq, mq->mqrq_cur);
> -
>                         mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
>                         mmc_start_req(card->host,
>                                       &mq->mqrq_cur->mmc_active, NULL);
> @@ -2361,14 +1922,6 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
>                 blk_queue_write_cache(md->queue.queue, true, true);
>         }
>
> -       if (mmc_card_mmc(card) &&
> -           (area_type == MMC_BLK_DATA_AREA_MAIN) &&
> -           (md->flags & MMC_BLK_CMD23) &&
> -           card->ext_csd.packed_event_en) {
> -               if (!mmc_packed_init(&md->queue, card))
> -                       md->flags |= MMC_BLK_PACKED_CMD;
> -       }
> -
>         return md;
>
>   err_putdisk:
> @@ -2472,8 +2025,6 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
>                  */
>                 card = md->queue.card;
>                 mmc_cleanup_queue(&md->queue);
> -               if (md->flags & MMC_BLK_PACKED_CMD)
> -                       mmc_packed_clean(&md->queue);
>                 if (md->disk->flags & GENHD_FL_UP) {
>                         device_remove_file(disk_to_dev(md->disk), &md->force_ro);
>                         if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
> diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
> index 3f6a2463ab30..7dacf2744fbd 100644
> --- a/drivers/mmc/card/queue.c
> +++ b/drivers/mmc/card/queue.c
> @@ -406,41 +406,6 @@ void mmc_queue_resume(struct mmc_queue *mq)
>         }
>  }
>
> -static unsigned int mmc_queue_packed_map_sg(struct mmc_queue *mq,
> -                                           struct mmc_packed *packed,
> -                                           struct scatterlist *sg,
> -                                           enum mmc_packed_type cmd_type)
> -{
> -       struct scatterlist *__sg = sg;
> -       unsigned int sg_len = 0;
> -       struct request *req;
> -
> -       if (mmc_packed_wr(cmd_type)) {
> -               unsigned int hdr_sz = mmc_large_sector(mq->card) ? 4096 : 512;
> -               unsigned int max_seg_sz = queue_max_segment_size(mq->queue);
> -               unsigned int len, remain, offset = 0;
> -               u8 *buf = (u8 *)packed->cmd_hdr;
> -
> -               remain = hdr_sz;
> -               do {
> -                       len = min(remain, max_seg_sz);
> -                       sg_set_buf(__sg, buf + offset, len);
> -                       offset += len;
> -                       remain -= len;
> -                       sg_unmark_end(__sg++);
> -                       sg_len++;
> -               } while (remain);
> -       }
> -
> -       list_for_each_entry(req, &packed->list, queuelist) {
> -               sg_len += blk_rq_map_sg(mq->queue, req, __sg);
> -               __sg = sg + (sg_len - 1);
> -               sg_unmark_end(__sg++);
> -       }
> -       sg_mark_end(sg + (sg_len - 1));
> -       return sg_len;
> -}
> -
>  /*
>   * Prepare the sg list(s) to be handed of to the host driver
>   */
> @@ -449,26 +414,14 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
>         unsigned int sg_len;
>         size_t buflen;
>         struct scatterlist *sg;
> -       enum mmc_packed_type cmd_type;
>         int i;
>
> -       cmd_type = mqrq->cmd_type;
> -
> -       if (!mqrq->bounce_buf) {
> -               if (mmc_packed_cmd(cmd_type))
> -                       return mmc_queue_packed_map_sg(mq, mqrq->packed,
> -                                                      mqrq->sg, cmd_type);
> -               else
> -                       return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
> -       }
> +       if (!mqrq->bounce_buf)
> +               return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
>
>         BUG_ON(!mqrq->bounce_sg);
>
> -       if (mmc_packed_cmd(cmd_type))
> -               sg_len = mmc_queue_packed_map_sg(mq, mqrq->packed,
> -                                                mqrq->bounce_sg, cmd_type);
> -       else
> -               sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
> +       sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
>
>         mqrq->bounce_sg_len = sg_len;
>
> diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
> index 334c9306070f..47f5532b5776 100644
> --- a/drivers/mmc/card/queue.h
> +++ b/drivers/mmc/card/queue.h
> @@ -22,23 +22,6 @@ struct mmc_blk_request {
>         int                     retune_retry_done;
>  };
>
> -enum mmc_packed_type {
> -       MMC_PACKED_NONE = 0,
> -       MMC_PACKED_WRITE,
> -};
> -
> -#define mmc_packed_cmd(type)   ((type) != MMC_PACKED_NONE)
> -#define mmc_packed_wr(type)    ((type) == MMC_PACKED_WRITE)
> -
> -struct mmc_packed {
> -       struct list_head        list;
> -       __le32                  cmd_hdr[1024];
> -       unsigned int            blocks;
> -       u8                      nr_entries;
> -       u8                      retries;
> -       s16                     idx_failure;
> -};
> -
>  struct mmc_queue_req {
>         struct request          *req;
>         struct mmc_blk_request  brq;
> @@ -47,8 +30,6 @@ struct mmc_queue_req {
>         struct scatterlist      *bounce_sg;
>         unsigned int            bounce_sg_len;
>         struct mmc_async_req    mmc_active;
> -       enum mmc_packed_type    cmd_type;
> -       struct mmc_packed       *packed;
>  };
>
>  struct mmc_queue {
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 2a6418d0c343..2ce32fefb41c 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -494,11 +494,6 @@ static inline int mmc_host_uhs(struct mmc_host *host)
>                  MMC_CAP_UHS_DDR50);
>  }
>
> -static inline int mmc_host_packed_wr(struct mmc_host *host)
> -{
> -       return host->caps2 & MMC_CAP2_PACKED_WR;
> -}
> -
>  static inline int mmc_card_hs(struct mmc_card *card)
>  {
>         return card->host->ios.timing == MMC_TIMING_SD_HS ||
> --
> 2.7.4
>

^ permalink raw reply

* Re: [PATCH mmc/next] mmc: sh_mobile_sdhi: remove support for sh7372
From: Ulf Hansson @ 2016-11-25 13:30 UTC (permalink / raw)
  To: Simon Horman
  Cc: Wolfram Sang, Magnus Damm, linux-mmc@vger.kernel.org,
	Linux-Renesas
In-Reply-To: <1479984534-25468-1-git-send-email-horms+renesas@verge.net.au>

On 24 November 2016 at 11:48, Simon Horman <horms+renesas@verge.net.au> wrote:
> Remove documentation of support for the SH7372 (SH-Mobile AP4) from the MMC
> driver. The driver itself appears to have no SH7372 specific code.
>
> Commit edf4100906044225 ("ARM: shmobile: sh7372 dtsi: Remove Legacy file")
> removes this SoC from the kernel in v4.1.
>
> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>

Thanks, applied for next!

Kind regards
Uffe

> ---
>  Documentation/devicetree/bindings/mmc/tmio_mmc.txt | 1 -
>  1 file changed, 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
> index 13df9c2399c3..1db9e74bb9c1 100644
> --- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
> +++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
> @@ -11,7 +11,6 @@ optional bindings can be used.
>
>  Required properties:
>  - compatible:  "renesas,sdhi-shmobile" - a generic sh-mobile SDHI unit
> -               "renesas,sdhi-sh7372" - SDHI IP on SH7372 SoC
>                 "renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
>                 "renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
>                 "renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
> --
> 2.7.0.rc3.207.g0ac5344
>

^ permalink raw reply

* Re: [PATCH mmc/next] mmc: sh_mmcif: Document r8a73a4, r8a7778 and sh73a0 DT bindings
From: Ulf Hansson @ 2016-11-25 13:31 UTC (permalink / raw)
  To: Simon Horman
  Cc: linux-mmc@vger.kernel.org, devicetree@vger.kernel.org,
	Magnus Damm, Linux-Renesas
In-Reply-To: <20161125075614.GB14431@verge.net.au>

On 25 November 2016 at 08:56, Simon Horman <horms+renesas@verge.net.au> wrote:
> Simply document new compatibility strings as the driver is already
> activated using a fallback compatibility string.
>
> These compat strings are in keeping with those for all other
> Renesas ARM based SoCs with sh_mmcif enabled in mainline.
>
> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>

Thanks, applied for next!

Kind regards
Uffe

> ---
> Reposted with r8a7778 instead of r8a7779 in subject
>
> I have also posted patches to use these new compat strings
> to bring the DT files of the SoCs in question in-line with those
> for other Renesas ARM based SoCs with sh_mmcif enabled in mainline.
> ---
>  Documentation/devicetree/bindings/mmc/renesas,mmcif.txt | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
> index ff611fa66871..e4ba92aa035e 100644
> --- a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
> +++ b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
> @@ -8,11 +8,14 @@ Required properties:
>
>  - compatible: should be "renesas,mmcif-<soctype>", "renesas,sh-mmcif" as a
>    fallback. Examples with <soctype> are:
> +       - "renesas,mmcif-r8a73a4" for the MMCIF found in r8a73a4 SoCs
>         - "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs
> +       - "renesas,mmcif-r8a7778" for the MMCIF found in r8a7778 SoCs
>         - "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs
>         - "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs
>         - "renesas,mmcif-r8a7793" for the MMCIF found in r8a7793 SoCs
>         - "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs
> +       - "renesas,mmcif-sh73a0" for the MMCIF found in sh73a0 SoCs
>
>  - clocks: reference to the functional clock
>
> --
> 2.7.0.rc3.207.g0ac5344
>

^ permalink raw reply

* Re: [PATCH 6/10] mmc: sdhci-xenon: Add Marvell Xenon SDHC core functionality
From: Ziji Hu @ 2016-11-25 13:43 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Jimmy Xu, Andrew Lunn, Romain Perier, Hanna Hawa,
	linux-kernel@vger.kernel.org, Nadav Haklai, Victor Gu, Doug Jones,
	Jisheng Zhang, Yehuda Yitschak, Wei(SOCP) Liu, Kostya Porotchkin,
	Sebastian Hesselbarth, devicetree@vger.kernel.org, Jason Cooper,
	Rob Herring, Ryan Gao, Gregory CLEMENT, Marcin Wojtas,
	linux-arm-kernel@lists.infradead.org, Thomas Petazzoni
In-Reply-To: <CAPDyKFoqyF5QkJy+PmGa-b8JhaUmVXeoqBfv+pdupFiJBgyiLg@mail.gmail.com>

Hi Ulf,

On 2016/11/25 21:06, Ulf Hansson wrote:
> [...]
> 
>>>>>>> +
>>>>>>> +       /*
>>>>>>> +        * Xenon Specific property:
>>>>>>> +        * emmc: explicitly indicate whether this slot is for eMMC
>>>>>>> +        * slotno: the index of slot. Refer to SDHC_SYS_CFG_INFO register
>>>>>>> +        * tun-count: the interval between re-tuning
>>>>>>> +        * PHY type: "sdhc phy", "emmc phy 5.0" or "emmc phy 5.1"
>>>>>>> +        */
>>>>>>> +       if (of_property_read_bool(np, "marvell,xenon-emmc"))
>>>>>>> +               priv->emmc_slot = true;
>>>>>>
>>>>>> So, you need this because of the eMMC voltage switch behaviour, right?
>>>>>>
>>>>>> Then I would rather like to describe this a generic DT bindings for
>>>>>> the eMMC voltage level support. There have acutally been some earlier
>>>>>> discussions for this, but we haven't yet made some changes.
>>>>>>
>>>>>> I think what is missing is a mmc-ddr-3_3v DT binding, which when set,
>>>>>> allows the host driver to accept I/O voltage switches to 3.3V. If not
>>>>>> supported the  ->start_signal_voltage_switch() ops may return -EINVAL.
>>>>>> This would inform the mmc core to move on to the next supported
>>>>>> voltage level. There might be some minor additional changes to the mmc
>>>>>> card initialization sequence, but those should be simple.
>>>>>>
>>>>>> I can help out to look into this, unless you want to do it yourself of course!?
>>>>>>
>>>>>    Yes. One of the reasons is to provide eMMC specific voltage setting.
>>>>>    But in my very own opinion, it should be irrelevant to voltage level.
>>>>>    The eMMC voltage setting on our SDHC is different from SD/SDIO voltage switch.
>>>>>    It will become more complex with different SOC implementation details.
>>>>
>>>> Got it. Although I think we can cope with that fine just by using the
>>>> different SD/eMMC speed modes settings defined in DT (or from the
>>>> SDHCI caps register)
>>>>
>>>     In my very opinion, I'm not sure if there is any corner case that driver cannot
>>>     determine the eMMC card type from DT and SDHC caps.
>>>
>>>>>    Unfortunately, MMC driver cannot determine the card type yet when eMMC voltage
>>>>>    setting should be executed.
>>>>>    Thus an flag is required here to tell driver to execute eMMC voltage setting.
>>>>>
>>>>>    Besides, additional eMMC specific settings might be implemented in future, besides
>>>>>    voltage setting. Most of them should be completed before MMC driver recognizes the
>>>>>    card type. Thus I have to keep this flag to indicate current SDHC is for eMMC.
>>>>
>>>> I doubt you will need a generic "eMMC" flag, but let's see when we go forward.
>>>>
>>>> Currently it's clear you don't need such a flag, so I will submit a
>>>> change adding a DT binding for "mmc-ddr-3_3v" then we can take it from
>>>> there, to see if it suits your needs.
>>>>
>>
>>     Another reason for a special "xenon-emmc" property is that our host IP usually can
>>     support both eMMC and SD. Whether a host is used as eMMC or SD depends on the
>>     final implementation of the actual product.
>>     Thus our host driver needs to know whether current SDHC is fixed as eMMC or SD.
>>     So far, It can only get the information from DT.
> 
> As a matter of fact for mounted non-removable cards, such as eMMC, we
> already have the option to describe some of their characteristics in
> DT. Perhaps that's what you need?
> 
> Please have a look at:
> Documentation/devicetree/bindings/mmc/mmc-card.txt
> 
   Great!
   I will try this mmc-card sub-node.

   Thank you very much.

Best regards,
Hu Ziji

>>
>>     After out host driver get the card type information from DT, it can prepare eMMC
>>     specific voltage, set eMMC specific mmc->caps/caps2 flags and do other
>>     vendor specific init, before card init procedure.
>>     Otherwise, our host driver has to wait until card type is determined in mmc_rescan().
>>
>>     A generic "eMMC" flag is unnecessary. I just require a private property,
>>     which is only used in our host driver and DT.
>>
>>     Thank you.
>>
>> Best regards,
>> Hu Ziji
>>
>>>
>>>     Actually, our eMMC is usually fixed as 1.8V.
>>>
>>>     The pair "no-sd" + "no-sdio" can provide the similar information.
>>>     But I'm not sure if it is proper to use those two property in such a way.
>>>
>>>     Thank you.
>>>
>>> Best regards
>>> Hu Ziji
>>>
>>>> [...]
>>>>
>>>> Kind regards
>>>> Uffe
>>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>
> 
> Kind regards
> Uffe
> 

^ permalink raw reply

* Re: [PATCH 6/10] mmc: sdhci-xenon: Add Marvell Xenon SDHC core functionality
From: Adrian Hunter @ 2016-11-25 14:04 UTC (permalink / raw)
  To: Ulf Hansson, Ziji Hu
  Cc: Jimmy Xu, Andrew Lunn, Romain Perier, Hanna Hawa, Nadav Haklai,
	Zhen Huang, Victor Gu, Doug Jones, Jisheng Zhang, Yehuda Yitschak,
	Wei(SOCP) Liu, Kostya Porotchkin, Sebastian Hesselbarth,
	devicetree@vger.kernel.org, Jason Cooper, Rob Herring, Ryan Gao,
	Gregory CLEMENT, Marcin Wojtas,
	linux-arm-kernel@lists.infradead.org, Thomas Petazzoni, linux-mmc
In-Reply-To: <CAPDyKFr9uEjVQmTNP0KK8Zj9mxCW3i564E=47vTK0RLvXCjw3Q@mail.gmail.com>

On 24/11/16 15:34, Ulf Hansson wrote:
> On 24 November 2016 at 13:41, Ziji Hu <huziji@marvell.com> wrote:
>> On 2016/11/24 18:43, Ulf Hansson wrote:
>>> On 31 October 2016 at 12:09, Gregory CLEMENT
>>> <gregory.clement@free-electrons.com> wrote:
>>>> From: Ziji Hu <huziji@marvell.com>
>>>> +static int xenon_start_signal_voltage_switch(struct mmc_host *mmc,
>>>> +                                            struct mmc_ios *ios)
>>>> +{
>>>> +       struct sdhci_host *host = mmc_priv(mmc);
>>>> +       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>>>> +       struct sdhci_xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
>>>> +
>>>> +       /*
>>>> +        * Before SD/SDIO set signal voltage, SD bus clock should be
>>>> +        * disabled. However, sdhci_set_clock will also disable the Internal
>>>> +        * clock in mmc_set_signal_voltage().
>>>
>>> If that's the case then that is wrong in the generic sdhci code.
>>> What's the reason why it can't be fixed there instead of having this
>>> workaround?
>>>
>>     In my very own opinion, SD Spec doesn't specify whether SDCLK should be
>>     enabled or not during power setting.
>>     Enabling SDCLK might be a special condition only required by our SDHC.
>>     I try to avoid breaking other vendors' SDHC functionality
>>     if their SDHCs require SDCLK disabled.
>>     Thus I prefer to keep it inside our SDHC driver.
> 
> I let Adrian comment on this.
> 
> For sure we should avoid breaking other sdhci variant, but on the
> other hand *if* the generic code is wrong we should fix it!

Yes, this looks like something that could perhaps be fixed in sdhci.  I will
look into it.

^ permalink raw reply

* Re: [PATCH V7 01/25] mmc: queue: Fix queue thread wake-up
From: Linus Walleij @ 2016-11-25 14:37 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Ulf Hansson, linux-mmc, Alex Lemberg, Mateusz Nowak,
	Yuliy Izrailov, Jaehoon Chung, Dong Aisheng, Das Asutosh,
	Zhangfei Gao, Dorfman Konstantin, David Griego, Sahitya Tummala,
	Harjani Ritesh, Venu Byravarasu
In-Reply-To: <1480068442-5169-2-git-send-email-adrian.hunter@intel.com>

On Fri, Nov 25, 2016 at 11:06 AM, Adrian Hunter <adrian.hunter@intel.com> wrote:

> The only time the driver sleeps expecting to be woken upon the arrival of
> a new request, is when the dispatch queue is empty. The only time that it
> is known whether the dispatch queue is empty is after NULL is returned
> from blk_fetch_request() while under the queue lock.
>
> Recognizing those facts, simplify the synchronization between the queue
> thread and the request function. A couple of flags tell the request
> function what to do, and the queue lock and barriers associated with
> wake-ups ensure synchronization.
>
> The result is simpler and allows the removal of the context_info lock.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Very nice patch!
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply

* Re: [PATCH V7 02/25] mmc: queue: Factor out mmc_queue_alloc_bounce_bufs()
From: Linus Walleij @ 2016-11-25 14:38 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Ulf Hansson, linux-mmc, Alex Lemberg, Mateusz Nowak,
	Yuliy Izrailov, Jaehoon Chung, Dong Aisheng, Das Asutosh,
	Zhangfei Gao, Dorfman Konstantin, David Griego, Sahitya Tummala,
	Harjani Ritesh, Venu Byravarasu
In-Reply-To: <1480068442-5169-3-git-send-email-adrian.hunter@intel.com>

On Fri, Nov 25, 2016 at 11:06 AM, Adrian Hunter <adrian.hunter@intel.com> wrote:

> In preparation for supporting a queue of requests, factor out
> mmc_queue_alloc_bounce_bufs().
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Nice refactoring.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply

* Re: [PATCH V7 03/25] mmc: queue: Factor out mmc_queue_alloc_bounce_sgs()
From: Linus Walleij @ 2016-11-25 14:39 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Ulf Hansson, linux-mmc, Alex Lemberg, Mateusz Nowak,
	Yuliy Izrailov, Jaehoon Chung, Dong Aisheng, Das Asutosh,
	Zhangfei Gao, Dorfman Konstantin, David Griego, Sahitya Tummala,
	Harjani Ritesh, Venu Byravarasu
In-Reply-To: <1480068442-5169-4-git-send-email-adrian.hunter@intel.com>

On Fri, Nov 25, 2016 at 11:07 AM, Adrian Hunter <adrian.hunter@intel.com> wrote:

> In preparation for supporting a queue of requests, factor out
> mmc_queue_alloc_bounce_sgs().
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Nice refactoring.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply

* Re: [PATCH V7 04/25] mmc: queue: Factor out mmc_queue_alloc_sgs()
From: Linus Walleij @ 2016-11-25 14:41 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Ulf Hansson, linux-mmc, Alex Lemberg, Mateusz Nowak,
	Yuliy Izrailov, Jaehoon Chung, Dong Aisheng, Das Asutosh,
	Zhangfei Gao, Dorfman Konstantin, David Griego, Sahitya Tummala,
	Harjani Ritesh, Venu Byravarasu
In-Reply-To: <1480068442-5169-5-git-send-email-adrian.hunter@intel.com>

On Fri, Nov 25, 2016 at 11:07 AM, Adrian Hunter <adrian.hunter@intel.com> wrote:

> In preparation for supporting a queue of requests, factor out
> mmc_queue_alloc_sgs().
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Nice refactoring.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply

* Re: [PATCH V7 05/25] mmc: queue: Factor out mmc_queue_reqs_free_bufs()
From: Linus Walleij @ 2016-11-25 14:42 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Ulf Hansson, linux-mmc, Alex Lemberg, Mateusz Nowak,
	Yuliy Izrailov, Jaehoon Chung, Dong Aisheng, Das Asutosh,
	Zhangfei Gao, Dorfman Konstantin, David Griego, Sahitya Tummala,
	Harjani Ritesh, Venu Byravarasu
In-Reply-To: <1480068442-5169-6-git-send-email-adrian.hunter@intel.com>

On Fri, Nov 25, 2016 at 11:07 AM, Adrian Hunter <adrian.hunter@intel.com> wrote:

> In preparation for supporting a queue of requests, factor out
> mmc_queue_reqs_free_bufs().
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Nice refactoring.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply

* Re: [PATCH V7 06/25] mmc: queue: Introduce queue depth
From: Linus Walleij @ 2016-11-25 14:43 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Ulf Hansson, linux-mmc, Alex Lemberg, Mateusz Nowak,
	Yuliy Izrailov, Jaehoon Chung, Dong Aisheng, Das Asutosh,
	Zhangfei Gao, Dorfman Konstantin, David Griego, Sahitya Tummala,
	Harjani Ritesh, Venu Byravarasu
In-Reply-To: <1480068442-5169-7-git-send-email-adrian.hunter@intel.com>

On Fri, Nov 25, 2016 at 11:07 AM, Adrian Hunter <adrian.hunter@intel.com> wrote:

> Add a mmc_queue member to record the size of the queue, which currently
> supports 2 requests on-the-go at a time.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
(...)
> +       /* Queue depth is only ever 2 with packed commands */

That's a weird comment.
It doesn't have anything with packed commands to do does it?
In that case it was just deleted.

Are you referring to the asynchronous issuing pipeline thing
(cur & next)?

Yours,
Linus Walleij

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox