mmc: Urgent data request flow
Subsystems (2)
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.
Signed-off-by Konstantin Dorfman <[email protected]>
--- 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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