1f397c8d8SUlf Hansson /* 2f397c8d8SUlf Hansson * Copyright 2007-2008 Pierre Ossman 3f397c8d8SUlf Hansson * 4f397c8d8SUlf Hansson * This program is free software; you can redistribute it and/or modify 5f397c8d8SUlf Hansson * it under the terms of the GNU General Public License as published by 6f397c8d8SUlf Hansson * the Free Software Foundation; either version 2 of the License, or (at 7f397c8d8SUlf Hansson * your option) any later version. 8f397c8d8SUlf Hansson */ 9f397c8d8SUlf Hansson 10f397c8d8SUlf Hansson #include <linux/mmc/core.h> 11f397c8d8SUlf Hansson #include <linux/mmc/card.h> 12f397c8d8SUlf Hansson #include <linux/mmc/host.h> 13f397c8d8SUlf Hansson #include <linux/mmc/mmc.h> 14f397c8d8SUlf Hansson #include <linux/slab.h> 15f397c8d8SUlf Hansson 16f397c8d8SUlf Hansson #include <linux/scatterlist.h> 17f397c8d8SUlf Hansson #include <linux/swap.h> /* For nr_free_buffer_pages() */ 18f397c8d8SUlf Hansson #include <linux/list.h> 19f397c8d8SUlf Hansson 20f397c8d8SUlf Hansson #include <linux/debugfs.h> 21f397c8d8SUlf Hansson #include <linux/uaccess.h> 22f397c8d8SUlf Hansson #include <linux/seq_file.h> 23f397c8d8SUlf Hansson #include <linux/module.h> 24f397c8d8SUlf Hansson 2555244c56SUlf Hansson #include "core.h" 264facdde1SUlf Hansson #include "card.h" 275857b29bSUlf Hansson #include "host.h" 284facdde1SUlf Hansson #include "bus.h" 299d4579a8SAdrian Hunter #include "mmc_ops.h" 3055244c56SUlf Hansson 31f397c8d8SUlf Hansson #define RESULT_OK 0 32f397c8d8SUlf Hansson #define RESULT_FAIL 1 33f397c8d8SUlf Hansson #define RESULT_UNSUP_HOST 2 34f397c8d8SUlf Hansson #define RESULT_UNSUP_CARD 3 35f397c8d8SUlf Hansson 36f397c8d8SUlf Hansson #define BUFFER_ORDER 2 37f397c8d8SUlf Hansson #define BUFFER_SIZE (PAGE_SIZE << BUFFER_ORDER) 38f397c8d8SUlf Hansson 39f397c8d8SUlf Hansson #define TEST_ALIGN_END 8 40f397c8d8SUlf Hansson 41f397c8d8SUlf Hansson /* 42f397c8d8SUlf Hansson * Limit the test area size to the maximum MMC HC erase group size. Note that 43f397c8d8SUlf Hansson * the maximum SD allocation unit size is just 4MiB. 44f397c8d8SUlf Hansson */ 45f397c8d8SUlf Hansson #define TEST_AREA_MAX_SIZE (128 * 1024 * 1024) 46f397c8d8SUlf Hansson 47f397c8d8SUlf Hansson /** 48f397c8d8SUlf Hansson * struct mmc_test_pages - pages allocated by 'alloc_pages()'. 49f397c8d8SUlf Hansson * @page: first page in the allocation 50f397c8d8SUlf Hansson * @order: order of the number of pages allocated 51f397c8d8SUlf Hansson */ 52f397c8d8SUlf Hansson struct mmc_test_pages { 53f397c8d8SUlf Hansson struct page *page; 54f397c8d8SUlf Hansson unsigned int order; 55f397c8d8SUlf Hansson }; 56f397c8d8SUlf Hansson 57f397c8d8SUlf Hansson /** 58f397c8d8SUlf Hansson * struct mmc_test_mem - allocated memory. 59f397c8d8SUlf Hansson * @arr: array of allocations 60f397c8d8SUlf Hansson * @cnt: number of allocations 61f397c8d8SUlf Hansson */ 62f397c8d8SUlf Hansson struct mmc_test_mem { 63f397c8d8SUlf Hansson struct mmc_test_pages *arr; 64f397c8d8SUlf Hansson unsigned int cnt; 65f397c8d8SUlf Hansson }; 66f397c8d8SUlf Hansson 67f397c8d8SUlf Hansson /** 68f397c8d8SUlf Hansson * struct mmc_test_area - information for performance tests. 69f397c8d8SUlf Hansson * @max_sz: test area size (in bytes) 70f397c8d8SUlf Hansson * @dev_addr: address on card at which to do performance tests 71f397c8d8SUlf Hansson * @max_tfr: maximum transfer size allowed by driver (in bytes) 72f397c8d8SUlf Hansson * @max_segs: maximum segments allowed by driver in scatterlist @sg 73f397c8d8SUlf Hansson * @max_seg_sz: maximum segment size allowed by driver 74f397c8d8SUlf Hansson * @blocks: number of (512 byte) blocks currently mapped by @sg 75f397c8d8SUlf Hansson * @sg_len: length of currently mapped scatterlist @sg 76f397c8d8SUlf Hansson * @mem: allocated memory 77f397c8d8SUlf Hansson * @sg: scatterlist 78f397c8d8SUlf Hansson */ 79f397c8d8SUlf Hansson struct mmc_test_area { 80f397c8d8SUlf Hansson unsigned long max_sz; 81f397c8d8SUlf Hansson unsigned int dev_addr; 82f397c8d8SUlf Hansson unsigned int max_tfr; 83f397c8d8SUlf Hansson unsigned int max_segs; 84f397c8d8SUlf Hansson unsigned int max_seg_sz; 85f397c8d8SUlf Hansson unsigned int blocks; 86f397c8d8SUlf Hansson unsigned int sg_len; 87f397c8d8SUlf Hansson struct mmc_test_mem *mem; 88f397c8d8SUlf Hansson struct scatterlist *sg; 89f397c8d8SUlf Hansson }; 90f397c8d8SUlf Hansson 91f397c8d8SUlf Hansson /** 92f397c8d8SUlf Hansson * struct mmc_test_transfer_result - transfer results for performance tests. 93f397c8d8SUlf Hansson * @link: double-linked list 94f397c8d8SUlf Hansson * @count: amount of group of sectors to check 95f397c8d8SUlf Hansson * @sectors: amount of sectors to check in one group 96f397c8d8SUlf Hansson * @ts: time values of transfer 97f397c8d8SUlf Hansson * @rate: calculated transfer rate 98f397c8d8SUlf Hansson * @iops: I/O operations per second (times 100) 99f397c8d8SUlf Hansson */ 100f397c8d8SUlf Hansson struct mmc_test_transfer_result { 101f397c8d8SUlf Hansson struct list_head link; 102f397c8d8SUlf Hansson unsigned int count; 103f397c8d8SUlf Hansson unsigned int sectors; 104f397c8d8SUlf Hansson struct timespec ts; 105f397c8d8SUlf Hansson unsigned int rate; 106f397c8d8SUlf Hansson unsigned int iops; 107f397c8d8SUlf Hansson }; 108f397c8d8SUlf Hansson 109f397c8d8SUlf Hansson /** 110f397c8d8SUlf Hansson * struct mmc_test_general_result - results for tests. 111f397c8d8SUlf Hansson * @link: double-linked list 112f397c8d8SUlf Hansson * @card: card under test 113f397c8d8SUlf Hansson * @testcase: number of test case 114f397c8d8SUlf Hansson * @result: result of test run 115f397c8d8SUlf Hansson * @tr_lst: transfer measurements if any as mmc_test_transfer_result 116f397c8d8SUlf Hansson */ 117f397c8d8SUlf Hansson struct mmc_test_general_result { 118f397c8d8SUlf Hansson struct list_head link; 119f397c8d8SUlf Hansson struct mmc_card *card; 120f397c8d8SUlf Hansson int testcase; 121f397c8d8SUlf Hansson int result; 122f397c8d8SUlf Hansson struct list_head tr_lst; 123f397c8d8SUlf Hansson }; 124f397c8d8SUlf Hansson 125f397c8d8SUlf Hansson /** 126f397c8d8SUlf Hansson * struct mmc_test_dbgfs_file - debugfs related file. 127f397c8d8SUlf Hansson * @link: double-linked list 128f397c8d8SUlf Hansson * @card: card under test 129f397c8d8SUlf Hansson * @file: file created under debugfs 130f397c8d8SUlf Hansson */ 131f397c8d8SUlf Hansson struct mmc_test_dbgfs_file { 132f397c8d8SUlf Hansson struct list_head link; 133f397c8d8SUlf Hansson struct mmc_card *card; 134f397c8d8SUlf Hansson struct dentry *file; 135f397c8d8SUlf Hansson }; 136f397c8d8SUlf Hansson 137f397c8d8SUlf Hansson /** 138f397c8d8SUlf Hansson * struct mmc_test_card - test information. 139f397c8d8SUlf Hansson * @card: card under test 140f397c8d8SUlf Hansson * @scratch: transfer buffer 141f397c8d8SUlf Hansson * @buffer: transfer buffer 142f397c8d8SUlf Hansson * @highmem: buffer for highmem tests 143f397c8d8SUlf Hansson * @area: information for performance tests 144f397c8d8SUlf Hansson * @gr: pointer to results of current testcase 145f397c8d8SUlf Hansson */ 146f397c8d8SUlf Hansson struct mmc_test_card { 147f397c8d8SUlf Hansson struct mmc_card *card; 148f397c8d8SUlf Hansson 149f397c8d8SUlf Hansson u8 scratch[BUFFER_SIZE]; 150f397c8d8SUlf Hansson u8 *buffer; 151f397c8d8SUlf Hansson #ifdef CONFIG_HIGHMEM 152f397c8d8SUlf Hansson struct page *highmem; 153f397c8d8SUlf Hansson #endif 154f397c8d8SUlf Hansson struct mmc_test_area area; 155f397c8d8SUlf Hansson struct mmc_test_general_result *gr; 156f397c8d8SUlf Hansson }; 157f397c8d8SUlf Hansson 158f397c8d8SUlf Hansson enum mmc_test_prep_media { 159f397c8d8SUlf Hansson MMC_TEST_PREP_NONE = 0, 160f397c8d8SUlf Hansson MMC_TEST_PREP_WRITE_FULL = 1 << 0, 161f397c8d8SUlf Hansson MMC_TEST_PREP_ERASE = 1 << 1, 162f397c8d8SUlf Hansson }; 163f397c8d8SUlf Hansson 164f397c8d8SUlf Hansson struct mmc_test_multiple_rw { 165f397c8d8SUlf Hansson unsigned int *sg_len; 166f397c8d8SUlf Hansson unsigned int *bs; 167f397c8d8SUlf Hansson unsigned int len; 168f397c8d8SUlf Hansson unsigned int size; 169f397c8d8SUlf Hansson bool do_write; 170f397c8d8SUlf Hansson bool do_nonblock_req; 171f397c8d8SUlf Hansson enum mmc_test_prep_media prepare; 172f397c8d8SUlf Hansson }; 173f397c8d8SUlf Hansson 174f397c8d8SUlf Hansson struct mmc_test_async_req { 175f397c8d8SUlf Hansson struct mmc_async_req areq; 176f397c8d8SUlf Hansson struct mmc_test_card *test; 177f397c8d8SUlf Hansson }; 178f397c8d8SUlf Hansson 179f397c8d8SUlf Hansson /*******************************************************************/ 180f397c8d8SUlf Hansson /* General helper functions */ 181f397c8d8SUlf Hansson /*******************************************************************/ 182f397c8d8SUlf Hansson 183f397c8d8SUlf Hansson /* 184f397c8d8SUlf Hansson * Configure correct block size in card 185f397c8d8SUlf Hansson */ 186f397c8d8SUlf Hansson static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size) 187f397c8d8SUlf Hansson { 188f397c8d8SUlf Hansson return mmc_set_blocklen(test->card, size); 189f397c8d8SUlf Hansson } 190f397c8d8SUlf Hansson 191f397c8d8SUlf Hansson static bool mmc_test_card_cmd23(struct mmc_card *card) 192f397c8d8SUlf Hansson { 193f397c8d8SUlf Hansson return mmc_card_mmc(card) || 194f397c8d8SUlf Hansson (mmc_card_sd(card) && card->scr.cmds & SD_SCR_CMD23_SUPPORT); 195f397c8d8SUlf Hansson } 196f397c8d8SUlf Hansson 197f397c8d8SUlf Hansson static void mmc_test_prepare_sbc(struct mmc_test_card *test, 198f397c8d8SUlf Hansson struct mmc_request *mrq, unsigned int blocks) 199f397c8d8SUlf Hansson { 200f397c8d8SUlf Hansson struct mmc_card *card = test->card; 201f397c8d8SUlf Hansson 202f397c8d8SUlf Hansson if (!mrq->sbc || !mmc_host_cmd23(card->host) || 203f397c8d8SUlf Hansson !mmc_test_card_cmd23(card) || !mmc_op_multi(mrq->cmd->opcode) || 204f397c8d8SUlf Hansson (card->quirks & MMC_QUIRK_BLK_NO_CMD23)) { 205f397c8d8SUlf Hansson mrq->sbc = NULL; 206f397c8d8SUlf Hansson return; 207f397c8d8SUlf Hansson } 208f397c8d8SUlf Hansson 209f397c8d8SUlf Hansson mrq->sbc->opcode = MMC_SET_BLOCK_COUNT; 210f397c8d8SUlf Hansson mrq->sbc->arg = blocks; 211f397c8d8SUlf Hansson mrq->sbc->flags = MMC_RSP_R1 | MMC_CMD_AC; 212f397c8d8SUlf Hansson } 213f397c8d8SUlf Hansson 214f397c8d8SUlf Hansson /* 215f397c8d8SUlf Hansson * Fill in the mmc_request structure given a set of transfer parameters. 216f397c8d8SUlf Hansson */ 217f397c8d8SUlf Hansson static void mmc_test_prepare_mrq(struct mmc_test_card *test, 218f397c8d8SUlf Hansson struct mmc_request *mrq, struct scatterlist *sg, unsigned sg_len, 219f397c8d8SUlf Hansson unsigned dev_addr, unsigned blocks, unsigned blksz, int write) 220f397c8d8SUlf Hansson { 221f397c8d8SUlf Hansson if (WARN_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop)) 222f397c8d8SUlf Hansson return; 223f397c8d8SUlf Hansson 224f397c8d8SUlf Hansson if (blocks > 1) { 225f397c8d8SUlf Hansson mrq->cmd->opcode = write ? 226f397c8d8SUlf Hansson MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK; 227f397c8d8SUlf Hansson } else { 228f397c8d8SUlf Hansson mrq->cmd->opcode = write ? 229f397c8d8SUlf Hansson MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK; 230f397c8d8SUlf Hansson } 231f397c8d8SUlf Hansson 232f397c8d8SUlf Hansson mrq->cmd->arg = dev_addr; 233f397c8d8SUlf Hansson if (!mmc_card_blockaddr(test->card)) 234f397c8d8SUlf Hansson mrq->cmd->arg <<= 9; 235f397c8d8SUlf Hansson 236f397c8d8SUlf Hansson mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC; 237f397c8d8SUlf Hansson 238f397c8d8SUlf Hansson if (blocks == 1) 239f397c8d8SUlf Hansson mrq->stop = NULL; 240f397c8d8SUlf Hansson else { 241f397c8d8SUlf Hansson mrq->stop->opcode = MMC_STOP_TRANSMISSION; 242f397c8d8SUlf Hansson mrq->stop->arg = 0; 243f397c8d8SUlf Hansson mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC; 244f397c8d8SUlf Hansson } 245f397c8d8SUlf Hansson 246f397c8d8SUlf Hansson mrq->data->blksz = blksz; 247f397c8d8SUlf Hansson mrq->data->blocks = blocks; 248f397c8d8SUlf Hansson mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; 249f397c8d8SUlf Hansson mrq->data->sg = sg; 250f397c8d8SUlf Hansson mrq->data->sg_len = sg_len; 251f397c8d8SUlf Hansson 252f397c8d8SUlf Hansson mmc_test_prepare_sbc(test, mrq, blocks); 253f397c8d8SUlf Hansson 254f397c8d8SUlf Hansson mmc_set_data_timeout(mrq->data, test->card); 255f397c8d8SUlf Hansson } 256f397c8d8SUlf Hansson 257f397c8d8SUlf Hansson static int mmc_test_busy(struct mmc_command *cmd) 258f397c8d8SUlf Hansson { 259f397c8d8SUlf Hansson return !(cmd->resp[0] & R1_READY_FOR_DATA) || 260f397c8d8SUlf Hansson (R1_CURRENT_STATE(cmd->resp[0]) == R1_STATE_PRG); 261f397c8d8SUlf Hansson } 262f397c8d8SUlf Hansson 263f397c8d8SUlf Hansson /* 264f397c8d8SUlf Hansson * Wait for the card to finish the busy state 265f397c8d8SUlf Hansson */ 266f397c8d8SUlf Hansson static int mmc_test_wait_busy(struct mmc_test_card *test) 267f397c8d8SUlf Hansson { 268f397c8d8SUlf Hansson int ret, busy; 269c7836d15SMasahiro Yamada struct mmc_command cmd = {}; 270f397c8d8SUlf Hansson 271f397c8d8SUlf Hansson busy = 0; 272f397c8d8SUlf Hansson do { 273f397c8d8SUlf Hansson memset(&cmd, 0, sizeof(struct mmc_command)); 274f397c8d8SUlf Hansson 275f397c8d8SUlf Hansson cmd.opcode = MMC_SEND_STATUS; 276f397c8d8SUlf Hansson cmd.arg = test->card->rca << 16; 277f397c8d8SUlf Hansson cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 278f397c8d8SUlf Hansson 279f397c8d8SUlf Hansson ret = mmc_wait_for_cmd(test->card->host, &cmd, 0); 280f397c8d8SUlf Hansson if (ret) 281f397c8d8SUlf Hansson break; 282f397c8d8SUlf Hansson 283f397c8d8SUlf Hansson if (!busy && mmc_test_busy(&cmd)) { 284f397c8d8SUlf Hansson busy = 1; 285f397c8d8SUlf Hansson if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) 2867200449dSMarkus Elfring pr_info("%s: Warning: Host did not wait for busy state to end.\n", 287f397c8d8SUlf Hansson mmc_hostname(test->card->host)); 288f397c8d8SUlf Hansson } 289f397c8d8SUlf Hansson } while (mmc_test_busy(&cmd)); 290f397c8d8SUlf Hansson 291f397c8d8SUlf Hansson return ret; 292f397c8d8SUlf Hansson } 293f397c8d8SUlf Hansson 294f397c8d8SUlf Hansson /* 295f397c8d8SUlf Hansson * Transfer a single sector of kernel addressable data 296f397c8d8SUlf Hansson */ 297f397c8d8SUlf Hansson static int mmc_test_buffer_transfer(struct mmc_test_card *test, 298f397c8d8SUlf Hansson u8 *buffer, unsigned addr, unsigned blksz, int write) 299f397c8d8SUlf Hansson { 300c7836d15SMasahiro Yamada struct mmc_request mrq = {}; 301c7836d15SMasahiro Yamada struct mmc_command cmd = {}; 302c7836d15SMasahiro Yamada struct mmc_command stop = {}; 303c7836d15SMasahiro Yamada struct mmc_data data = {}; 304f397c8d8SUlf Hansson 305f397c8d8SUlf Hansson struct scatterlist sg; 306f397c8d8SUlf Hansson 307f397c8d8SUlf Hansson mrq.cmd = &cmd; 308f397c8d8SUlf Hansson mrq.data = &data; 309f397c8d8SUlf Hansson mrq.stop = &stop; 310f397c8d8SUlf Hansson 311f397c8d8SUlf Hansson sg_init_one(&sg, buffer, blksz); 312f397c8d8SUlf Hansson 313f397c8d8SUlf Hansson mmc_test_prepare_mrq(test, &mrq, &sg, 1, addr, 1, blksz, write); 314f397c8d8SUlf Hansson 315f397c8d8SUlf Hansson mmc_wait_for_req(test->card->host, &mrq); 316f397c8d8SUlf Hansson 317f397c8d8SUlf Hansson if (cmd.error) 318f397c8d8SUlf Hansson return cmd.error; 319f397c8d8SUlf Hansson if (data.error) 320f397c8d8SUlf Hansson return data.error; 321f397c8d8SUlf Hansson 322f397c8d8SUlf Hansson return mmc_test_wait_busy(test); 323f397c8d8SUlf Hansson } 324f397c8d8SUlf Hansson 325f397c8d8SUlf Hansson static void mmc_test_free_mem(struct mmc_test_mem *mem) 326f397c8d8SUlf Hansson { 327f397c8d8SUlf Hansson if (!mem) 328f397c8d8SUlf Hansson return; 329f397c8d8SUlf Hansson while (mem->cnt--) 330f397c8d8SUlf Hansson __free_pages(mem->arr[mem->cnt].page, 331f397c8d8SUlf Hansson mem->arr[mem->cnt].order); 332f397c8d8SUlf Hansson kfree(mem->arr); 333f397c8d8SUlf Hansson kfree(mem); 334f397c8d8SUlf Hansson } 335f397c8d8SUlf Hansson 336f397c8d8SUlf Hansson /* 337f397c8d8SUlf Hansson * Allocate a lot of memory, preferably max_sz but at least min_sz. In case 338f397c8d8SUlf Hansson * there isn't much memory do not exceed 1/16th total lowmem pages. Also do 339f397c8d8SUlf Hansson * not exceed a maximum number of segments and try not to make segments much 340f397c8d8SUlf Hansson * bigger than maximum segment size. 341f397c8d8SUlf Hansson */ 342f397c8d8SUlf Hansson static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz, 343f397c8d8SUlf Hansson unsigned long max_sz, 344f397c8d8SUlf Hansson unsigned int max_segs, 345f397c8d8SUlf Hansson unsigned int max_seg_sz) 346f397c8d8SUlf Hansson { 347f397c8d8SUlf Hansson unsigned long max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE); 348f397c8d8SUlf Hansson unsigned long min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE); 349f397c8d8SUlf Hansson unsigned long max_seg_page_cnt = DIV_ROUND_UP(max_seg_sz, PAGE_SIZE); 350f397c8d8SUlf Hansson unsigned long page_cnt = 0; 351f397c8d8SUlf Hansson unsigned long limit = nr_free_buffer_pages() >> 4; 352f397c8d8SUlf Hansson struct mmc_test_mem *mem; 353f397c8d8SUlf Hansson 354f397c8d8SUlf Hansson if (max_page_cnt > limit) 355f397c8d8SUlf Hansson max_page_cnt = limit; 356f397c8d8SUlf Hansson if (min_page_cnt > max_page_cnt) 357f397c8d8SUlf Hansson min_page_cnt = max_page_cnt; 358f397c8d8SUlf Hansson 359f397c8d8SUlf Hansson if (max_seg_page_cnt > max_page_cnt) 360f397c8d8SUlf Hansson max_seg_page_cnt = max_page_cnt; 361f397c8d8SUlf Hansson 362f397c8d8SUlf Hansson if (max_segs > max_page_cnt) 363f397c8d8SUlf Hansson max_segs = max_page_cnt; 364f397c8d8SUlf Hansson 365554d7c54SMarkus Elfring mem = kzalloc(sizeof(*mem), GFP_KERNEL); 366f397c8d8SUlf Hansson if (!mem) 367f397c8d8SUlf Hansson return NULL; 368f397c8d8SUlf Hansson 3693972a20bSMarkus Elfring mem->arr = kcalloc(max_segs, sizeof(*mem->arr), GFP_KERNEL); 370f397c8d8SUlf Hansson if (!mem->arr) 371f397c8d8SUlf Hansson goto out_free; 372f397c8d8SUlf Hansson 373f397c8d8SUlf Hansson while (max_page_cnt) { 374f397c8d8SUlf Hansson struct page *page; 375f397c8d8SUlf Hansson unsigned int order; 376f397c8d8SUlf Hansson gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN | 377f397c8d8SUlf Hansson __GFP_NORETRY; 378f397c8d8SUlf Hansson 379f397c8d8SUlf Hansson order = get_order(max_seg_page_cnt << PAGE_SHIFT); 380f397c8d8SUlf Hansson while (1) { 381f397c8d8SUlf Hansson page = alloc_pages(flags, order); 382f397c8d8SUlf Hansson if (page || !order) 383f397c8d8SUlf Hansson break; 384f397c8d8SUlf Hansson order -= 1; 385f397c8d8SUlf Hansson } 386f397c8d8SUlf Hansson if (!page) { 387f397c8d8SUlf Hansson if (page_cnt < min_page_cnt) 388f397c8d8SUlf Hansson goto out_free; 389f397c8d8SUlf Hansson break; 390f397c8d8SUlf Hansson } 391f397c8d8SUlf Hansson mem->arr[mem->cnt].page = page; 392f397c8d8SUlf Hansson mem->arr[mem->cnt].order = order; 393f397c8d8SUlf Hansson mem->cnt += 1; 394f397c8d8SUlf Hansson if (max_page_cnt <= (1UL << order)) 395f397c8d8SUlf Hansson break; 396f397c8d8SUlf Hansson max_page_cnt -= 1UL << order; 397f397c8d8SUlf Hansson page_cnt += 1UL << order; 398f397c8d8SUlf Hansson if (mem->cnt >= max_segs) { 399f397c8d8SUlf Hansson if (page_cnt < min_page_cnt) 400f397c8d8SUlf Hansson goto out_free; 401f397c8d8SUlf Hansson break; 402f397c8d8SUlf Hansson } 403f397c8d8SUlf Hansson } 404f397c8d8SUlf Hansson 405f397c8d8SUlf Hansson return mem; 406f397c8d8SUlf Hansson 407f397c8d8SUlf Hansson out_free: 408f397c8d8SUlf Hansson mmc_test_free_mem(mem); 409f397c8d8SUlf Hansson return NULL; 410f397c8d8SUlf Hansson } 411f397c8d8SUlf Hansson 412f397c8d8SUlf Hansson /* 413f397c8d8SUlf Hansson * Map memory into a scatterlist. Optionally allow the same memory to be 414f397c8d8SUlf Hansson * mapped more than once. 415f397c8d8SUlf Hansson */ 416f397c8d8SUlf Hansson static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long size, 417f397c8d8SUlf Hansson struct scatterlist *sglist, int repeat, 418f397c8d8SUlf Hansson unsigned int max_segs, unsigned int max_seg_sz, 419f397c8d8SUlf Hansson unsigned int *sg_len, int min_sg_len) 420f397c8d8SUlf Hansson { 421f397c8d8SUlf Hansson struct scatterlist *sg = NULL; 422f397c8d8SUlf Hansson unsigned int i; 423f397c8d8SUlf Hansson unsigned long sz = size; 424f397c8d8SUlf Hansson 425f397c8d8SUlf Hansson sg_init_table(sglist, max_segs); 426f397c8d8SUlf Hansson if (min_sg_len > max_segs) 427f397c8d8SUlf Hansson min_sg_len = max_segs; 428f397c8d8SUlf Hansson 429f397c8d8SUlf Hansson *sg_len = 0; 430f397c8d8SUlf Hansson do { 431f397c8d8SUlf Hansson for (i = 0; i < mem->cnt; i++) { 432f397c8d8SUlf Hansson unsigned long len = PAGE_SIZE << mem->arr[i].order; 433f397c8d8SUlf Hansson 434f397c8d8SUlf Hansson if (min_sg_len && (size / min_sg_len < len)) 435f397c8d8SUlf Hansson len = ALIGN(size / min_sg_len, 512); 436f397c8d8SUlf Hansson if (len > sz) 437f397c8d8SUlf Hansson len = sz; 438f397c8d8SUlf Hansson if (len > max_seg_sz) 439f397c8d8SUlf Hansson len = max_seg_sz; 440f397c8d8SUlf Hansson if (sg) 441f397c8d8SUlf Hansson sg = sg_next(sg); 442f397c8d8SUlf Hansson else 443f397c8d8SUlf Hansson sg = sglist; 444f397c8d8SUlf Hansson if (!sg) 445f397c8d8SUlf Hansson return -EINVAL; 446f397c8d8SUlf Hansson sg_set_page(sg, mem->arr[i].page, len, 0); 447f397c8d8SUlf Hansson sz -= len; 448f397c8d8SUlf Hansson *sg_len += 1; 449f397c8d8SUlf Hansson if (!sz) 450f397c8d8SUlf Hansson break; 451f397c8d8SUlf Hansson } 452f397c8d8SUlf Hansson } while (sz && repeat); 453f397c8d8SUlf Hansson 454f397c8d8SUlf Hansson if (sz) 455f397c8d8SUlf Hansson return -EINVAL; 456f397c8d8SUlf Hansson 457f397c8d8SUlf Hansson if (sg) 458f397c8d8SUlf Hansson sg_mark_end(sg); 459f397c8d8SUlf Hansson 460f397c8d8SUlf Hansson return 0; 461f397c8d8SUlf Hansson } 462f397c8d8SUlf Hansson 463f397c8d8SUlf Hansson /* 464f397c8d8SUlf Hansson * Map memory into a scatterlist so that no pages are contiguous. Allow the 465f397c8d8SUlf Hansson * same memory to be mapped more than once. 466f397c8d8SUlf Hansson */ 467f397c8d8SUlf Hansson static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem, 468f397c8d8SUlf Hansson unsigned long sz, 469f397c8d8SUlf Hansson struct scatterlist *sglist, 470f397c8d8SUlf Hansson unsigned int max_segs, 471f397c8d8SUlf Hansson unsigned int max_seg_sz, 472f397c8d8SUlf Hansson unsigned int *sg_len) 473f397c8d8SUlf Hansson { 474f397c8d8SUlf Hansson struct scatterlist *sg = NULL; 475f397c8d8SUlf Hansson unsigned int i = mem->cnt, cnt; 476f397c8d8SUlf Hansson unsigned long len; 477f397c8d8SUlf Hansson void *base, *addr, *last_addr = NULL; 478f397c8d8SUlf Hansson 479f397c8d8SUlf Hansson sg_init_table(sglist, max_segs); 480f397c8d8SUlf Hansson 481f397c8d8SUlf Hansson *sg_len = 0; 482f397c8d8SUlf Hansson while (sz) { 483f397c8d8SUlf Hansson base = page_address(mem->arr[--i].page); 484f397c8d8SUlf Hansson cnt = 1 << mem->arr[i].order; 485f397c8d8SUlf Hansson while (sz && cnt) { 486f397c8d8SUlf Hansson addr = base + PAGE_SIZE * --cnt; 487f397c8d8SUlf Hansson if (last_addr && last_addr + PAGE_SIZE == addr) 488f397c8d8SUlf Hansson continue; 489f397c8d8SUlf Hansson last_addr = addr; 490f397c8d8SUlf Hansson len = PAGE_SIZE; 491f397c8d8SUlf Hansson if (len > max_seg_sz) 492f397c8d8SUlf Hansson len = max_seg_sz; 493f397c8d8SUlf Hansson if (len > sz) 494f397c8d8SUlf Hansson len = sz; 495f397c8d8SUlf Hansson if (sg) 496f397c8d8SUlf Hansson sg = sg_next(sg); 497f397c8d8SUlf Hansson else 498f397c8d8SUlf Hansson sg = sglist; 499f397c8d8SUlf Hansson if (!sg) 500f397c8d8SUlf Hansson return -EINVAL; 501f397c8d8SUlf Hansson sg_set_page(sg, virt_to_page(addr), len, 0); 502f397c8d8SUlf Hansson sz -= len; 503f397c8d8SUlf Hansson *sg_len += 1; 504f397c8d8SUlf Hansson } 505f397c8d8SUlf Hansson if (i == 0) 506f397c8d8SUlf Hansson i = mem->cnt; 507f397c8d8SUlf Hansson } 508f397c8d8SUlf Hansson 509f397c8d8SUlf Hansson if (sg) 510f397c8d8SUlf Hansson sg_mark_end(sg); 511f397c8d8SUlf Hansson 512f397c8d8SUlf Hansson return 0; 513f397c8d8SUlf Hansson } 514f397c8d8SUlf Hansson 515f397c8d8SUlf Hansson /* 516f397c8d8SUlf Hansson * Calculate transfer rate in bytes per second. 517f397c8d8SUlf Hansson */ 518f397c8d8SUlf Hansson static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts) 519f397c8d8SUlf Hansson { 520f397c8d8SUlf Hansson uint64_t ns; 521f397c8d8SUlf Hansson 522f397c8d8SUlf Hansson ns = ts->tv_sec; 523f397c8d8SUlf Hansson ns *= 1000000000; 524f397c8d8SUlf Hansson ns += ts->tv_nsec; 525f397c8d8SUlf Hansson 526f397c8d8SUlf Hansson bytes *= 1000000000; 527f397c8d8SUlf Hansson 528f397c8d8SUlf Hansson while (ns > UINT_MAX) { 529f397c8d8SUlf Hansson bytes >>= 1; 530f397c8d8SUlf Hansson ns >>= 1; 531f397c8d8SUlf Hansson } 532f397c8d8SUlf Hansson 533f397c8d8SUlf Hansson if (!ns) 534f397c8d8SUlf Hansson return 0; 535f397c8d8SUlf Hansson 536f397c8d8SUlf Hansson do_div(bytes, (uint32_t)ns); 537f397c8d8SUlf Hansson 538f397c8d8SUlf Hansson return bytes; 539f397c8d8SUlf Hansson } 540f397c8d8SUlf Hansson 541f397c8d8SUlf Hansson /* 542f397c8d8SUlf Hansson * Save transfer results for future usage 543f397c8d8SUlf Hansson */ 544f397c8d8SUlf Hansson static void mmc_test_save_transfer_result(struct mmc_test_card *test, 545f397c8d8SUlf Hansson unsigned int count, unsigned int sectors, struct timespec ts, 546f397c8d8SUlf Hansson unsigned int rate, unsigned int iops) 547f397c8d8SUlf Hansson { 548f397c8d8SUlf Hansson struct mmc_test_transfer_result *tr; 549f397c8d8SUlf Hansson 550f397c8d8SUlf Hansson if (!test->gr) 551f397c8d8SUlf Hansson return; 552f397c8d8SUlf Hansson 553554d7c54SMarkus Elfring tr = kmalloc(sizeof(*tr), GFP_KERNEL); 554f397c8d8SUlf Hansson if (!tr) 555f397c8d8SUlf Hansson return; 556f397c8d8SUlf Hansson 557f397c8d8SUlf Hansson tr->count = count; 558f397c8d8SUlf Hansson tr->sectors = sectors; 559f397c8d8SUlf Hansson tr->ts = ts; 560f397c8d8SUlf Hansson tr->rate = rate; 561f397c8d8SUlf Hansson tr->iops = iops; 562f397c8d8SUlf Hansson 563f397c8d8SUlf Hansson list_add_tail(&tr->link, &test->gr->tr_lst); 564f397c8d8SUlf Hansson } 565f397c8d8SUlf Hansson 566f397c8d8SUlf Hansson /* 567f397c8d8SUlf Hansson * Print the transfer rate. 568f397c8d8SUlf Hansson */ 569f397c8d8SUlf Hansson static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes, 570f397c8d8SUlf Hansson struct timespec *ts1, struct timespec *ts2) 571f397c8d8SUlf Hansson { 572f397c8d8SUlf Hansson unsigned int rate, iops, sectors = bytes >> 9; 573f397c8d8SUlf Hansson struct timespec ts; 574f397c8d8SUlf Hansson 575f397c8d8SUlf Hansson ts = timespec_sub(*ts2, *ts1); 576f397c8d8SUlf Hansson 577f397c8d8SUlf Hansson rate = mmc_test_rate(bytes, &ts); 578f397c8d8SUlf Hansson iops = mmc_test_rate(100, &ts); /* I/O ops per sec x 100 */ 579f397c8d8SUlf Hansson 580f397c8d8SUlf Hansson pr_info("%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu " 581f397c8d8SUlf Hansson "seconds (%u kB/s, %u KiB/s, %u.%02u IOPS)\n", 582f397c8d8SUlf Hansson mmc_hostname(test->card->host), sectors, sectors >> 1, 583f397c8d8SUlf Hansson (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec, 584f397c8d8SUlf Hansson (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024, 585f397c8d8SUlf Hansson iops / 100, iops % 100); 586f397c8d8SUlf Hansson 587f397c8d8SUlf Hansson mmc_test_save_transfer_result(test, 1, sectors, ts, rate, iops); 588f397c8d8SUlf Hansson } 589f397c8d8SUlf Hansson 590f397c8d8SUlf Hansson /* 591f397c8d8SUlf Hansson * Print the average transfer rate. 592f397c8d8SUlf Hansson */ 593f397c8d8SUlf Hansson static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes, 594f397c8d8SUlf Hansson unsigned int count, struct timespec *ts1, 595f397c8d8SUlf Hansson struct timespec *ts2) 596f397c8d8SUlf Hansson { 597f397c8d8SUlf Hansson unsigned int rate, iops, sectors = bytes >> 9; 598f397c8d8SUlf Hansson uint64_t tot = bytes * count; 599f397c8d8SUlf Hansson struct timespec ts; 600f397c8d8SUlf Hansson 601f397c8d8SUlf Hansson ts = timespec_sub(*ts2, *ts1); 602f397c8d8SUlf Hansson 603f397c8d8SUlf Hansson rate = mmc_test_rate(tot, &ts); 604f397c8d8SUlf Hansson iops = mmc_test_rate(count * 100, &ts); /* I/O ops per sec x 100 */ 605f397c8d8SUlf Hansson 606f397c8d8SUlf Hansson pr_info("%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " 607f397c8d8SUlf Hansson "%lu.%09lu seconds (%u kB/s, %u KiB/s, " 608f397c8d8SUlf Hansson "%u.%02u IOPS, sg_len %d)\n", 609f397c8d8SUlf Hansson mmc_hostname(test->card->host), count, sectors, count, 610f397c8d8SUlf Hansson sectors >> 1, (sectors & 1 ? ".5" : ""), 611f397c8d8SUlf Hansson (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec, 612f397c8d8SUlf Hansson rate / 1000, rate / 1024, iops / 100, iops % 100, 613f397c8d8SUlf Hansson test->area.sg_len); 614f397c8d8SUlf Hansson 615f397c8d8SUlf Hansson mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops); 616f397c8d8SUlf Hansson } 617f397c8d8SUlf Hansson 618f397c8d8SUlf Hansson /* 619f397c8d8SUlf Hansson * Return the card size in sectors. 620f397c8d8SUlf Hansson */ 621f397c8d8SUlf Hansson static unsigned int mmc_test_capacity(struct mmc_card *card) 622f397c8d8SUlf Hansson { 623f397c8d8SUlf Hansson if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) 624f397c8d8SUlf Hansson return card->ext_csd.sectors; 625f397c8d8SUlf Hansson else 626f397c8d8SUlf Hansson return card->csd.capacity << (card->csd.read_blkbits - 9); 627f397c8d8SUlf Hansson } 628f397c8d8SUlf Hansson 629f397c8d8SUlf Hansson /*******************************************************************/ 630f397c8d8SUlf Hansson /* Test preparation and cleanup */ 631f397c8d8SUlf Hansson /*******************************************************************/ 632f397c8d8SUlf Hansson 633f397c8d8SUlf Hansson /* 634f397c8d8SUlf Hansson * Fill the first couple of sectors of the card with known data 635f397c8d8SUlf Hansson * so that bad reads/writes can be detected 636f397c8d8SUlf Hansson */ 637f397c8d8SUlf Hansson static int __mmc_test_prepare(struct mmc_test_card *test, int write) 638f397c8d8SUlf Hansson { 639f397c8d8SUlf Hansson int ret, i; 640f397c8d8SUlf Hansson 641f397c8d8SUlf Hansson ret = mmc_test_set_blksize(test, 512); 642f397c8d8SUlf Hansson if (ret) 643f397c8d8SUlf Hansson return ret; 644f397c8d8SUlf Hansson 645f397c8d8SUlf Hansson if (write) 646f397c8d8SUlf Hansson memset(test->buffer, 0xDF, 512); 647f397c8d8SUlf Hansson else { 648f397c8d8SUlf Hansson for (i = 0; i < 512; i++) 649f397c8d8SUlf Hansson test->buffer[i] = i; 650f397c8d8SUlf Hansson } 651f397c8d8SUlf Hansson 652f397c8d8SUlf Hansson for (i = 0; i < BUFFER_SIZE / 512; i++) { 653f397c8d8SUlf Hansson ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1); 654f397c8d8SUlf Hansson if (ret) 655f397c8d8SUlf Hansson return ret; 656f397c8d8SUlf Hansson } 657f397c8d8SUlf Hansson 658f397c8d8SUlf Hansson return 0; 659f397c8d8SUlf Hansson } 660f397c8d8SUlf Hansson 661f397c8d8SUlf Hansson static int mmc_test_prepare_write(struct mmc_test_card *test) 662f397c8d8SUlf Hansson { 663f397c8d8SUlf Hansson return __mmc_test_prepare(test, 1); 664f397c8d8SUlf Hansson } 665f397c8d8SUlf Hansson 666f397c8d8SUlf Hansson static int mmc_test_prepare_read(struct mmc_test_card *test) 667f397c8d8SUlf Hansson { 668f397c8d8SUlf Hansson return __mmc_test_prepare(test, 0); 669f397c8d8SUlf Hansson } 670f397c8d8SUlf Hansson 671f397c8d8SUlf Hansson static int mmc_test_cleanup(struct mmc_test_card *test) 672f397c8d8SUlf Hansson { 673f397c8d8SUlf Hansson int ret, i; 674f397c8d8SUlf Hansson 675f397c8d8SUlf Hansson ret = mmc_test_set_blksize(test, 512); 676f397c8d8SUlf Hansson if (ret) 677f397c8d8SUlf Hansson return ret; 678f397c8d8SUlf Hansson 679f397c8d8SUlf Hansson memset(test->buffer, 0, 512); 680f397c8d8SUlf Hansson 681f397c8d8SUlf Hansson for (i = 0; i < BUFFER_SIZE / 512; i++) { 682f397c8d8SUlf Hansson ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1); 683f397c8d8SUlf Hansson if (ret) 684f397c8d8SUlf Hansson return ret; 685f397c8d8SUlf Hansson } 686f397c8d8SUlf Hansson 687f397c8d8SUlf Hansson return 0; 688f397c8d8SUlf Hansson } 689f397c8d8SUlf Hansson 690f397c8d8SUlf Hansson /*******************************************************************/ 691f397c8d8SUlf Hansson /* Test execution helpers */ 692f397c8d8SUlf Hansson /*******************************************************************/ 693f397c8d8SUlf Hansson 694f397c8d8SUlf Hansson /* 695f397c8d8SUlf Hansson * Modifies the mmc_request to perform the "short transfer" tests 696f397c8d8SUlf Hansson */ 697f397c8d8SUlf Hansson static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test, 698f397c8d8SUlf Hansson struct mmc_request *mrq, int write) 699f397c8d8SUlf Hansson { 700f397c8d8SUlf Hansson if (WARN_ON(!mrq || !mrq->cmd || !mrq->data)) 701f397c8d8SUlf Hansson return; 702f397c8d8SUlf Hansson 703f397c8d8SUlf Hansson if (mrq->data->blocks > 1) { 704f397c8d8SUlf Hansson mrq->cmd->opcode = write ? 705f397c8d8SUlf Hansson MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK; 706f397c8d8SUlf Hansson mrq->stop = NULL; 707f397c8d8SUlf Hansson } else { 708f397c8d8SUlf Hansson mrq->cmd->opcode = MMC_SEND_STATUS; 709f397c8d8SUlf Hansson mrq->cmd->arg = test->card->rca << 16; 710f397c8d8SUlf Hansson } 711f397c8d8SUlf Hansson } 712f397c8d8SUlf Hansson 713f397c8d8SUlf Hansson /* 714f397c8d8SUlf Hansson * Checks that a normal transfer didn't have any errors 715f397c8d8SUlf Hansson */ 716f397c8d8SUlf Hansson static int mmc_test_check_result(struct mmc_test_card *test, 717f397c8d8SUlf Hansson struct mmc_request *mrq) 718f397c8d8SUlf Hansson { 719f397c8d8SUlf Hansson int ret; 720f397c8d8SUlf Hansson 721f397c8d8SUlf Hansson if (WARN_ON(!mrq || !mrq->cmd || !mrq->data)) 722f397c8d8SUlf Hansson return -EINVAL; 723f397c8d8SUlf Hansson 724f397c8d8SUlf Hansson ret = 0; 725f397c8d8SUlf Hansson 726f397c8d8SUlf Hansson if (mrq->sbc && mrq->sbc->error) 727f397c8d8SUlf Hansson ret = mrq->sbc->error; 728f397c8d8SUlf Hansson if (!ret && mrq->cmd->error) 729f397c8d8SUlf Hansson ret = mrq->cmd->error; 730f397c8d8SUlf Hansson if (!ret && mrq->data->error) 731f397c8d8SUlf Hansson ret = mrq->data->error; 732f397c8d8SUlf Hansson if (!ret && mrq->stop && mrq->stop->error) 733f397c8d8SUlf Hansson ret = mrq->stop->error; 734f397c8d8SUlf Hansson if (!ret && mrq->data->bytes_xfered != 735f397c8d8SUlf Hansson mrq->data->blocks * mrq->data->blksz) 736f397c8d8SUlf Hansson ret = RESULT_FAIL; 737f397c8d8SUlf Hansson 738f397c8d8SUlf Hansson if (ret == -EINVAL) 739f397c8d8SUlf Hansson ret = RESULT_UNSUP_HOST; 740f397c8d8SUlf Hansson 741f397c8d8SUlf Hansson return ret; 742f397c8d8SUlf Hansson } 743f397c8d8SUlf Hansson 744f397c8d8SUlf Hansson static enum mmc_blk_status mmc_test_check_result_async(struct mmc_card *card, 745f397c8d8SUlf Hansson struct mmc_async_req *areq) 746f397c8d8SUlf Hansson { 747f397c8d8SUlf Hansson struct mmc_test_async_req *test_async = 748f397c8d8SUlf Hansson container_of(areq, struct mmc_test_async_req, areq); 749f397c8d8SUlf Hansson int ret; 750f397c8d8SUlf Hansson 751f397c8d8SUlf Hansson mmc_test_wait_busy(test_async->test); 752f397c8d8SUlf Hansson 753f397c8d8SUlf Hansson /* 754f397c8d8SUlf Hansson * FIXME: this would earlier just casts a regular error code, 755f397c8d8SUlf Hansson * either of the kernel type -ERRORCODE or the local test framework 756f397c8d8SUlf Hansson * RESULT_* errorcode, into an enum mmc_blk_status and return as 757f397c8d8SUlf Hansson * result check. Instead, convert it to some reasonable type by just 758f397c8d8SUlf Hansson * returning either MMC_BLK_SUCCESS or MMC_BLK_CMD_ERR. 759f397c8d8SUlf Hansson * If possible, a reasonable error code should be returned. 760f397c8d8SUlf Hansson */ 761f397c8d8SUlf Hansson ret = mmc_test_check_result(test_async->test, areq->mrq); 762f397c8d8SUlf Hansson if (ret) 763f397c8d8SUlf Hansson return MMC_BLK_CMD_ERR; 764f397c8d8SUlf Hansson 765f397c8d8SUlf Hansson return MMC_BLK_SUCCESS; 766f397c8d8SUlf Hansson } 767f397c8d8SUlf Hansson 768f397c8d8SUlf Hansson /* 769f397c8d8SUlf Hansson * Checks that a "short transfer" behaved as expected 770f397c8d8SUlf Hansson */ 771f397c8d8SUlf Hansson static int mmc_test_check_broken_result(struct mmc_test_card *test, 772f397c8d8SUlf Hansson struct mmc_request *mrq) 773f397c8d8SUlf Hansson { 774f397c8d8SUlf Hansson int ret; 775f397c8d8SUlf Hansson 776f397c8d8SUlf Hansson if (WARN_ON(!mrq || !mrq->cmd || !mrq->data)) 777f397c8d8SUlf Hansson return -EINVAL; 778f397c8d8SUlf Hansson 779f397c8d8SUlf Hansson ret = 0; 780f397c8d8SUlf Hansson 781f397c8d8SUlf Hansson if (!ret && mrq->cmd->error) 782f397c8d8SUlf Hansson ret = mrq->cmd->error; 783f397c8d8SUlf Hansson if (!ret && mrq->data->error == 0) 784f397c8d8SUlf Hansson ret = RESULT_FAIL; 785f397c8d8SUlf Hansson if (!ret && mrq->data->error != -ETIMEDOUT) 786f397c8d8SUlf Hansson ret = mrq->data->error; 787f397c8d8SUlf Hansson if (!ret && mrq->stop && mrq->stop->error) 788f397c8d8SUlf Hansson ret = mrq->stop->error; 789f397c8d8SUlf Hansson if (mrq->data->blocks > 1) { 790f397c8d8SUlf Hansson if (!ret && mrq->data->bytes_xfered > mrq->data->blksz) 791f397c8d8SUlf Hansson ret = RESULT_FAIL; 792f397c8d8SUlf Hansson } else { 793f397c8d8SUlf Hansson if (!ret && mrq->data->bytes_xfered > 0) 794f397c8d8SUlf Hansson ret = RESULT_FAIL; 795f397c8d8SUlf Hansson } 796f397c8d8SUlf Hansson 797f397c8d8SUlf Hansson if (ret == -EINVAL) 798f397c8d8SUlf Hansson ret = RESULT_UNSUP_HOST; 799f397c8d8SUlf Hansson 800f397c8d8SUlf Hansson return ret; 801f397c8d8SUlf Hansson } 802f397c8d8SUlf Hansson 803f397c8d8SUlf Hansson /* 804f397c8d8SUlf Hansson * Tests nonblock transfer with certain parameters 805f397c8d8SUlf Hansson */ 806f397c8d8SUlf Hansson static void mmc_test_nonblock_reset(struct mmc_request *mrq, 807f397c8d8SUlf Hansson struct mmc_command *cmd, 808f397c8d8SUlf Hansson struct mmc_command *stop, 809f397c8d8SUlf Hansson struct mmc_data *data) 810f397c8d8SUlf Hansson { 811f397c8d8SUlf Hansson memset(mrq, 0, sizeof(struct mmc_request)); 812f397c8d8SUlf Hansson memset(cmd, 0, sizeof(struct mmc_command)); 813f397c8d8SUlf Hansson memset(data, 0, sizeof(struct mmc_data)); 814f397c8d8SUlf Hansson memset(stop, 0, sizeof(struct mmc_command)); 815f397c8d8SUlf Hansson 816f397c8d8SUlf Hansson mrq->cmd = cmd; 817f397c8d8SUlf Hansson mrq->data = data; 818f397c8d8SUlf Hansson mrq->stop = stop; 819f397c8d8SUlf Hansson } 820f397c8d8SUlf Hansson static int mmc_test_nonblock_transfer(struct mmc_test_card *test, 821f397c8d8SUlf Hansson struct scatterlist *sg, unsigned sg_len, 822f397c8d8SUlf Hansson unsigned dev_addr, unsigned blocks, 823f397c8d8SUlf Hansson unsigned blksz, int write, int count) 824f397c8d8SUlf Hansson { 825f397c8d8SUlf Hansson struct mmc_request mrq1; 826f397c8d8SUlf Hansson struct mmc_command cmd1; 827f397c8d8SUlf Hansson struct mmc_command stop1; 828f397c8d8SUlf Hansson struct mmc_data data1; 829f397c8d8SUlf Hansson 830f397c8d8SUlf Hansson struct mmc_request mrq2; 831f397c8d8SUlf Hansson struct mmc_command cmd2; 832f397c8d8SUlf Hansson struct mmc_command stop2; 833f397c8d8SUlf Hansson struct mmc_data data2; 834f397c8d8SUlf Hansson 835f397c8d8SUlf Hansson struct mmc_test_async_req test_areq[2]; 836f397c8d8SUlf Hansson struct mmc_async_req *done_areq; 837f397c8d8SUlf Hansson struct mmc_async_req *cur_areq = &test_areq[0].areq; 838f397c8d8SUlf Hansson struct mmc_async_req *other_areq = &test_areq[1].areq; 839f397c8d8SUlf Hansson enum mmc_blk_status status; 840f397c8d8SUlf Hansson int i; 841f397c8d8SUlf Hansson int ret = RESULT_OK; 842f397c8d8SUlf Hansson 843f397c8d8SUlf Hansson test_areq[0].test = test; 844f397c8d8SUlf Hansson test_areq[1].test = test; 845f397c8d8SUlf Hansson 846f397c8d8SUlf Hansson mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1); 847f397c8d8SUlf Hansson mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2); 848f397c8d8SUlf Hansson 849f397c8d8SUlf Hansson cur_areq->mrq = &mrq1; 850f397c8d8SUlf Hansson cur_areq->err_check = mmc_test_check_result_async; 851f397c8d8SUlf Hansson other_areq->mrq = &mrq2; 852f397c8d8SUlf Hansson other_areq->err_check = mmc_test_check_result_async; 853f397c8d8SUlf Hansson 854f397c8d8SUlf Hansson for (i = 0; i < count; i++) { 855f397c8d8SUlf Hansson mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr, 856f397c8d8SUlf Hansson blocks, blksz, write); 857c3399ef5SLinus Walleij done_areq = mmc_start_areq(test->card->host, cur_areq, &status); 858f397c8d8SUlf Hansson 859f397c8d8SUlf Hansson if (status != MMC_BLK_SUCCESS || (!done_areq && i > 0)) { 860f397c8d8SUlf Hansson ret = RESULT_FAIL; 861f397c8d8SUlf Hansson goto err; 862f397c8d8SUlf Hansson } 863f397c8d8SUlf Hansson 864f397c8d8SUlf Hansson if (done_areq) { 865f397c8d8SUlf Hansson if (done_areq->mrq == &mrq2) 866f397c8d8SUlf Hansson mmc_test_nonblock_reset(&mrq2, &cmd2, 867f397c8d8SUlf Hansson &stop2, &data2); 868f397c8d8SUlf Hansson else 869f397c8d8SUlf Hansson mmc_test_nonblock_reset(&mrq1, &cmd1, 870f397c8d8SUlf Hansson &stop1, &data1); 871f397c8d8SUlf Hansson } 872f397c8d8SUlf Hansson swap(cur_areq, other_areq); 873f397c8d8SUlf Hansson dev_addr += blocks; 874f397c8d8SUlf Hansson } 875f397c8d8SUlf Hansson 876c3399ef5SLinus Walleij done_areq = mmc_start_areq(test->card->host, NULL, &status); 877f397c8d8SUlf Hansson if (status != MMC_BLK_SUCCESS) 878f397c8d8SUlf Hansson ret = RESULT_FAIL; 879f397c8d8SUlf Hansson 880f397c8d8SUlf Hansson return ret; 881f397c8d8SUlf Hansson err: 882f397c8d8SUlf Hansson return ret; 883f397c8d8SUlf Hansson } 884f397c8d8SUlf Hansson 885f397c8d8SUlf Hansson /* 886f397c8d8SUlf Hansson * Tests a basic transfer with certain parameters 887f397c8d8SUlf Hansson */ 888f397c8d8SUlf Hansson static int mmc_test_simple_transfer(struct mmc_test_card *test, 889f397c8d8SUlf Hansson struct scatterlist *sg, unsigned sg_len, unsigned dev_addr, 890f397c8d8SUlf Hansson unsigned blocks, unsigned blksz, int write) 891f397c8d8SUlf Hansson { 892c7836d15SMasahiro Yamada struct mmc_request mrq = {}; 893c7836d15SMasahiro Yamada struct mmc_command cmd = {}; 894c7836d15SMasahiro Yamada struct mmc_command stop = {}; 895c7836d15SMasahiro Yamada struct mmc_data data = {}; 896f397c8d8SUlf Hansson 897f397c8d8SUlf Hansson mrq.cmd = &cmd; 898f397c8d8SUlf Hansson mrq.data = &data; 899f397c8d8SUlf Hansson mrq.stop = &stop; 900f397c8d8SUlf Hansson 901f397c8d8SUlf Hansson mmc_test_prepare_mrq(test, &mrq, sg, sg_len, dev_addr, 902f397c8d8SUlf Hansson blocks, blksz, write); 903f397c8d8SUlf Hansson 904f397c8d8SUlf Hansson mmc_wait_for_req(test->card->host, &mrq); 905f397c8d8SUlf Hansson 906f397c8d8SUlf Hansson mmc_test_wait_busy(test); 907f397c8d8SUlf Hansson 908f397c8d8SUlf Hansson return mmc_test_check_result(test, &mrq); 909f397c8d8SUlf Hansson } 910f397c8d8SUlf Hansson 911f397c8d8SUlf Hansson /* 912f397c8d8SUlf Hansson * Tests a transfer where the card will fail completely or partly 913f397c8d8SUlf Hansson */ 914f397c8d8SUlf Hansson static int mmc_test_broken_transfer(struct mmc_test_card *test, 915f397c8d8SUlf Hansson unsigned blocks, unsigned blksz, int write) 916f397c8d8SUlf Hansson { 917c7836d15SMasahiro Yamada struct mmc_request mrq = {}; 918c7836d15SMasahiro Yamada struct mmc_command cmd = {}; 919c7836d15SMasahiro Yamada struct mmc_command stop = {}; 920c7836d15SMasahiro Yamada struct mmc_data data = {}; 921f397c8d8SUlf Hansson 922f397c8d8SUlf Hansson struct scatterlist sg; 923f397c8d8SUlf Hansson 924f397c8d8SUlf Hansson mrq.cmd = &cmd; 925f397c8d8SUlf Hansson mrq.data = &data; 926f397c8d8SUlf Hansson mrq.stop = &stop; 927f397c8d8SUlf Hansson 928f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer, blocks * blksz); 929f397c8d8SUlf Hansson 930f397c8d8SUlf Hansson mmc_test_prepare_mrq(test, &mrq, &sg, 1, 0, blocks, blksz, write); 931f397c8d8SUlf Hansson mmc_test_prepare_broken_mrq(test, &mrq, write); 932f397c8d8SUlf Hansson 933f397c8d8SUlf Hansson mmc_wait_for_req(test->card->host, &mrq); 934f397c8d8SUlf Hansson 935f397c8d8SUlf Hansson mmc_test_wait_busy(test); 936f397c8d8SUlf Hansson 937f397c8d8SUlf Hansson return mmc_test_check_broken_result(test, &mrq); 938f397c8d8SUlf Hansson } 939f397c8d8SUlf Hansson 940f397c8d8SUlf Hansson /* 941f397c8d8SUlf Hansson * Does a complete transfer test where data is also validated 942f397c8d8SUlf Hansson * 943f397c8d8SUlf Hansson * Note: mmc_test_prepare() must have been done before this call 944f397c8d8SUlf Hansson */ 945f397c8d8SUlf Hansson static int mmc_test_transfer(struct mmc_test_card *test, 946f397c8d8SUlf Hansson struct scatterlist *sg, unsigned sg_len, unsigned dev_addr, 947f397c8d8SUlf Hansson unsigned blocks, unsigned blksz, int write) 948f397c8d8SUlf Hansson { 949f397c8d8SUlf Hansson int ret, i; 950f397c8d8SUlf Hansson unsigned long flags; 951f397c8d8SUlf Hansson 952f397c8d8SUlf Hansson if (write) { 953f397c8d8SUlf Hansson for (i = 0; i < blocks * blksz; i++) 954f397c8d8SUlf Hansson test->scratch[i] = i; 955f397c8d8SUlf Hansson } else { 956f397c8d8SUlf Hansson memset(test->scratch, 0, BUFFER_SIZE); 957f397c8d8SUlf Hansson } 958f397c8d8SUlf Hansson local_irq_save(flags); 959f397c8d8SUlf Hansson sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE); 960f397c8d8SUlf Hansson local_irq_restore(flags); 961f397c8d8SUlf Hansson 962f397c8d8SUlf Hansson ret = mmc_test_set_blksize(test, blksz); 963f397c8d8SUlf Hansson if (ret) 964f397c8d8SUlf Hansson return ret; 965f397c8d8SUlf Hansson 966f397c8d8SUlf Hansson ret = mmc_test_simple_transfer(test, sg, sg_len, dev_addr, 967f397c8d8SUlf Hansson blocks, blksz, write); 968f397c8d8SUlf Hansson if (ret) 969f397c8d8SUlf Hansson return ret; 970f397c8d8SUlf Hansson 971f397c8d8SUlf Hansson if (write) { 972f397c8d8SUlf Hansson int sectors; 973f397c8d8SUlf Hansson 974f397c8d8SUlf Hansson ret = mmc_test_set_blksize(test, 512); 975f397c8d8SUlf Hansson if (ret) 976f397c8d8SUlf Hansson return ret; 977f397c8d8SUlf Hansson 978f397c8d8SUlf Hansson sectors = (blocks * blksz + 511) / 512; 979f397c8d8SUlf Hansson if ((sectors * 512) == (blocks * blksz)) 980f397c8d8SUlf Hansson sectors++; 981f397c8d8SUlf Hansson 982f397c8d8SUlf Hansson if ((sectors * 512) > BUFFER_SIZE) 983f397c8d8SUlf Hansson return -EINVAL; 984f397c8d8SUlf Hansson 985f397c8d8SUlf Hansson memset(test->buffer, 0, sectors * 512); 986f397c8d8SUlf Hansson 987f397c8d8SUlf Hansson for (i = 0; i < sectors; i++) { 988f397c8d8SUlf Hansson ret = mmc_test_buffer_transfer(test, 989f397c8d8SUlf Hansson test->buffer + i * 512, 990f397c8d8SUlf Hansson dev_addr + i, 512, 0); 991f397c8d8SUlf Hansson if (ret) 992f397c8d8SUlf Hansson return ret; 993f397c8d8SUlf Hansson } 994f397c8d8SUlf Hansson 995f397c8d8SUlf Hansson for (i = 0; i < blocks * blksz; i++) { 996f397c8d8SUlf Hansson if (test->buffer[i] != (u8)i) 997f397c8d8SUlf Hansson return RESULT_FAIL; 998f397c8d8SUlf Hansson } 999f397c8d8SUlf Hansson 1000f397c8d8SUlf Hansson for (; i < sectors * 512; i++) { 1001f397c8d8SUlf Hansson if (test->buffer[i] != 0xDF) 1002f397c8d8SUlf Hansson return RESULT_FAIL; 1003f397c8d8SUlf Hansson } 1004f397c8d8SUlf Hansson } else { 1005f397c8d8SUlf Hansson local_irq_save(flags); 1006f397c8d8SUlf Hansson sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE); 1007f397c8d8SUlf Hansson local_irq_restore(flags); 1008f397c8d8SUlf Hansson for (i = 0; i < blocks * blksz; i++) { 1009f397c8d8SUlf Hansson if (test->scratch[i] != (u8)i) 1010f397c8d8SUlf Hansson return RESULT_FAIL; 1011f397c8d8SUlf Hansson } 1012f397c8d8SUlf Hansson } 1013f397c8d8SUlf Hansson 1014f397c8d8SUlf Hansson return 0; 1015f397c8d8SUlf Hansson } 1016f397c8d8SUlf Hansson 1017f397c8d8SUlf Hansson /*******************************************************************/ 1018f397c8d8SUlf Hansson /* Tests */ 1019f397c8d8SUlf Hansson /*******************************************************************/ 1020f397c8d8SUlf Hansson 1021f397c8d8SUlf Hansson struct mmc_test_case { 1022f397c8d8SUlf Hansson const char *name; 1023f397c8d8SUlf Hansson 1024f397c8d8SUlf Hansson int (*prepare)(struct mmc_test_card *); 1025f397c8d8SUlf Hansson int (*run)(struct mmc_test_card *); 1026f397c8d8SUlf Hansson int (*cleanup)(struct mmc_test_card *); 1027f397c8d8SUlf Hansson }; 1028f397c8d8SUlf Hansson 1029f397c8d8SUlf Hansson static int mmc_test_basic_write(struct mmc_test_card *test) 1030f397c8d8SUlf Hansson { 1031f397c8d8SUlf Hansson int ret; 1032f397c8d8SUlf Hansson struct scatterlist sg; 1033f397c8d8SUlf Hansson 1034f397c8d8SUlf Hansson ret = mmc_test_set_blksize(test, 512); 1035f397c8d8SUlf Hansson if (ret) 1036f397c8d8SUlf Hansson return ret; 1037f397c8d8SUlf Hansson 1038f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer, 512); 1039f397c8d8SUlf Hansson 1040f397c8d8SUlf Hansson return mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 1); 1041f397c8d8SUlf Hansson } 1042f397c8d8SUlf Hansson 1043f397c8d8SUlf Hansson static int mmc_test_basic_read(struct mmc_test_card *test) 1044f397c8d8SUlf Hansson { 1045f397c8d8SUlf Hansson int ret; 1046f397c8d8SUlf Hansson struct scatterlist sg; 1047f397c8d8SUlf Hansson 1048f397c8d8SUlf Hansson ret = mmc_test_set_blksize(test, 512); 1049f397c8d8SUlf Hansson if (ret) 1050f397c8d8SUlf Hansson return ret; 1051f397c8d8SUlf Hansson 1052f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer, 512); 1053f397c8d8SUlf Hansson 1054f397c8d8SUlf Hansson return mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 0); 1055f397c8d8SUlf Hansson } 1056f397c8d8SUlf Hansson 1057f397c8d8SUlf Hansson static int mmc_test_verify_write(struct mmc_test_card *test) 1058f397c8d8SUlf Hansson { 1059f397c8d8SUlf Hansson struct scatterlist sg; 1060f397c8d8SUlf Hansson 1061f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer, 512); 1062f397c8d8SUlf Hansson 1063f397c8d8SUlf Hansson return mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1); 1064f397c8d8SUlf Hansson } 1065f397c8d8SUlf Hansson 1066f397c8d8SUlf Hansson static int mmc_test_verify_read(struct mmc_test_card *test) 1067f397c8d8SUlf Hansson { 1068f397c8d8SUlf Hansson struct scatterlist sg; 1069f397c8d8SUlf Hansson 1070f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer, 512); 1071f397c8d8SUlf Hansson 1072f397c8d8SUlf Hansson return mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0); 1073f397c8d8SUlf Hansson } 1074f397c8d8SUlf Hansson 1075f397c8d8SUlf Hansson static int mmc_test_multi_write(struct mmc_test_card *test) 1076f397c8d8SUlf Hansson { 1077f397c8d8SUlf Hansson unsigned int size; 1078f397c8d8SUlf Hansson struct scatterlist sg; 1079f397c8d8SUlf Hansson 1080f397c8d8SUlf Hansson if (test->card->host->max_blk_count == 1) 1081f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1082f397c8d8SUlf Hansson 1083f397c8d8SUlf Hansson size = PAGE_SIZE * 2; 1084f397c8d8SUlf Hansson size = min(size, test->card->host->max_req_size); 1085f397c8d8SUlf Hansson size = min(size, test->card->host->max_seg_size); 1086f397c8d8SUlf Hansson size = min(size, test->card->host->max_blk_count * 512); 1087f397c8d8SUlf Hansson 1088f397c8d8SUlf Hansson if (size < 1024) 1089f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1090f397c8d8SUlf Hansson 1091f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer, size); 1092f397c8d8SUlf Hansson 1093f397c8d8SUlf Hansson return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1); 1094f397c8d8SUlf Hansson } 1095f397c8d8SUlf Hansson 1096f397c8d8SUlf Hansson static int mmc_test_multi_read(struct mmc_test_card *test) 1097f397c8d8SUlf Hansson { 1098f397c8d8SUlf Hansson unsigned int size; 1099f397c8d8SUlf Hansson struct scatterlist sg; 1100f397c8d8SUlf Hansson 1101f397c8d8SUlf Hansson if (test->card->host->max_blk_count == 1) 1102f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1103f397c8d8SUlf Hansson 1104f397c8d8SUlf Hansson size = PAGE_SIZE * 2; 1105f397c8d8SUlf Hansson size = min(size, test->card->host->max_req_size); 1106f397c8d8SUlf Hansson size = min(size, test->card->host->max_seg_size); 1107f397c8d8SUlf Hansson size = min(size, test->card->host->max_blk_count * 512); 1108f397c8d8SUlf Hansson 1109f397c8d8SUlf Hansson if (size < 1024) 1110f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1111f397c8d8SUlf Hansson 1112f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer, size); 1113f397c8d8SUlf Hansson 1114f397c8d8SUlf Hansson return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0); 1115f397c8d8SUlf Hansson } 1116f397c8d8SUlf Hansson 1117f397c8d8SUlf Hansson static int mmc_test_pow2_write(struct mmc_test_card *test) 1118f397c8d8SUlf Hansson { 1119f397c8d8SUlf Hansson int ret, i; 1120f397c8d8SUlf Hansson struct scatterlist sg; 1121f397c8d8SUlf Hansson 1122f397c8d8SUlf Hansson if (!test->card->csd.write_partial) 1123f397c8d8SUlf Hansson return RESULT_UNSUP_CARD; 1124f397c8d8SUlf Hansson 1125f397c8d8SUlf Hansson for (i = 1; i < 512; i <<= 1) { 1126f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer, i); 1127f397c8d8SUlf Hansson ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1); 1128f397c8d8SUlf Hansson if (ret) 1129f397c8d8SUlf Hansson return ret; 1130f397c8d8SUlf Hansson } 1131f397c8d8SUlf Hansson 1132f397c8d8SUlf Hansson return 0; 1133f397c8d8SUlf Hansson } 1134f397c8d8SUlf Hansson 1135f397c8d8SUlf Hansson static int mmc_test_pow2_read(struct mmc_test_card *test) 1136f397c8d8SUlf Hansson { 1137f397c8d8SUlf Hansson int ret, i; 1138f397c8d8SUlf Hansson struct scatterlist sg; 1139f397c8d8SUlf Hansson 1140f397c8d8SUlf Hansson if (!test->card->csd.read_partial) 1141f397c8d8SUlf Hansson return RESULT_UNSUP_CARD; 1142f397c8d8SUlf Hansson 1143f397c8d8SUlf Hansson for (i = 1; i < 512; i <<= 1) { 1144f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer, i); 1145f397c8d8SUlf Hansson ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0); 1146f397c8d8SUlf Hansson if (ret) 1147f397c8d8SUlf Hansson return ret; 1148f397c8d8SUlf Hansson } 1149f397c8d8SUlf Hansson 1150f397c8d8SUlf Hansson return 0; 1151f397c8d8SUlf Hansson } 1152f397c8d8SUlf Hansson 1153f397c8d8SUlf Hansson static int mmc_test_weird_write(struct mmc_test_card *test) 1154f397c8d8SUlf Hansson { 1155f397c8d8SUlf Hansson int ret, i; 1156f397c8d8SUlf Hansson struct scatterlist sg; 1157f397c8d8SUlf Hansson 1158f397c8d8SUlf Hansson if (!test->card->csd.write_partial) 1159f397c8d8SUlf Hansson return RESULT_UNSUP_CARD; 1160f397c8d8SUlf Hansson 1161f397c8d8SUlf Hansson for (i = 3; i < 512; i += 7) { 1162f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer, i); 1163f397c8d8SUlf Hansson ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1); 1164f397c8d8SUlf Hansson if (ret) 1165f397c8d8SUlf Hansson return ret; 1166f397c8d8SUlf Hansson } 1167f397c8d8SUlf Hansson 1168f397c8d8SUlf Hansson return 0; 1169f397c8d8SUlf Hansson } 1170f397c8d8SUlf Hansson 1171f397c8d8SUlf Hansson static int mmc_test_weird_read(struct mmc_test_card *test) 1172f397c8d8SUlf Hansson { 1173f397c8d8SUlf Hansson int ret, i; 1174f397c8d8SUlf Hansson struct scatterlist sg; 1175f397c8d8SUlf Hansson 1176f397c8d8SUlf Hansson if (!test->card->csd.read_partial) 1177f397c8d8SUlf Hansson return RESULT_UNSUP_CARD; 1178f397c8d8SUlf Hansson 1179f397c8d8SUlf Hansson for (i = 3; i < 512; i += 7) { 1180f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer, i); 1181f397c8d8SUlf Hansson ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0); 1182f397c8d8SUlf Hansson if (ret) 1183f397c8d8SUlf Hansson return ret; 1184f397c8d8SUlf Hansson } 1185f397c8d8SUlf Hansson 1186f397c8d8SUlf Hansson return 0; 1187f397c8d8SUlf Hansson } 1188f397c8d8SUlf Hansson 1189f397c8d8SUlf Hansson static int mmc_test_align_write(struct mmc_test_card *test) 1190f397c8d8SUlf Hansson { 1191f397c8d8SUlf Hansson int ret, i; 1192f397c8d8SUlf Hansson struct scatterlist sg; 1193f397c8d8SUlf Hansson 1194f397c8d8SUlf Hansson for (i = 1; i < TEST_ALIGN_END; i++) { 1195f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer + i, 512); 1196f397c8d8SUlf Hansson ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1); 1197f397c8d8SUlf Hansson if (ret) 1198f397c8d8SUlf Hansson return ret; 1199f397c8d8SUlf Hansson } 1200f397c8d8SUlf Hansson 1201f397c8d8SUlf Hansson return 0; 1202f397c8d8SUlf Hansson } 1203f397c8d8SUlf Hansson 1204f397c8d8SUlf Hansson static int mmc_test_align_read(struct mmc_test_card *test) 1205f397c8d8SUlf Hansson { 1206f397c8d8SUlf Hansson int ret, i; 1207f397c8d8SUlf Hansson struct scatterlist sg; 1208f397c8d8SUlf Hansson 1209f397c8d8SUlf Hansson for (i = 1; i < TEST_ALIGN_END; i++) { 1210f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer + i, 512); 1211f397c8d8SUlf Hansson ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0); 1212f397c8d8SUlf Hansson if (ret) 1213f397c8d8SUlf Hansson return ret; 1214f397c8d8SUlf Hansson } 1215f397c8d8SUlf Hansson 1216f397c8d8SUlf Hansson return 0; 1217f397c8d8SUlf Hansson } 1218f397c8d8SUlf Hansson 1219f397c8d8SUlf Hansson static int mmc_test_align_multi_write(struct mmc_test_card *test) 1220f397c8d8SUlf Hansson { 1221f397c8d8SUlf Hansson int ret, i; 1222f397c8d8SUlf Hansson unsigned int size; 1223f397c8d8SUlf Hansson struct scatterlist sg; 1224f397c8d8SUlf Hansson 1225f397c8d8SUlf Hansson if (test->card->host->max_blk_count == 1) 1226f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1227f397c8d8SUlf Hansson 1228f397c8d8SUlf Hansson size = PAGE_SIZE * 2; 1229f397c8d8SUlf Hansson size = min(size, test->card->host->max_req_size); 1230f397c8d8SUlf Hansson size = min(size, test->card->host->max_seg_size); 1231f397c8d8SUlf Hansson size = min(size, test->card->host->max_blk_count * 512); 1232f397c8d8SUlf Hansson 1233f397c8d8SUlf Hansson if (size < 1024) 1234f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1235f397c8d8SUlf Hansson 1236f397c8d8SUlf Hansson for (i = 1; i < TEST_ALIGN_END; i++) { 1237f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer + i, size); 1238f397c8d8SUlf Hansson ret = mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1); 1239f397c8d8SUlf Hansson if (ret) 1240f397c8d8SUlf Hansson return ret; 1241f397c8d8SUlf Hansson } 1242f397c8d8SUlf Hansson 1243f397c8d8SUlf Hansson return 0; 1244f397c8d8SUlf Hansson } 1245f397c8d8SUlf Hansson 1246f397c8d8SUlf Hansson static int mmc_test_align_multi_read(struct mmc_test_card *test) 1247f397c8d8SUlf Hansson { 1248f397c8d8SUlf Hansson int ret, i; 1249f397c8d8SUlf Hansson unsigned int size; 1250f397c8d8SUlf Hansson struct scatterlist sg; 1251f397c8d8SUlf Hansson 1252f397c8d8SUlf Hansson if (test->card->host->max_blk_count == 1) 1253f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1254f397c8d8SUlf Hansson 1255f397c8d8SUlf Hansson size = PAGE_SIZE * 2; 1256f397c8d8SUlf Hansson size = min(size, test->card->host->max_req_size); 1257f397c8d8SUlf Hansson size = min(size, test->card->host->max_seg_size); 1258f397c8d8SUlf Hansson size = min(size, test->card->host->max_blk_count * 512); 1259f397c8d8SUlf Hansson 1260f397c8d8SUlf Hansson if (size < 1024) 1261f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1262f397c8d8SUlf Hansson 1263f397c8d8SUlf Hansson for (i = 1; i < TEST_ALIGN_END; i++) { 1264f397c8d8SUlf Hansson sg_init_one(&sg, test->buffer + i, size); 1265f397c8d8SUlf Hansson ret = mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0); 1266f397c8d8SUlf Hansson if (ret) 1267f397c8d8SUlf Hansson return ret; 1268f397c8d8SUlf Hansson } 1269f397c8d8SUlf Hansson 1270f397c8d8SUlf Hansson return 0; 1271f397c8d8SUlf Hansson } 1272f397c8d8SUlf Hansson 1273f397c8d8SUlf Hansson static int mmc_test_xfersize_write(struct mmc_test_card *test) 1274f397c8d8SUlf Hansson { 1275f397c8d8SUlf Hansson int ret; 1276f397c8d8SUlf Hansson 1277f397c8d8SUlf Hansson ret = mmc_test_set_blksize(test, 512); 1278f397c8d8SUlf Hansson if (ret) 1279f397c8d8SUlf Hansson return ret; 1280f397c8d8SUlf Hansson 1281f397c8d8SUlf Hansson return mmc_test_broken_transfer(test, 1, 512, 1); 1282f397c8d8SUlf Hansson } 1283f397c8d8SUlf Hansson 1284f397c8d8SUlf Hansson static int mmc_test_xfersize_read(struct mmc_test_card *test) 1285f397c8d8SUlf Hansson { 1286f397c8d8SUlf Hansson int ret; 1287f397c8d8SUlf Hansson 1288f397c8d8SUlf Hansson ret = mmc_test_set_blksize(test, 512); 1289f397c8d8SUlf Hansson if (ret) 1290f397c8d8SUlf Hansson return ret; 1291f397c8d8SUlf Hansson 1292f397c8d8SUlf Hansson return mmc_test_broken_transfer(test, 1, 512, 0); 1293f397c8d8SUlf Hansson } 1294f397c8d8SUlf Hansson 1295f397c8d8SUlf Hansson static int mmc_test_multi_xfersize_write(struct mmc_test_card *test) 1296f397c8d8SUlf Hansson { 1297f397c8d8SUlf Hansson int ret; 1298f397c8d8SUlf Hansson 1299f397c8d8SUlf Hansson if (test->card->host->max_blk_count == 1) 1300f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1301f397c8d8SUlf Hansson 1302f397c8d8SUlf Hansson ret = mmc_test_set_blksize(test, 512); 1303f397c8d8SUlf Hansson if (ret) 1304f397c8d8SUlf Hansson return ret; 1305f397c8d8SUlf Hansson 1306f397c8d8SUlf Hansson return mmc_test_broken_transfer(test, 2, 512, 1); 1307f397c8d8SUlf Hansson } 1308f397c8d8SUlf Hansson 1309f397c8d8SUlf Hansson static int mmc_test_multi_xfersize_read(struct mmc_test_card *test) 1310f397c8d8SUlf Hansson { 1311f397c8d8SUlf Hansson int ret; 1312f397c8d8SUlf Hansson 1313f397c8d8SUlf Hansson if (test->card->host->max_blk_count == 1) 1314f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1315f397c8d8SUlf Hansson 1316f397c8d8SUlf Hansson ret = mmc_test_set_blksize(test, 512); 1317f397c8d8SUlf Hansson if (ret) 1318f397c8d8SUlf Hansson return ret; 1319f397c8d8SUlf Hansson 1320f397c8d8SUlf Hansson return mmc_test_broken_transfer(test, 2, 512, 0); 1321f397c8d8SUlf Hansson } 1322f397c8d8SUlf Hansson 1323f397c8d8SUlf Hansson #ifdef CONFIG_HIGHMEM 1324f397c8d8SUlf Hansson 1325f397c8d8SUlf Hansson static int mmc_test_write_high(struct mmc_test_card *test) 1326f397c8d8SUlf Hansson { 1327f397c8d8SUlf Hansson struct scatterlist sg; 1328f397c8d8SUlf Hansson 1329f397c8d8SUlf Hansson sg_init_table(&sg, 1); 1330f397c8d8SUlf Hansson sg_set_page(&sg, test->highmem, 512, 0); 1331f397c8d8SUlf Hansson 1332f397c8d8SUlf Hansson return mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1); 1333f397c8d8SUlf Hansson } 1334f397c8d8SUlf Hansson 1335f397c8d8SUlf Hansson static int mmc_test_read_high(struct mmc_test_card *test) 1336f397c8d8SUlf Hansson { 1337f397c8d8SUlf Hansson struct scatterlist sg; 1338f397c8d8SUlf Hansson 1339f397c8d8SUlf Hansson sg_init_table(&sg, 1); 1340f397c8d8SUlf Hansson sg_set_page(&sg, test->highmem, 512, 0); 1341f397c8d8SUlf Hansson 1342f397c8d8SUlf Hansson return mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0); 1343f397c8d8SUlf Hansson } 1344f397c8d8SUlf Hansson 1345f397c8d8SUlf Hansson static int mmc_test_multi_write_high(struct mmc_test_card *test) 1346f397c8d8SUlf Hansson { 1347f397c8d8SUlf Hansson unsigned int size; 1348f397c8d8SUlf Hansson struct scatterlist sg; 1349f397c8d8SUlf Hansson 1350f397c8d8SUlf Hansson if (test->card->host->max_blk_count == 1) 1351f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1352f397c8d8SUlf Hansson 1353f397c8d8SUlf Hansson size = PAGE_SIZE * 2; 1354f397c8d8SUlf Hansson size = min(size, test->card->host->max_req_size); 1355f397c8d8SUlf Hansson size = min(size, test->card->host->max_seg_size); 1356f397c8d8SUlf Hansson size = min(size, test->card->host->max_blk_count * 512); 1357f397c8d8SUlf Hansson 1358f397c8d8SUlf Hansson if (size < 1024) 1359f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1360f397c8d8SUlf Hansson 1361f397c8d8SUlf Hansson sg_init_table(&sg, 1); 1362f397c8d8SUlf Hansson sg_set_page(&sg, test->highmem, size, 0); 1363f397c8d8SUlf Hansson 1364f397c8d8SUlf Hansson return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1); 1365f397c8d8SUlf Hansson } 1366f397c8d8SUlf Hansson 1367f397c8d8SUlf Hansson static int mmc_test_multi_read_high(struct mmc_test_card *test) 1368f397c8d8SUlf Hansson { 1369f397c8d8SUlf Hansson unsigned int size; 1370f397c8d8SUlf Hansson struct scatterlist sg; 1371f397c8d8SUlf Hansson 1372f397c8d8SUlf Hansson if (test->card->host->max_blk_count == 1) 1373f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1374f397c8d8SUlf Hansson 1375f397c8d8SUlf Hansson size = PAGE_SIZE * 2; 1376f397c8d8SUlf Hansson size = min(size, test->card->host->max_req_size); 1377f397c8d8SUlf Hansson size = min(size, test->card->host->max_seg_size); 1378f397c8d8SUlf Hansson size = min(size, test->card->host->max_blk_count * 512); 1379f397c8d8SUlf Hansson 1380f397c8d8SUlf Hansson if (size < 1024) 1381f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1382f397c8d8SUlf Hansson 1383f397c8d8SUlf Hansson sg_init_table(&sg, 1); 1384f397c8d8SUlf Hansson sg_set_page(&sg, test->highmem, size, 0); 1385f397c8d8SUlf Hansson 1386f397c8d8SUlf Hansson return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0); 1387f397c8d8SUlf Hansson } 1388f397c8d8SUlf Hansson 1389f397c8d8SUlf Hansson #else 1390f397c8d8SUlf Hansson 1391f397c8d8SUlf Hansson static int mmc_test_no_highmem(struct mmc_test_card *test) 1392f397c8d8SUlf Hansson { 1393f397c8d8SUlf Hansson pr_info("%s: Highmem not configured - test skipped\n", 1394f397c8d8SUlf Hansson mmc_hostname(test->card->host)); 1395f397c8d8SUlf Hansson return 0; 1396f397c8d8SUlf Hansson } 1397f397c8d8SUlf Hansson 1398f397c8d8SUlf Hansson #endif /* CONFIG_HIGHMEM */ 1399f397c8d8SUlf Hansson 1400f397c8d8SUlf Hansson /* 1401f397c8d8SUlf Hansson * Map sz bytes so that it can be transferred. 1402f397c8d8SUlf Hansson */ 1403f397c8d8SUlf Hansson static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz, 1404f397c8d8SUlf Hansson int max_scatter, int min_sg_len) 1405f397c8d8SUlf Hansson { 1406f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1407f397c8d8SUlf Hansson int err; 1408f397c8d8SUlf Hansson 1409f397c8d8SUlf Hansson t->blocks = sz >> 9; 1410f397c8d8SUlf Hansson 1411f397c8d8SUlf Hansson if (max_scatter) { 1412f397c8d8SUlf Hansson err = mmc_test_map_sg_max_scatter(t->mem, sz, t->sg, 1413f397c8d8SUlf Hansson t->max_segs, t->max_seg_sz, 1414f397c8d8SUlf Hansson &t->sg_len); 1415f397c8d8SUlf Hansson } else { 1416f397c8d8SUlf Hansson err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs, 1417f397c8d8SUlf Hansson t->max_seg_sz, &t->sg_len, min_sg_len); 1418f397c8d8SUlf Hansson } 1419f397c8d8SUlf Hansson if (err) 1420f397c8d8SUlf Hansson pr_info("%s: Failed to map sg list\n", 1421f397c8d8SUlf Hansson mmc_hostname(test->card->host)); 1422f397c8d8SUlf Hansson return err; 1423f397c8d8SUlf Hansson } 1424f397c8d8SUlf Hansson 1425f397c8d8SUlf Hansson /* 1426f397c8d8SUlf Hansson * Transfer bytes mapped by mmc_test_area_map(). 1427f397c8d8SUlf Hansson */ 1428f397c8d8SUlf Hansson static int mmc_test_area_transfer(struct mmc_test_card *test, 1429f397c8d8SUlf Hansson unsigned int dev_addr, int write) 1430f397c8d8SUlf Hansson { 1431f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1432f397c8d8SUlf Hansson 1433f397c8d8SUlf Hansson return mmc_test_simple_transfer(test, t->sg, t->sg_len, dev_addr, 1434f397c8d8SUlf Hansson t->blocks, 512, write); 1435f397c8d8SUlf Hansson } 1436f397c8d8SUlf Hansson 1437f397c8d8SUlf Hansson /* 1438f397c8d8SUlf Hansson * Map and transfer bytes for multiple transfers. 1439f397c8d8SUlf Hansson */ 1440f397c8d8SUlf Hansson static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz, 1441f397c8d8SUlf Hansson unsigned int dev_addr, int write, 1442f397c8d8SUlf Hansson int max_scatter, int timed, int count, 1443f397c8d8SUlf Hansson bool nonblock, int min_sg_len) 1444f397c8d8SUlf Hansson { 1445f397c8d8SUlf Hansson struct timespec ts1, ts2; 1446f397c8d8SUlf Hansson int ret = 0; 1447f397c8d8SUlf Hansson int i; 1448f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1449f397c8d8SUlf Hansson 1450f397c8d8SUlf Hansson /* 1451f397c8d8SUlf Hansson * In the case of a maximally scattered transfer, the maximum transfer 1452f397c8d8SUlf Hansson * size is further limited by using PAGE_SIZE segments. 1453f397c8d8SUlf Hansson */ 1454f397c8d8SUlf Hansson if (max_scatter) { 1455f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1456f397c8d8SUlf Hansson unsigned long max_tfr; 1457f397c8d8SUlf Hansson 1458f397c8d8SUlf Hansson if (t->max_seg_sz >= PAGE_SIZE) 1459f397c8d8SUlf Hansson max_tfr = t->max_segs * PAGE_SIZE; 1460f397c8d8SUlf Hansson else 1461f397c8d8SUlf Hansson max_tfr = t->max_segs * t->max_seg_sz; 1462f397c8d8SUlf Hansson if (sz > max_tfr) 1463f397c8d8SUlf Hansson sz = max_tfr; 1464f397c8d8SUlf Hansson } 1465f397c8d8SUlf Hansson 1466f397c8d8SUlf Hansson ret = mmc_test_area_map(test, sz, max_scatter, min_sg_len); 1467f397c8d8SUlf Hansson if (ret) 1468f397c8d8SUlf Hansson return ret; 1469f397c8d8SUlf Hansson 1470f397c8d8SUlf Hansson if (timed) 1471f397c8d8SUlf Hansson getnstimeofday(&ts1); 1472f397c8d8SUlf Hansson if (nonblock) 1473f397c8d8SUlf Hansson ret = mmc_test_nonblock_transfer(test, t->sg, t->sg_len, 1474f397c8d8SUlf Hansson dev_addr, t->blocks, 512, write, count); 1475f397c8d8SUlf Hansson else 1476f397c8d8SUlf Hansson for (i = 0; i < count && ret == 0; i++) { 1477f397c8d8SUlf Hansson ret = mmc_test_area_transfer(test, dev_addr, write); 1478f397c8d8SUlf Hansson dev_addr += sz >> 9; 1479f397c8d8SUlf Hansson } 1480f397c8d8SUlf Hansson 1481f397c8d8SUlf Hansson if (ret) 1482f397c8d8SUlf Hansson return ret; 1483f397c8d8SUlf Hansson 1484f397c8d8SUlf Hansson if (timed) 1485f397c8d8SUlf Hansson getnstimeofday(&ts2); 1486f397c8d8SUlf Hansson 1487f397c8d8SUlf Hansson if (timed) 1488f397c8d8SUlf Hansson mmc_test_print_avg_rate(test, sz, count, &ts1, &ts2); 1489f397c8d8SUlf Hansson 1490f397c8d8SUlf Hansson return 0; 1491f397c8d8SUlf Hansson } 1492f397c8d8SUlf Hansson 1493f397c8d8SUlf Hansson static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz, 1494f397c8d8SUlf Hansson unsigned int dev_addr, int write, int max_scatter, 1495f397c8d8SUlf Hansson int timed) 1496f397c8d8SUlf Hansson { 1497f397c8d8SUlf Hansson return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter, 1498f397c8d8SUlf Hansson timed, 1, false, 0); 1499f397c8d8SUlf Hansson } 1500f397c8d8SUlf Hansson 1501f397c8d8SUlf Hansson /* 1502f397c8d8SUlf Hansson * Write the test area entirely. 1503f397c8d8SUlf Hansson */ 1504f397c8d8SUlf Hansson static int mmc_test_area_fill(struct mmc_test_card *test) 1505f397c8d8SUlf Hansson { 1506f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1507f397c8d8SUlf Hansson 1508f397c8d8SUlf Hansson return mmc_test_area_io(test, t->max_tfr, t->dev_addr, 1, 0, 0); 1509f397c8d8SUlf Hansson } 1510f397c8d8SUlf Hansson 1511f397c8d8SUlf Hansson /* 1512f397c8d8SUlf Hansson * Erase the test area entirely. 1513f397c8d8SUlf Hansson */ 1514f397c8d8SUlf Hansson static int mmc_test_area_erase(struct mmc_test_card *test) 1515f397c8d8SUlf Hansson { 1516f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1517f397c8d8SUlf Hansson 1518f397c8d8SUlf Hansson if (!mmc_can_erase(test->card)) 1519f397c8d8SUlf Hansson return 0; 1520f397c8d8SUlf Hansson 1521f397c8d8SUlf Hansson return mmc_erase(test->card, t->dev_addr, t->max_sz >> 9, 1522f397c8d8SUlf Hansson MMC_ERASE_ARG); 1523f397c8d8SUlf Hansson } 1524f397c8d8SUlf Hansson 1525f397c8d8SUlf Hansson /* 1526f397c8d8SUlf Hansson * Cleanup struct mmc_test_area. 1527f397c8d8SUlf Hansson */ 1528f397c8d8SUlf Hansson static int mmc_test_area_cleanup(struct mmc_test_card *test) 1529f397c8d8SUlf Hansson { 1530f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1531f397c8d8SUlf Hansson 1532f397c8d8SUlf Hansson kfree(t->sg); 1533f397c8d8SUlf Hansson mmc_test_free_mem(t->mem); 1534f397c8d8SUlf Hansson 1535f397c8d8SUlf Hansson return 0; 1536f397c8d8SUlf Hansson } 1537f397c8d8SUlf Hansson 1538f397c8d8SUlf Hansson /* 1539f397c8d8SUlf Hansson * Initialize an area for testing large transfers. The test area is set to the 154074536bc0SMarkus Elfring * middle of the card because cards may have different characteristics at the 1541f397c8d8SUlf Hansson * front (for FAT file system optimization). Optionally, the area is erased 1542f397c8d8SUlf Hansson * (if the card supports it) which may improve write performance. Optionally, 1543f397c8d8SUlf Hansson * the area is filled with data for subsequent read tests. 1544f397c8d8SUlf Hansson */ 1545f397c8d8SUlf Hansson static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill) 1546f397c8d8SUlf Hansson { 1547f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1548f397c8d8SUlf Hansson unsigned long min_sz = 64 * 1024, sz; 1549f397c8d8SUlf Hansson int ret; 1550f397c8d8SUlf Hansson 1551f397c8d8SUlf Hansson ret = mmc_test_set_blksize(test, 512); 1552f397c8d8SUlf Hansson if (ret) 1553f397c8d8SUlf Hansson return ret; 1554f397c8d8SUlf Hansson 1555f397c8d8SUlf Hansson /* Make the test area size about 4MiB */ 1556f397c8d8SUlf Hansson sz = (unsigned long)test->card->pref_erase << 9; 1557f397c8d8SUlf Hansson t->max_sz = sz; 1558f397c8d8SUlf Hansson while (t->max_sz < 4 * 1024 * 1024) 1559f397c8d8SUlf Hansson t->max_sz += sz; 1560f397c8d8SUlf Hansson while (t->max_sz > TEST_AREA_MAX_SIZE && t->max_sz > sz) 1561f397c8d8SUlf Hansson t->max_sz -= sz; 1562f397c8d8SUlf Hansson 1563f397c8d8SUlf Hansson t->max_segs = test->card->host->max_segs; 1564f397c8d8SUlf Hansson t->max_seg_sz = test->card->host->max_seg_size; 1565f397c8d8SUlf Hansson t->max_seg_sz -= t->max_seg_sz % 512; 1566f397c8d8SUlf Hansson 1567f397c8d8SUlf Hansson t->max_tfr = t->max_sz; 1568f397c8d8SUlf Hansson if (t->max_tfr >> 9 > test->card->host->max_blk_count) 1569f397c8d8SUlf Hansson t->max_tfr = test->card->host->max_blk_count << 9; 1570f397c8d8SUlf Hansson if (t->max_tfr > test->card->host->max_req_size) 1571f397c8d8SUlf Hansson t->max_tfr = test->card->host->max_req_size; 1572f397c8d8SUlf Hansson if (t->max_tfr / t->max_seg_sz > t->max_segs) 1573f397c8d8SUlf Hansson t->max_tfr = t->max_segs * t->max_seg_sz; 1574f397c8d8SUlf Hansson 1575f397c8d8SUlf Hansson /* 1576f397c8d8SUlf Hansson * Try to allocate enough memory for a max. sized transfer. Less is OK 1577f397c8d8SUlf Hansson * because the same memory can be mapped into the scatterlist more than 1578f397c8d8SUlf Hansson * once. Also, take into account the limits imposed on scatterlist 1579f397c8d8SUlf Hansson * segments by the host driver. 1580f397c8d8SUlf Hansson */ 1581f397c8d8SUlf Hansson t->mem = mmc_test_alloc_mem(min_sz, t->max_tfr, t->max_segs, 1582f397c8d8SUlf Hansson t->max_seg_sz); 1583f397c8d8SUlf Hansson if (!t->mem) 1584f397c8d8SUlf Hansson return -ENOMEM; 1585f397c8d8SUlf Hansson 1586457e4f7fSMarkus Elfring t->sg = kmalloc_array(t->max_segs, sizeof(*t->sg), GFP_KERNEL); 1587f397c8d8SUlf Hansson if (!t->sg) { 1588f397c8d8SUlf Hansson ret = -ENOMEM; 1589f397c8d8SUlf Hansson goto out_free; 1590f397c8d8SUlf Hansson } 1591f397c8d8SUlf Hansson 1592f397c8d8SUlf Hansson t->dev_addr = mmc_test_capacity(test->card) / 2; 1593f397c8d8SUlf Hansson t->dev_addr -= t->dev_addr % (t->max_sz >> 9); 1594f397c8d8SUlf Hansson 1595f397c8d8SUlf Hansson if (erase) { 1596f397c8d8SUlf Hansson ret = mmc_test_area_erase(test); 1597f397c8d8SUlf Hansson if (ret) 1598f397c8d8SUlf Hansson goto out_free; 1599f397c8d8SUlf Hansson } 1600f397c8d8SUlf Hansson 1601f397c8d8SUlf Hansson if (fill) { 1602f397c8d8SUlf Hansson ret = mmc_test_area_fill(test); 1603f397c8d8SUlf Hansson if (ret) 1604f397c8d8SUlf Hansson goto out_free; 1605f397c8d8SUlf Hansson } 1606f397c8d8SUlf Hansson 1607f397c8d8SUlf Hansson return 0; 1608f397c8d8SUlf Hansson 1609f397c8d8SUlf Hansson out_free: 1610f397c8d8SUlf Hansson mmc_test_area_cleanup(test); 1611f397c8d8SUlf Hansson return ret; 1612f397c8d8SUlf Hansson } 1613f397c8d8SUlf Hansson 1614f397c8d8SUlf Hansson /* 1615f397c8d8SUlf Hansson * Prepare for large transfers. Do not erase the test area. 1616f397c8d8SUlf Hansson */ 1617f397c8d8SUlf Hansson static int mmc_test_area_prepare(struct mmc_test_card *test) 1618f397c8d8SUlf Hansson { 1619f397c8d8SUlf Hansson return mmc_test_area_init(test, 0, 0); 1620f397c8d8SUlf Hansson } 1621f397c8d8SUlf Hansson 1622f397c8d8SUlf Hansson /* 1623f397c8d8SUlf Hansson * Prepare for large transfers. Do erase the test area. 1624f397c8d8SUlf Hansson */ 1625f397c8d8SUlf Hansson static int mmc_test_area_prepare_erase(struct mmc_test_card *test) 1626f397c8d8SUlf Hansson { 1627f397c8d8SUlf Hansson return mmc_test_area_init(test, 1, 0); 1628f397c8d8SUlf Hansson } 1629f397c8d8SUlf Hansson 1630f397c8d8SUlf Hansson /* 1631f397c8d8SUlf Hansson * Prepare for large transfers. Erase and fill the test area. 1632f397c8d8SUlf Hansson */ 1633f397c8d8SUlf Hansson static int mmc_test_area_prepare_fill(struct mmc_test_card *test) 1634f397c8d8SUlf Hansson { 1635f397c8d8SUlf Hansson return mmc_test_area_init(test, 1, 1); 1636f397c8d8SUlf Hansson } 1637f397c8d8SUlf Hansson 1638f397c8d8SUlf Hansson /* 1639f397c8d8SUlf Hansson * Test best-case performance. Best-case performance is expected from 1640f397c8d8SUlf Hansson * a single large transfer. 1641f397c8d8SUlf Hansson * 1642f397c8d8SUlf Hansson * An additional option (max_scatter) allows the measurement of the same 1643f397c8d8SUlf Hansson * transfer but with no contiguous pages in the scatter list. This tests 1644f397c8d8SUlf Hansson * the efficiency of DMA to handle scattered pages. 1645f397c8d8SUlf Hansson */ 1646f397c8d8SUlf Hansson static int mmc_test_best_performance(struct mmc_test_card *test, int write, 1647f397c8d8SUlf Hansson int max_scatter) 1648f397c8d8SUlf Hansson { 1649f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1650f397c8d8SUlf Hansson 1651f397c8d8SUlf Hansson return mmc_test_area_io(test, t->max_tfr, t->dev_addr, write, 1652f397c8d8SUlf Hansson max_scatter, 1); 1653f397c8d8SUlf Hansson } 1654f397c8d8SUlf Hansson 1655f397c8d8SUlf Hansson /* 1656f397c8d8SUlf Hansson * Best-case read performance. 1657f397c8d8SUlf Hansson */ 1658f397c8d8SUlf Hansson static int mmc_test_best_read_performance(struct mmc_test_card *test) 1659f397c8d8SUlf Hansson { 1660f397c8d8SUlf Hansson return mmc_test_best_performance(test, 0, 0); 1661f397c8d8SUlf Hansson } 1662f397c8d8SUlf Hansson 1663f397c8d8SUlf Hansson /* 1664f397c8d8SUlf Hansson * Best-case write performance. 1665f397c8d8SUlf Hansson */ 1666f397c8d8SUlf Hansson static int mmc_test_best_write_performance(struct mmc_test_card *test) 1667f397c8d8SUlf Hansson { 1668f397c8d8SUlf Hansson return mmc_test_best_performance(test, 1, 0); 1669f397c8d8SUlf Hansson } 1670f397c8d8SUlf Hansson 1671f397c8d8SUlf Hansson /* 1672f397c8d8SUlf Hansson * Best-case read performance into scattered pages. 1673f397c8d8SUlf Hansson */ 1674f397c8d8SUlf Hansson static int mmc_test_best_read_perf_max_scatter(struct mmc_test_card *test) 1675f397c8d8SUlf Hansson { 1676f397c8d8SUlf Hansson return mmc_test_best_performance(test, 0, 1); 1677f397c8d8SUlf Hansson } 1678f397c8d8SUlf Hansson 1679f397c8d8SUlf Hansson /* 1680f397c8d8SUlf Hansson * Best-case write performance from scattered pages. 1681f397c8d8SUlf Hansson */ 1682f397c8d8SUlf Hansson static int mmc_test_best_write_perf_max_scatter(struct mmc_test_card *test) 1683f397c8d8SUlf Hansson { 1684f397c8d8SUlf Hansson return mmc_test_best_performance(test, 1, 1); 1685f397c8d8SUlf Hansson } 1686f397c8d8SUlf Hansson 1687f397c8d8SUlf Hansson /* 1688f397c8d8SUlf Hansson * Single read performance by transfer size. 1689f397c8d8SUlf Hansson */ 1690f397c8d8SUlf Hansson static int mmc_test_profile_read_perf(struct mmc_test_card *test) 1691f397c8d8SUlf Hansson { 1692f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1693f397c8d8SUlf Hansson unsigned long sz; 1694f397c8d8SUlf Hansson unsigned int dev_addr; 1695f397c8d8SUlf Hansson int ret; 1696f397c8d8SUlf Hansson 1697f397c8d8SUlf Hansson for (sz = 512; sz < t->max_tfr; sz <<= 1) { 1698f397c8d8SUlf Hansson dev_addr = t->dev_addr + (sz >> 9); 1699f397c8d8SUlf Hansson ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1); 1700f397c8d8SUlf Hansson if (ret) 1701f397c8d8SUlf Hansson return ret; 1702f397c8d8SUlf Hansson } 1703f397c8d8SUlf Hansson sz = t->max_tfr; 1704f397c8d8SUlf Hansson dev_addr = t->dev_addr; 1705f397c8d8SUlf Hansson return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1); 1706f397c8d8SUlf Hansson } 1707f397c8d8SUlf Hansson 1708f397c8d8SUlf Hansson /* 1709f397c8d8SUlf Hansson * Single write performance by transfer size. 1710f397c8d8SUlf Hansson */ 1711f397c8d8SUlf Hansson static int mmc_test_profile_write_perf(struct mmc_test_card *test) 1712f397c8d8SUlf Hansson { 1713f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1714f397c8d8SUlf Hansson unsigned long sz; 1715f397c8d8SUlf Hansson unsigned int dev_addr; 1716f397c8d8SUlf Hansson int ret; 1717f397c8d8SUlf Hansson 1718f397c8d8SUlf Hansson ret = mmc_test_area_erase(test); 1719f397c8d8SUlf Hansson if (ret) 1720f397c8d8SUlf Hansson return ret; 1721f397c8d8SUlf Hansson for (sz = 512; sz < t->max_tfr; sz <<= 1) { 1722f397c8d8SUlf Hansson dev_addr = t->dev_addr + (sz >> 9); 1723f397c8d8SUlf Hansson ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1); 1724f397c8d8SUlf Hansson if (ret) 1725f397c8d8SUlf Hansson return ret; 1726f397c8d8SUlf Hansson } 1727f397c8d8SUlf Hansson ret = mmc_test_area_erase(test); 1728f397c8d8SUlf Hansson if (ret) 1729f397c8d8SUlf Hansson return ret; 1730f397c8d8SUlf Hansson sz = t->max_tfr; 1731f397c8d8SUlf Hansson dev_addr = t->dev_addr; 1732f397c8d8SUlf Hansson return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1); 1733f397c8d8SUlf Hansson } 1734f397c8d8SUlf Hansson 1735f397c8d8SUlf Hansson /* 1736f397c8d8SUlf Hansson * Single trim performance by transfer size. 1737f397c8d8SUlf Hansson */ 1738f397c8d8SUlf Hansson static int mmc_test_profile_trim_perf(struct mmc_test_card *test) 1739f397c8d8SUlf Hansson { 1740f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1741f397c8d8SUlf Hansson unsigned long sz; 1742f397c8d8SUlf Hansson unsigned int dev_addr; 1743f397c8d8SUlf Hansson struct timespec ts1, ts2; 1744f397c8d8SUlf Hansson int ret; 1745f397c8d8SUlf Hansson 1746f397c8d8SUlf Hansson if (!mmc_can_trim(test->card)) 1747f397c8d8SUlf Hansson return RESULT_UNSUP_CARD; 1748f397c8d8SUlf Hansson 1749f397c8d8SUlf Hansson if (!mmc_can_erase(test->card)) 1750f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1751f397c8d8SUlf Hansson 1752f397c8d8SUlf Hansson for (sz = 512; sz < t->max_sz; sz <<= 1) { 1753f397c8d8SUlf Hansson dev_addr = t->dev_addr + (sz >> 9); 1754f397c8d8SUlf Hansson getnstimeofday(&ts1); 1755f397c8d8SUlf Hansson ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG); 1756f397c8d8SUlf Hansson if (ret) 1757f397c8d8SUlf Hansson return ret; 1758f397c8d8SUlf Hansson getnstimeofday(&ts2); 1759f397c8d8SUlf Hansson mmc_test_print_rate(test, sz, &ts1, &ts2); 1760f397c8d8SUlf Hansson } 1761f397c8d8SUlf Hansson dev_addr = t->dev_addr; 1762f397c8d8SUlf Hansson getnstimeofday(&ts1); 1763f397c8d8SUlf Hansson ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG); 1764f397c8d8SUlf Hansson if (ret) 1765f397c8d8SUlf Hansson return ret; 1766f397c8d8SUlf Hansson getnstimeofday(&ts2); 1767f397c8d8SUlf Hansson mmc_test_print_rate(test, sz, &ts1, &ts2); 1768f397c8d8SUlf Hansson return 0; 1769f397c8d8SUlf Hansson } 1770f397c8d8SUlf Hansson 1771f397c8d8SUlf Hansson static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz) 1772f397c8d8SUlf Hansson { 1773f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1774f397c8d8SUlf Hansson unsigned int dev_addr, i, cnt; 1775f397c8d8SUlf Hansson struct timespec ts1, ts2; 1776f397c8d8SUlf Hansson int ret; 1777f397c8d8SUlf Hansson 1778f397c8d8SUlf Hansson cnt = t->max_sz / sz; 1779f397c8d8SUlf Hansson dev_addr = t->dev_addr; 1780f397c8d8SUlf Hansson getnstimeofday(&ts1); 1781f397c8d8SUlf Hansson for (i = 0; i < cnt; i++) { 1782f397c8d8SUlf Hansson ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0); 1783f397c8d8SUlf Hansson if (ret) 1784f397c8d8SUlf Hansson return ret; 1785f397c8d8SUlf Hansson dev_addr += (sz >> 9); 1786f397c8d8SUlf Hansson } 1787f397c8d8SUlf Hansson getnstimeofday(&ts2); 1788f397c8d8SUlf Hansson mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); 1789f397c8d8SUlf Hansson return 0; 1790f397c8d8SUlf Hansson } 1791f397c8d8SUlf Hansson 1792f397c8d8SUlf Hansson /* 1793f397c8d8SUlf Hansson * Consecutive read performance by transfer size. 1794f397c8d8SUlf Hansson */ 1795f397c8d8SUlf Hansson static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test) 1796f397c8d8SUlf Hansson { 1797f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1798f397c8d8SUlf Hansson unsigned long sz; 1799f397c8d8SUlf Hansson int ret; 1800f397c8d8SUlf Hansson 1801f397c8d8SUlf Hansson for (sz = 512; sz < t->max_tfr; sz <<= 1) { 1802f397c8d8SUlf Hansson ret = mmc_test_seq_read_perf(test, sz); 1803f397c8d8SUlf Hansson if (ret) 1804f397c8d8SUlf Hansson return ret; 1805f397c8d8SUlf Hansson } 1806f397c8d8SUlf Hansson sz = t->max_tfr; 1807f397c8d8SUlf Hansson return mmc_test_seq_read_perf(test, sz); 1808f397c8d8SUlf Hansson } 1809f397c8d8SUlf Hansson 1810f397c8d8SUlf Hansson static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz) 1811f397c8d8SUlf Hansson { 1812f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1813f397c8d8SUlf Hansson unsigned int dev_addr, i, cnt; 1814f397c8d8SUlf Hansson struct timespec ts1, ts2; 1815f397c8d8SUlf Hansson int ret; 1816f397c8d8SUlf Hansson 1817f397c8d8SUlf Hansson ret = mmc_test_area_erase(test); 1818f397c8d8SUlf Hansson if (ret) 1819f397c8d8SUlf Hansson return ret; 1820f397c8d8SUlf Hansson cnt = t->max_sz / sz; 1821f397c8d8SUlf Hansson dev_addr = t->dev_addr; 1822f397c8d8SUlf Hansson getnstimeofday(&ts1); 1823f397c8d8SUlf Hansson for (i = 0; i < cnt; i++) { 1824f397c8d8SUlf Hansson ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0); 1825f397c8d8SUlf Hansson if (ret) 1826f397c8d8SUlf Hansson return ret; 1827f397c8d8SUlf Hansson dev_addr += (sz >> 9); 1828f397c8d8SUlf Hansson } 1829f397c8d8SUlf Hansson getnstimeofday(&ts2); 1830f397c8d8SUlf Hansson mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); 1831f397c8d8SUlf Hansson return 0; 1832f397c8d8SUlf Hansson } 1833f397c8d8SUlf Hansson 1834f397c8d8SUlf Hansson /* 1835f397c8d8SUlf Hansson * Consecutive write performance by transfer size. 1836f397c8d8SUlf Hansson */ 1837f397c8d8SUlf Hansson static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test) 1838f397c8d8SUlf Hansson { 1839f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1840f397c8d8SUlf Hansson unsigned long sz; 1841f397c8d8SUlf Hansson int ret; 1842f397c8d8SUlf Hansson 1843f397c8d8SUlf Hansson for (sz = 512; sz < t->max_tfr; sz <<= 1) { 1844f397c8d8SUlf Hansson ret = mmc_test_seq_write_perf(test, sz); 1845f397c8d8SUlf Hansson if (ret) 1846f397c8d8SUlf Hansson return ret; 1847f397c8d8SUlf Hansson } 1848f397c8d8SUlf Hansson sz = t->max_tfr; 1849f397c8d8SUlf Hansson return mmc_test_seq_write_perf(test, sz); 1850f397c8d8SUlf Hansson } 1851f397c8d8SUlf Hansson 1852f397c8d8SUlf Hansson /* 1853f397c8d8SUlf Hansson * Consecutive trim performance by transfer size. 1854f397c8d8SUlf Hansson */ 1855f397c8d8SUlf Hansson static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test) 1856f397c8d8SUlf Hansson { 1857f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1858f397c8d8SUlf Hansson unsigned long sz; 1859f397c8d8SUlf Hansson unsigned int dev_addr, i, cnt; 1860f397c8d8SUlf Hansson struct timespec ts1, ts2; 1861f397c8d8SUlf Hansson int ret; 1862f397c8d8SUlf Hansson 1863f397c8d8SUlf Hansson if (!mmc_can_trim(test->card)) 1864f397c8d8SUlf Hansson return RESULT_UNSUP_CARD; 1865f397c8d8SUlf Hansson 1866f397c8d8SUlf Hansson if (!mmc_can_erase(test->card)) 1867f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 1868f397c8d8SUlf Hansson 1869f397c8d8SUlf Hansson for (sz = 512; sz <= t->max_sz; sz <<= 1) { 1870f397c8d8SUlf Hansson ret = mmc_test_area_erase(test); 1871f397c8d8SUlf Hansson if (ret) 1872f397c8d8SUlf Hansson return ret; 1873f397c8d8SUlf Hansson ret = mmc_test_area_fill(test); 1874f397c8d8SUlf Hansson if (ret) 1875f397c8d8SUlf Hansson return ret; 1876f397c8d8SUlf Hansson cnt = t->max_sz / sz; 1877f397c8d8SUlf Hansson dev_addr = t->dev_addr; 1878f397c8d8SUlf Hansson getnstimeofday(&ts1); 1879f397c8d8SUlf Hansson for (i = 0; i < cnt; i++) { 1880f397c8d8SUlf Hansson ret = mmc_erase(test->card, dev_addr, sz >> 9, 1881f397c8d8SUlf Hansson MMC_TRIM_ARG); 1882f397c8d8SUlf Hansson if (ret) 1883f397c8d8SUlf Hansson return ret; 1884f397c8d8SUlf Hansson dev_addr += (sz >> 9); 1885f397c8d8SUlf Hansson } 1886f397c8d8SUlf Hansson getnstimeofday(&ts2); 1887f397c8d8SUlf Hansson mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); 1888f397c8d8SUlf Hansson } 1889f397c8d8SUlf Hansson return 0; 1890f397c8d8SUlf Hansson } 1891f397c8d8SUlf Hansson 1892f397c8d8SUlf Hansson static unsigned int rnd_next = 1; 1893f397c8d8SUlf Hansson 1894f397c8d8SUlf Hansson static unsigned int mmc_test_rnd_num(unsigned int rnd_cnt) 1895f397c8d8SUlf Hansson { 1896f397c8d8SUlf Hansson uint64_t r; 1897f397c8d8SUlf Hansson 1898f397c8d8SUlf Hansson rnd_next = rnd_next * 1103515245 + 12345; 1899f397c8d8SUlf Hansson r = (rnd_next >> 16) & 0x7fff; 1900f397c8d8SUlf Hansson return (r * rnd_cnt) >> 15; 1901f397c8d8SUlf Hansson } 1902f397c8d8SUlf Hansson 1903f397c8d8SUlf Hansson static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print, 1904f397c8d8SUlf Hansson unsigned long sz) 1905f397c8d8SUlf Hansson { 1906f397c8d8SUlf Hansson unsigned int dev_addr, cnt, rnd_addr, range1, range2, last_ea = 0, ea; 1907f397c8d8SUlf Hansson unsigned int ssz; 1908f397c8d8SUlf Hansson struct timespec ts1, ts2, ts; 1909f397c8d8SUlf Hansson int ret; 1910f397c8d8SUlf Hansson 1911f397c8d8SUlf Hansson ssz = sz >> 9; 1912f397c8d8SUlf Hansson 1913f397c8d8SUlf Hansson rnd_addr = mmc_test_capacity(test->card) / 4; 1914f397c8d8SUlf Hansson range1 = rnd_addr / test->card->pref_erase; 1915f397c8d8SUlf Hansson range2 = range1 / ssz; 1916f397c8d8SUlf Hansson 1917f397c8d8SUlf Hansson getnstimeofday(&ts1); 1918f397c8d8SUlf Hansson for (cnt = 0; cnt < UINT_MAX; cnt++) { 1919f397c8d8SUlf Hansson getnstimeofday(&ts2); 1920f397c8d8SUlf Hansson ts = timespec_sub(ts2, ts1); 1921f397c8d8SUlf Hansson if (ts.tv_sec >= 10) 1922f397c8d8SUlf Hansson break; 1923f397c8d8SUlf Hansson ea = mmc_test_rnd_num(range1); 1924f397c8d8SUlf Hansson if (ea == last_ea) 1925f397c8d8SUlf Hansson ea -= 1; 1926f397c8d8SUlf Hansson last_ea = ea; 1927f397c8d8SUlf Hansson dev_addr = rnd_addr + test->card->pref_erase * ea + 1928f397c8d8SUlf Hansson ssz * mmc_test_rnd_num(range2); 1929f397c8d8SUlf Hansson ret = mmc_test_area_io(test, sz, dev_addr, write, 0, 0); 1930f397c8d8SUlf Hansson if (ret) 1931f397c8d8SUlf Hansson return ret; 1932f397c8d8SUlf Hansson } 1933f397c8d8SUlf Hansson if (print) 1934f397c8d8SUlf Hansson mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); 1935f397c8d8SUlf Hansson return 0; 1936f397c8d8SUlf Hansson } 1937f397c8d8SUlf Hansson 1938f397c8d8SUlf Hansson static int mmc_test_random_perf(struct mmc_test_card *test, int write) 1939f397c8d8SUlf Hansson { 1940f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1941f397c8d8SUlf Hansson unsigned int next; 1942f397c8d8SUlf Hansson unsigned long sz; 1943f397c8d8SUlf Hansson int ret; 1944f397c8d8SUlf Hansson 1945f397c8d8SUlf Hansson for (sz = 512; sz < t->max_tfr; sz <<= 1) { 1946f397c8d8SUlf Hansson /* 1947f397c8d8SUlf Hansson * When writing, try to get more consistent results by running 1948f397c8d8SUlf Hansson * the test twice with exactly the same I/O but outputting the 1949f397c8d8SUlf Hansson * results only for the 2nd run. 1950f397c8d8SUlf Hansson */ 1951f397c8d8SUlf Hansson if (write) { 1952f397c8d8SUlf Hansson next = rnd_next; 1953f397c8d8SUlf Hansson ret = mmc_test_rnd_perf(test, write, 0, sz); 1954f397c8d8SUlf Hansson if (ret) 1955f397c8d8SUlf Hansson return ret; 1956f397c8d8SUlf Hansson rnd_next = next; 1957f397c8d8SUlf Hansson } 1958f397c8d8SUlf Hansson ret = mmc_test_rnd_perf(test, write, 1, sz); 1959f397c8d8SUlf Hansson if (ret) 1960f397c8d8SUlf Hansson return ret; 1961f397c8d8SUlf Hansson } 1962f397c8d8SUlf Hansson sz = t->max_tfr; 1963f397c8d8SUlf Hansson if (write) { 1964f397c8d8SUlf Hansson next = rnd_next; 1965f397c8d8SUlf Hansson ret = mmc_test_rnd_perf(test, write, 0, sz); 1966f397c8d8SUlf Hansson if (ret) 1967f397c8d8SUlf Hansson return ret; 1968f397c8d8SUlf Hansson rnd_next = next; 1969f397c8d8SUlf Hansson } 1970f397c8d8SUlf Hansson return mmc_test_rnd_perf(test, write, 1, sz); 1971f397c8d8SUlf Hansson } 1972f397c8d8SUlf Hansson 1973f397c8d8SUlf Hansson /* 1974f397c8d8SUlf Hansson * Random read performance by transfer size. 1975f397c8d8SUlf Hansson */ 1976f397c8d8SUlf Hansson static int mmc_test_random_read_perf(struct mmc_test_card *test) 1977f397c8d8SUlf Hansson { 1978f397c8d8SUlf Hansson return mmc_test_random_perf(test, 0); 1979f397c8d8SUlf Hansson } 1980f397c8d8SUlf Hansson 1981f397c8d8SUlf Hansson /* 1982f397c8d8SUlf Hansson * Random write performance by transfer size. 1983f397c8d8SUlf Hansson */ 1984f397c8d8SUlf Hansson static int mmc_test_random_write_perf(struct mmc_test_card *test) 1985f397c8d8SUlf Hansson { 1986f397c8d8SUlf Hansson return mmc_test_random_perf(test, 1); 1987f397c8d8SUlf Hansson } 1988f397c8d8SUlf Hansson 1989f397c8d8SUlf Hansson static int mmc_test_seq_perf(struct mmc_test_card *test, int write, 1990f397c8d8SUlf Hansson unsigned int tot_sz, int max_scatter) 1991f397c8d8SUlf Hansson { 1992f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 1993f397c8d8SUlf Hansson unsigned int dev_addr, i, cnt, sz, ssz; 1994f397c8d8SUlf Hansson struct timespec ts1, ts2; 1995f397c8d8SUlf Hansson int ret; 1996f397c8d8SUlf Hansson 1997f397c8d8SUlf Hansson sz = t->max_tfr; 1998f397c8d8SUlf Hansson 1999f397c8d8SUlf Hansson /* 2000f397c8d8SUlf Hansson * In the case of a maximally scattered transfer, the maximum transfer 2001f397c8d8SUlf Hansson * size is further limited by using PAGE_SIZE segments. 2002f397c8d8SUlf Hansson */ 2003f397c8d8SUlf Hansson if (max_scatter) { 2004f397c8d8SUlf Hansson unsigned long max_tfr; 2005f397c8d8SUlf Hansson 2006f397c8d8SUlf Hansson if (t->max_seg_sz >= PAGE_SIZE) 2007f397c8d8SUlf Hansson max_tfr = t->max_segs * PAGE_SIZE; 2008f397c8d8SUlf Hansson else 2009f397c8d8SUlf Hansson max_tfr = t->max_segs * t->max_seg_sz; 2010f397c8d8SUlf Hansson if (sz > max_tfr) 2011f397c8d8SUlf Hansson sz = max_tfr; 2012f397c8d8SUlf Hansson } 2013f397c8d8SUlf Hansson 2014f397c8d8SUlf Hansson ssz = sz >> 9; 2015f397c8d8SUlf Hansson dev_addr = mmc_test_capacity(test->card) / 4; 2016f397c8d8SUlf Hansson if (tot_sz > dev_addr << 9) 2017f397c8d8SUlf Hansson tot_sz = dev_addr << 9; 2018f397c8d8SUlf Hansson cnt = tot_sz / sz; 2019f397c8d8SUlf Hansson dev_addr &= 0xffff0000; /* Round to 64MiB boundary */ 2020f397c8d8SUlf Hansson 2021f397c8d8SUlf Hansson getnstimeofday(&ts1); 2022f397c8d8SUlf Hansson for (i = 0; i < cnt; i++) { 2023f397c8d8SUlf Hansson ret = mmc_test_area_io(test, sz, dev_addr, write, 2024f397c8d8SUlf Hansson max_scatter, 0); 2025f397c8d8SUlf Hansson if (ret) 2026f397c8d8SUlf Hansson return ret; 2027f397c8d8SUlf Hansson dev_addr += ssz; 2028f397c8d8SUlf Hansson } 2029f397c8d8SUlf Hansson getnstimeofday(&ts2); 2030f397c8d8SUlf Hansson 2031f397c8d8SUlf Hansson mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); 2032f397c8d8SUlf Hansson 2033f397c8d8SUlf Hansson return 0; 2034f397c8d8SUlf Hansson } 2035f397c8d8SUlf Hansson 2036f397c8d8SUlf Hansson static int mmc_test_large_seq_perf(struct mmc_test_card *test, int write) 2037f397c8d8SUlf Hansson { 2038f397c8d8SUlf Hansson int ret, i; 2039f397c8d8SUlf Hansson 2040f397c8d8SUlf Hansson for (i = 0; i < 10; i++) { 2041f397c8d8SUlf Hansson ret = mmc_test_seq_perf(test, write, 10 * 1024 * 1024, 1); 2042f397c8d8SUlf Hansson if (ret) 2043f397c8d8SUlf Hansson return ret; 2044f397c8d8SUlf Hansson } 2045f397c8d8SUlf Hansson for (i = 0; i < 5; i++) { 2046f397c8d8SUlf Hansson ret = mmc_test_seq_perf(test, write, 100 * 1024 * 1024, 1); 2047f397c8d8SUlf Hansson if (ret) 2048f397c8d8SUlf Hansson return ret; 2049f397c8d8SUlf Hansson } 2050f397c8d8SUlf Hansson for (i = 0; i < 3; i++) { 2051f397c8d8SUlf Hansson ret = mmc_test_seq_perf(test, write, 1000 * 1024 * 1024, 1); 2052f397c8d8SUlf Hansson if (ret) 2053f397c8d8SUlf Hansson return ret; 2054f397c8d8SUlf Hansson } 2055f397c8d8SUlf Hansson 2056f397c8d8SUlf Hansson return ret; 2057f397c8d8SUlf Hansson } 2058f397c8d8SUlf Hansson 2059f397c8d8SUlf Hansson /* 2060f397c8d8SUlf Hansson * Large sequential read performance. 2061f397c8d8SUlf Hansson */ 2062f397c8d8SUlf Hansson static int mmc_test_large_seq_read_perf(struct mmc_test_card *test) 2063f397c8d8SUlf Hansson { 2064f397c8d8SUlf Hansson return mmc_test_large_seq_perf(test, 0); 2065f397c8d8SUlf Hansson } 2066f397c8d8SUlf Hansson 2067f397c8d8SUlf Hansson /* 2068f397c8d8SUlf Hansson * Large sequential write performance. 2069f397c8d8SUlf Hansson */ 2070f397c8d8SUlf Hansson static int mmc_test_large_seq_write_perf(struct mmc_test_card *test) 2071f397c8d8SUlf Hansson { 2072f397c8d8SUlf Hansson return mmc_test_large_seq_perf(test, 1); 2073f397c8d8SUlf Hansson } 2074f397c8d8SUlf Hansson 2075f397c8d8SUlf Hansson static int mmc_test_rw_multiple(struct mmc_test_card *test, 2076f397c8d8SUlf Hansson struct mmc_test_multiple_rw *tdata, 2077f397c8d8SUlf Hansson unsigned int reqsize, unsigned int size, 2078f397c8d8SUlf Hansson int min_sg_len) 2079f397c8d8SUlf Hansson { 2080f397c8d8SUlf Hansson unsigned int dev_addr; 2081f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 2082f397c8d8SUlf Hansson int ret = 0; 2083f397c8d8SUlf Hansson 2084f397c8d8SUlf Hansson /* Set up test area */ 2085f397c8d8SUlf Hansson if (size > mmc_test_capacity(test->card) / 2 * 512) 2086f397c8d8SUlf Hansson size = mmc_test_capacity(test->card) / 2 * 512; 2087f397c8d8SUlf Hansson if (reqsize > t->max_tfr) 2088f397c8d8SUlf Hansson reqsize = t->max_tfr; 2089f397c8d8SUlf Hansson dev_addr = mmc_test_capacity(test->card) / 4; 2090f397c8d8SUlf Hansson if ((dev_addr & 0xffff0000)) 2091f397c8d8SUlf Hansson dev_addr &= 0xffff0000; /* Round to 64MiB boundary */ 2092f397c8d8SUlf Hansson else 2093f397c8d8SUlf Hansson dev_addr &= 0xfffff800; /* Round to 1MiB boundary */ 2094f397c8d8SUlf Hansson if (!dev_addr) 2095f397c8d8SUlf Hansson goto err; 2096f397c8d8SUlf Hansson 2097f397c8d8SUlf Hansson if (reqsize > size) 2098f397c8d8SUlf Hansson return 0; 2099f397c8d8SUlf Hansson 2100f397c8d8SUlf Hansson /* prepare test area */ 2101f397c8d8SUlf Hansson if (mmc_can_erase(test->card) && 2102f397c8d8SUlf Hansson tdata->prepare & MMC_TEST_PREP_ERASE) { 2103f397c8d8SUlf Hansson ret = mmc_erase(test->card, dev_addr, 2104f397c8d8SUlf Hansson size / 512, MMC_SECURE_ERASE_ARG); 2105f397c8d8SUlf Hansson if (ret) 2106f397c8d8SUlf Hansson ret = mmc_erase(test->card, dev_addr, 2107f397c8d8SUlf Hansson size / 512, MMC_ERASE_ARG); 2108f397c8d8SUlf Hansson if (ret) 2109f397c8d8SUlf Hansson goto err; 2110f397c8d8SUlf Hansson } 2111f397c8d8SUlf Hansson 2112f397c8d8SUlf Hansson /* Run test */ 2113f397c8d8SUlf Hansson ret = mmc_test_area_io_seq(test, reqsize, dev_addr, 2114f397c8d8SUlf Hansson tdata->do_write, 0, 1, size / reqsize, 2115f397c8d8SUlf Hansson tdata->do_nonblock_req, min_sg_len); 2116f397c8d8SUlf Hansson if (ret) 2117f397c8d8SUlf Hansson goto err; 2118f397c8d8SUlf Hansson 2119f397c8d8SUlf Hansson return ret; 2120f397c8d8SUlf Hansson err: 2121f397c8d8SUlf Hansson pr_info("[%s] error\n", __func__); 2122f397c8d8SUlf Hansson return ret; 2123f397c8d8SUlf Hansson } 2124f397c8d8SUlf Hansson 2125f397c8d8SUlf Hansson static int mmc_test_rw_multiple_size(struct mmc_test_card *test, 2126f397c8d8SUlf Hansson struct mmc_test_multiple_rw *rw) 2127f397c8d8SUlf Hansson { 2128f397c8d8SUlf Hansson int ret = 0; 2129f397c8d8SUlf Hansson int i; 2130f397c8d8SUlf Hansson void *pre_req = test->card->host->ops->pre_req; 2131f397c8d8SUlf Hansson void *post_req = test->card->host->ops->post_req; 2132f397c8d8SUlf Hansson 2133f397c8d8SUlf Hansson if (rw->do_nonblock_req && 2134f397c8d8SUlf Hansson ((!pre_req && post_req) || (pre_req && !post_req))) { 2135f397c8d8SUlf Hansson pr_info("error: only one of pre/post is defined\n"); 2136f397c8d8SUlf Hansson return -EINVAL; 2137f397c8d8SUlf Hansson } 2138f397c8d8SUlf Hansson 2139f397c8d8SUlf Hansson for (i = 0 ; i < rw->len && ret == 0; i++) { 2140f397c8d8SUlf Hansson ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size, 0); 2141f397c8d8SUlf Hansson if (ret) 2142f397c8d8SUlf Hansson break; 2143f397c8d8SUlf Hansson } 2144f397c8d8SUlf Hansson return ret; 2145f397c8d8SUlf Hansson } 2146f397c8d8SUlf Hansson 2147f397c8d8SUlf Hansson static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test, 2148f397c8d8SUlf Hansson struct mmc_test_multiple_rw *rw) 2149f397c8d8SUlf Hansson { 2150f397c8d8SUlf Hansson int ret = 0; 2151f397c8d8SUlf Hansson int i; 2152f397c8d8SUlf Hansson 2153f397c8d8SUlf Hansson for (i = 0 ; i < rw->len && ret == 0; i++) { 2154f397c8d8SUlf Hansson ret = mmc_test_rw_multiple(test, rw, 512 * 1024, rw->size, 2155f397c8d8SUlf Hansson rw->sg_len[i]); 2156f397c8d8SUlf Hansson if (ret) 2157f397c8d8SUlf Hansson break; 2158f397c8d8SUlf Hansson } 2159f397c8d8SUlf Hansson return ret; 2160f397c8d8SUlf Hansson } 2161f397c8d8SUlf Hansson 2162f397c8d8SUlf Hansson /* 2163f397c8d8SUlf Hansson * Multiple blocking write 4k to 4 MB chunks 2164f397c8d8SUlf Hansson */ 2165f397c8d8SUlf Hansson static int mmc_test_profile_mult_write_blocking_perf(struct mmc_test_card *test) 2166f397c8d8SUlf Hansson { 2167f397c8d8SUlf Hansson unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16, 2168f397c8d8SUlf Hansson 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22}; 2169f397c8d8SUlf Hansson struct mmc_test_multiple_rw test_data = { 2170f397c8d8SUlf Hansson .bs = bs, 2171f397c8d8SUlf Hansson .size = TEST_AREA_MAX_SIZE, 2172f397c8d8SUlf Hansson .len = ARRAY_SIZE(bs), 2173f397c8d8SUlf Hansson .do_write = true, 2174f397c8d8SUlf Hansson .do_nonblock_req = false, 2175f397c8d8SUlf Hansson .prepare = MMC_TEST_PREP_ERASE, 2176f397c8d8SUlf Hansson }; 2177f397c8d8SUlf Hansson 2178f397c8d8SUlf Hansson return mmc_test_rw_multiple_size(test, &test_data); 2179f397c8d8SUlf Hansson }; 2180f397c8d8SUlf Hansson 2181f397c8d8SUlf Hansson /* 2182f397c8d8SUlf Hansson * Multiple non-blocking write 4k to 4 MB chunks 2183f397c8d8SUlf Hansson */ 2184f397c8d8SUlf Hansson static int mmc_test_profile_mult_write_nonblock_perf(struct mmc_test_card *test) 2185f397c8d8SUlf Hansson { 2186f397c8d8SUlf Hansson unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16, 2187f397c8d8SUlf Hansson 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22}; 2188f397c8d8SUlf Hansson struct mmc_test_multiple_rw test_data = { 2189f397c8d8SUlf Hansson .bs = bs, 2190f397c8d8SUlf Hansson .size = TEST_AREA_MAX_SIZE, 2191f397c8d8SUlf Hansson .len = ARRAY_SIZE(bs), 2192f397c8d8SUlf Hansson .do_write = true, 2193f397c8d8SUlf Hansson .do_nonblock_req = true, 2194f397c8d8SUlf Hansson .prepare = MMC_TEST_PREP_ERASE, 2195f397c8d8SUlf Hansson }; 2196f397c8d8SUlf Hansson 2197f397c8d8SUlf Hansson return mmc_test_rw_multiple_size(test, &test_data); 2198f397c8d8SUlf Hansson } 2199f397c8d8SUlf Hansson 2200f397c8d8SUlf Hansson /* 2201f397c8d8SUlf Hansson * Multiple blocking read 4k to 4 MB chunks 2202f397c8d8SUlf Hansson */ 2203f397c8d8SUlf Hansson static int mmc_test_profile_mult_read_blocking_perf(struct mmc_test_card *test) 2204f397c8d8SUlf Hansson { 2205f397c8d8SUlf Hansson unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16, 2206f397c8d8SUlf Hansson 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22}; 2207f397c8d8SUlf Hansson struct mmc_test_multiple_rw test_data = { 2208f397c8d8SUlf Hansson .bs = bs, 2209f397c8d8SUlf Hansson .size = TEST_AREA_MAX_SIZE, 2210f397c8d8SUlf Hansson .len = ARRAY_SIZE(bs), 2211f397c8d8SUlf Hansson .do_write = false, 2212f397c8d8SUlf Hansson .do_nonblock_req = false, 2213f397c8d8SUlf Hansson .prepare = MMC_TEST_PREP_NONE, 2214f397c8d8SUlf Hansson }; 2215f397c8d8SUlf Hansson 2216f397c8d8SUlf Hansson return mmc_test_rw_multiple_size(test, &test_data); 2217f397c8d8SUlf Hansson } 2218f397c8d8SUlf Hansson 2219f397c8d8SUlf Hansson /* 2220f397c8d8SUlf Hansson * Multiple non-blocking read 4k to 4 MB chunks 2221f397c8d8SUlf Hansson */ 2222f397c8d8SUlf Hansson static int mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card *test) 2223f397c8d8SUlf Hansson { 2224f397c8d8SUlf Hansson unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16, 2225f397c8d8SUlf Hansson 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22}; 2226f397c8d8SUlf Hansson struct mmc_test_multiple_rw test_data = { 2227f397c8d8SUlf Hansson .bs = bs, 2228f397c8d8SUlf Hansson .size = TEST_AREA_MAX_SIZE, 2229f397c8d8SUlf Hansson .len = ARRAY_SIZE(bs), 2230f397c8d8SUlf Hansson .do_write = false, 2231f397c8d8SUlf Hansson .do_nonblock_req = true, 2232f397c8d8SUlf Hansson .prepare = MMC_TEST_PREP_NONE, 2233f397c8d8SUlf Hansson }; 2234f397c8d8SUlf Hansson 2235f397c8d8SUlf Hansson return mmc_test_rw_multiple_size(test, &test_data); 2236f397c8d8SUlf Hansson } 2237f397c8d8SUlf Hansson 2238f397c8d8SUlf Hansson /* 2239f397c8d8SUlf Hansson * Multiple blocking write 1 to 512 sg elements 2240f397c8d8SUlf Hansson */ 2241f397c8d8SUlf Hansson static int mmc_test_profile_sglen_wr_blocking_perf(struct mmc_test_card *test) 2242f397c8d8SUlf Hansson { 2243f397c8d8SUlf Hansson unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 2244f397c8d8SUlf Hansson 1 << 7, 1 << 8, 1 << 9}; 2245f397c8d8SUlf Hansson struct mmc_test_multiple_rw test_data = { 2246f397c8d8SUlf Hansson .sg_len = sg_len, 2247f397c8d8SUlf Hansson .size = TEST_AREA_MAX_SIZE, 2248f397c8d8SUlf Hansson .len = ARRAY_SIZE(sg_len), 2249f397c8d8SUlf Hansson .do_write = true, 2250f397c8d8SUlf Hansson .do_nonblock_req = false, 2251f397c8d8SUlf Hansson .prepare = MMC_TEST_PREP_ERASE, 2252f397c8d8SUlf Hansson }; 2253f397c8d8SUlf Hansson 2254f397c8d8SUlf Hansson return mmc_test_rw_multiple_sg_len(test, &test_data); 2255f397c8d8SUlf Hansson }; 2256f397c8d8SUlf Hansson 2257f397c8d8SUlf Hansson /* 2258f397c8d8SUlf Hansson * Multiple non-blocking write 1 to 512 sg elements 2259f397c8d8SUlf Hansson */ 2260f397c8d8SUlf Hansson static int mmc_test_profile_sglen_wr_nonblock_perf(struct mmc_test_card *test) 2261f397c8d8SUlf Hansson { 2262f397c8d8SUlf Hansson unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 2263f397c8d8SUlf Hansson 1 << 7, 1 << 8, 1 << 9}; 2264f397c8d8SUlf Hansson struct mmc_test_multiple_rw test_data = { 2265f397c8d8SUlf Hansson .sg_len = sg_len, 2266f397c8d8SUlf Hansson .size = TEST_AREA_MAX_SIZE, 2267f397c8d8SUlf Hansson .len = ARRAY_SIZE(sg_len), 2268f397c8d8SUlf Hansson .do_write = true, 2269f397c8d8SUlf Hansson .do_nonblock_req = true, 2270f397c8d8SUlf Hansson .prepare = MMC_TEST_PREP_ERASE, 2271f397c8d8SUlf Hansson }; 2272f397c8d8SUlf Hansson 2273f397c8d8SUlf Hansson return mmc_test_rw_multiple_sg_len(test, &test_data); 2274f397c8d8SUlf Hansson } 2275f397c8d8SUlf Hansson 2276f397c8d8SUlf Hansson /* 2277f397c8d8SUlf Hansson * Multiple blocking read 1 to 512 sg elements 2278f397c8d8SUlf Hansson */ 2279f397c8d8SUlf Hansson static int mmc_test_profile_sglen_r_blocking_perf(struct mmc_test_card *test) 2280f397c8d8SUlf Hansson { 2281f397c8d8SUlf Hansson unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 2282f397c8d8SUlf Hansson 1 << 7, 1 << 8, 1 << 9}; 2283f397c8d8SUlf Hansson struct mmc_test_multiple_rw test_data = { 2284f397c8d8SUlf Hansson .sg_len = sg_len, 2285f397c8d8SUlf Hansson .size = TEST_AREA_MAX_SIZE, 2286f397c8d8SUlf Hansson .len = ARRAY_SIZE(sg_len), 2287f397c8d8SUlf Hansson .do_write = false, 2288f397c8d8SUlf Hansson .do_nonblock_req = false, 2289f397c8d8SUlf Hansson .prepare = MMC_TEST_PREP_NONE, 2290f397c8d8SUlf Hansson }; 2291f397c8d8SUlf Hansson 2292f397c8d8SUlf Hansson return mmc_test_rw_multiple_sg_len(test, &test_data); 2293f397c8d8SUlf Hansson } 2294f397c8d8SUlf Hansson 2295f397c8d8SUlf Hansson /* 2296f397c8d8SUlf Hansson * Multiple non-blocking read 1 to 512 sg elements 2297f397c8d8SUlf Hansson */ 2298f397c8d8SUlf Hansson static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test) 2299f397c8d8SUlf Hansson { 2300f397c8d8SUlf Hansson unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 2301f397c8d8SUlf Hansson 1 << 7, 1 << 8, 1 << 9}; 2302f397c8d8SUlf Hansson struct mmc_test_multiple_rw test_data = { 2303f397c8d8SUlf Hansson .sg_len = sg_len, 2304f397c8d8SUlf Hansson .size = TEST_AREA_MAX_SIZE, 2305f397c8d8SUlf Hansson .len = ARRAY_SIZE(sg_len), 2306f397c8d8SUlf Hansson .do_write = false, 2307f397c8d8SUlf Hansson .do_nonblock_req = true, 2308f397c8d8SUlf Hansson .prepare = MMC_TEST_PREP_NONE, 2309f397c8d8SUlf Hansson }; 2310f397c8d8SUlf Hansson 2311f397c8d8SUlf Hansson return mmc_test_rw_multiple_sg_len(test, &test_data); 2312f397c8d8SUlf Hansson } 2313f397c8d8SUlf Hansson 2314f397c8d8SUlf Hansson /* 2315f397c8d8SUlf Hansson * eMMC hardware reset. 2316f397c8d8SUlf Hansson */ 2317f397c8d8SUlf Hansson static int mmc_test_reset(struct mmc_test_card *test) 2318f397c8d8SUlf Hansson { 2319f397c8d8SUlf Hansson struct mmc_card *card = test->card; 2320f397c8d8SUlf Hansson struct mmc_host *host = card->host; 2321f397c8d8SUlf Hansson int err; 2322f397c8d8SUlf Hansson 2323f397c8d8SUlf Hansson err = mmc_hw_reset(host); 2324f397c8d8SUlf Hansson if (!err) 2325f397c8d8SUlf Hansson return RESULT_OK; 2326f397c8d8SUlf Hansson else if (err == -EOPNOTSUPP) 2327f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 2328f397c8d8SUlf Hansson 2329f397c8d8SUlf Hansson return RESULT_FAIL; 2330f397c8d8SUlf Hansson } 2331f397c8d8SUlf Hansson 2332f397c8d8SUlf Hansson struct mmc_test_req { 2333f397c8d8SUlf Hansson struct mmc_request mrq; 2334f397c8d8SUlf Hansson struct mmc_command sbc; 2335f397c8d8SUlf Hansson struct mmc_command cmd; 2336f397c8d8SUlf Hansson struct mmc_command stop; 2337f397c8d8SUlf Hansson struct mmc_command status; 2338f397c8d8SUlf Hansson struct mmc_data data; 2339f397c8d8SUlf Hansson }; 2340f397c8d8SUlf Hansson 2341f397c8d8SUlf Hansson static struct mmc_test_req *mmc_test_req_alloc(void) 2342f397c8d8SUlf Hansson { 2343f397c8d8SUlf Hansson struct mmc_test_req *rq = kzalloc(sizeof(*rq), GFP_KERNEL); 2344f397c8d8SUlf Hansson 2345f397c8d8SUlf Hansson if (rq) { 2346f397c8d8SUlf Hansson rq->mrq.cmd = &rq->cmd; 2347f397c8d8SUlf Hansson rq->mrq.data = &rq->data; 2348f397c8d8SUlf Hansson rq->mrq.stop = &rq->stop; 2349f397c8d8SUlf Hansson } 2350f397c8d8SUlf Hansson 2351f397c8d8SUlf Hansson return rq; 2352f397c8d8SUlf Hansson } 2353f397c8d8SUlf Hansson 2354f397c8d8SUlf Hansson static int mmc_test_send_status(struct mmc_test_card *test, 2355f397c8d8SUlf Hansson struct mmc_command *cmd) 2356f397c8d8SUlf Hansson { 2357f397c8d8SUlf Hansson memset(cmd, 0, sizeof(*cmd)); 2358f397c8d8SUlf Hansson 2359f397c8d8SUlf Hansson cmd->opcode = MMC_SEND_STATUS; 2360f397c8d8SUlf Hansson if (!mmc_host_is_spi(test->card->host)) 2361f397c8d8SUlf Hansson cmd->arg = test->card->rca << 16; 2362f397c8d8SUlf Hansson cmd->flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; 2363f397c8d8SUlf Hansson 2364f397c8d8SUlf Hansson return mmc_wait_for_cmd(test->card->host, cmd, 0); 2365f397c8d8SUlf Hansson } 2366f397c8d8SUlf Hansson 2367f397c8d8SUlf Hansson static int mmc_test_ongoing_transfer(struct mmc_test_card *test, 2368f397c8d8SUlf Hansson unsigned int dev_addr, int use_sbc, 2369f397c8d8SUlf Hansson int repeat_cmd, int write, int use_areq) 2370f397c8d8SUlf Hansson { 2371f397c8d8SUlf Hansson struct mmc_test_req *rq = mmc_test_req_alloc(); 2372f397c8d8SUlf Hansson struct mmc_host *host = test->card->host; 2373f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 2374f397c8d8SUlf Hansson struct mmc_test_async_req test_areq = { .test = test }; 2375f397c8d8SUlf Hansson struct mmc_request *mrq; 2376f397c8d8SUlf Hansson unsigned long timeout; 2377f397c8d8SUlf Hansson bool expired = false; 2378f397c8d8SUlf Hansson enum mmc_blk_status blkstat = MMC_BLK_SUCCESS; 2379f397c8d8SUlf Hansson int ret = 0, cmd_ret; 2380f397c8d8SUlf Hansson u32 status = 0; 2381f397c8d8SUlf Hansson int count = 0; 2382f397c8d8SUlf Hansson 2383f397c8d8SUlf Hansson if (!rq) 2384f397c8d8SUlf Hansson return -ENOMEM; 2385f397c8d8SUlf Hansson 2386f397c8d8SUlf Hansson mrq = &rq->mrq; 2387f397c8d8SUlf Hansson if (use_sbc) 2388f397c8d8SUlf Hansson mrq->sbc = &rq->sbc; 2389f397c8d8SUlf Hansson mrq->cap_cmd_during_tfr = true; 2390f397c8d8SUlf Hansson 2391f397c8d8SUlf Hansson test_areq.areq.mrq = mrq; 2392f397c8d8SUlf Hansson test_areq.areq.err_check = mmc_test_check_result_async; 2393f397c8d8SUlf Hansson 2394f397c8d8SUlf Hansson mmc_test_prepare_mrq(test, mrq, t->sg, t->sg_len, dev_addr, t->blocks, 2395f397c8d8SUlf Hansson 512, write); 2396f397c8d8SUlf Hansson 2397f397c8d8SUlf Hansson if (use_sbc && t->blocks > 1 && !mrq->sbc) { 2398f397c8d8SUlf Hansson ret = mmc_host_cmd23(host) ? 2399f397c8d8SUlf Hansson RESULT_UNSUP_CARD : 2400f397c8d8SUlf Hansson RESULT_UNSUP_HOST; 2401f397c8d8SUlf Hansson goto out_free; 2402f397c8d8SUlf Hansson } 2403f397c8d8SUlf Hansson 2404f397c8d8SUlf Hansson /* Start ongoing data request */ 2405f397c8d8SUlf Hansson if (use_areq) { 2406c3399ef5SLinus Walleij mmc_start_areq(host, &test_areq.areq, &blkstat); 2407f397c8d8SUlf Hansson if (blkstat != MMC_BLK_SUCCESS) { 2408f397c8d8SUlf Hansson ret = RESULT_FAIL; 2409f397c8d8SUlf Hansson goto out_free; 2410f397c8d8SUlf Hansson } 2411f397c8d8SUlf Hansson } else { 2412f397c8d8SUlf Hansson mmc_wait_for_req(host, mrq); 2413f397c8d8SUlf Hansson } 2414f397c8d8SUlf Hansson 2415f397c8d8SUlf Hansson timeout = jiffies + msecs_to_jiffies(3000); 2416f397c8d8SUlf Hansson do { 2417f397c8d8SUlf Hansson count += 1; 2418f397c8d8SUlf Hansson 2419f397c8d8SUlf Hansson /* Send status command while data transfer in progress */ 2420f397c8d8SUlf Hansson cmd_ret = mmc_test_send_status(test, &rq->status); 2421f397c8d8SUlf Hansson if (cmd_ret) 2422f397c8d8SUlf Hansson break; 2423f397c8d8SUlf Hansson 2424f397c8d8SUlf Hansson status = rq->status.resp[0]; 2425f397c8d8SUlf Hansson if (status & R1_ERROR) { 2426f397c8d8SUlf Hansson cmd_ret = -EIO; 2427f397c8d8SUlf Hansson break; 2428f397c8d8SUlf Hansson } 2429f397c8d8SUlf Hansson 2430f397c8d8SUlf Hansson if (mmc_is_req_done(host, mrq)) 2431f397c8d8SUlf Hansson break; 2432f397c8d8SUlf Hansson 2433f397c8d8SUlf Hansson expired = time_after(jiffies, timeout); 2434f397c8d8SUlf Hansson if (expired) { 2435f397c8d8SUlf Hansson pr_info("%s: timeout waiting for Tran state status %#x\n", 2436f397c8d8SUlf Hansson mmc_hostname(host), status); 2437f397c8d8SUlf Hansson cmd_ret = -ETIMEDOUT; 2438f397c8d8SUlf Hansson break; 2439f397c8d8SUlf Hansson } 2440f397c8d8SUlf Hansson } while (repeat_cmd && R1_CURRENT_STATE(status) != R1_STATE_TRAN); 2441f397c8d8SUlf Hansson 2442f397c8d8SUlf Hansson /* Wait for data request to complete */ 2443f397c8d8SUlf Hansson if (use_areq) { 2444c3399ef5SLinus Walleij mmc_start_areq(host, NULL, &blkstat); 2445f397c8d8SUlf Hansson if (blkstat != MMC_BLK_SUCCESS) 2446f397c8d8SUlf Hansson ret = RESULT_FAIL; 2447f397c8d8SUlf Hansson } else { 2448f397c8d8SUlf Hansson mmc_wait_for_req_done(test->card->host, mrq); 2449f397c8d8SUlf Hansson } 2450f397c8d8SUlf Hansson 2451f397c8d8SUlf Hansson /* 2452f397c8d8SUlf Hansson * For cap_cmd_during_tfr request, upper layer must send stop if 2453f397c8d8SUlf Hansson * required. 2454f397c8d8SUlf Hansson */ 2455f397c8d8SUlf Hansson if (mrq->data->stop && (mrq->data->error || !mrq->sbc)) { 2456f397c8d8SUlf Hansson if (ret) 2457f397c8d8SUlf Hansson mmc_wait_for_cmd(host, mrq->data->stop, 0); 2458f397c8d8SUlf Hansson else 2459f397c8d8SUlf Hansson ret = mmc_wait_for_cmd(host, mrq->data->stop, 0); 2460f397c8d8SUlf Hansson } 2461f397c8d8SUlf Hansson 2462f397c8d8SUlf Hansson if (ret) 2463f397c8d8SUlf Hansson goto out_free; 2464f397c8d8SUlf Hansson 2465f397c8d8SUlf Hansson if (cmd_ret) { 2466f397c8d8SUlf Hansson pr_info("%s: Send Status failed: status %#x, error %d\n", 2467f397c8d8SUlf Hansson mmc_hostname(test->card->host), status, cmd_ret); 2468f397c8d8SUlf Hansson } 2469f397c8d8SUlf Hansson 2470f397c8d8SUlf Hansson ret = mmc_test_check_result(test, mrq); 2471f397c8d8SUlf Hansson if (ret) 2472f397c8d8SUlf Hansson goto out_free; 2473f397c8d8SUlf Hansson 2474f397c8d8SUlf Hansson ret = mmc_test_wait_busy(test); 2475f397c8d8SUlf Hansson if (ret) 2476f397c8d8SUlf Hansson goto out_free; 2477f397c8d8SUlf Hansson 2478f397c8d8SUlf Hansson if (repeat_cmd && (t->blocks + 1) << 9 > t->max_tfr) 2479f397c8d8SUlf Hansson pr_info("%s: %d commands completed during transfer of %u blocks\n", 2480f397c8d8SUlf Hansson mmc_hostname(test->card->host), count, t->blocks); 2481f397c8d8SUlf Hansson 2482f397c8d8SUlf Hansson if (cmd_ret) 2483f397c8d8SUlf Hansson ret = cmd_ret; 2484f397c8d8SUlf Hansson out_free: 2485f397c8d8SUlf Hansson kfree(rq); 2486f397c8d8SUlf Hansson 2487f397c8d8SUlf Hansson return ret; 2488f397c8d8SUlf Hansson } 2489f397c8d8SUlf Hansson 2490f397c8d8SUlf Hansson static int __mmc_test_cmds_during_tfr(struct mmc_test_card *test, 2491f397c8d8SUlf Hansson unsigned long sz, int use_sbc, int write, 2492f397c8d8SUlf Hansson int use_areq) 2493f397c8d8SUlf Hansson { 2494f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 2495f397c8d8SUlf Hansson int ret; 2496f397c8d8SUlf Hansson 2497f397c8d8SUlf Hansson if (!(test->card->host->caps & MMC_CAP_CMD_DURING_TFR)) 2498f397c8d8SUlf Hansson return RESULT_UNSUP_HOST; 2499f397c8d8SUlf Hansson 2500f397c8d8SUlf Hansson ret = mmc_test_area_map(test, sz, 0, 0); 2501f397c8d8SUlf Hansson if (ret) 2502f397c8d8SUlf Hansson return ret; 2503f397c8d8SUlf Hansson 2504f397c8d8SUlf Hansson ret = mmc_test_ongoing_transfer(test, t->dev_addr, use_sbc, 0, write, 2505f397c8d8SUlf Hansson use_areq); 2506f397c8d8SUlf Hansson if (ret) 2507f397c8d8SUlf Hansson return ret; 2508f397c8d8SUlf Hansson 2509f397c8d8SUlf Hansson return mmc_test_ongoing_transfer(test, t->dev_addr, use_sbc, 1, write, 2510f397c8d8SUlf Hansson use_areq); 2511f397c8d8SUlf Hansson } 2512f397c8d8SUlf Hansson 2513f397c8d8SUlf Hansson static int mmc_test_cmds_during_tfr(struct mmc_test_card *test, int use_sbc, 2514f397c8d8SUlf Hansson int write, int use_areq) 2515f397c8d8SUlf Hansson { 2516f397c8d8SUlf Hansson struct mmc_test_area *t = &test->area; 2517f397c8d8SUlf Hansson unsigned long sz; 2518f397c8d8SUlf Hansson int ret; 2519f397c8d8SUlf Hansson 2520f397c8d8SUlf Hansson for (sz = 512; sz <= t->max_tfr; sz += 512) { 2521f397c8d8SUlf Hansson ret = __mmc_test_cmds_during_tfr(test, sz, use_sbc, write, 2522f397c8d8SUlf Hansson use_areq); 2523f397c8d8SUlf Hansson if (ret) 2524f397c8d8SUlf Hansson return ret; 2525f397c8d8SUlf Hansson } 2526f397c8d8SUlf Hansson return 0; 2527f397c8d8SUlf Hansson } 2528f397c8d8SUlf Hansson 2529f397c8d8SUlf Hansson /* 2530f397c8d8SUlf Hansson * Commands during read - no Set Block Count (CMD23). 2531f397c8d8SUlf Hansson */ 2532f397c8d8SUlf Hansson static int mmc_test_cmds_during_read(struct mmc_test_card *test) 2533f397c8d8SUlf Hansson { 2534f397c8d8SUlf Hansson return mmc_test_cmds_during_tfr(test, 0, 0, 0); 2535f397c8d8SUlf Hansson } 2536f397c8d8SUlf Hansson 2537f397c8d8SUlf Hansson /* 2538f397c8d8SUlf Hansson * Commands during write - no Set Block Count (CMD23). 2539f397c8d8SUlf Hansson */ 2540f397c8d8SUlf Hansson static int mmc_test_cmds_during_write(struct mmc_test_card *test) 2541f397c8d8SUlf Hansson { 2542f397c8d8SUlf Hansson return mmc_test_cmds_during_tfr(test, 0, 1, 0); 2543f397c8d8SUlf Hansson } 2544f397c8d8SUlf Hansson 2545f397c8d8SUlf Hansson /* 2546f397c8d8SUlf Hansson * Commands during read - use Set Block Count (CMD23). 2547f397c8d8SUlf Hansson */ 2548f397c8d8SUlf Hansson static int mmc_test_cmds_during_read_cmd23(struct mmc_test_card *test) 2549f397c8d8SUlf Hansson { 2550f397c8d8SUlf Hansson return mmc_test_cmds_during_tfr(test, 1, 0, 0); 2551f397c8d8SUlf Hansson } 2552f397c8d8SUlf Hansson 2553f397c8d8SUlf Hansson /* 2554f397c8d8SUlf Hansson * Commands during write - use Set Block Count (CMD23). 2555f397c8d8SUlf Hansson */ 2556f397c8d8SUlf Hansson static int mmc_test_cmds_during_write_cmd23(struct mmc_test_card *test) 2557f397c8d8SUlf Hansson { 2558f397c8d8SUlf Hansson return mmc_test_cmds_during_tfr(test, 1, 1, 0); 2559f397c8d8SUlf Hansson } 2560f397c8d8SUlf Hansson 2561f397c8d8SUlf Hansson /* 2562f397c8d8SUlf Hansson * Commands during non-blocking read - use Set Block Count (CMD23). 2563f397c8d8SUlf Hansson */ 2564f397c8d8SUlf Hansson static int mmc_test_cmds_during_read_cmd23_nonblock(struct mmc_test_card *test) 2565f397c8d8SUlf Hansson { 2566f397c8d8SUlf Hansson return mmc_test_cmds_during_tfr(test, 1, 0, 1); 2567f397c8d8SUlf Hansson } 2568f397c8d8SUlf Hansson 2569f397c8d8SUlf Hansson /* 2570f397c8d8SUlf Hansson * Commands during non-blocking write - use Set Block Count (CMD23). 2571f397c8d8SUlf Hansson */ 2572f397c8d8SUlf Hansson static int mmc_test_cmds_during_write_cmd23_nonblock(struct mmc_test_card *test) 2573f397c8d8SUlf Hansson { 2574f397c8d8SUlf Hansson return mmc_test_cmds_during_tfr(test, 1, 1, 1); 2575f397c8d8SUlf Hansson } 2576f397c8d8SUlf Hansson 2577f397c8d8SUlf Hansson static const struct mmc_test_case mmc_test_cases[] = { 2578f397c8d8SUlf Hansson { 2579f397c8d8SUlf Hansson .name = "Basic write (no data verification)", 2580f397c8d8SUlf Hansson .run = mmc_test_basic_write, 2581f397c8d8SUlf Hansson }, 2582f397c8d8SUlf Hansson 2583f397c8d8SUlf Hansson { 2584f397c8d8SUlf Hansson .name = "Basic read (no data verification)", 2585f397c8d8SUlf Hansson .run = mmc_test_basic_read, 2586f397c8d8SUlf Hansson }, 2587f397c8d8SUlf Hansson 2588f397c8d8SUlf Hansson { 2589f397c8d8SUlf Hansson .name = "Basic write (with data verification)", 2590f397c8d8SUlf Hansson .prepare = mmc_test_prepare_write, 2591f397c8d8SUlf Hansson .run = mmc_test_verify_write, 2592f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2593f397c8d8SUlf Hansson }, 2594f397c8d8SUlf Hansson 2595f397c8d8SUlf Hansson { 2596f397c8d8SUlf Hansson .name = "Basic read (with data verification)", 2597f397c8d8SUlf Hansson .prepare = mmc_test_prepare_read, 2598f397c8d8SUlf Hansson .run = mmc_test_verify_read, 2599f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2600f397c8d8SUlf Hansson }, 2601f397c8d8SUlf Hansson 2602f397c8d8SUlf Hansson { 2603f397c8d8SUlf Hansson .name = "Multi-block write", 2604f397c8d8SUlf Hansson .prepare = mmc_test_prepare_write, 2605f397c8d8SUlf Hansson .run = mmc_test_multi_write, 2606f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2607f397c8d8SUlf Hansson }, 2608f397c8d8SUlf Hansson 2609f397c8d8SUlf Hansson { 2610f397c8d8SUlf Hansson .name = "Multi-block read", 2611f397c8d8SUlf Hansson .prepare = mmc_test_prepare_read, 2612f397c8d8SUlf Hansson .run = mmc_test_multi_read, 2613f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2614f397c8d8SUlf Hansson }, 2615f397c8d8SUlf Hansson 2616f397c8d8SUlf Hansson { 2617f397c8d8SUlf Hansson .name = "Power of two block writes", 2618f397c8d8SUlf Hansson .prepare = mmc_test_prepare_write, 2619f397c8d8SUlf Hansson .run = mmc_test_pow2_write, 2620f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2621f397c8d8SUlf Hansson }, 2622f397c8d8SUlf Hansson 2623f397c8d8SUlf Hansson { 2624f397c8d8SUlf Hansson .name = "Power of two block reads", 2625f397c8d8SUlf Hansson .prepare = mmc_test_prepare_read, 2626f397c8d8SUlf Hansson .run = mmc_test_pow2_read, 2627f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2628f397c8d8SUlf Hansson }, 2629f397c8d8SUlf Hansson 2630f397c8d8SUlf Hansson { 2631f397c8d8SUlf Hansson .name = "Weird sized block writes", 2632f397c8d8SUlf Hansson .prepare = mmc_test_prepare_write, 2633f397c8d8SUlf Hansson .run = mmc_test_weird_write, 2634f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2635f397c8d8SUlf Hansson }, 2636f397c8d8SUlf Hansson 2637f397c8d8SUlf Hansson { 2638f397c8d8SUlf Hansson .name = "Weird sized block reads", 2639f397c8d8SUlf Hansson .prepare = mmc_test_prepare_read, 2640f397c8d8SUlf Hansson .run = mmc_test_weird_read, 2641f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2642f397c8d8SUlf Hansson }, 2643f397c8d8SUlf Hansson 2644f397c8d8SUlf Hansson { 2645f397c8d8SUlf Hansson .name = "Badly aligned write", 2646f397c8d8SUlf Hansson .prepare = mmc_test_prepare_write, 2647f397c8d8SUlf Hansson .run = mmc_test_align_write, 2648f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2649f397c8d8SUlf Hansson }, 2650f397c8d8SUlf Hansson 2651f397c8d8SUlf Hansson { 2652f397c8d8SUlf Hansson .name = "Badly aligned read", 2653f397c8d8SUlf Hansson .prepare = mmc_test_prepare_read, 2654f397c8d8SUlf Hansson .run = mmc_test_align_read, 2655f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2656f397c8d8SUlf Hansson }, 2657f397c8d8SUlf Hansson 2658f397c8d8SUlf Hansson { 2659f397c8d8SUlf Hansson .name = "Badly aligned multi-block write", 2660f397c8d8SUlf Hansson .prepare = mmc_test_prepare_write, 2661f397c8d8SUlf Hansson .run = mmc_test_align_multi_write, 2662f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2663f397c8d8SUlf Hansson }, 2664f397c8d8SUlf Hansson 2665f397c8d8SUlf Hansson { 2666f397c8d8SUlf Hansson .name = "Badly aligned multi-block read", 2667f397c8d8SUlf Hansson .prepare = mmc_test_prepare_read, 2668f397c8d8SUlf Hansson .run = mmc_test_align_multi_read, 2669f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2670f397c8d8SUlf Hansson }, 2671f397c8d8SUlf Hansson 2672f397c8d8SUlf Hansson { 2673f397c8d8SUlf Hansson .name = "Correct xfer_size at write (start failure)", 2674f397c8d8SUlf Hansson .run = mmc_test_xfersize_write, 2675f397c8d8SUlf Hansson }, 2676f397c8d8SUlf Hansson 2677f397c8d8SUlf Hansson { 2678f397c8d8SUlf Hansson .name = "Correct xfer_size at read (start failure)", 2679f397c8d8SUlf Hansson .run = mmc_test_xfersize_read, 2680f397c8d8SUlf Hansson }, 2681f397c8d8SUlf Hansson 2682f397c8d8SUlf Hansson { 2683f397c8d8SUlf Hansson .name = "Correct xfer_size at write (midway failure)", 2684f397c8d8SUlf Hansson .run = mmc_test_multi_xfersize_write, 2685f397c8d8SUlf Hansson }, 2686f397c8d8SUlf Hansson 2687f397c8d8SUlf Hansson { 2688f397c8d8SUlf Hansson .name = "Correct xfer_size at read (midway failure)", 2689f397c8d8SUlf Hansson .run = mmc_test_multi_xfersize_read, 2690f397c8d8SUlf Hansson }, 2691f397c8d8SUlf Hansson 2692f397c8d8SUlf Hansson #ifdef CONFIG_HIGHMEM 2693f397c8d8SUlf Hansson 2694f397c8d8SUlf Hansson { 2695f397c8d8SUlf Hansson .name = "Highmem write", 2696f397c8d8SUlf Hansson .prepare = mmc_test_prepare_write, 2697f397c8d8SUlf Hansson .run = mmc_test_write_high, 2698f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2699f397c8d8SUlf Hansson }, 2700f397c8d8SUlf Hansson 2701f397c8d8SUlf Hansson { 2702f397c8d8SUlf Hansson .name = "Highmem read", 2703f397c8d8SUlf Hansson .prepare = mmc_test_prepare_read, 2704f397c8d8SUlf Hansson .run = mmc_test_read_high, 2705f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2706f397c8d8SUlf Hansson }, 2707f397c8d8SUlf Hansson 2708f397c8d8SUlf Hansson { 2709f397c8d8SUlf Hansson .name = "Multi-block highmem write", 2710f397c8d8SUlf Hansson .prepare = mmc_test_prepare_write, 2711f397c8d8SUlf Hansson .run = mmc_test_multi_write_high, 2712f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2713f397c8d8SUlf Hansson }, 2714f397c8d8SUlf Hansson 2715f397c8d8SUlf Hansson { 2716f397c8d8SUlf Hansson .name = "Multi-block highmem read", 2717f397c8d8SUlf Hansson .prepare = mmc_test_prepare_read, 2718f397c8d8SUlf Hansson .run = mmc_test_multi_read_high, 2719f397c8d8SUlf Hansson .cleanup = mmc_test_cleanup, 2720f397c8d8SUlf Hansson }, 2721f397c8d8SUlf Hansson 2722f397c8d8SUlf Hansson #else 2723f397c8d8SUlf Hansson 2724f397c8d8SUlf Hansson { 2725f397c8d8SUlf Hansson .name = "Highmem write", 2726f397c8d8SUlf Hansson .run = mmc_test_no_highmem, 2727f397c8d8SUlf Hansson }, 2728f397c8d8SUlf Hansson 2729f397c8d8SUlf Hansson { 2730f397c8d8SUlf Hansson .name = "Highmem read", 2731f397c8d8SUlf Hansson .run = mmc_test_no_highmem, 2732f397c8d8SUlf Hansson }, 2733f397c8d8SUlf Hansson 2734f397c8d8SUlf Hansson { 2735f397c8d8SUlf Hansson .name = "Multi-block highmem write", 2736f397c8d8SUlf Hansson .run = mmc_test_no_highmem, 2737f397c8d8SUlf Hansson }, 2738f397c8d8SUlf Hansson 2739f397c8d8SUlf Hansson { 2740f397c8d8SUlf Hansson .name = "Multi-block highmem read", 2741f397c8d8SUlf Hansson .run = mmc_test_no_highmem, 2742f397c8d8SUlf Hansson }, 2743f397c8d8SUlf Hansson 2744f397c8d8SUlf Hansson #endif /* CONFIG_HIGHMEM */ 2745f397c8d8SUlf Hansson 2746f397c8d8SUlf Hansson { 2747f397c8d8SUlf Hansson .name = "Best-case read performance", 2748f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare_fill, 2749f397c8d8SUlf Hansson .run = mmc_test_best_read_performance, 2750f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2751f397c8d8SUlf Hansson }, 2752f397c8d8SUlf Hansson 2753f397c8d8SUlf Hansson { 2754f397c8d8SUlf Hansson .name = "Best-case write performance", 2755f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare_erase, 2756f397c8d8SUlf Hansson .run = mmc_test_best_write_performance, 2757f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2758f397c8d8SUlf Hansson }, 2759f397c8d8SUlf Hansson 2760f397c8d8SUlf Hansson { 2761f397c8d8SUlf Hansson .name = "Best-case read performance into scattered pages", 2762f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare_fill, 2763f397c8d8SUlf Hansson .run = mmc_test_best_read_perf_max_scatter, 2764f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2765f397c8d8SUlf Hansson }, 2766f397c8d8SUlf Hansson 2767f397c8d8SUlf Hansson { 2768f397c8d8SUlf Hansson .name = "Best-case write performance from scattered pages", 2769f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare_erase, 2770f397c8d8SUlf Hansson .run = mmc_test_best_write_perf_max_scatter, 2771f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2772f397c8d8SUlf Hansson }, 2773f397c8d8SUlf Hansson 2774f397c8d8SUlf Hansson { 2775f397c8d8SUlf Hansson .name = "Single read performance by transfer size", 2776f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare_fill, 2777f397c8d8SUlf Hansson .run = mmc_test_profile_read_perf, 2778f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2779f397c8d8SUlf Hansson }, 2780f397c8d8SUlf Hansson 2781f397c8d8SUlf Hansson { 2782f397c8d8SUlf Hansson .name = "Single write performance by transfer size", 2783f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2784f397c8d8SUlf Hansson .run = mmc_test_profile_write_perf, 2785f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2786f397c8d8SUlf Hansson }, 2787f397c8d8SUlf Hansson 2788f397c8d8SUlf Hansson { 2789f397c8d8SUlf Hansson .name = "Single trim performance by transfer size", 2790f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare_fill, 2791f397c8d8SUlf Hansson .run = mmc_test_profile_trim_perf, 2792f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2793f397c8d8SUlf Hansson }, 2794f397c8d8SUlf Hansson 2795f397c8d8SUlf Hansson { 2796f397c8d8SUlf Hansson .name = "Consecutive read performance by transfer size", 2797f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare_fill, 2798f397c8d8SUlf Hansson .run = mmc_test_profile_seq_read_perf, 2799f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2800f397c8d8SUlf Hansson }, 2801f397c8d8SUlf Hansson 2802f397c8d8SUlf Hansson { 2803f397c8d8SUlf Hansson .name = "Consecutive write performance by transfer size", 2804f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2805f397c8d8SUlf Hansson .run = mmc_test_profile_seq_write_perf, 2806f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2807f397c8d8SUlf Hansson }, 2808f397c8d8SUlf Hansson 2809f397c8d8SUlf Hansson { 2810f397c8d8SUlf Hansson .name = "Consecutive trim performance by transfer size", 2811f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2812f397c8d8SUlf Hansson .run = mmc_test_profile_seq_trim_perf, 2813f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2814f397c8d8SUlf Hansson }, 2815f397c8d8SUlf Hansson 2816f397c8d8SUlf Hansson { 2817f397c8d8SUlf Hansson .name = "Random read performance by transfer size", 2818f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2819f397c8d8SUlf Hansson .run = mmc_test_random_read_perf, 2820f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2821f397c8d8SUlf Hansson }, 2822f397c8d8SUlf Hansson 2823f397c8d8SUlf Hansson { 2824f397c8d8SUlf Hansson .name = "Random write performance by transfer size", 2825f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2826f397c8d8SUlf Hansson .run = mmc_test_random_write_perf, 2827f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2828f397c8d8SUlf Hansson }, 2829f397c8d8SUlf Hansson 2830f397c8d8SUlf Hansson { 2831f397c8d8SUlf Hansson .name = "Large sequential read into scattered pages", 2832f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2833f397c8d8SUlf Hansson .run = mmc_test_large_seq_read_perf, 2834f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2835f397c8d8SUlf Hansson }, 2836f397c8d8SUlf Hansson 2837f397c8d8SUlf Hansson { 2838f397c8d8SUlf Hansson .name = "Large sequential write from scattered pages", 2839f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2840f397c8d8SUlf Hansson .run = mmc_test_large_seq_write_perf, 2841f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2842f397c8d8SUlf Hansson }, 2843f397c8d8SUlf Hansson 2844f397c8d8SUlf Hansson { 2845f397c8d8SUlf Hansson .name = "Write performance with blocking req 4k to 4MB", 2846f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2847f397c8d8SUlf Hansson .run = mmc_test_profile_mult_write_blocking_perf, 2848f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2849f397c8d8SUlf Hansson }, 2850f397c8d8SUlf Hansson 2851f397c8d8SUlf Hansson { 2852f397c8d8SUlf Hansson .name = "Write performance with non-blocking req 4k to 4MB", 2853f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2854f397c8d8SUlf Hansson .run = mmc_test_profile_mult_write_nonblock_perf, 2855f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2856f397c8d8SUlf Hansson }, 2857f397c8d8SUlf Hansson 2858f397c8d8SUlf Hansson { 2859f397c8d8SUlf Hansson .name = "Read performance with blocking req 4k to 4MB", 2860f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2861f397c8d8SUlf Hansson .run = mmc_test_profile_mult_read_blocking_perf, 2862f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2863f397c8d8SUlf Hansson }, 2864f397c8d8SUlf Hansson 2865f397c8d8SUlf Hansson { 2866f397c8d8SUlf Hansson .name = "Read performance with non-blocking req 4k to 4MB", 2867f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2868f397c8d8SUlf Hansson .run = mmc_test_profile_mult_read_nonblock_perf, 2869f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2870f397c8d8SUlf Hansson }, 2871f397c8d8SUlf Hansson 2872f397c8d8SUlf Hansson { 2873f397c8d8SUlf Hansson .name = "Write performance blocking req 1 to 512 sg elems", 2874f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2875f397c8d8SUlf Hansson .run = mmc_test_profile_sglen_wr_blocking_perf, 2876f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2877f397c8d8SUlf Hansson }, 2878f397c8d8SUlf Hansson 2879f397c8d8SUlf Hansson { 2880f397c8d8SUlf Hansson .name = "Write performance non-blocking req 1 to 512 sg elems", 2881f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2882f397c8d8SUlf Hansson .run = mmc_test_profile_sglen_wr_nonblock_perf, 2883f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2884f397c8d8SUlf Hansson }, 2885f397c8d8SUlf Hansson 2886f397c8d8SUlf Hansson { 2887f397c8d8SUlf Hansson .name = "Read performance blocking req 1 to 512 sg elems", 2888f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2889f397c8d8SUlf Hansson .run = mmc_test_profile_sglen_r_blocking_perf, 2890f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2891f397c8d8SUlf Hansson }, 2892f397c8d8SUlf Hansson 2893f397c8d8SUlf Hansson { 2894f397c8d8SUlf Hansson .name = "Read performance non-blocking req 1 to 512 sg elems", 2895f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2896f397c8d8SUlf Hansson .run = mmc_test_profile_sglen_r_nonblock_perf, 2897f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2898f397c8d8SUlf Hansson }, 2899f397c8d8SUlf Hansson 2900f397c8d8SUlf Hansson { 2901f397c8d8SUlf Hansson .name = "Reset test", 2902f397c8d8SUlf Hansson .run = mmc_test_reset, 2903f397c8d8SUlf Hansson }, 2904f397c8d8SUlf Hansson 2905f397c8d8SUlf Hansson { 2906f397c8d8SUlf Hansson .name = "Commands during read - no Set Block Count (CMD23)", 2907f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2908f397c8d8SUlf Hansson .run = mmc_test_cmds_during_read, 2909f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2910f397c8d8SUlf Hansson }, 2911f397c8d8SUlf Hansson 2912f397c8d8SUlf Hansson { 2913f397c8d8SUlf Hansson .name = "Commands during write - no Set Block Count (CMD23)", 2914f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2915f397c8d8SUlf Hansson .run = mmc_test_cmds_during_write, 2916f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2917f397c8d8SUlf Hansson }, 2918f397c8d8SUlf Hansson 2919f397c8d8SUlf Hansson { 2920f397c8d8SUlf Hansson .name = "Commands during read - use Set Block Count (CMD23)", 2921f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2922f397c8d8SUlf Hansson .run = mmc_test_cmds_during_read_cmd23, 2923f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2924f397c8d8SUlf Hansson }, 2925f397c8d8SUlf Hansson 2926f397c8d8SUlf Hansson { 2927f397c8d8SUlf Hansson .name = "Commands during write - use Set Block Count (CMD23)", 2928f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2929f397c8d8SUlf Hansson .run = mmc_test_cmds_during_write_cmd23, 2930f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2931f397c8d8SUlf Hansson }, 2932f397c8d8SUlf Hansson 2933f397c8d8SUlf Hansson { 2934f397c8d8SUlf Hansson .name = "Commands during non-blocking read - use Set Block Count (CMD23)", 2935f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2936f397c8d8SUlf Hansson .run = mmc_test_cmds_during_read_cmd23_nonblock, 2937f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2938f397c8d8SUlf Hansson }, 2939f397c8d8SUlf Hansson 2940f397c8d8SUlf Hansson { 2941f397c8d8SUlf Hansson .name = "Commands during non-blocking write - use Set Block Count (CMD23)", 2942f397c8d8SUlf Hansson .prepare = mmc_test_area_prepare, 2943f397c8d8SUlf Hansson .run = mmc_test_cmds_during_write_cmd23_nonblock, 2944f397c8d8SUlf Hansson .cleanup = mmc_test_area_cleanup, 2945f397c8d8SUlf Hansson }, 2946f397c8d8SUlf Hansson }; 2947f397c8d8SUlf Hansson 2948f397c8d8SUlf Hansson static DEFINE_MUTEX(mmc_test_lock); 2949f397c8d8SUlf Hansson 2950f397c8d8SUlf Hansson static LIST_HEAD(mmc_test_result); 2951f397c8d8SUlf Hansson 2952f397c8d8SUlf Hansson static void mmc_test_run(struct mmc_test_card *test, int testcase) 2953f397c8d8SUlf Hansson { 2954f397c8d8SUlf Hansson int i, ret; 2955f397c8d8SUlf Hansson 2956f397c8d8SUlf Hansson pr_info("%s: Starting tests of card %s...\n", 2957f397c8d8SUlf Hansson mmc_hostname(test->card->host), mmc_card_id(test->card)); 2958f397c8d8SUlf Hansson 2959f397c8d8SUlf Hansson mmc_claim_host(test->card->host); 2960f397c8d8SUlf Hansson 2961f397c8d8SUlf Hansson for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++) { 2962f397c8d8SUlf Hansson struct mmc_test_general_result *gr; 2963f397c8d8SUlf Hansson 2964f397c8d8SUlf Hansson if (testcase && ((i + 1) != testcase)) 2965f397c8d8SUlf Hansson continue; 2966f397c8d8SUlf Hansson 2967f397c8d8SUlf Hansson pr_info("%s: Test case %d. %s...\n", 2968f397c8d8SUlf Hansson mmc_hostname(test->card->host), i + 1, 2969f397c8d8SUlf Hansson mmc_test_cases[i].name); 2970f397c8d8SUlf Hansson 2971f397c8d8SUlf Hansson if (mmc_test_cases[i].prepare) { 2972f397c8d8SUlf Hansson ret = mmc_test_cases[i].prepare(test); 2973f397c8d8SUlf Hansson if (ret) { 29747200449dSMarkus Elfring pr_info("%s: Result: Prepare stage failed! (%d)\n", 2975f397c8d8SUlf Hansson mmc_hostname(test->card->host), 2976f397c8d8SUlf Hansson ret); 2977f397c8d8SUlf Hansson continue; 2978f397c8d8SUlf Hansson } 2979f397c8d8SUlf Hansson } 2980f397c8d8SUlf Hansson 2981554d7c54SMarkus Elfring gr = kzalloc(sizeof(*gr), GFP_KERNEL); 2982f397c8d8SUlf Hansson if (gr) { 2983f397c8d8SUlf Hansson INIT_LIST_HEAD(&gr->tr_lst); 2984f397c8d8SUlf Hansson 2985f397c8d8SUlf Hansson /* Assign data what we know already */ 2986f397c8d8SUlf Hansson gr->card = test->card; 2987f397c8d8SUlf Hansson gr->testcase = i; 2988f397c8d8SUlf Hansson 2989f397c8d8SUlf Hansson /* Append container to global one */ 2990f397c8d8SUlf Hansson list_add_tail(&gr->link, &mmc_test_result); 2991f397c8d8SUlf Hansson 2992f397c8d8SUlf Hansson /* 2993f397c8d8SUlf Hansson * Save the pointer to created container in our private 2994f397c8d8SUlf Hansson * structure. 2995f397c8d8SUlf Hansson */ 2996f397c8d8SUlf Hansson test->gr = gr; 2997f397c8d8SUlf Hansson } 2998f397c8d8SUlf Hansson 2999f397c8d8SUlf Hansson ret = mmc_test_cases[i].run(test); 3000f397c8d8SUlf Hansson switch (ret) { 3001f397c8d8SUlf Hansson case RESULT_OK: 3002f397c8d8SUlf Hansson pr_info("%s: Result: OK\n", 3003f397c8d8SUlf Hansson mmc_hostname(test->card->host)); 3004f397c8d8SUlf Hansson break; 3005f397c8d8SUlf Hansson case RESULT_FAIL: 3006f397c8d8SUlf Hansson pr_info("%s: Result: FAILED\n", 3007f397c8d8SUlf Hansson mmc_hostname(test->card->host)); 3008f397c8d8SUlf Hansson break; 3009f397c8d8SUlf Hansson case RESULT_UNSUP_HOST: 30107200449dSMarkus Elfring pr_info("%s: Result: UNSUPPORTED (by host)\n", 3011f397c8d8SUlf Hansson mmc_hostname(test->card->host)); 3012f397c8d8SUlf Hansson break; 3013f397c8d8SUlf Hansson case RESULT_UNSUP_CARD: 30147200449dSMarkus Elfring pr_info("%s: Result: UNSUPPORTED (by card)\n", 3015f397c8d8SUlf Hansson mmc_hostname(test->card->host)); 3016f397c8d8SUlf Hansson break; 3017f397c8d8SUlf Hansson default: 3018f397c8d8SUlf Hansson pr_info("%s: Result: ERROR (%d)\n", 3019f397c8d8SUlf Hansson mmc_hostname(test->card->host), ret); 3020f397c8d8SUlf Hansson } 3021f397c8d8SUlf Hansson 3022f397c8d8SUlf Hansson /* Save the result */ 3023f397c8d8SUlf Hansson if (gr) 3024f397c8d8SUlf Hansson gr->result = ret; 3025f397c8d8SUlf Hansson 3026f397c8d8SUlf Hansson if (mmc_test_cases[i].cleanup) { 3027f397c8d8SUlf Hansson ret = mmc_test_cases[i].cleanup(test); 3028f397c8d8SUlf Hansson if (ret) { 30297200449dSMarkus Elfring pr_info("%s: Warning: Cleanup stage failed! (%d)\n", 3030f397c8d8SUlf Hansson mmc_hostname(test->card->host), 3031f397c8d8SUlf Hansson ret); 3032f397c8d8SUlf Hansson } 3033f397c8d8SUlf Hansson } 3034f397c8d8SUlf Hansson } 3035f397c8d8SUlf Hansson 3036f397c8d8SUlf Hansson mmc_release_host(test->card->host); 3037f397c8d8SUlf Hansson 3038f397c8d8SUlf Hansson pr_info("%s: Tests completed.\n", 3039f397c8d8SUlf Hansson mmc_hostname(test->card->host)); 3040f397c8d8SUlf Hansson } 3041f397c8d8SUlf Hansson 3042f397c8d8SUlf Hansson static void mmc_test_free_result(struct mmc_card *card) 3043f397c8d8SUlf Hansson { 3044f397c8d8SUlf Hansson struct mmc_test_general_result *gr, *grs; 3045f397c8d8SUlf Hansson 3046f397c8d8SUlf Hansson mutex_lock(&mmc_test_lock); 3047f397c8d8SUlf Hansson 3048f397c8d8SUlf Hansson list_for_each_entry_safe(gr, grs, &mmc_test_result, link) { 3049f397c8d8SUlf Hansson struct mmc_test_transfer_result *tr, *trs; 3050f397c8d8SUlf Hansson 3051f397c8d8SUlf Hansson if (card && gr->card != card) 3052f397c8d8SUlf Hansson continue; 3053f397c8d8SUlf Hansson 3054f397c8d8SUlf Hansson list_for_each_entry_safe(tr, trs, &gr->tr_lst, link) { 3055f397c8d8SUlf Hansson list_del(&tr->link); 3056f397c8d8SUlf Hansson kfree(tr); 3057f397c8d8SUlf Hansson } 3058f397c8d8SUlf Hansson 3059f397c8d8SUlf Hansson list_del(&gr->link); 3060f397c8d8SUlf Hansson kfree(gr); 3061f397c8d8SUlf Hansson } 3062f397c8d8SUlf Hansson 3063f397c8d8SUlf Hansson mutex_unlock(&mmc_test_lock); 3064f397c8d8SUlf Hansson } 3065f397c8d8SUlf Hansson 3066f397c8d8SUlf Hansson static LIST_HEAD(mmc_test_file_test); 3067f397c8d8SUlf Hansson 3068f397c8d8SUlf Hansson static int mtf_test_show(struct seq_file *sf, void *data) 3069f397c8d8SUlf Hansson { 3070f397c8d8SUlf Hansson struct mmc_card *card = (struct mmc_card *)sf->private; 3071f397c8d8SUlf Hansson struct mmc_test_general_result *gr; 3072f397c8d8SUlf Hansson 3073f397c8d8SUlf Hansson mutex_lock(&mmc_test_lock); 3074f397c8d8SUlf Hansson 3075f397c8d8SUlf Hansson list_for_each_entry(gr, &mmc_test_result, link) { 3076f397c8d8SUlf Hansson struct mmc_test_transfer_result *tr; 3077f397c8d8SUlf Hansson 3078f397c8d8SUlf Hansson if (gr->card != card) 3079f397c8d8SUlf Hansson continue; 3080f397c8d8SUlf Hansson 3081f397c8d8SUlf Hansson seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result); 3082f397c8d8SUlf Hansson 3083f397c8d8SUlf Hansson list_for_each_entry(tr, &gr->tr_lst, link) { 3084f397c8d8SUlf Hansson seq_printf(sf, "%u %d %lu.%09lu %u %u.%02u\n", 3085f397c8d8SUlf Hansson tr->count, tr->sectors, 3086f397c8d8SUlf Hansson (unsigned long)tr->ts.tv_sec, 3087f397c8d8SUlf Hansson (unsigned long)tr->ts.tv_nsec, 3088f397c8d8SUlf Hansson tr->rate, tr->iops / 100, tr->iops % 100); 3089f397c8d8SUlf Hansson } 3090f397c8d8SUlf Hansson } 3091f397c8d8SUlf Hansson 3092f397c8d8SUlf Hansson mutex_unlock(&mmc_test_lock); 3093f397c8d8SUlf Hansson 3094f397c8d8SUlf Hansson return 0; 3095f397c8d8SUlf Hansson } 3096f397c8d8SUlf Hansson 3097f397c8d8SUlf Hansson static int mtf_test_open(struct inode *inode, struct file *file) 3098f397c8d8SUlf Hansson { 3099f397c8d8SUlf Hansson return single_open(file, mtf_test_show, inode->i_private); 3100f397c8d8SUlf Hansson } 3101f397c8d8SUlf Hansson 3102f397c8d8SUlf Hansson static ssize_t mtf_test_write(struct file *file, const char __user *buf, 3103f397c8d8SUlf Hansson size_t count, loff_t *pos) 3104f397c8d8SUlf Hansson { 3105f397c8d8SUlf Hansson struct seq_file *sf = (struct seq_file *)file->private_data; 3106f397c8d8SUlf Hansson struct mmc_card *card = (struct mmc_card *)sf->private; 3107f397c8d8SUlf Hansson struct mmc_test_card *test; 3108f397c8d8SUlf Hansson long testcase; 3109f397c8d8SUlf Hansson int ret; 3110f397c8d8SUlf Hansson 3111f397c8d8SUlf Hansson ret = kstrtol_from_user(buf, count, 10, &testcase); 3112f397c8d8SUlf Hansson if (ret) 3113f397c8d8SUlf Hansson return ret; 3114f397c8d8SUlf Hansson 3115554d7c54SMarkus Elfring test = kzalloc(sizeof(*test), GFP_KERNEL); 3116f397c8d8SUlf Hansson if (!test) 3117f397c8d8SUlf Hansson return -ENOMEM; 3118f397c8d8SUlf Hansson 3119f397c8d8SUlf Hansson /* 3120f397c8d8SUlf Hansson * Remove all test cases associated with given card. Thus we have only 3121f397c8d8SUlf Hansson * actual data of the last run. 3122f397c8d8SUlf Hansson */ 3123f397c8d8SUlf Hansson mmc_test_free_result(card); 3124f397c8d8SUlf Hansson 3125f397c8d8SUlf Hansson test->card = card; 3126f397c8d8SUlf Hansson 3127f397c8d8SUlf Hansson test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL); 3128f397c8d8SUlf Hansson #ifdef CONFIG_HIGHMEM 3129f397c8d8SUlf Hansson test->highmem = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, BUFFER_ORDER); 3130f397c8d8SUlf Hansson #endif 3131f397c8d8SUlf Hansson 3132f397c8d8SUlf Hansson #ifdef CONFIG_HIGHMEM 3133f397c8d8SUlf Hansson if (test->buffer && test->highmem) { 3134f397c8d8SUlf Hansson #else 3135f397c8d8SUlf Hansson if (test->buffer) { 3136f397c8d8SUlf Hansson #endif 3137f397c8d8SUlf Hansson mutex_lock(&mmc_test_lock); 3138f397c8d8SUlf Hansson mmc_test_run(test, testcase); 3139f397c8d8SUlf Hansson mutex_unlock(&mmc_test_lock); 3140f397c8d8SUlf Hansson } 3141f397c8d8SUlf Hansson 3142f397c8d8SUlf Hansson #ifdef CONFIG_HIGHMEM 3143f397c8d8SUlf Hansson __free_pages(test->highmem, BUFFER_ORDER); 3144f397c8d8SUlf Hansson #endif 3145f397c8d8SUlf Hansson kfree(test->buffer); 3146f397c8d8SUlf Hansson kfree(test); 3147f397c8d8SUlf Hansson 3148f397c8d8SUlf Hansson return count; 3149f397c8d8SUlf Hansson } 3150f397c8d8SUlf Hansson 3151f397c8d8SUlf Hansson static const struct file_operations mmc_test_fops_test = { 3152f397c8d8SUlf Hansson .open = mtf_test_open, 3153f397c8d8SUlf Hansson .read = seq_read, 3154f397c8d8SUlf Hansson .write = mtf_test_write, 3155f397c8d8SUlf Hansson .llseek = seq_lseek, 3156f397c8d8SUlf Hansson .release = single_release, 3157f397c8d8SUlf Hansson }; 3158f397c8d8SUlf Hansson 3159f397c8d8SUlf Hansson static int mtf_testlist_show(struct seq_file *sf, void *data) 3160f397c8d8SUlf Hansson { 3161f397c8d8SUlf Hansson int i; 3162f397c8d8SUlf Hansson 3163f397c8d8SUlf Hansson mutex_lock(&mmc_test_lock); 3164f397c8d8SUlf Hansson 3165dc3a5fe6SMarkus Elfring seq_puts(sf, "0:\tRun all tests\n"); 3166f397c8d8SUlf Hansson for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++) 3167f397c8d8SUlf Hansson seq_printf(sf, "%d:\t%s\n", i + 1, mmc_test_cases[i].name); 3168f397c8d8SUlf Hansson 3169f397c8d8SUlf Hansson mutex_unlock(&mmc_test_lock); 3170f397c8d8SUlf Hansson 3171f397c8d8SUlf Hansson return 0; 3172f397c8d8SUlf Hansson } 3173f397c8d8SUlf Hansson 3174f397c8d8SUlf Hansson static int mtf_testlist_open(struct inode *inode, struct file *file) 3175f397c8d8SUlf Hansson { 3176f397c8d8SUlf Hansson return single_open(file, mtf_testlist_show, inode->i_private); 3177f397c8d8SUlf Hansson } 3178f397c8d8SUlf Hansson 3179f397c8d8SUlf Hansson static const struct file_operations mmc_test_fops_testlist = { 3180f397c8d8SUlf Hansson .open = mtf_testlist_open, 3181f397c8d8SUlf Hansson .read = seq_read, 3182f397c8d8SUlf Hansson .llseek = seq_lseek, 3183f397c8d8SUlf Hansson .release = single_release, 3184f397c8d8SUlf Hansson }; 3185f397c8d8SUlf Hansson 3186f397c8d8SUlf Hansson static void mmc_test_free_dbgfs_file(struct mmc_card *card) 3187f397c8d8SUlf Hansson { 3188f397c8d8SUlf Hansson struct mmc_test_dbgfs_file *df, *dfs; 3189f397c8d8SUlf Hansson 3190f397c8d8SUlf Hansson mutex_lock(&mmc_test_lock); 3191f397c8d8SUlf Hansson 3192f397c8d8SUlf Hansson list_for_each_entry_safe(df, dfs, &mmc_test_file_test, link) { 3193f397c8d8SUlf Hansson if (card && df->card != card) 3194f397c8d8SUlf Hansson continue; 3195f397c8d8SUlf Hansson debugfs_remove(df->file); 3196f397c8d8SUlf Hansson list_del(&df->link); 3197f397c8d8SUlf Hansson kfree(df); 3198f397c8d8SUlf Hansson } 3199f397c8d8SUlf Hansson 3200f397c8d8SUlf Hansson mutex_unlock(&mmc_test_lock); 3201f397c8d8SUlf Hansson } 3202f397c8d8SUlf Hansson 3203f397c8d8SUlf Hansson static int __mmc_test_register_dbgfs_file(struct mmc_card *card, 3204f397c8d8SUlf Hansson const char *name, umode_t mode, const struct file_operations *fops) 3205f397c8d8SUlf Hansson { 3206f397c8d8SUlf Hansson struct dentry *file = NULL; 3207f397c8d8SUlf Hansson struct mmc_test_dbgfs_file *df; 3208f397c8d8SUlf Hansson 3209f397c8d8SUlf Hansson if (card->debugfs_root) 3210f397c8d8SUlf Hansson file = debugfs_create_file(name, mode, card->debugfs_root, 3211f397c8d8SUlf Hansson card, fops); 3212f397c8d8SUlf Hansson 3213f397c8d8SUlf Hansson if (IS_ERR_OR_NULL(file)) { 3214f397c8d8SUlf Hansson dev_err(&card->dev, 3215f397c8d8SUlf Hansson "Can't create %s. Perhaps debugfs is disabled.\n", 3216f397c8d8SUlf Hansson name); 3217f397c8d8SUlf Hansson return -ENODEV; 3218f397c8d8SUlf Hansson } 3219f397c8d8SUlf Hansson 3220554d7c54SMarkus Elfring df = kmalloc(sizeof(*df), GFP_KERNEL); 3221f397c8d8SUlf Hansson if (!df) { 3222f397c8d8SUlf Hansson debugfs_remove(file); 3223f397c8d8SUlf Hansson dev_err(&card->dev, 3224f397c8d8SUlf Hansson "Can't allocate memory for internal usage.\n"); 3225f397c8d8SUlf Hansson return -ENOMEM; 3226f397c8d8SUlf Hansson } 3227f397c8d8SUlf Hansson 3228f397c8d8SUlf Hansson df->card = card; 3229f397c8d8SUlf Hansson df->file = file; 3230f397c8d8SUlf Hansson 3231f397c8d8SUlf Hansson list_add(&df->link, &mmc_test_file_test); 3232f397c8d8SUlf Hansson return 0; 3233f397c8d8SUlf Hansson } 3234f397c8d8SUlf Hansson 3235f397c8d8SUlf Hansson static int mmc_test_register_dbgfs_file(struct mmc_card *card) 3236f397c8d8SUlf Hansson { 3237f397c8d8SUlf Hansson int ret; 3238f397c8d8SUlf Hansson 3239f397c8d8SUlf Hansson mutex_lock(&mmc_test_lock); 3240f397c8d8SUlf Hansson 3241f397c8d8SUlf Hansson ret = __mmc_test_register_dbgfs_file(card, "test", S_IWUSR | S_IRUGO, 3242f397c8d8SUlf Hansson &mmc_test_fops_test); 3243f397c8d8SUlf Hansson if (ret) 3244f397c8d8SUlf Hansson goto err; 3245f397c8d8SUlf Hansson 3246f397c8d8SUlf Hansson ret = __mmc_test_register_dbgfs_file(card, "testlist", S_IRUGO, 3247f397c8d8SUlf Hansson &mmc_test_fops_testlist); 3248f397c8d8SUlf Hansson if (ret) 3249f397c8d8SUlf Hansson goto err; 3250f397c8d8SUlf Hansson 3251f397c8d8SUlf Hansson err: 3252f397c8d8SUlf Hansson mutex_unlock(&mmc_test_lock); 3253f397c8d8SUlf Hansson 3254f397c8d8SUlf Hansson return ret; 3255f397c8d8SUlf Hansson } 3256f397c8d8SUlf Hansson 3257f397c8d8SUlf Hansson static int mmc_test_probe(struct mmc_card *card) 3258f397c8d8SUlf Hansson { 3259f397c8d8SUlf Hansson int ret; 3260f397c8d8SUlf Hansson 3261f397c8d8SUlf Hansson if (!mmc_card_mmc(card) && !mmc_card_sd(card)) 3262f397c8d8SUlf Hansson return -ENODEV; 3263f397c8d8SUlf Hansson 3264f397c8d8SUlf Hansson ret = mmc_test_register_dbgfs_file(card); 3265f397c8d8SUlf Hansson if (ret) 3266f397c8d8SUlf Hansson return ret; 3267f397c8d8SUlf Hansson 32689d4579a8SAdrian Hunter if (card->ext_csd.cmdq_en) { 32699d4579a8SAdrian Hunter mmc_claim_host(card->host); 32709d4579a8SAdrian Hunter ret = mmc_cmdq_disable(card); 32719d4579a8SAdrian Hunter mmc_release_host(card->host); 32729d4579a8SAdrian Hunter if (ret) 32739d4579a8SAdrian Hunter return ret; 32749d4579a8SAdrian Hunter } 32759d4579a8SAdrian Hunter 3276f397c8d8SUlf Hansson dev_info(&card->dev, "Card claimed for testing.\n"); 3277f397c8d8SUlf Hansson 3278f397c8d8SUlf Hansson return 0; 3279f397c8d8SUlf Hansson } 3280f397c8d8SUlf Hansson 3281f397c8d8SUlf Hansson static void mmc_test_remove(struct mmc_card *card) 3282f397c8d8SUlf Hansson { 32839d4579a8SAdrian Hunter if (card->reenable_cmdq) { 32849d4579a8SAdrian Hunter mmc_claim_host(card->host); 32859d4579a8SAdrian Hunter mmc_cmdq_enable(card); 32869d4579a8SAdrian Hunter mmc_release_host(card->host); 32879d4579a8SAdrian Hunter } 3288f397c8d8SUlf Hansson mmc_test_free_result(card); 3289f397c8d8SUlf Hansson mmc_test_free_dbgfs_file(card); 3290f397c8d8SUlf Hansson } 3291f397c8d8SUlf Hansson 3292f397c8d8SUlf Hansson static void mmc_test_shutdown(struct mmc_card *card) 3293f397c8d8SUlf Hansson { 3294f397c8d8SUlf Hansson } 3295f397c8d8SUlf Hansson 3296f397c8d8SUlf Hansson static struct mmc_driver mmc_driver = { 3297f397c8d8SUlf Hansson .drv = { 3298f397c8d8SUlf Hansson .name = "mmc_test", 3299f397c8d8SUlf Hansson }, 3300f397c8d8SUlf Hansson .probe = mmc_test_probe, 3301f397c8d8SUlf Hansson .remove = mmc_test_remove, 3302f397c8d8SUlf Hansson .shutdown = mmc_test_shutdown, 3303f397c8d8SUlf Hansson }; 3304f397c8d8SUlf Hansson 3305f397c8d8SUlf Hansson static int __init mmc_test_init(void) 3306f397c8d8SUlf Hansson { 3307f397c8d8SUlf Hansson return mmc_register_driver(&mmc_driver); 3308f397c8d8SUlf Hansson } 3309f397c8d8SUlf Hansson 3310f397c8d8SUlf Hansson static void __exit mmc_test_exit(void) 3311f397c8d8SUlf Hansson { 3312f397c8d8SUlf Hansson /* Clear stalled data if card is still plugged */ 3313f397c8d8SUlf Hansson mmc_test_free_result(NULL); 3314f397c8d8SUlf Hansson mmc_test_free_dbgfs_file(NULL); 3315f397c8d8SUlf Hansson 3316f397c8d8SUlf Hansson mmc_unregister_driver(&mmc_driver); 3317f397c8d8SUlf Hansson } 3318f397c8d8SUlf Hansson 3319f397c8d8SUlf Hansson module_init(mmc_test_init); 3320f397c8d8SUlf Hansson module_exit(mmc_test_exit); 3321f397c8d8SUlf Hansson 3322f397c8d8SUlf Hansson MODULE_LICENSE("GPL"); 3323f397c8d8SUlf Hansson MODULE_DESCRIPTION("Multimedia Card (MMC) host test driver"); 3324f397c8d8SUlf Hansson MODULE_AUTHOR("Pierre Ossman"); 3325