@@ -22,6 +22,7 @@
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/seq_file.h>
+#include <linux/random.h>
#define RESULT_OK 0
#define RESULT_FAIL 1
@@ -51,10 +52,12 @@ struct mmc_test_pages {
* struct mmc_test_mem - allocated memory.
* @arr: array of allocations
* @cnt: number of allocations
+ * @size_min_cmn: lowest common size in array of allocations
*/
struct mmc_test_mem {
struct mmc_test_pages *arr;
unsigned int cnt;
+ unsigned int size_min_cmn;
};
/**
@@ -148,6 +151,21 @@ struct mmc_test_card {
struct mmc_test_general_result *gr;
};
+enum mmc_test_prep_media {
+ MMC_TEST_PREP_NONE = 0,
+ MMC_TEST_PREP_WRITE_FULL = 1 << 0,
+ MMC_TEST_PREP_ERASE = 1 << 1,
+};
+
+struct mmc_test_multiple_rw {
+ unsigned int *bs;
+ unsigned int len;
+ unsigned int size;
+ bool do_write;
+ bool do_nonblock_req;
+ enum mmc_test_prep_media prepare;
+};
+
/*******************************************************************/
/* General helper functions */
/*******************************************************************/
@@ -307,6 +325,7 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
unsigned long max_seg_page_cnt = DIV_ROUND_UP(max_seg_sz, PAGE_SIZE);
unsigned long page_cnt = 0;
unsigned long limit = nr_free_buffer_pages() >> 4;
+ unsigned int min_cmn = 0;
struct mmc_test_mem *mem;
if (max_page_cnt > limit)
@@ -350,6 +369,12 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
mem->arr[mem->cnt].page = page;
mem->arr[mem->cnt].order = order;
mem->cnt += 1;
+ if (!min_cmn)
+ min_cmn = PAGE_SIZE << order;
+ else
+ min_cmn = min(min_cmn,
+ (unsigned int) (PAGE_SIZE << order));
+
if (max_page_cnt <= (1UL << order))
break;
max_page_cnt -= 1UL << order;
@@ -360,6 +385,7 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
break;
}
}
+ mem->size_min_cmn = min_cmn;
return mem;
@@ -386,7 +412,6 @@ static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
do {
for (i = 0; i < mem->cnt; i++) {
unsigned long len = PAGE_SIZE << mem->arr[i].order;
-
if (len > sz)
len = sz;
if (len > max_seg_sz)
@@ -725,6 +750,94 @@ static int mmc_test_check_broken_result(struct mmc_test_card *test, }
/*
+ * Tests nonblock transfer with certain parameters */ static void
+mmc_test_nonblock_reset(struct mmc_request *mrq,
+ struct mmc_command *cmd,
+ struct mmc_command *stop,
+ struct mmc_data *data)
+{
+ memset(mrq, 0, sizeof(struct mmc_request));
+ memset(cmd, 0, sizeof(struct mmc_command));
+ memset(data, 0, sizeof(struct mmc_data));
+ memset(stop, 0, sizeof(struct mmc_command));
+
+ mrq->cmd = cmd;
+ mrq->data = data;
+ mrq->stop = stop;
+}
+static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
+ struct scatterlist *sg, unsigned sg_len,
+ unsigned dev_addr, unsigned blocks,
+ unsigned blksz, int write, int count) {
+ struct mmc_request mrq1;
+ struct mmc_command cmd1;
+ struct mmc_command stop1;
+ struct mmc_data data1;
+
+ struct mmc_request mrq2;
+ struct mmc_command cmd2;
+ struct mmc_command stop2;
+ struct mmc_data data2;
+
+ struct mmc_request *cur_mrq;
+ struct mmc_request *prev_mrq;
+ int i;
+ int ret = 0;
+
+ if (!test->card->host->ops->pre_req ||
+ !test->card->host->ops->post_req)
+ return -RESULT_UNSUP_HOST;
+
+ mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1);
+ mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2);
+
+ cur_mrq = &mrq1;
+ prev_mrq = NULL;
+
+ for (i = 0; i < count; i++) {
+ mmc_test_prepare_mrq(test, cur_mrq, sg, sg_len, dev_addr,
+ blocks, blksz, write);
+ mmc_pre_req(test->card->host, cur_mrq, !prev_mrq);
+
+ if (prev_mrq) {
+ mmc_wait_for_req_done(prev_mrq);
+ mmc_test_wait_busy(test);
+ ret = mmc_test_check_result(test, prev_mrq);
+ if (ret)
+ goto err;
+ }
+
+ mmc_start_req(test->card->host, cur_mrq);
+
+ if (prev_mrq)
+ mmc_post_req(test->card->host, prev_mrq, 0);
+
+ prev_mrq = cur_mrq;
+ if (cur_mrq == &mrq1) {
+ mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2);
+ cur_mrq = &mrq2;
+ } else {
+ mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1);
+ cur_mrq = &mrq1;
+ }
+ dev_addr += blocks;
+ }
+
+ mmc_wait_for_req_done(prev_mrq);
+ mmc_test_wait_busy(test);
+ ret = mmc_test_check_result(test, prev_mrq);
+ if (ret)
+ goto err;
+ mmc_post_req(test->card->host, prev_mrq, 0);
+
+ return ret;
+err:
+ return ret;
+}
+
+/*
* Tests a basic transfer with certain parameters
*/
static int mmc_test_simple_transfer(struct mmc_test_card *test, @@ -1351,14 +1464,17 @@ static int mmc_test_area_transfer(struct mmc_test_card *test, }
/*
- * Map and transfer bytes.
+ * Map and transfer bytes for multiple transfers.