diff options
author | Per Forlin <per.forlin@linaro.org> | 2011-07-01 12:55:26 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-07-20 17:21:12 -0400 |
commit | 9f9c4180f88d127e2bb83913d80750a8fbdb8f3e (patch) | |
tree | 85a4be48d2eb4b2360e1a86e662174ca4078eeb0 /drivers/mmc | |
parent | 54f3caf5bcb732c9ac48308b7b43eb9aaa7ed8ca (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.c | 318 |
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 | ||
151 | enum 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 | |||
157 | struct 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 | |||
166 | struct 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 | */ |
663 | static int mmc_test_check_result(struct mmc_test_card *test, | 683 | static 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 | ||
708 | static 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 | */ | ||
756 | static 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 | } | ||
770 | static 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; | ||
828 | err: | ||
829 | return ret; | ||
830 | } | ||
831 | |||
832 | /* | ||
723 | * Tests a basic transfer with certain parameters | 833 | * Tests a basic transfer with certain parameters |
724 | */ | 834 | */ |
725 | static int mmc_test_simple_transfer(struct mmc_test_card *test, | 835 | static 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 | */ |
1341 | static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz, | 1451 | static 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 | ||
1504 | static 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 | ||
2085 | static 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 | |||
2134 | static 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 | */ | ||
2159 | static 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 | */ | ||
2178 | static 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 | */ | ||
2197 | static 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 | */ | ||
2216 | static 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 | |||
1957 | static const struct mmc_test_case mmc_test_cases[] = { | 2232 | static 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 | ||
2226 | static DEFINE_MUTEX(mmc_test_lock); | 2528 | static DEFINE_MUTEX(mmc_test_lock); |