mmc: card: Add eMMC4.5 packing control unit-tests

Expose the packing control test.
Test the packing control feature under these scenarios:
- Packing expected: entering write packing state,
  staying in write packing state.
- Packing not expected: not entering write packing state
  when not supposed to.
- Mixed states: test the ability to shift from packing
  to no-packing and back, and the opposite.

Change-Id: I5a93df8b5b7c48d355c3cc881699a3f9592914e6
Signed-off-by: Lee Susman <lsusman@codeaurora.org>
Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
This commit is contained in:
Tatyana Brokhman 2012-10-09 13:53:43 +02:00 committed by Subhash Jadavani
parent fececf257d
commit cbaf05043f

View file

@ -82,6 +82,25 @@ enum mmc_block_test_testcases {
TEST_CMD23_BITS_16TO29_SET,
TEST_CMD23_HDR_BLK_NOT_IN_COUNT,
INVALID_CMD_MAX_TESTCASE = TEST_CMD23_HDR_BLK_NOT_IN_COUNT,
/*
* Start of packing control test group.
* in these next testcases the abbreviation FB = followed by
*/
PACKING_CONTROL_MIN_TESTCASE,
TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ =
PACKING_CONTROL_MIN_TESTCASE,
TEST_PACKING_EXP_N_OVER_TRIGGER,
TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ,
TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N,
TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER,
TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS,
TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS,
TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER,
TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER,
TEST_PACK_MIX_PACKED_NO_PACKED_PACKED,
TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED,
PACKING_CONTROL_MAX_TESTCASE = TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED,
};
enum mmc_block_test_group {
@ -90,6 +109,7 @@ enum mmc_block_test_group {
TEST_SEND_WRITE_PACKING_GROUP,
TEST_ERR_CHECK_GROUP,
TEST_SEND_INVALID_GROUP,
TEST_PACKING_CONTROL_GROUP,
};
struct mmc_block_test_debug {
@ -97,6 +117,7 @@ struct mmc_block_test_debug {
struct dentry *err_check_test;
struct dentry *send_invalid_packed_test;
struct dentry *random_test_seed;
struct dentry *packing_control_test;
};
struct mmc_block_test_data {
@ -453,6 +474,28 @@ static char *get_test_case_str(struct test_data *td)
return "Test invalid - cmd23 bits [16-29] set";
case TEST_CMD23_HDR_BLK_NOT_IN_COUNT:
return "Test invalid - cmd23 header block not in count";
case TEST_PACKING_EXP_N_OVER_TRIGGER:
return "\nTest packing control - pack n";
case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
return "\nTest packing control - pack n followed by read";
case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
return "\nTest packing control - pack n followed by flush";
case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
return "\nTest packing control - pack one followed by read";
case TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER:
return "\nTest packing control - pack threshold";
case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
return "\nTest packing control - no packing";
case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
return "\nTest packing control - no packing, trigger requests";
case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
return "\nTest packing control - no pack, trigger-read-trigger";
case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
return "\nTest packing control- no pack, trigger-flush-trigger";
case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
return "\nTest packing control - mix: pack -> no pack -> pack";
case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
return "\nTest packing control - mix: no pack->pack->no pack";
default:
return "Unknown testcase";
}
@ -504,7 +547,7 @@ static int check_wr_packing_statistics(struct test_data *td)
stop_reason = mmc_packed_stats->pack_stop_reason;
for (i = 1 ; i <= max_packed_reqs ; ++i) {
for (i = 1; i <= max_packed_reqs; ++i) {
if (mmc_packed_stats->packing_events[i] !=
expected_stats.packing_events[i]) {
test_pr_err(
@ -709,7 +752,7 @@ static int prepare_request_add_write_reqs(struct test_data *td,
test_pr_info("%s: Adding %d write requests, first req_id=%d", __func__,
num_requests, td->wr_rd_next_req_id);
for (i = 1 ; i <= num_requests ; i++) {
for (i = 1; i <= num_requests; i++) {
start_sec = td->start_sector + 4096 * td->num_of_write_bios;
if (is_random)
pseudo_rnd_num_of_bios(bio_seed, &num_bios);
@ -824,6 +867,185 @@ static int prepare_packed_requests(struct test_data *td, int is_err_expected,
return 0;
}
/*
* Prepare the write, read and flush requests for the packing control
* testcases
*/
static int prepare_packed_control_tests_requests(struct test_data *td,
int is_err_expected, int num_requests, int is_random)
{
int ret = 0;
struct mmc_queue *mq;
int max_packed_reqs;
int temp_num_req = num_requests;
struct request_queue *req_q;
int test_packed_trigger;
int num_packed_reqs;
if (!td) {
test_pr_err("%s: NULL td\n", __func__);
return -EINVAL;
}
req_q = td->req_q;
if (!req_q) {
test_pr_err("%s: NULL request queue\n", __func__);
return -EINVAL;
}
mq = req_q->queuedata;
if (!mq) {
test_pr_err("%s: NULL mq", __func__);
return -EINVAL;
}
max_packed_reqs = mq->card->ext_csd.max_packed_writes;
test_packed_trigger = mq->num_wr_reqs_to_start_packing;
num_packed_reqs = num_requests - test_packed_trigger;
if (mbtd->random_test_seed == 0) {
mbtd->random_test_seed =
(unsigned int)(get_jiffies_64() & 0xFFFF);
test_pr_info("%s: got seed from jiffies %d",
__func__, mbtd->random_test_seed);
}
mmc_blk_init_packed_statistics(mq->card);
if (td->test_info.testcase ==
TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED) {
temp_num_req = num_requests;
num_requests = test_packed_trigger - 1;
}
/* Verify that the packing is disabled before starting the test */
mq->wr_packing_enabled = false;
mq->num_of_potential_packed_wr_reqs = 0;
if (td->test_info.testcase == TEST_PACK_MIX_PACKED_NO_PACKED_PACKED) {
mq->num_of_potential_packed_wr_reqs = test_packed_trigger + 1;
mq->wr_packing_enabled = true;
num_requests = test_packed_trigger + 2;
}
ret = prepare_request_add_write_reqs(td, num_requests, is_err_expected,
is_random);
if (ret)
goto exit;
if (td->test_info.testcase == TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED)
num_requests = temp_num_req;
memset((void *)mbtd->exp_packed_stats.pack_stop_reason, 0,
sizeof(mbtd->exp_packed_stats.pack_stop_reason));
memset(mbtd->exp_packed_stats.packing_events, 0,
(max_packed_reqs + 1) * sizeof(u32));
switch (td->test_info.testcase) {
case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
ret = prepare_request_add_read(td);
if (ret)
goto exit;
mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
break;
case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
ret = prepare_request_add_flush(td);
if (ret)
goto exit;
ret = prepare_request_add_write_reqs(td, num_packed_reqs,
is_err_expected, is_random);
if (ret)
goto exit;
mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
mbtd->exp_packed_stats.pack_stop_reason[FLUSH_OR_DISCARD] = 1;
mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 2;
break;
case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
ret = prepare_request_add_read(td);
if (ret)
goto exit;
ret = prepare_request_add_write_reqs(td, test_packed_trigger,
is_err_expected, is_random);
if (ret)
goto exit;
mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
break;
case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
ret = prepare_request_add_flush(td);
if (ret)
goto exit;
ret = prepare_request_add_write_reqs(td, test_packed_trigger,
is_err_expected, is_random);
if (ret)
goto exit;
mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
break;
case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
ret = prepare_request_add_read(td);
if (ret)
goto exit;
ret = prepare_request_add_write_reqs(td, test_packed_trigger-1,
is_err_expected, is_random);
if (ret)
goto exit;
ret = prepare_request_add_write_reqs(td, num_requests,
is_err_expected, is_random);
if (ret)
goto exit;
mbtd->exp_packed_stats.packing_events[num_requests] = 1;
mbtd->exp_packed_stats.packing_events[num_requests-1] = 1;
mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
break;
case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
ret = prepare_request_add_read(td);
if (ret)
goto exit;
ret = prepare_request_add_write_reqs(td, num_requests,
is_err_expected, is_random);
if (ret)
goto exit;
ret = prepare_request_add_read(td);
if (ret)
goto exit;
ret = prepare_request_add_write_reqs(td, test_packed_trigger-1,
is_err_expected, is_random);
if (ret)
goto exit;
mbtd->exp_packed_stats.pack_stop_reason[WRONG_DATA_DIR] = 1;
mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
break;
case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
break;
default:
mbtd->exp_packed_stats.pack_stop_reason[EMPTY_QUEUE] = 1;
mbtd->exp_packed_stats.packing_events[num_packed_reqs] = 1;
}
mbtd->num_requests = num_requests;
exit:
return ret;
}
/*
* Prepare requests for the TEST_RET_PARTIAL_FOLLOWED_BY_ABORT testcase.
* In this testcase we have mixed error expectations from different
@ -847,13 +1069,14 @@ static int prepare_partial_followed_by_abort(struct test_data *td,
mmc_blk_init_packed_statistics(mq->card);
for (i = 1 ; i <= num_requests ; i++) {
for (i = 1; i <= num_requests; i++) {
if (i > (num_requests / 2))
is_err_expected = 1;
start_address = td->start_sector + 4096*td->num_of_write_bios;
start_address = td->start_sector + 4096 * td->num_of_write_bios;
ret = test_iosched_add_wr_rd_test_req(is_err_expected, WRITE,
start_address, (i%5)+1, TEST_PATTERN_5A, NULL);
start_address, (i % 5) + 1, TEST_PATTERN_5A,
NULL);
if (ret) {
test_pr_err("%s: failed to add a write request",
__func__);
@ -887,6 +1110,8 @@ static int get_num_requests(struct test_data *td)
int num_requests;
int min_num_requests = 2;
int is_random = mbtd->is_random;
int max_for_double;
int test_packed_trigger;
req_q = test_iosched_get_req_queue();
if (req_q)
@ -903,16 +1128,52 @@ static int get_num_requests(struct test_data *td)
max_num_requests = mq->card->ext_csd.max_packed_writes;
num_requests = max_num_requests - 2;
test_packed_trigger = mq->num_wr_reqs_to_start_packing;
/*
* Here max_for_double is intended for packed control testcases
* in which we issue many write requests. It's purpose is to prevent
* exceeding max number of req_queue requests.
*/
max_for_double = max_num_requests - 10;
if (td->test_info.testcase ==
TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
/* Don't expect packing, so issue up to trigger-1 reqs */
num_requests = test_packed_trigger - 1;
if (is_random) {
if (td->test_info.testcase ==
TEST_RET_PARTIAL_FOLLOWED_BY_ABORT)
/*
* Here we don't want num_requests to be less than 1
* as a consequence of division by 2.
*/
min_num_requests = 3;
if (td->test_info.testcase ==
TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
/* Don't expect packing, so issue up to trigger reqs */
max_num_requests = test_packed_trigger;
num_requests = pseudo_random_seed(seed, min_num_requests,
max_num_requests - 1);
}
if (td->test_info.testcase ==
TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS)
num_requests -= test_packed_trigger;
if (td->test_info.testcase == TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N)
num_requests =
num_requests > max_for_double ? max_for_double : num_requests;
if (mbtd->test_group == TEST_PACKING_CONTROL_GROUP)
num_requests += test_packed_trigger;
if (td->test_info.testcase == TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS)
num_requests = test_packed_trigger;
return num_requests;
}
@ -928,6 +1189,7 @@ static int prepare_test(struct test_data *td)
int num_requests = 0;
int ret = 0;
int is_random = mbtd->is_random;
int test_packed_trigger = mq->num_wr_reqs_to_start_packing;
if (!mq) {
test_pr_err("%s: NULL mq", __func__);
@ -996,6 +1258,33 @@ static int prepare_test(struct test_data *td)
case TEST_HDR_CMD23_PACKED_BIT_SET:
ret = prepare_packed_requests(td, 1, num_requests, is_random);
break;
case TEST_PACKING_EXP_N_OVER_TRIGGER:
case TEST_PACKING_EXP_N_OVER_TRIGGER_FB_READ:
case TEST_PACKING_NOT_EXP_TRIGGER_REQUESTS:
case TEST_PACKING_NOT_EXP_LESS_THAN_TRIGGER_REQUESTS:
case TEST_PACK_MIX_PACKED_NO_PACKED_PACKED:
case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
ret = prepare_packed_control_tests_requests(td, 0, num_requests,
is_random);
break;
case TEST_PACKING_EXP_THRESHOLD_OVER_TRIGGER:
ret = prepare_packed_control_tests_requests(td, 0,
max_num_requests, is_random);
break;
case TEST_PACKING_EXP_ONE_OVER_TRIGGER_FB_READ:
ret = prepare_packed_control_tests_requests(td, 0,
test_packed_trigger + 1,
is_random);
break;
case TEST_PACKING_EXP_N_OVER_TRIGGER_FLUSH_N:
ret = prepare_packed_control_tests_requests(td, 0, num_requests,
is_random);
break;
case TEST_PACKING_NOT_EXP_TRIGGER_READ_TRIGGER:
case TEST_PACKING_NOT_EXP_TRIGGER_FLUSH_TRIGGER:
ret = prepare_packed_control_tests_requests(td, 0,
test_packed_trigger, is_random);
break;
default:
test_pr_info("%s: Invalid test case...", __func__);
return -EINVAL;
@ -1083,6 +1372,9 @@ static int validate_packed_commands_settings(void)
/* disable the packing control */
host->caps2 &= ~MMC_CAP2_PACKED_WR_CONTROL;
break;
case TEST_PACKING_CONTROL_GROUP:
host->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
break;
default:
break;
}
@ -1134,12 +1426,12 @@ static ssize_t send_write_packing_test_write(struct file *file,
mbtd->test_info.get_test_case_str_fn = get_test_case_str;
mbtd->test_info.post_test_fn = post_test;
for (i = 0 ; i < number ; ++i) {
for (i = 0; i < number; ++i) {
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
test_pr_info("%s: ====================", __func__);
for (j = SEND_WRITE_PACKING_MIN_TESTCASE ;
j <= SEND_WRITE_PACKING_MAX_TESTCASE ; j++) {
for (j = SEND_WRITE_PACKING_MIN_TESTCASE;
j <= SEND_WRITE_PACKING_MAX_TESTCASE; j++) {
mbtd->test_info.testcase = j;
mbtd->is_random = RANDOM_TEST;
@ -1232,7 +1524,7 @@ static ssize_t err_check_test_write(struct file *file,
mbtd->test_info.get_test_case_str_fn = get_test_case_str;
mbtd->test_info.post_test_fn = post_test;
for (i = 0 ; i < number ; ++i) {
for (i = 0; i < number; ++i) {
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
test_pr_info("%s: ====================", __func__);
@ -1331,7 +1623,7 @@ static ssize_t send_invalid_packed_test_write(struct file *file,
mbtd->test_info.get_test_case_str_fn = get_test_case_str;
mbtd->test_info.post_test_fn = post_test;
for (i = 0 ; i < number ; ++i) {
for (i = 0; i < number; ++i) {
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
test_pr_info("%s: ====================", __func__);
@ -1407,12 +1699,123 @@ const struct file_operations send_invalid_packed_test_ops = {
.read = send_invalid_packed_test_read,
};
/* packing_control TEST */
static ssize_t write_packing_control_test_write(struct file *file,
const char __user *buf,
size_t count,
loff_t *ppos)
{
int ret = 0;
int i = 0;
int number = -1;
int j = 0;
struct mmc_queue *mq = test_iosched_get_req_queue()->queuedata;
int max_num_requests = mq->card->ext_csd.max_packed_writes;
int test_successful = 1;
test_pr_info("%s: -- write_packing_control TEST --", __func__);
sscanf(buf, "%d", &number);
if (number <= 0)
number = 1;
test_pr_info("%s: max_num_requests = %d ", __func__,
max_num_requests);
memset(&mbtd->test_info, 0, sizeof(struct test_info));
mbtd->test_group = TEST_PACKING_CONTROL_GROUP;
if (validate_packed_commands_settings())
return count;
mbtd->test_info.data = mbtd;
mbtd->test_info.prepare_test_fn = prepare_test;
mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
mbtd->test_info.get_test_case_str_fn = get_test_case_str;
for (i = 0; i < number; ++i) {
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
test_pr_info("%s: ====================", __func__);
for (j = PACKING_CONTROL_MIN_TESTCASE;
j <= PACKING_CONTROL_MAX_TESTCASE; j++) {
test_successful = 1;
mbtd->test_info.testcase = j;
mbtd->is_random = RANDOM_TEST;
ret = test_iosched_start_test(&mbtd->test_info);
if (ret) {
test_successful = 0;
break;
}
/* Allow FS requests to be dispatched */
msleep(1000);
mbtd->test_info.testcase = j;
mbtd->is_random = NON_RANDOM_TEST;
ret = test_iosched_start_test(&mbtd->test_info);
if (ret) {
test_successful = 0;
break;
}
/* Allow FS requests to be dispatched */
msleep(1000);
}
if (!test_successful)
break;
}
test_pr_info("%s: Completed all the test cases.", __func__);
return count;
}
static ssize_t write_packing_control_test_read(struct file *file,
char __user *buffer,
size_t count,
loff_t *offset)
{
memset((void *)buffer, 0, count);
snprintf(buffer, count,
"\nwrite_packing_control_test\n"
"=========\n"
"Description:\n"
"This test checks the following scenarios\n"
"- Packing expected - one over trigger\n"
"- Packing expected - N over trigger\n"
"- Packing expected - N over trigger followed by read\n"
"- Packing expected - N over trigger followed by flush\n"
"- Packing expected - threshold over trigger FB by flush\n"
"- Packing not expected - less than trigger\n"
"- Packing not expected - trigger requests\n"
"- Packing not expected - trigger, read, trigger\n"
"- Mixed state - packing -> no packing -> packing\n"
"- Mixed state - no packing -> packing -> no packing\n");
if (message_repeat == 1) {
message_repeat = 0;
return strnlen(buffer, count);
} else {
return 0;
}
}
const struct file_operations write_packing_control_test_ops = {
.open = test_open,
.write = write_packing_control_test_write,
.read = write_packing_control_test_read,
};
static void mmc_block_test_debugfs_cleanup(void)
{
debugfs_remove(mbtd->debug.random_test_seed);
debugfs_remove(mbtd->debug.send_write_packing_test);
debugfs_remove(mbtd->debug.err_check_test);
debugfs_remove(mbtd->debug.send_invalid_packed_test);
debugfs_remove(mbtd->debug.packing_control_test);
}
static int mmc_block_test_debugfs_init(void)
@ -1464,6 +1867,16 @@ static int mmc_block_test_debugfs_init(void)
if (!mbtd->debug.send_invalid_packed_test)
goto err_nomem;
mbtd->debug.packing_control_test = debugfs_create_file(
"packing_control_test",
S_IRUGO | S_IWUGO,
tests_root,
NULL,
&write_packing_control_test_ops);
if (!mbtd->debug.packing_control_test)
goto err_nomem;
return 0;
err_nomem: