kernel_samsung_a34x-permissive/drivers/misc/mediatek/cmdq/v2/cmdq_test.c
2024-04-28 15:51:13 +02:00

5597 lines
148 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/atomic.h>
#include "cmdq_record_private.h"
#include "cmdq_reg.h"
#include "cmdq_virtual.h"
#include "cmdq_mdp_common.h"
#include "cmdq_device.h"
#define CMDQ_TEST
#ifdef CMDQ_TEST
#define CMDQ_TESTCASE_PARAMETER_MAX 4
#define CMDQ_MONITOR_EVENT_MAX 10
#define CMDQ_TEST_MMSYS_DUMMY_PA (0x14000000 + \
cmdq_dev_get_mmsys_dummy_reg_offset())
#define CMDQ_TEST_MMSYS_DUMMY_VA (cmdq_dev_get_module_base_VA_MMSYS_CONFIG() + \
cmdq_dev_get_mmsys_dummy_reg_offset())
#define CMDQ_TEST_GCE_DUMMY_PA CMDQ_GPR_R32_PA(CMDQ_DATA_REG_2D_SHARPNESS_1)
#define CMDQ_TEST_GCE_DUMMY_VA CMDQ_GPR_R32(CMDQ_DATA_REG_2D_SHARPNESS_1)
/* test configuration */
static DEFINE_MUTEX(gCmdqTestProcLock);
enum CMDQ_TEST_TYPE_ENUM {
CMDQ_TEST_TYPE_NORMAL = 0,
CMDQ_TEST_TYPE_SECURE = 1,
CMDQ_TEST_TYPE_MONITOR_EVENT = 2,
CMDQ_TEST_TYPE_MONITOR_POLL = 3,
CMDQ_TEST_TYPE_OPEN_COMMAND_DUMP = 4,
CMDQ_TEST_TYPE_DUMP_DTS = 5,
CMDQ_TEST_TYPE_FEATURE_CONFIG = 6,
CMDQ_TEST_TYPE_MMSYS_PERFORMANCE = 7,
CMDQ_TEST_TYPE_MAX /* ALWAYS keep at the end */
};
enum CMDQ_MOITOR_TYPE_ENUM {
CMDQ_MOITOR_TYPE_FLUSH = 0,
CMDQ_MOITOR_TYPE_WFE = 1, /* wait for event and clear */
CMDQ_MOITOR_TYPE_WAIT_NO_CLEAR = 2,
CMDQ_MOITOR_TYPE_QUERYREGISTER = 3,
CMDQ_MOITOR_TYPE_MAX /* ALWAYS keep at the end */
};
struct cmdqMonitorEventStruct {
bool status;
struct cmdqRecStruct *cmdqHandle;
cmdqBackupSlotHandle slotHandle;
uint32_t monitorNUM;
uint32_t waitType[CMDQ_MONITOR_EVENT_MAX];
uint64_t monitorEvent[CMDQ_MONITOR_EVENT_MAX];
uint32_t previousValue[CMDQ_MONITOR_EVENT_MAX];
};
struct cmdqMonitorPollStruct {
bool status;
struct cmdqRecStruct *cmdqHandle;
cmdqBackupSlotHandle slotHandle;
uint64_t pollReg;
uint64_t pollValue;
uint64_t pollMask;
uint32_t delayTime;
struct delayed_work delayContinueWork;
};
static int64_t gCmdqTestConfig[CMDQ_MONITOR_EVENT_MAX];
static bool gCmdqTestSecure;
static struct cmdqMonitorEventStruct gEventMonitor;
static struct cmdqMonitorPollStruct gPollMonitor;
#ifdef _CMDQ_TEST_PROC_
static struct proc_dir_entry *gCmdqTestProcEntry;
#endif
#define CMDQ_TEST_FAIL(string, args...) \
{ \
if (1) { \
pr_notice("[CMDQ][ERR]TEST FAIL: "string, ##args); \
} \
}
static int32_t _test_submit_async_internal(struct cmdqRecStruct *handle,
struct TaskStruct **ppTask,
bool internal, bool ignore_timeout)
{
struct TaskPrivateStruct private = {
.node_private_data = NULL,
.internal = internal,
.ignore_timeout = ignore_timeout,
};
struct cmdqCommandStruct desc = {
.scenario = handle->scenario,
.priority = handle->priority,
.engineFlag = handle->engineFlag,
.pVABase = (cmdqU32Ptr_t) (unsigned long)handle->pBuffer,
.blockSize = handle->blockSize,
.privateData = (cmdqU32Ptr_t)(unsigned long)(&private),
};
/* secure path */
cmdq_setup_sec_data_of_command_desc_by_rec_handle(&desc, handle);
/* profile marker */
cmdq_rec_setup_profile_marker_data(&desc, handle);
return cmdqCoreSubmitTaskAsync(&desc, NULL, 0, ppTask);
}
static int32_t _test_submit_async(struct cmdqRecStruct *handle,
struct TaskStruct **ppTask)
{
return _test_submit_async_internal(handle, ppTask, false, false);
}
s32 _test_backup_instructions(struct TaskStruct *task,
s32 **instructions_out)
{
s32 *insts_buffer = NULL;
struct CmdBufferStruct *cmd_buffer = NULL;
u32 buffer_count = 0;
insts_buffer = vzalloc(task->bufferSize);
if (!insts_buffer)
return -ENOMEM;
list_for_each_entry(cmd_buffer, &task->cmd_buffer_list, listEntry) {
u32 buf_size = list_is_last(&cmd_buffer->listEntry,
&task->cmd_buffer_list) ?
CMDQ_CMD_BUFFER_SIZE - task->buf_available_size :
CMDQ_CMD_BUFFER_SIZE;
memcpy(insts_buffer +
CMDQ_CMD_BUFFER_SIZE / sizeof(s32) * buffer_count,
cmd_buffer->pVABase, buf_size);
buffer_count++;
}
*instructions_out = insts_buffer;
return 0;
}
void _test_free_backup_instructions(s32 **instructions_out)
{
if (*instructions_out)
vfree(*instructions_out);
*instructions_out = NULL;
}
static void testcase_scenario(void)
{
struct cmdqRecStruct *hRec;
int32_t ret;
int i = 0;
CMDQ_MSG("%s\n", __func__);
/* make sure each scenario runs properly with empty commands */
for (i = 0; i < CMDQ_MAX_SCENARIO_COUNT; ++i) {
if (cmdq_core_is_request_from_user_space(i))
continue;
CMDQ_MSG("%s id:%d\n", __func__, i);
cmdq_task_create((enum CMDQ_SCENARIO_ENUM) i, &hRec);
cmdq_task_reset(hRec);
cmdq_task_set_secure(hRec, false);
ret = cmdq_task_flush(hRec);
}
cmdq_task_destroy(hRec);
CMDQ_MSG("%s END\n", __func__);
}
static s32 _test_submit_sync(struct cmdqRecStruct *handle,
bool ignore_timeout)
{
struct cmdqCommandStruct desc = { 0 };
struct TaskPrivateStruct private = {
.node_private_data = NULL,
.internal = true,
.ignore_timeout = ignore_timeout,
};
s32 status;
status = cmdq_op_finalize_command(handle, false);
if (status < 0)
return status;
CMDQ_MSG("Submit task scenario: %d, priority: %d, engine: 0x%llx\n",
handle->scenario, handle->priority,
handle->engineFlag);
CMDQ_MSG("buffer: 0x%p, size: %d\n",
handle->pBuffer,
handle->blockSize);
desc.scenario = handle->scenario;
desc.priority = handle->priority;
desc.engineFlag = handle->engineFlag;
desc.pVABase = (cmdqU32Ptr_t) (unsigned long)handle->pBuffer;
desc.blockSize = handle->blockSize;
desc.privateData = (cmdqU32Ptr_t)(unsigned long)(&private);
/* secure path */
cmdq_setup_sec_data_of_command_desc_by_rec_handle(&desc, handle);
/* profile marker */
cmdq_rec_setup_profile_marker_data(&desc, handle);
return cmdqCoreSubmitTask(&desc);
}
struct cmdq_test_timer {
struct timer_list test_timer;
u32 event;
};
static struct cmdq_test_timer cmdq_ttm;
static bool test_timer_stop;
static void _testcase_sync_token_timer_func(struct timer_list *t)
{
struct cmdq_test_timer *tm = from_timer(tm, t, test_timer);
/* trigger sync event */
CMDQ_MSG("trigger event:0x%08lx\n", (1L << 16) | tm->event);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | tm->event);
}
static void _testcase_sync_token_timer_loop_func(struct timer_list *t)
{
struct cmdq_test_timer *tm = from_timer(tm, t, test_timer);
/* trigger sync event */
CMDQ_MSG("trigger event:0x%08lx\n", (1L << 16) | tm->event);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | tm->event);
if (test_timer_stop) {
del_timer(&tm->test_timer);
return;
}
/* repeate timeout until user delete it */
mod_timer(&tm->test_timer, jiffies + msecs_to_jiffies(10));
}
static void testcase_sync_token(void)
{
struct cmdqRecStruct *hRec;
int32_t ret = 0;
CMDQ_MSG("%s\n", __func__);
cmdq_task_create(CMDQ_SCENARIO_SUB_DISP, &hRec);
do {
cmdq_task_reset(hRec);
cmdq_task_set_secure(hRec, gCmdqTestSecure);
/* setup timer to trigger sync token */
cmdq_ttm.event = CMDQ_SYNC_TOKEN_USER_0;
timer_setup(&cmdq_ttm.test_timer,
_testcase_sync_token_timer_func, 0);
mod_timer(&cmdq_ttm.test_timer,
jiffies + msecs_to_jiffies(1000));
/* wait for sync token */
cmdq_op_wait(hRec, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_MSG("start waiting\n");
ret = cmdq_task_flush(hRec);
CMDQ_MSG("waiting done\n");
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
del_timer(&cmdq_ttm.test_timer);
} while (0);
CMDQ_MSG("%s, timeout case\n", __func__);
/* */
/* test for timeout */
/* */
do {
cmdq_task_reset(hRec);
cmdq_task_set_secure(hRec, gCmdqTestSecure);
/* wait for sync token */
cmdq_op_wait(hRec, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_MSG("start waiting\n");
ret = cmdq_task_flush(hRec);
CMDQ_MSG("waiting done\n");
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
} while (0);
cmdq_task_destroy(hRec);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_async_suspend_resume(void)
{
struct cmdqRecStruct *hReqA;
struct TaskStruct *pTaskA;
int32_t ret = 0;
CMDQ_MSG("%s\n", __func__);
/* setup timer to trigger sync token
* timer_setup(&timer_reqA, &_testcase_sync_token_timer_func,
* CMDQ_SYNC_TOKEN_USER_0);
*/
/* mod_timer(&timer_reqA, jiffies + msecs_to_jiffies(300)); */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
do {
/* let this thread wait for user token, then finish */
cmdq_task_create(CMDQ_SCENARIO_PRIMARY_ALL, &hReqA);
cmdq_task_reset(hReqA);
cmdq_task_set_secure(hReqA, gCmdqTestSecure);
cmdq_op_wait(hReqA, CMDQ_SYNC_TOKEN_USER_0);
cmdq_append_command(hReqA, CMDQ_CODE_EOC, 0, 1, 0, 0);
cmdq_append_command(hReqA, CMDQ_CODE_JUMP, 0, 8, 0, 0);
ret = _test_submit_async(hReqA, &pTaskA);
CMDQ_MSG("%s pTask %p, engine:0x%llx, scenario:%d\n",
__func__, pTaskA,
pTaskA->engineFlag, pTaskA->scenario);
CMDQ_MSG("%s start suspend+resume thread 0========\n",
__func__);
cmdq_core_suspend_HW_thread(0, __LINE__);
CMDQ_REG_SET32(CMDQ_THR_SUSPEND_TASK(0), 0x00); /* resume */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) |
CMDQ_SYNC_TOKEN_USER_0);
msleep_interruptible(500);
CMDQ_MSG("%s start wait A========\n", __func__);
ret = cmdqCoreWaitAndReleaseTask(pTaskA, 500);
} while (0);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
cmdq_task_destroy(hReqA);
/* del_timer(&timer_reqA); */
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_errors(void)
{
struct cmdqRecStruct *hReq;
struct TaskStruct *pTask;
int32_t ret;
const uint32_t UNKNOWN_OP = 0x50;
uint32_t *pCommand;
ret = 0;
do {
/* SW timeout */
CMDQ_MSG("%s line:%d\n", __func__, __LINE__);
CMDQ_MSG("============= INIFINITE Wait ==============\n");
cmdqCoreClearEvent(CMDQ_EVENT_MDP_RSZ0_EOF);
cmdq_task_create(CMDQ_SCENARIO_PRIMARY_DISP, &hReq);
/* turn on ALL engine flag to test dump */
for (ret = 0; ret < CMDQ_MAX_ENGINE_COUNT; ++ret)
hReq->engineFlag |= 1LL << ret;
cmdq_task_reset(hReq);
cmdq_task_set_secure(hReq, gCmdqTestSecure);
cmdq_op_wait(hReq, CMDQ_EVENT_MDP_RSZ0_EOF);
cmdq_task_flush(hReq);
CMDQ_MSG("=============== INIFINITE JUMP =============\n");
/* HW timeout */
CMDQ_MSG("%s line:%d\n", __func__, __LINE__);
cmdqCoreClearEvent(CMDQ_EVENT_MDP_RSZ0_EOF);
cmdq_task_reset(hReq);
cmdq_task_set_secure(hReq, gCmdqTestSecure);
cmdq_op_wait(hReq, CMDQ_EVENT_MDP_RSZ0_EOF);
/* JUMP to connect tasks */
cmdq_append_command(hReq, CMDQ_CODE_JUMP, 0, 8, 0, 0);
ret = _test_submit_async(hReq, &pTask);
msleep_interruptible(500);
ret = cmdqCoreWaitAndReleaseTask(pTask, 8000);
CMDQ_MSG("================ POLL INIFINITE ==============\n");
CMDQ_MSG("testReg: %lx\n", CMDQ_TEST_GCE_DUMMY_VA);
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, 0x0);
cmdq_task_reset(hReq);
cmdq_task_set_secure(hReq, gCmdqTestSecure);
cmdq_op_poll(hReq, CMDQ_TEST_GCE_DUMMY_PA, 1, 0xFFFFFFFF);
cmdq_task_flush(hReq);
CMDQ_MSG("================= INVALID INSTR =================\n");
/* invalid instruction */
CMDQ_MSG("%s line:%d\n", __func__, __LINE__);
cmdq_task_reset(hReq);
cmdq_task_set_secure(hReq, gCmdqTestSecure);
cmdq_append_command(hReq, CMDQ_CODE_JUMP, -1, 0, 0, 0);
cmdq_task_flush(hReq);
CMDQ_MSG("==== INVALID INSTR: UNKNOWN OP(0x%x) ====\n",
UNKNOWN_OP);
CMDQ_MSG("%s line:%d\n", __func__, __LINE__);
/* invalid instruction is asserted when unknown OP */
cmdq_task_reset(hReq);
cmdq_task_set_secure(hReq, gCmdqTestSecure);
{
pCommand = (uint32_t *) ((uint8_t *) hReq->pBuffer +
hReq->blockSize);
*pCommand++ = 0x0;
*pCommand++ = (UNKNOWN_OP << 24);
hReq->blockSize += 8;
}
cmdq_task_flush(hReq);
} while (0);
cmdq_task_destroy(hReq);
CMDQ_MSG("%s END\n", __func__);
}
static int32_t finishCallback(unsigned long data)
{
CMDQ_LOG("callback() with data=0x%08lx\n", data);
return 0;
}
static void testcase_fire_and_forget(void)
{
struct cmdqRecStruct *hReqA, *hReqB;
CMDQ_MSG("%s\n", __func__);
do {
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &hReqA);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &hReqB);
cmdq_task_reset(hReqA);
cmdq_task_reset(hReqB);
cmdq_task_set_secure(hReqA, gCmdqTestSecure);
cmdq_task_set_secure(hReqB, gCmdqTestSecure);
CMDQ_MSG("%s %d\n", __func__, __LINE__);
cmdq_task_flush_async(hReqA);
CMDQ_MSG("%s %d\n", __func__, __LINE__);
cmdq_task_flush_async_callback(hReqB, finishCallback, 443);
CMDQ_MSG("%s %d\n", __func__, __LINE__);
} while (0);
cmdq_task_destroy(hReqA);
cmdq_task_destroy(hReqB);
CMDQ_MSG("%s END\n", __func__);
}
static struct cmdq_test_timer cmdq_treqa;
static struct cmdq_test_timer cmdq_treqb;
static void testcase_async_request(void)
{
struct cmdqRecStruct *hReqA, *hReqB;
struct TaskStruct *pTaskA, *pTaskB;
int32_t ret = 0;
CMDQ_MSG("%s\n", __func__);
/* setup timer to trigger sync token */
cmdq_treqa.event = CMDQ_SYNC_TOKEN_USER_0;
timer_setup(&cmdq_treqa.test_timer, _testcase_sync_token_timer_func, 0);
mod_timer(&cmdq_treqa.test_timer, jiffies + msecs_to_jiffies(1000));
cmdq_treqa.event = CMDQ_SYNC_TOKEN_USER_1;
timer_setup(&cmdq_treqb.test_timer, _testcase_sync_token_timer_func, 0);
/* mod_timer(&timer_reqB, jiffies + msecs_to_jiffies(1300)); */
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_1);
do {
cmdq_task_create(CMDQ_SCENARIO_SUB_DISP, &hReqA);
cmdq_task_reset(hReqA);
cmdq_task_set_secure(hReqA, gCmdqTestSecure);
cmdq_op_wait(hReqA, CMDQ_SYNC_TOKEN_USER_0);
cmdq_append_command(hReqA, CMDQ_CODE_EOC, 0, 1, 0, 0);
cmdq_append_command(hReqA, CMDQ_CODE_JUMP, 0, 8, 0, 0);
cmdq_task_create(CMDQ_SCENARIO_SUB_DISP, &hReqB);
cmdq_task_reset(hReqB);
cmdq_task_set_secure(hReqB, gCmdqTestSecure);
cmdq_op_wait(hReqB, CMDQ_SYNC_TOKEN_USER_1);
cmdq_append_command(hReqB, CMDQ_CODE_EOC, 0, 1, 0, 0);
cmdq_append_command(hReqB, CMDQ_CODE_JUMP, 0, 8, 0, 0);
ret = _test_submit_async(hReqA, &pTaskA);
ret = _test_submit_async(hReqB, &pTaskB);
CMDQ_MSG("%s start wait sleep========\n", __func__);
msleep_interruptible(500);
CMDQ_MSG("%s start wait A========\n", __func__);
ret = cmdqCoreWaitAndReleaseTask(pTaskA, 500);
CMDQ_MSG("%s start wait B, this should timeout========\n",
__func__);
ret = cmdqCoreWaitAndReleaseTask(pTaskB, 600);
CMDQ_MSG("%s wait B get %d ========\n", __func__, ret);
} while (0);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_1);
cmdq_task_destroy(hReqA);
cmdq_task_destroy(hReqB);
del_timer(&cmdq_treqa.test_timer);
del_timer(&cmdq_treqb.test_timer);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_multiple_async_request(void)
{
#define TEST_REQ_COUNT 24
struct cmdqRecStruct *hReq[TEST_REQ_COUNT] = { 0 };
struct TaskStruct *pTask[TEST_REQ_COUNT] = { 0 };
int32_t ret = 0;
int i;
CMDQ_MSG("%s\n", __func__);
test_timer_stop = false;
cmdq_ttm.event = CMDQ_SYNC_TOKEN_USER_0;
timer_setup(&cmdq_ttm.test_timer,
_testcase_sync_token_timer_loop_func, 0);
mod_timer(&cmdq_ttm.test_timer, jiffies + msecs_to_jiffies(10));
/* Queue multiple async request */
/* to test dynamic task allocation */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
for (i = 0; i < TEST_REQ_COUNT; ++i) {
ret = cmdq_task_create(CMDQ_SCENARIO_DEBUG, &hReq[i]);
if (ret < 0) {
CMDQ_ERR("%s cmdq_task_create failed:%d, i:%d\n ",
__func__, ret, i);
continue;
}
cmdq_task_reset(hReq[i]);
/* specify engine flag in order to dispatch */
/* all tasks to the same HW thread */
hReq[i]->engineFlag = (1LL << CMDQ_ENG_MDP_CAMIN);
cmdq_task_set_secure(hReq[i], gCmdqTestSecure);
cmdq_op_wait(hReq[i], CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_finalize_command(hReq[i], false);
/* higher priority for later tasks */
hReq[i]->priority = i;
_test_submit_async(hReq[i], &pTask[i]);
CMDQ_MSG("======== create task[%2d]=0x%p done ========\n",
i, pTask[i]);
}
/* release token and wait them */
for (i = 0; i < TEST_REQ_COUNT; ++i) {
if (pTask[i] == NULL) {
CMDQ_ERR("%s pTask[%d] is NULL\n ", __func__, i);
continue;
}
msleep_interruptible(100);
CMDQ_LOG("======== wait task[%2d]=0x%p ========\n",
i, pTask[i]);
ret = cmdqCoreWaitAndReleaseTask(pTask[i], 1000);
cmdq_task_destroy(hReq[i]);
}
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
test_timer_stop = true;
del_timer(&cmdq_ttm.test_timer);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_async_request_partial_engine(void)
{
int32_t ret = 0;
int i;
enum CMDQ_SCENARIO_ENUM scn[] = { CMDQ_SCENARIO_PRIMARY_DISP,
CMDQ_SCENARIO_JPEG_DEC,
CMDQ_SCENARIO_PRIMARY_MEMOUT,
CMDQ_SCENARIO_SUB_DISP,
CMDQ_SCENARIO_DEBUG,
};
struct cmdqRecStruct *hReq;
struct TaskStruct *pTasks[ARRAY_SIZE(scn)] = { 0 };
struct cmdq_test_timer *timers;
timers = kmalloc_array(ARRAY_SIZE(scn),
sizeof(struct timer_list), GFP_ATOMIC);
if (timers == NULL)
return;
CMDQ_MSG("%s\n", __func__);
/* setup timer to trigger sync token */
for (i = 0; i < ARRAY_SIZE(scn); i++) {
timers[i].event = CMDQ_SYNC_TOKEN_USER_0 + i;
timer_setup(&timers[i].test_timer,
_testcase_sync_token_timer_func, 0);
mod_timer(&timers[i].test_timer, jiffies +
msecs_to_jiffies(50 * (1 + i)));
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD,
CMDQ_SYNC_TOKEN_USER_0 + i);
cmdq_task_create(scn[i], &hReq);
cmdq_task_reset(hReq);
cmdq_task_set_secure(hReq, false);
cmdq_op_wait(hReq, CMDQ_SYNC_TOKEN_USER_0 + i);
cmdq_op_finalize_command(hReq, false);
CMDQ_MSG("TEST: SUBMIT scneario %d\n", scn[i]);
ret = _test_submit_async(hReq, &pTasks[i]);
cmdq_task_destroy(hReq);
}
/* wait for task completion */
for (i = 0; i < ARRAY_SIZE(scn); ++i)
ret = cmdqCoreWaitAndReleaseTask(pTasks[i],
msecs_to_jiffies(3000));
/* clear token */
for (i = 0; i < ARRAY_SIZE(scn); i++) {
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD,
CMDQ_SYNC_TOKEN_USER_0 + i);
del_timer(&timers[i].test_timer);
}
if (timers != NULL) {
kfree(timers);
timers = NULL;
}
CMDQ_MSG("%s END\n", __func__);
}
static void _testcase_unlock_all_event_timer_func(struct timer_list *t)
{
u32 token = 0;
CMDQ_LOG("%s\n", __func__);
/* trigger sync event */
CMDQ_MSG("trigger events\n");
for (token = 0; token < CMDQ_SYNC_TOKEN_MAX; ++token) {
/* 3 threads waiting, so update 3 times */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | token);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | token);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | token);
}
}
static void testcase_sync_token_threaded(void)
{
/* high prio */
enum CMDQ_SCENARIO_ENUM scn[] = { CMDQ_SCENARIO_PRIMARY_DISP,
CMDQ_SCENARIO_JPEG_DEC, /* normal prio */
CMDQ_SCENARIO_TRIGGER_LOOP /* normal prio */
};
int32_t ret = 0;
int i = 0;
uint32_t token = 0;
struct cmdq_test_timer timers[ARRAY_SIZE(scn)];
struct cmdqRecStruct *hReq[ARRAY_SIZE(scn)] = { 0 };
struct TaskStruct *pTasks[ARRAY_SIZE(scn)] = { 0 };
CMDQ_MSG("%s\n", __func__);
/* setup timer to trigger sync token */
for (i = 0; i < ARRAY_SIZE(scn); i++) {
timer_setup(&timers[i].test_timer,
_testcase_unlock_all_event_timer_func, 0);
mod_timer(&timers[i].test_timer,
jiffies + msecs_to_jiffies(500));
/* */
/* 3 threads, all wait & clear 511 events */
/* */
cmdq_task_create(scn[i], &hReq[i]);
cmdq_task_reset(hReq[i]);
cmdq_task_set_secure(hReq[i], false);
for (token = 0; token < CMDQ_SYNC_TOKEN_MAX; ++token)
cmdq_op_wait(hReq[i], (enum CMDQ_EVENT_ENUM) token);
cmdq_op_finalize_command(hReq[i], false);
CMDQ_MSG("TEST: SUBMIT scneario %d\n", scn[i]);
ret = _test_submit_async(hReq[i], &pTasks[i]);
}
/* wait for task completion */
msleep_interruptible(1000);
for (i = 0; i < ARRAY_SIZE(scn); ++i)
ret = cmdqCoreWaitAndReleaseTask(pTasks[i],
msecs_to_jiffies(5000));
/* clear token */
for (i = 0; i < ARRAY_SIZE(scn); ++i) {
cmdq_task_destroy(hReq[i]);
del_timer(&timers[i].test_timer);
}
CMDQ_MSG("%s END\n", __func__);
}
static struct cmdq_test_timer cmdq_tltm;
static int g_loopIter;
static struct cmdqRecStruct *hLoopReq;
static void _testcase_loop_timer_func(struct timer_list *t)
{
struct cmdq_test_timer *tm = from_timer(tm, t, test_timer);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) | tm->event);
mod_timer(&tm->test_timer, jiffies + msecs_to_jiffies(300));
g_loopIter++;
}
static void testcase_loop(void)
{
int status = 0;
CMDQ_MSG("%s\n", __func__);
cmdq_task_create(CMDQ_SCENARIO_TRIGGER_LOOP, &hLoopReq);
cmdq_task_reset(hLoopReq);
cmdq_task_set_secure(hLoopReq, false);
cmdq_op_wait(hLoopReq, CMDQ_SYNC_TOKEN_USER_0);
cmdq_tltm.event = CMDQ_SYNC_TOKEN_USER_0;
timer_setup(&cmdq_tltm.test_timer, _testcase_loop_timer_func, 0);
mod_timer(&cmdq_tltm.test_timer, jiffies + msecs_to_jiffies(300));
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
g_loopIter = 0;
/* should success */
status = cmdq_task_start_loop(hLoopReq);
/* should fail because already started */
CMDQ_MSG("============%s start loop\n", __func__);
status = cmdq_task_start_loop(hLoopReq);
cmdq_task_dump_command(hLoopReq);
/* WAIT */
while (g_loopIter < 20)
msleep_interruptible(2000);
msleep_interruptible(2000);
CMDQ_MSG("============%s stop timer\n", __func__);
cmdq_task_destroy(hLoopReq);
del_timer(&cmdq_tltm.test_timer);
CMDQ_MSG("%s\n", __func__);
}
static unsigned long gLoopCount;
static void _testcase_trigger_func(struct timer_list *t)
{
/* trigger sync event */
CMDQ_MSG("_testcase_trigger_func");
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) |
CMDQ_SYNC_TOKEN_USER_0);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) |
CMDQ_SYNC_TOKEN_USER_1);
if (test_timer_stop) {
del_timer(&cmdq_ttm.test_timer);
return;
}
/* start again */
mod_timer(&cmdq_ttm.test_timer, jiffies + msecs_to_jiffies(1000));
gLoopCount++;
}
static void testcase_trigger_thread(void)
{
struct cmdqRecStruct *hTrigger, *hConfig;
int32_t ret = 0;
int index = 0;
CMDQ_MSG("%s\n", __func__);
/* setup timer to trigger sync token for every 1 sec */
test_timer_stop = false;
timer_setup(&cmdq_ttm.test_timer, _testcase_trigger_func, 0);
mod_timer(&cmdq_ttm.test_timer, jiffies + msecs_to_jiffies(1000));
do {
/* THREAD 1, trigger loop */
cmdq_task_create(CMDQ_SCENARIO_TRIGGER_LOOP, &hTrigger);
cmdq_task_reset(hTrigger);
/* * WAIT and CLEAR config dirty */
/* cmdq_op_wait(hTrigger, CMDQ_SYNC_TOKEN_CONFIG_DIRTY); */
/* * WAIT and CLEAR TE */
/* cmdq_op_wait(hTrigger, CMDQ_EVENT_MDP_DSI0_TE_SOF); */
/* * WAIT and CLEAR stream done */
/* cmdq_op_wait(hTrigger, CMDQ_EVENT_MUTEX0_STREAM_EOF); */
/* * WRITE mutex enable */
/* cmdq_op_wait(hTrigger, MM_MUTEX_BASE + 0x20); */
cmdq_op_wait(hTrigger, CMDQ_SYNC_TOKEN_USER_0);
/* * RUN forever but each IRQ trigger */
/* is bypass to my_irq_callback */
ret = cmdq_task_start_loop(hTrigger);
/* THREAD 2, config thread */
cmdq_task_create(CMDQ_SCENARIO_JPEG_DEC, &hConfig);
hConfig->priority = CMDQ_THR_PRIO_NORMAL;
cmdq_task_reset(hConfig);
/* insert tons of instructions */
for (index = 0; index < 10; ++index)
cmdq_append_command(hConfig, CMDQ_CODE_MOVE, 0,
0x1, 0, 0);
ret = cmdq_task_flush(hConfig);
CMDQ_MSG("flush 0\n");
hConfig->priority = CMDQ_THR_PRIO_DISPLAY_CONFIG;
cmdq_task_reset(hConfig);
/* insert tons of instructions */
for (index = 0; index < 10; ++index)
cmdq_append_command(hConfig, CMDQ_CODE_MOVE, 0,
0x1, 0, 0);
ret = cmdq_task_flush(hConfig);
CMDQ_MSG("flush 1\n");
cmdq_task_reset(hConfig);
/* insert tons of instructions */
for (index = 0; index < 500; ++index)
cmdq_append_command(hConfig, CMDQ_CODE_MOVE, 0,
0x1, 0, 0);
ret = cmdq_task_flush(hConfig);
CMDQ_MSG("flush 2\n");
/* WAIT */
while (gLoopCount < 20)
msleep_interruptible(2000);
} while (0);
test_timer_stop = true;
del_timer(&cmdq_ttm.test_timer);
cmdq_task_destroy(hTrigger);
cmdq_task_destroy(hConfig);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_prefetch_scenarios(void)
{
/* make sure both prefetch and non-prefetch cases */
/* handle 248+ instructions properly */
struct cmdqRecStruct *hConfig;
int32_t ret = 0;
int index = 0, scn = 0;
const int INSTRUCTION_COUNT = 500;
CMDQ_MSG("%s\n", __func__);
/* make sure each scenario runs properly with 248+ commands */
for (scn = 0; scn < CMDQ_MAX_SCENARIO_COUNT; ++scn) {
if (cmdq_core_is_request_from_user_space(scn))
continue;
CMDQ_MSG("%s scenario:%d\n", __func__, scn);
cmdq_task_create((enum CMDQ_SCENARIO_ENUM) scn, &hConfig);
cmdq_task_reset(hConfig);
/* insert tons of instructions */
for (index = 0; index < INSTRUCTION_COUNT; ++index)
cmdq_append_command(hConfig, CMDQ_CODE_MOVE,
0, 0x1, 0, 0);
ret = cmdq_task_flush(hConfig);
}
cmdq_task_destroy(hConfig);
CMDQ_MSG("%s END\n", __func__);
}
void testcase_clkmgr_impl(enum CMDQ_ENG_ENUM engine,
char *name,
const unsigned long testWriteReg,
const uint32_t testWriteValue,
const unsigned long testReadReg,
const bool verifyWriteResult)
{
/* clkmgr is not available on FPGA */
#ifndef CONFIG_MTK_FPGA
uint32_t value = 0;
CMDQ_MSG("====== %s:%s ======\n", __func__, name);
CMDQ_VERBOSE("clk engine:%d, name:%s\n", engine, name);
CMDQ_VERBOSE("write reg(0x%lx) to 0x%08x, read reg(0x%lx)\n",
testWriteReg, testWriteValue,
testReadReg);
CMDQ_VERBOSE("verify write result:%d\n",
verifyWriteResult);
/* turn on CLK, function should work */
CMDQ_MSG("enable_clock\n");
if (engine == CMDQ_ENG_CMDQ) {
/* Turn on CMDQ engine */
cmdq_dev_enable_gce_clock(true);
} else {
/* Turn on MDP engines */
cmdq_mdp_get_func()->enableMdpClock(true, engine);
}
CMDQ_REG_SET32(testWriteReg, testWriteValue);
value = CMDQ_REG_GET32(testReadReg);
if ((true == verifyWriteResult) && (testWriteValue != value)) {
CMDQ_ERR("when enable clock reg(0x%lx) = 0x%08x\n",
testReadReg, value);
/* BUG(); */
}
/* turn off CLK, function should not work and */
/* access register should not cause hang */
CMDQ_MSG("disable_clock\n");
if (engine == CMDQ_ENG_CMDQ) {
/* Turn on CMDQ engine */
cmdq_dev_enable_gce_clock(false);
} else {
/* Turn on MDP engines */
cmdq_mdp_get_func()->enableMdpClock(false, engine);
}
CMDQ_REG_SET32(testWriteReg, testWriteValue);
value = CMDQ_REG_GET32(testReadReg);
if (value != 0) {
CMDQ_ERR("when disable clock reg(0x%lx) = 0x%08x\n",
testReadReg, value);
/* BUG(); */
}
#endif
}
static void testcase_clkmgr(void)
{
CMDQ_MSG("%s\n", __func__);
#ifdef CMDQ_PWR_AWARE
testcase_clkmgr_impl(CMDQ_ENG_CMDQ,
"CMDQ_TEST",
CMDQ_GPR_R32(CMDQ_DATA_REG_DEBUG),
0xFFFFDEAD, CMDQ_GPR_R32(CMDQ_DATA_REG_DEBUG), true);
cmdq_mdp_get_func()->testcaseClkmgrMdp();
#endif /* defined(CMDQ_PWR_AWARE) */
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_dram_access(void)
{
#ifdef CMDQ_GPR_SUPPORT
struct cmdqRecStruct *handle = NULL;
uint32_t *regResults;
dma_addr_t regResultsMVA;
dma_addr_t dstMVA;
uint32_t arg_a;
uint32_t subsysCode;
uint32_t *pCmdEnd = NULL;
unsigned long long data64;
CMDQ_MSG("%s\n", __func__);
regResults = cmdq_core_alloc_hw_buffer(cmdq_dev_get(),
sizeof(uint32_t) * 2,
&regResultsMVA, GFP_KERNEL);
/* set up intput */
regResults[0] = 0xdeaddead; /* this is read-from */
regResults[1] = 0xffffffff; /* this is write-to */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
/* */
/* READ from DRAME: register to read from */
/* */
/* note that we force convert to physical reg address. */
/* if it is already physical address, it won't be */
/* affected (at least on this platform) */
arg_a = CMDQ_TEST_GCE_DUMMY_PA;
subsysCode = cmdq_core_subsys_from_phys_addr(arg_a);
pCmdEnd = (uint32_t *) (((char *)handle->pBuffer) + handle->blockSize);
CMDQ_MSG("pCmdEnd initial=0x%p, reg MVA=%pa, size=%d\n",
pCmdEnd, &regResultsMVA, handle->blockSize);
/* Move &(regResults[0]) to CMDQ_DATA_REG_DEBUG_DST */
*pCmdEnd = (uint32_t) CMDQ_PHYS_TO_AREG(regResultsMVA);
pCmdEnd += 1;
*pCmdEnd = (CMDQ_CODE_MOVE << 24) |
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
((regResultsMVA >> 32) & 0xffff) |
#endif
((CMDQ_DATA_REG_DEBUG_DST & 0x1f) << 16) | (4 << 21);
pCmdEnd += 1;
/* */
/* WRITE to DRAME: */
/* from src_addr(CMDQ_DATA_REG_DEBUG_DST) */
/* to external RAM (regResults[1]) */
/* */
/* Read data from *CMDQ_DATA_REG_DEBUG_DST to CMDQ_DATA_REG_DEBUG */
*pCmdEnd = CMDQ_DATA_REG_DEBUG;
pCmdEnd += 1;
*pCmdEnd =
(CMDQ_CODE_READ << 24) | (0 & 0xffff) |
((CMDQ_DATA_REG_DEBUG_DST & 0x1f) << 16) |
(6 << 21);
pCmdEnd += 1;
/* Load dst_addr to GPR: Move &(regResults[1]) */
/* to CMDQ_DATA_REG_DEBUG_DST */
/* note regResults is a uint32_t array */
dstMVA = regResultsMVA + 4;
*pCmdEnd = ((uint32_t) dstMVA);
pCmdEnd += 1;
*pCmdEnd = (CMDQ_CODE_MOVE << 24) |
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
((dstMVA >> 32) & 0xffff) |
#endif
((CMDQ_DATA_REG_DEBUG_DST & 0x1f) << 16) | (4 << 21);
pCmdEnd += 1;
/* Write from CMDQ_DATA_REG_DEBUG to *CMDQ_DATA_REG_DEBUG_DST */
*pCmdEnd = CMDQ_DATA_REG_DEBUG;
pCmdEnd += 1;
*pCmdEnd = (CMDQ_CODE_WRITE << 24) |
(0 & 0xffff) | ((CMDQ_DATA_REG_DEBUG_DST & 0x1f) << 16) |
(6 << 21);
pCmdEnd += 1;
handle->blockSize += 4 * 8; /* 4 * 64-bit instructions */
cmdq_task_dump_command(handle);
cmdq_task_flush(handle);
cmdq_task_dump_command(handle);
cmdq_task_destroy(handle);
data64 = 0LL;
data64 = CMDQ_REG_GET64_GPR_PX(CMDQ_DATA_REG_DEBUG_DST);
CMDQ_MSG("regResults=[0x%08x, 0x%08x]\n", regResults[0], regResults[1]);
CMDQ_MSG("CMDQ_DATA_REG_DEBUG=0x%08x, CMDQ_DATA_REG_DEBUG_DST=0x%llx\n",
CMDQ_REG_GET32(CMDQ_GPR_R32(CMDQ_DATA_REG_DEBUG)), data64);
if (regResults[1] != regResults[0]) {
/* Test DRAM access fail */
CMDQ_ERR("ERROR!!!!!!\n");
} else {
/* Test DRAM access success */
CMDQ_MSG("OK!!!!!!\n");
}
cmdq_core_free_hw_buffer(cmdq_dev_get(),
2 * sizeof(uint32_t), regResults,
regResultsMVA);
CMDQ_MSG("%s END\n", __func__);
#else
CMDQ_ERR("func:%s failed since CMDQ doesn't support GPR\n", __func__);
#endif
}
static void testcase_long_command(void)
{
int i;
struct cmdqRecStruct *handle = NULL;
uint32_t data;
uint32_t pattern = 0x0;
CMDQ_MSG("%s\n", __func__);
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, 0xdeaddead);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
/* build a 64KB instruction buffer */
for (i = 0; i < 64 * 1024 / 8; ++i) {
pattern = i;
cmdq_op_write_reg(handle, CMDQ_TEST_GCE_DUMMY_PA, pattern, ~0);
}
cmdq_task_flush(handle);
cmdq_task_destroy(handle);
/* verify data */
do {
if (true == gCmdqTestSecure) {
CMDQ_LOG("%s, timeout case in secure path\n",
__func__);
break;
}
data = CMDQ_REG_GET32(CMDQ_TEST_GCE_DUMMY_VA);
if (pattern != data) {
CMDQ_ERR("TEST FAIL: regL0x%08x, not pattern 0x%08x\n",
data,
pattern);
}
} while (0);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_perisys_apb(void)
{
#ifdef CMDQ_GPR_SUPPORT
/* write value to PERISYS register */
/* we use MSDC debug to test: */
/* write SEL, read OUT. */
const uint32_t MSDC_SW_DBG_SEL_PA = 0x11230000 + 0xA0;
const uint32_t MSDC_SW_DBG_OUT_PA = 0x11230000 + 0xA4;
const uint32_t AUDIO_TOP_CONF0_PA = 0x11220000;
#ifdef CMDQ_OF_SUPPORT
const unsigned long MSDC_VA_BASE =
cmdq_dev_alloc_module_base_VA_by_name("mediatek,MSDC0");
const unsigned long AUDIO_VA_BASE =
cmdq_dev_alloc_module_base_VA_by_name("mediatek,AUDIO");
const unsigned long MSDC_SW_DBG_OUT = MSDC_VA_BASE + 0xA4;
const unsigned long AUDIO_TOP_CONF0 = AUDIO_VA_BASE;
/* CMDQ_LOG("MSDC_VA_BASE: VA:%lx, PA: 0x%08x\n", */
/* MSDC_VA_BASE, 0x11230000); */
/* CMDQ_LOG("AUDIO_VA_BASE: VA:%lx, PA: 0x%08x\n", */
/* AUDIO_TOP_CONF0_PA, 0x11220000); */
#else
const uint32_t MSDC_SW_DBG_OUT = 0xF1230000 + 0xA4;
const uint32_t AUDIO_TOP_CONF0 = 0xF1220000;
#endif
const uint32_t AUDIO_TOP_MASK = ~0 & ~(1 << 28 |
1 << 21 |
1 << 17 |
1 << 16 |
1 << 15 |
1 << 11 |
1 << 10 |
1 << 7 |
1 << 5 |
1 << 4 |
1 << 3 |
1 << 1 | 1 << 0);
struct cmdqRecStruct *handle = NULL;
uint32_t data = 0;
uint32_t dataRead = 0;
CMDQ_MSG("%s\n", __func__);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, false);
cmdq_op_write_reg(handle, MSDC_SW_DBG_SEL_PA, 1, ~0);
cmdq_task_flush(handle);
/* verify data */
data = CMDQ_REG_GET32(MSDC_SW_DBG_OUT);
if (data != ~0) {
/* MSDC_SW_DBG_OUT would not same as sel setting */
CMDQ_MSG("write 0xFFFFFFFF to MSDC_SW_DBG_OUT = 0x%08x=====\n",
data);
CMDQ_MSG("MSDC_SW_DBG_OUT: PA(0x%x) VA(0x%lx) =====\n",
MSDC_SW_DBG_OUT_PA, MSDC_SW_DBG_OUT);
}
/* test read from AP_DMA_GLOBAL_SLOW_DOWN to CMDQ GPR */
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, false);
cmdq_op_read_to_data_register(handle, MSDC_SW_DBG_OUT_PA,
CMDQ_DATA_REG_PQ_COLOR);
cmdq_task_flush(handle);
/* verify data */
dataRead = CMDQ_REG_GET32(CMDQ_GPR_R32(CMDQ_DATA_REG_PQ_COLOR));
if (data != dataRead || data == 0) {
/* test fail */
CMDQ_ERR("TEST FAIL: read 0x%08x, different=====\n",
dataRead);
CMDQ_ERR("MSDC_SW_DBG_OUT: PA(0x%x) VA(0x%lx) =====\n",
MSDC_SW_DBG_OUT_PA, MSDC_SW_DBG_OUT);
}
CMDQ_REG_SET32(AUDIO_TOP_CONF0, ~0);
data = CMDQ_REG_GET32(AUDIO_TOP_CONF0);
if (data != ~0) {
CMDQ_ERR("write 0xFFFFFFFF to AUDIO_TOP_CONF0 = 0x%08x=====\n",
data);
CMDQ_ERR("AUDIO_TOP_CONF0: PA(0x%x) VA(0x%lx) =====\n",
AUDIO_TOP_CONF0_PA, AUDIO_TOP_CONF0);
}
CMDQ_REG_SET32(AUDIO_TOP_CONF0, 0);
data = CMDQ_REG_GET32(AUDIO_TOP_CONF0);
CMDQ_MSG("Before AUDIO_TOP_CONF0 = 0x%08x=====\n", data);
cmdq_task_reset(handle);
cmdq_op_write_reg(handle, AUDIO_TOP_CONF0_PA, ~0, AUDIO_TOP_MASK);
cmdq_task_flush(handle);
/* verify data */
data = CMDQ_REG_GET32(AUDIO_TOP_CONF0);
CMDQ_MSG("after AUDIO_TOP_CONF0 = 0x%08x=====\n", data);
if (data != AUDIO_TOP_MASK) {
/* test fail */
CMDQ_ERR("TEST FAIL: AUDIO_TOP_CONF0 is 0x%08x=====\n", data);
CMDQ_ERR("AUDIO_TOP_CONF0: PA(0x%x) VA(0x%lx) =====\n",
AUDIO_TOP_CONF0_PA, AUDIO_TOP_CONF0);
}
cmdq_task_destroy(handle);
#ifdef CMDQ_OF_SUPPORT
/* release registers map */
cmdq_dev_free_module_base_VA(MSDC_VA_BASE);
cmdq_dev_free_module_base_VA(AUDIO_VA_BASE);
#endif
CMDQ_MSG("%s END\n", __func__);
return;
#else
CMDQ_ERR("func:%s failed since CMDQ doesn't support GPR\n", __func__);
#endif /* CMDQ_GPR_SUPPORT */
}
static void testcase_write_address(void)
{
dma_addr_t pa = 0;
uint32_t value = 0;
CMDQ_MSG("%s\n", __func__);
cmdqCoreAllocWriteAddress(3, &pa);
CMDQ_LOG("ALLOC: 0x%pa\n", &pa);
value = cmdqCoreReadWriteAddress(pa);
CMDQ_LOG("value 0: 0x%08x\n", value);
value = cmdqCoreReadWriteAddress(pa + 1);
CMDQ_LOG("value 1: 0x%08x\n", value);
value = cmdqCoreReadWriteAddress(pa + 2);
CMDQ_LOG("value 2: 0x%08x\n", value);
value = cmdqCoreReadWriteAddress(pa + 3);
CMDQ_LOG("value 3: 0x%08x\n", value);
value = cmdqCoreReadWriteAddress(pa + 4);
CMDQ_LOG("value 4: 0x%08x\n", value);
value = cmdqCoreReadWriteAddress(pa + (4 * 20));
CMDQ_LOG("value 80: 0x%08x\n", value);
/* free invalid start address fist to verify error handle */
CMDQ_LOG("cmdqCoreFreeWriteAddress, pa:0, it's a error case\n");
cmdqCoreFreeWriteAddress(0);
/* ok case */
CMDQ_LOG("cmdqCoreFreeWriteAddress, pa:%pa, it's a ok case\n", &pa);
cmdqCoreFreeWriteAddress(pa);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_write_from_data_reg(void)
{
#ifdef CMDQ_GPR_SUPPORT
struct cmdqRecStruct *handle = NULL;
uint32_t value;
const uint32_t PATTERN = 0xFFFFDEAD;
const uint32_t srcGprId = CMDQ_DATA_REG_DEBUG;
uint32_t dstRegPA;
unsigned long dummy_va;
CMDQ_MSG("%s\n", __func__);
if (gCmdqTestSecure) {
dummy_va = CMDQ_TEST_MMSYS_DUMMY_VA;
dstRegPA = CMDQ_TEST_MMSYS_DUMMY_PA;
} else {
dummy_va = CMDQ_TEST_GCE_DUMMY_VA;
dstRegPA = CMDQ_TEST_GCE_DUMMY_PA;
}
/* clean dst register value */
CMDQ_REG_SET32((void *)dummy_va, 0x0);
/* init GPR as value 0xFFFFDEAD */
CMDQ_REG_SET32(CMDQ_GPR_R32(srcGprId), PATTERN);
value = CMDQ_REG_GET32(CMDQ_GPR_R32(srcGprId));
if (value != PATTERN) {
CMDQ_ERR("init to 0x%08x failed, value: 0x%08x\n",
PATTERN,
value);
}
/* write GPR data reg to hw register */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
cmdq_op_write_from_data_register(handle, srcGprId, dstRegPA);
cmdq_task_flush(handle);
cmdq_task_dump_command(handle);
cmdq_task_destroy(handle);
/* verify */
value = CMDQ_REG_GET32((void *)dummy_va);
if (value != PATTERN) {
CMDQ_ERR("%s failed, dstReg value not 0x%08x, value: 0x%08x\n",
__func__,
PATTERN, value);
}
CMDQ_MSG("%s END\n", __func__);
#else
CMDQ_ERR("func:%s failed since CMDQ doesn't support GPR\n", __func__);
#endif
}
static void testcase_read_to_data_reg(void)
{
#ifdef CMDQ_GPR_SUPPORT
struct cmdqRecStruct *handle = NULL;
uint32_t data;
unsigned long long data64;
CMDQ_MSG("%s\n", __func__);
/* init GPR 64 */
CMDQ_REG_SET64_GPR_PX(CMDQ_DATA_REG_PQ_COLOR_DST,
0x1234567890ABCDEFULL);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, 0xdeaddead);
/* R4 */
CMDQ_REG_SET32(CMDQ_GPR_R32(CMDQ_DATA_REG_PQ_COLOR), 0xbeefbeef);
/* R5 */
CMDQ_REG_SET32(CMDQ_GPR_R32(CMDQ_DATA_REG_2D_SHARPNESS_0), 0x0);
cmdq_get_func()->dumpGPR();
/* [read 64 bit test] move data from GPR */
/* to GPR_Px: COLOR to COLOR_DST (64 bit) */
cmdq_op_read_to_data_register(handle,
CMDQ_GPR_R32_PA(CMDQ_DATA_REG_PQ_COLOR),
CMDQ_DATA_REG_PQ_COLOR_DST);
/* [read 32 bit test] move data from register */
/* value to GPR_Rx: MM_DUMMY_REG to COLOR(32 bit) */
cmdq_op_read_to_data_register(handle, CMDQ_TEST_GCE_DUMMY_PA,
CMDQ_DATA_REG_PQ_COLOR);
cmdq_task_flush(handle);
cmdq_task_dump_command(handle);
cmdq_task_destroy(handle);
cmdq_get_func()->dumpGPR();
/* verify data */
data = CMDQ_REG_GET32(CMDQ_GPR_R32(CMDQ_DATA_REG_PQ_COLOR));
if (data != 0xdeaddead) {
/* Print error status */
CMDQ_ERR("PQ reg value is 0x%08x\n", data);
}
data64 = 0LL;
data64 = CMDQ_REG_GET64_GPR_PX(CMDQ_DATA_REG_PQ_COLOR_DST);
if (data64 != 0xbeefbeef) {
CMDQ_ERR("PQ_DST reg value is 0x%llx\n",
data64);
}
CMDQ_MSG("%s END\n", __func__);
return;
#else
CMDQ_ERR("func:%s failed since CMDQ doesn't support GPR\n", __func__);
return;
#endif
}
static void testcase_write_reg_from_slot(void)
{
#ifdef CMDQ_GPR_SUPPORT
const uint32_t PATTEN = 0xBCBCBCBC;
struct cmdqRecStruct *handle = NULL;
cmdqBackupSlotHandle hSlot = 0;
uint32_t value = 0;
long long value64 = 0LL;
const enum CMDQ_DATA_REGISTER_ENUM dstRegId = CMDQ_DATA_REG_DEBUG;
const enum CMDQ_DATA_REGISTER_ENUM srcRegId = CMDQ_DATA_REG_DEBUG_DST;
CMDQ_MSG("%s\n", __func__);
/* init */
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, 0xdeaddead);
CMDQ_REG_SET32(CMDQ_GPR_R32(dstRegId), 0xdeaddead);
CMDQ_REG_SET64_GPR_PX(srcRegId, 0xdeaddeaddeaddead);
cmdq_alloc_mem(&hSlot, 1);
cmdq_cpu_write_mem(hSlot, 0, PATTEN);
cmdq_cpu_read_mem(hSlot, 0, &value);
if (value != PATTEN) {
/* Print error status */
CMDQ_ERR("%s, slot init failed\n", __func__);
}
/* Create cmdqRec */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
/* Reset command buffer */
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
/* Insert commands to write register with slot's value */
cmdq_op_read_mem_to_reg(handle, hSlot, 0, CMDQ_TEST_GCE_DUMMY_PA);
/* Execute commands */
cmdq_task_flush(handle);
/* debug dump command instructions */
cmdq_task_dump_command(handle);
/* we can destroy cmdqRec handle after flush. */
cmdq_task_destroy(handle);
/* verify */
value = CMDQ_REG_GET32(CMDQ_TEST_GCE_DUMMY_VA);
if (value != PATTEN) {
/* Print error status */
CMDQ_ERR("%s failed, value:0x%x\n", __func__, value);
}
value = CMDQ_REG_GET32(CMDQ_GPR_R32(dstRegId));
value64 = CMDQ_REG_GET64_GPR_PX(srcRegId);
CMDQ_LOG("srcGPR(%x):0x%llx\n", srcRegId, value64);
CMDQ_LOG("dstGPR(%x):0x%08x\n", dstRegId, value);
/* release result free slot */
cmdq_free_mem(hSlot);
CMDQ_MSG("%s END\n", __func__);
return;
#else
CMDQ_ERR("func:%s failed since CMDQ doesn't support GPR\n", __func__);
return;
#endif
}
static void testcase_backup_reg_to_slot(void)
{
#ifdef CMDQ_GPR_SUPPORT
struct cmdqRecStruct *handle = NULL;
cmdqBackupSlotHandle hSlot = 0;
int i;
uint32_t value = 0;
CMDQ_MSG("%s\n", __func__);
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, 0xdeaddead);
/* Create cmdqRec */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
/* Create Slot */
cmdq_alloc_mem(&hSlot, 5);
for (i = 0; i < 5; ++i)
cmdq_cpu_write_mem(hSlot, i, i);
for (i = 0; i < 5; ++i) {
cmdq_cpu_read_mem(hSlot, i, &value);
if (value != i) {
/* Print error status */
CMDQ_ERR("testcase_cmdqBackupWriteSlot FAILED!!!!!\n");
}
CMDQ_LOG("testcase_cmdqBackupWriteSlot OK!!!!!\n");
}
/* Reset command buffer */
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
/* Insert commands to backup registers */
for (i = 0; i < 5; ++i)
cmdq_op_read_reg_to_mem(handle, hSlot, i,
CMDQ_TEST_GCE_DUMMY_PA);
/* Execute commands */
cmdq_task_flush(handle);
/* debug dump command instructions */
cmdq_task_dump_command(handle);
/* we can destroy cmdqRec handle after flush. */
cmdq_task_destroy(handle);
/* verify data by reading it back from slot */
for (i = 0; i < 5; ++i) {
cmdq_cpu_read_mem(hSlot, i, &value);
CMDQ_LOG("backup slot %d = 0x%08x\n", i, value);
if (value != 0xdeaddead) {
/* content error */
CMDQ_ERR("content error!!!!!!!!!!!!!!!!!!!!\n");
}
}
/* release result free slot */
cmdq_free_mem(hSlot);
CMDQ_MSG("%s END\n", __func__);
return;
#else
CMDQ_ERR("func:%s failed since CMDQ doesn't support GPR\n", __func__);
return;
#endif
}
static void testcase_update_value_to_slot(void)
{
int32_t i;
uint32_t value;
struct cmdqRecStruct *handle = NULL;
cmdqBackupSlotHandle hSlot = 0;
const uint32_t PATTERNS[] = {
0xDEAD0000, 0xDEAD0001, 0xDEAD0002, 0xDEAD0003, 0xDEAD0004
};
CMDQ_MSG("%s\n", __func__);
/* Create Slot */
cmdq_alloc_mem(&hSlot, 5);
/*use CMDQ to update slot value */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
for (i = 0; i < 5; ++i)
cmdq_op_write_mem(handle, hSlot, i, PATTERNS[i]);
cmdq_task_flush(handle);
cmdq_task_dump_command(handle);
cmdq_task_destroy(handle);
/* CPU verify value by reading it back from slot */
for (i = 0; i < 5; ++i) {
cmdq_cpu_read_mem(hSlot, i, &value);
if (PATTERNS[i] != value) {
CMDQ_ERR("slot[%d] = 0x%08x...error! pattern:0x%08x\n",
i, value, PATTERNS[i]);
} else {
CMDQ_LOG("slot[%d] = 0x%08x\n", i, value);
}
}
/* release result free slot */
cmdq_free_mem(hSlot);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_poll(void)
{
struct cmdqRecStruct *handle = NULL;
struct TaskStruct *p_task;
uint32_t value = 0;
uint32_t pollingVal = 0x00003001;
CMDQ_MSG("%s\n", __func__);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
cmdq_op_poll(handle, CMDQ_TEST_GCE_DUMMY_PA, pollingVal, ~0);
cmdq_op_finalize_command(handle, false);
_test_submit_async(handle, &p_task);
/* Set MMSYS dummy register value after clock is on */
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, pollingVal);
value = CMDQ_REG_GET32(CMDQ_TEST_GCE_DUMMY_VA);
CMDQ_MSG("target value is 0x%08x\n", value);
cmdqCoreWaitAndReleaseTask(p_task, 500);
cmdq_task_destroy(handle);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_write_with_mask(void)
{
struct cmdqRecStruct *handle = NULL;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
const uint32_t MASK = (1 << 16);
const uint32_t EXPECT_RESULT = PATTERN & MASK;
uint32_t value = 0;
unsigned long dummy_va, dummy_pa;
CMDQ_MSG("%s\n", __func__);
if (gCmdqTestSecure) {
dummy_va = CMDQ_TEST_MMSYS_DUMMY_VA;
dummy_pa = CMDQ_TEST_MMSYS_DUMMY_PA;
} else {
dummy_va = CMDQ_TEST_GCE_DUMMY_VA;
dummy_pa = CMDQ_TEST_GCE_DUMMY_PA;
}
/* set to 0x0 */
CMDQ_REG_SET32((void *)dummy_va, 0x0);
/* use CMDQ to set to PATTERN */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
cmdq_op_write_reg(handle, dummy_pa, PATTERN, MASK);
cmdq_task_flush(handle);
cmdq_task_destroy(handle);
/* value check */
value = CMDQ_REG_GET32((void *)dummy_va);
if (value != EXPECT_RESULT) {
/* test fail */
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n",
value, EXPECT_RESULT);
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_write(void)
{
struct cmdqRecStruct *handle = NULL;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
uint32_t value = 0;
unsigned long dummy_va, dummy_pa;
CMDQ_MSG("%s\n", __func__);
if (gCmdqTestSecure) {
dummy_va = CMDQ_TEST_MMSYS_DUMMY_VA;
dummy_pa = CMDQ_TEST_MMSYS_DUMMY_PA;
} else {
dummy_va = CMDQ_TEST_GCE_DUMMY_VA;
dummy_pa = CMDQ_TEST_GCE_DUMMY_PA;
}
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32((void *)dummy_va, ~0);
/* use CMDQ to set to PATTERN */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
cmdq_op_write_reg(handle, dummy_pa, PATTERN, ~0);
cmdq_task_flush(handle);
cmdq_task_destroy(handle);
/* value check */
value = CMDQ_REG_GET32((void *)dummy_va);
if (value != PATTERN) {
/* test fail */
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n",
value, PATTERN);
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_prefetch(void)
{
struct cmdqRecStruct *handle = NULL;
int i;
uint32_t value = 0;
/* 0xDEADDEAD; */
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
const uint32_t testRegPA = CMDQ_TEST_GCE_DUMMY_PA;
const uint32_t REP_COUNT = 500;
CMDQ_MSG("%s\n", __func__);
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, ~0);
/* No prefetch. */
/* use CMDQ to set to PATTERN */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, false);
for (i = 0; i < REP_COUNT; ++i)
cmdq_op_write_reg(handle, testRegPA, PATTERN, ~0);
cmdq_task_flush_async(handle);
cmdq_task_flush_async(handle);
cmdq_task_flush_async(handle);
msleep_interruptible(1000);
/* use prefetch */
cmdq_task_create(CMDQ_SCENARIO_DEBUG_PREFETCH, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, false);
for (i = 0; i < REP_COUNT; ++i)
cmdq_op_write_reg(handle, testRegPA, PATTERN, ~0);
cmdq_task_flush_async(handle);
cmdq_task_flush_async(handle);
cmdq_task_flush_async(handle);
msleep_interruptible(1000);
cmdq_task_destroy(handle);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_GCE_DUMMY_VA);
if (value != PATTERN) {
/* test fail */
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n",
value, PATTERN);
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_backup_register(void)
{
#ifdef CMDQ_GPR_SUPPORT
struct cmdqRecStruct *handle = NULL;
int ret = 0;
uint32_t regAddr[3] = { CMDQ_TEST_GCE_DUMMY_PA,
CMDQ_GPR_R32_PA(CMDQ_DATA_REG_PQ_COLOR),
CMDQ_GPR_R32_PA(CMDQ_DATA_REG_2D_SHARPNESS_0)
};
uint32_t regValue[3] = { 0 };
CMDQ_MSG("%s\n", __func__);
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, 0xAAAAAAAA);
CMDQ_REG_SET32(CMDQ_GPR_R32(CMDQ_DATA_REG_PQ_COLOR), 0xBBBBBBBB);
CMDQ_REG_SET32(CMDQ_GPR_R32(CMDQ_DATA_REG_2D_SHARPNESS_0), 0xCCCCCCCC);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
ret = cmdq_task_flush_and_read_register(handle, 3, regAddr, regValue);
cmdq_task_destroy(handle);
if (regValue[0] != 0xAAAAAAAA) {
/* Print error status */
CMDQ_ERR("regValue[0] is 0x%08x, wrong!\n", regValue[0]);
}
if (regValue[1] != 0xBBBBBBBB) {
/* Print error status */
CMDQ_ERR("regValue[1] is 0x%08x, wrong!\n", regValue[1]);
}
if (regValue[2] != 0xCCCCCCCC) {
/* Print error status */
CMDQ_ERR("regValue[2] is 0x%08x, wrong!\n", regValue[2]);
}
CMDQ_MSG("%s END\n", __func__);
#else
CMDQ_ERR("func:%s failed since CMDQ doesn't support GPR\n", __func__);
#endif
}
static void testcase_get_result(void)
{
#ifdef CMDQ_GPR_SUPPORT
int i;
struct cmdqRecStruct *handle = NULL;
int ret = 0;
struct cmdqCommandStruct desc = { 0 };
int registers[1] = { CMDQ_TEST_GCE_DUMMY_PA };
int result[1] = { 0 };
CMDQ_MSG("%s\n", __func__);
/* make sure each scenario runs properly with empty commands */
/* use CMDQ_SCENARIO_PRIMARY_ALL to test */
/* because it has COLOR0 HW flag */
cmdq_task_create(CMDQ_SCENARIO_PRIMARY_ALL, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
/* insert dummy commands */
cmdq_op_finalize_command(handle, false);
/* init desc attributes after finalize command */
/* to ensure correct size and buffer addr */
desc.scenario = handle->scenario;
desc.priority = handle->priority;
desc.engineFlag = handle->engineFlag;
desc.pVABase = (cmdqU32Ptr_t) (unsigned long)handle->pBuffer;
desc.blockSize = handle->blockSize;
desc.regRequest.count = 1;
desc.regRequest.regAddresses = (cmdqU32Ptr_t) (unsigned long)registers;
desc.regValue.count = 1;
desc.regValue.regValues = (cmdqU32Ptr_t) (unsigned long)result;
desc.secData.is_secure = handle->secData.is_secure;
desc.secData.addrMetadataCount = 0;
desc.secData.addrMetadataMaxCount = 0;
desc.secData.waitCookie = 0;
desc.secData.resetExecCnt = false;
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, 0xdeaddead);
/* manually raise the dirty flag */
cmdqCoreSetEvent(CMDQ_EVENT_MUTEX0_STREAM_EOF);
cmdqCoreSetEvent(CMDQ_EVENT_MUTEX1_STREAM_EOF);
cmdqCoreSetEvent(CMDQ_EVENT_MUTEX2_STREAM_EOF);
cmdqCoreSetEvent(CMDQ_EVENT_MUTEX3_STREAM_EOF);
for (i = 0; i < 1; ++i) {
ret = cmdqCoreSubmitTask(&desc);
if (CMDQ_U32_PTR(desc.regValue.regValues)[0] != 0xdeaddead) {
CMDQ_ERR("TEST FAIL: reg value is 0x%08x\n",
CMDQ_U32_PTR(desc.regValue.regValues)[0]);
}
}
cmdq_task_destroy(handle);
CMDQ_MSG("%s END\n", __func__);
return;
#else
CMDQ_ERR("func:%s failed since CMDQ doesn't support GPR\n", __func__);
#endif
}
static int _testcase_simplest_command_loop_submit(
const uint32_t loop, enum CMDQ_SCENARIO_ENUM scenario,
const long long engineFlag,
const bool isSecureTask)
{
struct cmdqRecStruct *handle = NULL;
int32_t i;
CMDQ_MSG("%s\n", __func__);
cmdq_task_create(scenario, &handle);
for (i = 0; i < loop; i++) {
CMDQ_MSG("pid: %d, flush:%4d, engineFlag:0x%llx, sec:%d\n",
current->pid, i, engineFlag, isSecureTask);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, isSecureTask);
handle->engineFlag = engineFlag;
cmdq_task_flush(handle);
}
cmdq_task_destroy(handle);
CMDQ_MSG("%s END\n", __func__);
return 0;
}
/* threadfn: int (*threadfn)(void *data) */
static int _testcase_thread_dispatch(void *data)
{
long long engineFlag;
engineFlag = *((long long *)data);
_testcase_simplest_command_loop_submit(1000, CMDQ_SCENARIO_DEBUG,
engineFlag, false);
return 0;
}
static void testcase_thread_dispatch(void)
{
char threadName[20];
struct task_struct *pKThread1;
struct task_struct *pKThread2;
const long long engineFlag1 = (0x1 << CMDQ_ENG_ISP_IMGI) |
(0x1 << CMDQ_ENG_ISP_IMGO);
const long long engineFlag2 = (0x1 << CMDQ_ENG_MDP_RDMA0) |
(0x1 << CMDQ_ENG_MDP_WROT0);
CMDQ_MSG("%s\n", __func__);
CMDQ_MSG("====== 2 THREAD with different engines ===============\n");
sprintf(threadName, "cmdqKTHR_%llx", engineFlag1);
pKThread1 = kthread_run(_testcase_thread_dispatch,
(void *)(&engineFlag1), threadName);
if (IS_ERR(pKThread1)) {
CMDQ_ERR("create thread failed, thread:%s\n", threadName);
return;
}
sprintf(threadName, "cmdqKTHR_%llx", engineFlag2);
pKThread2 = kthread_run(_testcase_thread_dispatch,
(void *)(&engineFlag2), threadName);
if (IS_ERR(pKThread2)) {
CMDQ_ERR("create thread failed, thread:%s\n", threadName);
return;
}
msleep_interruptible(5 * 1000);
/* ensure both thread execute all command */
_testcase_simplest_command_loop_submit(1, CMDQ_SCENARIO_DEBUG,
engineFlag1, false);
_testcase_simplest_command_loop_submit(1, CMDQ_SCENARIO_DEBUG,
engineFlag2, false);
CMDQ_MSG("%s END\n", __func__);
}
static int _testcase_full_thread_array(void *data)
{
/* this testcase will be passed only when cmdqSecDr */
/* support async config mode because */
/* never execute event setting till IWC back to NWd */
struct cmdqRecStruct *handle = NULL;
int32_t i;
/* clearn event first */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
/* specify engine flag in order to */
/* dispatch all tasks to the same HW thread */
handle->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
cmdq_op_wait_no_clear(handle, CMDQ_SYNC_TOKEN_USER_0);
for (i = 0; i < 50; i++) {
CMDQ_LOG("pid: %d, flush:%6d\n", current->pid, i);
if (i == 40) {
CMDQ_LOG("set token: %d to 1\n",
CMDQ_SYNC_TOKEN_USER_0);
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
}
cmdq_task_flush_async(handle);
}
cmdq_task_destroy(handle);
return 0;
}
static void testcase_full_thread_array(void)
{
char threadName[20];
struct task_struct *pKThread;
CMDQ_MSG("%s\n", __func__);
sprintf(threadName, "cmdqKTHR");
pKThread = kthread_run(_testcase_full_thread_array, NULL, threadName);
if (IS_ERR(pKThread)) {
/* create thread failed */
CMDQ_ERR("create thread failed, thread:%s\n", threadName);
}
msleep_interruptible(5 * 1000);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_module_full_dump(void)
{
struct cmdqRecStruct *handle = NULL;
const bool alreadyEnableLog = cmdq_core_should_print_msg();
CMDQ_MSG("%s\n", __func__);
/* enable full dump */
if (false == alreadyEnableLog)
cmdq_core_set_log_level(1);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
/* clean SW token to invoke SW timeout latter */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
/* turn on ALL except DISP engine flag to test dump */
handle->engineFlag = ~(CMDQ_ENG_DISP_GROUP_BITS);
CMDQ_LOG("%s, engine: 0x%llx, it's a timeout case\n",
__func__, handle->engineFlag);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, false);
cmdq_op_wait_no_clear(handle, CMDQ_SYNC_TOKEN_USER_0);
cmdq_task_flush(handle);
/* disable full dump */
if (false == alreadyEnableLog)
cmdq_core_set_log_level(0);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_profile_marker(void)
{
struct cmdqRecStruct *handle = NULL;
/* const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16); */
/* uint32_t value = 0; */
CMDQ_MSG("%s\n", __func__);
CMDQ_MSG("%s: write op without profile marker\n", __func__);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_op_write_reg(handle, CMDQ_TEST_GCE_DUMMY_PA, 0xBCBCBCBC, ~0);
cmdq_task_flush(handle);
CMDQ_MSG("%s: write op with profile marker\n", __func__);
cmdq_task_reset(handle);
cmdq_op_write_reg(handle, CMDQ_TEST_GCE_DUMMY_PA, 0x11111111, ~0);
cmdq_op_profile_marker(handle, "WRI_BEGIN");
cmdq_op_write_reg(handle, CMDQ_TEST_GCE_DUMMY_PA, 0x22222222, ~0);
cmdq_op_profile_marker(handle, "WRI_END");
cmdq_task_dump_command(handle);
cmdq_task_flush(handle);
cmdq_task_destroy(handle);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_estimate_command_exec_time(void)
{
struct cmdqRecStruct *handle = NULL;
cmdqBackupSlotHandle hSlot = 0;
cmdq_alloc_mem(&hSlot, 1);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
CMDQ_MSG("%s\n", __func__);
CMDQ_LOG("=====write(1), write_w_mask(2), poll(2),\n");
CMDQ_LOG("wait(2), sync(1), eof(1), jump(1)\n");
cmdq_op_write_reg(handle, CMDQ_TEST_GCE_DUMMY_PA, 0xBBBBBBBA, ~0);
cmdq_op_write_reg(handle, CMDQ_TEST_GCE_DUMMY_PA, 0xBBBBBBBB, 0x1);
cmdq_op_write_reg(handle, CMDQ_TEST_GCE_DUMMY_PA, 0xBBBBBBBC, 0x3);
cmdq_op_poll(handle, CMDQ_TEST_GCE_DUMMY_PA, 0xCCCCCCCA, ~0);
cmdq_op_poll(handle, CMDQ_TEST_GCE_DUMMY_PA, 0xCCCCCCCB, 0x1);
cmdq_op_wait(handle, CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_wait_no_clear(handle, CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_clear_event(handle, CMDQ_SYNC_TOKEN_USER_1);
cmdq_task_dump_command(handle);
cmdq_task_estimate_command_exec_time(handle);
CMDQ_LOG("=====slots...\n");
cmdq_task_reset(handle);
cmdq_op_read_reg_to_mem(handle, hSlot, 0, CMDQ_TEST_GCE_DUMMY_PA);
cmdq_op_read_mem_to_reg(handle, hSlot, 0, CMDQ_TEST_GCE_DUMMY_PA);
cmdq_op_write_mem(handle, hSlot, 0, 0xDEADDEAD);
cmdq_task_dump_command(handle);
cmdq_task_estimate_command_exec_time(handle);
CMDQ_MSG("%s END\n", __func__);
cmdq_free_mem(hSlot);
cmdq_task_destroy(handle);
}
#ifdef CMDQ_SECURE_PATH_SUPPORT
#include "cmdq_sec.h"
#include "cmdq_sec_iwc_common.h"
#include "cmdqsectl_api.h"
int32_t cmdq_sec_submit_to_secure_world_async_unlocked(
uint32_t iwcCommand,
struct TaskStruct *pTask, int32_t thread,
CmdqSecFillIwcCB iwcFillCB, void *data, bool throwAEE);
#endif
void testcase_secure_basic(void)
{
#ifdef CMDQ_SECURE_PATH_SUPPORT
int32_t status = 0;
CMDQ_MSG("%s\n", __func__);
do {
CMDQ_MSG("=========== Hello cmdqSecTl ===========\n ");
status =
cmdq_sec_submit_to_secure_world_async_unlocked(
CMD_CMDQ_TL_TEST_HELLO_TL, NULL,
CMDQ_INVALID_THREAD, NULL, NULL, false);
if (status < 0) {
/* entry cmdqSecTL failed */
CMDQ_ERR("entry cmdqSecTL failed, status:%d\n", status);
}
CMDQ_MSG("=========== Hello cmdqSecDr ===========\n ");
status =
cmdq_sec_submit_to_secure_world_async_unlocked(
CMD_CMDQ_TL_TEST_DUMMY, NULL,
CMDQ_INVALID_THREAD,
NULL, NULL, false);
if (status < 0) {
/* entry cmdqSecDr failed */
CMDQ_ERR("entry cmdqSecDr failed, status:%d\n", status);
}
} while (0);
CMDQ_MSG("%s END\n", __func__);
#endif
}
void testcase_secure_disp_scenario(void)
{
#ifdef CMDQ_SECURE_PATH_SUPPORT
/* note: this case used to verify command compose in secure world. */
/* It must test when DISP driver has */
/* switched primary DISP to secure path, */
/* otherwise we should disable "enable GCE" */
/* in SWd in order to prevent phone hang */
struct cmdqRecStruct *hDISP;
struct cmdqRecStruct *hSubDisp;
struct cmdqRecStruct *hDisableDISP;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
CMDQ_MSG("%s\n", __func__);
CMDQ_LOG("=========== secure primary path ===========\n");
cmdq_task_create(CMDQ_SCENARIO_PRIMARY_DISP, &hDISP);
cmdq_task_reset(hDISP);
cmdq_task_set_secure(hDISP, true);
cmdq_op_write_reg(hDISP, CMDQ_TEST_MMSYS_DUMMY_PA, PATTERN, ~0);
cmdq_task_flush(hDISP);
cmdq_task_destroy(hDISP);
CMDQ_LOG("=========== secure sub path ===========\n");
cmdq_task_create(CMDQ_SCENARIO_SUB_DISP, &hSubDisp);
cmdq_task_reset(hSubDisp);
cmdq_task_set_secure(hSubDisp, true);
cmdq_op_write_reg(hSubDisp, CMDQ_TEST_MMSYS_DUMMY_PA, PATTERN, ~0);
cmdq_task_flush(hSubDisp);
cmdq_task_destroy(hSubDisp);
CMDQ_LOG("=========== disp secure primary path ===========\n");
cmdq_task_create(CMDQ_SCENARIO_DISP_PRIMARY_DISABLE_SECURE_PATH,
&hDisableDISP);
cmdq_task_reset(hDisableDISP);
cmdq_task_set_secure(hDisableDISP, true);
cmdq_op_write_reg(hDisableDISP, CMDQ_TEST_MMSYS_DUMMY_PA, PATTERN, ~0);
cmdq_task_flush(hDisableDISP);
cmdq_task_destroy(hDisableDISP);
CMDQ_MSG("%s END\n", __func__);
#endif
}
void testcase_secure_meta_data(void)
{
#ifdef CMDQ_SECURE_PATH_SUPPORT
struct cmdqRecStruct *hReqMDP;
struct cmdqRecStruct *hReqDISP;
const uint32_t PATTERN_MDP = (1 << 0) | (1 << 2) | (1 << 16);
const uint32_t PATTERN_DISP = 0xBCBCBCBC;
uint32_t value = 0;
CMDQ_MSG("%s\n", __func__);
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(CMDQ_TEST_MMSYS_DUMMY_VA, ~0);
CMDQ_MSG("=========== MDP case ===========\n");
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &hReqMDP);
cmdq_task_reset(hReqMDP);
cmdq_task_set_secure(hReqMDP, true);
/* specify use MDP engine */
hReqMDP->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0) |
(1LL << CMDQ_ENG_MDP_WROT0);
/* enable secure test */
cmdq_task_secure_enable_dapc(hReqMDP,
(1LL << CMDQ_ENG_MDP_RDMA0) |
(1LL << CMDQ_ENG_MDP_WROT0));
cmdq_task_secure_enable_port_security(hReqMDP,
(1LL << CMDQ_ENG_MDP_RDMA0) |
(1LL << CMDQ_ENG_MDP_WROT0));
/* record command */
cmdq_op_write_reg(hReqMDP, CMDQ_TEST_MMSYS_DUMMY_PA, PATTERN_MDP, ~0);
cmdq_task_flush(hReqMDP);
cmdq_task_destroy(hReqMDP);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
if (value != PATTERN_MDP) {
/* test fail */
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n",
value, PATTERN_MDP);
}
CMDQ_MSG("=========== DISP case ===========\n");
cmdq_task_create(CMDQ_SCENARIO_SUB_DISP, &hReqDISP);
cmdq_task_reset(hReqDISP);
cmdq_task_set_secure(hReqDISP, true);
/* enable secure test */
cmdq_task_secure_enable_dapc(hReqDISP, (1LL << CMDQ_ENG_DISP_WDMA1));
cmdq_task_secure_enable_port_security(hReqDISP,
(1LL << CMDQ_ENG_DISP_WDMA1));
/* record command */
cmdq_op_write_reg(hReqDISP, CMDQ_TEST_MMSYS_DUMMY_PA, PATTERN_DISP, ~0);
cmdq_task_flush(hReqDISP);
cmdq_task_destroy(hReqDISP);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
if (value != PATTERN_DISP) {
/* test fail */
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n",
value, PATTERN_DISP);
}
CMDQ_MSG("%s END\n", __func__);
#else
CMDQ_ERR("%s failed since not support secure path\n", __func__);
#endif
}
void testcase_submit_after_error_happened(void)
{
struct cmdqRecStruct *handle = NULL;
const uint32_t pollingVal = 0x00003001;
CMDQ_MSG("%s\n", __func__);
CMDQ_MSG("=========== timeout case ===========\n");
/* let poll INIFINITE */
/* CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, pollingVal); */
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, ~0);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
cmdq_op_poll(handle, CMDQ_TEST_GCE_DUMMY_PA, pollingVal, ~0);
cmdq_task_flush(handle);
CMDQ_MSG("=========== okay case ===========\n");
_testcase_simplest_command_loop_submit(1, CMDQ_SCENARIO_DEBUG, 0,
gCmdqTestSecure);
/* clear up */
cmdq_task_destroy(handle);
CMDQ_MSG("%s END\n", __func__);
}
void testcase_write_stress_test(void)
{
int32_t loop;
CMDQ_MSG("%s\n", __func__);
loop = 1;
CMDQ_MSG("=============== loop x %d ===============\n", loop);
_testcase_simplest_command_loop_submit(loop, CMDQ_SCENARIO_DEBUG,
0, gCmdqTestSecure);
loop = 100;
CMDQ_MSG("=============== loop x %d ===============\n", loop);
_testcase_simplest_command_loop_submit(loop, CMDQ_SCENARIO_DEBUG,
0, gCmdqTestSecure);
CMDQ_MSG("%s END\n", __func__);
}
void testcase_prefetch_multiple_command(void)
{
#define TEST_PREFETCH_MARKER_LOOP 2
int32_t i;
int32_t ret;
struct cmdqRecStruct *handle[TEST_PREFETCH_MARKER_LOOP] = { 0 };
struct TaskStruct *pTask[TEST_PREFETCH_MARKER_LOOP] = { 0 };
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_MSG("%s\n", __func__);
for (i = 0; i < TEST_PREFETCH_MARKER_LOOP; i++) {
CMDQ_MSG("=============== flush:%d/%d ===============\n",
i, TEST_PREFETCH_MARKER_LOOP);
cmdq_task_create(CMDQ_SCENARIO_DEBUG_PREFETCH, &(handle[i]));
cmdq_task_reset(handle[i]);
cmdq_task_set_secure(handle[i], false);
/* record instructions which needs prefetch */
cmdqRecEnablePrefetch(handle[i]);
cmdq_op_wait(handle[i], CMDQ_SYNC_TOKEN_USER_0);
cmdqRecDisablePrefetch(handle[i]);
/* record instructions which does not need prefetch */
cmdq_op_write_reg(handle[i], CMDQ_TEST_GCE_DUMMY_PA,
0x3000, ~0);
cmdq_op_finalize_command(handle[i], false);
cmdq_task_dump_command(handle[i]);
ret = _test_submit_async(handle[i], &pTask[i]);
}
for (i = 0; i < TEST_PREFETCH_MARKER_LOOP; ++i) {
if (pTask[i] == NULL) {
CMDQ_ERR("%s pTask[%d] is NULL\n ", __func__, i);
continue;
}
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
msleep_interruptible(100);
CMDQ_MSG("wait 0x%p, i:%2d========\n", pTask[i], i);
ret = cmdqCoreWaitAndReleaseTask(pTask[i], 500);
cmdq_task_destroy(handle[i]);
}
CMDQ_MSG("%s END\n", __func__);
}
#ifdef CMDQ_SECURE_PATH_SUPPORT
static int _testcase_concurrency(void *data)
{
uint32_t securePath;
securePath = *((uint32_t *) data);
CMDQ_MSG("start secure(%d) path\n", securePath);
_testcase_simplest_command_loop_submit(1000, CMDQ_SCENARIO_DEBUG,
(0x1 << CMDQ_ENG_MDP_RSZ0),
securePath);
return 0;
}
#endif
static void testcase_concurrency_for_normal_path_and_secure_path(
void)
{
#ifdef CMDQ_SECURE_PATH_SUPPORT
struct task_struct *pKThread1;
struct task_struct *pKThread2;
const uint32_t securePath[2] = { 0, 1 };
CMDQ_MSG("%s\n", __func__);
pKThread1 = kthread_run(_testcase_concurrency,
(void *)(&securePath[0]), "cmdqNormal");
if (IS_ERR(pKThread1)) {
CMDQ_ERR("create cmdqNormal failed\n");
return;
}
pKThread2 = kthread_run(_testcase_concurrency,
(void *)(&securePath[1]), "cmdqSecure");
if (IS_ERR(pKThread2)) {
CMDQ_ERR("create cmdqSecure failed\n");
return;
}
msleep_interruptible(5 * 1000);
/* ensure both thread execute all command */
_testcase_simplest_command_loop_submit(1,
CMDQ_SCENARIO_DEBUG, 0x0, false);
CMDQ_MSG("%s END\n", __func__);
return;
#endif
}
void testcase_async_write_stress_test(void)
{
}
static void testcase_nonsuspend_irq(void)
{
struct cmdqRecStruct *handle, *handle2;
struct TaskStruct *pTask, *pTask2;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
uint32_t value = 0;
CMDQ_MSG("%s\n", __func__);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, ~0);
/* use CMDQ to set to PATTERN */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
handle->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0);
cmdq_op_write_reg(handle, CMDQ_TEST_GCE_DUMMY_PA, PATTERN, ~0);
cmdq_op_wait(handle, CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_finalize_command(handle, false);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle2);
cmdq_task_reset(handle2);
cmdq_task_set_secure(handle2, gCmdqTestSecure);
handle2->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0);
/* force GCE to wait in second command before EOC */
cmdq_op_wait(handle2, CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_finalize_command(handle2, false);
_test_submit_async(handle, &pTask);
_test_submit_async(handle2, &pTask2);
msleep_interruptible(500);
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
/* test code: use to trigger GCE continue test command */
/* put in cmdq_core::handleIRQ to test */
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
CMDQ_MSG("IRQ: After set user sw token\n");
cmdqCoreWaitAndReleaseTask(pTask, 500);
cmdqCoreWaitAndReleaseTask(pTask2, 500);
cmdq_task_destroy(handle);
cmdq_task_destroy(handle2);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_GCE_DUMMY_VA);
if (value != PATTERN) {
/* test fail */
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n",
value, PATTERN);
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_module_full_mdp_engine(void)
{
struct cmdqRecStruct *handle = NULL;
const bool alreadyEnableLog = cmdq_core_should_print_msg();
CMDQ_MSG("%s\n", __func__);
/* enable full dump */
if (false == alreadyEnableLog)
cmdq_core_set_log_level(1);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
/* turn on ALL except DISP engine flag to test clock operation */
handle->engineFlag = ~(CMDQ_ENG_DISP_GROUP_BITS);
CMDQ_LOG("%s, engine: 0x%llx, it's a engine clock test case\n",
__func__, handle->engineFlag);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, false);
cmdq_task_flush(handle);
/* disable full dump */
if (false == alreadyEnableLog)
cmdq_core_set_log_level(0);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_trigger_engine_dispatch_check(void)
{
struct cmdqRecStruct *handle, *handle2, *hTrigger;
struct TaskStruct *pTask;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
uint32_t value = 0;
uint32_t loopIndex = 0;
CMDQ_MSG("%s\n", __func__);
/* Create first task and run without wait */
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, ~0);
/* use CMDQ to set to PATTERN */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
handle->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0);
cmdq_op_finalize_command(handle, false);
_test_submit_async(handle, &pTask);
/* Create trigger loop */
cmdq_task_create(CMDQ_SCENARIO_TRIGGER_LOOP, &hTrigger);
cmdq_task_reset(hTrigger);
cmdq_op_wait(hTrigger, CMDQ_SYNC_TOKEN_USER_0);
cmdq_task_start_loop(hTrigger);
/* Sleep to let trigger loop run fow a while */
CMDQ_MSG("%s before start sleep and trigger token\n", __func__);
for (loopIndex = 0; loopIndex < 10; loopIndex++) {
msleep_interruptible(500);
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
CMDQ_MSG("%s after sleep 5000 and send (%d)\n", __func__,
loopIndex);
}
/* Create second task and should run well */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle2);
cmdq_task_reset(handle2);
cmdq_task_set_secure(handle2, gCmdqTestSecure);
handle2->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0);
cmdq_op_write_reg(handle2, CMDQ_TEST_GCE_DUMMY_PA, PATTERN, ~0);
cmdq_task_flush(handle2);
cmdq_task_destroy(handle2);
/* Call wait to release first task */
cmdqCoreWaitAndReleaseTask(pTask, 500);
cmdq_task_destroy(handle);
cmdq_task_destroy(hTrigger);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_GCE_DUMMY_VA);
if (value != PATTERN) {
/* test fail */
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n",
value, PATTERN);
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_complicated_engine_thread(void)
{
#define TASK_COUNT 6
struct cmdqRecStruct *handle[TASK_COUNT] = { 0 };
struct TaskStruct *pTask[TASK_COUNT] = { 0 };
uint64_t engineFlag[TASK_COUNT] = { 0 };
uint32_t taskIndex = 0;
CMDQ_MSG("%s\n", __func__);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
/* config engine flag for test */
engineFlag[0] = (1LL << CMDQ_ENG_MDP_RDMA0);
engineFlag[1] = (1LL << CMDQ_ENG_MDP_RDMA0) |
(1LL << CMDQ_ENG_MDP_RSZ0);
engineFlag[2] = (1LL << CMDQ_ENG_MDP_RSZ0);
engineFlag[3] = (1LL << CMDQ_ENG_MDP_TDSHP0);
engineFlag[4] = (1LL << CMDQ_ENG_MDP_RDMA0) |
(1LL << CMDQ_ENG_MDP_TDSHP0);
engineFlag[5] = (1LL << CMDQ_ENG_MDP_TDSHP0) |
(1LL << CMDQ_ENG_MDP_RSZ0);
for (taskIndex = 0; taskIndex < TASK_COUNT; taskIndex++) {
/* Create task and run with wait */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle[taskIndex]);
cmdq_task_reset(handle[taskIndex]);
cmdq_task_set_secure(handle[taskIndex], gCmdqTestSecure);
handle[taskIndex]->engineFlag = engineFlag[taskIndex];
cmdq_op_wait(handle[taskIndex], CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_finalize_command(handle[taskIndex], false);
_test_submit_async(handle[taskIndex], &pTask[taskIndex]);
}
for (taskIndex = 0; taskIndex < TASK_COUNT; taskIndex++) {
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
/* Call wait to release task */
cmdqCoreWaitAndReleaseTask(pTask[taskIndex], 500);
cmdq_task_destroy(handle[taskIndex]);
msleep_interruptible(1000);
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_append_task_verify(void)
{
struct cmdqRecStruct *handle, *handle2;
struct TaskStruct *pTask, *pTask2;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
uint32_t value = 0;
uint32_t loopIndex = 0;
CMDQ_MSG("%s\n", __func__);
cmdq_task_create(CMDQ_SCENARIO_DEBUG_PREFETCH, &handle);
cmdq_task_create(CMDQ_SCENARIO_DEBUG_PREFETCH, &handle2);
for (loopIndex = 0; loopIndex < 2; loopIndex++) {
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
/* clear dummy register */
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, ~0);
/* Create first task and run with wait */
/* use CMDQ to set to PATTERN */
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
if (loopIndex == 1)
cmdqRecEnablePrefetch(handle);
cmdq_op_wait(handle, CMDQ_SYNC_TOKEN_USER_0);
if (loopIndex == 1)
cmdqRecDisablePrefetch(handle);
cmdq_op_finalize_command(handle, false);
/* Create second task and should run well */
cmdq_task_reset(handle2);
cmdq_task_set_secure(handle2, gCmdqTestSecure);
if (loopIndex == 1)
cmdqRecEnablePrefetch(handle2);
cmdq_op_write_reg(handle2, CMDQ_TEST_GCE_DUMMY_PA, PATTERN, ~0);
if (loopIndex == 1)
cmdqRecDisablePrefetch(handle2);
cmdq_op_finalize_command(handle2, false);
_test_submit_async(handle, &pTask);
_test_submit_async(handle2, &pTask2);
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
/* Call wait to release first task */
cmdqCoreWaitAndReleaseTask(pTask, 500);
cmdqCoreWaitAndReleaseTask(pTask2, 500);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_GCE_DUMMY_VA);
if (value != PATTERN) {
/* test fail */
CMDQ_ERR("TEST FAIL: value is 0x%08x, not 0x%08x\n",
value, PATTERN);
}
}
cmdq_task_destroy(handle);
cmdq_task_destroy(handle2);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_manual_suspend_resume_test(void)
{
struct cmdqRecStruct *handle = NULL;
struct TaskStruct *pTask, *pTask2;
CMDQ_MSG("%s\n", __func__);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, false);
cmdq_op_wait(handle, CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_finalize_command(handle, false);
_test_submit_async(handle, &pTask);
/* Manual suspend and resume */
cmdqCoreSuspend();
cmdqCoreResumedNotifier();
_test_submit_async(handle, &pTask2);
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
/* Call wait to release second task */
cmdqCoreWaitAndReleaseTask(pTask2, 500);
cmdq_task_destroy(handle);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_timeout_wait_early_test(void)
{
struct cmdqRecStruct *handle = NULL;
struct TaskStruct *pTask;
CMDQ_MSG("%s\n", __func__);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
cmdq_task_create(CMDQ_SCENARIO_PRIMARY_DISP, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, false);
cmdq_op_wait_no_clear(handle, CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_finalize_command(handle, false);
_test_submit_async(handle, &pTask);
cmdq_task_flush(handle);
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
/* Call wait to release first task */
cmdqCoreWaitAndReleaseTask(pTask, 500);
cmdq_task_destroy(handle);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_timeout_reorder_test(void)
{
struct cmdqRecStruct *handle = NULL;
CMDQ_MSG("%s\n", __func__);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
cmdq_task_create(CMDQ_SCENARIO_PRIMARY_DISP, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, false);
cmdq_op_wait(handle, CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_finalize_command(handle, false);
handle->priority = 0;
cmdq_task_flush_async(handle);
handle->priority = 2;
cmdq_task_flush_async(handle);
handle->priority = 4;
cmdq_task_flush_async(handle);
cmdq_task_destroy(handle);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_error_irq(void)
{
struct cmdqRecStruct *handle = NULL;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
uint32_t value = 0;
struct TaskStruct *pTask;
CMDQ_MSG("%s\n", __func__);
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, ~0);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
/* wait and block instruction */
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
handle->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0);
cmdq_op_wait(handle, CMDQ_SYNC_TOKEN_USER_0);
cmdq_task_flush_async(handle);
/* invalid instruction */
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
handle->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0);
cmdq_append_command(handle, CMDQ_CODE_JUMP, -1, 0, 0, 0);
cmdq_task_dump_command(handle);
cmdq_task_flush_async(handle);
/* Normal command */
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
handle->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0);
cmdq_op_write_reg(handle, CMDQ_TEST_GCE_DUMMY_PA, PATTERN, ~0);
cmdq_task_flush_async(handle);
/* invalid instruction is asserted when unknown OP */
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
handle->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0);
{
const uint32_t UNKNOWN_OP = 0x50;
uint32_t *pCommand;
pCommand = (uint32_t *) ((uint8_t *) handle->pBuffer +
handle->blockSize);
*pCommand++ = 0x0;
*pCommand++ = (UNKNOWN_OP << 24);
handle->blockSize += 8;
}
cmdq_task_flush_async(handle);
/* use CMDQ to set to PATTERN */
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
handle->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0);
cmdq_op_write_reg(handle, CMDQ_TEST_GCE_DUMMY_PA, PATTERN, ~0);
cmdq_op_finalize_command(handle, false);
_test_submit_async(handle, &pTask);
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
cmdqCoreWaitAndReleaseTask(pTask, 500);
cmdq_task_destroy(handle);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_GCE_DUMMY_VA);
if (value != PATTERN) {
/* test fail */
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n",
value, PATTERN);
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_open_buffer_dump(int32_t scenario,
int32_t bufferSize)
{
CMDQ_MSG("%s\n", __func__);
CMDQ_MSG("[TESTCASE]CONFIG: bufferSize: %d, scenario: %d\n",
bufferSize, scenario);
cmdq_core_set_command_buffer_dump(scenario, bufferSize);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_check_dts_correctness(void)
{
CMDQ_MSG("%s\n", __func__);
cmdq_dev_test_dts_correctness();
CMDQ_MSG("%s END\n", __func__);
}
static int32_t testcase_monitor_callback(unsigned long data)
{
uint32_t i;
uint32_t monitorValue[CMDQ_MONITOR_EVENT_MAX];
uint32_t durationTime[CMDQ_MONITOR_EVENT_MAX];
if (false == gEventMonitor.status)
return 0;
for (i = 0; i < gEventMonitor.monitorNUM; i++) {
/* Read monitor time */
cmdq_cpu_read_mem(gEventMonitor.slotHandle,
i, &monitorValue[i]);
switch (gEventMonitor.waitType[i]) {
case CMDQ_MOITOR_TYPE_WFE:
durationTime[i] = (monitorValue[i] -
gEventMonitor.previousValue[i]) * 76;
CMDQ_LOG("[WFE] event: %s, duration: (%u ns)\n",
cmdq_core_get_event_name_ENUM(
gEventMonitor.monitorEvent[i]),
durationTime[i]);
CMDQ_MSG("[MONITOR][WFE] time:(%u ns)\n",
monitorValue[i]);
break;
case CMDQ_MOITOR_TYPE_WAIT_NO_CLEAR:
durationTime[i] = (monitorValue[i] -
gEventMonitor.previousValue[i]) * 76;
CMDQ_LOG("[Wait] event: %s, duration: (%u ns)\n",
cmdq_core_get_event_name_ENUM(
gEventMonitor.monitorEvent[i]),
durationTime[i]);
CMDQ_MSG("[MONITOR] time:(%u ns)\n", monitorValue[i]);
break;
case CMDQ_MOITOR_TYPE_QUERYREGISTER:
CMDQ_LOG(" Register:0x08%llx, value:(0x04%x)\n",
gEventMonitor.monitorEvent[i],
monitorValue[i]);
break;
}
/* Update previous monitor time */
gEventMonitor.previousValue[i] = monitorValue[i];
}
return 0;
}
static void testcase_monitor_trigger_initialization(void)
{
/* Create Slot*/
cmdq_alloc_mem(&gEventMonitor.slotHandle, CMDQ_MONITOR_EVENT_MAX);
/* Create CMDQ handle */
cmdq_task_create(CMDQ_SCENARIO_HIGHP_TRIGGER_LOOP,
&gEventMonitor.cmdqHandle);
cmdq_task_reset(gEventMonitor.cmdqHandle);
/* Insert enable pre-fetch instruction */
cmdqRecEnablePrefetch(gEventMonitor.cmdqHandle);
}
static void testcase_monitor_trigger(uint32_t waitType,
uint64_t monitorEvent)
{
int32_t eventID;
bool successAddInstruction = false;
CMDQ_MSG("%s\n", __func__);
if (true == gEventMonitor.status) {
/* Reset monitor status */
gEventMonitor.status = false;
CMDQ_LOG("stop monitor thread\n");
/* Stop trigger loop */
cmdq_task_stop_loop(gEventMonitor.cmdqHandle);
/* Destroy slot & CMDQ handle */
cmdq_free_mem(gEventMonitor.slotHandle);
/* Dump CMDQ command */
cmdq_task_destroy(gEventMonitor.cmdqHandle);
/* Reset global variable */
memset(&(gEventMonitor), 0x0, sizeof(gEventMonitor));
}
if (gEventMonitor.monitorNUM == 0) {
/* Monitor trigger thread initialization */
testcase_monitor_trigger_initialization();
} else if (gEventMonitor.monitorNUM >= CMDQ_MONITOR_EVENT_MAX) {
waitType = CMDQ_MOITOR_TYPE_FLUSH;
CMDQ_LOG("reach MAX monitor number: %d, force flush\n",
gEventMonitor.monitorNUM);
}
switch (waitType) {
case CMDQ_MOITOR_TYPE_FLUSH:
if (gEventMonitor.monitorNUM > 0) {
CMDQ_LOG("start monitor thread\n");
/* Insert disable pre-fetch instruction */
cmdqRecDisablePrefetch(gEventMonitor.cmdqHandle);
/* Set monitor status */
gEventMonitor.status = true;
/* Start trigger loop */
cmdq_task_start_loop_callback(gEventMonitor.cmdqHandle,
&testcase_monitor_callback, 0);
cmdq_task_dump_command(gEventMonitor.cmdqHandle);
}
break;
case CMDQ_MOITOR_TYPE_WFE:
eventID = (int32_t)monitorEvent;
if (eventID >= 0 && eventID < CMDQ_SYNC_TOKEN_MAX) {
cmdq_op_wait(gEventMonitor.cmdqHandle, eventID);
cmdq_op_read_reg_to_mem(gEventMonitor.cmdqHandle,
gEventMonitor.slotHandle,
gEventMonitor.monitorNUM, CMDQ_APXGPT2_COUNT);
successAddInstruction = true;
}
break;
case CMDQ_MOITOR_TYPE_WAIT_NO_CLEAR:
eventID = (int32_t)monitorEvent;
if (eventID >= 0 && eventID < CMDQ_SYNC_TOKEN_MAX) {
cmdq_op_wait_no_clear(gEventMonitor.cmdqHandle,
eventID);
cmdq_op_read_reg_to_mem(gEventMonitor.cmdqHandle,
gEventMonitor.slotHandle,
gEventMonitor.monitorNUM, CMDQ_APXGPT2_COUNT);
successAddInstruction = true;
}
break;
case CMDQ_MOITOR_TYPE_QUERYREGISTER:
cmdq_op_read_reg_to_mem(gEventMonitor.cmdqHandle,
gEventMonitor.slotHandle,
gEventMonitor.monitorNUM, monitorEvent);
successAddInstruction = true;
break;
}
if (true == successAddInstruction) {
gEventMonitor.waitType[gEventMonitor.monitorNUM] = waitType;
gEventMonitor.monitorEvent[gEventMonitor.monitorNUM] =
monitorEvent;
gEventMonitor.monitorNUM++;
}
CMDQ_MSG("%s\n", __func__);
}
static void testcase_poll_monitor_delay_continue(
struct work_struct *workItem)
{
/* set event to start next polling */
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_POLL_MONITOR);
CMDQ_LOG("monitor after delay: (%d)ms, start polling again\n",
gPollMonitor.delayTime);
}
static int32_t testcase_poll_monitor_callback(unsigned long data)
{
uint32_t pollTime;
if (false == gPollMonitor.status)
return 0;
cmdq_cpu_read_mem(gPollMonitor.slotHandle, 0, &pollTime);
CMDQ_LOG("monitor, time: (%u ns), regAddr: 0x%08llx,\n",
pollTime, gPollMonitor.pollReg);
CMDQ_LOG("regValue: 0x%08llx, regMask=0x%08llx\n",
gPollMonitor.pollValue, gPollMonitor.pollMask);
schedule_delayed_work(&gPollMonitor.delayContinueWork,
gPollMonitor.delayTime);
return 0;
}
static void testcase_poll_monitor_trigger(uint64_t pollReg,
uint64_t pollValue, uint64_t pollMask)
{
CMDQ_MSG("%s\n", __func__);
if (true == gPollMonitor.status) {
/* Reset monitor status */
gPollMonitor.status = false;
CMDQ_LOG("stop polling monitor thread: regAddr: 0x%08llx\n",
gPollMonitor.pollReg);
/* Stop trigger loop */
cmdq_task_stop_loop(gPollMonitor.cmdqHandle);
/* Destroy slot & CMDQ handle */
cmdq_free_mem(gPollMonitor.slotHandle);
cmdq_task_destroy(gPollMonitor.cmdqHandle);
/* Reset global variable */
memset(&(gPollMonitor), 0x0, sizeof(gPollMonitor));
}
if (-1 == pollReg)
return;
CMDQ_LOG("regAddr=0x%08llx, regValue=0x%08llx, regMask=0x%08llx\n",
pollReg, pollValue, pollMask);
/* Set event to start first polling */
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_POLL_MONITOR);
/* Create slot */
cmdq_alloc_mem(&gPollMonitor.slotHandle, 1);
/* Create CMDQ handle */
cmdq_task_create(CMDQ_SCENARIO_LOWP_TRIGGER_LOOP,
&gPollMonitor.cmdqHandle);
cmdq_task_reset(gPollMonitor.cmdqHandle);
/* Insert monitor thread command */
cmdq_op_wait(gPollMonitor.cmdqHandle, CMDQ_SYNC_TOKEN_POLL_MONITOR);
if (cmdq_op_poll(gPollMonitor.cmdqHandle,
pollReg, pollValue, pollMask) == 0) {
cmdq_op_read_reg_to_mem(gPollMonitor.cmdqHandle,
gPollMonitor.slotHandle, 0, CMDQ_APXGPT2_COUNT);
/* Set value to global variable */
gPollMonitor.pollReg = pollReg;
gPollMonitor.pollValue = pollValue;
gPollMonitor.pollMask = pollMask;
gPollMonitor.delayTime = 1;
gPollMonitor.status = true;
INIT_DELAYED_WORK(&gPollMonitor.delayContinueWork,
testcase_poll_monitor_delay_continue);
/* Start trigger loop */
cmdq_task_start_loop_callback(gPollMonitor.cmdqHandle,
&testcase_poll_monitor_callback, 0);
/* Dump CMDQ command */
cmdq_task_dump_command(gPollMonitor.cmdqHandle);
} else {
/* Destroy slot & CMDQ handle */
cmdq_free_mem(gPollMonitor.slotHandle);
cmdq_task_destroy(gPollMonitor.cmdqHandle);
}
CMDQ_MSG("%s\n", __func__);
}
static void testcase_acquire_resource(enum CMDQ_EVENT_ENUM resourceEvent,
bool acquireExpected)
{
struct cmdqRecStruct *handle = NULL;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
uint32_t value = 0;
int32_t acquireResult;
CMDQ_MSG("%s\n", __func__);
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, ~0);
/* use CMDQ to set to PATTERN */
cmdq_task_create(CMDQ_SCENARIO_PRIMARY_DISP, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
acquireResult = cmdq_resource_acquire_and_write(handle, resourceEvent,
CMDQ_TEST_GCE_DUMMY_PA, PATTERN, ~0);
if (acquireResult < 0) {
/* Do error handle for acquire resource fail */
if (acquireExpected) {
/* print error message */
CMDQ_ERR("Acquire resource fail: it's not expected!\n");
} else {
/* print message */
CMDQ_LOG("Acquire resource fail: it's expected!\n");
}
} else {
if (!acquireExpected) {
/* print error message */
CMDQ_ERR("Acquire resource success: not expected!\n");
} else {
/* print message */
CMDQ_LOG("Acquire resource success: it's expected!\n");
}
}
cmdq_task_flush(handle);
cmdq_task_destroy(handle);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_GCE_DUMMY_VA);
if (value != PATTERN && acquireExpected) {
/* test fail */
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n",
value, PATTERN);
}
CMDQ_MSG("%s END\n", __func__);
}
static int32_t testcase_res_release_cb(enum CMDQ_EVENT_ENUM resourceEvent)
{
struct cmdqRecStruct *handle = NULL;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
CMDQ_MSG("%s\n", __func__);
/* Flush release command immedately with wait MUTEX event */
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, ~0);
/* use CMDQ to set to PATTERN */
cmdq_task_create(CMDQ_SCENARIO_PRIMARY_DISP, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
/* simulate display need to wait single */
cmdq_op_wait_no_clear(handle, CMDQ_SYNC_TOKEN_USER_0);
/* simulate release resource via write register */
cmdq_resource_release_and_write(handle, resourceEvent,
CMDQ_TEST_GCE_DUMMY_PA, PATTERN, ~0);
cmdq_task_flush_async(handle);
cmdq_task_destroy(handle);
CMDQ_MSG("%s END\n", __func__);
return 0;
}
static int32_t testcase_res_available_cb(
enum CMDQ_EVENT_ENUM resourceEvent)
{
CMDQ_MSG("%s\n", __func__);
testcase_acquire_resource(resourceEvent, true);
CMDQ_MSG("%s END\n", __func__);
return 0;
}
static void testcase_notify_and_delay_submit(uint32_t delayTimeMS)
{
struct cmdqRecStruct *handle = NULL;
const uint32_t PATTERN = (1 << 0) | (1 << 2) | (1 << 16);
uint32_t value = 0;
const uint64_t engineFlag = (1LL << CMDQ_ENG_MDP_WROT0);
const enum CMDQ_EVENT_ENUM resourceEvent = CMDQ_SYNC_RESOURCE_WROT0;
uint32_t contDelay;
CMDQ_MSG("%s\n", __func__);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
cmdqCoreSetResourceCallback(resourceEvent,
testcase_res_available_cb, testcase_res_release_cb);
testcase_acquire_resource(resourceEvent, true);
/* notify and delay time*/
if (delayTimeMS > 0) {
CMDQ_MSG("Before delay for acquire\n");
msleep_interruptible(delayTimeMS);
CMDQ_MSG("Before lock and delay\n");
cmdqCoreLockResource(engineFlag, true);
msleep_interruptible(delayTimeMS);
CMDQ_MSG("After lock and delay\n");
}
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(CMDQ_TEST_GCE_DUMMY_VA, ~0);
/* use CMDQ to set to PATTERN */
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, gCmdqTestSecure);
handle->engineFlag = engineFlag;
cmdq_op_wait_no_clear(handle, resourceEvent);
cmdq_op_write_reg(handle, CMDQ_TEST_GCE_DUMMY_PA, PATTERN, ~0);
cmdq_task_flush_async(handle);
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
msleep_interruptible(2000);
/* Delay and continue sent */
for (contDelay = 300; contDelay < CMDQ_DELAY_RELEASE_RESOURCE_MS*1.2;
contDelay += 300) {
CMDQ_MSG("Before delay and flush\n");
msleep_interruptible(contDelay);
CMDQ_MSG("After delay\n");
cmdq_task_flush(handle);
CMDQ_MSG("After flush\n");
}
/* Simulate DISP acquire fail case, acquire immediate after flush MDP */
cmdq_task_flush_async(handle);
testcase_acquire_resource(resourceEvent, false);
cmdq_task_flush_async(handle);
cmdq_task_destroy(handle);
/* value check */
value = CMDQ_REG_GET32(CMDQ_TEST_GCE_DUMMY_VA);
if (value != PATTERN) {
/* test fail */
CMDQ_ERR("TEST FAIL: wrote value is 0x%08x, not 0x%08x\n",
value, PATTERN);
}
CMDQ_MSG("%s END\n", __func__);
}
void testcase_prefetch_round(uint32_t loopCount, uint32_t cmdCount,
bool withMask, bool withWait)
{
#define TEST_PREFETCH_LOOP 3
int32_t i, j, k;
int32_t ret;
struct cmdqRecStruct *handle[TEST_PREFETCH_LOOP] = {0};
struct TaskStruct *pTask[TEST_PREFETCH_LOOP] = { 0 };
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_MSG("%s: count:%d, withMask:%d, withWait:%d\n",
__func__, cmdCount, withMask, withWait);
for (i = 0; i < TEST_PREFETCH_LOOP; i++) {
CMDQ_MSG("=============== flush:%d/%d =======\n",
i, TEST_PREFETCH_LOOP);
for (k = 0; k < loopCount; k++) {
CMDQ_MSG("===== loop:%d/%d ===============\n",
k, loopCount);
cmdq_task_create(CMDQ_SCENARIO_DEBUG_PREFETCH,
&(handle[i]));
cmdq_task_reset(handle[i]);
cmdq_task_set_secure(handle[i], false);
/* record instructions which needs prefetch */
/* use pre-fetch with marker */
if (i == 1)
cmdqRecEnablePrefetch(handle[i]);
if (withWait)
cmdq_op_wait(handle[i], CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_profile_marker(handle[i], "ANA_BEGIN");
for (j = 0; j < cmdCount; j++) {
/* record instructions which */
/* does not need prefetch */
if (withMask)
cmdq_op_write_reg(handle[i],
CMDQ_TEST_GCE_DUMMY_PA,
0x3210, ~0xfff0);
else
cmdq_op_write_reg(handle[i],
CMDQ_TEST_GCE_DUMMY_PA,
0x3210, ~0);
}
/* disable pre-fetch with marker */
if (i == 1)
cmdqRecDisablePrefetch(handle[i]);
cmdq_op_profile_marker(handle[i], "ANA_END");
cmdq_op_finalize_command(handle[i], false);
ret = _test_submit_async(handle[i], &pTask[i]);
if (withWait) {
msleep_interruptible(500);
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
}
CMDQ_MSG("wait 0x%p, i:%2d========\n", pTask[i], i);
ret = cmdqCoreWaitAndReleaseTask(pTask[i], 500);
cmdq_task_destroy(handle[i]);
}
}
CMDQ_MSG("%s END\n", __func__);
}
void testcase_prefetch_from_DTS(void)
{
int32_t i, j;
uint32_t thread_prefetch_size;
CMDQ_MSG("%s\n", __func__);
for (i = 0; i < CMDQ_MAX_THREAD_COUNT; i++) {
thread_prefetch_size = cmdq_core_get_thread_prefetch_size(i);
for (j = 100; j <= (thread_prefetch_size + 60); j += 40) {
testcase_prefetch_round(1, j, false, true);
testcase_prefetch_round(1, j, false, false);
}
}
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_specific_bus_MMSYS(void)
{
uint32_t i;
const uint32_t loop = 1000;
const uint32_t pattern = (1 << 0) | (1 << 2) | (1 << 16);
uint32_t mmsys_register;
struct cmdqRecStruct *handle = NULL;
cmdqBackupSlotHandle slot_handle;
uint32_t start_time, end_time, duration_time;
CMDQ_MSG("%s\n", __func__);
cmdq_alloc_mem(&slot_handle, 2);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
cmdq_op_wait(handle, CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_read_reg_to_mem(handle, slot_handle, 0, CMDQ_APXGPT2_COUNT);
for (i = 0; i < loop; i++) {
mmsys_register = CMDQ_TEST_MMSYS_DUMMY_PA + (i%2)*0x4;
if (i%11 == 10)
cmdq_op_read_to_data_register(handle,
mmsys_register,
CMDQ_DATA_REG_2D_SHARPNESS_0);
else
cmdq_op_write_reg(handle, mmsys_register, pattern, ~0);
}
cmdq_op_read_reg_to_mem(handle, slot_handle, 1, CMDQ_APXGPT2_COUNT);
cmdq_task_flush(handle);
cmdq_cpu_read_mem(slot_handle, 0, &start_time);
cmdq_cpu_read_mem(slot_handle, 1, &end_time);
duration_time = (end_time - start_time) * 76;
CMDQ_LOG("duration time, %u, ns\n", duration_time);
cmdq_task_destroy(handle);
cmdq_free_mem(slot_handle);
CMDQ_MSG("%s END\n", __func__);
}
void cmdq_track_task(const struct TaskStruct *pTask)
{
CMDQ_LOG("track_task: engine: 0x%08llx\n", pTask->engineFlag);
}
static void testcase_track_task_cb(void)
{
struct cmdqRecStruct *handle = NULL;
CMDQ_MSG("%s\n", __func__);
cmdqCoreRegisterTrackTaskCB(CMDQ_GROUP_MDP, cmdq_track_task);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
handle->engineFlag = (1LL << CMDQ_ENG_MDP_CAMIN);
cmdq_task_flush(handle);
cmdqCoreRegisterTrackTaskCB(CMDQ_GROUP_MDP, NULL);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_while_test_mmsys_bus(void)
{
int32_t i;
const uint32_t loop = 5000;
CMDQ_MSG("%s\n", __func__);
for (i = 0; i < loop; i++) {
testcase_specific_bus_MMSYS();
msleep_interruptible(100);
}
CMDQ_MSG("%s END\n", __func__);
}
static int testcase_set_gce_event(void *data)
{
CMDQ_MSG("%s\n", __func__);
while (1) {
if (kthread_should_stop())
break;
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
msleep_interruptible(150);
}
CMDQ_MSG("%s END\n", __func__);
return 0;
}
static int testcase_cpu_config_non_mmsys(void *data)
{
CMDQ_MSG("%s\n", __func__);
while (1) {
if (kthread_should_stop())
break;
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(CMDQ_GPR_R32(CMDQ_DATA_REG_JPEG), ~0);
/* udelay(1); */
}
CMDQ_MSG("%s END\n", __func__);
return 0;
}
static int testcase_cpu_config_mmsys(void *data)
{
unsigned long mmsys_register;
CMDQ_MSG("%s\n", __func__);
cmdq_get_func()->enableCommonClockLocked(true);
while (1) {
if (kthread_should_stop())
break;
mmsys_register = CMDQ_TEST_MMSYS_DUMMY_VA + 0x4;
/* set to 0xFFFFFFFF */
CMDQ_REG_SET32(mmsys_register, ~0);
/* udelay(1); */
}
CMDQ_MSG("%s END\n", __func__);
return 0;
}
#define CMDQ_TEST_MAX_THREAD (32)
struct task_struct *set_event_config_th;
struct task_struct *busy_mmsys_config_th[CMDQ_TEST_MAX_THREAD] = {NULL};
struct task_struct *busy_non_mmsys_config_th[CMDQ_TEST_MAX_THREAD] = {NULL};
static void testcase_run_set_gce_event_loop(void)
{
set_event_config_th = kthread_run(testcase_set_gce_event, NULL,
"set_cmdq_event_loop");
if (IS_ERR(set_event_config_th)) {
/* print error log */
CMDQ_LOG("%s, init kthread_run failed!\n", __func__);
set_event_config_th = NULL;
}
}
static void testcase_stop_set_gce_event_loop(void)
{
if (set_event_config_th == NULL)
return;
kthread_stop(set_event_config_th);
set_event_config_th = NULL;
}
static void testcase_run_busy_non_mmsys_config_loop(void)
{
uint32_t i;
for (i = 0; i < CMDQ_TEST_MAX_THREAD; i++) {
busy_non_mmsys_config_th[i] = kthread_run(
testcase_cpu_config_non_mmsys,
NULL, "busy_config_non-mm");
if (IS_ERR(busy_non_mmsys_config_th[i])) {
/* print error log */
CMDQ_LOG("%s, thread id: %d, kthread_run failed!\n",
__func__, i);
busy_non_mmsys_config_th[i] = NULL;
}
}
}
static void testcase_stop_busy_non_mmsys_config_loop(void)
{
uint32_t i;
for (i = 0; i < CMDQ_TEST_MAX_THREAD; i++) {
if (busy_non_mmsys_config_th[i] == NULL)
continue;
kthread_stop(busy_non_mmsys_config_th[i]);
busy_non_mmsys_config_th[i] = NULL;
}
}
static void testcase_run_busy_mmsys_config_loop(void)
{
uint32_t i;
for (i = 0; i < CMDQ_TEST_MAX_THREAD; i++) {
busy_mmsys_config_th[i] = kthread_run(testcase_cpu_config_mmsys,
NULL, "busy_config_mm");
if (IS_ERR(busy_mmsys_config_th[i])) {
/* print error log */
CMDQ_LOG("%s, thread id: %d, kthread_run failed!\n",
__func__, i);
busy_mmsys_config_th[i] = NULL;
}
}
}
static void testcase_stop_busy_mmsys_config_loop(void)
{
uint32_t i;
for (i = 0; i < CMDQ_TEST_MAX_THREAD; i++) {
if (busy_mmsys_config_th[i] == NULL)
continue;
kthread_stop(busy_mmsys_config_th[i]);
busy_mmsys_config_th[i] = NULL;
}
}
static void testcase_mmsys_performance(int32_t test_id)
{
switch (test_id) {
case 0:
/* test GCE config only in bus idle situation */
testcase_run_set_gce_event_loop();
msleep_interruptible(500);
testcase_while_test_mmsys_bus();
msleep_interruptible(500);
testcase_stop_set_gce_event_loop();
break;
case 1:
/* test GCE config only when CPU */
/* busy configure MMSYS situation */
testcase_run_set_gce_event_loop();
msleep_interruptible(500);
testcase_run_busy_mmsys_config_loop();
msleep_interruptible(500);
testcase_while_test_mmsys_bus();
msleep_interruptible(500);
testcase_stop_busy_mmsys_config_loop();
msleep_interruptible(500);
testcase_stop_set_gce_event_loop();
break;
case 2:
/* test GCE config only when CPU */
/* busy configure non-MMSYS situation */
testcase_run_set_gce_event_loop();
msleep_interruptible(500);
testcase_run_busy_non_mmsys_config_loop();
msleep_interruptible(500);
testcase_while_test_mmsys_bus();
msleep_interruptible(500);
testcase_stop_busy_non_mmsys_config_loop();
msleep_interruptible(500);
testcase_stop_set_gce_event_loop();
break;
default:
CMDQ_LOG("[TESTCASE] testcase Not Found: test_id: %d\n",
test_id);
break;
}
}
void testcase_monitor_mem_start(void)
{
CMDQ_MSG("%s\n", __func__);
cmdq_core_set_mem_monitor(true);
CMDQ_MSG("%s END\n", __func__);
}
void testcase_monitor_mem_stop(void)
{
CMDQ_MSG("%s\n", __func__);
cmdq_core_set_mem_monitor(false);
cmdq_core_dump_mem_monitor();
CMDQ_MSG("%s END\n", __func__);
}
void _testcase_boundary_mem_inst(uint32_t inst_num)
{
int i;
struct cmdqRecStruct *handle = NULL;
uint32_t data;
uint32_t pattern = 0x0;
const unsigned long MMSYS_DUMMY_REG = CMDQ_TEST_MMSYS_DUMMY_VA;
CMDQ_REG_SET32(MMSYS_DUMMY_REG, 0xdeaddead);
if (CMDQ_REG_GET32(MMSYS_DUMMY_REG) != 0xdeaddead)
CMDQ_ERR("%s verify pattern register fail: 0x%08x\n",
__func__, (uint32_t)CMDQ_REG_GET32(MMSYS_DUMMY_REG));
cmdqRecCreate(CMDQ_SCENARIO_DEBUG, &handle);
cmdqRecReset(handle);
cmdqRecSetSecure(handle, gCmdqTestSecure);
/* Build a buffer with N instructions. */
CMDQ_MSG("%s record inst count: %u size: %u\n", __func__, inst_num,
(uint32_t)(inst_num * CMDQ_INST_SIZE));
for (i = 0; i < inst_num; ++i) {
pattern = i;
cmdqRecWrite(handle, CMDQ_TEST_MMSYS_DUMMY_PA, pattern, ~0);
}
cmdqRecFlush(handle);
cmdqRecDestroy(handle);
/* verify data */
do {
if (true == gCmdqTestSecure) {
CMDQ_LOG("%s, timeout case in secure path\n", __func__);
break;
}
data = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
if (pattern != data) {
CMDQ_ERR("TEST FAIL: reg 0x%08x, not pattern 0x%08x\n",
data,
pattern);
}
} while (0);
}
void testcase_boundary_mem(void)
{
uint32_t inst_num = 0;
uint32_t base_inst_num = 0;
uint32_t buffer_num = 0;
CMDQ_MSG("%s\n", __func__);
/* test cross page from 1 to 3 cases */
for (buffer_num = 1; buffer_num < 4; buffer_num++) {
base_inst_num = buffer_num *
CMDQ_CMD_BUFFER_SIZE / CMDQ_INST_SIZE;
/*
* We check 0~4 cases.
* Case 0: 3 inst (OP+EOC+JUMP) in last buffer
* Case 1: 2 inst (EOC+JUMP) in last buffer
* Case 2: last buffer empty, EOC+JUMP at end of previous buffer
* Case 3: EOC+JUMP+Blank at end of last buffer
* Case 4: EOC+JUMP+2 Blank at end of last buffer
*/
for (inst_num = 0; inst_num < 5; inst_num++)
_testcase_boundary_mem_inst(base_inst_num - inst_num);
}
CMDQ_MSG("%s END\n", __func__);
}
void testcase_boundary_mem_param(void)
{
uint32_t base_inst_num = 0;
uint32_t buffer_num = (uint32_t)gCmdqTestConfig[2];
uint32_t inst_num = (uint32_t)gCmdqTestConfig[3];
CMDQ_MSG("%s\n", __func__);
base_inst_num = buffer_num * CMDQ_CMD_BUFFER_SIZE / CMDQ_INST_SIZE;
_testcase_boundary_mem_inst(base_inst_num - inst_num);
CMDQ_MSG("%s END\n", __func__);
}
void _testcase_longloop_inst(uint32_t inst_num)
{
int i = 0;
int status = 0;
uint32_t data;
uint32_t pattern = 0x0;
const unsigned long DUMMY_REG_VA = CMDQ_TEST_GCE_DUMMY_VA;
const unsigned long DUMMY_REG_PA = CMDQ_TEST_GCE_DUMMY_PA;
CMDQ_REG_SET32(DUMMY_REG_VA, 0xdeaddead);
if (CMDQ_REG_GET32(DUMMY_REG_VA) != 0xdeaddead)
CMDQ_ERR("%s verify pattern register fail: 0x%08x\n",
__func__, (uint32_t)CMDQ_REG_GET32(DUMMY_REG_VA));
cmdqRecCreate(CMDQ_SCENARIO_TRIGGER_LOOP, &hLoopReq);
cmdqRecReset(hLoopReq);
cmdqRecSetSecure(hLoopReq, false);
cmdqRecWait(hLoopReq, CMDQ_SYNC_TOKEN_USER_0);
cmdqRecWait(hLoopReq, CMDQ_SYNC_TOKEN_USER_0);
g_loopIter = 0;
cmdq_ttm.event = CMDQ_SYNC_TOKEN_USER_0;
timer_setup(&cmdq_tltm.test_timer, _testcase_loop_timer_func, 0);
mod_timer(&cmdq_tltm.test_timer, jiffies + msecs_to_jiffies(300));
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
/*
* Build a buffer with N instructions.
* The -2 for wait and clear instruction.
*/
CMDQ_MSG("%s record inst count: %u size: %u\n", __func__, inst_num,
(uint32_t)(inst_num * CMDQ_INST_SIZE));
for (i = 0; i < inst_num - 2; ++i) {
pattern = i + 1;
cmdqRecWrite(hLoopReq, DUMMY_REG_PA, pattern, ~0);
}
/* should success */
status = cmdqRecStartLoop(hLoopReq);
if (status != 0)
CMDQ_MSG("TEST FAIL: Unable to start loop\n");
/* WAIT */
while (g_loopIter < 5)
msleep_interruptible(500);
CMDQ_MSG("%s ===== stop timer\n", __func__);
cmdqRecDestroy(hLoopReq);
del_timer(&cmdq_tltm.test_timer);
/* verify data */
do {
if (true == gCmdqTestSecure) {
CMDQ_LOG("%s, timeout case in secure path\n", __func__);
break;
}
data = CMDQ_REG_GET32(DUMMY_REG_VA);
if ((data >= 1 && data <= inst_num) == false) {
CMDQ_ERR("TEST FAIL: reg:0x%08x, pattern:0x%08x\n",
data, pattern);
}
} while (0);
}
void testcase_longloop(void)
{
uint32_t last_inst = 0;
uint32_t page_num = 0;
CMDQ_MSG("%s\n", __func__);
for (page_num = 1; page_num < 4; page_num++) {
for (last_inst = 0; last_inst < 5; last_inst++)
_testcase_longloop_inst(
CMDQ_CMD_BUFFER_SIZE *
page_num / CMDQ_INST_SIZE - last_inst);
}
CMDQ_MSG("%s\n", __func__);
}
int32_t _testcase_secure_handle(uint32_t secHandle,
enum CMDQ_SCENARIO_ENUM scenario)
{
#ifdef CMDQ_SECURE_PATH_SUPPORT
struct cmdqRecStruct *hReqMDP;
const uint32_t PATTERN_MDP = (1 << 0) | (1 << 2) | (1 << 16);
int32_t status;
cmdq_task_create(scenario, &hReqMDP);
cmdq_task_reset(hReqMDP);
cmdq_task_set_secure(hReqMDP, true);
/* specify use MDP engine */
hReqMDP->engineFlag = (1LL << CMDQ_ENG_MDP_RDMA0) |
(1LL << CMDQ_ENG_MDP_WROT0);
/* enable secure test */
cmdq_task_secure_enable_dapc(hReqMDP,
(1LL << CMDQ_ENG_MDP_RDMA0) | (1LL << CMDQ_ENG_MDP_WROT0));
cmdq_task_secure_enable_port_security(hReqMDP,
(1LL << CMDQ_ENG_MDP_RDMA0) | (1LL << CMDQ_ENG_MDP_WROT0));
/* record command */
cmdq_op_write_reg(hReqMDP, CMDQ_TEST_MMSYS_DUMMY_PA, PATTERN_MDP, ~0);
cmdq_op_write_reg_secure(hReqMDP, CMDQ_TEST_MMSYS_DUMMY_PA,
CMDQ_SAM_H_2_MVA,
secHandle, 0xf000, 0x100, 0);
cmdq_append_command(hReqMDP, CMDQ_CODE_EOC, 0, 1, 0, 0);
cmdq_append_command(hReqMDP, CMDQ_CODE_JUMP, 0, 8, 0, 0);
status = cmdq_task_flush(hReqMDP);
cmdq_task_destroy(hReqMDP);
CMDQ_MSG("%s end\n", __func__);
return status;
#else
return 0;
#endif
}
void testcase_invalid_handle(void)
{
#ifdef CMDQ_SECURE_PATH_SUPPORT
int32_t status;
CMDQ_MSG("%s\n", __func__);
/* In this case we use an invalid secure */
/* handle to check error handling */
status = _testcase_secure_handle(0xdeaddead, CMDQ_SCENARIO_SUB_DISP);
if (status >= 0)
CMDQ_ERR("TEST FAIL:invalid handle, status: %d\n", status);
/* Handle 0 will make SW do not translate to PA. */
status = _testcase_secure_handle(0x0, CMDQ_SCENARIO_DEBUG);
if (status >= 0)
CMDQ_ERR("TEST FAIL: handle 0, status: %d\n", status);
CMDQ_MSG("%s END\n", __func__);
#else
CMDQ_ERR("%s failed since not support secure path\n", __func__);
#endif
}
void testcase_get_task_by_engine(void)
{
struct cmdqRecStruct *handle = NULL;
struct TaskStruct task;
const uint64_t engineFlag = (0x1 << CMDQ_ENG_MDP_RDMA0) |
(0x1 << CMDQ_ENG_MDP_WROT0);
int32_t status;
const uint32_t debug_str_len = 1024;
CMDQ_MSG("%s\n", __func__);
memset(&task, 0, sizeof(struct TaskStruct));
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
/* clearn event first */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
/* assign engine flag */
handle->engineFlag = engineFlag;
cmdq_op_wait_no_clear(handle, CMDQ_SYNC_TOKEN_USER_0);
/* must fail before flush */
status = cmdq_core_get_running_task_by_engine(engineFlag,
debug_str_len, &task);
if (status != -EFAULT) {
CMDQ_ERR("FAIL: engine flag before:0x%llx,task flag: 0x%llx\n",
engineFlag, task.engineFlag);
}
task.userDebugStr = kzalloc(debug_str_len, GFP_KERNEL);
cmdq_task_flush_async(handle);
status = cmdq_core_get_running_task_by_engine(engineFlag,
debug_str_len, &task);
if (status != 0) {
CMDQ_ERR("FAIL:engine flag:0x%016llx,task flag:0x%016llx\n",
engineFlag, task.engineFlag);
}
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
cmdq_task_destroy(handle);
kfree(task.userDebugStr);
task.userDebugStr = NULL;
CMDQ_MSG("%s end\n", __func__);
}
void testcase_reorder(void)
{
struct cmdqRecStruct *handleA, *handleB;
uint32_t idx = 0;
uint32_t data;
const unsigned long MMSYS_DUMMY_REG = CMDQ_TEST_MMSYS_DUMMY_VA;
struct TaskStruct *pTaskA1 = NULL, *pTaskA2 = NULL, *pTaskA3 = NULL;
struct TaskStruct *pTaskB = NULL;
CMDQ_MSG("%s\n", __func__);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_REG_SET32(MMSYS_DUMMY_REG, 0xdeaddead);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handleA);
cmdq_task_reset(handleA);
cmdq_task_set_secure(handleA, gCmdqTestSecure);
cmdq_op_wait_no_clear(handleA, CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_finalize_command(handleA, false);
handleA->engineFlag = (1LL << CMDQ_ENG_MDP_CAMIN);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handleB);
cmdq_task_reset(handleB);
cmdq_task_set_secure(handleB, gCmdqTestSecure);
cmdq_op_wait_no_clear(handleB, CMDQ_SYNC_TOKEN_USER_0);
handleB->engineFlag = (1LL << CMDQ_ENG_MDP_CAMIN);
/*
* Make this task to boundary size.
* -3 because reserve for wait+eoc+jump
*/
for (idx = 0; idx < CMDQ_CMD_BUFFER_SIZE / sizeof(CMDQ_INST_SIZE) - 3;
idx++)
cmdqRecWrite(handleB, CMDQ_TEST_MMSYS_DUMMY_PA, idx, ~0);
idx--;
cmdq_op_finalize_command(handleB, false);
/* large task insert to front case */
handleA->priority = 0;
_test_submit_async(handleA, &pTaskA1);
handleA->priority = 1;
_test_submit_async(handleA, &pTaskA2);
handleA->priority = 4;
_test_submit_async(handleA, &pTaskA3);
handleB->priority = 7;
_test_submit_async(handleB, &pTaskB);
/* set token to run */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, (1L << 16) |
CMDQ_SYNC_TOKEN_USER_0);
cmdqCoreWaitAndReleaseTask(pTaskA1, 500);
cmdqCoreWaitAndReleaseTask(pTaskA2, 500);
cmdqCoreWaitAndReleaseTask(pTaskA3, 500);
cmdqCoreWaitAndReleaseTask(pTaskB, 500);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
data = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
if (idx != data)
CMDQ_ERR(
"TEST FAIL: reg value is 0x%08x, not pattern 0x%08x (large in front case)\n",
data, idx);
/* clear dummy again */
CMDQ_REG_SET32(MMSYS_DUMMY_REG, 0xdeaddead);
/* large task switch to last case */
handleA->priority = 0;
_test_submit_async(handleA, &pTaskA1);
handleB->priority = 1;
_test_submit_async(handleB, &pTaskB);
handleA->priority = 4;
_test_submit_async(handleA, &pTaskA2);
/* set token to run */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD,
(1L << 16) | CMDQ_SYNC_TOKEN_USER_0);
cmdqCoreWaitAndReleaseTask(pTaskA1, 500);
cmdqCoreWaitAndReleaseTask(pTaskA2, 500);
cmdqCoreWaitAndReleaseTask(pTaskB, 500);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
data = CMDQ_REG_GET32(CMDQ_TEST_MMSYS_DUMMY_VA);
if (idx != data)
CMDQ_ERR(
"TEST FAIL: reg value is 0x%08x, not pattern 0x%08x (large at last case)\n",
data, idx);
cmdq_task_destroy(handleA);
cmdq_task_destroy(handleB);
CMDQ_MSG("%s END\n", __func__);
}
void testcase_reorder_last(void)
{
struct cmdqRecStruct *handleA, *handleB, *handleC;
uint32_t idx = 0;
struct TaskStruct *tasks[30] = {0};
uint32_t task_idx = 0;
uint32_t wait_task_idx = 0;
CMDQ_MSG("%s\n", __func__);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_1);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handleA);
cmdq_task_reset(handleA);
cmdq_task_set_secure(handleA, gCmdqTestSecure);
cmdq_op_wait(handleA, CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_finalize_command(handleA, false);
handleA->engineFlag = (1LL << CMDQ_ENG_MDP_CAMIN);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handleB);
cmdq_task_reset(handleB);
cmdq_task_set_secure(handleB, gCmdqTestSecure);
cmdq_op_wait_no_clear(handleB, CMDQ_SYNC_TOKEN_USER_1);
cmdq_op_finalize_command(handleB, false);
handleB->engineFlag = (1LL << CMDQ_ENG_MDP_CAMIN);
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handleC);
cmdq_task_reset(handleC);
cmdq_task_set_secure(handleC, gCmdqTestSecure);
cmdq_op_wait(handleC, CMDQ_SYNC_TOKEN_USER_1);
cmdq_op_finalize_command(handleC, false);
handleC->engineFlag = (1LL << CMDQ_ENG_MDP_CAMIN);
_test_submit_async(handleA, &tasks[task_idx++]);
_test_submit_async(handleA, &tasks[task_idx++]);
/* full the thread except last one */
for (idx = 2; idx < 14; idx++)
_test_submit_async(handleB, &tasks[task_idx++]);
/* do not let last task in thread array run */
_test_submit_async(handleC, &tasks[task_idx++]);
/* this is the last task in thread list, index 15 */
_test_submit_async(handleB, &tasks[task_idx++]);
/* let first 1 task go and insert more one */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD,
(1L << 16) | CMDQ_SYNC_TOKEN_USER_0);
msleep_interruptible(3);
wait_task_idx = task_idx;
_test_submit_async(handleA, &tasks[task_idx++]);
msleep_interruptible(3);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD,
(1L << 16) | CMDQ_SYNC_TOKEN_USER_1);
/* wait the target, this must timeout without KE */
CMDQ_LOG("%s wait task: 0x%p, end inst: 0x%08x:%08x\n",
__func__, tasks[wait_task_idx],
tasks[wait_task_idx]->pCMDEnd[0],
tasks[wait_task_idx]->pCMDEnd[-1]);
if (cmdqCoreWaitAndReleaseTask(tasks[wait_task_idx], 2500) == 0)
CMDQ_ERR("TEST FAIL: Last task should timeout not success!\n");
/* clear all */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD,
(1L << 16) | CMDQ_SYNC_TOKEN_USER_0);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD,
(1L << 16) | CMDQ_SYNC_TOKEN_USER_1);
msleep_interruptible(100);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD,
(1L << 16) | CMDQ_SYNC_TOKEN_USER_0);
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD,
(1L << 16) | CMDQ_SYNC_TOKEN_USER_1);
for (idx = 0; idx < task_idx; idx++) {
if (idx == wait_task_idx)
continue;
CMDQ_LOG("%s wait other tasks: 0x%p, end inst: 0x%08x:%08x\n",
__func__, tasks[idx],
tasks[idx]->pCMDEnd[0], tasks[idx]->pCMDEnd[-1]);
if (cmdqCoreWaitAndReleaseTask(tasks[idx], 500) < 0)
CMDQ_ERR("TEST FAIL: Other task not pass,task:0x%p\n",
tasks[idx]);
}
cmdq_task_destroy(handleA);
cmdq_task_destroy(handleB);
cmdq_task_destroy(handleC);
CMDQ_LOG("%s END\n", __func__);
}
static void testcase_timeout_secure_dapc(void)
{
struct cmdqRecStruct *handle = NULL;
struct TaskStruct *pTask;
uint64_t engineFlag = (1LL << CMDQ_ENG_MDP_WROT1) |
(1LL << CMDQ_ENG_MDP_WROT0);
CMDQ_MSG("%s\n", __func__);
/* clear token */
CMDQ_REG_SET32(CMDQ_SYNC_TOKEN_UPD, CMDQ_SYNC_TOKEN_USER_0);
cmdq_task_create(CMDQ_SCENARIO_PRIMARY_DISP, &handle);
cmdq_task_reset(handle);
cmdq_task_set_secure(handle, true);
handle->engineFlag = engineFlag;
cmdq_task_secure_enable_port_security(handle, engineFlag);
cmdq_task_secure_enable_dapc(handle,
(1LL << CMDQ_ENG_MDP_WROT1) | (1LL << CMDQ_ENG_MDP_WROT0));
cmdq_op_wait_no_clear(handle, CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_finalize_command(handle, false);
_test_submit_async(handle, &pTask);
cmdq_task_flush(handle);
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
/* Call wait to release first task */
cmdqCoreWaitAndReleaseTask(pTask, 500);
cmdq_task_destroy(handle);
CMDQ_MSG("%s END\n", __func__);
}
static void testcase_end_addr_conflict(void)
{
struct cmdqRecStruct *loop_handle, *submit_handle;
u32 index;
u32 test_thread = cmdq_get_func()->dispThread(
CMDQ_SCENARIO_DEBUG_PREFETCH);
u32 test_thread_end = CMDQ_THR_FIX_END_ADDR(test_thread);
/* build trigger loop to write END addr value */
cmdq_task_create(CMDQ_SCENARIO_TRIGGER_LOOP, &loop_handle);
cmdq_task_reset(loop_handle);
cmdq_task_set_secure(loop_handle, gCmdqTestSecure);
for (index = 0; index < 48; index++)
cmdq_op_write_reg(loop_handle,
CMDQ_TEST_GCE_DUMMY_PA, test_thread_end, ~0);
cmdq_task_start_loop(loop_handle);
/* repeatly submit task to catch error */
cmdq_task_create(CMDQ_SCENARIO_DEBUG_PREFETCH, &submit_handle);
for (index = 0; index < 48; index++) {
cmdq_task_reset(submit_handle);
cmdq_task_set_secure(submit_handle, gCmdqTestSecure);
cmdq_op_write_reg(submit_handle,
CMDQ_TEST_GCE_DUMMY_PA, test_thread_end, ~0);
cmdq_task_flush(submit_handle);
CMDQ_LOG("Flush test round #%u\n", index);
msleep_interruptible(500);
}
cmdq_task_stop_loop(loop_handle);
cmdq_task_destroy(loop_handle);
cmdq_task_destroy(submit_handle);
}
enum ENGINE_POLICY_ENUM {
CMDQ_TESTCASE_ENGINE_NOT_SET,
CMDQ_TESTCASE_ENGINE_SAME,
CMDQ_TESTCASE_ENGINE_RANDOM,
};
enum WAIT_POLICY_ENUM {
CMDQ_TESTCASE_WAITOP_NOT_SET,
CMDQ_TESTCASE_WAITOP_ALWAYS,
CMDQ_TESTCASE_WAITOP_RANDOM,
CMDQ_TESTCASE_WAITOP_BEFORE_END,
};
enum BRANCH_POLICY_ENUM {
CMDQ_TESTCASE_BRANCH_NONE = 0,
CMDQ_TESTCASE_BRANCH_CONTINUE,
CMDQ_TESTCASE_BRANCH_BREAK,
CMDQ_TESTCASE_BRANCH_MAX,
};
enum ROUND_LOOP_TIME_POLICY_ENUM {
CMDQ_TESTCASE_LOOP_FAST = 4,
CMDQ_TESTCASE_LOOP_MEDIUM = 16,
CMDQ_TESTCASE_LOOP_SLOW = 60,
};
enum POLL_POLICY_ENUM {
CMDQ_TESTCASE_POLL_NONE,
CMDQ_TESTCASE_POLL_PASS,
CMDQ_TESTCASE_POLL_ALL,
};
enum TRIGGER_THREAD_POLICY_ENUM {
CMDQ_TESTCASE_TRIGGER_RANDOM = 0,
CMDQ_TESTCASE_TRIGGER_FAST = 4,
CMDQ_TESTCASE_TRIGGER_MEDIUM = 16,
CMDQ_TESTCASE_TRIGGER_SLOW = 80,
};
enum SECURE_POLICY_ENUM {
CMDQ_TESTCASE_NO_SECURE,
CMDQ_TESTCASE_SECURE_RANDOM,
};
struct stress_policy {
enum ENGINE_POLICY_ENUM engines_policy;
enum WAIT_POLICY_ENUM wait_policy;
enum ROUND_LOOP_TIME_POLICY_ENUM loop_policy;
enum POLL_POLICY_ENUM poll_policy;
enum TRIGGER_THREAD_POLICY_ENUM trigger_policy;
enum SECURE_POLICY_ENUM secure_policy;
};
struct thread_param {
struct completion cmplt;
atomic_t stop;
u32 run_count;
bool multi_task;
struct stress_policy policy;
};
struct random_data {
struct work_struct release_work;
struct thread_param *thread;
struct cmdqRecStruct *handle;
struct TaskStruct *task;
atomic_t *ref_count;
cmdqBackupSlotHandle slot;
u32 round;
u32 *slot_expect_values;
u32 slot_reserve_count;
u32 slot_count;
u32 last_write;
u32 mask;
u32 inst_count;
u32 wait_count;
unsigned long dummy_reg_pa;
unsigned long dummy_reg_va;
u32 expect_result;
bool may_wait;
u32 poll_count;
};
/* trigger thread only set these bits */
#define CMDQ_TEST_POLL_BIT 0xFFFFFFF
/* secure task command buffer is limited */
#define CMDQ_MAX_SECURE_INST_COUNT (0x7F00 / CMDQ_INST_SIZE)
bool _is_boundary_offset(u32 offset)
{
u32 offset_idx = offset / CMDQ_INST_SIZE;
u32 buffer_inst_count = CMDQ_CMD_BUFFER_SIZE / CMDQ_INST_SIZE;
u32 offset_idx_mod = ((offset_idx +
(offset_idx / (buffer_inst_count - 1))) % buffer_inst_count);
return (offset_idx_mod == 0 || offset_idx_mod == 1);
}
static bool _append_op_read_mem_to_reg(struct cmdqRecStruct *handle,
struct random_data *data, u32 limit_size)
{
u32 slot_idx = 0;
slot_idx = (get_random_int() % data->slot_count) +
data->slot_reserve_count;
cmdq_op_read_mem_to_reg(handle, data->slot, slot_idx,
data->dummy_reg_pa);
data->last_write = data->slot_expect_values[slot_idx];
return true;
}
static bool _append_op_read_reg_to_mem(struct cmdqRecStruct *handle,
struct random_data *data, u32 limit_size)
{
u32 slot_idx = 0;
if (data->thread->multi_task)
return true;
slot_idx = (get_random_int() % data->slot_count) +
data->slot_reserve_count;
cmdq_op_read_reg_to_mem(handle, data->slot,
slot_idx, data->dummy_reg_pa);
data->slot_expect_values[slot_idx] = data->last_write;
return true;
}
static bool _append_op_write_reg(struct cmdqRecStruct *handle,
struct random_data *data,
u32 limit_size)
{
u32 random_value = get_random_int();
bool use_mask = get_random_int() % 10;
if (use_mask) {
data->mask = get_random_int();
random_value = (data->last_write & ~data->mask) |
(random_value & data->mask);
} else {
data->mask = ~0;
}
cmdq_op_write_reg(handle, data->dummy_reg_pa,
data->last_write, data->mask);
data->last_write = random_value;
return true;
}
static bool _append_op_wait(struct cmdqRecStruct *handle,
struct random_data *data,
u32 limit_size)
{
const u32 max_wait_count = 2;
const u32 max_wait_bound_count = 5;
const unsigned long tokens[] = {
CMDQ_SYNC_TOKEN_USER_0,
CMDQ_SYNC_TOKEN_USER_1
};
unsigned long token;
if (!data->may_wait || data->wait_count > max_wait_bound_count)
return true;
/* we save few chance to insert wait in boundary case */
if (data->wait_count > max_wait_count &&
handle->blockSize >= CMDQ_CMD_BUFFER_SIZE &&
!_is_boundary_offset(handle->blockSize))
return true;
token = tokens[get_random_int() % 2];
data->wait_count++;
if (get_random_int() % 8)
cmdq_op_wait_no_clear(handle, token);
else
cmdq_op_wait(handle, token);
return true;
}
static bool _append_op_poll(struct cmdqRecStruct *handle,
struct random_data *data,
u32 limit_size)
{
const u64 dummy_poll_pa = CMDQ_GPR_R32_PA(CMDQ_GET_GPR_PX2RX_LOW(
CMDQ_DATA_REG_2D_SHARPNESS_0_DST));
const u32 max_poll_count = 2;
const u32 min_poll_instruction = 18;
u32 poll_bit = 0;
u32 size_before = handle->blockSize;
if (data->thread->policy.poll_policy == CMDQ_TESTCASE_POLL_NONE ||
limit_size < CMDQ_INST_SIZE * min_poll_instruction ||
data->poll_count >= max_poll_count)
return true;
CMDQ_MSG("%s limit: %u block size: %u\n",
__func__, limit_size, handle->blockSize);
data->poll_count++;
if (data->thread->policy.poll_policy == CMDQ_TESTCASE_POLL_PASS)
poll_bit = 1 << (get_random_int() % 28);
else
poll_bit = 1 << (get_random_int() % 32);
cmdq_op_write_reg(handle, dummy_poll_pa, 0, poll_bit);
size_before = handle->blockSize;
cmdq_op_poll(handle, dummy_poll_pa, poll_bit, poll_bit);
CMDQ_LOG("%s round:%u poll:0x%08x count:%u block size:%u op size:%u\n",
__func__, data->round, poll_bit,
data->poll_count, handle->blockSize,
handle->blockSize - size_before);
return true;
}
static bool _append_random_instructions(struct cmdqRecStruct *handle,
struct random_data *random_context, u32 limit_size)
{
typedef bool(*append_op_func)(struct cmdqRecStruct *handle,
struct random_data *data,
u32 limit_size);
const append_op_func op_funcs[] = {
_append_op_read_mem_to_reg,
_append_op_read_reg_to_mem,
_append_op_write_reg,
_append_op_wait,
_append_op_poll,
};
while (handle->blockSize < limit_size) {
s32 op_idx = get_random_int() % ARRAY_SIZE(op_funcs);
if (!op_funcs[op_idx](handle, random_context,
limit_size - handle->blockSize))
return false;
}
return true;
}
bool _stress_is_ignore_timeout(struct stress_policy *policy)
{
bool ignore = false;
/* exclude some case that timeout is expected */
if (policy->wait_policy != CMDQ_TESTCASE_WAITOP_NOT_SET) {
/* insert wait op into testcase will trigger timeout */
ignore = true;
} else if (policy->engines_policy == CMDQ_TESTCASE_ENGINE_RANDOM) {
/* random engine flag may cause */
/* task never able to run, thus timedout */
ignore = true;
} else if (policy->poll_policy != CMDQ_TESTCASE_POLL_NONE) {
/* timeout due to poll fail */
ignore = true;
}
return ignore;
}
static void _dump_stress_task_result(s32 status,
struct random_data *random_context,
s32 *insts_buffer, u32 insts_buffer_size)
{
u32 result_val = 0, i = 0;
bool error_happen = false;
do {
if (status == -ETIMEDOUT) {
error_happen = !_stress_is_ignore_timeout(
&random_context->thread->policy);
if (!error_happen) {
CMDQ_LOG("Task timeout:%p round:%u skip\n",
random_context->task,
random_context->round);
}
break;
} else if (status < 0) {
error_happen = true;
break;
}
/* register may write by other task, */
/* thus only check in multi-task case */
if (!random_context->thread->multi_task) {
result_val = CMDQ_REG_GET32(
random_context->dummy_reg_va);
if (result_val != random_context->last_write) {
CMDQ_TEST_FAIL("Reg value mismatch\n");
CMDQ_TEST_FAIL("0x%08x to 0x%08x round: %u\n",
result_val,
random_context->last_write,
random_context->round);
error_happen = true;
}
}
for (i = random_context->slot_reserve_count;
i < random_context->slot_reserve_count +
random_context->slot_count; i++) {
cmdq_cpu_read_mem(random_context->slot,
i, &result_val);
if (result_val !=
random_context->slot_expect_values[i]) {
CMDQ_TEST_FAIL("Slot %u value mismatch\n",
i);
CMDQ_TEST_FAIL("exp:0x%x reg:0x%x round:%u\n",
random_context->slot_expect_values[i],
result_val, random_context->round);
error_happen = true;
}
}
cmdq_cpu_read_mem(random_context->slot, 1, &result_val);
if (result_val != random_context->expect_result) {
CMDQ_TEST_FAIL("mismatch exp:0x%x res:0x%x round:%u\n",
random_context->expect_result,
result_val, random_context->round);
error_happen = true;
}
} while (0);
if (error_happen) {
char longMsg[CMDQ_LONGSTRING_MAX];
u32 msgOffset;
s32 msgMAXSize;
s32 poll_value = CMDQ_REG_GET32(CMDQ_GPR_R32(
CMDQ_GET_GPR_PX2RX_LOW(
CMDQ_DATA_REG_2D_SHARPNESS_0_DST)));
atomic_set(&random_context->thread->stop, 1);
cmdq_core_longstring_init(longMsg, &msgOffset, &msgMAXSize);
cmdqCoreLongString(false, longMsg, &msgOffset, &msgMAXSize,
"task: 0x%p round: %u size: %u wait: %d:%d multi: %d engine: %d ",
random_context->task,
random_context->round,
insts_buffer_size ?
insts_buffer_size :
random_context->handle->blockSize,
random_context->may_wait,
random_context->wait_count,
random_context->thread->multi_task,
random_context->thread->policy.engines_policy);
cmdqCoreLongString(false, longMsg, &msgOffset, &msgMAXSize,
"status: %d poll: %d, reg: 0x%08x count: %u\n",
status,
random_context->thread->policy.poll_policy,
poll_value,
random_context->poll_count);
CMDQ_TEST_FAIL("%s", longMsg);
/* wait other threads stop print messages */
msleep_interruptible(10);
if (insts_buffer && insts_buffer_size)
cmdqCoreDumpCommandMem(insts_buffer, insts_buffer_size);
else
cmdq_task_dump_command(random_context->handle);
}
}
static void _testcase_stress_release_work(struct work_struct *work_item)
{
struct random_data *random_context = (struct random_data *)container_of(
work_item, struct random_data, release_work);
s32 *insts_buffer = NULL;
u32 insts_buffer_size = 0;
s32 status = 0;
do {
if (!random_context->task) {
CMDQ_TEST_FAIL("Task does not submit, round: %u\n",
random_context->round);
break;
}
_test_backup_instructions(random_context->task, &insts_buffer);
insts_buffer_size = random_context->task->bufferSize;
status = cmdqCoreWaitAndReleaseTask(random_context->task, 500);
_dump_stress_task_result(status, random_context,
insts_buffer, insts_buffer_size);
} while (0);
_test_free_backup_instructions(&insts_buffer);
cmdq_task_destroy(random_context->handle);
cmdq_free_mem(random_context->slot);
atomic_dec(random_context->ref_count);
kfree(random_context->slot_expect_values);
kfree(random_context);
}
void _testcase_stress_submit_release_work(struct work_struct *work_item)
{
struct random_data *random_context = (struct random_data *)container_of(
work_item, struct random_data, release_work);
s32 status = 0;
do {
status = _test_submit_sync(random_context->handle,
_stress_is_ignore_timeout(
&random_context->thread->policy));
_dump_stress_task_result(status, random_context, NULL, 0);
} while (0);
cmdq_task_destroy(random_context->handle);
cmdq_free_mem(random_context->slot);
atomic_dec(random_context->ref_count);
kfree(random_context->slot_expect_values);
kfree(random_context);
}
void _testcase_on_exec_suspend(struct TaskStruct *task, s32 thread)
{
const unsigned long tokens[] = {
CMDQ_SYNC_TOKEN_USER_0,
CMDQ_SYNC_TOKEN_USER_1
};
cmdqCoreSetEvent(tokens[get_random_int() % ARRAY_SIZE(tokens)]);
}
static int _testcase_gen_task_thread(void *data)
{
#define MAX_RELEASE_QUEUE 4
const unsigned long dummy_reg_va = CMDQ_TEST_GCE_DUMMY_VA;
const unsigned long dummy_reg_pa = CMDQ_TEST_GCE_DUMMY_PA;
const u32 inst_count_pattern[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
126, 127, 128, 129, 130,
254, 255, 256, 257, 258,
510, 511, 512, 513, 514,
1022, 1023, 1024, 1025, 1026};
const u32 reserve_slot_count = 2;
const u32 max_slot_count = 4;
const u32 total_slot = reserve_slot_count + max_slot_count;
const u32 max_muti_task = CMDQ_MAX_TASK_IN_THREAD + 1;
const u32 max_buffer_count = 4;
struct thread_param *thread_data = (struct thread_param *)data;
struct workqueue_struct *release_queues[MAX_RELEASE_QUEUE] = {0};
const bool ignore_timeout = _stress_is_ignore_timeout(
&thread_data->policy);
u32 engines[] = {CMDQ_ENG_MDP_CAMIN, CMDQ_ENG_MDP_RDMA0,
CMDQ_ENG_MDP_RDMA1,
CMDQ_ENG_MDP_WROT0, CMDQ_ENG_MDP_WROT1};
u32 task_count = 0;
atomic_t task_ref_count;
u32 wait_count = 0;
u32 engine_sel = 0;
s32 status = 0;
u32 i = 0;
struct StressContextStruct *stress_context =
cmdq_core_get_stress_context();
CMDQ_MSG("%s\n", __func__);
for (i = 0; i < MAX_RELEASE_QUEUE; i++)
release_queues[i] =
create_singlethread_workqueue("cmdq_random_release");
CMDQ_REG_SET32(dummy_reg_va, 0xdeaddead);
if (CMDQ_REG_GET32(dummy_reg_va) != 0xdeaddead)
CMDQ_ERR("%s verify pattern register fail: 0x%08x\n",
__func__, (u32)CMDQ_REG_GET32(dummy_reg_va));
if (thread_data->policy.engines_policy == CMDQ_TESTCASE_ENGINE_SAME)
engine_sel = get_random_int() %
((1 << ARRAY_SIZE(engines)) - 1);
else
engine_sel = 0;
if (thread_data->policy.wait_policy == CMDQ_TESTCASE_WAITOP_BEFORE_END)
stress_context->exec_suspend = _testcase_on_exec_suspend;
else
cmdq_core_clean_stress_context();
atomic_set(&task_ref_count, 0);
for (task_count = 0; !atomic_read(&thread_data->stop) &&
task_count < thread_data->run_count; task_count++) {
struct random_data *random_context = NULL;
struct cmdqRecStruct *handle = NULL;
u32 i = 0;
if (!thread_data->multi_task) {
if (atomic_read(&task_ref_count) > 0) {
msleep_interruptible(8);
task_count--;
continue;
}
} else {
if (atomic_read(&task_ref_count) >= max_muti_task) {
msleep_interruptible(8);
task_count--;
continue;
}
}
random_context = kzalloc(sizeof(*random_context), GFP_KERNEL);
random_context->thread = thread_data;
random_context->round = task_count;
random_context->dummy_reg_pa = dummy_reg_pa;
random_context->dummy_reg_va = dummy_reg_va;
random_context->ref_count = &task_ref_count;
random_context->slot_reserve_count = reserve_slot_count;
random_context->slot_count = max_slot_count;
random_context->slot_expect_values = kcalloc(total_slot,
sizeof(*random_context->slot_expect_values),
GFP_KERNEL);
cmdq_alloc_mem(&random_context->slot, total_slot);
for (i = 0; i < reserve_slot_count; i++) {
/*
* slot 0: Final dummy register value read back.
* slot 1: Logic add counter
*/
cmdq_cpu_write_mem(random_context->slot, i, 0);
random_context->slot_expect_values[i] = 0;
}
for (i = reserve_slot_count; i < total_slot; i++) {
cmdq_cpu_write_mem(random_context->slot, i, i);
random_context->slot_expect_values[i] = i;
}
cmdq_task_create(CMDQ_SCENARIO_DEBUG, &handle);
cmdq_task_reset(handle);
random_context->handle = handle;
switch (thread_data->policy.wait_policy) {
case CMDQ_TESTCASE_WAITOP_NOT_SET:
case CMDQ_TESTCASE_WAITOP_BEFORE_END:
random_context->may_wait = false;
break;
case CMDQ_TESTCASE_WAITOP_ALWAYS:
random_context->may_wait = true;
break;
case CMDQ_TESTCASE_WAITOP_RANDOM:
/* give 1/10 chance the task has wait instructions */
random_context->may_wait = get_random_int() % 10;
break;
default:
random_context->may_wait = get_random_int() % 10;
break;
}
for (i = 0; i < (get_random_int() % max_buffer_count) + 1; i++)
random_context->inst_count +=
inst_count_pattern[get_random_int() %
ARRAY_SIZE(inst_count_pattern)];
#ifdef CMDQ_SECURE_PATH_SUPPORT
/* decide if this task can be secure */
if (thread_data->policy.secure_policy ==
CMDQ_TESTCASE_SECURE_RANDOM &&
random_context->inst_count <
CMDQ_MAX_SECURE_INST_COUNT) {
cmdq_task_set_secure(handle,
(get_random_int() % 20) == 0);
random_context->dummy_reg_pa = CMDQ_TEST_MMSYS_DUMMY_PA;
random_context->dummy_reg_va = CMDQ_TEST_MMSYS_DUMMY_VA;
}
#endif
/* set engine flag and priority */
handle->priority = get_random_int() % 16;
if (thread_data->policy.engines_policy ==
CMDQ_TESTCASE_ENGINE_RANDOM) {
engine_sel = get_random_int() %
((1 << ARRAY_SIZE(engines)) - 1);
for (i = 0; i < ARRAY_SIZE(engines); i++) {
if (((1 << i) & engine_sel) != 0)
handle->engineFlag =
handle->engineFlag |
(1 << engines[i]);
}
} else {
handle->engineFlag = engine_sel;
}
if (!thread_data->multi_task) {
/* clear the reg first */
cmdq_op_write_reg(handle, dummy_reg_pa, 0, ~0);
}
/* append random instructions */
if (random_context->inst_count > 4) {
if (!_append_random_instructions(handle,
random_context,
(random_context->inst_count - 4) *
CMDQ_INST_SIZE)) {
CMDQ_ERR("%s err during append random instr\n",
__func__);
atomic_set(&thread_data->stop, 1);
cmdq_free_mem(random_context->slot);
kfree(random_context->slot_expect_values);
kfree(random_context);
break;
}
}
if (!thread_data->multi_task) {
cmdqRecBackupRegisterToSlot(handle,
random_context->slot, 0, dummy_reg_pa);
random_context->slot_expect_values[0] =
random_context->last_write;
}
if (thread_data->policy.wait_policy ==
CMDQ_TESTCASE_WAITOP_BEFORE_END) {
/* make sure task wait before eoc */
cmdq_op_clear_event(handle, CMDQ_SYNC_TOKEN_USER_0);
cmdq_op_wait(handle, CMDQ_SYNC_TOKEN_USER_0);
/* do not queue too much tasks in thread */
if ((u32)atomic_read(&task_ref_count) >= 2)
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
}
if (get_random_int() % 2) {
status = cmdq_op_finalize_command(handle, false);
if (status < 0) {
CMDQ_ERR("Fail to finalize round:%u st:%d\n",
task_count, status);
cmdq_free_mem(random_context->slot);
kfree(random_context->slot_expect_values);
kfree(random_context);
break;
}
/* async submit case, with contains */
/* more info during release */
status = _test_submit_async_internal(handle,
&random_context->task, true, ignore_timeout);
if (status < 0) {
CMDQ_ERR("Fail to submit round:%u status:%d\n",
task_count, status);
cmdq_free_mem(random_context->slot);
kfree(random_context->slot_expect_values);
kfree(random_context);
break;
}
INIT_WORK(&random_context->release_work,
_testcase_stress_release_work);
atomic_inc(&task_ref_count);
CMDQ_LOG("Round: %u task: %p thread: %d\n",
task_count, random_context->task,
random_context->task->thread);
CMDQ_LOG("size: %u ref: %u start async\n",
random_context->task->bufferSize,
(u32)atomic_read(&task_ref_count));
} else {
/* sync flush case, will blocking worker */
INIT_WORK(&random_context->release_work,
_testcase_stress_submit_release_work);
atomic_inc(&task_ref_count);
CMDQ_LOG("Round: %u size: %u ref: %u start sync\n",
task_count, handle->blockSize,
(u32)atomic_read(&task_ref_count));
}
queue_work(release_queues[get_random_int() % MAX_RELEASE_QUEUE],
&random_context->release_work);
msleep_interruptible(get_random_int() %
(u32)thread_data->policy.loop_policy + 1);
}
while (atomic_read(&task_ref_count) > 0) {
/* set events to speed up task finish */
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_0);
cmdqCoreSetEvent(CMDQ_SYNC_TOKEN_USER_1);
msleep_interruptible(500);
CMDQ_ERR("%s wait for all task done: %u\n",
__func__, wait_count++);
}
CMDQ_LOG("%s END\n", __func__);
cmdq_core_clean_stress_context();
for (i = 0; i < MAX_RELEASE_QUEUE; i++)
destroy_workqueue(release_queues[i]);
cmdq_core_reset_first_dump();
complete(&thread_data->cmplt);
return 0;
}
static int _testcase_trigger_event_thread(void *data)
{
struct thread_param *thread_data = (struct thread_param *)data;
u8 event_idx = 0;
const unsigned long tokens[] = {
CMDQ_SYNC_TOKEN_USER_0,
CMDQ_SYNC_TOKEN_USER_1
};
const unsigned long dummy_poll_va = CMDQ_GPR_R32(CMDQ_GET_GPR_PX2RX_LOW(
CMDQ_DATA_REG_2D_SHARPNESS_0_DST));
u32 poll_bit_counter = 0xf;
u32 dummy_value = 0;
u32 trigger_interval = (u32)thread_data->policy.trigger_policy;
CMDQ_LOG("%s\n", __func__);
if (!trigger_interval)
trigger_interval = get_random_int() %
(u32)CMDQ_TESTCASE_TRIGGER_SLOW;
if (trigger_interval <= 1)
trigger_interval = 2;
/* randomly clear/set event */
while (!atomic_read(&thread_data->stop)) {
event_idx = get_random_int() % ARRAY_SIZE(tokens);
if (get_random_int() % 2)
cmdqCoreSetEvent(tokens[event_idx]);
else
cmdqCoreClearEvent(tokens[event_idx]);
dummy_value = CMDQ_REG_GET32(dummy_poll_va);
CMDQ_REG_SET32(dummy_poll_va, dummy_value | poll_bit_counter);
poll_bit_counter = poll_bit_counter << 4;
if (poll_bit_counter > CMDQ_TEST_POLL_BIT)
poll_bit_counter = 0xf;
msleep_interruptible(get_random_int() % trigger_interval + 1);
}
CMDQ_LOG("%s END\n", __func__);
complete(&thread_data->cmplt);
return 0;
}
static void testcase_gen_random_case(bool multi_task,
struct stress_policy policy)
{
struct task_struct *random_thread_handle;
struct task_struct *trigger_thread_handle;
struct thread_param random_thread = { {0} };
struct thread_param trigger_thread = { {0} };
const u32 finish_timeout_ms = 1000;
u32 timeout_counter = 0;
s32 wait_status = 0;
CMDQ_LOG("%s start with multi-task: %s engine: %d\n",
__func__, multi_task ? "True" : "False",
policy.engines_policy);
CMDQ_LOG("wait: %d loop: %d timeout: %s\n",
policy.wait_policy, policy.loop_policy,
_stress_is_ignore_timeout(&policy) ? "ignore" : "aee");
random_thread.multi_task = multi_task;
random_thread.policy = policy;
do {
init_completion(&random_thread.cmplt);
atomic_set(&random_thread.stop, 0);
init_completion(&trigger_thread.cmplt);
atomic_set(&trigger_thread.stop, 0);
random_thread.run_count = 3000;
random_thread_handle = kthread_run(_testcase_gen_task_thread,
(void *)&random_thread, "cmdq_gen");
if (IS_ERR(random_thread_handle)) {
CMDQ_TEST_FAIL("Fail to start gen task thread\n");
break;
}
trigger_thread_handle = kthread_run(
_testcase_trigger_event_thread,
(void *)&trigger_thread, "mdq_trigger");
if (IS_ERR(trigger_thread_handle)) {
CMDQ_TEST_FAIL("Fail to start trigger event thread\n");
atomic_set(&random_thread.stop, 1);
wait_for_completion(&random_thread.cmplt);
break;
}
wait_for_completion(&random_thread.cmplt);
atomic_set(&trigger_thread.stop, 1);
do {
wait_status = wait_for_completion_interruptible_timeout(
&trigger_thread.cmplt,
msecs_to_jiffies(finish_timeout_ms));
CMDQ_LOG("wait trigger thr done count:%u status:%d\n",
timeout_counter, wait_status);
msleep_interruptible(finish_timeout_ms);
timeout_counter++;
} while (wait_status <= 0);
} while (0);
CMDQ_LOG("%s END\n", __func__);
}
void testcase_stress_basic(void)
{
struct stress_policy policy = {0};
#ifdef CMDQ_SECURE_PATH_SUPPORT
if (gCmdqTestSecure)
policy.secure_policy = CMDQ_TESTCASE_SECURE_RANDOM;
#endif
policy.engines_policy = CMDQ_TESTCASE_ENGINE_NOT_SET;
policy.wait_policy = CMDQ_TESTCASE_WAITOP_NOT_SET;
policy.loop_policy = CMDQ_TESTCASE_LOOP_FAST;
policy.trigger_policy = CMDQ_TESTCASE_TRIGGER_SLOW;
testcase_gen_random_case(true, policy);
msleep_interruptible(10);
policy.engines_policy = CMDQ_TESTCASE_ENGINE_SAME;
policy.wait_policy = CMDQ_TESTCASE_WAITOP_BEFORE_END;
policy.trigger_policy = CMDQ_TESTCASE_TRIGGER_MEDIUM;
testcase_gen_random_case(true, policy);
msleep_interruptible(10);
policy.wait_policy = CMDQ_TESTCASE_WAITOP_RANDOM;
testcase_gen_random_case(true, policy);
msleep_interruptible(10);
policy.engines_policy = CMDQ_TESTCASE_ENGINE_RANDOM;
policy.wait_policy = CMDQ_TESTCASE_WAITOP_RANDOM;
testcase_gen_random_case(true, policy);
}
void testcase_stress_poll(void)
{
struct stress_policy policy = {0};
policy.engines_policy = CMDQ_TESTCASE_ENGINE_NOT_SET;
policy.wait_policy = CMDQ_TESTCASE_WAITOP_NOT_SET;
policy.loop_policy = CMDQ_TESTCASE_LOOP_MEDIUM;
policy.poll_policy = CMDQ_TESTCASE_POLL_PASS;
testcase_gen_random_case(true, policy);
msleep_interruptible(10);
policy.poll_policy = CMDQ_TESTCASE_POLL_ALL;
testcase_gen_random_case(true, policy);
}
void testcase_stress_timeout(void)
{
struct stress_policy policy = {0};
#ifdef CMDQ_SECURE_PATH_SUPPORT
if (gCmdqTestSecure)
policy.secure_policy = CMDQ_TESTCASE_SECURE_RANDOM;
#endif
policy.engines_policy = CMDQ_TESTCASE_ENGINE_SAME;
policy.wait_policy = CMDQ_TESTCASE_WAITOP_RANDOM;
policy.loop_policy = CMDQ_TESTCASE_LOOP_MEDIUM;
testcase_gen_random_case(true, policy);
msleep_interruptible(10);
policy.engines_policy = CMDQ_TESTCASE_ENGINE_SAME;
testcase_gen_random_case(true, policy);
}
enum CMDQ_TESTCASE_ENUM {
CMDQ_TESTCASE_DEFAULT = 0,
CMDQ_TESTCASE_BASIC = 1,
CMDQ_TESTCASE_ERROR = 2,
CMDQ_TESTCASE_FPGA = 3,
/* user request get some registers' value when task execution */
CMDQ_TESTCASE_READ_REG_REQUEST,
CMDQ_TESTCASE_GPR,
CMDQ_TESTCASE_SW_TIMEOUT_HANDLE,
CMDQ_TESTCASE_END, /* always at the end */
};
static void testcase_general_handling(int32_t testID)
{
/* Turn on GCE clock to make sure GPR is always alive */
cmdq_dev_enable_gce_clock(true);
switch (testID) {
case 303:
testcase_stress_timeout();
break;
case 302:
testcase_stress_poll();
break;
case 300:
testcase_stress_basic();
break;
case 143:
testcase_end_addr_conflict();
break;
case 142:
testcase_timeout_secure_dapc();
testcase_secure_basic();
break;
case 141:
testcase_track_task_cb();
break;
case 140:
testcase_reorder();
testcase_reorder_last();
break;
case 139:
testcase_invalid_handle();
break;
case 131:
testcase_get_task_by_engine();
break;
case 130:
testcase_longloop();
break;
case 129:
testcase_boundary_mem();
break;
case 128:
testcase_boundary_mem_param();
break;
case 123:
testcase_monitor_mem_stop();
break;
case 122:
testcase_monitor_mem_start();
break;
case 121:
testcase_prefetch_from_DTS();
break;
case 120:
testcase_notify_and_delay_submit(16);
break;
case 119:
testcase_check_dts_correctness();
break;
case 118:
testcase_error_irq();
break;
case 117:
testcase_timeout_reorder_test();
break;
case 116:
testcase_timeout_wait_early_test();
break;
case 115:
testcase_manual_suspend_resume_test();
break;
case 114:
testcase_append_task_verify();
break;
default:
CMDQ_LOG("CONF Not Found:gCmdqTestSecure:%d,testType: %lld in %s\n",
gCmdqTestSecure, gCmdqTestConfig[0], __func__);
break;
}
/* Turn off GCE clock */
cmdq_dev_enable_gce_clock(false);
}
static void testcase_general_handling_ex1(int32_t testID)
{
/* Turn on GCE clock to make sure GPR is always alive */
cmdq_dev_enable_gce_clock(true);
switch (testID) {
case 113:
testcase_trigger_engine_dispatch_check();
break;
case 112:
testcase_complicated_engine_thread();
break;
case 111:
testcase_module_full_mdp_engine();
break;
case 110:
testcase_nonsuspend_irq();
break;
case 109:
testcase_estimate_command_exec_time();
break;
case 108:
testcase_profile_marker();
break;
case 107:
testcase_prefetch_multiple_command();
break;
case 106:
testcase_concurrency_for_normal_path_and_secure_path();
break;
case 105:
testcase_async_write_stress_test();
break;
case 104:
testcase_submit_after_error_happened();
break;
case 103:
testcase_secure_meta_data();
break;
case 102:
testcase_secure_disp_scenario();
break;
case 101:
testcase_write_stress_test();
break;
case 100:
testcase_secure_basic();
break;
case 99:
testcase_write();
testcase_write_with_mask();
break;
case 98:
testcase_errors();
break;
case 97:
testcase_scenario();
break;
case 96:
testcase_sync_token();
break;
case 95:
testcase_write_address();
break;
case 94:
testcase_async_request();
break;
case 93:
testcase_async_suspend_resume();
break;
case 92:
testcase_async_request_partial_engine();
break;
case 91:
testcase_prefetch_scenarios();
break;
case 90:
testcase_loop();
break;
case 89:
testcase_trigger_thread();
break;
case 88:
testcase_multiple_async_request();
break;
case 87:
testcase_get_result();
break;
case 86:
testcase_read_to_data_reg();
break;
case 85:
testcase_dram_access();
break;
case 84:
testcase_backup_register();
break;
case 83:
testcase_fire_and_forget();
break;
case 82:
testcase_sync_token_threaded();
break;
case 81:
testcase_long_command();
break;
case 80:
testcase_clkmgr();
break;
case 79:
testcase_perisys_apb();
break;
case 78:
testcase_backup_reg_to_slot();
break;
case 77:
testcase_thread_dispatch();
break;
case 75:
testcase_full_thread_array();
break;
case 74:
testcase_module_full_dump();
break;
case 73:
testcase_write_from_data_reg();
break;
case 72:
testcase_update_value_to_slot();
break;
case 71:
testcase_poll();
break;
case 70:
testcase_write_reg_from_slot();
break;
case CMDQ_TESTCASE_FPGA:
testcase_write();
testcase_write_with_mask();
testcase_poll();
testcase_scenario();
testcase_estimate_command_exec_time();
testcase_prefetch_multiple_command();
testcase_write_stress_test();
testcase_async_suspend_resume();
testcase_async_request_partial_engine();
testcase_prefetch_scenarios();
testcase_loop();
testcase_trigger_thread();
testcase_multiple_async_request();
testcase_get_result();
testcase_dram_access();
testcase_backup_register();
testcase_fire_and_forget();
testcase_long_command();
testcase_backup_reg_to_slot();
testcase_write_from_data_reg();
testcase_update_value_to_slot();
break;
case CMDQ_TESTCASE_ERROR:
testcase_errors();
testcase_async_request();
testcase_module_full_dump();
break;
case CMDQ_TESTCASE_BASIC:
testcase_write();
testcase_write_with_mask();
testcase_poll();
testcase_scenario();
break;
case CMDQ_TESTCASE_READ_REG_REQUEST:
testcase_get_result();
break;
case CMDQ_TESTCASE_GPR:
testcase_read_to_data_reg(); /* must verify! */
testcase_dram_access();
break;
case CMDQ_TESTCASE_DEFAULT:
testcase_multiple_async_request();
testcase_read_to_data_reg();
testcase_get_result();
testcase_scenario();
testcase_write();
testcase_poll();
testcase_write_address();
testcase_async_suspend_resume();
testcase_async_request_partial_engine();
testcase_prefetch_scenarios();
testcase_loop();
testcase_trigger_thread();
testcase_prefetch();
testcase_long_command();
testcase_dram_access();
testcase_backup_register();
testcase_fire_and_forget();
testcase_backup_reg_to_slot();
testcase_thread_dispatch();
testcase_full_thread_array();
break;
default:
CMDQ_LOG("CONF Not Found:gCmdqTestSecure:%d,testType: %lld in %s\n",
gCmdqTestSecure, gCmdqTestConfig[0], __func__);
break;
}
/* Turn off GCE clock */
cmdq_dev_enable_gce_clock(false);
}
ssize_t cmdq_test_proc(struct file *fp, char __user *u,
size_t s, loff_t *l)
{
int64_t testParameter[CMDQ_TESTCASE_PARAMETER_MAX];
mutex_lock(&gCmdqTestProcLock);
/* make sure the following section is protected */
smp_mb();
CMDQ_LOG("[TESTCASE]CONFIG: gCmdqTestSecure: %d, testType: %lld\n",
gCmdqTestSecure, gCmdqTestConfig[0]);
CMDQ_LOG("[TESTCASE]CONFIG PARAMETER:[1]:%lld,[2]:%lld,[3]:%lld\n",
gCmdqTestConfig[1], gCmdqTestConfig[2], gCmdqTestConfig[3]);
memcpy(testParameter, gCmdqTestConfig, sizeof(testParameter));
gCmdqTestConfig[0] = 0LL;
gCmdqTestConfig[1] = -1LL;
mutex_unlock(&gCmdqTestProcLock);
/* trigger test case here */
CMDQ_MSG("//\n//\n//\ncmdq_test_proc\n");
cmdq_get_func()->testSetup();
switch (testParameter[0]) {
case CMDQ_TEST_TYPE_NORMAL:
case CMDQ_TEST_TYPE_SECURE:
testcase_general_handling((int32_t)testParameter[1]);
testcase_general_handling_ex1((int32_t)testParameter[1]);
break;
case CMDQ_TEST_TYPE_MONITOR_EVENT:
/* (wait type, event ID or back register) */
testcase_monitor_trigger((uint32_t)testParameter[1],
(uint64_t)testParameter[2]);
break;
case CMDQ_TEST_TYPE_MONITOR_POLL:
/* (poll register, poll value, poll mask) */
testcase_poll_monitor_trigger((uint64_t)testParameter[1],
(uint64_t)testParameter[2],
(uint64_t)testParameter[3]);
break;
case CMDQ_TEST_TYPE_OPEN_COMMAND_DUMP:
/* (scenario, buffersize) */
testcase_open_buffer_dump((int32_t)testParameter[1],
(int32_t)testParameter[2]);
break;
case CMDQ_TEST_TYPE_DUMP_DTS:
cmdq_core_dump_dts_setting();
break;
case CMDQ_TEST_TYPE_FEATURE_CONFIG:
if ((int32_t)testParameter[1] < 0)
cmdq_core_dump_feature();
else
cmdq_core_set_feature((int32_t)testParameter[1],
(uint32_t)testParameter[2]);
break;
case CMDQ_TEST_TYPE_MMSYS_PERFORMANCE:
testcase_mmsys_performance((int32_t)testParameter[1]);
break;
default:
break;
}
cmdq_get_func()->testCleanup();
CMDQ_MSG("%s ended\n", __func__);
return 0;
}
static ssize_t cmdq_write_test_proc_config(struct file *file,
const char __user *userBuf,
size_t count, loff_t *data)
{
bool trick_test = false;
char desc[50];
long long testConfig[CMDQ_TESTCASE_PARAMETER_MAX];
int32_t len = 0;
do {
/* copy user input */
len = (count < (sizeof(desc) - 1)) ?
count : (sizeof(desc) - 1);
if (copy_from_user(desc, userBuf, len)) {
CMDQ_MSG("TEST_CONFIG: data fail, length:%d\n", len);
break;
}
desc[len] = '\0';
/* Set initial test config value */
memset(testConfig, -1, sizeof(testConfig));
/* process and update config */
if (sscanf(desc, "%lld %lld %lld %lld",
&testConfig[0], &testConfig[1],
&testConfig[2], &testConfig[3]) <= 0) {
/* sscanf returns the number of items */
/* in argument list successfully filled. */
CMDQ_MSG("TEST_CONFIG: sscanf failed, len:%d\n", len);
break;
}
CMDQ_MSG("TEST_CONFIG: %lld, %lld, %lld, %lld\n",
testConfig[0], testConfig[1],
testConfig[2], testConfig[3]);
if ((testConfig[0] < 0) ||
(testConfig[0] >= CMDQ_TEST_TYPE_MAX)) {
CMDQ_MSG("TEST_CONFIG: Type:%lld, newTestSuit:%lld\n",
testConfig[0], testConfig[1]);
break;
}
if ((testConfig[0] < 2) && (testConfig[1] < 0))
trick_test = true;
mutex_lock(&gCmdqTestProcLock);
/* set memory barrier for lock */
smp_mb();
memcpy(&gCmdqTestConfig, &testConfig, sizeof(testConfig));
if (testConfig[0] == CMDQ_TEST_TYPE_NORMAL)
gCmdqTestSecure = false;
else
gCmdqTestSecure = true;
mutex_unlock(&gCmdqTestProcLock);
} while (0);
if (trick_test) {
char node_name[25];
char clk_name[20];
int clk_enable = 0;
struct clk *clk_module;
/* trick to control clock by test node for testing */
if (sscanf(desc, "%d %24s %19s",
&clk_enable, node_name, clk_name) <= 0) {
/* sscanf returns the number of */
/* items in argument list successfully filled. */
CMDQ_LOG("CLOCK_TEST_CONFIG: sscanf failed: %s\n",
desc);
} else {
cmdq_dev_get_module_clock_by_name(node_name,
clk_name, &clk_module);
cmdq_dev_enable_device_clock(clk_enable,
clk_module, clk_name);
}
}
return count;
}
void cmdq_test_init_setting(void)
{
memset(&(gEventMonitor), 0x0, sizeof(gEventMonitor));
memset(&(gPollMonitor), 0x0, sizeof(gPollMonitor));
}
static int cmdq_test_open(struct inode *pInode, struct file *pFile)
{
return 0;
}
static const struct file_operations cmdq_fops = {
.owner = THIS_MODULE,
.open = cmdq_test_open,
.read = cmdq_test_proc,
.write = cmdq_write_test_proc_config,
};
static int __init cmdq_test_init(void)
{
#ifdef _CMDQ_TEST_PROC_
CMDQ_MSG("%s\n", __func__);
/* Initial value */
gCmdqTestSecure = false;
gCmdqTestConfig[0] = 0LL;
gCmdqTestConfig[1] = -1LL;
/* Mout proc entry for debug */
gCmdqTestProcEntry = proc_mkdir("cmdq_test", NULL);
if (gCmdqTestProcEntry != NULL) {
if (proc_create("test", 0660,
gCmdqTestProcEntry, &cmdq_fops) == NULL) {
/* cmdq_test_init failed */
CMDQ_MSG("%s failed\n", __func__);
}
}
#endif
return 0;
}
static void __exit cmdq_test_exit(void)
{
#ifdef _CMDQ_TEST_PROC_
CMDQ_MSG("%s\n", __func__);
if (gCmdqTestProcEntry != NULL) {
proc_remove(gCmdqTestProcEntry);
gCmdqTestProcEntry = NULL;
}
#endif
}
module_init(cmdq_test_init);
module_exit(cmdq_test_exit);
MODULE_LICENSE("GPL");
#endif /* CMDQ_TEST */