371 lines
8.6 KiB
C
371 lines
8.6 KiB
C
|
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
|
/*
|
||
|
|
* Copyright (c) 2020 MediaTek Inc.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <linux/vmalloc.h>
|
||
|
|
#include <linux/slab.h>
|
||
|
|
#include <linux/module.h>
|
||
|
|
#include <linux/fs.h>
|
||
|
|
#include <linux/debugfs.h>
|
||
|
|
#include <linux/errno.h>
|
||
|
|
#include <linux/uaccess.h>
|
||
|
|
|
||
|
|
#include "mdw_cmn.h"
|
||
|
|
#include "mdw_tag.h"
|
||
|
|
#include "mdw_rsc.h"
|
||
|
|
#include "mdw_dbg.h"
|
||
|
|
#include "apusys_dbg.h"
|
||
|
|
#include "mdw_mem.h"
|
||
|
|
#include "mdw_trace.h"
|
||
|
|
#include "mdw_usr.h"
|
||
|
|
#include "mdw_sched.h"
|
||
|
|
|
||
|
|
#include "aee.h"
|
||
|
|
|
||
|
|
struct dentry *mdw_dbg_root;
|
||
|
|
struct dentry *mdw_dbg_user;
|
||
|
|
struct dentry *mdw_dbg_devinfo;
|
||
|
|
struct dentry *mdw_dbg_device;
|
||
|
|
struct dentry *mdw_dbg_trace;
|
||
|
|
struct dentry *mdw_dbg_test;
|
||
|
|
struct dentry *mdw_dbg_log;
|
||
|
|
|
||
|
|
u32 g_mdw_klog;
|
||
|
|
u32 g_dbg_prop[MDW_DBG_PROP_MAX];
|
||
|
|
|
||
|
|
u8 cfg_apusys_trace;
|
||
|
|
|
||
|
|
enum {
|
||
|
|
APUSYS_DBG_TEST_SUSPEND,
|
||
|
|
APUSYS_DBG_TEST_LOCKDEV,
|
||
|
|
APUSYS_DBG_TEST_UNLOCKDEV,
|
||
|
|
APUSYS_DBG_TEST_MULTITEST,
|
||
|
|
APUSYS_DBG_TEST_TCM_DEFAULT,
|
||
|
|
APUSYS_DBG_TEST_QUERY_MEM,
|
||
|
|
APUSYS_DBG_TEST_AEE,
|
||
|
|
APUSYS_DBG_CMD_TIMEOUT_AEE,
|
||
|
|
APUSYS_DBG_TEST_MAX,
|
||
|
|
};
|
||
|
|
|
||
|
|
int mdw_dbg_get_prop(int idx)
|
||
|
|
{
|
||
|
|
if (idx >= MDW_DBG_PROP_MAX)
|
||
|
|
return -EINVAL;
|
||
|
|
|
||
|
|
return g_dbg_prop[idx];
|
||
|
|
}
|
||
|
|
|
||
|
|
void mdw_dbg_aee(char *name)
|
||
|
|
{
|
||
|
|
#ifdef CONFIG_MTK_AEE_FEATURE
|
||
|
|
aee_kernel_warning("VPU", "\nCRDISPATCH_KEY:APUSYS_MIDDLEWARE\n",
|
||
|
|
name);
|
||
|
|
#else
|
||
|
|
mdw_drv_info("not support aee\n");
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
//----------------------------------------------
|
||
|
|
// user table dump
|
||
|
|
static int mdw_dbg_dump_usr(struct seq_file *s, void *unused)
|
||
|
|
{
|
||
|
|
mdw_usr_dump(s);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int mdw_dbg_open_usr(struct inode *inode, struct file *file)
|
||
|
|
{
|
||
|
|
return single_open(file, mdw_dbg_dump_usr, inode->i_private);
|
||
|
|
}
|
||
|
|
|
||
|
|
static const struct file_operations mdw_dbg_fops_user = {
|
||
|
|
.open = mdw_dbg_open_usr,
|
||
|
|
.read = seq_read,
|
||
|
|
.llseek = seq_lseek,
|
||
|
|
.release = single_release,
|
||
|
|
};
|
||
|
|
|
||
|
|
//----------------------------------------------
|
||
|
|
// device table dump
|
||
|
|
static int mdw_dbg_dump_devinfo(struct seq_file *s, void *unused)
|
||
|
|
{
|
||
|
|
mdw_rsc_dump(s);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int mdw_dbg_open_devinfo(struct inode *inode, struct file *file)
|
||
|
|
{
|
||
|
|
return single_open(file, mdw_dbg_dump_devinfo, inode->i_private);
|
||
|
|
}
|
||
|
|
|
||
|
|
static const struct file_operations mdw_dbg_fops_devinfo = {
|
||
|
|
.open = mdw_dbg_open_devinfo,
|
||
|
|
.read = seq_read,
|
||
|
|
.llseek = seq_lseek,
|
||
|
|
.release = single_release,
|
||
|
|
//.write = seq_write,
|
||
|
|
};
|
||
|
|
|
||
|
|
//----------------------------------------------
|
||
|
|
static int mdw_dbg_test_dump(struct seq_file *s, void *unused)
|
||
|
|
{
|
||
|
|
mdw_con_info(s, "-------------------------------------------------\n");
|
||
|
|
mdw_con_info(s, " multicore(%d):\n",
|
||
|
|
g_dbg_prop[MDW_DBG_PROP_MULTICORE]);
|
||
|
|
mdw_con_info(s, " 0: scheduler decide\n");
|
||
|
|
mdw_con_info(s, " 1: force single\n");
|
||
|
|
mdw_con_info(s, " 2: force multi\n");
|
||
|
|
mdw_con_info(s, " tcm_default(0x%x):\n",
|
||
|
|
g_dbg_prop[MDW_DBG_PROP_TCM_DEFAULT]);
|
||
|
|
mdw_con_info(s, " set default tcm size if user doesn't set\n");
|
||
|
|
mdw_con_info(s, " 1MB: 1048546\n");
|
||
|
|
mdw_con_info(s, " query_mem(%d):\n",
|
||
|
|
g_dbg_prop[MDW_DBG_PROP_QUERY_MEM]);
|
||
|
|
mdw_con_info(s, " 0: disable, can't query kva/iova from code\n");
|
||
|
|
mdw_con_info(s, " 1: enable, can query kva/iova from code\n");
|
||
|
|
mdw_con_info(s, " lockdev <device_type> <index>\n");
|
||
|
|
mdw_con_info(s, " device_type/index: check /d/apusys_midware/devinfo\n");
|
||
|
|
mdw_con_info(s, " unlockdev <device_type> <index>\n");
|
||
|
|
mdw_con_info(s, " device_type/index: check /d/apusys_midware/devinfo\n");
|
||
|
|
mdw_con_info(s, " aee_test:\n");
|
||
|
|
mdw_con_info(s, " 1: trigger aee to dump information\n");
|
||
|
|
mdw_con_info(s, " aee_cmd_timeout(%d):\n",
|
||
|
|
g_dbg_prop[MDW_DBG_PROP_CMD_TIMEOUT_AEE]);
|
||
|
|
mdw_con_info(s, " 0: disable\n");
|
||
|
|
mdw_con_info(s, " 1: enable, trigger aee when cmd timeout\n");
|
||
|
|
mdw_con_info(s, "-------------------------------------------------\n");
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int mdw_dbg_open_test(struct inode *inode, struct file *file)
|
||
|
|
{
|
||
|
|
return single_open(file, mdw_dbg_test_dump, inode->i_private);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void mdw_dbg_test_func(int test, int *arg, int count)
|
||
|
|
{
|
||
|
|
unsigned int vlm_start = 0, vlm_size = 0;
|
||
|
|
int type = 0, idx = 0;
|
||
|
|
struct mdw_dev_info *d = NULL;
|
||
|
|
|
||
|
|
switch (test) {
|
||
|
|
case APUSYS_DBG_TEST_SUSPEND:
|
||
|
|
if (count != 1) {
|
||
|
|
mdw_drv_warn("suspend test need 1 arg\n");
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (arg[0])
|
||
|
|
mdw_sched_pause();
|
||
|
|
else
|
||
|
|
mdw_sched_restart();
|
||
|
|
break;
|
||
|
|
|
||
|
|
case APUSYS_DBG_TEST_LOCKDEV:
|
||
|
|
if (count != 2) {
|
||
|
|
mdw_drv_warn("lock test need 2 arg\n");
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
type = arg[0];
|
||
|
|
idx = arg[1];
|
||
|
|
d = mdw_rsc_get_dinfo(type, idx);
|
||
|
|
if (!d)
|
||
|
|
return;
|
||
|
|
|
||
|
|
mdw_drv_warn("lock dev(%d-%d), ret(%d)\n",
|
||
|
|
type, idx, d->lock(d));
|
||
|
|
break;
|
||
|
|
|
||
|
|
case APUSYS_DBG_TEST_UNLOCKDEV:
|
||
|
|
if (count != 2) {
|
||
|
|
mdw_drv_warn("unlock test need 2 args\n");
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
type = arg[0];
|
||
|
|
idx = arg[1];
|
||
|
|
d = mdw_rsc_get_dinfo(type, idx);
|
||
|
|
if (!d)
|
||
|
|
return;
|
||
|
|
|
||
|
|
mdw_drv_warn("lock dev(%d-%d), ret(%d)\n",
|
||
|
|
type, idx, d->unlock(d));
|
||
|
|
break;
|
||
|
|
|
||
|
|
case APUSYS_DBG_TEST_MULTITEST:
|
||
|
|
if (count != 1) {
|
||
|
|
mdw_drv_warn("multi test need 1 arg\n");
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (arg[0] > 2) {
|
||
|
|
mdw_drv_warn("multicore not support(%d)\n", arg[0]);
|
||
|
|
} else {
|
||
|
|
g_dbg_prop[MDW_DBG_PROP_MULTICORE] = arg[0];
|
||
|
|
mdw_drv_debug("setup multi test %d\n", arg[0]);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case APUSYS_DBG_TEST_TCM_DEFAULT:
|
||
|
|
if (count != 1) {
|
||
|
|
mdw_drv_warn("default tcm test need 1 arg\n");
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
mdw_mem_get_vlm(&vlm_start, &vlm_size);
|
||
|
|
|
||
|
|
g_dbg_prop[MDW_DBG_PROP_TCM_DEFAULT] = vlm_size <
|
||
|
|
(unsigned int)arg[0] ? vlm_size : (unsigned int)arg[0];
|
||
|
|
|
||
|
|
mdw_drv_warn("tcm default(%u/%d)\n", vlm_size, arg[0]);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case APUSYS_DBG_TEST_QUERY_MEM:
|
||
|
|
if (count != 1) {
|
||
|
|
mdw_drv_warn("query mem test need 1 arg\n");
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
mdw_drv_warn("query mem(%d)\n", arg[0]);
|
||
|
|
g_dbg_prop[MDW_DBG_PROP_QUERY_MEM] = arg[0];
|
||
|
|
break;
|
||
|
|
|
||
|
|
case APUSYS_DBG_TEST_AEE:
|
||
|
|
mdw_dbg_aee("apusys midware test");
|
||
|
|
break;
|
||
|
|
|
||
|
|
case APUSYS_DBG_CMD_TIMEOUT_AEE:
|
||
|
|
if (count != 1) {
|
||
|
|
mdw_drv_warn("timeout aee enable need 1 arg\n");
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
mdw_drv_warn("timeout aee(%d)\n", arg[0]);
|
||
|
|
g_dbg_prop[MDW_DBG_PROP_CMD_TIMEOUT_AEE] = arg[0];
|
||
|
|
break;
|
||
|
|
|
||
|
|
|
||
|
|
default:
|
||
|
|
mdw_drv_warn("no test(%d/%d/%d)\n", test, arg[0], count);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static ssize_t mdw_dbg_write_test(struct file *flip,
|
||
|
|
const char __user *buffer,
|
||
|
|
size_t count, loff_t *f_pos)
|
||
|
|
{
|
||
|
|
char *tmp, *token, *cursor;
|
||
|
|
int ret, i, test;
|
||
|
|
const int max_arg = 2;
|
||
|
|
unsigned int args[max_arg];
|
||
|
|
|
||
|
|
tmp = kzalloc(count + 1, GFP_KERNEL);
|
||
|
|
if (!tmp)
|
||
|
|
return -ENOMEM;
|
||
|
|
|
||
|
|
ret = copy_from_user(tmp, buffer, count);
|
||
|
|
if (ret) {
|
||
|
|
mdw_drv_err("copy_from_user failed, ret=%d\n", ret);
|
||
|
|
goto out;
|
||
|
|
}
|
||
|
|
|
||
|
|
tmp[count] = '\0';
|
||
|
|
cursor = tmp;
|
||
|
|
|
||
|
|
/* parse a command */
|
||
|
|
token = strsep(&cursor, " ");
|
||
|
|
if (strcmp(token, "suspend") == 0)
|
||
|
|
test = APUSYS_DBG_TEST_SUSPEND;
|
||
|
|
else if (strcmp(token, "lockdev") == 0)
|
||
|
|
test = APUSYS_DBG_TEST_LOCKDEV;
|
||
|
|
else if (strcmp(token, "unlockdev") == 0)
|
||
|
|
test = APUSYS_DBG_TEST_UNLOCKDEV;
|
||
|
|
else if (strcmp(token, "multicore") == 0)
|
||
|
|
test = APUSYS_DBG_TEST_MULTITEST;
|
||
|
|
else if (strcmp(token, "tcm_default") == 0)
|
||
|
|
test = APUSYS_DBG_TEST_TCM_DEFAULT;
|
||
|
|
else if (strcmp(token, "query_mem") == 0)
|
||
|
|
test = APUSYS_DBG_TEST_QUERY_MEM;
|
||
|
|
else if (strcmp(token, "aee_test") == 0)
|
||
|
|
test = APUSYS_DBG_TEST_AEE;
|
||
|
|
else if (strcmp(token, "aee_cmd_timeout") == 0)
|
||
|
|
test = APUSYS_DBG_CMD_TIMEOUT_AEE;
|
||
|
|
else {
|
||
|
|
ret = -EINVAL;
|
||
|
|
mdw_drv_err("no test(%s)\n", token);
|
||
|
|
goto out;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* parse arguments */
|
||
|
|
for (i = 0; i < max_arg && (token = strsep(&cursor, " ")); i++) {
|
||
|
|
ret = kstrtouint(token, 10, &args[i]);
|
||
|
|
if (ret) {
|
||
|
|
mdw_drv_err("fail to parse args[%d]\n", i);
|
||
|
|
goto out;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* call test */
|
||
|
|
mdw_dbg_test_func(test, args, i);
|
||
|
|
|
||
|
|
ret = count;
|
||
|
|
out:
|
||
|
|
|
||
|
|
kfree(tmp);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static const struct file_operations mdw_dbg_fops_test = {
|
||
|
|
.open = mdw_dbg_open_test,
|
||
|
|
.read = seq_read,
|
||
|
|
.llseek = seq_lseek,
|
||
|
|
.release = single_release,
|
||
|
|
.write = mdw_dbg_write_test,
|
||
|
|
};
|
||
|
|
|
||
|
|
//----------------------------------------------
|
||
|
|
int mdw_dbg_init(void)
|
||
|
|
{
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
mdw_flw_debug("+\n");
|
||
|
|
|
||
|
|
g_mdw_klog = 0;
|
||
|
|
memset(g_dbg_prop, 0, sizeof(g_dbg_prop));
|
||
|
|
|
||
|
|
/* create debug root */
|
||
|
|
mdw_dbg_root = debugfs_create_dir(APUSYS_DBG_DIR, NULL);
|
||
|
|
|
||
|
|
/* create device table info */
|
||
|
|
mdw_dbg_devinfo = debugfs_create_file("devinfo", 0444,
|
||
|
|
mdw_dbg_root, NULL, &mdw_dbg_fops_devinfo);
|
||
|
|
|
||
|
|
/* create device queue info */
|
||
|
|
mdw_dbg_device = debugfs_create_dir("device", mdw_dbg_root);
|
||
|
|
|
||
|
|
/* create user info */
|
||
|
|
mdw_dbg_user = debugfs_create_file("user", 0444,
|
||
|
|
mdw_dbg_root, NULL, &mdw_dbg_fops_user);
|
||
|
|
|
||
|
|
|
||
|
|
/* create feature option info */
|
||
|
|
mdw_dbg_test = debugfs_create_file("test", 0644,
|
||
|
|
mdw_dbg_root, NULL, &mdw_dbg_fops_test);
|
||
|
|
|
||
|
|
/* create log level */
|
||
|
|
mdw_dbg_log = debugfs_create_u32("klog", 0644,
|
||
|
|
mdw_dbg_root, &g_mdw_klog);
|
||
|
|
|
||
|
|
/* create trace enable */
|
||
|
|
cfg_apusys_trace = 0;
|
||
|
|
mdw_dbg_trace = debugfs_create_u8("trace_en", 0644,
|
||
|
|
mdw_dbg_root, &cfg_apusys_trace);
|
||
|
|
|
||
|
|
|
||
|
|
mdw_flw_debug("-\n");
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int mdw_dbg_exit(void)
|
||
|
|
{
|
||
|
|
debugfs_remove_recursive(mdw_dbg_root);
|
||
|
|
return 0;
|
||
|
|
}
|