Skip to contentSkip to conversation

mmc: Urgent data request flow

PATCH New Maya Erez 1 participant 1 message Sep 20, 2012

Subsystems (2)
lore
Share & tools
lore

Maya Erez

author
#0 lore raw

PATCH 1/2 mmc: Urgent data request flow

From: Konstantin Dorfman <[email protected]>

Urgent request notification stops currently running packed transaction on bus. Finished part of the request will be acknowledged to the block layer, remainder will be re-inserted back to be fetched later, this will minimize urgent request latency.

---
 drivers/mmc/card/block.c |  171 +++++++++++++++++++++++---
 drivers/mmc/card/queue.c |   40 ++++++
 drivers/mmc/card/queue.h |    1 +
 drivers/mmc/core/core.c  |  306 ++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/mmc/card.h |   14 ++
 include/linux/mmc/core.h |   21 +++
 include/linux/mmc/host.h |    4 +
 include/linux/mmc/mmc.h  |    1 +
 8 files changed, 534 insertions(+), 24 deletions(-)
drivers/mmc/card/block.c +154 -17
index ea52ac2..e739c2f 100644
@@ -119,17 +119,6 @@ struct mmc_blk_data {
 
 static DEFINE_MUTEX(open_lock);
 
-enum mmc_blk_status {
-	MMC_BLK_SUCCESS = 0,
-	MMC_BLK_PARTIAL,
-	MMC_BLK_CMD_ERR,
-	MMC_BLK_RETRY,
-	MMC_BLK_ABORT,
-	MMC_BLK_DATA_ERR,
-	MMC_BLK_ECC_ERR,
-	MMC_BLK_NOMEDIUM,
-};
-
 enum {
 	MMC_PACKED_N_IDX = -1,
 	MMC_PACKED_N_ZERO,
@@ -1133,6 +1122,113 @@ static int mmc_blk_err_check(struct mmc_card *card,
 	return MMC_BLK_SUCCESS;
 }
 
+/*
+ * mmc_blk_reinsert_request() - re-insert request back into block layer
+ * @areq:	request to re-insert.
+ *
+ * Request may be packed or single. When fails to reinsert request, -EIO will be
+ * reported for this request and rest of packed_list
+ */
+static void mmc_blk_reinsert_request(struct mmc_async_req *areq)
+{
+	struct request *prq;
+	int ret = 0;
+	struct mmc_queue_req *mq_rq;
+	struct request_queue *q;
+
+	mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
+	q = mq_rq->req->q;
+	if (mq_rq->packed_cmd != MMC_PACKED_NONE) {
+		while (!list_empty(&mq_rq->packed_list)) {
+			/* return requests in reverse order */
+			prq = list_entry_rq(mq_rq->packed_list.prev);
+			list_del_init(&prq->queuelist);
+			ret = blk_reinsert_request(q, prq);
+			if (ret)
+				goto reinsert_error;
+		}
+	} else {
+		ret = blk_reinsert_request(q, mq_rq->req);
+		if (ret) {
+			pr_err("%s: blk_reinsert_request() fails (%d)",
+					__func__, ret);
+			blk_end_request(mq_rq->req, -EIO,
+					blk_rq_cur_bytes(mq_rq->req));
+		}
+	}
+	return;
+
+reinsert_error:
+	pr_err("%s: blk_reinsert_request() fails (%d)", __func__, ret);
+	while (!list_empty(&mq_rq->packed_list)) {
+		prq = list_entry_rq(mq_rq->packed_list.next);
+		list_del_init(&prq->queuelist);
+		blk_end_request(prq, -EIO, blk_rq_cur_bytes(prq));
+	}
+}
+
+/*
+ * mmc_update_interrupted_request() - update details of the interrupted request
+ * @card:	the MMC card associated with the request.
+ * @areq:	interrupted async request.
+ *
+ * Get stopped request state from card and updates successfully done part
+ * of the request by setting packed_fail_idx. For not packed request
+ * packed_fail_idx unchanged (-1).
+ *
+ * Returns: 0 for success, MMC_BLK_ABORT otherwise
+ */
+static int mmc_update_interrupted_request(struct mmc_card *card,
+					struct mmc_async_req *areq)
+{
+	int ret = MMC_BLK_SUCCESS;
+	u8 *ext_csd;
+	int correctly_done;
+	struct mmc_queue_req *mq_rq = container_of(areq, struct mmc_queue_req,
+			mmc_active);
+	struct request *prq;
+	u8 req_index = 0;
+
+	ext_csd = kmalloc(512, GFP_KERNEL);
+	if (!ext_csd) {
+		ret = MMC_BLK_ABORT;
+		goto exit;
+	}
+
+	mq_rq->packed_fail_idx = 0;
+
+	if (mq_rq->packed_cmd != MMC_PACKED_NONE) {
+		/* get correctly programmed sectors number from card */
+		ret = mmc_send_ext_csd(card, ext_csd);
+		if (ret) {
+			pr_err("%s: error %d sending ext_csd\n",
+					mq_rq->req->rq_disk->disk_name, ret);
+			ret = MMC_BLK_ABORT;
+			goto exit;
+		}
+		correctly_done = card->ext_csd.data_sector_size *
+			(ext_csd[EXT_CSD_CORRECTLY_PRG_SECTORS_NUM + 0] << 0 |
+			 ext_csd[EXT_CSD_CORRECTLY_PRG_SECTORS_NUM + 1] << 8 |
+			 ext_csd[EXT_CSD_CORRECTLY_PRG_SECTORS_NUM + 2] << 16 |
+			 ext_csd[EXT_CSD_CORRECTLY_PRG_SECTORS_NUM + 3] << 24);
+
+		list_for_each_entry(prq, &mq_rq->packed_list, queuelist) {
+			if (correctly_done < 0)
+				break;
+			if (correctly_done -  (int)blk_rq_bytes(prq) < 0) {
+				/* prq is not successfull */
+				mq_rq->packed_fail_idx = req_index;
+				break;
+			}
+			correctly_done -= blk_rq_bytes(prq);
+			req_index++;
+		}
+	}
+exit:
+	kfree(ext_csd);
+	return ret;
+}
+
 static int mmc_blk_packed_err_check(struct mmc_card *card,
 				    struct mmc_async_req *areq)
 {
@@ -1324,7 +1420,10 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
 	}
 
 	mqrq->mmc_active.mrq = &brq->mrq;
+	mqrq->mmc_active.mrq->sync_data = &mq->sync_data;
 	mqrq->mmc_active.err_check = mmc_blk_err_check;
+	mqrq->mmc_active.reinsert_request = mmc_blk_reinsert_request;
+	mqrq->mmc_active.update_interrupted = mmc_update_interrupted_request;
 
 	mmc_queue_bounce_pre(mqrq);
 }
@@ -1372,6 +1471,21 @@ static void mmc_blk_write_packing_control(struct mmc_queue *mq,
 
 }
 
+/**
+ * mmc_blk_disable_wr_packing() - disables packing mode
+ * @mq:	MMC queue.
+ *
+ * Note: this function may be called from 2 threads (mmc_queue_thread() and
+ * block layer context), in this case the code should be under lock to
+ * resolve race.
+ */
+void mmc_blk_disable_wr_packing(struct mmc_queue *mq)
+{
+	mq->wr_packing_enabled = false;
+	mq->num_of_potential_packed_wr_reqs = 0;
+}
+EXPORT_SYMBOL(mmc_blk_disable_wr_packing);
+
 static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
 {
 	struct request_queue *q = mq->queue;
@@ -1566,6 +1680,9 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
 
 	mqrq->mmc_active.mrq = &brq->mrq;
 	mqrq->mmc_active.err_check = mmc_blk_packed_err_check;
+	mqrq->mmc_active.mrq->sync_data = &mq->sync_data;
+	mqrq->mmc_active.reinsert_request = mmc_blk_reinsert_request;
+	mqrq->mmc_active.update_interrupted = mmc_update_interrupted_request;
 
 	mmc_queue_bounce_pre(mqrq);
 }
@@ -1702,7 +1819,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 			areq = &mq->mqrq_cur->mmc_active;
 		} else
 			areq = NULL;
-		areq = mmc_start_req(card->host, areq, (int *) &status);
+		areq = mmc_start_data_req(card->host, areq, (int *) &status);
 		if (!areq)
 			return 0;
 
@@ -1713,6 +1830,26 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 		mmc_queue_bounce_post(mq_rq);
 
 		switch (status) {
+		case MMC_BLK_URGENT:
+			if (mq_rq->packed_cmd != MMC_PACKED_NONE) {
+				/* complete successfully transmitted part */
+				ret = mmc_blk_end_packed_req(mq_rq);
+				if (ret)
+					/* process for not transmitted part */
+					mmc_blk_reinsert_request(areq);
+			} else { /* non packed request */
+				ret = blk_reinsert_request(mq->queue,
+						mq_rq->req);
+				if (ret)
+					blk_end_request(mq_rq->req, -EIO,
+						blk_rq_cur_bytes(mq_rq->req));
+			}
+			mq->mqrq_prev->brq.mrq.data = NULL;
+			mq->mqrq_prev->req = NULL;
+			mq->mqrq_cur->brq.mrq.data = NULL;
+			mq->mqrq_cur->req = NULL;
+			ret = 0;
+			break;
 		case MMC_BLK_SUCCESS:
 		case MMC_BLK_PARTIAL:
 			/*
@@ -1795,14 +1932,14 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 				 */
 				mmc_blk_rw_rq_prep(mq_rq, card,
 						disable_multi, mq);
-				mmc_start_req(card->host,
-						&mq_rq->mmc_active, NULL);
+				mmc_start_data_req(card->host,
+					&mq_rq->mmc_active, (int *) &status);
 			} else {
 				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);
+				mmc_start_data_req(card->host,
+					&mq_rq->mmc_active, (int *) &status);
 			}
 		}
 	} while (ret);
@@ -1829,7 +1966,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 			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);
+		mmc_start_data_req(card->host, &mq->mqrq_cur->mmc_active, NULL);
 	}
 
 	return 0;
drivers/mmc/card/queue.c +40 -0
index 79ef91b..b56ff33 100644
@@ -120,6 +120,38 @@ static void mmc_request_fn(struct request_queue *q)
 		wake_up_process(mq->thread);
 }
 
+/*
+ * mmc_urgent_request() - Urgent MMC request handler.
+ * @q: request queue.
+ *
+ * This is called when block layer has urgent request for delivery.
+ * When mmc context is waiting for current request, it will be awaken,
+ * current request interrupted and re-inserted back into block layer.
+ * The next fetched request should be urgent request.
+ */
+static void mmc_urgent_request(struct request_queue *q)
+{
+	unsigned long flags;
+	struct mmc_queue *mq = q->queuedata;
+
+	mq->sync_data.skip_urgent_flag = false;
+	/* critical section with mmc_wait_data_done() */
+	spin_lock_irqsave(&mq->sync_data.lock, flags);
+
+	/* do stop flow only when mmc thread is waiting for done */
+	if (mq->sync_data.waiting_flag &&
+		!mq->sync_data.skip_urgent_flag) {
+
+		mmc_blk_disable_wr_packing(mq);
+		mq->sync_data.urgent_flag = true;
+		wake_up_interruptible(&mq->sync_data.wait);
+		spin_unlock_irqrestore(&mq->sync_data.lock, flags);
+	} else {
+		spin_unlock_irqrestore(&mq->sync_data.lock, flags);
+		mmc_request_fn(q);
+	}
+}
+
 static struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
 {
 	struct scatterlist *sg;
@@ -182,6 +214,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
 	if (!mq->queue)
 		return -ENOMEM;
 
+	blk_urgent_request(mq->queue, mmc_urgent_request);
+
 	INIT_LIST_HEAD(&mqrq_cur->packed_list);
 	INIT_LIST_HEAD(&mqrq_prev->packed_list);
 
@@ -270,6 +304,12 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
 	}
 
 	sema_init(&mq->thread_sem, 1);
+	spin_lock_init(&mq->sync_data.lock);
+	mq->sync_data.skip_urgent_flag = false;
+	mq->sync_data.urgent_flag = false;
+	mq->sync_data.done_flag = false;
+	mq->sync_data.waiting_flag = false;
+	init_waitqueue_head(&mq->sync_data.wait);
 
 	mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s",
 		host->index, subname ? subname : "");
drivers/mmc/card/queue.h +1 -0
index 93e4b59..73a8ee2 100644
@@ -48,6 +48,7 @@ struct mmc_queue {
 	bool			wr_packing_enabled;
 	int			num_of_potential_packed_wr_reqs;
 	int			num_wr_reqs_to_start_packing;
+	struct mmc_sync_data	sync_data;
 };
 
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
drivers/mmc/core/core.c +299 -7

