diff options
Diffstat (limited to 'drivers/mmc/core/queue.c')
| -rw-r--r-- | drivers/mmc/core/queue.c | 41 | 
1 files changed, 38 insertions, 3 deletions
diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 7102e2ebc614..9edc08685e86 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -21,6 +21,8 @@  #include "card.h"  #include "host.h" +#define MMC_DMA_MAP_MERGE_SEGMENTS	512 +  static inline bool mmc_cqe_dcmd_busy(struct mmc_queue *mq)  {  	/* Allow only 1 DCMD at a time */ @@ -193,6 +195,12 @@ static void mmc_queue_setup_discard(struct request_queue *q,  		blk_queue_flag_set(QUEUE_FLAG_SECERASE, q);  } +static unsigned int mmc_get_max_segments(struct mmc_host *host) +{ +	return host->can_dma_map_merge ? MMC_DMA_MAP_MERGE_SEGMENTS : +					 host->max_segs; +} +  /**   * mmc_init_request() - initialize the MMC-specific per-request data   * @q: the request queue @@ -206,7 +214,7 @@ static int __mmc_init_request(struct mmc_queue *mq, struct request *req,  	struct mmc_card *card = mq->card;  	struct mmc_host *host = card->host; -	mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp); +	mq_rq->sg = mmc_alloc_sg(mmc_get_max_segments(host), gfp);  	if (!mq_rq->sg)  		return -ENOMEM; @@ -362,13 +370,23 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)  		blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH);  	blk_queue_max_hw_sectors(mq->queue,  		min(host->max_blk_count, host->max_req_size / 512)); -	blk_queue_max_segments(mq->queue, host->max_segs); +	if (host->can_dma_map_merge) +		WARN(!blk_queue_can_use_dma_map_merging(mq->queue, +							mmc_dev(host)), +		     "merging was advertised but not possible"); +	blk_queue_max_segments(mq->queue, mmc_get_max_segments(host));  	if (mmc_card_mmc(card))  		block_size = card->ext_csd.data_sector_size;  	blk_queue_logical_block_size(mq->queue, block_size); -	blk_queue_max_segment_size(mq->queue, +	/* +	 * After blk_queue_can_use_dma_map_merging() was called with succeed, +	 * since it calls blk_queue_virt_boundary(), the mmc should not call +	 * both blk_queue_max_segment_size(). +	 */ +	if (!host->can_dma_map_merge) +		blk_queue_max_segment_size(mq->queue,  			round_down(host->max_seg_size, block_size));  	dma_set_max_seg_size(mmc_dev(host), queue_max_segment_size(mq->queue)); @@ -381,6 +399,11 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)  	init_waitqueue_head(&mq->wait);  } +static inline bool mmc_merge_capable(struct mmc_host *host) +{ +	return host->caps2 & MMC_CAP2_MERGE_CAPABLE; +} +  /* Set queue depth to get a reasonable value for q->nr_requests */  #define MMC_QUEUE_DEPTH 64 @@ -418,6 +441,18 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)  	mq->tag_set.cmd_size = sizeof(struct mmc_queue_req);  	mq->tag_set.driver_data = mq; +	/* +	 * Since blk_mq_alloc_tag_set() calls .init_request() of mmc_mq_ops, +	 * the host->can_dma_map_merge should be set before to get max_segs +	 * from mmc_get_max_segments(). +	 */ +	if (mmc_merge_capable(host) && +	    host->max_segs < MMC_DMA_MAP_MERGE_SEGMENTS && +	    dma_get_merge_boundary(mmc_dev(host))) +		host->can_dma_map_merge = 1; +	else +		host->can_dma_map_merge = 0; +  	ret = blk_mq_alloc_tag_set(&mq->tag_set);  	if (ret)  		return ret;  |