diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/mmc/card/mmc_test.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/mmc/card/mmc_test.c')
-rw-r--r-- | drivers/mmc/card/mmc_test.c | 811 |
1 files changed, 671 insertions, 140 deletions
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 5dd8576b5c18..233cdfae92f4 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c | |||
@@ -17,6 +17,11 @@ | |||
17 | 17 | ||
18 | #include <linux/scatterlist.h> | 18 | #include <linux/scatterlist.h> |
19 | #include <linux/swap.h> /* For nr_free_buffer_pages() */ | 19 | #include <linux/swap.h> /* For nr_free_buffer_pages() */ |
20 | #include <linux/list.h> | ||
21 | |||
22 | #include <linux/debugfs.h> | ||
23 | #include <linux/uaccess.h> | ||
24 | #include <linux/seq_file.h> | ||
20 | 25 | ||
21 | #define RESULT_OK 0 | 26 | #define RESULT_OK 0 |
22 | #define RESULT_FAIL 1 | 27 | #define RESULT_FAIL 1 |
@@ -56,7 +61,9 @@ struct mmc_test_mem { | |||
56 | * struct mmc_test_area - information for performance tests. | 61 | * struct mmc_test_area - information for performance tests. |
57 | * @max_sz: test area size (in bytes) | 62 | * @max_sz: test area size (in bytes) |
58 | * @dev_addr: address on card at which to do performance tests | 63 | * @dev_addr: address on card at which to do performance tests |
59 | * @max_segs: maximum segments in scatterlist @sg | 64 | * @max_tfr: maximum transfer size allowed by driver (in bytes) |
65 | * @max_segs: maximum segments allowed by driver in scatterlist @sg | ||
66 | * @max_seg_sz: maximum segment size allowed by driver | ||
60 | * @blocks: number of (512 byte) blocks currently mapped by @sg | 67 | * @blocks: number of (512 byte) blocks currently mapped by @sg |
61 | * @sg_len: length of currently mapped scatterlist @sg | 68 | * @sg_len: length of currently mapped scatterlist @sg |
62 | * @mem: allocated memory | 69 | * @mem: allocated memory |
@@ -65,7 +72,9 @@ struct mmc_test_mem { | |||
65 | struct mmc_test_area { | 72 | struct mmc_test_area { |
66 | unsigned long max_sz; | 73 | unsigned long max_sz; |
67 | unsigned int dev_addr; | 74 | unsigned int dev_addr; |
75 | unsigned int max_tfr; | ||
68 | unsigned int max_segs; | 76 | unsigned int max_segs; |
77 | unsigned int max_seg_sz; | ||
69 | unsigned int blocks; | 78 | unsigned int blocks; |
70 | unsigned int sg_len; | 79 | unsigned int sg_len; |
71 | struct mmc_test_mem *mem; | 80 | struct mmc_test_mem *mem; |
@@ -73,12 +82,59 @@ struct mmc_test_area { | |||
73 | }; | 82 | }; |
74 | 83 | ||
75 | /** | 84 | /** |
85 | * struct mmc_test_transfer_result - transfer results for performance tests. | ||
86 | * @link: double-linked list | ||
87 | * @count: amount of group of sectors to check | ||
88 | * @sectors: amount of sectors to check in one group | ||
89 | * @ts: time values of transfer | ||
90 | * @rate: calculated transfer rate | ||
91 | * @iops: I/O operations per second (times 100) | ||
92 | */ | ||
93 | struct mmc_test_transfer_result { | ||
94 | struct list_head link; | ||
95 | unsigned int count; | ||
96 | unsigned int sectors; | ||
97 | struct timespec ts; | ||
98 | unsigned int rate; | ||
99 | unsigned int iops; | ||
100 | }; | ||
101 | |||
102 | /** | ||
103 | * struct mmc_test_general_result - results for tests. | ||
104 | * @link: double-linked list | ||
105 | * @card: card under test | ||
106 | * @testcase: number of test case | ||
107 | * @result: result of test run | ||
108 | * @tr_lst: transfer measurements if any as mmc_test_transfer_result | ||
109 | */ | ||
110 | struct mmc_test_general_result { | ||
111 | struct list_head link; | ||
112 | struct mmc_card *card; | ||
113 | int testcase; | ||
114 | int result; | ||
115 | struct list_head tr_lst; | ||
116 | }; | ||
117 | |||
118 | /** | ||
119 | * struct mmc_test_dbgfs_file - debugfs related file. | ||
120 | * @link: double-linked list | ||
121 | * @card: card under test | ||
122 | * @file: file created under debugfs | ||
123 | */ | ||
124 | struct mmc_test_dbgfs_file { | ||
125 | struct list_head link; | ||
126 | struct mmc_card *card; | ||
127 | struct dentry *file; | ||
128 | }; | ||
129 | |||
130 | /** | ||
76 | * struct mmc_test_card - test information. | 131 | * struct mmc_test_card - test information. |
77 | * @card: card under test | 132 | * @card: card under test |
78 | * @scratch: transfer buffer | 133 | * @scratch: transfer buffer |
79 | * @buffer: transfer buffer | 134 | * @buffer: transfer buffer |
80 | * @highmem: buffer for highmem tests | 135 | * @highmem: buffer for highmem tests |
81 | * @area: information for performance tests | 136 | * @area: information for performance tests |
137 | * @gr: pointer to results of current testcase | ||
82 | */ | 138 | */ |
83 | struct mmc_test_card { | 139 | struct mmc_test_card { |
84 | struct mmc_card *card; | 140 | struct mmc_card *card; |
@@ -88,7 +144,8 @@ struct mmc_test_card { | |||
88 | #ifdef CONFIG_HIGHMEM | 144 | #ifdef CONFIG_HIGHMEM |
89 | struct page *highmem; | 145 | struct page *highmem; |
90 | #endif | 146 | #endif |
91 | struct mmc_test_area area; | 147 | struct mmc_test_area area; |
148 | struct mmc_test_general_result *gr; | ||
92 | }; | 149 | }; |
93 | 150 | ||
94 | /*******************************************************************/ | 151 | /*******************************************************************/ |
@@ -100,17 +157,7 @@ struct mmc_test_card { | |||
100 | */ | 157 | */ |
101 | static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size) | 158 | static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size) |
102 | { | 159 | { |
103 | struct mmc_command cmd; | 160 | return mmc_set_blocklen(test->card, size); |
104 | int ret; | ||
105 | |||
106 | cmd.opcode = MMC_SET_BLOCKLEN; | ||
107 | cmd.arg = size; | ||
108 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
109 | ret = mmc_wait_for_cmd(test->card->host, &cmd, 0); | ||
110 | if (ret) | ||
111 | return ret; | ||
112 | |||
113 | return 0; | ||
114 | } | 161 | } |
115 | 162 | ||
116 | /* | 163 | /* |
@@ -165,7 +212,7 @@ static int mmc_test_busy(struct mmc_command *cmd) | |||
165 | static int mmc_test_wait_busy(struct mmc_test_card *test) | 212 | static int mmc_test_wait_busy(struct mmc_test_card *test) |
166 | { | 213 | { |
167 | int ret, busy; | 214 | int ret, busy; |
168 | struct mmc_command cmd; | 215 | struct mmc_command cmd = {0}; |
169 | 216 | ||
170 | busy = 0; | 217 | busy = 0; |
171 | do { | 218 | do { |
@@ -181,9 +228,10 @@ static int mmc_test_wait_busy(struct mmc_test_card *test) | |||
181 | 228 | ||
182 | if (!busy && mmc_test_busy(&cmd)) { | 229 | if (!busy && mmc_test_busy(&cmd)) { |
183 | busy = 1; | 230 | busy = 1; |
184 | printk(KERN_INFO "%s: Warning: Host did not " | 231 | if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) |
185 | "wait for busy state to end.\n", | 232 | printk(KERN_INFO "%s: Warning: Host did not " |
186 | mmc_hostname(test->card->host)); | 233 | "wait for busy state to end.\n", |
234 | mmc_hostname(test->card->host)); | ||
187 | } | 235 | } |
188 | } while (mmc_test_busy(&cmd)); | 236 | } while (mmc_test_busy(&cmd)); |
189 | 237 | ||
@@ -198,18 +246,13 @@ static int mmc_test_buffer_transfer(struct mmc_test_card *test, | |||
198 | { | 246 | { |
199 | int ret; | 247 | int ret; |
200 | 248 | ||
201 | struct mmc_request mrq; | 249 | struct mmc_request mrq = {0}; |
202 | struct mmc_command cmd; | 250 | struct mmc_command cmd = {0}; |
203 | struct mmc_command stop; | 251 | struct mmc_command stop = {0}; |
204 | struct mmc_data data; | 252 | struct mmc_data data = {0}; |
205 | 253 | ||
206 | struct scatterlist sg; | 254 | struct scatterlist sg; |
207 | 255 | ||
208 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
209 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
210 | memset(&data, 0, sizeof(struct mmc_data)); | ||
211 | memset(&stop, 0, sizeof(struct mmc_command)); | ||
212 | |||
213 | mrq.cmd = &cmd; | 256 | mrq.cmd = &cmd; |
214 | mrq.data = &data; | 257 | mrq.data = &data; |
215 | mrq.stop = &stop; | 258 | mrq.stop = &stop; |
@@ -244,28 +287,39 @@ static void mmc_test_free_mem(struct mmc_test_mem *mem) | |||
244 | } | 287 | } |
245 | 288 | ||
246 | /* | 289 | /* |
247 | * Allocate a lot of memory, preferrably max_sz but at least min_sz. In case | 290 | * Allocate a lot of memory, preferably max_sz but at least min_sz. In case |
248 | * there isn't much memory do not exceed 1/16th total lowmem pages. | 291 | * there isn't much memory do not exceed 1/16th total lowmem pages. Also do |
292 | * not exceed a maximum number of segments and try not to make segments much | ||
293 | * bigger than maximum segment size. | ||
249 | */ | 294 | */ |
250 | static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz, | 295 | static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz, |
251 | unsigned long max_sz) | 296 | unsigned long max_sz, |
297 | unsigned int max_segs, | ||
298 | unsigned int max_seg_sz) | ||
252 | { | 299 | { |
253 | unsigned long max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE); | 300 | unsigned long max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE); |
254 | unsigned long min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE); | 301 | unsigned long min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE); |
302 | unsigned long max_seg_page_cnt = DIV_ROUND_UP(max_seg_sz, PAGE_SIZE); | ||
255 | unsigned long page_cnt = 0; | 303 | unsigned long page_cnt = 0; |
256 | unsigned long limit = nr_free_buffer_pages() >> 4; | 304 | unsigned long limit = nr_free_buffer_pages() >> 4; |
257 | struct mmc_test_mem *mem; | 305 | struct mmc_test_mem *mem; |
258 | 306 | ||
259 | if (max_page_cnt > limit) | 307 | if (max_page_cnt > limit) |
260 | max_page_cnt = limit; | 308 | max_page_cnt = limit; |
261 | if (max_page_cnt < min_page_cnt) | 309 | if (min_page_cnt > max_page_cnt) |
262 | max_page_cnt = min_page_cnt; | 310 | min_page_cnt = max_page_cnt; |
311 | |||
312 | if (max_seg_page_cnt > max_page_cnt) | ||
313 | max_seg_page_cnt = max_page_cnt; | ||
314 | |||
315 | if (max_segs > max_page_cnt) | ||
316 | max_segs = max_page_cnt; | ||
263 | 317 | ||
264 | mem = kzalloc(sizeof(struct mmc_test_mem), GFP_KERNEL); | 318 | mem = kzalloc(sizeof(struct mmc_test_mem), GFP_KERNEL); |
265 | if (!mem) | 319 | if (!mem) |
266 | return NULL; | 320 | return NULL; |
267 | 321 | ||
268 | mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_page_cnt, | 322 | mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_segs, |
269 | GFP_KERNEL); | 323 | GFP_KERNEL); |
270 | if (!mem->arr) | 324 | if (!mem->arr) |
271 | goto out_free; | 325 | goto out_free; |
@@ -276,7 +330,7 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz, | |||
276 | gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN | | 330 | gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN | |
277 | __GFP_NORETRY; | 331 | __GFP_NORETRY; |
278 | 332 | ||
279 | order = get_order(max_page_cnt << PAGE_SHIFT); | 333 | order = get_order(max_seg_page_cnt << PAGE_SHIFT); |
280 | while (1) { | 334 | while (1) { |
281 | page = alloc_pages(flags, order); | 335 | page = alloc_pages(flags, order); |
282 | if (page || !order) | 336 | if (page || !order) |
@@ -295,6 +349,11 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz, | |||
295 | break; | 349 | break; |
296 | max_page_cnt -= 1UL << order; | 350 | max_page_cnt -= 1UL << order; |
297 | page_cnt += 1UL << order; | 351 | page_cnt += 1UL << order; |
352 | if (mem->cnt >= max_segs) { | ||
353 | if (page_cnt < min_page_cnt) | ||
354 | goto out_free; | ||
355 | break; | ||
356 | } | ||
298 | } | 357 | } |
299 | 358 | ||
300 | return mem; | 359 | return mem; |
@@ -310,7 +369,8 @@ out_free: | |||
310 | */ | 369 | */ |
311 | static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz, | 370 | static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz, |
312 | struct scatterlist *sglist, int repeat, | 371 | struct scatterlist *sglist, int repeat, |
313 | unsigned int max_segs, unsigned int *sg_len) | 372 | unsigned int max_segs, unsigned int max_seg_sz, |
373 | unsigned int *sg_len) | ||
314 | { | 374 | { |
315 | struct scatterlist *sg = NULL; | 375 | struct scatterlist *sg = NULL; |
316 | unsigned int i; | 376 | unsigned int i; |
@@ -322,8 +382,10 @@ static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz, | |||
322 | for (i = 0; i < mem->cnt; i++) { | 382 | for (i = 0; i < mem->cnt; i++) { |
323 | unsigned long len = PAGE_SIZE << mem->arr[i].order; | 383 | unsigned long len = PAGE_SIZE << mem->arr[i].order; |
324 | 384 | ||
325 | if (sz < len) | 385 | if (len > sz) |
326 | len = sz; | 386 | len = sz; |
387 | if (len > max_seg_sz) | ||
388 | len = max_seg_sz; | ||
327 | if (sg) | 389 | if (sg) |
328 | sg = sg_next(sg); | 390 | sg = sg_next(sg); |
329 | else | 391 | else |
@@ -355,6 +417,7 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem, | |||
355 | unsigned long sz, | 417 | unsigned long sz, |
356 | struct scatterlist *sglist, | 418 | struct scatterlist *sglist, |
357 | unsigned int max_segs, | 419 | unsigned int max_segs, |
420 | unsigned int max_seg_sz, | ||
358 | unsigned int *sg_len) | 421 | unsigned int *sg_len) |
359 | { | 422 | { |
360 | struct scatterlist *sg = NULL; | 423 | struct scatterlist *sg = NULL; |
@@ -365,7 +428,7 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem, | |||
365 | sg_init_table(sglist, max_segs); | 428 | sg_init_table(sglist, max_segs); |
366 | 429 | ||
367 | *sg_len = 0; | 430 | *sg_len = 0; |
368 | while (sz && i) { | 431 | while (sz) { |
369 | base = page_address(mem->arr[--i].page); | 432 | base = page_address(mem->arr[--i].page); |
370 | cnt = 1 << mem->arr[i].order; | 433 | cnt = 1 << mem->arr[i].order; |
371 | while (sz && cnt) { | 434 | while (sz && cnt) { |
@@ -374,7 +437,9 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem, | |||
374 | continue; | 437 | continue; |
375 | last_addr = addr; | 438 | last_addr = addr; |
376 | len = PAGE_SIZE; | 439 | len = PAGE_SIZE; |
377 | if (sz < len) | 440 | if (len > max_seg_sz) |
441 | len = max_seg_sz; | ||
442 | if (len > sz) | ||
378 | len = sz; | 443 | len = sz; |
379 | if (sg) | 444 | if (sg) |
380 | sg = sg_next(sg); | 445 | sg = sg_next(sg); |
@@ -386,6 +451,8 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem, | |||
386 | sz -= len; | 451 | sz -= len; |
387 | *sg_len += 1; | 452 | *sg_len += 1; |
388 | } | 453 | } |
454 | if (i == 0) | ||
455 | i = mem->cnt; | ||
389 | } | 456 | } |
390 | 457 | ||
391 | if (sg) | 458 | if (sg) |
@@ -421,23 +488,52 @@ static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts) | |||
421 | } | 488 | } |
422 | 489 | ||
423 | /* | 490 | /* |
491 | * Save transfer results for future usage | ||
492 | */ | ||
493 | static void mmc_test_save_transfer_result(struct mmc_test_card *test, | ||
494 | unsigned int count, unsigned int sectors, struct timespec ts, | ||
495 | unsigned int rate, unsigned int iops) | ||
496 | { | ||
497 | struct mmc_test_transfer_result *tr; | ||
498 | |||
499 | if (!test->gr) | ||
500 | return; | ||
501 | |||
502 | tr = kmalloc(sizeof(struct mmc_test_transfer_result), GFP_KERNEL); | ||
503 | if (!tr) | ||
504 | return; | ||
505 | |||
506 | tr->count = count; | ||
507 | tr->sectors = sectors; | ||
508 | tr->ts = ts; | ||
509 | tr->rate = rate; | ||
510 | tr->iops = iops; | ||
511 | |||
512 | list_add_tail(&tr->link, &test->gr->tr_lst); | ||
513 | } | ||
514 | |||
515 | /* | ||
424 | * Print the transfer rate. | 516 | * Print the transfer rate. |
425 | */ | 517 | */ |
426 | static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes, | 518 | static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes, |
427 | struct timespec *ts1, struct timespec *ts2) | 519 | struct timespec *ts1, struct timespec *ts2) |
428 | { | 520 | { |
429 | unsigned int rate, sectors = bytes >> 9; | 521 | unsigned int rate, iops, sectors = bytes >> 9; |
430 | struct timespec ts; | 522 | struct timespec ts; |
431 | 523 | ||
432 | ts = timespec_sub(*ts2, *ts1); | 524 | ts = timespec_sub(*ts2, *ts1); |
433 | 525 | ||
434 | rate = mmc_test_rate(bytes, &ts); | 526 | rate = mmc_test_rate(bytes, &ts); |
527 | iops = mmc_test_rate(100, &ts); /* I/O ops per sec x 100 */ | ||
435 | 528 | ||
436 | printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu " | 529 | printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu " |
437 | "seconds (%u kB/s, %u KiB/s)\n", | 530 | "seconds (%u kB/s, %u KiB/s, %u.%02u IOPS)\n", |
438 | mmc_hostname(test->card->host), sectors, sectors >> 1, | 531 | mmc_hostname(test->card->host), sectors, sectors >> 1, |
439 | (sectors == 1 ? ".5" : ""), (unsigned long)ts.tv_sec, | 532 | (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec, |
440 | (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024); | 533 | (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024, |
534 | iops / 100, iops % 100); | ||
535 | |||
536 | mmc_test_save_transfer_result(test, 1, sectors, ts, rate, iops); | ||
441 | } | 537 | } |
442 | 538 | ||
443 | /* | 539 | /* |
@@ -447,20 +543,24 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes, | |||
447 | unsigned int count, struct timespec *ts1, | 543 | unsigned int count, struct timespec *ts1, |
448 | struct timespec *ts2) | 544 | struct timespec *ts2) |
449 | { | 545 | { |
450 | unsigned int rate, sectors = bytes >> 9; | 546 | unsigned int rate, iops, sectors = bytes >> 9; |
451 | uint64_t tot = bytes * count; | 547 | uint64_t tot = bytes * count; |
452 | struct timespec ts; | 548 | struct timespec ts; |
453 | 549 | ||
454 | ts = timespec_sub(*ts2, *ts1); | 550 | ts = timespec_sub(*ts2, *ts1); |
455 | 551 | ||
456 | rate = mmc_test_rate(tot, &ts); | 552 | rate = mmc_test_rate(tot, &ts); |
553 | iops = mmc_test_rate(count * 100, &ts); /* I/O ops per sec x 100 */ | ||
457 | 554 | ||
458 | printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " | 555 | printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " |
459 | "%lu.%09lu seconds (%u kB/s, %u KiB/s)\n", | 556 | "%lu.%09lu seconds (%u kB/s, %u KiB/s, " |
557 | "%u.%02u IOPS)\n", | ||
460 | mmc_hostname(test->card->host), count, sectors, count, | 558 | mmc_hostname(test->card->host), count, sectors, count, |
461 | sectors >> 1, (sectors == 1 ? ".5" : ""), | 559 | sectors >> 1, (sectors & 1 ? ".5" : ""), |
462 | (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec, | 560 | (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec, |
463 | rate / 1000, rate / 1024); | 561 | rate / 1000, rate / 1024, iops / 100, iops % 100); |
562 | |||
563 | mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops); | ||
464 | } | 564 | } |
465 | 565 | ||
466 | /* | 566 | /* |
@@ -626,15 +726,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test, | |||
626 | struct scatterlist *sg, unsigned sg_len, unsigned dev_addr, | 726 | struct scatterlist *sg, unsigned sg_len, unsigned dev_addr, |
627 | unsigned blocks, unsigned blksz, int write) | 727 | unsigned blocks, unsigned blksz, int write) |
628 | { | 728 | { |
629 | struct mmc_request mrq; | 729 | struct mmc_request mrq = {0}; |
630 | struct mmc_command cmd; | 730 | struct mmc_command cmd = {0}; |
631 | struct mmc_command stop; | 731 | struct mmc_command stop = {0}; |
632 | struct mmc_data data; | 732 | struct mmc_data data = {0}; |
633 | |||
634 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
635 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
636 | memset(&data, 0, sizeof(struct mmc_data)); | ||
637 | memset(&stop, 0, sizeof(struct mmc_command)); | ||
638 | 733 | ||
639 | mrq.cmd = &cmd; | 734 | mrq.cmd = &cmd; |
640 | mrq.data = &data; | 735 | mrq.data = &data; |
@@ -656,18 +751,13 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test, | |||
656 | static int mmc_test_broken_transfer(struct mmc_test_card *test, | 751 | static int mmc_test_broken_transfer(struct mmc_test_card *test, |
657 | unsigned blocks, unsigned blksz, int write) | 752 | unsigned blocks, unsigned blksz, int write) |
658 | { | 753 | { |
659 | struct mmc_request mrq; | 754 | struct mmc_request mrq = {0}; |
660 | struct mmc_command cmd; | 755 | struct mmc_command cmd = {0}; |
661 | struct mmc_command stop; | 756 | struct mmc_command stop = {0}; |
662 | struct mmc_data data; | 757 | struct mmc_data data = {0}; |
663 | 758 | ||
664 | struct scatterlist sg; | 759 | struct scatterlist sg; |
665 | 760 | ||
666 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
667 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
668 | memset(&data, 0, sizeof(struct mmc_data)); | ||
669 | memset(&stop, 0, sizeof(struct mmc_command)); | ||
670 | |||
671 | mrq.cmd = &cmd; | 761 | mrq.cmd = &cmd; |
672 | mrq.data = &data; | 762 | mrq.data = &data; |
673 | mrq.stop = &stop; | 763 | mrq.stop = &stop; |
@@ -1215,16 +1305,22 @@ static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz, | |||
1215 | int max_scatter) | 1305 | int max_scatter) |
1216 | { | 1306 | { |
1217 | struct mmc_test_area *t = &test->area; | 1307 | struct mmc_test_area *t = &test->area; |
1308 | int err; | ||
1218 | 1309 | ||
1219 | t->blocks = sz >> 9; | 1310 | t->blocks = sz >> 9; |
1220 | 1311 | ||
1221 | if (max_scatter) { | 1312 | if (max_scatter) { |
1222 | return mmc_test_map_sg_max_scatter(t->mem, sz, t->sg, | 1313 | err = mmc_test_map_sg_max_scatter(t->mem, sz, t->sg, |
1223 | t->max_segs, &t->sg_len); | 1314 | t->max_segs, t->max_seg_sz, |
1224 | } else { | ||
1225 | return mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs, | ||
1226 | &t->sg_len); | 1315 | &t->sg_len); |
1316 | } else { | ||
1317 | err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs, | ||
1318 | t->max_seg_sz, &t->sg_len); | ||
1227 | } | 1319 | } |
1320 | if (err) | ||
1321 | printk(KERN_INFO "%s: Failed to map sg list\n", | ||
1322 | mmc_hostname(test->card->host)); | ||
1323 | return err; | ||
1228 | } | 1324 | } |
1229 | 1325 | ||
1230 | /* | 1326 | /* |
@@ -1249,6 +1345,22 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz, | |||
1249 | struct timespec ts1, ts2; | 1345 | struct timespec ts1, ts2; |
1250 | int ret; | 1346 | int ret; |
1251 | 1347 | ||
1348 | /* | ||
1349 | * In the case of a maximally scattered transfer, the maximum transfer | ||
1350 | * size is further limited by using PAGE_SIZE segments. | ||
1351 | */ | ||
1352 | if (max_scatter) { | ||
1353 | struct mmc_test_area *t = &test->area; | ||
1354 | unsigned long max_tfr; | ||
1355 | |||
1356 | if (t->max_seg_sz >= PAGE_SIZE) | ||
1357 | max_tfr = t->max_segs * PAGE_SIZE; | ||
1358 | else | ||
1359 | max_tfr = t->max_segs * t->max_seg_sz; | ||
1360 | if (sz > max_tfr) | ||
1361 | sz = max_tfr; | ||
1362 | } | ||
1363 | |||
1252 | ret = mmc_test_area_map(test, sz, max_scatter); | 1364 | ret = mmc_test_area_map(test, sz, max_scatter); |
1253 | if (ret) | 1365 | if (ret) |
1254 | return ret; | 1366 | return ret; |
@@ -1274,8 +1386,9 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz, | |||
1274 | */ | 1386 | */ |
1275 | static int mmc_test_area_fill(struct mmc_test_card *test) | 1387 | static int mmc_test_area_fill(struct mmc_test_card *test) |
1276 | { | 1388 | { |
1277 | return mmc_test_area_io(test, test->area.max_sz, test->area.dev_addr, | 1389 | struct mmc_test_area *t = &test->area; |
1278 | 1, 0, 0); | 1390 | |
1391 | return mmc_test_area_io(test, t->max_tfr, t->dev_addr, 1, 0, 0); | ||
1279 | } | 1392 | } |
1280 | 1393 | ||
1281 | /* | 1394 | /* |
@@ -1288,7 +1401,7 @@ static int mmc_test_area_erase(struct mmc_test_card *test) | |||
1288 | if (!mmc_can_erase(test->card)) | 1401 | if (!mmc_can_erase(test->card)) |
1289 | return 0; | 1402 | return 0; |
1290 | 1403 | ||
1291 | return mmc_erase(test->card, t->dev_addr, test->area.max_sz >> 9, | 1404 | return mmc_erase(test->card, t->dev_addr, t->max_sz >> 9, |
1292 | MMC_ERASE_ARG); | 1405 | MMC_ERASE_ARG); |
1293 | } | 1406 | } |
1294 | 1407 | ||
@@ -1306,38 +1419,52 @@ static int mmc_test_area_cleanup(struct mmc_test_card *test) | |||
1306 | } | 1419 | } |
1307 | 1420 | ||
1308 | /* | 1421 | /* |
1309 | * Initialize an area for testing large transfers. The size of the area is the | 1422 | * Initialize an area for testing large transfers. The test area is set to the |
1310 | * preferred erase size which is a good size for optimal transfer speed. Note | 1423 | * middle of the card because cards may have different charateristics at the |
1311 | * that is typically 4MiB for modern cards. The test area is set to the middle | 1424 | * front (for FAT file system optimization). Optionally, the area is erased |
1312 | * of the card because cards may have different charateristics at the front | 1425 | * (if the card supports it) which may improve write performance. Optionally, |
1313 | * (for FAT file system optimization). Optionally, the area is erased (if the | 1426 | * the area is filled with data for subsequent read tests. |
1314 | * card supports it) which may improve write performance. Optionally, the area | ||
1315 | * is filled with data for subsequent read tests. | ||
1316 | */ | 1427 | */ |
1317 | static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill) | 1428 | static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill) |
1318 | { | 1429 | { |
1319 | struct mmc_test_area *t = &test->area; | 1430 | struct mmc_test_area *t = &test->area; |
1320 | unsigned long min_sz = 64 * 1024; | 1431 | unsigned long min_sz = 64 * 1024, sz; |
1321 | int ret; | 1432 | int ret; |
1322 | 1433 | ||
1323 | ret = mmc_test_set_blksize(test, 512); | 1434 | ret = mmc_test_set_blksize(test, 512); |
1324 | if (ret) | 1435 | if (ret) |
1325 | return ret; | 1436 | return ret; |
1326 | 1437 | ||
1327 | if (test->card->pref_erase > TEST_AREA_MAX_SIZE >> 9) | 1438 | /* Make the test area size about 4MiB */ |
1328 | t->max_sz = TEST_AREA_MAX_SIZE; | 1439 | sz = (unsigned long)test->card->pref_erase << 9; |
1329 | else | 1440 | t->max_sz = sz; |
1330 | t->max_sz = (unsigned long)test->card->pref_erase << 9; | 1441 | while (t->max_sz < 4 * 1024 * 1024) |
1442 | t->max_sz += sz; | ||
1443 | while (t->max_sz > TEST_AREA_MAX_SIZE && t->max_sz > sz) | ||
1444 | t->max_sz -= sz; | ||
1445 | |||
1446 | t->max_segs = test->card->host->max_segs; | ||
1447 | t->max_seg_sz = test->card->host->max_seg_size; | ||
1448 | |||
1449 | t->max_tfr = t->max_sz; | ||
1450 | if (t->max_tfr >> 9 > test->card->host->max_blk_count) | ||
1451 | t->max_tfr = test->card->host->max_blk_count << 9; | ||
1452 | if (t->max_tfr > test->card->host->max_req_size) | ||
1453 | t->max_tfr = test->card->host->max_req_size; | ||
1454 | if (t->max_tfr / t->max_seg_sz > t->max_segs) | ||
1455 | t->max_tfr = t->max_segs * t->max_seg_sz; | ||
1456 | |||
1331 | /* | 1457 | /* |
1332 | * Try to allocate enough memory for the whole area. Less is OK | 1458 | * Try to allocate enough memory for a max. sized transfer. Less is OK |
1333 | * because the same memory can be mapped into the scatterlist more than | 1459 | * because the same memory can be mapped into the scatterlist more than |
1334 | * once. | 1460 | * once. Also, take into account the limits imposed on scatterlist |
1461 | * segments by the host driver. | ||
1335 | */ | 1462 | */ |
1336 | t->mem = mmc_test_alloc_mem(min_sz, t->max_sz); | 1463 | t->mem = mmc_test_alloc_mem(min_sz, t->max_tfr, t->max_segs, |
1464 | t->max_seg_sz); | ||
1337 | if (!t->mem) | 1465 | if (!t->mem) |
1338 | return -ENOMEM; | 1466 | return -ENOMEM; |
1339 | 1467 | ||
1340 | t->max_segs = DIV_ROUND_UP(t->max_sz, PAGE_SIZE); | ||
1341 | t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL); | 1468 | t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL); |
1342 | if (!t->sg) { | 1469 | if (!t->sg) { |
1343 | ret = -ENOMEM; | 1470 | ret = -ENOMEM; |
@@ -1401,8 +1528,10 @@ static int mmc_test_area_prepare_fill(struct mmc_test_card *test) | |||
1401 | static int mmc_test_best_performance(struct mmc_test_card *test, int write, | 1528 | static int mmc_test_best_performance(struct mmc_test_card *test, int write, |
1402 | int max_scatter) | 1529 | int max_scatter) |
1403 | { | 1530 | { |
1404 | return mmc_test_area_io(test, test->area.max_sz, test->area.dev_addr, | 1531 | struct mmc_test_area *t = &test->area; |
1405 | write, max_scatter, 1); | 1532 | |
1533 | return mmc_test_area_io(test, t->max_tfr, t->dev_addr, write, | ||
1534 | max_scatter, 1); | ||
1406 | } | 1535 | } |
1407 | 1536 | ||
1408 | /* | 1537 | /* |
@@ -1442,17 +1571,19 @@ static int mmc_test_best_write_perf_max_scatter(struct mmc_test_card *test) | |||
1442 | */ | 1571 | */ |
1443 | static int mmc_test_profile_read_perf(struct mmc_test_card *test) | 1572 | static int mmc_test_profile_read_perf(struct mmc_test_card *test) |
1444 | { | 1573 | { |
1574 | struct mmc_test_area *t = &test->area; | ||
1445 | unsigned long sz; | 1575 | unsigned long sz; |
1446 | unsigned int dev_addr; | 1576 | unsigned int dev_addr; |
1447 | int ret; | 1577 | int ret; |
1448 | 1578 | ||
1449 | for (sz = 512; sz < test->area.max_sz; sz <<= 1) { | 1579 | for (sz = 512; sz < t->max_tfr; sz <<= 1) { |
1450 | dev_addr = test->area.dev_addr + (sz >> 9); | 1580 | dev_addr = t->dev_addr + (sz >> 9); |
1451 | ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1); | 1581 | ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1); |
1452 | if (ret) | 1582 | if (ret) |
1453 | return ret; | 1583 | return ret; |
1454 | } | 1584 | } |
1455 | dev_addr = test->area.dev_addr; | 1585 | sz = t->max_tfr; |
1586 | dev_addr = t->dev_addr; | ||
1456 | return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1); | 1587 | return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1); |
1457 | } | 1588 | } |
1458 | 1589 | ||
@@ -1461,6 +1592,7 @@ static int mmc_test_profile_read_perf(struct mmc_test_card *test) | |||
1461 | */ | 1592 | */ |
1462 | static int mmc_test_profile_write_perf(struct mmc_test_card *test) | 1593 | static int mmc_test_profile_write_perf(struct mmc_test_card *test) |
1463 | { | 1594 | { |
1595 | struct mmc_test_area *t = &test->area; | ||
1464 | unsigned long sz; | 1596 | unsigned long sz; |
1465 | unsigned int dev_addr; | 1597 | unsigned int dev_addr; |
1466 | int ret; | 1598 | int ret; |
@@ -1468,8 +1600,8 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test) | |||
1468 | ret = mmc_test_area_erase(test); | 1600 | ret = mmc_test_area_erase(test); |
1469 | if (ret) | 1601 | if (ret) |
1470 | return ret; | 1602 | return ret; |
1471 | for (sz = 512; sz < test->area.max_sz; sz <<= 1) { | 1603 | for (sz = 512; sz < t->max_tfr; sz <<= 1) { |
1472 | dev_addr = test->area.dev_addr + (sz >> 9); | 1604 | dev_addr = t->dev_addr + (sz >> 9); |
1473 | ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1); | 1605 | ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1); |
1474 | if (ret) | 1606 | if (ret) |
1475 | return ret; | 1607 | return ret; |
@@ -1477,7 +1609,8 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test) | |||
1477 | ret = mmc_test_area_erase(test); | 1609 | ret = mmc_test_area_erase(test); |
1478 | if (ret) | 1610 | if (ret) |
1479 | return ret; | 1611 | return ret; |
1480 | dev_addr = test->area.dev_addr; | 1612 | sz = t->max_tfr; |
1613 | dev_addr = t->dev_addr; | ||
1481 | return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1); | 1614 | return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1); |
1482 | } | 1615 | } |
1483 | 1616 | ||
@@ -1486,6 +1619,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test) | |||
1486 | */ | 1619 | */ |
1487 | static int mmc_test_profile_trim_perf(struct mmc_test_card *test) | 1620 | static int mmc_test_profile_trim_perf(struct mmc_test_card *test) |
1488 | { | 1621 | { |
1622 | struct mmc_test_area *t = &test->area; | ||
1489 | unsigned long sz; | 1623 | unsigned long sz; |
1490 | unsigned int dev_addr; | 1624 | unsigned int dev_addr; |
1491 | struct timespec ts1, ts2; | 1625 | struct timespec ts1, ts2; |
@@ -1497,8 +1631,8 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test) | |||
1497 | if (!mmc_can_erase(test->card)) | 1631 | if (!mmc_can_erase(test->card)) |
1498 | return RESULT_UNSUP_HOST; | 1632 | return RESULT_UNSUP_HOST; |
1499 | 1633 | ||
1500 | for (sz = 512; sz < test->area.max_sz; sz <<= 1) { | 1634 | for (sz = 512; sz < t->max_sz; sz <<= 1) { |
1501 | dev_addr = test->area.dev_addr + (sz >> 9); | 1635 | dev_addr = t->dev_addr + (sz >> 9); |
1502 | getnstimeofday(&ts1); | 1636 | getnstimeofday(&ts1); |
1503 | ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG); | 1637 | ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG); |
1504 | if (ret) | 1638 | if (ret) |
@@ -1506,7 +1640,7 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test) | |||
1506 | getnstimeofday(&ts2); | 1640 | getnstimeofday(&ts2); |
1507 | mmc_test_print_rate(test, sz, &ts1, &ts2); | 1641 | mmc_test_print_rate(test, sz, &ts1, &ts2); |
1508 | } | 1642 | } |
1509 | dev_addr = test->area.dev_addr; | 1643 | dev_addr = t->dev_addr; |
1510 | getnstimeofday(&ts1); | 1644 | getnstimeofday(&ts1); |
1511 | ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG); | 1645 | ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG); |
1512 | if (ret) | 1646 | if (ret) |
@@ -1516,29 +1650,66 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test) | |||
1516 | return 0; | 1650 | return 0; |
1517 | } | 1651 | } |
1518 | 1652 | ||
1653 | static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz) | ||
1654 | { | ||
1655 | struct mmc_test_area *t = &test->area; | ||
1656 | unsigned int dev_addr, i, cnt; | ||
1657 | struct timespec ts1, ts2; | ||
1658 | int ret; | ||
1659 | |||
1660 | cnt = t->max_sz / sz; | ||
1661 | dev_addr = t->dev_addr; | ||
1662 | getnstimeofday(&ts1); | ||
1663 | for (i = 0; i < cnt; i++) { | ||
1664 | ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0); | ||
1665 | if (ret) | ||
1666 | return ret; | ||
1667 | dev_addr += (sz >> 9); | ||
1668 | } | ||
1669 | getnstimeofday(&ts2); | ||
1670 | mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); | ||
1671 | return 0; | ||
1672 | } | ||
1673 | |||
1519 | /* | 1674 | /* |
1520 | * Consecutive read performance by transfer size. | 1675 | * Consecutive read performance by transfer size. |
1521 | */ | 1676 | */ |
1522 | static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test) | 1677 | static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test) |
1523 | { | 1678 | { |
1679 | struct mmc_test_area *t = &test->area; | ||
1524 | unsigned long sz; | 1680 | unsigned long sz; |
1681 | int ret; | ||
1682 | |||
1683 | for (sz = 512; sz < t->max_tfr; sz <<= 1) { | ||
1684 | ret = mmc_test_seq_read_perf(test, sz); | ||
1685 | if (ret) | ||
1686 | return ret; | ||
1687 | } | ||
1688 | sz = t->max_tfr; | ||
1689 | return mmc_test_seq_read_perf(test, sz); | ||
1690 | } | ||
1691 | |||
1692 | static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz) | ||
1693 | { | ||
1694 | struct mmc_test_area *t = &test->area; | ||
1525 | unsigned int dev_addr, i, cnt; | 1695 | unsigned int dev_addr, i, cnt; |
1526 | struct timespec ts1, ts2; | 1696 | struct timespec ts1, ts2; |
1527 | int ret; | 1697 | int ret; |
1528 | 1698 | ||
1529 | for (sz = 512; sz <= test->area.max_sz; sz <<= 1) { | 1699 | ret = mmc_test_area_erase(test); |
1530 | cnt = test->area.max_sz / sz; | 1700 | if (ret) |
1531 | dev_addr = test->area.dev_addr; | 1701 | return ret; |
1532 | getnstimeofday(&ts1); | 1702 | cnt = t->max_sz / sz; |
1533 | for (i = 0; i < cnt; i++) { | 1703 | dev_addr = t->dev_addr; |
1534 | ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0); | 1704 | getnstimeofday(&ts1); |
1535 | if (ret) | 1705 | for (i = 0; i < cnt; i++) { |
1536 | return ret; | 1706 | ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0); |
1537 | dev_addr += (sz >> 9); | 1707 | if (ret) |
1538 | } | 1708 | return ret; |
1539 | getnstimeofday(&ts2); | 1709 | dev_addr += (sz >> 9); |
1540 | mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); | ||
1541 | } | 1710 | } |
1711 | getnstimeofday(&ts2); | ||
1712 | mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); | ||
1542 | return 0; | 1713 | return 0; |
1543 | } | 1714 | } |
1544 | 1715 | ||
@@ -1547,28 +1718,17 @@ static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test) | |||
1547 | */ | 1718 | */ |
1548 | static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test) | 1719 | static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test) |
1549 | { | 1720 | { |
1721 | struct mmc_test_area *t = &test->area; | ||
1550 | unsigned long sz; | 1722 | unsigned long sz; |
1551 | unsigned int dev_addr, i, cnt; | ||
1552 | struct timespec ts1, ts2; | ||
1553 | int ret; | 1723 | int ret; |
1554 | 1724 | ||
1555 | for (sz = 512; sz <= test->area.max_sz; sz <<= 1) { | 1725 | for (sz = 512; sz < t->max_tfr; sz <<= 1) { |
1556 | ret = mmc_test_area_erase(test); | 1726 | ret = mmc_test_seq_write_perf(test, sz); |
1557 | if (ret) | 1727 | if (ret) |
1558 | return ret; | 1728 | return ret; |
1559 | cnt = test->area.max_sz / sz; | ||
1560 | dev_addr = test->area.dev_addr; | ||
1561 | getnstimeofday(&ts1); | ||
1562 | for (i = 0; i < cnt; i++) { | ||
1563 | ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0); | ||
1564 | if (ret) | ||
1565 | return ret; | ||
1566 | dev_addr += (sz >> 9); | ||
1567 | } | ||
1568 | getnstimeofday(&ts2); | ||
1569 | mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); | ||
1570 | } | 1729 | } |
1571 | return 0; | 1730 | sz = t->max_tfr; |
1731 | return mmc_test_seq_write_perf(test, sz); | ||
1572 | } | 1732 | } |
1573 | 1733 | ||
1574 | /* | 1734 | /* |
@@ -1576,6 +1736,7 @@ static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test) | |||
1576 | */ | 1736 | */ |
1577 | static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test) | 1737 | static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test) |
1578 | { | 1738 | { |
1739 | struct mmc_test_area *t = &test->area; | ||
1579 | unsigned long sz; | 1740 | unsigned long sz; |
1580 | unsigned int dev_addr, i, cnt; | 1741 | unsigned int dev_addr, i, cnt; |
1581 | struct timespec ts1, ts2; | 1742 | struct timespec ts1, ts2; |
@@ -1587,15 +1748,15 @@ static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test) | |||
1587 | if (!mmc_can_erase(test->card)) | 1748 | if (!mmc_can_erase(test->card)) |
1588 | return RESULT_UNSUP_HOST; | 1749 | return RESULT_UNSUP_HOST; |
1589 | 1750 | ||
1590 | for (sz = 512; sz <= test->area.max_sz; sz <<= 1) { | 1751 | for (sz = 512; sz <= t->max_sz; sz <<= 1) { |
1591 | ret = mmc_test_area_erase(test); | 1752 | ret = mmc_test_area_erase(test); |
1592 | if (ret) | 1753 | if (ret) |
1593 | return ret; | 1754 | return ret; |
1594 | ret = mmc_test_area_fill(test); | 1755 | ret = mmc_test_area_fill(test); |
1595 | if (ret) | 1756 | if (ret) |
1596 | return ret; | 1757 | return ret; |
1597 | cnt = test->area.max_sz / sz; | 1758 | cnt = t->max_sz / sz; |
1598 | dev_addr = test->area.dev_addr; | 1759 | dev_addr = t->dev_addr; |
1599 | getnstimeofday(&ts1); | 1760 | getnstimeofday(&ts1); |
1600 | for (i = 0; i < cnt; i++) { | 1761 | for (i = 0; i < cnt; i++) { |
1601 | ret = mmc_erase(test->card, dev_addr, sz >> 9, | 1762 | ret = mmc_erase(test->card, dev_addr, sz >> 9, |
@@ -1610,6 +1771,189 @@ static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test) | |||
1610 | return 0; | 1771 | return 0; |
1611 | } | 1772 | } |
1612 | 1773 | ||
1774 | static unsigned int rnd_next = 1; | ||
1775 | |||
1776 | static unsigned int mmc_test_rnd_num(unsigned int rnd_cnt) | ||
1777 | { | ||
1778 | uint64_t r; | ||
1779 | |||
1780 | rnd_next = rnd_next * 1103515245 + 12345; | ||
1781 | r = (rnd_next >> 16) & 0x7fff; | ||
1782 | return (r * rnd_cnt) >> 15; | ||
1783 | } | ||
1784 | |||
1785 | static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print, | ||
1786 | unsigned long sz) | ||
1787 | { | ||
1788 | unsigned int dev_addr, cnt, rnd_addr, range1, range2, last_ea = 0, ea; | ||
1789 | unsigned int ssz; | ||
1790 | struct timespec ts1, ts2, ts; | ||
1791 | int ret; | ||
1792 | |||
1793 | ssz = sz >> 9; | ||
1794 | |||
1795 | rnd_addr = mmc_test_capacity(test->card) / 4; | ||
1796 | range1 = rnd_addr / test->card->pref_erase; | ||
1797 | range2 = range1 / ssz; | ||
1798 | |||
1799 | getnstimeofday(&ts1); | ||
1800 | for (cnt = 0; cnt < UINT_MAX; cnt++) { | ||
1801 | getnstimeofday(&ts2); | ||
1802 | ts = timespec_sub(ts2, ts1); | ||
1803 | if (ts.tv_sec >= 10) | ||
1804 | break; | ||
1805 | ea = mmc_test_rnd_num(range1); | ||
1806 | if (ea == last_ea) | ||
1807 | ea -= 1; | ||
1808 | last_ea = ea; | ||
1809 | dev_addr = rnd_addr + test->card->pref_erase * ea + | ||
1810 | ssz * mmc_test_rnd_num(range2); | ||
1811 | ret = mmc_test_area_io(test, sz, dev_addr, write, 0, 0); | ||
1812 | if (ret) | ||
1813 | return ret; | ||
1814 | } | ||
1815 | if (print) | ||
1816 | mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); | ||
1817 | return 0; | ||
1818 | } | ||
1819 | |||
1820 | static int mmc_test_random_perf(struct mmc_test_card *test, int write) | ||
1821 | { | ||
1822 | struct mmc_test_area *t = &test->area; | ||
1823 | unsigned int next; | ||
1824 | unsigned long sz; | ||
1825 | int ret; | ||
1826 | |||
1827 | for (sz = 512; sz < t->max_tfr; sz <<= 1) { | ||
1828 | /* | ||
1829 | * When writing, try to get more consistent results by running | ||
1830 | * the test twice with exactly the same I/O but outputting the | ||
1831 | * results only for the 2nd run. | ||
1832 | */ | ||
1833 | if (write) { | ||
1834 | next = rnd_next; | ||
1835 | ret = mmc_test_rnd_perf(test, write, 0, sz); | ||
1836 | if (ret) | ||
1837 | return ret; | ||
1838 | rnd_next = next; | ||
1839 | } | ||
1840 | ret = mmc_test_rnd_perf(test, write, 1, sz); | ||
1841 | if (ret) | ||
1842 | return ret; | ||
1843 | } | ||
1844 | sz = t->max_tfr; | ||
1845 | if (write) { | ||
1846 | next = rnd_next; | ||
1847 | ret = mmc_test_rnd_perf(test, write, 0, sz); | ||
1848 | if (ret) | ||
1849 | return ret; | ||
1850 | rnd_next = next; | ||
1851 | } | ||
1852 | return mmc_test_rnd_perf(test, write, 1, sz); | ||
1853 | } | ||
1854 | |||
1855 | /* | ||
1856 | * Random read performance by transfer size. | ||
1857 | */ | ||
1858 | static int mmc_test_random_read_perf(struct mmc_test_card *test) | ||
1859 | { | ||
1860 | return mmc_test_random_perf(test, 0); | ||
1861 | } | ||
1862 | |||
1863 | /* | ||
1864 | * Random write performance by transfer size. | ||
1865 | */ | ||
1866 | static int mmc_test_random_write_perf(struct mmc_test_card *test) | ||
1867 | { | ||
1868 | return mmc_test_random_perf(test, 1); | ||
1869 | } | ||
1870 | |||
1871 | static int mmc_test_seq_perf(struct mmc_test_card *test, int write, | ||
1872 | unsigned int tot_sz, int max_scatter) | ||
1873 | { | ||
1874 | struct mmc_test_area *t = &test->area; | ||
1875 | unsigned int dev_addr, i, cnt, sz, ssz; | ||
1876 | struct timespec ts1, ts2; | ||
1877 | int ret; | ||
1878 | |||
1879 | sz = t->max_tfr; | ||
1880 | |||
1881 | /* | ||
1882 | * In the case of a maximally scattered transfer, the maximum transfer | ||
1883 | * size is further limited by using PAGE_SIZE segments. | ||
1884 | */ | ||
1885 | if (max_scatter) { | ||
1886 | unsigned long max_tfr; | ||
1887 | |||
1888 | if (t->max_seg_sz >= PAGE_SIZE) | ||
1889 | max_tfr = t->max_segs * PAGE_SIZE; | ||
1890 | else | ||
1891 | max_tfr = t->max_segs * t->max_seg_sz; | ||
1892 | if (sz > max_tfr) | ||
1893 | sz = max_tfr; | ||
1894 | } | ||
1895 | |||
1896 | ssz = sz >> 9; | ||
1897 | dev_addr = mmc_test_capacity(test->card) / 4; | ||
1898 | if (tot_sz > dev_addr << 9) | ||
1899 | tot_sz = dev_addr << 9; | ||
1900 | cnt = tot_sz / sz; | ||
1901 | dev_addr &= 0xffff0000; /* Round to 64MiB boundary */ | ||
1902 | |||
1903 | getnstimeofday(&ts1); | ||
1904 | for (i = 0; i < cnt; i++) { | ||
1905 | ret = mmc_test_area_io(test, sz, dev_addr, write, | ||
1906 | max_scatter, 0); | ||
1907 | if (ret) | ||
1908 | return ret; | ||
1909 | dev_addr += ssz; | ||
1910 | } | ||
1911 | getnstimeofday(&ts2); | ||
1912 | |||
1913 | mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); | ||
1914 | |||
1915 | return 0; | ||
1916 | } | ||
1917 | |||
1918 | static int mmc_test_large_seq_perf(struct mmc_test_card *test, int write) | ||
1919 | { | ||
1920 | int ret, i; | ||
1921 | |||
1922 | for (i = 0; i < 10; i++) { | ||
1923 | ret = mmc_test_seq_perf(test, write, 10 * 1024 * 1024, 1); | ||
1924 | if (ret) | ||
1925 | return ret; | ||
1926 | } | ||
1927 | for (i = 0; i < 5; i++) { | ||
1928 | ret = mmc_test_seq_perf(test, write, 100 * 1024 * 1024, 1); | ||
1929 | if (ret) | ||
1930 | return ret; | ||
1931 | } | ||
1932 | for (i = 0; i < 3; i++) { | ||
1933 | ret = mmc_test_seq_perf(test, write, 1000 * 1024 * 1024, 1); | ||
1934 | if (ret) | ||
1935 | return ret; | ||
1936 | } | ||
1937 | |||
1938 | return ret; | ||
1939 | } | ||
1940 | |||
1941 | /* | ||
1942 | * Large sequential read performance. | ||
1943 | */ | ||
1944 | static int mmc_test_large_seq_read_perf(struct mmc_test_card *test) | ||
1945 | { | ||
1946 | return mmc_test_large_seq_perf(test, 0); | ||
1947 | } | ||
1948 | |||
1949 | /* | ||
1950 | * Large sequential write performance. | ||
1951 | */ | ||
1952 | static int mmc_test_large_seq_write_perf(struct mmc_test_card *test) | ||
1953 | { | ||
1954 | return mmc_test_large_seq_perf(test, 1); | ||
1955 | } | ||
1956 | |||
1613 | static const struct mmc_test_case mmc_test_cases[] = { | 1957 | static const struct mmc_test_case mmc_test_cases[] = { |
1614 | { | 1958 | { |
1615 | .name = "Basic write (no data verification)", | 1959 | .name = "Basic write (no data verification)", |
@@ -1849,10 +2193,40 @@ static const struct mmc_test_case mmc_test_cases[] = { | |||
1849 | .cleanup = mmc_test_area_cleanup, | 2193 | .cleanup = mmc_test_area_cleanup, |
1850 | }, | 2194 | }, |
1851 | 2195 | ||
2196 | { | ||
2197 | .name = "Random read performance by transfer size", | ||
2198 | .prepare = mmc_test_area_prepare, | ||
2199 | .run = mmc_test_random_read_perf, | ||
2200 | .cleanup = mmc_test_area_cleanup, | ||
2201 | }, | ||
2202 | |||
2203 | { | ||
2204 | .name = "Random write performance by transfer size", | ||
2205 | .prepare = mmc_test_area_prepare, | ||
2206 | .run = mmc_test_random_write_perf, | ||
2207 | .cleanup = mmc_test_area_cleanup, | ||
2208 | }, | ||
2209 | |||
2210 | { | ||
2211 | .name = "Large sequential read into scattered pages", | ||
2212 | .prepare = mmc_test_area_prepare, | ||
2213 | .run = mmc_test_large_seq_read_perf, | ||
2214 | .cleanup = mmc_test_area_cleanup, | ||
2215 | }, | ||
2216 | |||
2217 | { | ||
2218 | .name = "Large sequential write from scattered pages", | ||
2219 | .prepare = mmc_test_area_prepare, | ||
2220 | .run = mmc_test_large_seq_write_perf, | ||
2221 | .cleanup = mmc_test_area_cleanup, | ||
2222 | }, | ||
2223 | |||
1852 | }; | 2224 | }; |
1853 | 2225 | ||
1854 | static DEFINE_MUTEX(mmc_test_lock); | 2226 | static DEFINE_MUTEX(mmc_test_lock); |
1855 | 2227 | ||
2228 | static LIST_HEAD(mmc_test_result); | ||
2229 | |||
1856 | static void mmc_test_run(struct mmc_test_card *test, int testcase) | 2230 | static void mmc_test_run(struct mmc_test_card *test, int testcase) |
1857 | { | 2231 | { |
1858 | int i, ret; | 2232 | int i, ret; |
@@ -1863,6 +2237,8 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) | |||
1863 | mmc_claim_host(test->card->host); | 2237 | mmc_claim_host(test->card->host); |
1864 | 2238 | ||
1865 | for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) { | 2239 | for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) { |
2240 | struct mmc_test_general_result *gr; | ||
2241 | |||
1866 | if (testcase && ((i + 1) != testcase)) | 2242 | if (testcase && ((i + 1) != testcase)) |
1867 | continue; | 2243 | continue; |
1868 | 2244 | ||
@@ -1881,6 +2257,25 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) | |||
1881 | } | 2257 | } |
1882 | } | 2258 | } |
1883 | 2259 | ||
2260 | gr = kzalloc(sizeof(struct mmc_test_general_result), | ||
2261 | GFP_KERNEL); | ||
2262 | if (gr) { | ||
2263 | INIT_LIST_HEAD(&gr->tr_lst); | ||
2264 | |||
2265 | /* Assign data what we know already */ | ||
2266 | gr->card = test->card; | ||
2267 | gr->testcase = i; | ||
2268 | |||
2269 | /* Append container to global one */ | ||
2270 | list_add_tail(&gr->link, &mmc_test_result); | ||
2271 | |||
2272 | /* | ||
2273 | * Save the pointer to created container in our private | ||
2274 | * structure. | ||
2275 | */ | ||
2276 | test->gr = gr; | ||
2277 | } | ||
2278 | |||
1884 | ret = mmc_test_cases[i].run(test); | 2279 | ret = mmc_test_cases[i].run(test); |
1885 | switch (ret) { | 2280 | switch (ret) { |
1886 | case RESULT_OK: | 2281 | case RESULT_OK: |
@@ -1906,6 +2301,10 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) | |||
1906 | mmc_hostname(test->card->host), ret); | 2301 | mmc_hostname(test->card->host), ret); |
1907 | } | 2302 | } |
1908 | 2303 | ||
2304 | /* Save the result */ | ||
2305 | if (gr) | ||
2306 | gr->result = ret; | ||
2307 | |||
1909 | if (mmc_test_cases[i].cleanup) { | 2308 | if (mmc_test_cases[i].cleanup) { |
1910 | ret = mmc_test_cases[i].cleanup(test); | 2309 | ret = mmc_test_cases[i].cleanup(test); |
1911 | if (ret) { | 2310 | if (ret) { |
@@ -1923,30 +2322,95 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) | |||
1923 | mmc_hostname(test->card->host)); | 2322 | mmc_hostname(test->card->host)); |
1924 | } | 2323 | } |
1925 | 2324 | ||
1926 | static ssize_t mmc_test_show(struct device *dev, | 2325 | static void mmc_test_free_result(struct mmc_card *card) |
1927 | struct device_attribute *attr, char *buf) | 2326 | { |
2327 | struct mmc_test_general_result *gr, *grs; | ||
2328 | |||
2329 | mutex_lock(&mmc_test_lock); | ||
2330 | |||
2331 | list_for_each_entry_safe(gr, grs, &mmc_test_result, link) { | ||
2332 | struct mmc_test_transfer_result *tr, *trs; | ||
2333 | |||
2334 | if (card && gr->card != card) | ||
2335 | continue; | ||
2336 | |||
2337 | list_for_each_entry_safe(tr, trs, &gr->tr_lst, link) { | ||
2338 | list_del(&tr->link); | ||
2339 | kfree(tr); | ||
2340 | } | ||
2341 | |||
2342 | list_del(&gr->link); | ||
2343 | kfree(gr); | ||
2344 | } | ||
2345 | |||
2346 | mutex_unlock(&mmc_test_lock); | ||
2347 | } | ||
2348 | |||
2349 | static LIST_HEAD(mmc_test_file_test); | ||
2350 | |||
2351 | static int mtf_test_show(struct seq_file *sf, void *data) | ||
1928 | { | 2352 | { |
2353 | struct mmc_card *card = (struct mmc_card *)sf->private; | ||
2354 | struct mmc_test_general_result *gr; | ||
2355 | |||
1929 | mutex_lock(&mmc_test_lock); | 2356 | mutex_lock(&mmc_test_lock); |
2357 | |||
2358 | list_for_each_entry(gr, &mmc_test_result, link) { | ||
2359 | struct mmc_test_transfer_result *tr; | ||
2360 | |||
2361 | if (gr->card != card) | ||
2362 | continue; | ||
2363 | |||
2364 | seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result); | ||
2365 | |||
2366 | list_for_each_entry(tr, &gr->tr_lst, link) { | ||
2367 | seq_printf(sf, "%u %d %lu.%09lu %u %u.%02u\n", | ||
2368 | tr->count, tr->sectors, | ||
2369 | (unsigned long)tr->ts.tv_sec, | ||
2370 | (unsigned long)tr->ts.tv_nsec, | ||
2371 | tr->rate, tr->iops / 100, tr->iops % 100); | ||
2372 | } | ||
2373 | } | ||
2374 | |||
1930 | mutex_unlock(&mmc_test_lock); | 2375 | mutex_unlock(&mmc_test_lock); |
1931 | 2376 | ||
1932 | return 0; | 2377 | return 0; |
1933 | } | 2378 | } |
1934 | 2379 | ||
1935 | static ssize_t mmc_test_store(struct device *dev, | 2380 | static int mtf_test_open(struct inode *inode, struct file *file) |
1936 | struct device_attribute *attr, const char *buf, size_t count) | ||
1937 | { | 2381 | { |
1938 | struct mmc_card *card; | 2382 | return single_open(file, mtf_test_show, inode->i_private); |
2383 | } | ||
2384 | |||
2385 | static ssize_t mtf_test_write(struct file *file, const char __user *buf, | ||
2386 | size_t count, loff_t *pos) | ||
2387 | { | ||
2388 | struct seq_file *sf = (struct seq_file *)file->private_data; | ||
2389 | struct mmc_card *card = (struct mmc_card *)sf->private; | ||
1939 | struct mmc_test_card *test; | 2390 | struct mmc_test_card *test; |
1940 | int testcase; | 2391 | char lbuf[12]; |
2392 | long testcase; | ||
2393 | |||
2394 | if (count >= sizeof(lbuf)) | ||
2395 | return -EINVAL; | ||
1941 | 2396 | ||
1942 | card = container_of(dev, struct mmc_card, dev); | 2397 | if (copy_from_user(lbuf, buf, count)) |
2398 | return -EFAULT; | ||
2399 | lbuf[count] = '\0'; | ||
1943 | 2400 | ||
1944 | testcase = simple_strtol(buf, NULL, 10); | 2401 | if (strict_strtol(lbuf, 10, &testcase)) |
2402 | return -EINVAL; | ||
1945 | 2403 | ||
1946 | test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL); | 2404 | test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL); |
1947 | if (!test) | 2405 | if (!test) |
1948 | return -ENOMEM; | 2406 | return -ENOMEM; |
1949 | 2407 | ||
2408 | /* | ||
2409 | * Remove all test cases associated with given card. Thus we have only | ||
2410 | * actual data of the last run. | ||
2411 | */ | ||
2412 | mmc_test_free_result(card); | ||
2413 | |||
1950 | test->card = card; | 2414 | test->card = card; |
1951 | 2415 | ||
1952 | test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL); | 2416 | test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL); |
@@ -1973,16 +2437,78 @@ static ssize_t mmc_test_store(struct device *dev, | |||
1973 | return count; | 2437 | return count; |
1974 | } | 2438 | } |
1975 | 2439 | ||
1976 | static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store); | 2440 | static const struct file_operations mmc_test_fops_test = { |
2441 | .open = mtf_test_open, | ||
2442 | .read = seq_read, | ||
2443 | .write = mtf_test_write, | ||
2444 | .llseek = seq_lseek, | ||
2445 | .release = single_release, | ||
2446 | }; | ||
2447 | |||
2448 | static void mmc_test_free_file_test(struct mmc_card *card) | ||
2449 | { | ||
2450 | struct mmc_test_dbgfs_file *df, *dfs; | ||
2451 | |||
2452 | mutex_lock(&mmc_test_lock); | ||
2453 | |||
2454 | list_for_each_entry_safe(df, dfs, &mmc_test_file_test, link) { | ||
2455 | if (card && df->card != card) | ||
2456 | continue; | ||
2457 | debugfs_remove(df->file); | ||
2458 | list_del(&df->link); | ||
2459 | kfree(df); | ||
2460 | } | ||
2461 | |||
2462 | mutex_unlock(&mmc_test_lock); | ||
2463 | } | ||
2464 | |||
2465 | static int mmc_test_register_file_test(struct mmc_card *card) | ||
2466 | { | ||
2467 | struct dentry *file = NULL; | ||
2468 | struct mmc_test_dbgfs_file *df; | ||
2469 | int ret = 0; | ||
2470 | |||
2471 | mutex_lock(&mmc_test_lock); | ||
2472 | |||
2473 | if (card->debugfs_root) | ||
2474 | file = debugfs_create_file("test", S_IWUSR | S_IRUGO, | ||
2475 | card->debugfs_root, card, &mmc_test_fops_test); | ||
2476 | |||
2477 | if (IS_ERR_OR_NULL(file)) { | ||
2478 | dev_err(&card->dev, | ||
2479 | "Can't create file. Perhaps debugfs is disabled.\n"); | ||
2480 | ret = -ENODEV; | ||
2481 | goto err; | ||
2482 | } | ||
2483 | |||
2484 | df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL); | ||
2485 | if (!df) { | ||
2486 | debugfs_remove(file); | ||
2487 | dev_err(&card->dev, | ||
2488 | "Can't allocate memory for internal usage.\n"); | ||
2489 | ret = -ENOMEM; | ||
2490 | goto err; | ||
2491 | } | ||
2492 | |||
2493 | df->card = card; | ||
2494 | df->file = file; | ||
2495 | |||
2496 | list_add(&df->link, &mmc_test_file_test); | ||
2497 | |||
2498 | err: | ||
2499 | mutex_unlock(&mmc_test_lock); | ||
2500 | |||
2501 | return ret; | ||
2502 | } | ||
1977 | 2503 | ||
1978 | static int mmc_test_probe(struct mmc_card *card) | 2504 | static int mmc_test_probe(struct mmc_card *card) |
1979 | { | 2505 | { |
1980 | int ret; | 2506 | int ret; |
1981 | 2507 | ||
1982 | if ((card->type != MMC_TYPE_MMC) && (card->type != MMC_TYPE_SD)) | 2508 | if (!mmc_card_mmc(card) && !mmc_card_sd(card)) |
1983 | return -ENODEV; | 2509 | return -ENODEV; |
1984 | 2510 | ||
1985 | ret = device_create_file(&card->dev, &dev_attr_test); | 2511 | ret = mmc_test_register_file_test(card); |
1986 | if (ret) | 2512 | if (ret) |
1987 | return ret; | 2513 | return ret; |
1988 | 2514 | ||
@@ -1993,7 +2519,8 @@ static int mmc_test_probe(struct mmc_card *card) | |||
1993 | 2519 | ||
1994 | static void mmc_test_remove(struct mmc_card *card) | 2520 | static void mmc_test_remove(struct mmc_card *card) |
1995 | { | 2521 | { |
1996 | device_remove_file(&card->dev, &dev_attr_test); | 2522 | mmc_test_free_result(card); |
2523 | mmc_test_free_file_test(card); | ||
1997 | } | 2524 | } |
1998 | 2525 | ||
1999 | static struct mmc_driver mmc_driver = { | 2526 | static struct mmc_driver mmc_driver = { |
@@ -2011,6 +2538,10 @@ static int __init mmc_test_init(void) | |||
2011 | 2538 | ||
2012 | static void __exit mmc_test_exit(void) | 2539 | static void __exit mmc_test_exit(void) |
2013 | { | 2540 | { |
2541 | /* Clear stalled data if card is still plugged */ | ||
2542 | mmc_test_free_result(NULL); | ||
2543 | mmc_test_free_file_test(NULL); | ||
2544 | |||
2014 | mmc_unregister_driver(&mmc_driver); | 2545 | mmc_unregister_driver(&mmc_driver); |
2015 | } | 2546 | } |
2016 | 2547 | ||