Add attribute bouncesz under sysfs. Provide a helper of dynamic adjustment of bounce buffer for SDMA mmc card at run-time (mounted or unmounted filesystem). bouncesz should be integer multiple of 512, the value range is from 4K to 4M. 1. use variable instead of MMC_QUEUE_BOUNCESZ; 2. Re-initialize bounce buffer accorinding to new bounce size at run-time; Cc: Chris Ball <cjb@xxxxxxxxxx> Cc: Rob Landley <rob@xxxxxxxxxxx> Signed-off-by: Qiang Liu <qiang.liu@xxxxxxxxxxxxx> --- Hi all, I resend the patch because bounce size is a key factor of performance for some SDMA card, larger bounce size will improve throughput under condition of mass data transfer. So I add this helper and export the value to user space. drivers/mmc/card/block.c | 48 +++++++++++++++++++++ drivers/mmc/card/queue.c | 102 +++++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/card/queue.h | 6 +++ 3 files changed, 155 insertions(+), 1 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index f1c84de..3ea4ac3 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -58,6 +58,9 @@ MODULE_ALIAS("mmc:block"); #define INAND_CMD38_ARG_SECTRIM1 0x81 #define INAND_CMD38_ARG_SECTRIM2 0x88 +#define MMC_MIN_QUEUE_BOUNCESZ 4096 +#define MMC_MAX_QUEUE_BOUNCESZ 4194304 + static DEFINE_MUTEX(block_mutex); /* @@ -107,6 +110,7 @@ struct mmc_blk_data { unsigned int part_curr; struct device_attribute force_ro; struct device_attribute power_ro_lock; + struct device_attribute bouncesz; int area_type; }; @@ -263,6 +267,33 @@ out: return ret; } +#ifdef CONFIG_MMC_BLOCK_BOUNCE +static ssize_t mmc_bouncesz_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", mmc_queue_bouncesz); +} + +static ssize_t mmc_bouncesz_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int bouncesz; + struct mmc_blk_data *md; + + if ((sscanf(buf, "%d", &bouncesz) != 1) || + (bouncesz < MMC_MIN_QUEUE_BOUNCESZ) || + (bouncesz > MMC_MAX_QUEUE_BOUNCESZ) || + (bouncesz % 512 != 0)) + return -EINVAL; + + md = mmc_blk_get(dev_to_disk(dev)); + mmc_reinit_bounce_queue(&md->queue, md->queue.card, bouncesz); + mmc_blk_put(md); + return mmc_queue_bouncesz; +} +#endif + static int mmc_blk_open(struct block_device *bdev, fmode_t mode) { struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk); @@ -1648,6 +1679,8 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md) del_gendisk(md->disk); } + device_remove_file(disk_to_dev(md->disk), &md->bouncesz); + /* Then flush out any already in there */ mmc_cleanup_queue(&md->queue); mmc_blk_put(md); @@ -1683,6 +1716,17 @@ static int mmc_add_disk(struct mmc_blk_data *md) if (ret) goto force_ro_fail; +#ifdef CONFIG_MMC_BLOCK_BOUNCE + md->bouncesz.show = mmc_bouncesz_show; + md->bouncesz.store = mmc_bouncesz_store; + sysfs_attr_init(&md->bouncesz.attr); + md->bouncesz.attr.name = "bouncesz"; + md->bouncesz.attr.mode = S_IRUGO | S_IWUSR; + ret = device_create_file(disk_to_dev(md->disk), &md->bouncesz); + if (ret) + goto bouncesz_fail; +#endif + if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && card->ext_csd.boot_ro_lockable) { umode_t mode; @@ -1707,6 +1751,10 @@ static int mmc_add_disk(struct mmc_blk_data *md) power_ro_lock_fail: device_remove_file(disk_to_dev(md->disk), &md->force_ro); +#ifdef CONFIG_MMC_BLOCK_BOUNCE +bouncesz_fail: + device_remove_file(disk_to_dev(md->disk), &md->bouncesz); +#endif force_ro_fail: del_gendisk(md->disk); diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index e360a97..b9777a5 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -22,6 +22,10 @@ #define MMC_QUEUE_BOUNCESZ 65536 +#ifdef CONFIG_MMC_BLOCK_BOUNCE +unsigned mmc_queue_bouncesz = MMC_QUEUE_BOUNCESZ; +#endif + #define MMC_QUEUE_SUSPENDED (1 << 0) /* @@ -188,7 +192,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, if (host->max_segs == 1) { unsigned int bouncesz; - bouncesz = MMC_QUEUE_BOUNCESZ; + bouncesz = mmc_queue_bouncesz; if (bouncesz > host->max_req_size) bouncesz = host->max_req_size; @@ -332,6 +336,102 @@ void mmc_cleanup_queue(struct mmc_queue *mq) EXPORT_SYMBOL(mmc_cleanup_queue); /** + * mmc_reinit_bounce_queue - re-initialise a bounce buffer. + * @mq: mmc queue + * @card: mmc card to attach this queue + * @bouncesz: the bounce size that need re-initializing + * + * Initialise a MMC card request queue. + */ +#ifdef CONFIG_MMC_BLOCK_BOUNCE +int mmc_reinit_bounce_queue(struct mmc_queue *mq, struct mmc_card *card, + unsigned int bouncesz) +{ + struct mmc_host *host = card->host; + struct mmc_queue_req *mqrq_cur = &mq->mqrq[0]; + struct mmc_queue_req *mqrq_prev = &mq->mqrq[1]; + int ret; + struct scatterlist *curr_bounce_sg, *prev_bounce_sg; + char *curr_bounce_buf, *prev_bounce_buf; + + mmc_claim_host(card->host); + + bouncesz = min(bouncesz, host->max_req_size); + bouncesz = min(bouncesz, host->max_seg_size); + bouncesz = min(bouncesz, host->max_blk_count * 512); + + /* store current using addr of bounce_buf and bounce_sg */ + curr_bounce_sg = mqrq_cur->bounce_sg; + prev_bounce_sg = mqrq_prev->bounce_sg; + curr_bounce_buf = mqrq_cur->bounce_buf; + prev_bounce_buf = mqrq_prev->bounce_buf; + + if (host->max_segs != 1) + goto restore_queue; + + /* realloc bounce queue use given bounce size */ + mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); + if (!mqrq_cur->bounce_buf) { + printk(KERN_WARNING "%s: unable to " + "allocate bounce cur buffer\n", + mmc_card_name(card)); + ret = -ENOMEM; + goto restore_queue; + } + + mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); + if (!mqrq_prev->bounce_buf) { + printk(KERN_WARNING "%s: unable to " + "allocate bounce prev buffer\n", + mmc_card_name(card)); + kfree(mqrq_cur->bounce_buf); + mqrq_cur->bounce_buf = NULL; + ret = -ENOMEM; + goto restore_queue; + } + + mqrq_cur->bounce_sg = + mmc_alloc_sg(bouncesz / 512, &ret); + if (ret) + goto cleanup_queue; + + mqrq_prev->bounce_sg = + mmc_alloc_sg(bouncesz / 512, &ret); + if (ret) + goto cleanup_queue; + + blk_queue_max_hw_sectors(mq->queue, bouncesz / 512); + blk_queue_max_segments(mq->queue, bouncesz / 512); + blk_queue_max_segment_size(mq->queue, bouncesz); + mmc_queue_bouncesz = bouncesz; + + kfree(curr_bounce_sg); + kfree(prev_bounce_sg); + kfree(curr_bounce_buf); + kfree(prev_bounce_buf); + + mmc_release_host(card->host); + return 0; + +cleanup_queue: + /* cleanup bounce queue first */ + kfree(mqrq_cur->sg); + kfree(mqrq_cur->bounce_buf); + kfree(mqrq_prev->sg); + kfree(mqrq_prev->bounce_buf); + +restore_queue: + mqrq_cur->bounce_buf = curr_bounce_buf; + mqrq_prev->bounce_buf = prev_bounce_buf; + mqrq_cur->bounce_sg = curr_bounce_sg; + mqrq_prev->bounce_sg = prev_bounce_sg; + + mmc_release_host(card->host); + return ret; +} +#endif + +/** * mmc_queue_suspend - suspend a MMC request queue * @mq: MMC queue to suspend * diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index d2a1eb4..c1dee6d 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -46,4 +46,10 @@ extern unsigned int mmc_queue_map_sg(struct mmc_queue *, extern void mmc_queue_bounce_pre(struct mmc_queue_req *); extern void mmc_queue_bounce_post(struct mmc_queue_req *); +#ifdef CONFIG_MMC_BLOCK_BOUNCE +extern int mmc_reinit_bounce_queue(struct mmc_queue *, struct mmc_card *, + unsigned int); +extern unsigned mmc_queue_bouncesz; +#endif + #endif -- 1.7.5.1 -- To unsubscribe from this list: send the line "unsubscribe linux-doc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html