diff options
| author | Adrian Hunter <adrian.hunter@nokia.com> | 2010-08-11 17:17:51 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-12 11:43:31 -0400 |
| commit | fec4dcce237c7185ff7129e704bc508850b6e3f0 (patch) | |
| tree | 018b868ff5a1a66ac5dfcbc8704362295987f4f6 | |
| parent | 64f7120d890b892ed2c82c87bed958902e809075 (diff) | |
mmc_test: fix large memory allocation
- Fix mmc_test_alloc_mem.
- Use nr_free_buffer_pages() instead of sysinfo.totalram to determine
total lowmem pages.
- Change variables containing memory sizes to unsigned long.
- Limit maximum test area size to 128MiB because that is the maximum MMC
high capacity erase size (the maxmium SD allocation unit size is just
4MiB)
Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | drivers/mmc/card/mmc_test.c | 76 |
1 files changed, 47 insertions, 29 deletions
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 197f3877b017..5dd8576b5c18 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | 17 | ||
| 18 | #include <linux/scatterlist.h> | 18 | #include <linux/scatterlist.h> |
| 19 | #include <linux/swap.h> /* For nr_free_buffer_pages() */ | ||
| 19 | 20 | ||
| 20 | #define RESULT_OK 0 | 21 | #define RESULT_OK 0 |
| 21 | #define RESULT_FAIL 1 | 22 | #define RESULT_FAIL 1 |
| @@ -25,6 +26,12 @@ | |||
| 25 | #define BUFFER_ORDER 2 | 26 | #define BUFFER_ORDER 2 |
| 26 | #define BUFFER_SIZE (PAGE_SIZE << BUFFER_ORDER) | 27 | #define BUFFER_SIZE (PAGE_SIZE << BUFFER_ORDER) |
| 27 | 28 | ||
| 29 | /* | ||
| 30 | * Limit the test area size to the maximum MMC HC erase group size. Note that | ||
| 31 | * the maximum SD allocation unit size is just 4MiB. | ||
| 32 | */ | ||
| 33 | #define TEST_AREA_MAX_SIZE (128 * 1024 * 1024) | ||
| 34 | |||
| 28 | /** | 35 | /** |
| 29 | * struct mmc_test_pages - pages allocated by 'alloc_pages()'. | 36 | * struct mmc_test_pages - pages allocated by 'alloc_pages()'. |
| 30 | * @page: first page in the allocation | 37 | * @page: first page in the allocation |
| @@ -47,8 +54,8 @@ struct mmc_test_mem { | |||
| 47 | 54 | ||
| 48 | /** | 55 | /** |
| 49 | * struct mmc_test_area - information for performance tests. | 56 | * struct mmc_test_area - information for performance tests. |
| 50 | * @dev_addr: address on card at which to do performance tests | ||
| 51 | * @max_sz: test area size (in bytes) | 57 | * @max_sz: test area size (in bytes) |
| 58 | * @dev_addr: address on card at which to do performance tests | ||
| 52 | * @max_segs: maximum segments in scatterlist @sg | 59 | * @max_segs: maximum segments in scatterlist @sg |
| 53 | * @blocks: number of (512 byte) blocks currently mapped by @sg | 60 | * @blocks: number of (512 byte) blocks currently mapped by @sg |
| 54 | * @sg_len: length of currently mapped scatterlist @sg | 61 | * @sg_len: length of currently mapped scatterlist @sg |
| @@ -56,8 +63,8 @@ struct mmc_test_mem { | |||
| 56 | * @sg: scatterlist | 63 | * @sg: scatterlist |
| 57 | */ | 64 | */ |
| 58 | struct mmc_test_area { | 65 | struct mmc_test_area { |
| 66 | unsigned long max_sz; | ||
| 59 | unsigned int dev_addr; | 67 | unsigned int dev_addr; |
| 60 | unsigned int max_sz; | ||
| 61 | unsigned int max_segs; | 68 | unsigned int max_segs; |
| 62 | unsigned int blocks; | 69 | unsigned int blocks; |
| 63 | unsigned int sg_len; | 70 | unsigned int sg_len; |
| @@ -238,20 +245,19 @@ static void mmc_test_free_mem(struct mmc_test_mem *mem) | |||
| 238 | 245 | ||
| 239 | /* | 246 | /* |
| 240 | * Allocate a lot of memory, preferrably max_sz but at least min_sz. In case | 247 | * Allocate a lot of memory, preferrably max_sz but at least min_sz. In case |
| 241 | * there isn't much memory do not exceed 1/16th total RAM. | 248 | * there isn't much memory do not exceed 1/16th total lowmem pages. |
| 242 | */ | 249 | */ |
| 243 | static struct mmc_test_mem *mmc_test_alloc_mem(unsigned int min_sz, | 250 | static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz, |
| 244 | unsigned int max_sz) | 251 | unsigned long max_sz) |
| 245 | { | 252 | { |
| 246 | unsigned int max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE); | 253 | unsigned long max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE); |
| 247 | unsigned int min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE); | 254 | unsigned long min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE); |
| 248 | unsigned int page_cnt = 0; | 255 | unsigned long page_cnt = 0; |
| 256 | unsigned long limit = nr_free_buffer_pages() >> 4; | ||
| 249 | struct mmc_test_mem *mem; | 257 | struct mmc_test_mem *mem; |
| 250 | struct sysinfo si; | ||
| 251 | 258 | ||
| 252 | si_meminfo(&si); | 259 | if (max_page_cnt > limit) |
| 253 | if (max_page_cnt > si.totalram >> 4) | 260 | max_page_cnt = limit; |
| 254 | max_page_cnt = si.totalram >> 4; | ||
| 255 | if (max_page_cnt < min_page_cnt) | 261 | if (max_page_cnt < min_page_cnt) |
| 256 | max_page_cnt = min_page_cnt; | 262 | max_page_cnt = min_page_cnt; |
| 257 | 263 | ||
| @@ -270,7 +276,7 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned int min_sz, | |||
| 270 | gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN | | 276 | gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN | |
| 271 | __GFP_NORETRY; | 277 | __GFP_NORETRY; |
| 272 | 278 | ||
| 273 | order = get_order(page_cnt << PAGE_SHIFT); | 279 | order = get_order(max_page_cnt << PAGE_SHIFT); |
| 274 | while (1) { | 280 | while (1) { |
| 275 | page = alloc_pages(flags, order); | 281 | page = alloc_pages(flags, order); |
| 276 | if (page || !order) | 282 | if (page || !order) |
| @@ -285,8 +291,10 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned int min_sz, | |||
| 285 | mem->arr[mem->cnt].page = page; | 291 | mem->arr[mem->cnt].page = page; |
| 286 | mem->arr[mem->cnt].order = order; | 292 | mem->arr[mem->cnt].order = order; |
| 287 | mem->cnt += 1; | 293 | mem->cnt += 1; |
| 288 | max_page_cnt -= 1 << order; | 294 | if (max_page_cnt <= (1UL << order)) |
| 289 | page_cnt += 1 << order; | 295 | break; |
| 296 | max_page_cnt -= 1UL << order; | ||
| 297 | page_cnt += 1UL << order; | ||
| 290 | } | 298 | } |
| 291 | 299 | ||
| 292 | return mem; | 300 | return mem; |
| @@ -300,7 +308,7 @@ out_free: | |||
| 300 | * Map memory into a scatterlist. Optionally allow the same memory to be | 308 | * Map memory into a scatterlist. Optionally allow the same memory to be |
| 301 | * mapped more than once. | 309 | * mapped more than once. |
| 302 | */ | 310 | */ |
| 303 | static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned int sz, | 311 | static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz, |
| 304 | struct scatterlist *sglist, int repeat, | 312 | struct scatterlist *sglist, int repeat, |
| 305 | unsigned int max_segs, unsigned int *sg_len) | 313 | unsigned int max_segs, unsigned int *sg_len) |
| 306 | { | 314 | { |
| @@ -312,7 +320,7 @@ static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned int sz, | |||
| 312 | *sg_len = 0; | 320 | *sg_len = 0; |
| 313 | do { | 321 | do { |
| 314 | for (i = 0; i < mem->cnt; i++) { | 322 | for (i = 0; i < mem->cnt; i++) { |
| 315 | unsigned int len = PAGE_SIZE << mem->arr[i].order; | 323 | unsigned long len = PAGE_SIZE << mem->arr[i].order; |
| 316 | 324 | ||
| 317 | if (sz < len) | 325 | if (sz < len) |
| 318 | len = sz; | 326 | len = sz; |
| @@ -344,13 +352,14 @@ static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned int sz, | |||
| 344 | * same memory to be mapped more than once. | 352 | * same memory to be mapped more than once. |
| 345 | */ | 353 | */ |
| 346 | static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem, | 354 | static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem, |
| 347 | unsigned int sz, | 355 | unsigned long sz, |
| 348 | struct scatterlist *sglist, | 356 | struct scatterlist *sglist, |
| 349 | unsigned int max_segs, | 357 | unsigned int max_segs, |
| 350 | unsigned int *sg_len) | 358 | unsigned int *sg_len) |
| 351 | { | 359 | { |
| 352 | struct scatterlist *sg = NULL; | 360 | struct scatterlist *sg = NULL; |
| 353 | unsigned int i = mem->cnt, cnt, len; | 361 | unsigned int i = mem->cnt, cnt; |
| 362 | unsigned long len; | ||
| 354 | void *base, *addr, *last_addr = NULL; | 363 | void *base, *addr, *last_addr = NULL; |
| 355 | 364 | ||
| 356 | sg_init_table(sglist, max_segs); | 365 | sg_init_table(sglist, max_segs); |
| @@ -1202,7 +1211,7 @@ static int mmc_test_no_highmem(struct mmc_test_card *test) | |||
| 1202 | /* | 1211 | /* |
| 1203 | * Map sz bytes so that it can be transferred. | 1212 | * Map sz bytes so that it can be transferred. |
| 1204 | */ | 1213 | */ |
| 1205 | static int mmc_test_area_map(struct mmc_test_card *test, unsigned int sz, | 1214 | static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz, |
| 1206 | int max_scatter) | 1215 | int max_scatter) |
| 1207 | { | 1216 | { |
| 1208 | struct mmc_test_area *t = &test->area; | 1217 | struct mmc_test_area *t = &test->area; |
| @@ -1233,7 +1242,7 @@ static int mmc_test_area_transfer(struct mmc_test_card *test, | |||
| 1233 | /* | 1242 | /* |
| 1234 | * Map and transfer bytes. | 1243 | * Map and transfer bytes. |
| 1235 | */ | 1244 | */ |
| 1236 | static int mmc_test_area_io(struct mmc_test_card *test, unsigned int sz, | 1245 | static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz, |
| 1237 | unsigned int dev_addr, int write, int max_scatter, | 1246 | unsigned int dev_addr, int write, int max_scatter, |
| 1238 | int timed) | 1247 | int timed) |
| 1239 | { | 1248 | { |
| @@ -1308,19 +1317,22 @@ static int mmc_test_area_cleanup(struct mmc_test_card *test) | |||
| 1308 | static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill) | 1317 | static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill) |
| 1309 | { | 1318 | { |
| 1310 | struct mmc_test_area *t = &test->area; | 1319 | struct mmc_test_area *t = &test->area; |
| 1311 | unsigned int min_sz = 64 * 1024; | 1320 | unsigned long min_sz = 64 * 1024; |
| 1312 | int ret; | 1321 | int ret; |
| 1313 | 1322 | ||
| 1314 | ret = mmc_test_set_blksize(test, 512); | 1323 | ret = mmc_test_set_blksize(test, 512); |
| 1315 | if (ret) | 1324 | if (ret) |
| 1316 | return ret; | 1325 | return ret; |
| 1317 | 1326 | ||
| 1327 | if (test->card->pref_erase > TEST_AREA_MAX_SIZE >> 9) | ||
| 1328 | t->max_sz = TEST_AREA_MAX_SIZE; | ||
| 1329 | else | ||
| 1330 | t->max_sz = (unsigned long)test->card->pref_erase << 9; | ||
| 1318 | /* | 1331 | /* |
| 1319 | * Try to allocate enough memory for the whole area. Less is OK | 1332 | * Try to allocate enough memory for the whole area. Less is OK |
| 1320 | * because the same memory can be mapped into the scatterlist more than | 1333 | * because the same memory can be mapped into the scatterlist more than |
| 1321 | * once. | 1334 | * once. |
| 1322 | */ | 1335 | */ |
| 1323 | t->max_sz = test->card->pref_erase << 9; | ||
| 1324 | t->mem = mmc_test_alloc_mem(min_sz, t->max_sz); | 1336 | t->mem = mmc_test_alloc_mem(min_sz, t->max_sz); |
| 1325 | if (!t->mem) | 1337 | if (!t->mem) |
| 1326 | return -ENOMEM; | 1338 | return -ENOMEM; |
| @@ -1430,7 +1442,8 @@ static int mmc_test_best_write_perf_max_scatter(struct mmc_test_card *test) | |||
| 1430 | */ | 1442 | */ |
| 1431 | static int mmc_test_profile_read_perf(struct mmc_test_card *test) | 1443 | static int mmc_test_profile_read_perf(struct mmc_test_card *test) |
| 1432 | { | 1444 | { |
| 1433 | unsigned int sz, dev_addr; | 1445 | unsigned long sz; |
| 1446 | unsigned int dev_addr; | ||
| 1434 | int ret; | 1447 | int ret; |
| 1435 | 1448 | ||
| 1436 | for (sz = 512; sz < test->area.max_sz; sz <<= 1) { | 1449 | for (sz = 512; sz < test->area.max_sz; sz <<= 1) { |
| @@ -1448,7 +1461,8 @@ static int mmc_test_profile_read_perf(struct mmc_test_card *test) | |||
| 1448 | */ | 1461 | */ |
| 1449 | static int mmc_test_profile_write_perf(struct mmc_test_card *test) | 1462 | static int mmc_test_profile_write_perf(struct mmc_test_card *test) |
| 1450 | { | 1463 | { |
| 1451 | unsigned int sz, dev_addr; | 1464 | unsigned long sz; |
| 1465 | unsigned int dev_addr; | ||
| 1452 | int ret; | 1466 | int ret; |
| 1453 | 1467 | ||
| 1454 | ret = mmc_test_area_erase(test); | 1468 | ret = mmc_test_area_erase(test); |
| @@ -1472,7 +1486,8 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test) | |||
| 1472 | */ | 1486 | */ |
| 1473 | static int mmc_test_profile_trim_perf(struct mmc_test_card *test) | 1487 | static int mmc_test_profile_trim_perf(struct mmc_test_card *test) |
| 1474 | { | 1488 | { |
| 1475 | unsigned int sz, dev_addr; | 1489 | unsigned long sz; |
| 1490 | unsigned int dev_addr; | ||
| 1476 | struct timespec ts1, ts2; | 1491 | struct timespec ts1, ts2; |
| 1477 | int ret; | 1492 | int ret; |
| 1478 | 1493 | ||
| @@ -1506,7 +1521,8 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test) | |||
| 1506 | */ | 1521 | */ |
| 1507 | static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test) | 1522 | static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test) |
| 1508 | { | 1523 | { |
| 1509 | unsigned int sz, dev_addr, i, cnt; | 1524 | unsigned long sz; |
| 1525 | unsigned int dev_addr, i, cnt; | ||
| 1510 | struct timespec ts1, ts2; | 1526 | struct timespec ts1, ts2; |
| 1511 | int ret; | 1527 | int ret; |
| 1512 | 1528 | ||
| @@ -1531,7 +1547,8 @@ static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test) | |||
| 1531 | */ | 1547 | */ |
| 1532 | static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test) | 1548 | static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test) |
| 1533 | { | 1549 | { |
| 1534 | unsigned int sz, dev_addr, i, cnt; | 1550 | unsigned long sz; |
| 1551 | unsigned int dev_addr, i, cnt; | ||
| 1535 | struct timespec ts1, ts2; | 1552 | struct timespec ts1, ts2; |
| 1536 | int ret; | 1553 | int ret; |
| 1537 | 1554 | ||
| @@ -1559,7 +1576,8 @@ static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test) | |||
| 1559 | */ | 1576 | */ |
| 1560 | static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test) | 1577 | static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test) |
| 1561 | { | 1578 | { |
| 1562 | unsigned int sz, dev_addr, i, cnt; | 1579 | unsigned long sz; |
| 1580 | unsigned int dev_addr, i, cnt; | ||
| 1563 | struct timespec ts1, ts2; | 1581 | struct timespec ts1, ts2; |
| 1564 | int ret; | 1582 | int ret; |
| 1565 | 1583 | ||
