| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright 2007-2008 Pierre Ossman |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 6 | | - * the Free Software Foundation; either version 2 of the License, or (at |
|---|
| 7 | | - * your option) any later version. |
|---|
| 8 | 4 | */ |
|---|
| 9 | 5 | |
|---|
| 10 | 6 | #include <linux/mmc/core.h> |
|---|
| .. | .. |
|---|
| 75 | 71 | * @sg_len: length of currently mapped scatterlist @sg |
|---|
| 76 | 72 | * @mem: allocated memory |
|---|
| 77 | 73 | * @sg: scatterlist |
|---|
| 74 | + * @sg_areq: scatterlist for non-blocking request |
|---|
| 78 | 75 | */ |
|---|
| 79 | 76 | struct mmc_test_area { |
|---|
| 80 | 77 | unsigned long max_sz; |
|---|
| .. | .. |
|---|
| 86 | 83 | unsigned int sg_len; |
|---|
| 87 | 84 | struct mmc_test_mem *mem; |
|---|
| 88 | 85 | struct scatterlist *sg; |
|---|
| 86 | + struct scatterlist *sg_areq; |
|---|
| 89 | 87 | }; |
|---|
| 90 | 88 | |
|---|
| 91 | 89 | /** |
|---|
| .. | .. |
|---|
| 840 | 838 | } |
|---|
| 841 | 839 | |
|---|
| 842 | 840 | static int mmc_test_nonblock_transfer(struct mmc_test_card *test, |
|---|
| 843 | | - struct scatterlist *sg, unsigned sg_len, |
|---|
| 844 | | - unsigned dev_addr, unsigned blocks, |
|---|
| 845 | | - unsigned blksz, int write, int count) |
|---|
| 841 | + unsigned int dev_addr, int write, |
|---|
| 842 | + int count) |
|---|
| 846 | 843 | { |
|---|
| 847 | 844 | struct mmc_test_req *rq1, *rq2; |
|---|
| 848 | 845 | struct mmc_request *mrq, *prev_mrq; |
|---|
| 849 | 846 | int i; |
|---|
| 850 | 847 | int ret = RESULT_OK; |
|---|
| 848 | + struct mmc_test_area *t = &test->area; |
|---|
| 849 | + struct scatterlist *sg = t->sg; |
|---|
| 850 | + struct scatterlist *sg_areq = t->sg_areq; |
|---|
| 851 | 851 | |
|---|
| 852 | 852 | rq1 = mmc_test_req_alloc(); |
|---|
| 853 | 853 | rq2 = mmc_test_req_alloc(); |
|---|
| .. | .. |
|---|
| 861 | 861 | |
|---|
| 862 | 862 | for (i = 0; i < count; i++) { |
|---|
| 863 | 863 | mmc_test_req_reset(container_of(mrq, struct mmc_test_req, mrq)); |
|---|
| 864 | | - mmc_test_prepare_mrq(test, mrq, sg, sg_len, dev_addr, blocks, |
|---|
| 865 | | - blksz, write); |
|---|
| 864 | + mmc_test_prepare_mrq(test, mrq, sg, t->sg_len, dev_addr, |
|---|
| 865 | + t->blocks, 512, write); |
|---|
| 866 | 866 | ret = mmc_test_start_areq(test, mrq, prev_mrq); |
|---|
| 867 | 867 | if (ret) |
|---|
| 868 | 868 | goto err; |
|---|
| .. | .. |
|---|
| 871 | 871 | prev_mrq = &rq2->mrq; |
|---|
| 872 | 872 | |
|---|
| 873 | 873 | swap(mrq, prev_mrq); |
|---|
| 874 | | - dev_addr += blocks; |
|---|
| 874 | + swap(sg, sg_areq); |
|---|
| 875 | + dev_addr += t->blocks; |
|---|
| 875 | 876 | } |
|---|
| 876 | 877 | |
|---|
| 877 | 878 | ret = mmc_test_start_areq(test, NULL, prev_mrq); |
|---|
| .. | .. |
|---|
| 1400 | 1401 | * Map sz bytes so that it can be transferred. |
|---|
| 1401 | 1402 | */ |
|---|
| 1402 | 1403 | static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz, |
|---|
| 1403 | | - int max_scatter, int min_sg_len) |
|---|
| 1404 | + int max_scatter, int min_sg_len, bool nonblock) |
|---|
| 1404 | 1405 | { |
|---|
| 1405 | 1406 | struct mmc_test_area *t = &test->area; |
|---|
| 1406 | 1407 | int err; |
|---|
| 1408 | + unsigned int sg_len = 0; |
|---|
| 1407 | 1409 | |
|---|
| 1408 | 1410 | t->blocks = sz >> 9; |
|---|
| 1409 | 1411 | |
|---|
| .. | .. |
|---|
| 1415 | 1417 | err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs, |
|---|
| 1416 | 1418 | t->max_seg_sz, &t->sg_len, min_sg_len); |
|---|
| 1417 | 1419 | } |
|---|
| 1420 | + |
|---|
| 1421 | + if (err || !nonblock) |
|---|
| 1422 | + goto err; |
|---|
| 1423 | + |
|---|
| 1424 | + if (max_scatter) { |
|---|
| 1425 | + err = mmc_test_map_sg_max_scatter(t->mem, sz, t->sg_areq, |
|---|
| 1426 | + t->max_segs, t->max_seg_sz, |
|---|
| 1427 | + &sg_len); |
|---|
| 1428 | + } else { |
|---|
| 1429 | + err = mmc_test_map_sg(t->mem, sz, t->sg_areq, 1, t->max_segs, |
|---|
| 1430 | + t->max_seg_sz, &sg_len, min_sg_len); |
|---|
| 1431 | + } |
|---|
| 1432 | + if (!err && sg_len != t->sg_len) |
|---|
| 1433 | + err = -EINVAL; |
|---|
| 1434 | + |
|---|
| 1435 | +err: |
|---|
| 1418 | 1436 | if (err) |
|---|
| 1419 | 1437 | pr_info("%s: Failed to map sg list\n", |
|---|
| 1420 | 1438 | mmc_hostname(test->card->host)); |
|---|
| .. | .. |
|---|
| 1444 | 1462 | struct timespec64 ts1, ts2; |
|---|
| 1445 | 1463 | int ret = 0; |
|---|
| 1446 | 1464 | int i; |
|---|
| 1447 | | - struct mmc_test_area *t = &test->area; |
|---|
| 1448 | 1465 | |
|---|
| 1449 | 1466 | /* |
|---|
| 1450 | 1467 | * In the case of a maximally scattered transfer, the maximum transfer |
|---|
| .. | .. |
|---|
| 1462 | 1479 | sz = max_tfr; |
|---|
| 1463 | 1480 | } |
|---|
| 1464 | 1481 | |
|---|
| 1465 | | - ret = mmc_test_area_map(test, sz, max_scatter, min_sg_len); |
|---|
| 1482 | + ret = mmc_test_area_map(test, sz, max_scatter, min_sg_len, nonblock); |
|---|
| 1466 | 1483 | if (ret) |
|---|
| 1467 | 1484 | return ret; |
|---|
| 1468 | 1485 | |
|---|
| 1469 | 1486 | if (timed) |
|---|
| 1470 | 1487 | ktime_get_ts64(&ts1); |
|---|
| 1471 | 1488 | if (nonblock) |
|---|
| 1472 | | - ret = mmc_test_nonblock_transfer(test, t->sg, t->sg_len, |
|---|
| 1473 | | - dev_addr, t->blocks, 512, write, count); |
|---|
| 1489 | + ret = mmc_test_nonblock_transfer(test, dev_addr, write, count); |
|---|
| 1474 | 1490 | else |
|---|
| 1475 | 1491 | for (i = 0; i < count && ret == 0; i++) { |
|---|
| 1476 | 1492 | ret = mmc_test_area_transfer(test, dev_addr, write); |
|---|
| .. | .. |
|---|
| 1529 | 1545 | struct mmc_test_area *t = &test->area; |
|---|
| 1530 | 1546 | |
|---|
| 1531 | 1547 | kfree(t->sg); |
|---|
| 1548 | + kfree(t->sg_areq); |
|---|
| 1532 | 1549 | mmc_test_free_mem(t->mem); |
|---|
| 1533 | 1550 | |
|---|
| 1534 | 1551 | return 0; |
|---|
| .. | .. |
|---|
| 1584 | 1601 | |
|---|
| 1585 | 1602 | t->sg = kmalloc_array(t->max_segs, sizeof(*t->sg), GFP_KERNEL); |
|---|
| 1586 | 1603 | if (!t->sg) { |
|---|
| 1604 | + ret = -ENOMEM; |
|---|
| 1605 | + goto out_free; |
|---|
| 1606 | + } |
|---|
| 1607 | + |
|---|
| 1608 | + t->sg_areq = kmalloc_array(t->max_segs, sizeof(*t->sg_areq), |
|---|
| 1609 | + GFP_KERNEL); |
|---|
| 1610 | + if (!t->sg_areq) { |
|---|
| 1587 | 1611 | ret = -ENOMEM; |
|---|
| 1588 | 1612 | goto out_free; |
|---|
| 1589 | 1613 | } |
|---|
| .. | .. |
|---|
| 2472 | 2496 | if (!(test->card->host->caps & MMC_CAP_CMD_DURING_TFR)) |
|---|
| 2473 | 2497 | return RESULT_UNSUP_HOST; |
|---|
| 2474 | 2498 | |
|---|
| 2475 | | - ret = mmc_test_area_map(test, sz, 0, 0); |
|---|
| 2499 | + ret = mmc_test_area_map(test, sz, 0, 0, use_areq); |
|---|
| 2476 | 2500 | if (ret) |
|---|
| 2477 | 2501 | return ret; |
|---|
| 2478 | 2502 | |
|---|
| .. | .. |
|---|
| 2645 | 2669 | }, |
|---|
| 2646 | 2670 | |
|---|
| 2647 | 2671 | { |
|---|
| 2648 | | - .name = "Correct xfer_size at write (start failure)", |
|---|
| 2672 | + .name = "Proper xfer_size at write (start failure)", |
|---|
| 2649 | 2673 | .run = mmc_test_xfersize_write, |
|---|
| 2650 | 2674 | }, |
|---|
| 2651 | 2675 | |
|---|
| 2652 | 2676 | { |
|---|
| 2653 | | - .name = "Correct xfer_size at read (start failure)", |
|---|
| 2677 | + .name = "Proper xfer_size at read (start failure)", |
|---|
| 2654 | 2678 | .run = mmc_test_xfersize_read, |
|---|
| 2655 | 2679 | }, |
|---|
| 2656 | 2680 | |
|---|
| 2657 | 2681 | { |
|---|
| 2658 | | - .name = "Correct xfer_size at write (midway failure)", |
|---|
| 2682 | + .name = "Proper xfer_size at write (midway failure)", |
|---|
| 2659 | 2683 | .run = mmc_test_multi_xfersize_write, |
|---|
| 2660 | 2684 | }, |
|---|
| 2661 | 2685 | |
|---|
| 2662 | 2686 | { |
|---|
| 2663 | | - .name = "Correct xfer_size at read (midway failure)", |
|---|
| 2687 | + .name = "Proper xfer_size at read (midway failure)", |
|---|
| 2664 | 2688 | .run = mmc_test_multi_xfersize_read, |
|---|
| 2665 | 2689 | }, |
|---|
| 2666 | 2690 | |
|---|
| .. | .. |
|---|
| 3145 | 3169 | return 0; |
|---|
| 3146 | 3170 | } |
|---|
| 3147 | 3171 | |
|---|
| 3148 | | -static int mtf_testlist_open(struct inode *inode, struct file *file) |
|---|
| 3149 | | -{ |
|---|
| 3150 | | - return single_open(file, mtf_testlist_show, inode->i_private); |
|---|
| 3151 | | -} |
|---|
| 3152 | | - |
|---|
| 3153 | | -static const struct file_operations mmc_test_fops_testlist = { |
|---|
| 3154 | | - .open = mtf_testlist_open, |
|---|
| 3155 | | - .read = seq_read, |
|---|
| 3156 | | - .llseek = seq_lseek, |
|---|
| 3157 | | - .release = single_release, |
|---|
| 3158 | | -}; |
|---|
| 3172 | +DEFINE_SHOW_ATTRIBUTE(mtf_testlist); |
|---|
| 3159 | 3173 | |
|---|
| 3160 | 3174 | static void mmc_test_free_dbgfs_file(struct mmc_card *card) |
|---|
| 3161 | 3175 | { |
|---|
| .. | .. |
|---|
| 3182 | 3196 | |
|---|
| 3183 | 3197 | if (card->debugfs_root) |
|---|
| 3184 | 3198 | file = debugfs_create_file(name, mode, card->debugfs_root, |
|---|
| 3185 | | - card, fops); |
|---|
| 3186 | | - |
|---|
| 3187 | | - if (IS_ERR_OR_NULL(file)) { |
|---|
| 3188 | | - dev_err(&card->dev, |
|---|
| 3189 | | - "Can't create %s. Perhaps debugfs is disabled.\n", |
|---|
| 3190 | | - name); |
|---|
| 3191 | | - return -ENODEV; |
|---|
| 3192 | | - } |
|---|
| 3199 | + card, fops); |
|---|
| 3193 | 3200 | |
|---|
| 3194 | 3201 | df = kmalloc(sizeof(*df), GFP_KERNEL); |
|---|
| 3195 | 3202 | if (!df) { |
|---|
| .. | .. |
|---|
| 3216 | 3223 | goto err; |
|---|
| 3217 | 3224 | |
|---|
| 3218 | 3225 | ret = __mmc_test_register_dbgfs_file(card, "testlist", S_IRUGO, |
|---|
| 3219 | | - &mmc_test_fops_testlist); |
|---|
| 3226 | + &mtf_testlist_fops); |
|---|
| 3220 | 3227 | if (ret) |
|---|
| 3221 | 3228 | goto err; |
|---|
| 3222 | 3229 | |
|---|