2025-10-10 16:07:00 +08:00

1238 lines
28 KiB
C
Executable File

// Copyright 2022-2023 Beken
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <os/mem.h>
#include "string.h"
#include <common/bk_include.h>
#include "bk_uart.h"
#include "sdio_utils.h"
#include "sdio_slave_driver.h"
#include "sdio_test.h"
#if CONFIG_TRNG_SUPPORT
#include "driver/trng.h"
#endif
#include <driver/aon_rtc.h>
#include "driver/wdt.h"
#include "bk_wdt.h"
#if CONFIG_SDIO_TEST_EN
static bool s_sdio_test_inited = false;
static beken_queue_t s_sdio_test_msg_que = NULL;
static beken_thread_t s_test_sdio_thread = NULL;
static volatile uint8_t s_sdio_test_main_case;
static volatile uint8_t s_sdio_test_sub_case;
#define SDIO_CHAN_MAX_CNT 2
//static beken_thread_t s_sdio_test_thread_handle = NULL;
#define SDIO_BUFFER_SIZE 2048
//tx/rx has seperate thread, then it can random tx/rx, on only one thread, tx/rx has to one by one
static beken_thread_t s_tx_thread_handle[SDIO_CHAN_MAX_CNT];
static beken_queue_t s_sdio_ch_x_tx_msg_que[SDIO_CHAN_MAX_CNT];
static volatile uint32_t s_tx_tp_sub_case[SDIO_CHAN_MAX_CNT];
static beken_thread_t s_rx_thread_handle[SDIO_CHAN_MAX_CNT];
static beken_queue_t s_sdio_ch_x_rx_msg_que[SDIO_CHAN_MAX_CNT];
static volatile uint32_t s_rx_tp_sub_case[SDIO_CHAN_MAX_CNT];
static sdio_tp_statisic_t s_tx_tp_statistic[SDIO_CHAN_MAX_CNT];
static sdio_tp_statisic_t s_rx_tp_statistic[SDIO_CHAN_MAX_CNT];
#if CONFIG_TRNG_SUPPORT
static uint32_t wait_ms = 3000;
static uint32_t rx_wait_ms = 0;
#endif
#if 0
static bk_err_t sdio_test_tx_cb(sdio_node_ptr_t head_p, sdio_node_ptr_t tail_p, uint32_t count)
{
bk_err_t ret = BK_OK;
sdio_node_ptr_t cur_p = head_p;
uint32_t i = count, j = 0;
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
//check tx data after finish
while(cur_p && (i > 0))
{
for(j = 0; j < cur_p->len; j += 4)
{
os_printf("0x%08x ", *(uint32_t *)((uint8_t *)cur_p + (sizeof(sdio_node_t)) + j));
if(j % 16 == 0)
os_printf("\r\n");
}
cur_p = cur_p->next;
i--;
}
//TODO:release buffer
//WARNING: Application should should use self CHAN_ID and CHAN_DIRECT.
bk_sdio_chan_push_free_list(SDIO_CHAN_PLATFORM, SDIO_CHAN_TX, head_p, tail_p, count);
//notify app task finish read
SDIO_LOG_DEBUG_FUNCTION_EXIT();
return ret;
}
#else
static bk_err_t sdio_test_tx_cb( sdio_node_ptr_t head_p, sdio_node_ptr_t tail_p, uint32_t count)
{
bk_err_t ret = BK_OK;
sdio_chan_id_t chan_id = SDIO_CHAN_PLATFORM;
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
if(s_sdio_ch_x_tx_msg_que[chan_id % SDIO_CHAN_MAX_CNT])
{
sdio_test_tp_msg_t msg;
msg.param1 = chan_id % SDIO_CHAN_MAX_CNT;
msg.param2 = (uint32_t)head_p;
msg.param3 = (uint32_t)tail_p;
msg.param4 = count;
ret = rtos_push_to_queue(&s_sdio_ch_x_tx_msg_que[chan_id % SDIO_CHAN_MAX_CNT], &msg, BEKEN_NO_WAIT);
if (kNoErr != ret)
{
SDIO_LOG_ERR("sdio test tx msg failed\r\n");
}
}
else //sync:
{
//TODO:release buffer to free list mem-pool
//WARNING: Application should should use self CHAN_ID and CHAN_DIRECT.
ret = bk_sdio_chan_push_free_list(chan_id, SDIO_CHAN_TX, head_p, tail_p, count);
if(ret)
{
SDIO_LOG_ERR("err release buff");
}
}
SDIO_LOG_DEBUG_FUNCTION_EXIT();
//notify app task finish write
return ret;
}
#endif
static bk_err_t sdio_test_tx_init(uint32_t chan_id, uint32_t buf_cnt, uint32_t buf_size)
{
bk_err_t ret = BK_OK;
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
ret = bk_sdio_init_channel(chan_id, SDIO_CHAN_TX, buf_cnt, buf_size);
if(ret != BK_OK)
{
SDIO_LOG_ERR("init channel");
return ret;
}
bk_sdio_register_chan_cb(chan_id, SDIO_CHAN_TX, (sdio_chan_cb_t)sdio_test_tx_cb);
SDIO_LOG_DEBUG_FUNCTION_EXIT();
return ret;
}
////////////////////////////////////////////
volatile uint8_t g_sdio_log_level = SDIO_LOG_DEBUG_LEVEL;
void sdio_set_log_level(uint8_t level)
{
SDIO_LOG_ERR("%s:%d", __func__, level);
g_sdio_log_level = level;
}
void sdio_set_tx_delay_time(uint32_t time_ms){
wait_ms = time_ms;
}
void sdio_set_rx_delay_time(uint32_t time_ms){
rx_wait_ms = time_ms;
}
extern uint32_t sdio_list_compute_total_length(sdio_list_t *list_p);
static void sdio_test_tx_tp_thread(void *arg)
{
bk_err_t ret = BK_OK;
sdio_chan_id_t chan_id = (sdio_chan_id_t)arg;
uint32_t val_test[SDIO_CHAN_MAX_CNT] = {0};
struct timeval rtc_start_time = {0, 0};
#if (CONFIG_TASK_WDT)
bk_task_wdt_stop();
#endif
while(1)
{
sdio_test_tp_msg_t msg;
sdio_node_ptr_t buf_p = NULL;
uint32_t len = SDIO_TEST_BUFFER_SIZE * SDIO_TEST_BUFFER_CNT;
uint32_t size = 0;
if(s_tx_tp_sub_case[chan_id] == 0)
{
#if (CONFIG_TRNG_SUPPORT)
//wait_ms = bk_rand() % 1000;
//rtos_delay_milliseconds(wait_ms);
#endif
if(s_tx_tp_statistic[chan_id].end_time)
{
sdio_set_log_level(SDIO_LOG_DEBUG_LEVEL);
SDIO_LOG_ERR("TP:start_t=%u,end_t=%u, period_t=%u, cnt=%d,len=%d",
(uint32_t)s_tx_tp_statistic[chan_id].start_time,
(uint32_t)s_tx_tp_statistic[chan_id].end_time,
(uint32_t)(s_tx_tp_statistic[chan_id].end_time - s_tx_tp_statistic[chan_id].start_time),
s_tx_tp_statistic[chan_id].payload_cnt,
s_tx_tp_statistic[chan_id].total_len);
}
s_tx_tp_statistic[chan_id].start_time = 0;
s_tx_tp_statistic[chan_id].end_time = 0;
continue;
}
else if(s_tx_tp_statistic[chan_id].start_time == 0) //start, first entry
{
sdio_set_log_level(SDIO_LOG_ERR_LEVEL);
//s_tx_tp_statistic[chan_id].start_time = riscv_get_mtimer();
bk_rtc_gettimeofday(&rtc_start_time, 0);
s_tx_tp_statistic[chan_id].start_time = 1000000 * (rtc_start_time.tv_sec) + rtc_start_time.tv_usec;
}
//request write buf
ret = bk_sdio_chan_pop_free_node(chan_id, SDIO_CHAN_TX, &buf_p, &size);
if((ret == BK_OK) && buf_p)
{
s_tx_tp_statistic[chan_id].payload_cnt++;
#if (CONFIG_TRNG_SUPPORT)
//len = bk_rand() % SDIO_TEST_BUFFER_SIZE;
#endif
SDIO_LOG_INFO("pop node, len = %d, size = %d\n", len, size);
len = len < size? len : size;
uint32_t *ptmp = (uint32_t *)((uint8_t *)buf_p + sizeof(sdio_node_t));
for (int i = 0; i < len/4; i++) {
//*ptmp = val_test[chan_id] + 0x10000000 * (chan_id);
*ptmp = val_test[chan_id] + (0x90000000);
ptmp++;
}
SDIO_LOG_INFO("val_test[%d] = 0x%x\n", chan_id, val_test[chan_id]);
val_test[chan_id]++;
#if 0
buf_p->pbd.len = len + sizeof(sdio_sw_pbd_t); //SDIO ASIC will read this value to SDIO FIFO
buf_p->sw_pbd.len = len; //valid data size, exclude sdio_sw_pbd_t
buf_p->sw_pbd.type = sdio_get_core_id();
buf_p->sw_pbd.sub_type = chan_id;
#else
buf_p->len = len;
#endif
#if (CONFIG_TRNG_SUPPORT)
//wait_ms = bk_rand() % 20;
rtos_delay_milliseconds(wait_ms);
#endif
//request read
#if CONFIG_SDIO_SYNC_TRANS
ret = bk_sdio_slave_sync_write(chan_id, buf_p, buf_p, 1, BEKEN_WAIT_FOREVER);
#else
ret = bk_sdio_slave_sync_write(chan_id, buf_p, buf_p, 1);
#endif
if(ret)
{
SDIO_LOG_ERR("write fail");
}
}
else
{
SDIO_LOG_ERR("no free buff");
}
//wait write finish
ret = rtos_pop_from_queue(&s_sdio_ch_x_tx_msg_que[chan_id], &msg, SDIO_TEST_TP_MSG_WAIT_TIME);
if (kNoErr == ret)
{
sdio_list_t list;
//deal APP data
list.head = (sdio_node_ptr_t)msg.param2;
list.tail = (sdio_node_ptr_t)msg.param3;
list.count = msg.param4;
s_tx_tp_statistic[chan_id].total_len += sdio_list_compute_total_length(&list);
//release buffer
ret = bk_sdio_chan_push_free_list(chan_id, SDIO_CHAN_TX, list.head, list.tail, list.count);
} else {
SDIO_LOG_ERR("TX Tp rtos_pop_from_queue error\r\n");
}
}
SDIO_LOG_DEBUG_FUNCTION_EXIT();
}
static bk_err_t sdio_test_tx_tp_init(uint32_t chan_id, uint32_t buf_cnt, uint32_t buf_size)
{
bk_err_t ret = BK_OK;
char str_name[64];
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
#if (CONFIG_TRNG_SUPPORT)
bk_trng_start();
#endif
//tx hasn't init thread
if(s_tx_thread_handle[chan_id] == NULL)
{
memset(str_name, 0, sizeof(str_name));
snprintf(str_name, sizeof(str_name), "%s_ch%d_dir%d", SDIO_TEST_TP_THREAD_NAME, (int32_t)chan_id, SDIO_CHAN_TX);
ret = rtos_create_thread(
&s_tx_thread_handle[chan_id],
SDIO_TEST_TX_TP_PRIORITY+chan_id,
str_name,
sdio_test_tx_tp_thread,
SDIO_TEST_TX_TP_THREAD_STACK_SIZE,
(beken_thread_arg_t)chan_id
);
if (kNoErr != ret)
{
SDIO_LOG_ERR("init thread ret=%d", ret);
return ret;
}
}
//tx notify queue init
if(s_sdio_ch_x_tx_msg_que[chan_id] == NULL)
{
memset(str_name, 0, sizeof(str_name));
snprintf(str_name, sizeof(str_name), "%s_ch%d", SDIO_TEST_TX_TP_MSG_QUEUE_NAME, (int32_t)chan_id);
ret = rtos_init_queue(&s_sdio_ch_x_tx_msg_que[chan_id],
str_name,
sizeof(sdio_test_tp_msg_t),
SDIO_TEST_TX_TP_MSG_QUEUE_COUNT
);
if (kNoErr != ret)
{
SDIO_LOG_ERR("init queue ret=%d", ret);
return ret;
}
}
ret = sdio_test_tx_init(chan_id, buf_cnt, buf_size);
if (kNoErr != ret)
{
SDIO_LOG_ERR("tx init fail=%d", ret);
return ret;
}
return ret;
}
////////////////////////////////////////////
static bk_err_t sdio_test_tx_sub_case(SDIO_TEST_MSG_T *msg_p)
{
bk_err_t ret = BK_OK;
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
switch(msg_p->sub_case)
{
//chan id, buf_cnt, buf_size
case SDIO_TEST_TX_INIT:
{
sdio_chan_id_t id = msg_p->param1;
uint32_t buf_size = msg_p->param2;
uint32_t buf_cnt = msg_p->param3;
ret = sdio_test_tx_init(id, buf_cnt, buf_size);
break;
}
//len, value
case SDIO_TEST_TX_SINGLE_PACKET:
{
sdio_node_ptr_t buf_p = NULL;
uint32_t len = msg_p->param1;
uint32_t value = (uint32_t)msg_p->param2;
uint32_t size;
ret = bk_sdio_chan_pop_free_node(SDIO_CHAN_PLATFORM, SDIO_CHAN_TX, &buf_p, &size);
if((ret == BK_OK) && buf_p)
{
//fill data
if(len > size)
{
len = size;
SDIO_LOG_ERR("max packet size=%d, len=%d", size, len);
}
if(value == 12345678) {
#if 0
for (int i = 0; i < len; i++) {
//buf_p[i]
*((uint8_t *)(buf_p + sizeof(sdio_node_t) + i)) = i & 0xff;
}
#else
memset((uint8_t *)buf_p + sizeof(sdio_node_t), 0, len);
uint8_t *send_data = (uint8_t *)os_zalloc(len);
if (send_data == NULL) {
os_printf("send buffer malloc failed\r\n");
break;
}
for (int i = 0; i < len; i++) {
send_data[i] = i & 0xff;
}
memcpy((uint8_t *)buf_p + sizeof(sdio_node_t), send_data, len);
os_free(send_data);
#endif
} else {
memset((uint8_t *)buf_p + sizeof(sdio_node_t), value, len);
}
buf_p->len = len;
//request write
#if CONFIG_SDIO_SYNC_TRANS
ret = bk_sdio_slave_sync_write(SDIO_CHAN_PLATFORM, buf_p, buf_p, 1, BEKEN_WAIT_FOREVER);
#else
ret = bk_sdio_slave_sync_write(SDIO_CHAN_PLATFORM, buf_p, buf_p, 1);
#endif
}
else
{
SDIO_LOG_ERR("no free buff");
ret = BK_FAIL;
}
break;
}
case SDIO_TEST_TX_MANY_SINGLE_PACKETS:
{
break;
}
case SDIO_TEST_TX_MULTI_PACKETS:
{
break;
}
//chan id, buf_cnt, buf_size
case SDIO_TEST_TX_TP_INIT:
{
sdio_chan_id_t chan_id = msg_p->param1;
uint32_t buf_size = msg_p->param2;
uint32_t buf_cnt = msg_p->param3;
ret = sdio_test_tx_tp_init(chan_id, buf_cnt, buf_size);
break;
}
//len, value
case SDIO_TEST_TX_TP_START:
{
sdio_chan_id_t chan_id = msg_p->param1 % SDIO_CHAN_MAX_CNT;
wait_ms = msg_p->param2;
s_tx_tp_sub_case[chan_id] = 1;
break;
}
case SDIO_TEST_TX_TP_STOP:
{
sdio_chan_id_t chan_id = msg_p->param1 % SDIO_CHAN_MAX_CNT;
struct timeval rtc_end_time = {0, 0};
bk_rtc_gettimeofday(&rtc_end_time, 0);
s_tx_tp_statistic[chan_id].end_time = 1000000 * (rtc_end_time.tv_sec) + rtc_end_time.tv_usec;
s_tx_tp_sub_case[chan_id] = 0;
break;
}
#if CONFIG_SDIO_SYNC_TRANS
case SDIO_TEST_TX_SINGLE_BUF:
{
extern bk_err_t bk_sdio_slave_tx(char* buf_p, uint32_t len, uint32_t timeout_ms);
uint32_t timeout = 20000;
uint32_t buf_len = msg_p->param1;
uint8_t *send_data = (uint8_t *)os_zalloc(buf_len);
if (send_data == NULL) {
SDIO_LOG_ERR("send buffer malloc failed\r\n");
return ret;
}
for (int i = 0; i < buf_len; i++) {
send_data[i] = i & 0xff;
}
bk_sdio_slave_tx((char* )send_data, buf_len, timeout);
if (send_data) {
os_free(send_data);
}
send_data = NULL;
SDIO_LOG_INFO("sdio send raw data, data_len=%d\n", buf_len);
break;
}
#endif
default:
break;
}
SDIO_LOG_DEBUG_FUNCTION_EXIT();
return ret;
}
#if 0
static bk_err_t sdio_test_rx_cb(sdio_node_ptr_t head_p, sdio_node_ptr_t tail_p, uint32_t count)
{
bk_err_t ret = BK_OK;
sdio_node_ptr_t cur_p = head_p;
uint32_t i = count, j = 0;
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
//deal data
while(cur_p && (i > 0))
{
for(j = 0; j < cur_p->len; j += 4)
{
os_printf("0x%08x ", *(uint32_t *)((uint8_t *)cur_p + (sizeof(sdio_node_t)) + j));
if(j % 16 == 0)
os_printf("\r\n");
}
cur_p = cur_p->next;
i--;
}
//TODO:release buffer to free list mem-pool
//WARNING: Application should should use self CHAN_ID and CHAN_DIRECT.
ret = bk_sdio_chan_push_free_list(SDIO_CHAN_PLATFORM, SDIO_CHAN_RX, head_p, tail_p, count);
SDIO_LOG_DEBUG_FUNCTION_EXIT();
return ret;
}
#else
static bk_err_t sdio_test_rx_cb( sdio_node_ptr_t head_p, sdio_node_ptr_t tail_p, uint32_t count)
{
bk_err_t ret = BK_OK;
static uint32_t rx_val_test[SDIO_CHAN_MAX_CNT] = {0};
int print_len = 2048;
sdio_chan_id_t chan_id = SDIO_CHAN_PLATFORM;
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
//async: notify APP rx thread, default usage method
if(s_sdio_ch_x_rx_msg_que[chan_id % SDIO_CHAN_MAX_CNT])
{
//dump received data to check data validation
sdio_node_ptr_t cur_p = head_p;
uint32_t i = count, j = 0;
while(cur_p && (i > 0))
{
//not print received data by default
#if 0
os_printf("core_id=0x%x, payload cur_p=0x%08x \r\n", chan_id, cur_p);
for(j = 0; j < print_len; j += sizeof(uint32_t))
{
os_printf("0x%08x ", *(uint32_t *)((uint8_t *)cur_p + (sizeof(sdio_node_t)) + j));
if(j && (j % 16 == 0))
os_printf("\r\n");
}
#else
for (j = 4; j < print_len - 4; j += sizeof(uint32_t)) {
if(*(uint32_t *)((uint8_t *)cur_p + (sizeof(sdio_node_t)) + j) != (rx_val_test[chan_id] + 0x10000000 * (chan_id))) {
os_printf("rx_tp_cb error, cur_p_word[%d] = 0x%x, correct value is 0x%x.\n" , j, *(uint32_t *)((uint8_t *)cur_p + (sizeof(sdio_node_t)) + j), (rx_val_test[chan_id] + 0x10000000 * (chan_id)) );
}
}
#endif
rx_val_test[chan_id]++;
cur_p = (sdio_node_ptr_t)cur_p->next;
i--;
}
/////////////////
sdio_test_tp_msg_t msg;
msg.param1 = chan_id % SDIO_CHAN_MAX_CNT;
msg.param2 = (uint32_t)head_p;
msg.param3 = (uint32_t)tail_p;
msg.param4 = count;
ret = rtos_push_to_queue(&s_sdio_ch_x_rx_msg_que[chan_id % SDIO_CHAN_MAX_CNT], &msg, BEKEN_NO_WAIT);
if (kNoErr != ret)
{
SDIO_LOG_ERR("sdio test rx msg failed\r\n");
}
}
else //sync:
{
sdio_node_ptr_t cur_p = head_p;
uint32_t i = count, j = 0;
//deal data
while(cur_p && (i > 0))
{
os_printf("sync: chan_id=0x%x, payload cur_p=0x%08x \r\n", chan_id, cur_p);
for(j = 0; j < print_len; j += sizeof(uint32_t))
{
os_printf("0x%08x ", *(uint32_t *)((uint8_t *)cur_p + (sizeof(sdio_node_t)) + j));
if(j && (j % 16 == 0))
os_printf("\r\n");
}
#if 0
extern uint32_t looptest_flag;
if (looptest_flag == 1) {
for (j = 0; j < (cur_p->sw_pbd.len - 4); j++) {
if( *((uint8_t *)cur_p + (sizeof(sdio_node_t)) + j) != ((j + 0x84) % 256)) {
os_printf("loopback error, cur_p_byte[%d] = 0x%x, correct value is 0x%x.\n" , j, *((uint8_t *)cur_p + (sizeof(sdio_node_t)) + j), ((j + 0x80) % 256) );
}
}
}
#endif
os_printf("\r\n");
cur_p = (sdio_node_ptr_t)cur_p->next;
i--;
}
//TODO:release buffer to free list mem-pool
//WARNING: Application should should use self CHAN_ID and CHAN_DIRECT.
ret = bk_sdio_chan_push_free_list(chan_id, SDIO_CHAN_RX, head_p, tail_p, count);
}
SDIO_LOG_DEBUG_FUNCTION_EXIT();
return ret;
}
#endif
static bk_err_t sdio_test_rx_init(uint32_t chan_id, uint32_t buf_cnt, uint32_t buf_size)
{
bk_err_t ret = BK_OK;
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
ret = bk_sdio_init_channel(chan_id, SDIO_CHAN_RX, buf_cnt, buf_size);
if(ret != BK_OK)
{
SDIO_LOG_ERR("init channel");
return ret;
}
ret = bk_sdio_register_chan_cb(chan_id, SDIO_CHAN_RX, (sdio_chan_cb_t)sdio_test_rx_cb);
SDIO_LOG_DEBUG_FUNCTION_EXIT();
return ret;
}
///////////////////////////////////////////////////////////
//one channel one thread
static void sdio_test_rx_tp_thread(void *arg)
{
bk_err_t ret = BK_OK;
sdio_chan_id_t chan_id = (sdio_chan_id_t)arg%SDIO_CHAN_MAX_CNT;
struct timeval rtc_start_time = {0, 0};
#if (CONFIG_TASK_WDT)
bk_task_wdt_stop();
#endif
while(1)
{
sdio_test_tp_msg_t msg;
sdio_node_ptr_t buf_p = NULL;
uint32_t len = SDIO_TEST_BUFFER_SIZE * SDIO_TEST_BUFFER_CNT ;
#if 0
uint32_t value = 0;
#endif
uint32_t size = 0;
#if (CONFIG_TRNG_SUPPORT)
//rx_wait_ms = bk_rand() % 1000;
#endif
//rtos_delay_milliseconds(rx_wait_ms);
if(s_rx_tp_sub_case[chan_id] == 0) //stop status
{
if(s_rx_tp_statistic[chan_id].end_time)
{
sdio_set_log_level(SDIO_LOG_DEBUG_LEVEL);
SDIO_LOG_ERR("TP:start_t=%u,end_t=%u,period_t=%u,cnt=%d,len=%d",
(uint32_t)s_rx_tp_statistic[chan_id].start_time,
(uint32_t)s_rx_tp_statistic[chan_id].end_time,
(uint32_t)(s_rx_tp_statistic[chan_id].end_time - s_rx_tp_statistic[chan_id].start_time),
s_rx_tp_statistic[chan_id].payload_cnt,
s_rx_tp_statistic[chan_id].total_len);
}
s_rx_tp_statistic[chan_id].start_time = 0;
s_rx_tp_statistic[chan_id].end_time = 0;
continue;
}
else if(s_rx_tp_statistic[chan_id].start_time == 0) //start, first entry
{
sdio_set_log_level(SDIO_LOG_ERR_LEVEL);
bk_rtc_gettimeofday(&rtc_start_time, 0);
s_rx_tp_statistic[chan_id].start_time = 1000000 * (rtc_start_time.tv_sec) + rtc_start_time.tv_usec;
}
//request read buf
ret = bk_sdio_chan_pop_free_node(chan_id, SDIO_CHAN_RX, &buf_p, &size);
if((ret == BK_OK) && buf_p)
{
s_rx_tp_statistic[chan_id].payload_cnt++;
len = len < size? len : size;
#if 0
//fill dirty data
if(value == 12345678)
{
for(uint32_t i = 0; i < len; i++)
*(uint8_t *)((uint8_t *)buf_p + sizeof(sdio_node_t) + i) = i & 0xff;
}
else
{
memset((uint8_t *)buf_p + sizeof(sdio_node_t), value, len);
}
#endif
#if 0
buf_p->pbd.len = len + sizeof(sdio_sw_pbd_t); //SDIO ASIC will read this value to SDIO FIFO
buf_p->sw_pbd.len = len; //valid data size, exclude sdio_sw_pbd_t
#else
buf_p->len = len;
#endif
//request read
#if CONFIG_SDIO_SYNC_TRANS
ret = bk_sdio_slave_sync_read(chan_id, buf_p, buf_p, 1, BEKEN_WAIT_FOREVER);
#else
ret = bk_sdio_slave_sync_read(chan_id, buf_p, buf_p, 1);
#endif
}
else
{
#if (CONFIG_TRNG_SUPPORT)
//rx_wait_ms = bk_rand() % 1000;
#endif
//SDIO_LOG_DEBUG("rx tp no free node, all nodes poped.");
//SDIO_LOG_ERR("rx tp no free node, all nodes poped.");
//rtos_delay_milliseconds(rx_wait_ms);
}
//wait read finish
#if (CONFIG_TRNG_SUPPORT)
//rx_wait_ms = bk_rand() % 10;
#endif
ret = rtos_pop_from_queue(&s_sdio_ch_x_rx_msg_que[chan_id], &msg, SDIO_TEST_TP_MSG_WAIT_TIME);
if (kNoErr == ret)
{
sdio_list_t list;
//deal APP data
list.head = (sdio_node_ptr_t)msg.param2;
list.tail = (sdio_node_ptr_t)msg.param3;
list.count = msg.param4;
s_rx_tp_statistic[chan_id].total_len += sdio_list_compute_total_length(&list);
//release buffer
ret = bk_sdio_chan_push_free_list(chan_id, SDIO_CHAN_RX, list.head, list.tail, list.count);
} else {
//SDIO_LOG_ERR("RX rtos_pop_from_queue error\r\n");
}
}
SDIO_LOG_DEBUG_FUNCTION_EXIT();
}
static bk_err_t sdio_test_rx_tp_init(uint32_t chan_id, uint32_t buf_cnt, uint32_t buf_size)
{
bk_err_t ret = BK_OK;
char str_name[64];
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
//rx hasn't init thread
if(s_rx_thread_handle[chan_id] == NULL)
{
memset(str_name, 0, sizeof(str_name));
snprintf(str_name, sizeof(str_name), "%s_ch%d_dir%d", SDIO_TEST_TP_THREAD_NAME, (int32_t)chan_id, SDIO_CHAN_RX);
ret = rtos_create_thread(
&s_rx_thread_handle[chan_id],
SDIO_TEST_RX_TP_PRIORITY+chan_id,
str_name,
sdio_test_rx_tp_thread,
SDIO_TEST_RX_TP_THREAD_STACK_SIZE,
(beken_thread_arg_t)chan_id
);
if (kNoErr != ret)
{
SDIO_LOG_ERR("init thread ret=%d", ret);
return ret;
}
}
//rx notify queue init
if(s_sdio_ch_x_rx_msg_que[chan_id] == NULL)
{
memset(str_name, 0, sizeof(str_name));
snprintf(str_name, sizeof(str_name), "%s_ch%d", SDIO_TEST_RX_TP_MSG_QUEUE_NAME, (int32_t)chan_id);
ret = rtos_init_queue(&s_sdio_ch_x_rx_msg_que[chan_id],
str_name,
sizeof(sdio_test_tp_msg_t),
SDIO_TEST_RX_TP_MSG_QUEUE_COUNT
);
if (kNoErr != ret)
{
SDIO_LOG_ERR("init queue ret=%d", ret);
return ret;
}
}
ret = sdio_test_rx_init(chan_id, buf_cnt, buf_size);
if (kNoErr != ret)
{
SDIO_LOG_ERR("rx init fail=%d", ret);
return ret;
}
return ret;
}
///////////////////////////////////////////////////////////
static bk_err_t sdio_test_rx_sub_case(SDIO_TEST_MSG_T *msg_p)
{
bk_err_t ret = BK_OK;
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
switch(msg_p->sub_case)
{
//chan id, buf_cnt, buf_size
case SDIO_TEST_RX_INIT:
{
sdio_chan_id_t id = msg_p->param1;
uint32_t buf_size = msg_p->param2;
uint32_t buf_cnt = msg_p->param3;
ret = sdio_test_rx_init(id, buf_cnt, buf_size);
break;
}
//len, value
case SDIO_TEST_RX_SINGLE_PACKET:
{
sdio_node_ptr_t buf_p = NULL;
uint32_t len = msg_p->param1;
uint8_t value = (uint8_t)msg_p->param2;
uint32_t size = 0;
ret = bk_sdio_chan_pop_free_node(SDIO_CHAN_PLATFORM, SDIO_CHAN_RX, &buf_p, &size);
if((ret == BK_OK) && buf_p)
{
len = len < size? len : size;
//fill dirty data
memset((uint8_t *)buf_p + sizeof(sdio_node_t), value, len);
buf_p->len = len;
//request read
#if CONFIG_SDIO_SYNC_TRANS
ret = bk_sdio_slave_sync_read(SDIO_CHAN_PLATFORM, buf_p, buf_p, 1, BEKEN_WAIT_FOREVER);
#else
ret = bk_sdio_slave_sync_read(SDIO_CHAN_PLATFORM, buf_p, buf_p, 1);
#endif
}
else
{
SDIO_LOG_ERR("no free buff");
ret = BK_FAIL;
}
break;
}
case SDIO_TEST_RX_MANY_SINGLE_PACKETS:
{
break;
}
case SDIO_TEST_RX_MULTI_PACKETS:
{
break;
}
//chan id, buf_cnt, buf_size
case SDIO_TEST_RX_TP_INIT:
{
sdio_chan_id_t chan_id = msg_p->param1;
uint32_t buf_size = msg_p->param2;
uint32_t buf_cnt = msg_p->param3;
ret = sdio_test_rx_tp_init(chan_id, buf_cnt, buf_size);
break;
}
//len, value
case SDIO_TEST_RX_TP_START:
{
sdio_chan_id_t chan_id = msg_p->param1 % SDIO_CHAN_MAX_CNT;
rx_wait_ms = msg_p->param2;
s_rx_tp_sub_case[chan_id] = 1;
break;
}
case SDIO_TEST_RX_TP_STOP:
{
sdio_chan_id_t chan_id = msg_p->param1 % SDIO_CHAN_MAX_CNT;
struct timeval rtc_end_time = {0, 0};
bk_rtc_gettimeofday(&rtc_end_time, 0);
s_rx_tp_statistic[chan_id].end_time = 1000000 * (rtc_end_time.tv_sec) + rtc_end_time.tv_usec;
s_rx_tp_sub_case[chan_id] = 0;
break;
}
#if CONFIG_SDIO_SYNC_TRANS
case SDIO_TEST_RX_SINGLE_BUF:
{
extern bk_err_t bk_sdio_slave_rx(char* buf_p, uint32_t len, uint32_t timeout_ms);
uint32_t timeout = 20000;
uint32_t buf_len = msg_p->param1;
uint8_t *recv_data = (uint8_t *)os_malloc(buf_len);
if (recv_data == NULL) {
SDIO_LOG_ERR("recv buffer malloc failed\r\n");
return ret;
}
os_memset(recv_data, 0xff, buf_len);
bk_sdio_slave_rx((char* )recv_data, buf_len, timeout);
SDIO_LOG_INFO("sdio dma recv, data_len=%d\n", buf_len);
for (int i = 0; i < buf_len; i++) {
SDIO_LOG_INFO("recv_buffer[%d]=0x%x\n", i, recv_data[i]);
}
if (recv_data) {
os_free(recv_data);
}
recv_data = NULL;
break;
}
#endif
default:
break;
}
SDIO_LOG_DEBUG_FUNCTION_EXIT();
return ret;
}
static bk_err_t sdio_test_send_msg(SDIO_TEST_MSG_T *msg_p)
{
bk_err_t ret = BK_FAIL;
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
if (s_sdio_test_msg_que)
{
ret = rtos_push_to_queue(&s_sdio_test_msg_que, msg_p, BEKEN_NO_WAIT);
if (kNoErr != ret)
SDIO_LOG_ERR("sdio test send msg failed\r\n");
}
SDIO_LOG_DEBUG_FUNCTION_EXIT();
return ret;
}
/**
* @brief Set the sdio test case.
*
* This API set the sdio driver test case.
* - It will tested with the selected case.
* - Every case param has itself mean.
*
* @attention 1. This API should be called after sdio test inited.
*
* @return
* - BK_OK: succeed
* - others: other errors.
*/
bk_err_t bk_sdio_set_test_case(
uint8_t main_case,
uint8_t sub_case,
uint32_t param1,
uint32_t param2,
uint32_t param3,
uint32_t param4
)
{
SDIO_TEST_MSG_T msg;
if(main_case >= SDIO_TEST_MAX_MAIN_CASE)
{
SDIO_LOG_ERR("main case id %d is big then %d", main_case, SDIO_TEST_MAX_MAIN_CASE);
return BK_FAIL;
}
msg.main_case = main_case;
msg.sub_case = sub_case;
msg.param1 = param1;
msg.param2 = param2;
msg.param3 = param3;
msg.param4 = param4;
return sdio_test_send_msg(&msg);
}
static void sdio_test_thread(void *arg)
{
bk_err_t ret = BK_OK;
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
while(1)
{
SDIO_TEST_MSG_T msg;
ret = rtos_pop_from_queue(&s_sdio_test_msg_que, &msg, BEKEN_WAIT_FOREVER);
if (kNoErr == ret)
{
//
switch(msg.main_case)
{
case SDIO_TEST_TX:
{
if(msg.sub_case >= SDIO_TEST_TX_MAX_SUB_CASE)
{
SDIO_LOG_ERR("sub case id %d is big then %d", msg.sub_case, SDIO_TEST_TX_MAX_SUB_CASE);
break;
}
sdio_test_tx_sub_case(&msg);
break;
}
case SDIO_TEST_RX:
{
if(msg.sub_case >= SDIO_TEST_RX_MAX_SUB_CASE)
{
SDIO_LOG_ERR("sub case id %d is big then %d", msg.sub_case, SDIO_TEST_RX_MAX_SUB_CASE);
break;
}
sdio_test_rx_sub_case(&msg);
break;
}
default:
break;
}
}
}
SDIO_LOG_DEBUG_FUNCTION_EXIT();
//TODO: Assert
}
/**
* @brief Init the sdio driver test program.
*
* This API init the sdio driver test program.
* - It will create a task do selected test case.
* - It can select test case by command line.
*
* @attention 1. This API should be called after sdio inited finish.
*
* @return
* - BK_OK: succeed
* - others: other errors.
*/
bk_err_t bk_sdio_test_init(void)
{
bk_err_t ret = BK_OK;
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
if(s_sdio_test_inited)
{
SDIO_LOG_INFO("has inited");
return ret;
}
ret = rtos_init_queue(
&s_sdio_test_msg_que,
SDIO_TEST_MSG_QUEUE_NAME,
sizeof(SDIO_TEST_MSG_T),
SDIO_TEST_MSG_QUEUE_COUNT
);
if (kNoErr != ret)
{
SDIO_LOG_ERR("init queue ret=%d", ret);
goto err_exit;
}
ret = rtos_create_thread(
&s_test_sdio_thread,
SDIO_TEST_PRIORITY,
SDIO_TEST_THREAD_NAME,
sdio_test_thread,
SDIO_TEST_THREAD_STACK_SIZE,
NULL
);
if (kNoErr != ret)
{
SDIO_LOG_ERR("init thread ret=%d", ret);
goto err_exit;
}
s_sdio_test_inited = true;
SDIO_LOG_DEBUG_FUNCTION_EXIT();
//return, or err_exit release resources caused bug.
return ret;
err_exit:
if(s_sdio_test_msg_que)
{
rtos_deinit_queue(&s_sdio_test_msg_que);
s_sdio_test_msg_que = NULL;
}
if(s_test_sdio_thread)
{
rtos_delete_thread(&s_test_sdio_thread);
s_test_sdio_thread = NULL;
}
return ret;
}
/**
* @brief Deinit the sdio driver test program.
*
* This API init the sdio driver test program.
* - It will delete the test thread and queue.
*
* @attention 1. This API should be called after sdio inited finish.
*
* @return
* - BK_OK: succeed
* - others: other errors.
*/
bk_err_t bk_sdio_test_deinit(void)
{
bk_err_t ret = BK_OK;
SDIO_LOG_DEBUG_FUNCTION_ENTRY();
if(s_sdio_test_msg_que)
{
ret = rtos_deinit_queue(&s_sdio_test_msg_que);
if (BK_OK != ret)
{
SDIO_LOG_ERR("deinit queue ret=%d", ret);
return ret;
}
s_sdio_test_msg_que = NULL;
}
if(s_test_sdio_thread)
{
ret = rtos_delete_thread(&s_test_sdio_thread);
if (BK_OK != ret)
{
SDIO_LOG_ERR("delete thread ret=%d", ret);
return ret;
}
s_test_sdio_thread = NULL;
}
SDIO_LOG_DEBUG_FUNCTION_EXIT();
return BK_OK;
}
#endif //CONFIG_SDIO_TEST_EN