2011/2/18 Andrei Warkentin <andr...@motorola.com>:
> On Fri, Feb 18, 2011 at 1:47 PM, Andrei Warkentin <andr...@motorola.com> 
> wrote:
>> On Fri, Feb 18, 2011 at 7:44 AM, Arnd Bergmann <a...@arndb.de> wrote:
>>> I'm curious. Neither the manfid nor the oemid fields of either card
>>> match what I have seen on SD cards, I would expect them to be
>>>
>>> Sandisk: manfid 0x000003, oemid 0x5344
>>> Toshiba: manfid 0x000002, oemid 0x544d
>>>
>>> I have not actually seen any Toshiba SD cards, but I assume that they
>>> use the same controllers as Kingston.
>>>
>>> Does anyone know if the IDs have any correlation between MMC and SD
>>> controllers?
>>>
>>>        Arnd
>>>
>>
>> I'm unsure about the older scheme (assigned by MMCA), but ever since
>> MMC is now JEDEC-controlled, the IDs have changed. Sandisk's new id
>> will be 0x45, and Toshiba I guess will be 0x11.
>>
>
> Flashbench timings for both Sandisk and Toshiba cards. Attaching due to size.
>
> Some interesting things that I don't understand. For the align test, I
> extended it to do a write align test (-A). I tried two partitions that
> I could write over, and both read and writes behaved differently for
> the two partitions on same device. Odd. They are both 4MB aligned.
>
> On the sandisk it was the write align that made the page size stand
> out.  The read align had pretty constant results.
>
> On the toshiba the results varied wildly for the two partitions. For
> partition 6, there was a clear pattern in the diff values for read
> align. For 9, it was all over the place. For 9 with the write align,
> 8K and 16K the crossing writes took ~115ms!! Look in attached files
> for all the data.
>
> The AU tests were interesting too, especially how with several open
> AUs the throughput is higher for certain smaller sizes on sandisk, but
> if I interpret it correctly both cards have at least 4 AUs, as I
> didn't see yet a significant drop for small sizes. The larger ones I
> am running now on mmcblk0p9 which is sufficiently larger for these
> tests... (mmcblk0p6 is only 40mb, p9 is 314 mb)
>
> Thanks,
> A
>

I thought this was pretty interesting -

# echo 0 > /sys/block/mmcblk0/device/page_size
# ./flashbench -A -b 1024 /dev/block/mmcblk0p9
write align 8388608     pre 3.59ms      on 6.54ms       post 3.65ms     diff 
2.92ms
write align 4194304     pre 4.13ms      on 7.37ms       post 4.27ms     diff 
3.17ms
write align 2097152     pre 3.62ms      on 6.81ms       post 3.94ms     diff 
3.03ms
write align 1048576     pre 3.62ms      on 6.53ms       post 3.55ms     diff 
2.95ms
write align 524288      pre 3.62ms      on 6.51ms       post 3.63ms     diff 
2.88ms
write align 262144      pre 3.62ms      on 6.51ms       post 3.63ms     diff 
2.89ms
write align 131072      pre 3.62ms      on 6.5ms        post 3.63ms     diff 
2.88ms
write align 65536       pre 3.61ms      on 6.49ms       post 3.62ms     diff 
2.88ms
write align 32768       pre 3.61ms      on 6.49ms       post 3.61ms     diff 
2.88ms
write align 16384       pre 3.68ms      on 107ms        post 3.51ms     diff 
103ms
write align 8192        pre 3.74ms      on 121ms        post 3.91ms     diff 
117ms
write align 4096        pre 3.88ms      on 3.87ms       post 3.87ms     diff 
-2937ns
write align 2048        pre 3.89ms      on 3.88ms       post 3.88ms     diff 
-8734ns
# fjnh84@fjnh84-desktop:~/src/n/src/flash$ adb -s 17006185428011d7 shell
# echo 8192 > /sys/block/mmcblk0/device/page_size
# cd data
# ./flashbench -A -b 1024 /dev/block/mmcblk0p9
write align 8388608     pre 3.33ms      on 6.8ms        post 3.65ms     diff 
3.31ms
write align 4194304     pre 4.34ms      on 8.14ms       post 4.53ms     diff 
3.71ms
write align 2097152     pre 3.64ms      on 7.31ms       post 4.09ms     diff 
3.44ms
write align 1048576     pre 3.65ms      on 7.52ms       post 3.65ms     diff 
3.87ms
write align 524288      pre 3.62ms      on 6.8ms        post 3.63ms     diff 
3.17ms
write align 262144      pre 3.62ms      on 6.84ms       post 3.63ms     diff 
3.22ms
write align 131072      pre 3.62ms      on 6.85ms       post 3.44ms     diff 
3.32ms
write align 65536       pre 3.39ms      on 6.8ms        post 3.66ms     diff 
3.28ms
write align 32768       pre 3.64ms      on 6.86ms       post 3.66ms     diff 
3.21ms
write align 16384       pre 3.67ms      on 6.86ms       post 3.65ms     diff 
3.2ms
write align 8192        pre 3.66ms      on 6.84ms       post 3.64ms     diff 
3.19ms
write align 4096        pre 3.71ms      on 3.71ms       post 3.64ms     diff 
38.6µs
write align 2048        pre 3.71ms      on 3.71ms       post 3.72ms     diff 
-656ns

