Hi Chris, Do you have any concerns about this patch? Or another advice? Thanks. -----Original Message----- From: Liu Qiang-B32616 Sent: Wednesday, December 21, 2011 3:10 PM To: cjb@xxxxxxxxxx; linux-mmc@xxxxxxxxxxxxxxx Cc: Li Yang-R58472; Liu Qiang-B32616; Liu Qiang-B32616 Subject: [PATCH V2 1/2] SD/MMC: add an interface to re-initialize bounce buffer Add bounce_size under /sys/block/mmcblk0/bouncesz. Support dynamic adjustment of bounce buffer in run-time (include mounted or unmounted filesystem). /sys/block/mmcblk0/bouncesz should be integer multiple of 512, the value should be range from 4096 to 4194304. 1. use variable instead of MMC_QUEUE_BOUNCESZ; 2. Re-initialize bounce buffer accorinding to new bounce size at run-time; Signed-off-by: Qiang Liu <qiang.liu@xxxxxxxxxxxxx> --- changes for V2 merge former 2 patches to 1 Here is the test results with different mmc bounce size, IOzone is used to test performance of mass data transmission. Environment: PowerPC P1022DS platform, Sandisk Class 10, 4G memory card, EXT4 filesystem [root@p2020ds root]# cat /sys/fs/ block/mmcblk0/bouncesz 65536 [root@p2020ds root]# mount /dev/mmcblk0p1 /mnt/ EXT4-fs (mmcblk0p1): mounted filesystem without journal. Opts: [root@p2020ds root]# iozone -Rab result -i0 -i1 -r64 =- -n1g -g4g -f /mnt/ff ........ KB reclen write rewrite read reread 1048576 64 14229 13286 662028 663372 2097152 64 13758 12605 49549 47443 4194304 64 13435 12215 21974 22096 ........ [root@p2020ds root]# echo 262144 > /sys/block/mmcblk0/bouncesz [root@p2020ds root]# cat /sys/block/mmcblk0/bouncesz 262144 [root@p2020ds root]# iozone -Rab result -i0 -i1 -r64 -n1g -g4g -f /mnt/ff ........ KB reclen write rewrite read reread 1048576 64 19228 19416 676659 677785 2097152 64 18512 18499 26978 27055 4194304 64 17932 18185 21945 21805 ........ [root@p2020ds root]# echo 8192 > /sys/block/mmcblk0/bouncesz [root@p2020ds root]# cat /sys/block/mmcblk0/bouncesz 8192 [root@p2020ds root]# iozone -Rab result -i0 -i1 -r64 -n1g -g1g -f /mnt/ff KB reclen write rewrite read reread 1048576 64 5068 3324 640266 641609 ------------------------------------------------------------------------------- drivers/mmc/card/block.c | 43 +++++++++++++++++++ drivers/mmc/card/queue.c | 102 +++++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/card/queue.h | 6 +++ 3 files changed, 149 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 0c959c9..790abe2 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -59,6 +59,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); /* @@ -108,6 +111,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; }; @@ -1633,6 +1637,7 @@ 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); @@ -1739,6 +1744,33 @@ static const struct mmc_fixup blk_fixups[] = END_FIXUP }; +#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_probe(struct mmc_card *card) { struct mmc_blk_data *md, *part_md; @@ -1771,6 +1803,17 @@ static int mmc_blk_probe(struct mmc_card *card) mmc_set_drvdata(card, md); mmc_fixup_device(card, blk_fixups); +#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; + err = device_create_file(disk_to_dev(md->disk), &md->bouncesz); + if (err) + goto out; +#endif + if (mmc_add_disk(md)) goto out; diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index dcad59c..c563e33 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -21,7 +21,9 @@ #include "queue.h" #define MMC_QUEUE_BOUNCESZ 65536 - +#ifdef CONFIG_MMC_BLOCK_BOUNCE +unsigned mmc_queue_bouncesz = MMC_QUEUE_BOUNCESZ; #endif #define MMC_QUEUE_SUSPENDED (1 << 0) /* @@ -185,7 +187,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; @@ -329,6 +331,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.6.4 -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html