#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/slab.h>
#include <linux/scatterlist.h>
#include <linux/list.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/seq_file.h>
#include <linux/module.h>
#include "core.h"
#include "card.h"
#include "host.h"
#include "bus.h"
#include "mmc_ops.h"
#define RESULT_OK …
#define RESULT_FAIL …
#define RESULT_UNSUP_HOST …
#define RESULT_UNSUP_CARD …
#define BUFFER_ORDER …
#define BUFFER_SIZE …
#define TEST_ALIGN_END …
#define TEST_AREA_MAX_SIZE …
struct mmc_test_pages { … };
struct mmc_test_mem { … };
struct mmc_test_area { … };
struct mmc_test_transfer_result { … };
struct mmc_test_general_result { … };
struct mmc_test_dbgfs_file { … };
struct mmc_test_card { … };
enum mmc_test_prep_media { … };
struct mmc_test_multiple_rw { … };
static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
{ … }
static bool mmc_test_card_cmd23(struct mmc_card *card)
{ … }
static void mmc_test_prepare_sbc(struct mmc_test_card *test,
struct mmc_request *mrq, unsigned int blocks)
{ … }
static void mmc_test_prepare_mrq(struct mmc_test_card *test,
struct mmc_request *mrq, struct scatterlist *sg, unsigned sg_len,
unsigned dev_addr, unsigned blocks, unsigned blksz, int write)
{ … }
static int mmc_test_busy(struct mmc_command *cmd)
{ … }
static int mmc_test_wait_busy(struct mmc_test_card *test)
{ … }
static int mmc_test_buffer_transfer(struct mmc_test_card *test,
u8 *buffer, unsigned addr, unsigned blksz, int write)
{ … }
static void mmc_test_free_mem(struct mmc_test_mem *mem)
{ … }
static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
unsigned long max_sz,
unsigned int max_segs,
unsigned int max_seg_sz)
{ … }
static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long size,
struct scatterlist *sglist, int repeat,
unsigned int max_segs, unsigned int max_seg_sz,
unsigned int *sg_len, int min_sg_len)
{ … }
static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
unsigned long sz,
struct scatterlist *sglist,
unsigned int max_segs,
unsigned int max_seg_sz,
unsigned int *sg_len)
{ … }
static unsigned int mmc_test_rate(uint64_t bytes, struct timespec64 *ts)
{ … }
static void mmc_test_save_transfer_result(struct mmc_test_card *test,
unsigned int count, unsigned int sectors, struct timespec64 ts,
unsigned int rate, unsigned int iops)
{ … }
static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
struct timespec64 *ts1, struct timespec64 *ts2)
{ … }
static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
unsigned int count, struct timespec64 *ts1,
struct timespec64 *ts2)
{ … }
static unsigned int mmc_test_capacity(struct mmc_card *card)
{ … }
static int __mmc_test_prepare(struct mmc_test_card *test, int write, int val)
{ … }
static int mmc_test_prepare_write(struct mmc_test_card *test)
{ … }
static int mmc_test_prepare_read(struct mmc_test_card *test)
{ … }
static int mmc_test_cleanup(struct mmc_test_card *test)
{ … }
static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test,
struct mmc_request *mrq, int write)
{ … }
static int mmc_test_check_result(struct mmc_test_card *test,
struct mmc_request *mrq)
{ … }
static int mmc_test_check_broken_result(struct mmc_test_card *test,
struct mmc_request *mrq)
{ … }
struct mmc_test_req { … };
static void mmc_test_req_reset(struct mmc_test_req *rq)
{ … }
static struct mmc_test_req *mmc_test_req_alloc(void)
{ … }
static void mmc_test_wait_done(struct mmc_request *mrq)
{ … }
static int mmc_test_start_areq(struct mmc_test_card *test,
struct mmc_request *mrq,
struct mmc_request *prev_mrq)
{ … }
static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
unsigned int dev_addr, int write,
int count)
{ … }
static int mmc_test_simple_transfer(struct mmc_test_card *test,
struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
unsigned blocks, unsigned blksz, int write)
{ … }
static int mmc_test_broken_transfer(struct mmc_test_card *test,
unsigned blocks, unsigned blksz, int write)
{ … }
static int mmc_test_transfer(struct mmc_test_card *test,
struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
unsigned blocks, unsigned blksz, int write)
{ … }
struct mmc_test_case { … };
static int mmc_test_basic_write(struct mmc_test_card *test)
{ … }
static int mmc_test_basic_read(struct mmc_test_card *test)
{ … }
static int mmc_test_verify_write(struct mmc_test_card *test)
{ … }
static int mmc_test_verify_read(struct mmc_test_card *test)
{ … }
static int mmc_test_multi_write(struct mmc_test_card *test)
{ … }
static int mmc_test_multi_read(struct mmc_test_card *test)
{ … }
static int mmc_test_pow2_write(struct mmc_test_card *test)
{ … }
static int mmc_test_pow2_read(struct mmc_test_card *test)
{ … }
static int mmc_test_weird_write(struct mmc_test_card *test)
{ … }
static int mmc_test_weird_read(struct mmc_test_card *test)
{ … }
static int mmc_test_align_write(struct mmc_test_card *test)
{ … }
static int mmc_test_align_read(struct mmc_test_card *test)
{ … }
static int mmc_test_align_multi_write(struct mmc_test_card *test)
{ … }
static int mmc_test_align_multi_read(struct mmc_test_card *test)
{ … }
static int mmc_test_xfersize_write(struct mmc_test_card *test)
{ … }
static int mmc_test_xfersize_read(struct mmc_test_card *test)
{ … }
static int mmc_test_multi_xfersize_write(struct mmc_test_card *test)
{ … }
static int mmc_test_multi_xfersize_read(struct mmc_test_card *test)
{ … }
#ifdef CONFIG_HIGHMEM
static int mmc_test_write_high(struct mmc_test_card *test)
{
struct scatterlist sg;
sg_init_table(&sg, 1);
sg_set_page(&sg, test->highmem, 512, 0);
return mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
}
static int mmc_test_read_high(struct mmc_test_card *test)
{
struct scatterlist sg;
sg_init_table(&sg, 1);
sg_set_page(&sg, test->highmem, 512, 0);
return mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
}
static int mmc_test_multi_write_high(struct mmc_test_card *test)
{
unsigned int size;
struct scatterlist sg;
if (test->card->host->max_blk_count == 1)
return RESULT_UNSUP_HOST;
size = PAGE_SIZE * 2;
size = min(size, test->card->host->max_req_size);
size = min(size, test->card->host->max_seg_size);
size = min(size, test->card->host->max_blk_count * 512);
if (size < 1024)
return RESULT_UNSUP_HOST;
sg_init_table(&sg, 1);
sg_set_page(&sg, test->highmem, size, 0);
return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1);
}
static int mmc_test_multi_read_high(struct mmc_test_card *test)
{
unsigned int size;
struct scatterlist sg;
if (test->card->host->max_blk_count == 1)
return RESULT_UNSUP_HOST;
size = PAGE_SIZE * 2;
size = min(size, test->card->host->max_req_size);
size = min(size, test->card->host->max_seg_size);
size = min(size, test->card->host->max_blk_count * 512);
if (size < 1024)
return RESULT_UNSUP_HOST;
sg_init_table(&sg, 1);
sg_set_page(&sg, test->highmem, size, 0);
return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0);
}
#else
static int mmc_test_no_highmem(struct mmc_test_card *test)
{ … }
#endif
static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
int max_scatter, int min_sg_len, bool nonblock)
{ … }
static int mmc_test_area_transfer(struct mmc_test_card *test,
unsigned int dev_addr, int write)
{ … }
static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
unsigned int dev_addr, int write,
int max_scatter, int timed, int count,
bool nonblock, int min_sg_len)
{ … }
static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
unsigned int dev_addr, int write, int max_scatter,
int timed)
{ … }
static int mmc_test_area_fill(struct mmc_test_card *test)
{ … }
static int mmc_test_area_erase(struct mmc_test_card *test)
{ … }
static int mmc_test_area_cleanup(struct mmc_test_card *test)
{ … }
static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
{ … }
static int mmc_test_area_prepare(struct mmc_test_card *test)
{ … }
static int mmc_test_area_prepare_erase(struct mmc_test_card *test)
{ … }
static int mmc_test_area_prepare_fill(struct mmc_test_card *test)
{ … }
static int mmc_test_best_performance(struct mmc_test_card *test, int write,
int max_scatter)
{ … }
static int mmc_test_best_read_performance(struct mmc_test_card *test)
{ … }
static int mmc_test_best_write_performance(struct mmc_test_card *test)
{ … }
static int mmc_test_best_read_perf_max_scatter(struct mmc_test_card *test)
{ … }
static int mmc_test_best_write_perf_max_scatter(struct mmc_test_card *test)
{ … }
static int mmc_test_profile_read_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_profile_write_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
{ … }
static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
{ … }
static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
{ … }
static unsigned int rnd_next = …;
static unsigned int mmc_test_rnd_num(unsigned int rnd_cnt)
{ … }
static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
unsigned long sz, int secs, int force_retuning)
{ … }
static int mmc_test_random_perf(struct mmc_test_card *test, int write)
{ … }
static int mmc_test_retuning(struct mmc_test_card *test)
{ … }
static int mmc_test_random_read_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_random_write_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
unsigned int tot_sz, int max_scatter)
{ … }
static int mmc_test_large_seq_perf(struct mmc_test_card *test, int write)
{ … }
static int mmc_test_large_seq_read_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_large_seq_write_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_rw_multiple(struct mmc_test_card *test,
struct mmc_test_multiple_rw *tdata,
unsigned int reqsize, unsigned int size,
int min_sg_len)
{ … }
static int mmc_test_rw_multiple_size(struct mmc_test_card *test,
struct mmc_test_multiple_rw *rw)
{ … }
static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test,
struct mmc_test_multiple_rw *rw)
{ … }
static int mmc_test_profile_mult_write_blocking_perf(struct mmc_test_card *test)
{
unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
struct mmc_test_multiple_rw test_data = {
.bs = bs,
.size = TEST_AREA_MAX_SIZE,
.len = ARRAY_SIZE(bs),
.do_write = true,
.do_nonblock_req = false,
.prepare = MMC_TEST_PREP_ERASE,
};
return mmc_test_rw_multiple_size(test, &test_data);
};
static int mmc_test_profile_mult_write_nonblock_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_profile_mult_read_blocking_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_profile_sglen_wr_blocking_perf(struct mmc_test_card *test)
{
unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
1 << 7, 1 << 8, 1 << 9};
struct mmc_test_multiple_rw test_data = {
.sg_len = sg_len,
.size = TEST_AREA_MAX_SIZE,
.len = ARRAY_SIZE(sg_len),
.do_write = true,
.do_nonblock_req = false,
.prepare = MMC_TEST_PREP_ERASE,
};
return mmc_test_rw_multiple_sg_len(test, &test_data);
};
static int mmc_test_profile_sglen_wr_nonblock_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_profile_sglen_r_blocking_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test)
{ … }
static int mmc_test_reset(struct mmc_test_card *test)
{ … }
static int mmc_test_send_status(struct mmc_test_card *test,
struct mmc_command *cmd)
{ … }
static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
unsigned int dev_addr, int use_sbc,
int repeat_cmd, int write, int use_areq)
{ … }
static int __mmc_test_cmds_during_tfr(struct mmc_test_card *test,
unsigned long sz, int use_sbc, int write,
int use_areq)
{ … }
static int mmc_test_cmds_during_tfr(struct mmc_test_card *test, int use_sbc,
int write, int use_areq)
{ … }
static int mmc_test_cmds_during_read(struct mmc_test_card *test)
{ … }
static int mmc_test_cmds_during_write(struct mmc_test_card *test)
{ … }
static int mmc_test_cmds_during_read_cmd23(struct mmc_test_card *test)
{ … }
static int mmc_test_cmds_during_write_cmd23(struct mmc_test_card *test)
{ … }
static int mmc_test_cmds_during_read_cmd23_nonblock(struct mmc_test_card *test)
{ … }
static int mmc_test_cmds_during_write_cmd23_nonblock(struct mmc_test_card *test)
{ … }
static const struct mmc_test_case mmc_test_cases[] = …;
static DEFINE_MUTEX(mmc_test_lock);
static LIST_HEAD(mmc_test_result);
static void mmc_test_run(struct mmc_test_card *test, int testcase)
{ … }
static void mmc_test_free_result(struct mmc_card *card)
{ … }
static LIST_HEAD(mmc_test_file_test);
static int mtf_test_show(struct seq_file *sf, void *data)
{ … }
static int mtf_test_open(struct inode *inode, struct file *file)
{ … }
static ssize_t mtf_test_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{ … }
static const struct file_operations mmc_test_fops_test = …;
static int mtf_testlist_show(struct seq_file *sf, void *data)
{ … }
DEFINE_SHOW_ATTRIBUTE(…);
static void mmc_test_free_dbgfs_file(struct mmc_card *card)
{ … }
static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
const char *name, umode_t mode, const struct file_operations *fops)
{ … }
static int mmc_test_register_dbgfs_file(struct mmc_card *card)
{ … }
static int mmc_test_probe(struct mmc_card *card)
{ … }
static void mmc_test_remove(struct mmc_card *card)
{ … }
static struct mmc_driver mmc_driver = …;
static int __init mmc_test_init(void)
{ … }
static void __exit mmc_test_exit(void)
{ … }
module_init(…) …;
module_exit(mmc_test_exit);
MODULE_LICENSE(…) …;
MODULE_DESCRIPTION(…) …;
MODULE_AUTHOR(…) …;