From 8e8b3f514c12a3b800bba8a7766c71139ad75b89 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 4 Nov 2016 11:05:19 +0100 Subject: mmc: core: use enum mmc_blk_status properly There were several instances of code using the enum mmc_blk_status by arbitrarily converting it to an int and throwing it around to different functions. This makes the code hard to understand to may give rise to strange errors. Especially the function prototype mmc_start_req() had to be modified to take a pointer to an enum mmc_blk_status and the function pointer .err_check() inside struct mmc_async_req needed to return an enum mmc_blk_status. In every case: instead of assigning the block layer error code to an int, use the enum, also change the signature of all functions actually passing this enum to use the enum. To make it possible to use the enum everywhere applicable, move it to so that all code actually using it can also see it. An interesting case was encountered in the MMC test code which did not return a enum mmc_blk_status at all in the .err_check function supposed to check whether asynchronous requests worked or not: instead it returned a normal -ERROR or even the test frameworks internal error codes. The test code would also pass on enum mmc_blk_status codes as error codes inside the test code instead of converting them to the local RESULT_* codes. I have tried to fix all instances properly and run some tests on the result. Cc: Chunyan Zhang Cc: Baolin Wang Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- include/linux/mmc/host.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux/mmc/host.h') diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 0b2439441cc8..5310f94be0ab 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -173,7 +173,7 @@ struct mmc_async_req { * Check error status of completed mmc request. * Returns 0 if success otherwise non zero. */ - int (*err_check) (struct mmc_card *, struct mmc_async_req *); + enum mmc_blk_status (*err_check)(struct mmc_card *, struct mmc_async_req *); }; /** -- cgit v1.2.3 From c820af5f18ec248b3cb61a9a9ce47ef0f2e9ec63 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 3 Nov 2016 15:15:59 +0100 Subject: mmc: core: Add helper to see if a host can be retuned This is in preparation for restoring saved tuning parameters when resuming the TMIO driver. Signed-off-by: Simon Horman Acked-by: Wolfram Sang Tested-by: Wolfram Sang Signed-off-by: Ulf Hansson --- include/linux/mmc/host.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include/linux/mmc/host.h') diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 5310f94be0ab..68639295148d 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -546,6 +546,11 @@ static inline void mmc_retune_recheck(struct mmc_host *host) host->retune_now = 1; } +static inline bool mmc_can_retune(struct mmc_host *host) +{ + return host->can_retune == 1; +} + void mmc_retune_pause(struct mmc_host *host); void mmc_retune_unpause(struct mmc_host *host); -- cgit v1.2.3 From d3c6aac3bdfe97b8b44db6a8aba59786cb9531dc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 23 Nov 2016 11:02:24 +0100 Subject: mmc: delete is_first_req parameter from pre-request callback The void (*pre_req) callback in the struct mmc_host_ops vtable is passing an argument "is_first_req" indicating whether this is the first request or not. None of the in-kernel users use this parameter: instead, since they all just do variants of dma_map* they use the DMA cookie to indicate whether a pre* callback has already been done for a request when they decide how to handle it. Delete the parameter from the callback and all users, as it is just pointless cruft. Signed-off-by: Linus Walleij Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 11 ++++------- drivers/mmc/host/dw_mmc.c | 3 +-- drivers/mmc/host/jz4740_mmc.c | 3 +-- drivers/mmc/host/mmci.c | 3 +-- drivers/mmc/host/mtk-sd.c | 3 +-- drivers/mmc/host/omap_hsmmc.c | 3 +-- drivers/mmc/host/rtsx_pci_sdmmc.c | 3 +-- drivers/mmc/host/sdhci.c | 3 +-- include/linux/mmc/host.h | 3 +-- 9 files changed, 12 insertions(+), 23 deletions(-) (limited to 'include/linux/mmc/host.h') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 060f76742550..f39397f7c8dc 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -611,18 +611,15 @@ EXPORT_SYMBOL(mmc_is_req_done); * mmc_pre_req - Prepare for a new request * @host: MMC host to prepare command * @mrq: MMC request to prepare for - * @is_first_req: true if there is no previous started request - * that may run in parellel to this call, otherwise false * * mmc_pre_req() is called in prior to mmc_start_req() to let * host prepare for the new request. Preparation of a request may be * performed while another request is running on the host. */ -static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, - bool is_first_req) +static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq) { if (host->ops->pre_req) - host->ops->pre_req(host, mrq, is_first_req); + host->ops->pre_req(host, mrq); } /** @@ -667,7 +664,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, /* Prepare a new request */ if (areq) - mmc_pre_req(host, areq->mrq, !host->areq); + mmc_pre_req(host, areq->mrq); if (host->areq) { status = mmc_wait_for_data_req_done(host, host->areq->mrq, areq); @@ -696,7 +693,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, /* prepare the request again */ if (areq) - mmc_pre_req(host, areq->mrq, !host->areq); + mmc_pre_req(host, areq->mrq); } } diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 881ca3e37da4..d400afc74719 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -886,8 +886,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host, } static void dw_mci_pre_req(struct mmc_host *mmc, - struct mmc_request *mrq, - bool is_first_req) + struct mmc_request *mrq) { struct dw_mci_slot *slot = mmc_priv(mmc); struct mmc_data *data = mrq->data; diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 684087db170b..819ad32964fc 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -320,8 +320,7 @@ dma_unmap: } static void jz4740_mmc_pre_request(struct mmc_host *mmc, - struct mmc_request *mrq, - bool is_first_req) + struct mmc_request *mrq) { struct jz4740_mmc_host *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 6af3ee7b452a..01a804792f30 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -699,8 +699,7 @@ static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) next->dma_chan = NULL; } -static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) +static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct mmci_host *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 86af0b199a54..10ef2ae1d2f6 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -927,8 +927,7 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) msdc_start_command(host, mrq, mrq->cmd); } -static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) +static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq) { struct msdc_host *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 5f2f24a7360d..ad11c4cc12ed 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1565,8 +1565,7 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, } } -static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) +static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq) { struct omap_hsmmc_host *host = mmc_priv(mmc); diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 3ccaa1415f33..ecb99a8d2fa2 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -190,8 +190,7 @@ static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host, return using_cookie; } -static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) +static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq) { struct realtek_pci_sdmmc *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 62aedf191b0c..7f2526c9572f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2202,8 +2202,7 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, data->host_cookie = COOKIE_UNMAPPED; } -static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) +static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq) { struct sdhci_host *host = mmc_priv(mmc); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 68639295148d..2a6418d0c343 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -93,8 +93,7 @@ struct mmc_host_ops { */ void (*post_req)(struct mmc_host *host, struct mmc_request *req, int err); - void (*pre_req)(struct mmc_host *host, struct mmc_request *req, - bool is_first_req); + void (*pre_req)(struct mmc_host *host, struct mmc_request *req); void (*request)(struct mmc_host *host, struct mmc_request *req); /* -- cgit v1.2.3 From 03d640ae1f9b24b1d2a11f747143a1ecc0745019 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 25 Nov 2016 10:35:00 +0100 Subject: mmc: block: delete packed command support 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 commit ce39f9d17c14 ("mmc: support packed write command for eMMC4.5 devices") commit 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 Cc: Maya Erez Acked-by: Jaehoon Chung Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- 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(-) (limited to 'include/linux/mmc/host.h') 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 @@ again: 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 || -- cgit v1.2.3 From e0097cf5f2f1b7b8a594beaa32a604776d3ca6ce Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 29 Nov 2016 12:09:10 +0200 Subject: mmc: queue: Fix queue thread wake-up 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 Reviewed-by: Linus Walleij Reviewed-by: Harjani Ritesh Signed-off-by: Ulf Hansson --- drivers/mmc/card/block.c | 7 ------- drivers/mmc/card/queue.c | 35 +++++++++++++++++++++-------------- drivers/mmc/card/queue.h | 1 + drivers/mmc/core/core.c | 6 ------ include/linux/mmc/host.h | 2 -- 5 files changed, 22 insertions(+), 29 deletions(-) (limited to 'include/linux/mmc/host.h') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 3e73be0e7281..646d1a1fa6ca 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1758,8 +1758,6 @@ 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; - struct mmc_host *host = card->host; - unsigned long flags; bool req_is_special = mmc_req_is_special(req); if (req && !mq->mqrq_prev->req) @@ -1792,11 +1790,6 @@ int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) mmc_blk_issue_rw_rq(mq, NULL); ret = mmc_blk_issue_flush(mq, req); } else { - if (!req && host->areq) { - spin_lock_irqsave(&host->context_info.lock, flags); - host->context_info.is_waiting_last_req = true; - spin_unlock_irqrestore(&host->context_info.lock, flags); - } ret = mmc_blk_issue_rw_rq(mq, req); } diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 7dacf2744fbd..010888d8d97c 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -53,6 +53,7 @@ static int mmc_queue_thread(void *d) { struct mmc_queue *mq = d; struct request_queue *q = mq->queue; + struct mmc_context_info *cntx = &mq->card->host->context_info; current->flags |= PF_MEMALLOC; @@ -63,6 +64,19 @@ static int mmc_queue_thread(void *d) spin_lock_irq(q->queue_lock); set_current_state(TASK_INTERRUPTIBLE); req = blk_fetch_request(q); + mq->asleep = false; + cntx->is_waiting_last_req = false; + cntx->is_new_req = false; + if (!req) { + /* + * Dispatch queue is empty so set flags for + * mmc_request_fn() to wake us up. + */ + if (mq->mqrq_prev->req) + cntx->is_waiting_last_req = true; + else + mq->asleep = true; + } mq->mqrq_cur->req = req; spin_unlock_irq(q->queue_lock); @@ -115,7 +129,6 @@ static void mmc_request_fn(struct request_queue *q) { struct mmc_queue *mq = q->queuedata; struct request *req; - unsigned long flags; struct mmc_context_info *cntx; if (!mq) { @@ -127,19 +140,13 @@ static void mmc_request_fn(struct request_queue *q) } cntx = &mq->card->host->context_info; - if (!mq->mqrq_cur->req && mq->mqrq_prev->req) { - /* - * New MMC request arrived when MMC thread may be - * blocked on the previous request to be complete - * with no current request fetched - */ - spin_lock_irqsave(&cntx->lock, flags); - if (cntx->is_waiting_last_req) { - cntx->is_new_req = true; - wake_up_interruptible(&cntx->wait); - } - spin_unlock_irqrestore(&cntx->lock, flags); - } else if (!mq->mqrq_cur->req && !mq->mqrq_prev->req) + + if (cntx->is_waiting_last_req) { + cntx->is_new_req = true; + wake_up_interruptible(&cntx->wait); + } + + if (mq->asleep) wake_up_process(mq->thread); } diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index 47f5532b5776..d09fce655800 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -39,6 +39,7 @@ struct mmc_queue { 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[2]; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f39397f7c8dc..dc1f27ee50b8 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -504,18 +504,14 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host, struct mmc_command *cmd; struct mmc_context_info *context_info = &host->context_info; enum mmc_blk_status status; - unsigned long flags; while (1) { wait_event_interruptible(context_info->wait, (context_info->is_done_rcv || context_info->is_new_req)); - spin_lock_irqsave(&context_info->lock, flags); context_info->is_waiting_last_req = false; - spin_unlock_irqrestore(&context_info->lock, flags); if (context_info->is_done_rcv) { context_info->is_done_rcv = false; - context_info->is_new_req = false; cmd = mrq->cmd; if (!cmd->error || !cmd->retries || @@ -534,7 +530,6 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host, continue; /* wait for done/new event again */ } } else if (context_info->is_new_req) { - context_info->is_new_req = false; if (!next_req) return MMC_BLK_NEW_REQUEST; } @@ -3016,7 +3011,6 @@ void mmc_unregister_pm_notifier(struct mmc_host *host) */ void mmc_init_context_info(struct mmc_host *host) { - spin_lock_init(&host->context_info.lock); host->context_info.is_new_req = false; host->context_info.is_done_rcv = false; host->context_info.is_waiting_last_req = false; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 2ce32fefb41c..8bc884121465 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -197,14 +197,12 @@ struct mmc_slot { * @is_new_req wake up reason was new request * @is_waiting_last_req mmc context waiting for single running request * @wait wait queue - * @lock lock to protect data fields */ struct mmc_context_info { bool is_done_rcv; bool is_new_req; bool is_waiting_last_req; wait_queue_head_t wait; - spinlock_t lock; }; struct regulator; -- cgit v1.2.3