sdk-hwV1.3/lichee/xr806/appos/project/common/cmd/cmd_sd.c

678 lines
18 KiB
C
Executable File

/*
* Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef CONFIG_SDMMC
#include <string.h>
#include "sys/xr_debug.h"
#include "cmd_util.h"
#include "cmd_sd.h"
#include "driver/chip/hal_def.h"
#include "driver/chip/sdmmc/hal_sdhost.h"
#include "driver/chip/sdmmc/sdmmc.h"
static struct mmc_card *card;
extern int32_t mmc_test(uint32_t host_id, uint32_t cd_mode, uint32_t sdc_degmask, uint32_t card_dbgmask);
extern int32_t mmc_test_init(uint32_t host_id, SDC_InitTypeDef *sdc_param, uint32_t scan);
extern int32_t mmc_test_exit(uint16_t sd_id, uint16_t host_id);
extern struct mmc_card *mmc_scan_init(uint16_t sd_id, uint16_t sdc_id, SDCard_InitTypeDef *card_param);
/* drv sd init [<card_id> <debug_mask>]
* eg:
* 1. drv sd init
* 2. drv sd init 0 0x7f
*/
static enum cmd_status cmd_sd_init_exec(char *cmd)
{
uint32_t cnt;
uint32_t card_id, debug_mask;
SDC_InitTypeDef sdc_param = { 0 };
cnt = cmd_sscanf(cmd, "%d 0x%x", &card_id, &debug_mask);
if (cnt != 2) {
mmc_test_init(0, NULL, 0);
} else {
sdc_param.cd_mode = CARD_ALWAYS_PRESENT;
sdc_param.debug_mask = debug_mask;
mmc_test_init(card_id, &sdc_param, 0);
}
return CMD_STATUS_OK;
}
/* drv sd scan [<card_id> <host_id> <card_type> <debug_mask>]
* eg:
* 1. drv sd scan
* 2. drv sd scan 0 0 2 0x7f
*/
static enum cmd_status cmd_sd_scan_exec(char *cmd)
{
uint32_t cnt;
uint32_t card_id, host_id, type, debug_mask;
SDCard_InitTypeDef card_param = { 0 };
cnt = cmd_sscanf(cmd, "%d %d %d 0x%x", &card_id, &host_id, &type, &debug_mask);
if (cnt != 4) {
card = mmc_scan_init(0, 0, NULL);
} else {
card_param.debug_mask = debug_mask;
card_param.type = type;
card = mmc_scan_init(card_id, host_id, &card_param);
}
if (!card) {
CMD_ERR("scan card failed!\n");
return CMD_STATUS_OK;;
}
return CMD_STATUS_OK;
}
/*
* drv sd read s=<Start_Sector> n=<sector_num>
*/
static enum cmd_status cmd_sd_read_exec(char *cmd)
{
int32_t err;
uint32_t cnt;
uint32_t start_sector, r_secnum;
char *buf;
cnt = cmd_sscanf(cmd, "s=%d n=%d", &start_sector, &r_secnum);
if (cnt != 2) {
CMD_ERR("invalid argument %s\n", cmd);
return CMD_STATUS_FAIL;
}
buf = cmd_malloc(r_secnum*512);
if (!buf)
return CMD_STATUS_OK;;
err = mmc_block_read(card, (uint8_t *)buf, start_sector, r_secnum);
if (err) {
CMD_ERR("mmc mult blocks read err!\n");
return CMD_STATUS_FAIL;
}
CMD_DBG("read from %d sector, %d sectors\n", start_sector, r_secnum);
print_hex_dump_bytes(buf, r_secnum*512);
return CMD_STATUS_OK;
}
/*
* eg:
* 1. drv sd test
* 2. drv sd test 0 3 0x3c 0x3c
* 3. drv sd test 0 2 0x3c 0x3c
*/
static enum cmd_status cmd_sd_test_exec(char *cmd)
{
uint32_t cnt;
uint32_t host_id, cd_mode, sdc_degmask, card_dbgmask;
cnt = cmd_sscanf(cmd, "%d %d 0x%x 0x%x", &host_id, &cd_mode, &sdc_degmask, &card_dbgmask);
if (cnt != 4) {
CMD_DBG("use defaule argument %s\n", cmd);
host_id = 0;
cd_mode = CARD_ALWAYS_PRESENT;
sdc_degmask = ROM_WRN_MASK | ROM_ERR_MASK | ROM_ANY_MASK;
card_dbgmask = ROM_WRN_MASK | ROM_ERR_MASK | ROM_ANY_MASK;
}
mmc_test(host_id, cd_mode, sdc_degmask, card_dbgmask);
printf("%s,%d\n", __func__, __LINE__);
return CMD_STATUS_OK;
}
/*
* drv sd deinit [<card_id> <host_id>]
* eg.
* 1. sd deinit
* 2. sd deinit 0 0
*/
static enum cmd_status cmd_sd_deinit_exec(char *cmd)
{
uint32_t cnt;
uint32_t card_id, host_id;
cnt = cmd_sscanf(cmd, "%d %d", &card_id, &host_id);
if (cnt != 2) {
card_id = 0;
host_id = 0;
}
mmc_test_exit(card_id, host_id);
return CMD_STATUS_OK;
}
#define CMD_ARG_LEN 64
struct sd_test_param {
uint8_t task_idx;
uint8_t random;
uint8_t task_num;
uint8_t card_dma_use;
uint16_t time_sec;
uint16_t host_debug_mask;
uint16_t card_debug_mask;
uint32_t start_sector;
uint32_t sector_num;
};
static void cmd_sd_bench_task(void *arg)
{
int32_t err;
char *cmd = (char *)arg;
uint32_t start_sector;
uint32_t cnt;
uint32_t throuth_mb, throuth_kb;
OS_Time_t tick_use;
uint32_t bench_sector;
cnt = cmd_sscanf(cmd, "s=%d", &start_sector);
if (cnt != 1) {
CMD_ERR("invalid argument %s\n", cmd);
goto out;
}
mmc_test_init(0, NULL, 1);
card = mmc_card_open(0);
if (!card) {
CMD_ERR("card open failed!\n");
goto out;
}
bench_sector = start_sector - 1;
for (int i = 0; i < 20; i++) {
uint32_t bench_size = 512 * (1 << i);
uint8_t *buf = cmd_malloc(bench_size);
if (!buf) {
CMD_DBG("%s test end for malloc buff failed!\n", __func__);
goto out;
}
for (int j = 0; j < bench_size/4; j++)
((unsigned int *)buf)[j] = j;
bench_sector += bench_size/512;
tick_use = OS_GetTicks();
err = mmc_block_write(card, buf, bench_sector, bench_size/512);
tick_use = OS_GetTicks() - tick_use;
if (!tick_use)
tick_use = 1;
if (err) {
CMD_ERR("mmc mult blocks write err!\n");
goto next;
} else {
throuth_kb = bench_size*1000/1024/(uint32_t)OS_TicksToMSecs(tick_use);
throuth_mb = throuth_kb/1000;
CMD_DBG("%s mult blocks write ok, ", __func__);
if (bench_size <= 512)
CMD_LOG(CMD_DBG_ON, "0.5");
else
CMD_LOG(CMD_DBG_ON, "%3d", bench_size/1024);
CMD_LOG(CMD_DBG_ON, " KB use:%3d ms, throughput:%d.%d MB/S\n",
(uint32_t)OS_TicksToMSecs(tick_use),
throuth_mb, throuth_kb - throuth_mb);
}
for (int j = 0; j < bench_size/4; j++)
((unsigned int *)buf)[j] = 0;
tick_use = OS_GetTicks();
err = mmc_block_read(card, buf, bench_sector, bench_size/512);
tick_use = OS_GetTicks() - tick_use;
if (!tick_use)
tick_use = 1;
if (err) {
CMD_ERR("mmc mult blocks read err!\n");
goto next;
} else {
throuth_kb = bench_size*1000/1024/(uint32_t)OS_TicksToMSecs(tick_use);
throuth_mb = throuth_kb/1000;
CMD_DBG("%s mult blocks read ok, ", __func__);
if (bench_size <= 512)
CMD_LOG(CMD_DBG_ON, "0.5");
else
CMD_LOG(CMD_DBG_ON, "%3d", bench_size/1024);
CMD_LOG(CMD_DBG_ON, " KB use:%3d ms, throughput:%d.%d MB/S\n",
(uint32_t)OS_TicksToMSecs(tick_use),
throuth_mb, throuth_kb - throuth_mb);
}
err = 0;
for (int j = 0; j < bench_size/4; j++) {
if (((unsigned int *)buf)[j] != j) {
err = -1;
break;
}
}
if (err) {
CMD_ERR("mmc %d blocks write data err!\n", bench_size/512);
goto next;
}
next:
cmd_free(buf);
if (err)
break;
}
out:
CMD_DBG("%s test end\n", __func__);
mmc_card_close(0);
mmc_test_exit(card->id, 0);
cmd_free(arg);
OS_ThreadDelete(NULL);
}
#define PRESS_FILE_SIZE (20 * 1024 * 1024) /* 20M */
#define PRESS_READ_SIZE 2048
#define PRESS_WRITE_SIZE 8192
static OS_Semaphore_t sem_wait;
static void cmd_sd_press_read_task(void *arg)
{
int32_t err;
struct sd_test_param *param = (struct sd_test_param *)arg;
OS_Time_t tick_now = 0, tick_print = 0;
OS_Time_t tick_end = OS_GetTicks() + OS_MSecsToTicks(param->time_sec * 1000);
uint32_t random_sleep = param->random;
char *buf;
uint32_t start_sector = param->start_sector;
card = mmc_card_open(0);
if (!card) {
CMD_ERR("card open failed!\n");
goto fail;
}
if (param->task_idx == 0) {
buf = cmd_malloc(4096);
for (int i = 0; i < 512 / 4; i++) {
((unsigned int *)buf)[i] = i;
}
memcpy(buf+512, buf, 512);
memcpy(buf+1024, buf, 1024);
memcpy(buf+2048, buf, 2048);
CMD_DBG("%s do nothing until sd card prepare ok!\n", __func__);
for (int i = 0; i < (PRESS_FILE_SIZE+4095)/4096; i++) { /* 10M */
int32_t err;
err = mmc_block_write(card, (uint8_t *)buf,
start_sector + (i * (4096 / 512)),
4096 / 512);
if (err)
goto out;
}
CMD_DBG("%s sd card prepared ok!\n", __func__);
for (int j = 0; j < param->task_num - 1; j++)
OS_SemaphoreRelease(&sem_wait);
cmd_free(buf);
} else {
OS_SemaphoreWait(&sem_wait, OS_WAIT_FOREVER);
}
buf = cmd_malloc(param->sector_num*512);
if (!buf)
goto exit;
if (!random_sleep)
random_sleep = 2;
OS_MSleep(random_sleep);
CMD_DBG("%s id:%d random:%d start_sector:%d\n", __func__, param->task_idx,
random_sleep, start_sector);
while (tick_now < tick_end) {
int j;
err = mmc_block_read(card, (uint8_t *)buf, start_sector, param->sector_num);
if (err) {
CMD_ERR("mmc mult blocks read err!\n");
goto out;
}
err = 0;
for (j = 0; j < param->sector_num*(512/4); j++) {
if (((unsigned int *)buf)[j] != (j & 0x07f)) {
err = -1;
CMD_ERR("%x %x\n", j, ((unsigned int *)buf)[j]);
break;
}
}
if (err) {
CMD_ERR("mmc %d blocks read data err! at sector:%d count:%d\n",
param->sector_num, start_sector, j);
goto out;
} else
;//CMD_DBG("%s mmc blocks read data ok! at sector:%d\n",
// __func__, start_sector);
start_sector += param->sector_num;
if (start_sector >= param->start_sector + PRESS_FILE_SIZE/512) {
start_sector = param->start_sector;
}
OS_MSleep(random_sleep);
tick_now = OS_GetTicks();
if (tick_now >= tick_print + 5000) {
CMD_DBG("%s id:%d testing... at sector:%d\n", __func__,
param->task_idx, start_sector);
tick_print = tick_now;
}
}
out:
CMD_DBG("%s id:%d test end\n", __func__, param->task_idx);
cmd_free(buf);
exit:
mmc_card_close(0);
fail:
cmd_free(param);
if (param->task_idx == 0)
OS_SemaphoreDelete(&sem_wait);
OS_ThreadDelete(NULL);
}
static void cmd_sd_press_write_task(void *arg)
{
int32_t err;
struct sd_test_param *param = (struct sd_test_param *)arg;
OS_Time_t tick_now = 0, tick_print = 0;
OS_Time_t tick_end = OS_GetTicks() + OS_MSecsToTicks(param->time_sec * 1000);
uint32_t random_sleep = param->random;
char *buf;
uint32_t start_sector = param->start_sector;
uint32_t round = 0;
uint32_t total_num;
card = mmc_card_open(0);
if (!card) {
CMD_ERR("card open failed!\n");
goto fail;
}
buf = cmd_malloc(param->sector_num * 512);
if (!buf)
goto out;
for (int i = 0; i < 512 / 4; i++)
((unsigned int *)buf)[i] = i;
for (int i = 1; i < param->sector_num; i++)
memcpy(buf + i * 512, buf, 512);
if (!random_sleep)
random_sleep = 2;
OS_MSleep(random_sleep);
CMD_DBG("%s id:%d random:%d\n", __func__, param->task_idx, random_sleep);
while (tick_now < tick_end) {
err = mmc_block_write(card, (uint8_t *)buf, start_sector, param->sector_num);
if (err) {
CMD_ERR("mmc mult blocks write err!\n");
goto out;
}
start_sector += param->sector_num;
if (start_sector >= param->start_sector + PRESS_FILE_SIZE / 512) {
start_sector = param->start_sector;
round = 1;
}
OS_MSleep(random_sleep);
tick_now = OS_GetTicks();
if (tick_now >= tick_print + 5000) {
CMD_DBG("%s id:%d testing... at sector:%d\n", __func__,
param->task_idx, start_sector);
tick_print = tick_now;
}
}
CMD_DBG("%s test end. round:%d start_sector:%d end_sector:%d\n", __func__,
round, param->start_sector, start_sector);
if (round) {
total_num = PRESS_FILE_SIZE / 512;
} else {
// BUG_ON(start_sector <= param->start_sector);
total_num = start_sector - param->start_sector;
}
total_num /= param->sector_num;
start_sector = param->start_sector;
CMD_DBG("%s test checking... start_sector:%d total_num:%d\n", __func__,
start_sector, total_num);
for (int i = 0; i < total_num; i++) {
int j;
memset(buf, 0, param->sector_num * 512);
err = mmc_block_read(card, (uint8_t *)buf, start_sector, param->sector_num);
if (err) {
CMD_ERR("mmc mult blocks read err!\n");
goto out;
}
err = 0;
for (j = 0; j < param->sector_num * (512 / 4); j++) {
if (((unsigned int *)buf)[j] != (j & 0x07f)) {
err = -1;
break;
}
}
if (err) {
CMD_ERR("%x %x\n", ((unsigned int *)buf)[j], (j & 0x07f));
CMD_ERR("mmc %d blocks write data err! at sector:%d count:%d\n",
param->sector_num, start_sector, j);
goto out;
} else
;//CMD_DBG("%s mmc blocks write data ok! at sector:%d\n",
// __func__, start_sector);
start_sector += param->sector_num;
}
out:
mmc_card_close(0);
CMD_DBG("%s id:%d test end\n", __func__, param->task_idx);
cmd_free(buf);
fail:
cmd_free(param);
OS_ThreadDelete(NULL);
}
/*
* drv sd bench s=<Start_Sector>
*/
static enum cmd_status cmd_sd_bench_exec(char *cmd)
{
OS_Thread_t thread;
char *param;
uint32_t len;
len = strlen(cmd);
if (len >= CMD_ARG_LEN) {
CMD_ERR("should adjust CMD_ARG_LEN to %d\n", len);
return CMD_STATUS_FAIL;
}
param = cmd_malloc(CMD_ARG_LEN);
if (!param)
return CMD_STATUS_FAIL;
memcpy(param, cmd, len);
param[len+1] = 0;
OS_ThreadSetInvalid(&thread);
if (OS_ThreadCreate(&thread,
"",
cmd_sd_bench_task,
param,
OS_THREAD_PRIO_APP,
2 * 1024) != OS_OK) {
CMD_ERR("create sd bench test task failed\n");
return CMD_STATUS_FAIL;
}
return CMD_STATUS_OK;
}
/*
* drv sd press r=<threads_num> s=<Start_Sector> n=<sector_num> w=<threads_num>
* s=<Start_Sector> n=<sector_num> t=<secons>
* eg:
* drv sd press r=2 s=200000 n=20 w=2 s=400000 n=20 t=600
*/
static enum cmd_status cmd_sd_press_exec(char *cmd)
{
OS_Thread_t thread;
struct sd_test_param *param;
uint32_t r_threads, w_threads;
uint32_t r_secnum, w_secnum;
uint32_t cnt;
uint32_t time_sec;
uint32_t start_rsector, start_wsector;
cnt = cmd_sscanf(cmd, "r=%d s=%d n=%d w=%d s=%d n=%d t=%d",
&r_threads, &start_rsector, &r_secnum,
&w_threads, &start_wsector, &w_secnum, &time_sec);
if (cnt != 7) {
CMD_ERR("invalid argument %s\n", cmd);
return CMD_STATUS_FAIL;
}
OS_SemaphoreCreate(&sem_wait, 0, OS_SEMAPHORE_MAX_COUNT);
OS_MSleep(5);
for (uint32_t i = 0; i < r_threads; i++) {
param = cmd_malloc(sizeof(struct sd_test_param));
if (!param)
return CMD_STATUS_FAIL;
param->task_idx = i;
param->task_num = r_threads;
param->start_sector = start_rsector;
param->sector_num = r_secnum;
param->time_sec = time_sec;
param->random = rand() % 8 + i;
if (!r_secnum || time_sec < 2) {
CMD_ERR("%s read n=<sector_num> should not 0 !\n", __func__);
cmd_free(param);
goto out;
}
OS_ThreadSetInvalid(&thread);
if (OS_ThreadCreate(&thread,
"",
cmd_sd_press_read_task,
param,
OS_THREAD_PRIO_APP,
2 * 1024) != OS_OK) {
CMD_ERR("create sd press read task:%d failed\n", i);
return CMD_STATUS_FAIL;
}
(void)cmd_sd_press_read_task;
OS_MSleep(2);
}
for (uint32_t i = 0; i < w_threads; i++) {
param = cmd_malloc(sizeof(struct sd_test_param));
if (!param)
return CMD_STATUS_FAIL;
param->task_idx = i;
param->task_num = w_threads;
param->start_sector = start_wsector;
param->sector_num = w_secnum;
param->time_sec = time_sec;
param->random = rand() % 20 + i;
if (!w_secnum || time_sec < 2) {
CMD_ERR("%s write n=<sector_num> should not 0 !\n", __func__);
cmd_free(param);
goto out;
}
OS_ThreadSetInvalid(&thread);
if (OS_ThreadCreate(&thread,
"",
cmd_sd_press_write_task,
param,
OS_THREAD_PRIO_APP,
2 * 1024) != OS_OK) {
CMD_ERR("create sd press write task:%d failed\n", i);
return CMD_STATUS_FAIL;
}
OS_MSleep(2);
}
out:
return CMD_STATUS_OK;
}
#if CMD_DESCRIBE
#define sd_init_help_info \
"init sd card, sd init [<card_id> <debug_mask>]\n"\
"\t\t\tsd init\n"\
"\t\t\tsd init 0 0x7f"
#define sd_deinit_help_info \
"deinit sd card, sd deinit [<card_id> <host_id>]\n"\
"\t\t\tsd deinit\n"\
"\t\t\tsd deinit 0 0"
#define sd_scan_help_info \
"scan sd card, sd scan [<card_id> <host_id> <card_type> <debug_mask>]\n"\
"\t\t\tsd scan\n"\
"\t\t\tsd scan 0 0 2 0x7f"
#define sd_read_help_info "read data, sd read s=<Start_Sector> n=<sector_num>"
#define sd_test_help_info \
"write data, sd test [<host_id> <cd_mode> <sdc_degmask> <card_dbgmask>]\n"\
"\t\t\tsd test 0 3 0x3c 0x3c\n"\
"\t\t\tsd test 0 2 0x3c 0x3c"
#define sd_bench_help_info "bench sd card, sd bench s=<Start_Sector>"
#define sd_press_help_info \
"press sd card, sd press r=<threads_num> s=<Start_Sector> n=<sector_num> w=<threads_num> s=<Start_Sector> n=<sector_num> t=<secons>\n"\
"\t\t\tsd test 0 3 0x3c 0x3c\n"\
"\t\t\tsd test 0 2 0x3c 0x3c"
#endif
static enum cmd_status cmd_sd_help_exec(char *cmd);
static const struct cmd_data g_sd_cmds[] = {
{ "init", cmd_sd_init_exec, CMD_DESC(sd_init_help_info) },
{ "deinit", cmd_sd_deinit_exec, CMD_DESC(sd_deinit_help_info) },
{ "scan", cmd_sd_scan_exec, CMD_DESC(sd_scan_help_info) },
{ "read", cmd_sd_read_exec, CMD_DESC(sd_read_help_info) },
{ "test", cmd_sd_test_exec, CMD_DESC(sd_test_help_info) },
{ "bench", cmd_sd_bench_exec, CMD_DESC(sd_bench_help_info) },
{ "press", cmd_sd_press_exec, CMD_DESC(sd_press_help_info) },
{ "help", cmd_sd_help_exec, CMD_DESC(CMD_HELP_DESC) },
};
static enum cmd_status cmd_sd_help_exec(char *cmd)
{
return cmd_help_exec(g_sd_cmds, cmd_nitems(g_sd_cmds), 8);
}
enum cmd_status cmd_sd_exec(char *cmd)
{
return cmd_exec(cmd, g_sd_cmds, cmd_nitems(g_sd_cmds));
}
#endif