diff --git a/drivers/video/tegra/host/nvdla/nvdla.h b/drivers/video/tegra/host/nvdla/nvdla.h index 227ba6cf..7b6a8bf1 100644 --- a/drivers/video/tegra/host/nvdla/nvdla.h +++ b/drivers/video/tegra/host/nvdla/nvdla.h @@ -116,9 +116,11 @@ struct nvdla_cmd_mem { * @pdev pointer to platform device * @pool pointer to queue table * @dbg_mask debug mask for print level - * @en_trace flag to enable tracing + * @en_trace flag to enable kernel tracing * @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 */ struct nvdla_device { struct platform_device *pdev; @@ -131,6 +133,8 @@ struct nvdla_device { u32 en_trace; u32 fw_version; struct nvdla_cmd_mem cmd_mem; + u32 trace_enable; + u32 events_mask; }; /** diff --git a/drivers/video/tegra/host/nvdla/nvdla_debug.c b/drivers/video/tegra/host/nvdla/nvdla_debug.c index 1db8ada5..cff4747f 100644 --- a/drivers/video/tegra/host/nvdla/nvdla_debug.c +++ b/drivers/video/tegra/host/nvdla/nvdla_debug.c @@ -1,7 +1,7 @@ /* * NVDLA debug utils * - * Copyright (c) 2016, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2016 - 2017, 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, @@ -70,7 +70,7 @@ static const struct file_operations nvdla_fw_ver_fops = { .release = single_release, }; -static int debug_dla_dump_show(struct seq_file *s, void *data) +static int debug_dla_tracedump_show(struct seq_file *s, void *data) { char *bufptr; struct flcn *m; @@ -87,7 +87,7 @@ static int debug_dla_dump_show(struct seq_file *s, void *data) if (!m) return 0; - if (m->trace_dump_va) { + if (m->trace_dump_va && nvdla_dev->trace_enable) { bufptr = (char *)m->trace_dump_va; if (!strcmp(bufptr, "")) @@ -132,21 +132,299 @@ static int debug_dla_dump_show(struct seq_file *s, void *data) return 0; } -static int debug_dla_trace_open(struct inode *inode, struct file *file) +static int debug_dla_enable_trace_show(struct seq_file *s, void *data) { - return single_open(file, debug_dla_dump_show, inode->i_private); + struct nvdla_device *nvdla_dev = (struct nvdla_device *)s->private; + + seq_printf(s, "%u\n", nvdla_dev->trace_enable); + return 0; } -static const struct file_operations debug_dla_trace_fops = { - .open = debug_dla_trace_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, +static int debug_dla_eventmask_show(struct seq_file *s, void *data) +{ + struct nvdla_device *nvdla_dev = (struct nvdla_device *)s->private; + + seq_printf(s, "%u\n", nvdla_dev->events_mask); + return 0; +} + +static int debug_dla_eventmask_help_show(struct seq_file *s, void *data) +{ + seq_printf(s, "%s\n", + "\nDla Firmware has following different tracing categories:"); + seq_printf(s, "%s\n", " BIT(0) - Processor\n" + " BIT(1) - Falcon\n" + " BIT(2) - Events\n" + " BIT(3) - Scheduler Queue\n" + " BIT(4) - Operation Cache\n"); + seq_printf(s, "%s\n", "To enable all type of tracing events," + "set all bits ( 0 - 4 ): "); + seq_printf(s, "%s\n\n", " echo 31 > events_mask"); + return 0; +} + +static int debug_dla_bintracedump_show(struct seq_file *s, void *data) +{ + char *bufptr; + struct flcn *m; + struct nvdla_device *nvdla_dev; + struct platform_device *pdev; + uint32_t i = 0; + uint32_t offset = TRACE_DATA_OFFSET; + uint32_t start, end, datasize; + + nvdla_dev = (struct nvdla_device *)s->private; + pdev = nvdla_dev->pdev; + m = get_flcn(pdev); + + if (!m) + return 0; + + if (m->trace_dump_va && nvdla_dev->trace_enable) { + bufptr = (char *)m->trace_dump_va; + + if (!strcmp(bufptr, "")) + return 0; + + memcpy(&start, bufptr, sizeof(uint32_t)); + memcpy(&end, ((char *)bufptr + sizeof(uint32_t)), + sizeof(uint32_t)); + + i = start; + + if (start == (end + 1)) + datasize = (uint32_t)TRACE_BUFFER_SIZE - offset; + else + datasize = end - start; + + /* to read trace buffer from 0th index */ + i = 0; + /* in this case, datasize includes header data also */ + datasize += offset; + + /* Dump data in binary format. */ + while (i < datasize) + seq_printf(s, "%c", bufptr[i++]); + } + + return 0; +} + +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); +} + +static int debug_dla_eventmask_open(struct inode *inode, struct file *file) +{ + return single_open(file, debug_dla_eventmask_show, inode->i_private); +} + +static int debug_dla_eventmask_help_open(struct inode *inode, struct file *file) +{ + return single_open(file, debug_dla_eventmask_help_show, inode->i_private); +} + +static int debug_dla_trace_open(struct inode *inode, struct file *file) +{ + return single_open(file, debug_dla_tracedump_show, inode->i_private); +} + +static int debug_dla_bintrace_open(struct inode *inode, struct file *file) +{ + return single_open(file, debug_dla_bintracedump_show, inode->i_private); +} + +static ssize_t debug_dla_eventmask_set(struct file *file, + const char __user *buffer, size_t count, loff_t *off) +{ + int ret; + u32 val; + struct platform_device *pdev; + struct nvdla_device *nvdla_dev; + struct seq_file *p = file->private_data; + char str[] = "0123456789abcdef"; + + nvdla_dev = (struct nvdla_device *)p->private; + pdev = nvdla_dev->pdev; + count = min_t(size_t, strlen(str), count); + if (copy_from_user(str, buffer, count)) + return -EFAULT; + + mutex_lock(&p->lock); + /* get value entered by user in variable val */ + ret = sscanf(str, "%u", &val); + /* Check valid values for event_mask */ + if (ret == 1 && val <= 31) + nvdla_dev->events_mask = val; + mutex_unlock(&p->lock); + + if (ret != 1) { + nvdla_dbg_err(pdev, "Incorrect input!"); + goto invalid_input; + } + + /* + * Currently only five trace categories are added, + * and hence only five bits are being used to enable/disable + * the trace categories. + */ + if (val > 31) { + nvdla_dbg_err(pdev, + "invalid input, please" + " check /d/nvdla*/firmware/trace/events/help"); + ret = -EINVAL; + goto invalid_input; + } + + /* Add send command to firmware from here */ + return count; + +invalid_input: + return ret; +} + +static ssize_t debug_dla_enable_trace_set(struct file *file, + const char __user *buffer, size_t count, loff_t *off) +{ + int ret; + u32 val; + struct nvdla_device *nvdla_dev; + struct platform_device *pdev; + struct seq_file *p = file->private_data; + char str[] = "0123456789abcdef"; + + nvdla_dev = (struct nvdla_device *)p->private; + pdev = nvdla_dev->pdev; + count = min_t(size_t, strlen(str), count); + if (copy_from_user(str, buffer, count)) + return -EFAULT; + + mutex_lock(&p->lock); + /* get value entered by user in variable val */ + ret = sscanf(str, "%u", &val); + /* Check valid values for trace_enable */ + if (ret == 1 && (val == 0 || val == 1)) + nvdla_dev->trace_enable = val; + mutex_unlock(&p->lock); + + if (ret != 1) { + nvdla_dbg_err(pdev, "Incorrect input!"); + goto invalid_input; + } + + if (val != 0 && val != 1) { + nvdla_dbg_err(pdev, + "invalid input, please" + " enter 0(disable) or 1(enable)!"); + ret = -EINVAL; + goto invalid_input; + } + + /* Add send command to firmware from here */ + return count; + +invalid_input: + return ret; +} + +static const struct file_operations debug_dla_enable_trace_fops = { + .open = debug_dla_enable_trace_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = debug_dla_enable_trace_set, }; +static const struct file_operations debug_dla_eventmask_fops = { + .open = debug_dla_eventmask_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = debug_dla_eventmask_set, +}; + +static const struct file_operations debug_dla_eventmask_help_fops = { + .open = debug_dla_eventmask_help_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations debug_dla_event_trace_fops = { + .open = debug_dla_trace_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations debug_dla_bin_event_trace_fops = { + .open = debug_dla_bintrace_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void dla_fw_debugfs_init(struct platform_device *pdev) +{ + struct dentry *fw_dir, *fw_trace, *events; + struct nvhost_device_data *pdata = platform_get_drvdata(pdev); + struct nvdla_device *nvdla_dev = pdata->private_data; + struct dentry *dla_debugfs_root = pdata->debugfs; + + if (!dla_debugfs_root) + return; + + fw_dir = debugfs_create_dir("firmware", dla_debugfs_root); + if (!fw_dir) + return; + + if (!debugfs_create_file("version", S_IRUGO, fw_dir, + nvdla_dev, &nvdla_fw_ver_fops)) + goto trace_failed; + + fw_trace = debugfs_create_dir("trace", fw_dir); + if (!fw_trace) + goto trace_failed; + + if (!debugfs_create_file("enable", S_IRUGO | S_IWUSR, fw_trace, + nvdla_dev, &debug_dla_enable_trace_fops)) + goto trace_failed; + + if (!debugfs_create_file("text_trace", S_IRUGO, fw_trace, + nvdla_dev, &debug_dla_event_trace_fops)) + goto trace_failed; + + if (!debugfs_create_file("bin_trace", S_IRUGO, fw_trace, + nvdla_dev, &debug_dla_bin_event_trace_fops)) + goto trace_failed; + + events = debugfs_create_dir("events", fw_trace); + if (!events) + goto event_failed; + + if (!debugfs_create_file("category", S_IWUSR | S_IRUGO, events, + nvdla_dev, &debug_dla_eventmask_fops)) { + goto event_failed; + } + + if (!debugfs_create_file("help", S_IRUGO, events, + nvdla_dev, &debug_dla_eventmask_help_fops)) { + goto event_failed; + } + + return; + +event_failed: + debugfs_remove_recursive(events); + return; + +trace_failed: + debugfs_remove_recursive(fw_dir); +} + void nvdla_debug_init(struct platform_device *pdev) { - struct dentry *ret; struct nvhost_device_data *pdata = platform_get_drvdata(pdev); struct nvdla_device *nvdla_dev = pdata->private_data; struct dentry *de = pdata->debugfs; @@ -158,10 +436,6 @@ void nvdla_debug_init(struct platform_device *pdev) &nvdla_dev->dbg_mask); debugfs_create_u32("en_trace", S_IRUGO | S_IWUSR, de, &nvdla_dev->en_trace); - debugfs_create_file("fw_version", S_IRUGO, de, nvdla_dev, - &nvdla_fw_ver_fops); - ret = debugfs_create_file("fw_trace", S_IRUGO, - de, nvdla_dev, &debug_dla_trace_fops); - if (!ret) - nvdla_dbg_err(pdev, "Failed to create trace debug file!\n"); + + dla_fw_debugfs_init(pdev); }