[PATCH RESEND 1/2] SD/MMC: add an interface to re-initialize bounce buffer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux