From c032aa992edd86eb352d0ccae5867b38c55ec815 Mon Sep 17 00:00:00 2001 From: Adeel Raza Date: Fri, 28 May 2021 20:08:31 -0700 Subject: [PATCH] platform: tegra: dce: Add debugfs for external tests External clients such as MODS require the ability to run tests. Add support for this feature. Currently only the following 2 external client tests are supported: - MODS ALU test - MODS DMA test Bug 3198239 JIRA TDS-6362 Change-Id: I18c20a9fa5d2606056d65b76fbaae9b0c81746d4 Signed-off-by: Adeel Raza Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2606595 Tested-by: mobile promotions Reviewed-by: mobile promotions --- drivers/platform/tegra/dce/dce-admin.c | 39 +++++ drivers/platform/tegra/dce/dce-debug.c | 148 ++++++++++++++++++ drivers/platform/tegra/dce/include/dce.h | 7 + .../dce/include/interface/dce-admin-cmds.h | 20 ++- 4 files changed, 209 insertions(+), 5 deletions(-) diff --git a/drivers/platform/tegra/dce/dce-admin.c b/drivers/platform/tegra/dce/dce-admin.c index 9597643a..83fb263c 100644 --- a/drivers/platform/tegra/dce/dce-admin.c +++ b/drivers/platform/tegra/dce/dce-admin.c @@ -395,6 +395,45 @@ out: return ret; } +/** + * dce_admin_send_cmd_ext_test - Sends DCE_ADMIN_CMD_EXT_TEST cmd. + * + * @d - Pointer to tegra_dce struct. + * @msg - Pointer to dce_ipc_msg struct. + * + * Return - 0 if successful + */ +int dce_admin_send_cmd_ext_test(struct tegra_dce *d, + struct dce_ipc_message *msg) +{ + int ret = -1; + struct dce_admin_ipc_cmd *req_msg; + struct dce_admin_ipc_resp *resp_msg; + + if (!msg || !msg->tx.data || !msg->rx.data) + goto out; + + /* return if dce bootstrap not completed */ + if (!dce_is_bootstrap_done(d)) { + dce_err(d, "Admin Bootstrap not yet done"); + goto out; + } + + req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data); + resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data); + + req_msg->cmd = (uint32_t)DCE_ADMIN_CMD_EXT_TEST; + + ret = dce_admin_send_msg(d, msg); + if (ret) { + dce_err(d, "Error sending test msg : [%d]", ret); + goto out; + } + +out: + return ret; +} + /** * dce_admin_send_cmd_ver - Sends DCE_ADMIN_CMD_VERSION cmd. * diff --git a/drivers/platform/tegra/dce/dce-debug.c b/drivers/platform/tegra/dce/dce-debug.c index 39b37f75..c712fbe5 100644 --- a/drivers/platform/tegra/dce/dce-debug.c +++ b/drivers/platform/tegra/dce/dce-debug.c @@ -18,6 +18,7 @@ #include #include #include +#include /** * dbg_dce_load_fw - loads the fw to DRAM. @@ -305,6 +306,132 @@ static const struct file_operations admin_echo_fops = { .write = dbg_dce_admin_echo_fops_write, }; +/* + * Debugfs nodes for displaying a help message about tests required by external + * clients (ex: MODS) + */ +static int dbg_dce_tests_external_help_fops_show(struct seq_file *s, void *data) +{ + /* TODO: Add test description? */ + seq_printf(s, "DCE External Test List\n" + "----------------------\n" + " - Test #0: MODS ALU Test\n" + " - Test #1: MODS DMA Test\n"); + + return 0; + +} + +static int dbg_dce_tests_external_help_fops_open(struct inode *inode, + struct file *file) +{ + return single_open(file, dbg_dce_tests_external_help_fops_show, + inode->i_private); +} + +static const struct file_operations tests_external_help_fops = { + .open = dbg_dce_tests_external_help_fops_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* Get status of last external client test run */ +static ssize_t dbg_dce_tests_external_status_fops_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + struct tegra_dce *d = file->private_data; + struct dce_device *d_dev = dce_device_from_dce(d); + char buf[15]; + ssize_t bytes_printed; + + bytes_printed = snprintf(buf, 15, "%d\n", d_dev->ext_test_status); + if (bytes_printed < 0) { + dce_err(d, "Unable to return external test status"); + buf[0] = '\0'; + bytes_printed = 0; + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, bytes_printed); +} + +static const struct file_operations tests_external_status_fops = { + .open = simple_open, + .read = dbg_dce_tests_external_status_fops_read, +}; + +/* Run an external client test */ +static ssize_t dbg_dce_tests_external_run_fops_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + u32 test; + struct dce_ipc_message *msg = NULL; + struct dce_admin_ipc_cmd *req_msg = NULL; + struct dce_admin_ipc_resp *resp_msg = NULL; + struct tegra_dce *d = file->private_data; + struct dce_device *d_dev = dce_device_from_dce(d); + + ret = kstrtou32_from_user(user_buf, count, 10, &test); + if (ret) { + dce_err(d, "Invalid test number!"); + d_dev->ext_test_status = DCE_ERR_CORE_NOT_FOUND; + return -EINVAL; + } + switch (test) { + case DCE_ADMIN_EXT_TEST_ALU: + dce_info(d, "Running ALU test"); + break; + + case DCE_ADMIN_EXT_TEST_DMA: + dce_info(d, "Running DMA test"); + break; + + default: + dce_err(d, "Test(%u) not found! Check help node for valid test IDs.", + test); + d_dev->ext_test_status = DCE_ERR_CORE_NOT_FOUND; + return -EINVAL; + } + + msg = dce_admin_allocate_message(d); + if (!msg) { + dce_err(d, "IPC msg allocation failed"); + d_dev->ext_test_status = DCE_ERR_CORE_OTHER; + goto exit; + } + + req_msg = (struct dce_admin_ipc_cmd *)(msg->tx.data); + resp_msg = (struct dce_admin_ipc_resp *) (msg->rx.data); + + req_msg->args.ext_test.test = test; + ret = dce_admin_send_cmd_ext_test(d, msg); + if (ret) { + dce_err(d, "Admin msg failed"); + d_dev->ext_test_status = DCE_ERR_CORE_IPC_IVC_ERR; + goto exit; + } + + if (resp_msg->error == DCE_ERR_CORE_SUCCESS) + dce_info(d, "Test passed!"); + else if (resp_msg->error == DCE_ERR_CORE_NOT_IMPLEMENTED) + dce_err(d, "Test not implemented!"); + else + dce_err(d, "Test failed(%d)!", (int32_t)resp_msg->error); + d_dev->ext_test_status = resp_msg->error; + +exit: + if (msg) + dce_admin_free_message(d, msg); + + return count; +} + +static const struct file_operations tests_external_run_fops = { + .open = simple_open, + .write = dbg_dce_tests_external_run_fops_write, +}; + static ssize_t dbg_dce_boot_dce_fops_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -568,6 +695,7 @@ void dce_init_debug(struct tegra_dce *d) struct dentry *retval; struct device *dev = dev_from_dce(d); struct dce_device *d_dev = dce_device_from_dce(d); + struct dentry *debugfs_dir = NULL; d_dev->debugfs = debugfs_create_dir("tegra_dce", NULL); if (!d_dev->debugfs) @@ -608,6 +736,26 @@ void dce_init_debug(struct tegra_dce *d) if (!retval) goto err_handle; + /* Tests */ + debugfs_dir = debugfs_create_dir("tests", d_dev->debugfs); + if (!debugfs_dir) + goto err_handle; + debugfs_dir = debugfs_create_dir("external", debugfs_dir); + if (!debugfs_dir) + goto err_handle; + retval = debugfs_create_file("help", 0444, + debugfs_dir, d, &tests_external_help_fops); + if (!retval) + goto err_handle; + retval = debugfs_create_file("run", 0220, + debugfs_dir, d, &tests_external_run_fops); + if (!retval) + goto err_handle; + retval = debugfs_create_file("status", 0444, + debugfs_dir, d, &tests_external_status_fops); + if (!retval) + goto err_handle; + return; err_handle: diff --git a/drivers/platform/tegra/dce/include/dce.h b/drivers/platform/tegra/dce/include/dce.h index f16291bc..7197cb73 100644 --- a/drivers/platform/tegra/dce/include/dce.h +++ b/drivers/platform/tegra/dce/include/dce.h @@ -237,6 +237,11 @@ struct dce_device { * @debugfs : Debugfs node for DCE Linux device. */ struct dentry *debugfs; + /** + * @ext_test_status : Return code for external client tests run via + * debugfs + */ + s32 ext_test_status; #endif }; @@ -395,6 +400,8 @@ int dce_admin_get_ipc_channel_info(struct tegra_dce *d, struct dce_ipc_queue_info *q_info); int dce_admin_send_cmd_echo(struct tegra_dce *d, struct dce_ipc_message *msg); +int dce_admin_send_cmd_ext_test(struct tegra_dce *d, + struct dce_ipc_message *msg); int dce_admin_handle_ipc_requested_event(struct tegra_dce *d, void *params); int dce_admin_handle_ipc_received_event(struct tegra_dce *d, void *params); int dce_admin_ipc_wait(struct tegra_dce *d, u32 w_type); diff --git a/drivers/platform/tegra/dce/include/interface/dce-admin-cmds.h b/drivers/platform/tegra/dce/include/interface/dce-admin-cmds.h index 7b285d1d..6f5b9904 100644 --- a/drivers/platform/tegra/dce/include/interface/dce-admin-cmds.h +++ b/drivers/platform/tegra/dce/include/interface/dce-admin-cmds.h @@ -52,13 +52,14 @@ // coverage data #define DCE_ADMIN_CMD_PERF_START 0x0FU // start collecting perf data #define DCE_ADMIN_CMD_PERF_STOP 0x10U // stop collecting perf data -#define DCE_ADMIN_CMD_TEST_START 0x11U // start tests -#define DCE_ADMIN_CMD_TEST_STOP 0x12U // stop tests and return status -#define DCE_ADMIN_CMD_DEBUG 0x13U // debug command +#define DCE_ADMIN_CMD_INT_TEST_START 0x11U // start internal tests +#define DCE_ADMIN_CMD_INT_TEST_STOP 0x12U // stop internal tests and return status +#define DCE_ADMIN_CMD_EXT_TEST 0x13U // run external test (blocking call) +#define DCE_ADMIN_CMD_DEBUG 0x14U // debug command -#define DCE_ADMIN_CMD_RM_BOOTSTRAP 0x14U // tell RM to "bootstrap" +#define DCE_ADMIN_CMD_RM_BOOTSTRAP 0x15U // tell RM to "bootstrap" -#define DCE_ADMIN_CMD_NEXT 0x15U // must be last command ID + 1 +#define DCE_ADMIN_CMD_NEXT 0x16U // must be last command ID + 1 struct dce_admin_version_info { uint32_t version; @@ -79,6 +80,14 @@ struct dce_admin_echo { uint32_t data; }; +enum dce_admin_ext_test { + DCE_ADMIN_EXT_TEST_ALU = 0U, + DCE_ADMIN_EXT_TEST_DMA = 1U, +}; +struct dce_admin_ext_test_args { + enum dce_admin_ext_test test; +}; + struct dce_admin_log_args { uint32_t log_enable; uint32_t log_level; @@ -133,6 +142,7 @@ struct dce_admin_ipc_cmd { union { struct dce_admin_version_info version; struct dce_admin_echo echo; + struct dce_admin_ext_test_args ext_test; struct dce_admin_log_args log; struct dce_admin_ipc_info_args ipc_info; struct dce_admin_mem_args mem_map;