This was with the split unaligned accesses patch... Which I am
attaching for comments.

Thanks,
A
From b3e6a556a716e7cec86071342197e798b38c3cbf Mon Sep 17 00:00:00 2001
From: Andrei Warkentin <andr...@motorola.com>
Date: Fri, 18 Feb 2011 17:46:00 -0600
Subject: [PATCH] MMC: Split non-page-size aligned accesses.

If the card page size is known, splits the access into an unaligned
and an aligned portion, which helps with the performance.

Change-Id: I4ad7588d613d775212fac87436e418577909a22b
Signed-off-by: Andrei Warkentin <andr...@motorola.com>
---
 drivers/mmc/card/block.c |  111 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mmc/card.h |    1 +
 2 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 7054fd5..be7d739 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 
 #include <linux/kernel.h>
+#include <linux/ctype.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
@@ -67,6 +68,74 @@ struct mmc_blk_data {
 
 static DEFINE_MUTEX(open_lock);
 
+static ssize_t
+show_block_attr(struct device *dev, struct device_attribute *attr,
+		char *buf);
+
+static ssize_t
+set_block_attr(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count);
+
+static DEVICE_ATTR(page_size, S_IRUGO | S_IWUSR, show_block_attr, set_block_attr);
+
+static ssize_t
+show_block_attr(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	unsigned int val;
+	ssize_t ret = 0;
+	struct mmc_card *card = container_of(dev, struct mmc_card, dev);
+	mmc_claim_host(card->host);
+	if (attr == &dev_attr_page_size)
+		val = card->page_size;
+	else
+		ret = -EINVAL;
+
+	mmc_release_host(card->host);
+	if (!ret)
+		ret = sprintf(buf, "%u\n", val);
+	return ret;
+}
+
+static ssize_t
+set_block_attr(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	ssize_t ret;
+	char *after;
+	unsigned int val, *dest = NULL;
+	struct mmc_card *card = container_of(dev, struct mmc_card, dev);
+	val = simple_strtoul(buf, &after, 10);
+	ret = after - buf;
+
+	while (isspace(*after++))
+		ret++;
+
+	if (ret != count)
+		return -EINVAL;
+
+	if (attr == &dev_attr_page_size)
+		dest = &card->page_size;
+	else
+		return -EINVAL;
+
+	if (dest) {
+		mmc_claim_host(card->host);
+		*dest = val;
+		mmc_release_host(card->host);
+	}
+	return ret;
+}
+
+static struct attribute *capability_attrs[] = {
+	&dev_attr_page_size.attr,
+	NULL,
+};
+
+static struct attribute_group attr_group = {
+        .attrs = capability_attrs,
+};
+
 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 {
 	struct mmc_blk_data *md;
@@ -312,6 +381,38 @@ out:
 	return err ? 0 : 1;
 }
 
+
+/*
+ * If the request is not aligned, split it into an unaligned
+ * and an aligned portion. Here we can adjust
+ * the size of the MMC request and let the block layer request handle
+ * deal with generating another MMC request.
+ */
+static bool mmc_adjust_write(struct mmc_card *card,
+			     struct mmc_request *mrq)
+{
+	unsigned int left_in_page;
+	unsigned int page_size_blocks;
+
+	if (!card->page_size)
+		return false;
+
+	page_size_blocks = card->page_size / mrq->data->blksz;
+	left_in_page = page_size_blocks -
+		(mrq->cmd->arg % page_size_blocks);
+
+	/* Aligned access. */
+	if (left_in_page == page_size_blocks)
+		return false;
+
+	/* Not straddling page boundary. */
+	if (mrq->data->blocks <= left_in_page)
+		return false;
+
+	mrq->data->blocks = left_in_page;
+	return true;
+}
+
 static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
@@ -339,6 +440,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
 		brq.data.blocks = blk_rq_sectors(req);
 
+		/* Check for unaligned accesses straddling pages. */
+		if (rq_data_dir(req) == WRITE)
+			mmc_adjust_write(card, &brq.mrq);
+
 		/*
 		 * The block layer doesn't support all sector count
 		 * restrictions, so we need to be prepared for too big
@@ -707,6 +812,10 @@ static int mmc_blk_probe(struct mmc_card *card)
 	if (err)
 		goto out;
 
+	err = sysfs_create_group(&card->dev.kobj, &attr_group);
+	if (err)
+		goto out;
+
 	string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2,
 			cap_str, sizeof(cap_str));
 	printk(KERN_INFO "%s: %s %s %s %s\n",
@@ -735,6 +844,8 @@ static void mmc_blk_remove(struct mmc_card *card)
 		/* Stop new requests from getting into the queue */
 		del_gendisk(md->disk);
 
+		sysfs_remove_group(&card->dev.kobj, &attr_group);
+
 		/* Then flush out any already in there */
 		mmc_cleanup_queue(&md->queue);
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 6b75250..d52768a 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -123,7 +123,7 @@ struct mmc_card {
 	unsigned int		erase_size;	/* erase size in sectors */
  	unsigned int		erase_shift;	/* if erase unit is power 2 */
  	unsigned int		pref_erase;	/* in sectors */
+ 	unsigned int		page_size;	/* page size in bytes */
  	u8			erased_byte;	/* value of erased bytes */
 
 	u32			raw_cid[4];	/* raw card CID */
-- 
1.7.0.4

Reply via email to