summary refs log tree commit diff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorPierre Ossman <drzeus@drzeus.cx>2008-07-21 00:14:52 +0200
committerPierre Ossman <drzeus@drzeus.cx>2008-07-23 14:42:08 +0200
commit48b5352ea1891455eb8e824cf7d92f66931a090f (patch)
tree5068eb9fb3d16e0f1353a662b48c370fdabfcd7e /drivers/mmc
parent2661081f5ab9cb25359d27f88707a018cf4e68e9 (diff)
downloadlinux-48b5352ea1891455eb8e824cf7d92f66931a090f.tar.gz
mmc_test: test oversized sg lists
Add tests that make sure the driver properly checks the blocks and
blksz fields and doesn't assume the sg list has a size that perfectly
matches the current request.

Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/card/mmc_test.c85
1 files changed, 82 insertions, 3 deletions
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 6fc13d4c634a..25296011df59 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -388,14 +388,16 @@ static int mmc_test_transfer(struct mmc_test_card *test,
 	int ret, i;
 	unsigned long flags;
 
+	BUG_ON(blocks * blksz > BUFFER_SIZE);
+
 	if (write) {
 		for (i = 0;i < blocks * blksz;i++)
 			test->scratch[i] = i;
 	} else {
-		memset(test->scratch, 0, BUFFER_SIZE);
+		memset(test->scratch, 0, blocks * blksz);
 	}
 	local_irq_save(flags);
-	sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
+	sg_copy_from_buffer(sg, sg_len, test->scratch, blocks * blksz);
 	local_irq_restore(flags);
 
 	ret = mmc_test_set_blksize(test, blksz);
@@ -442,7 +444,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
 		}
 	} else {
 		local_irq_save(flags);
-		sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
+		sg_copy_to_buffer(sg, sg_len, test->scratch, blocks * blksz);
 		local_irq_restore(flags);
 		for (i = 0;i < blocks * blksz;i++) {
 			if (test->scratch[i] != (u8)i)
@@ -803,6 +805,69 @@ static int mmc_test_multi_xfersize_read(struct mmc_test_card *test)
 	return 0;
 }
 
+static int mmc_test_bigsg_write(struct mmc_test_card *test)
+{
+	int ret;
+	unsigned int size;
+	struct scatterlist sg;
+
+	if (test->card->host->max_blk_count == 1)
+		return RESULT_UNSUP_HOST;
+
+	size = PAGE_SIZE * 2;
+	size = min(size, test->card->host->max_req_size);
+	size = min(size, test->card->host->max_seg_size);
+	size = min(size, test->card->host->max_blk_count * 512);
+
+	memset(test->buffer, 0, BUFFER_SIZE);
+
+	if (size < 1024)
+		return RESULT_UNSUP_HOST;
+
+	sg_init_table(&sg, 1);
+	sg_init_one(&sg, test->buffer, BUFFER_SIZE);
+
+	ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int mmc_test_bigsg_read(struct mmc_test_card *test)
+{
+	int ret, i;
+	unsigned int size;
+	struct scatterlist sg;
+
+	if (test->card->host->max_blk_count == 1)
+		return RESULT_UNSUP_HOST;
+
+	size = PAGE_SIZE * 2;
+	size = min(size, test->card->host->max_req_size);
+	size = min(size, test->card->host->max_seg_size);
+	size = min(size, test->card->host->max_blk_count * 512);
+
+	if (size < 1024)
+		return RESULT_UNSUP_HOST;
+
+	memset(test->buffer, 0xCD, BUFFER_SIZE);
+
+	sg_init_table(&sg, 1);
+	sg_init_one(&sg, test->buffer, BUFFER_SIZE);
+	ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
+	if (ret)
+		return ret;
+
+	/* mmc_test_transfer() doesn't check for read overflows */
+	for (i = size;i < BUFFER_SIZE;i++) {
+		if (test->buffer[i] != 0xCD)
+			return RESULT_FAIL;
+	}
+
+	return 0;
+}
+
 #ifdef CONFIG_HIGHMEM
 
 static int mmc_test_write_high(struct mmc_test_card *test)
@@ -1006,6 +1071,20 @@ static const struct mmc_test_case mmc_test_cases[] = {
 		.run = mmc_test_multi_xfersize_read,
 	},
 
+	{
+		.name = "Over-sized SG list write",
+		.prepare = mmc_test_prepare_write,
+		.run = mmc_test_bigsg_write,
+		.cleanup = mmc_test_cleanup,
+	},
+
+	{
+		.name = "Over-sized SG list read",
+		.prepare = mmc_test_prepare_read,
+		.run = mmc_test_bigsg_read,
+		.cleanup = mmc_test_cleanup,
+	},
+
 #ifdef CONFIG_HIGHMEM
 
 	{