337 lines not on this page · raw message

include/linux/mmc/card.h +14 -0
index a585f63..50eb211 100644
@@ -181,6 +181,7 @@ struct sdio_cis {
 struct mmc_host;
 struct sdio_func;
 struct sdio_func_tuple;
+struct mmc_queue;
 
 #define SDIO_MAX_FUNCS		7
 
@@ -206,6 +207,18 @@ struct mmc_part {
 #define MMC_BLK_DATA_AREA_GP	(1<<2)
 };
 
+enum mmc_blk_status {
+	MMC_BLK_SUCCESS = 0,
+	MMC_BLK_PARTIAL,
+	MMC_BLK_CMD_ERR,
+	MMC_BLK_RETRY,
+	MMC_BLK_ABORT,
+	MMC_BLK_DATA_ERR,
+	MMC_BLK_ECC_ERR,
+	MMC_BLK_NOMEDIUM,
+	MMC_BLK_URGENT,
+};
+
 /*
  * MMC device
  */
@@ -505,4 +518,5 @@ extern void mmc_unregister_driver(struct mmc_driver *);
 extern void mmc_fixup_device(struct mmc_card *card,
 			     const struct mmc_fixup *table);
 
+extern void mmc_blk_disable_wr_packing(struct mmc_queue *mq);
 #endif /* LINUX_MMC_CARD_H */
include/linux/mmc/core.h +21 -0
index d787037..c02d753 100644
@@ -10,6 +10,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/completion.h>
+#include <linux/semaphore.h>
 
 struct request;
 struct mmc_data;
@@ -123,6 +124,23 @@ struct mmc_data {
 	s32			host_cookie;	/* host private data */
 };
 
+/**
+ * mmc_sync_data - synchronization details for mmc context
+ * @done_flag		wake up reason was done request
+ * @urgent_flag		wake up reason was urgent block request
+ * @skip_urgent_flag	done arrived before urgent
+ * @wait		wait queue
+ * @mmc_sem		semaphore to serialize wake up code
+ */
+struct mmc_sync_data {
+	bool			done_flag;
+	bool			urgent_flag;
+	bool			skip_urgent_flag;
+	bool			waiting_flag;
+	wait_queue_head_t	wait;
+	spinlock_t		lock;
+};
+
 struct mmc_request {
 	struct mmc_command	*sbc;		/* SET_BLOCK_COUNT for multiblock */
 	struct mmc_command	*cmd;
@@ -131,6 +149,7 @@ struct mmc_request {
 
 	struct completion	completion;
 	void			(*done)(struct mmc_request *);/* completion function */
+	struct mmc_sync_data    *sync_data;
 };
 
 struct mmc_host;
@@ -139,6 +158,8 @@ struct mmc_async_req;
 
 extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
 					   struct mmc_async_req *, int *);
+extern struct mmc_async_req *mmc_start_data_req(struct mmc_host *,
+					   struct mmc_async_req *, int *);
 extern int mmc_interrupt_hpi(struct mmc_card *);
 extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
include/linux/mmc/host.h +4 -0
index 263452f..4dcdc29 100644
@@ -151,6 +151,10 @@ struct mmc_async_req {
 	 * Returns 0 if success otherwise non zero.
 	 */
 	int (*err_check) (struct mmc_card *, struct mmc_async_req *);
+	/* Reinserts request back to the block layer */
+	void (*reinsert_request) (struct mmc_async_req *);
+	/* update what part of request is not done (packed_fail_idx) */
+	int (*update_interrupted) (struct mmc_card *, struct mmc_async_req *);
 };
 
 /**
include/linux/mmc/mmc.h +1 -0
index 254901a..20f67be 100644
@@ -318,6 +318,7 @@ struct _mmc_csd {
 #define EXT_CSD_PWR_CL_200_360		237	/* RO */
 #define EXT_CSD_PWR_CL_DDR_52_195	238	/* RO */
 #define EXT_CSD_PWR_CL_DDR_52_360	239	/* RO */
+#define EXT_CSD_CORRECTLY_PRG_SECTORS_NUM 242	/* RO, 4 bytes */
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
Signature · 5 lines
1.7.6
-- 
QUALCOMM ISRAEL,
on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation