From 0c6ea4efe2b0e9363741ff8aea60da354e840de7 Mon Sep 17 00:00:00 2001 From: Akshata Bhat Date: Tue, 18 Oct 2022 18:40:12 -0700 Subject: [PATCH] nvdla: kmd: Debugfs nodes for resource utilization + Added a debugfs node to input window size + Added a debugfs node to output utilization rate Commands to input window size: * echo [unsigned_value_in_us] > /sys/kernel/debug/nvdla0/firmware/window_size * echo [unsigned_value_in_us] > /sys/kernel/debug/nvdla1/firmware/window_size Commands to output utilization rate: * cat /sys/kernel/debug/nvdla0/firmware/utilization_rate * cat /sys/kernel/debug/nvdla1/firmware/utilization_rate JIRA DLA-6318 Signed-off-by: Akshata Bhat Change-Id: I17b0a5bb9a3e632d992c7b38cf84d472a99d28ed Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2794433 Reviewed-by: Arvind M Reviewed-by: svc_kernel_abi Reviewed-by: Amit Sharma (SW-TEGRA) Tested-by: Arvind M GVS: Gerrit_Virtual_Submit --- .../video/tegra/host/nvdla/dla_os_interface.h | 34 ++- drivers/video/tegra/host/nvdla/nvdla.c | 88 ++++++ drivers/video/tegra/host/nvdla/nvdla.h | 42 +-- drivers/video/tegra/host/nvdla/nvdla_debug.c | 267 ++++++++++++++++++ 4 files changed, 401 insertions(+), 30 deletions(-) diff --git a/drivers/video/tegra/host/nvdla/dla_os_interface.h b/drivers/video/tegra/host/nvdla/dla_os_interface.h index 8e7601b9..cc340bf8 100644 --- a/drivers/video/tegra/host/nvdla/dla_os_interface.h +++ b/drivers/video/tegra/host/nvdla/dla_os_interface.h @@ -1,7 +1,7 @@ /* * NVDLA OS Interface * - * Copyright (c) 2016-2021, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2016-2022, NVIDIA Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -141,39 +141,47 @@ enum dla_commands { /** * Used for testing communication between CCPLEX and DLA */ - DLA_CMD_PING = 1U, - DLA_CMD_GET_STATUS_UNUSED = 2U, - DLA_CMD_RESET_UNUSED = 3U, - DLA_CMD_DLA_CONTROL_UNUSED = 4U, + DLA_CMD_PING = 1U, + DLA_CMD_GET_STATUS_UNUSED = 2U, + DLA_CMD_RESET_UNUSED = 3U, + DLA_CMD_DLA_CONTROL_UNUSED = 4U, DLA_CMD_GET_QUEUE_STATUS_UNUSED = 5U, - DLA_CMD_GET_STATISTICS_UNUSED = 6U, + DLA_CMD_GET_STATISTICS = 6U, /** * Submit task to DLA */ - DLA_CMD_SUBMIT_TASK = 7U, + DLA_CMD_SUBMIT_TASK = 7U, DLA_CMD_SET_SCHEDULER_UNUSED = 8U, - DLA_CMD_READ_INFO_UNUSED = 9U, + DLA_CMD_READ_INFO_UNUSED = 9U, /** * Set various debugging parameters (trace/printf/crashdump) * Only enabled in Debug build. */ - DLA_CMD_SET_DEBUG = 10U, + DLA_CMD_SET_DEBUG = 10U, /** * Set the address & size of various regions used for various reasons */ - DLA_CMD_SET_REGIONS = 11U, + DLA_CMD_SET_REGIONS = 11U, /** * Suspend processing a queue */ - DLA_CMD_QUEUE_SUSPEND = 12U, + DLA_CMD_QUEUE_SUSPEND = 12U, /** * Resume processing a queue */ - DLA_CMD_QUEUE_RESUME = 13U, + DLA_CMD_QUEUE_RESUME = 13U, /** * Flushes a queue */ - DLA_CMD_QUEUE_FLUSH = 14U, + DLA_CMD_QUEUE_FLUSH = 14U, + /** + * Sets stat window size + */ + DLA_CMD_SET_STAT_WINDOW_SIZE = 15U, + /** + * Gets stat window size + */ + DLA_CMD_GET_STAT_WINDOW_SIZE = 16U, }; /** diff --git a/drivers/video/tegra/host/nvdla/nvdla.c b/drivers/video/tegra/host/nvdla/nvdla.c index b7089911..f20141d6 100644 --- a/drivers/video/tegra/host/nvdla/nvdla.c +++ b/drivers/video/tegra/host/nvdla/nvdla.c @@ -592,6 +592,78 @@ out: return ret; } +/* Free utilization rate memory */ +void nvdla_free_utilization_rate_memory(struct platform_device *pdev) +{ + struct nvhost_device_data *pdata = platform_get_drvdata(pdev); + struct nvdla_device *nvdla_dev = pdata->private_data; + + if (nvdla_dev->utilization_mem_pa) { + dma_free_attrs(&pdev->dev, sizeof(unsigned int), + nvdla_dev->utilization_mem_va, + nvdla_dev->utilization_mem_pa, + 0); + nvdla_dev->utilization_mem_va = NULL; + nvdla_dev->utilization_mem_pa = 0; + } +} + +/* Allocate memory to store the resource utilization rate */ +int nvdla_alloc_utilization_rate_memory(struct platform_device *pdev) +{ + struct nvhost_device_data *pdata = platform_get_drvdata(pdev); + struct nvdla_device *nvdla_dev = pdata->private_data; + int err = 0; + + /* allocate memory for utilization rate */ + nvdla_dev->utilization_mem_va = dma_alloc_attrs(&pdev->dev, + sizeof(unsigned int), &nvdla_dev->utilization_mem_pa, + GFP_KERNEL, 0); + + if (nvdla_dev->utilization_mem_va == NULL) { + nvdla_dbg_err(pdev, "utilization rate dma alloc failed"); + err = -ENOMEM; + } + + return err; +} + +/* Free window size memory */ +void nvdla_free_window_size_memory(struct platform_device *pdev) +{ + struct nvhost_device_data *pdata = platform_get_drvdata(pdev); + struct nvdla_device *nvdla_dev = pdata->private_data; + + if (nvdla_dev->window_mem_pa) { + dma_free_attrs(&pdev->dev, sizeof(unsigned int), + nvdla_dev->window_mem_va, + nvdla_dev->window_mem_pa, + 0); + nvdla_dev->window_mem_va = NULL; + nvdla_dev->window_mem_pa = 0; + } +} + +/* Allocate memory to store the window size for which the utilization rate is computed */ +int nvdla_alloc_window_size_memory(struct platform_device *pdev) +{ + struct nvhost_device_data *pdata = platform_get_drvdata(pdev); + struct nvdla_device *nvdla_dev = pdata->private_data; + int err = 0; + + /* allocate memory for window_size */ + nvdla_dev->window_mem_va = dma_alloc_attrs(&pdev->dev, + sizeof(unsigned int), &nvdla_dev->window_mem_pa, + GFP_KERNEL, 0); + + if (nvdla_dev->window_mem_va == NULL) { + nvdla_dbg_err(pdev, "window size dma alloc failed"); + err = -ENOMEM; + } + + return err; +} + #ifdef CONFIG_TEGRA_SOC_HWPM static int nvdla_hwpm_ip_pm(void *ip_dev, bool disable) { @@ -879,6 +951,14 @@ static int nvdla_probe(struct platform_device *pdev) if (err) goto err_alloc_cmd_mem; + err = nvdla_alloc_utilization_rate_memory(pdev); + if (err) + goto err_alloc_utilization_rate_mem; + + err = nvdla_alloc_window_size_memory(pdev); + if (err) + goto err_alloc_window_size_mem; + #ifdef CONFIG_TEGRA_SOC_HWPM nvdla_dbg_info(pdev, "hwpm ip %s register", pdev->name); hwpm_ip_ops.ip_dev = (void *)pdev; @@ -892,6 +972,11 @@ static int nvdla_probe(struct platform_device *pdev) nvdla_dbg_info(pdev, "pdata:%p initialized\n", pdata); return 0; + +err_alloc_window_size_mem: + nvdla_free_utilization_rate_memory(pdev); +err_alloc_utilization_rate_mem: + nvdla_free_cmd_memory(pdev); err_alloc_cmd_mem: err_mss_init: nvdla_queue_deinit(nvdla_dev->pool); @@ -951,6 +1036,9 @@ static int __exit nvdla_remove(struct platform_device *pdev) nvdla_dev->debug_dump_pa = 0; } + nvdla_free_utilization_rate_memory(pdev); + nvdla_free_window_size_memory(pdev); + /* free command mem in last */ nvdla_free_cmd_memory(pdev); diff --git a/drivers/video/tegra/host/nvdla/nvdla.h b/drivers/video/tegra/host/nvdla/nvdla.h index 4e40178d..6ecae352 100644 --- a/drivers/video/tegra/host/nvdla/nvdla.h +++ b/drivers/video/tegra/host/nvdla/nvdla.h @@ -225,23 +225,27 @@ enum nvdla_submit_mode { /** * data structure to keep per DLA engine device data * - * @pdev pointer to platform device - * @pool pointer to queue table - * @dbg_mask debug mask for print level - * @en_trace flag to enable kernel tracing - * @submit_mode flag to enable task submit mode, default is - * NVDLA_SUBMIT_MODE_MMIO - * @fw_version saves current firmware version - * @cmd_mem structure to hold command memory pool - * @trace_enable to enable/disable the DLA firmware trace - * @events_mask mask to set/reset the different DLA firmware trace event - * @debug_dump_pa physical address of print buffer - * @debug_dump_va virtual address of print buffer - * @trace_dump_pa physical address of trace buffer - * @trace_dump_va virtual address of trace buffer - * @en_fw_gcov flag to enable firmware gcov - * @gcov_dump_pa physical address of fw gcov buffer - * @gcov_dump_va virtual address of fw gcovbuffer + * @pdev pointer to platform device + * @pool pointer to queue table + * @dbg_mask debug mask for print level + * @en_trace flag to enable kernel tracing + * @submit_mode flag to enable task submit mode, default is + * NVDLA_SUBMIT_MODE_MMIO + * @fw_version saves current firmware version + * @cmd_mem structure to hold command memory pool + * @trace_enable to enable/disable the DLA firmware trace + * @events_mask mask to set/reset the different DLA firmware trace event + * @debug_dump_pa physical address of print buffer + * @debug_dump_va virtual address of print buffer + * @trace_dump_pa physical address of trace buffer + * @trace_dump_va virtual address of trace buffer + * @en_fw_gcov flag to enable firmware gcov + * @gcov_dump_pa physical address of fw gcov buffer + * @gcov_dump_va virtual address of fw gcovbuffer + * @utilization_mem_pa physical address of resource utilization buffer + * @utilization_mem_va virtual address of resource utilization buffer + * @window_mem_pa physical address of window size buffer + * @window_mem_va virtual address of window size buffer * @is_suspended flag to check if module is in suspend state. * @ping_lock lock to synchronize the ping operation requests. */ @@ -267,6 +271,10 @@ struct nvdla_device { dma_addr_t gcov_dump_pa; u32 *gcov_dump_va; struct work_struct reset_work; + dma_addr_t utilization_mem_pa; + u32 *utilization_mem_va; + dma_addr_t window_mem_pa; + u32 *window_mem_va; #ifdef CONFIG_PM bool is_suspended; #endif diff --git a/drivers/video/tegra/host/nvdla/nvdla_debug.c b/drivers/video/tegra/host/nvdla/nvdla_debug.c index 5b65e93a..bab19e24 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_debug.c +++ b/drivers/video/tegra/host/nvdla/nvdla_debug.c @@ -288,6 +288,240 @@ static int debug_dla_fw_gcov_gcda_show(struct seq_file *s, void *data) return 0; } +static int nvdla_get_stats(struct nvdla_device *nvdla_dev) +{ + int err = 0; + struct nvdla_cmd_data cmd_data; + struct platform_device *pdev; + + /* prepare command data */ + cmd_data.method_id = DLA_CMD_GET_STATISTICS; + cmd_data.method_data = ALIGNED_DMA(nvdla_dev->utilization_mem_pa); + cmd_data.wait = true; + + pdev = nvdla_dev->pdev; + if (pdev == NULL) + return -EFAULT; + + /* pass set debug command to falcon */ + err = nvdla_send_cmd(pdev, &cmd_data); + if (err != 0) + nvdla_dbg_err(pdev, "failed to send get stats command"); + + return err; +} + +static int debug_dla_fw_resource_util_show(struct seq_file *s, void *data) +{ + int err; + struct nvdla_device *nvdla_dev; + struct platform_device *pdev; + + unsigned int utilization, util_rate_characteristic, util_rate_mantissa; + + if (s == NULL) { + err = -EFAULT; + goto fail_no_dev; + } + + nvdla_dev = (struct nvdla_device *) s->private; + if (nvdla_dev == NULL) { + err = -EFAULT; + goto fail_no_dev; + } + + pdev = nvdla_dev->pdev; + if (pdev == NULL) { + err = -EFAULT; + goto fail_no_dev; + } + + /* make sure that device is powered on */ + err = nvhost_module_busy(pdev); + if (err != 0) { + nvdla_dbg_err(pdev, "failed to power on\n"); + err = -ENODEV; + goto fail_no_dev; + } + + err = nvdla_get_stats(nvdla_dev); + if (err != 0) { + nvdla_dbg_err(pdev, "Failed to send get stats command"); + goto fail_to_send_cmd; + } + + utilization = *(unsigned int *)nvdla_dev->utilization_mem_va; + util_rate_characteristic = (utilization / 10000); + util_rate_mantissa = (utilization % 10000); + + seq_printf(s, "%u.%04u\n", util_rate_characteristic, util_rate_mantissa); + +fail_to_send_cmd: + nvhost_module_idle(pdev); +fail_no_dev: + return err; +} + +static int nvdla_get_window_size(struct nvdla_device *nvdla_dev) +{ + int err = 0; + struct nvdla_cmd_data cmd_data; + struct platform_device *pdev; + + /* prepare command data */ + cmd_data.method_id = DLA_CMD_GET_STAT_WINDOW_SIZE; + cmd_data.method_data = ALIGNED_DMA(nvdla_dev->window_mem_pa); + cmd_data.wait = true; + + pdev = nvdla_dev->pdev; + if (pdev == NULL) { + err = -EFAULT; + goto fail_no_dev; + } + + /* make sure that device is powered on */ + err = nvhost_module_busy(pdev); + if (err != 0) { + nvdla_dbg_err(pdev, "failed to power on\n"); + err = -ENODEV; + goto fail_no_dev; + } + + /* pass set debug command to falcon */ + err = nvdla_send_cmd(pdev, &cmd_data); + if (err != 0) { + nvdla_dbg_err(pdev, "failed to send set window command"); + goto fail_to_send_cmd; + } + +fail_to_send_cmd: + nvhost_module_idle(pdev); +fail_no_dev: + return err; +} + +static int debug_dla_fw_stat_window_show(struct seq_file *s, void *data) +{ + int err; + struct nvdla_device *nvdla_dev; + struct platform_device *pdev; + + if (s == NULL) { + err = -EFAULT; + goto fail; + } + + nvdla_dev = (struct nvdla_device *) s->private; + if (nvdla_dev == NULL) { + err = -EFAULT; + goto fail; + } + + pdev = nvdla_dev->pdev; + if (pdev == NULL) { + err = -EFAULT; + goto fail; + } + + err = nvdla_get_window_size(nvdla_dev); + if (err != 0) { + nvdla_dbg_err(pdev, "Failed to get window size"); + goto fail; + } + + seq_printf(s, "%u\n", *(unsigned int *)nvdla_dev->window_mem_va); + + return 0; + +fail: + return err; +} + +/* + * When the user calls this debugfs node, the configurable + * window size value is passed down to the FW + */ +static int nvdla_set_window_size(struct nvdla_device *nvdla_dev) +{ + int err = 0; + struct nvdla_cmd_data cmd_data; + struct platform_device *pdev; + + /* prepare command data */ + cmd_data.method_id = DLA_CMD_SET_STAT_WINDOW_SIZE; + cmd_data.method_data = ALIGNED_DMA(nvdla_dev->window_mem_pa); + cmd_data.wait = true; + + pdev = nvdla_dev->pdev; + if (pdev == NULL) { + err = -EFAULT; + goto fail_no_dev; + } + + /* make sure that device is powered on */ + err = nvhost_module_busy(pdev); + if (err != 0) { + nvdla_dbg_err(pdev, "failed to power on\n"); + err = -ENODEV; + goto fail_no_dev; + } + + /* pass set debug command to falcon */ + err = nvdla_send_cmd(pdev, &cmd_data); + if (err != 0) { + nvdla_dbg_err(pdev, "failed to send set window command"); + goto fail_to_send_cmd; + } + +fail_to_send_cmd: + nvhost_module_idle(pdev); +fail_no_dev: + return err; +} + +static ssize_t debug_dla_fw_stat_window_write(struct file *file, + const char __user *buffer, size_t count, loff_t *off) +{ + int err; + struct seq_file *priv_data; + struct nvdla_device *nvdla_dev; + struct platform_device *pdev; + long write_value; + u32 *window_va; + + /* Fetch user requested write-value. */ + err = kstrtol_from_user(buffer, count, 10, &write_value); + if (err < 0) + goto fail; + + priv_data = file->private_data; + if (priv_data == NULL) + goto fail; + + nvdla_dev = (struct nvdla_device *) priv_data->private; + if (nvdla_dev == NULL) + goto fail; + + pdev = nvdla_dev->pdev; + if (pdev == NULL) + goto fail; + + window_va = nvdla_dev->window_mem_va; + if (write_value < UINT_MAX) + *window_va = write_value; + + err = nvdla_set_window_size(nvdla_dev); + if (err != 0) { + nvdla_dbg_err(pdev, "Failed to send set window size command"); + goto fail; + } + + return count; + +fail: + return -1; +} + static int debug_dla_enable_trace_open(struct inode *inode, struct file *file) { return single_open(file, debug_dla_enable_trace_show, inode->i_private); @@ -323,6 +557,16 @@ static int debug_dla_fw_gcov_gcda_open(struct inode *inode, struct file *file) return single_open(file, debug_dla_fw_gcov_gcda_show, inode->i_private); } +static int debug_dla_fw_resource_util_open(struct inode *inode, struct file *file) +{ + return single_open(file, debug_dla_fw_resource_util_show, inode->i_private); +} + +static int debug_dla_fw_stat_window_open(struct inode *inode, struct file *file) +{ + return single_open(file, debug_dla_fw_stat_window_show, inode->i_private); +} + static int debug_set_trace_event_config(struct platform_device *pdev, u32 value, u32 sub_cmd) { @@ -610,6 +854,21 @@ static const struct file_operations nvdla_fw_reload_fops = { .write = debug_dla_fw_reload_set, }; +static const struct file_operations debug_dla_resource_util_fops = { + .open = debug_dla_fw_resource_util_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations debug_dla_stat_window_fops = { + .open = debug_dla_fw_stat_window_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = debug_dla_fw_stat_window_write, +}; + static void dla_fw_debugfs_init(struct platform_device *pdev) { struct dentry *fw_dir, *fw_trace, *events, *fw_gcov; @@ -674,6 +933,14 @@ static void dla_fw_debugfs_init(struct platform_device *pdev) nvdla_dev, &debug_dla_fw_gcov_gcda_fops)) goto gcov_failed; + if (!debugfs_create_file("utilization_rate", S_IRUSR, fw_dir, + nvdla_dev, &debug_dla_resource_util_fops)) + goto trace_failed; + + if (!debugfs_create_file("stat_window_size", S_IRUSR | S_IWUSR, fw_dir, + nvdla_dev, &debug_dla_stat_window_fops)) + goto trace_failed; + return; gcov_failed: