aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorPer Forlin <per.forlin@linaro.org>2011-07-01 12:55:26 -0400
committerChris Ball <cjb@laptop.org>2011-07-20 17:21:12 -0400
commit9f9c4180f88d127e2bb83913d80750a8fbdb8f3e (patch)
tree85a4be48d2eb4b2360e1a86e662174ca4078eeb0 /drivers/mmc
parent54f3caf5bcb732c9ac48308b7b43eb9aaa7ed8ca (diff)
mmc: mmc_test: add test for non-blocking transfers
Add four tests for read and write performance per different transfer size, 4k to 4M. * Read using blocking mmc request * Read using non-blocking mmc request * Write using blocking mmc request * Write using non-blocking mmc request The host driver must support pre_req() and post_req() in order to run the non-blocking test cases. Signed-off-by: Per Forlin <per.forlin@linaro.org> Acked-by: Kyungmin Park <kyungmin.park@samsung.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Reviewed-by: Venkatraman S <svenkatr@ti.com> Tested-by: Sourav Poddar<sourav.poddar@ti.com> Tested-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/card/mmc_test.c318
1 files changed, 310 insertions, 8 deletions
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index e8508e99aed5..51031a54470f 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -148,6 +148,26 @@ struct mmc_test_card {
148 struct mmc_test_general_result *gr; 148 struct mmc_test_general_result *gr;
149}; 149};
150 150
151enum mmc_test_prep_media {
152 MMC_TEST_PREP_NONE = 0,
153 MMC_TEST_PREP_WRITE_FULL = 1 << 0,
154 MMC_TEST_PREP_ERASE = 1 << 1,
155};
156
157struct mmc_test_multiple_rw {
158 unsigned int *bs;
159 unsigned int len;
160 unsigned int size;
161 bool do_write;
162 bool do_nonblock_req;
163 enum mmc_test_prep_media prepare;
164};
165
166struct mmc_test_async_req {
167 struct mmc_async_req areq;
168 struct mmc_test_card *test;
169};
170
151/*******************************************************************/ 171/*******************************************************************/
152/* General helper functions */ 172/* General helper functions */
153/*******************************************************************/ 173/*******************************************************************/
@@ -661,7 +681,7 @@ static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test,
661 * Checks that a normal transfer didn't have any errors 681 * Checks that a normal transfer didn't have any errors
662 */ 682 */
663static int mmc_test_check_result(struct mmc_test_card *test, 683static int mmc_test_check_result(struct mmc_test_card *test,
664 struct mmc_request *mrq) 684 struct mmc_request *mrq)
665{ 685{
666 int ret; 686 int ret;
667 687
@@ -685,6 +705,17 @@ static int mmc_test_check_result(struct mmc_test_card *test,
685 return ret; 705 return ret;
686} 706}
687 707
708static int mmc_test_check_result_async(struct mmc_card *card,
709 struct mmc_async_req *areq)
710{
711 struct mmc_test_async_req *test_async =
712 container_of(areq, struct mmc_test_async_req, areq);
713
714 mmc_test_wait_busy(test_async->test);
715
716 return mmc_test_check_result(test_async->test, areq->mrq);
717}
718
688/* 719/*
689 * Checks that a "short transfer" behaved as expected 720 * Checks that a "short transfer" behaved as expected
690 */ 721 */
@@ -720,6 +751,85 @@ static int mmc_test_check_broken_result(struct mmc_test_card *test,
720} 751}
721 752
722/* 753/*
754 * Tests nonblock transfer with certain parameters
755 */
756static void mmc_test_nonblock_reset(struct mmc_request *mrq,
757 struct mmc_command *cmd,
758 struct mmc_command *stop,
759 struct mmc_data *data)
760{
761 memset(mrq, 0, sizeof(struct mmc_request));
762 memset(cmd, 0, sizeof(struct mmc_command));
763 memset(data, 0, sizeof(struct mmc_data));
764 memset(stop, 0, sizeof(struct mmc_command));
765
766 mrq->cmd = cmd;
767 mrq->data = data;
768 mrq->stop = stop;
769}
770static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
771 struct scatterlist *sg, unsigned sg_len,
772 unsigned dev_addr, unsigned blocks,
773 unsigned blksz, int write, int count)
774{
775 struct mmc_request mrq1;
776 struct mmc_command cmd1;
777 struct mmc_command stop1;
778 struct mmc_data data1;
779
780 struct mmc_request mrq2;
781 struct mmc_command cmd2;
782 struct mmc_command stop2;
783 struct mmc_data data2;
784
785 struct mmc_test_async_req test_areq[2];
786 struct mmc_async_req *done_areq;
787 struct mmc_async_req *cur_areq = &test_areq[0].areq;
788 struct mmc_async_req *other_areq = &test_areq[1].areq;
789 int i;
790 int ret;
791
792 test_areq[0].test = test;
793 test_areq[1].test = test;
794
795 mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1);
796 mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2);
797
798 cur_areq->mrq = &mrq1;
799 cur_areq->err_check = mmc_test_check_result_async;
800 other_areq->mrq = &mrq2;
801 other_areq->err_check = mmc_test_check_result_async;
802
803 for (i = 0; i < count; i++) {
804 mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr,
805 blocks, blksz, write);
806 done_areq = mmc_start_req(test->card->host, cur_areq, &ret);
807
808 if (ret || (!done_areq && i > 0))
809 goto err;
810
811 if (done_areq) {
812 if (done_areq->mrq == &mrq2)
813 mmc_test_nonblock_reset(&mrq2, &cmd2,
814 &stop2, &data2);
815 else
816 mmc_test_nonblock_reset(&mrq1, &cmd1,
817 &stop1, &data1);
818 }
819 done_areq = cur_areq;
820 cur_areq = other_areq;
821 other_areq = done_areq;
822 dev_addr += blocks;
823 }
824
825 done_areq = mmc_start_req(test->card->host, NULL, &ret);
826
827 return ret;
828err:
829 return ret;
830}
831
832/*
723 * Tests a basic transfer with certain parameters 833 * Tests a basic transfer with certain parameters
724 */ 834 */
725static int mmc_test_simple_transfer(struct mmc_test_card *test, 835static int mmc_test_simple_transfer(struct mmc_test_card *test,
@@ -1336,14 +1446,17 @@ static int mmc_test_area_transfer(struct mmc_test_card *test,
1336} 1446}
1337 1447
1338/* 1448/*
1339 * Map and transfer bytes. 1449 * Map and transfer bytes for multiple transfers.
1340 */ 1450 */
1341static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz, 1451static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
1342 unsigned int dev_addr, int write, int max_scatter, 1452 unsigned int dev_addr, int write,
1343 int timed) 1453 int max_scatter, int timed, int count,
1454 bool nonblock)
1344{ 1455{
1345 struct timespec ts1, ts2; 1456 struct timespec ts1, ts2;
1346 int ret; 1457 int ret = 0;
1458 int i;
1459 struct mmc_test_area *t = &test->area;
1347 1460
1348 /* 1461 /*
1349 * In the case of a maximally scattered transfer, the maximum transfer 1462 * In the case of a maximally scattered transfer, the maximum transfer
@@ -1367,8 +1480,15 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
1367 1480
1368 if (timed) 1481 if (timed)
1369 getnstimeofday(&ts1); 1482 getnstimeofday(&ts1);
1483 if (nonblock)
1484 ret = mmc_test_nonblock_transfer(test, t->sg, t->sg_len,
1485 dev_addr, t->blocks, 512, write, count);
1486 else
1487 for (i = 0; i < count && ret == 0; i++) {
1488 ret = mmc_test_area_transfer(test, dev_addr, write);
1489 dev_addr += sz >> 9;
1490 }
1370 1491
1371 ret = mmc_test_area_transfer(test, dev_addr, write);
1372 if (ret) 1492 if (ret)
1373 return ret; 1493 return ret;
1374 1494
@@ -1376,11 +1496,19 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
1376 getnstimeofday(&ts2); 1496 getnstimeofday(&ts2);
1377 1497
1378 if (timed) 1498 if (timed)
1379 mmc_test_print_rate(test, sz, &ts1, &ts2); 1499 mmc_test_print_avg_rate(test, sz, count, &ts1, &ts2);
1380 1500
1381 return 0; 1501 return 0;
1382} 1502}
1383 1503
1504static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
1505 unsigned int dev_addr, int write, int max_scatter,
1506 int timed)
1507{
1508 return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter,
1509 timed, 1, false);
1510}
1511
1384/* 1512/*
1385 * Write the test area entirely. 1513 * Write the test area entirely.
1386 */ 1514 */
@@ -1954,6 +2082,153 @@ static int mmc_test_large_seq_write_perf(struct mmc_test_card *test)
1954 return mmc_test_large_seq_perf(test, 1); 2082 return mmc_test_large_seq_perf(test, 1);
1955} 2083}
1956 2084
2085static int mmc_test_rw_multiple(struct mmc_test_card *test,
2086 struct mmc_test_multiple_rw *tdata,
2087 unsigned int reqsize, unsigned int size)
2088{
2089 unsigned int dev_addr;
2090 struct mmc_test_area *t = &test->area;
2091 int ret = 0;
2092
2093 /* Set up test area */
2094 if (size > mmc_test_capacity(test->card) / 2 * 512)
2095 size = mmc_test_capacity(test->card) / 2 * 512;
2096 if (reqsize > t->max_tfr)
2097 reqsize = t->max_tfr;
2098 dev_addr = mmc_test_capacity(test->card) / 4;
2099 if ((dev_addr & 0xffff0000))
2100 dev_addr &= 0xffff0000; /* Round to 64MiB boundary */
2101 else
2102 dev_addr &= 0xfffff800; /* Round to 1MiB boundary */
2103 if (!dev_addr)
2104 goto err;
2105
2106 if (reqsize > size)
2107 return 0;
2108
2109 /* prepare test area */
2110 if (mmc_can_erase(test->card) &&
2111 tdata->prepare & MMC_TEST_PREP_ERASE) {
2112 ret = mmc_erase(test->card, dev_addr,
2113 size / 512, MMC_SECURE_ERASE_ARG);
2114 if (ret)
2115 ret = mmc_erase(test->card, dev_addr,
2116 size / 512, MMC_ERASE_ARG);
2117 if (ret)
2118 goto err;
2119 }
2120
2121 /* Run test */
2122 ret = mmc_test_area_io_seq(test, reqsize, dev_addr,
2123 tdata->do_write, 0, 1, size / reqsize,
2124 tdata->do_nonblock_req);
2125 if (ret)
2126 goto err;
2127
2128 return ret;
2129 err:
2130 printk(KERN_INFO "[%s] error\n", __func__);
2131 return ret;
2132}
2133
2134static int mmc_test_rw_multiple_size(struct mmc_test_card *test,
2135 struct mmc_test_multiple_rw *rw)
2136{
2137 int ret = 0;
2138 int i;
2139 void *pre_req = test->card->host->ops->pre_req;
2140 void *post_req = test->card->host->ops->post_req;
2141
2142 if (rw->do_nonblock_req &&
2143 ((!pre_req && post_req) || (pre_req && !post_req))) {
2144 printk(KERN_INFO "error: only one of pre/post is defined\n");
2145 return -EINVAL;
2146 }
2147
2148 for (i = 0 ; i < rw->len && ret == 0; i++) {
2149 ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size);
2150 if (ret)
2151 break;
2152 }
2153 return ret;
2154}
2155
2156/*
2157 * Multiple blocking write 4k to 4 MB chunks
2158 */
2159static int mmc_test_profile_mult_write_blocking_perf(struct mmc_test_card *test)
2160{
2161 unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
2162 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
2163 struct mmc_test_multiple_rw test_data = {
2164 .bs = bs,
2165 .size = TEST_AREA_MAX_SIZE,
2166 .len = ARRAY_SIZE(bs),
2167 .do_write = true,
2168 .do_nonblock_req = false,
2169 .prepare = MMC_TEST_PREP_ERASE,
2170 };
2171
2172 return mmc_test_rw_multiple_size(test, &test_data);
2173};
2174
2175/*
2176 * Multiple non-blocking write 4k to 4 MB chunks
2177 */
2178static int mmc_test_profile_mult_write_nonblock_perf(struct mmc_test_card *test)
2179{
2180 unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
2181 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
2182 struct mmc_test_multiple_rw test_data = {
2183 .bs = bs,
2184 .size = TEST_AREA_MAX_SIZE,
2185 .len = ARRAY_SIZE(bs),
2186 .do_write = true,
2187 .do_nonblock_req = true,
2188 .prepare = MMC_TEST_PREP_ERASE,
2189 };
2190
2191 return mmc_test_rw_multiple_size(test, &test_data);
2192}
2193
2194/*
2195 * Multiple blocking read 4k to 4 MB chunks
2196 */
2197static int mmc_test_profile_mult_read_blocking_perf(struct mmc_test_card *test)
2198{
2199 unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
2200 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
2201 struct mmc_test_multiple_rw test_data = {
2202 .bs = bs,
2203 .size = TEST_AREA_MAX_SIZE,
2204 .len = ARRAY_SIZE(bs),
2205 .do_write = false,
2206 .do_nonblock_req = false,
2207 .prepare = MMC_TEST_PREP_NONE,
2208 };
2209
2210 return mmc_test_rw_multiple_size(test, &test_data);
2211}
2212
2213/*
2214 * Multiple non-blocking read 4k to 4 MB chunks
2215 */
2216static int mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card *test)
2217{
2218 unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
2219 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
2220 struct mmc_test_multiple_rw test_data = {
2221 .bs = bs,
2222 .size = TEST_AREA_MAX_SIZE,
2223 .len = ARRAY_SIZE(bs),
2224 .do_write = false,
2225 .do_nonblock_req = true,
2226 .prepare = MMC_TEST_PREP_NONE,
2227 };
2228
2229 return mmc_test_rw_multiple_size(test, &test_data);
2230}
2231
1957static const struct mmc_test_case mmc_test_cases[] = { 2232static const struct mmc_test_case mmc_test_cases[] = {
1958 { 2233 {
1959 .name = "Basic write (no data verification)", 2234 .name = "Basic write (no data verification)",
@@ -2221,6 +2496,33 @@ static const struct mmc_test_case mmc_test_cases[] = {
2221 .cleanup = mmc_test_area_cleanup, 2496 .cleanup = mmc_test_area_cleanup,
2222 }, 2497 },
2223 2498
2499 {
2500 .name = "Write performance with blocking req 4k to 4MB",
2501 .prepare = mmc_test_area_prepare,
2502 .run = mmc_test_profile_mult_write_blocking_perf,
2503 .cleanup = mmc_test_area_cleanup,
2504 },
2505
2506 {
2507 .name = "Write performance with non-blocking req 4k to 4MB",
2508 .prepare = mmc_test_area_prepare,
2509 .run = mmc_test_profile_mult_write_nonblock_perf,
2510 .cleanup = mmc_test_area_cleanup,
2511 },
2512
2513 {
2514 .name = "Read performance with blocking req 4k to 4MB",
2515 .prepare = mmc_test_area_prepare,
2516 .run = mmc_test_profile_mult_read_blocking_perf,
2517 .cleanup = mmc_test_area_cleanup,
2518 },
2519
2520 {
2521 .name = "Read performance with non-blocking req 4k to 4MB",
2522 .prepare = mmc_test_area_prepare,
2523 .run = mmc_test_profile_mult_read_nonblock_perf,
2524 .cleanup = mmc_test_area_cleanup,
2525 },
2224}; 2526};
2225 2527
2226static DEFINE_MUTEX(mmc_test_lock); 2528static DEFINE_MUTEX(mmc_test_lock);