mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
tegra_bootloader_debug: move profiler to sysfs
Add changes to use sysfs file system for reading bootloader profiling data. Golden debug registers dump for mb1, mb2 and cpu_bl continue to use debugfs file system. Bug 3512531 Bug 3896536 Change-Id: I34d337cc8cfb8f36f7ae833ad8cee8dd3f1d90f0 Signed-off-by: Anvesh Salveru <asalveru@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2690043 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2864625 Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com> Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com> Tested-by: Bharat Nihalani <bnihalani@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
79cd1e31b1
commit
28e5701fd6
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
// Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@@ -18,11 +18,13 @@
|
|||||||
|
|
||||||
static const char *module_name = "tegra_bootloader_debug";
|
static const char *module_name = "tegra_bootloader_debug";
|
||||||
static const char *dir_name = "tegra_bootloader";
|
static const char *dir_name = "tegra_bootloader";
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
static const char *gr_file_mb1 = "gr_mb1";
|
static const char *gr_file_mb1 = "gr_mb1";
|
||||||
static const char *gr_file_mb2 = "gr_mb2";
|
static const char *gr_file_mb2 = "gr_mb2";
|
||||||
static const char *gr_file_cpu_bl = "gr_cpu_bl";
|
static const char *gr_file_cpu_bl = "gr_cpu_bl";
|
||||||
static const char *profiler = "profiler";
|
|
||||||
static const char *boot_cfg = "boot_cfg";
|
static const char *boot_cfg = "boot_cfg";
|
||||||
|
#endif
|
||||||
|
|
||||||
struct gr_address_value {
|
struct gr_address_value {
|
||||||
unsigned int gr_address;
|
unsigned int gr_address;
|
||||||
@@ -68,21 +70,21 @@ struct spi_boot_rx_frame_full {
|
|||||||
uint8_t data[8200 - sizeof(struct spi_boot_header)];
|
uint8_t data[8200 - sizeof(struct spi_boot_header)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct kobject *boot_profiler_kobj;
|
||||||
|
static void *tegra_bl_mapped_prof_start;
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
const uint32_t gr_mb1 = enum_gr_mb1;
|
const uint32_t gr_mb1 = enum_gr_mb1;
|
||||||
const uint32_t gr_mb2 = enum_gr_mb2;
|
const uint32_t gr_mb2 = enum_gr_mb2;
|
||||||
const uint32_t gr_cpu_bl = enum_gr_cpu_bl;
|
const uint32_t gr_cpu_bl = enum_gr_cpu_bl;
|
||||||
|
|
||||||
static int dbg_golden_register_show(struct seq_file *s, void *unused);
|
static int dbg_golden_register_show(struct seq_file *s, void *unused);
|
||||||
static int profiler_show(struct seq_file *s, void *unused);
|
|
||||||
static int profiler_open(struct inode *inode, struct file *file);
|
|
||||||
static int dbg_golden_register_open_mb1(struct inode *inode, struct file *file);
|
static int dbg_golden_register_open_mb1(struct inode *inode, struct file *file);
|
||||||
static int dbg_golden_register_open_mb2(struct inode *inode, struct file *file);
|
static int dbg_golden_register_open_mb2(struct inode *inode, struct file *file);
|
||||||
static int dbg_golden_register_open_cpu_bl(struct inode *inode, struct file *file);
|
static int dbg_golden_register_open_cpu_bl(struct inode *inode, struct file *file);
|
||||||
static struct dentry *bl_debug_node;
|
static struct dentry *bl_debug_node;
|
||||||
static struct dentry *bl_debug_verify_reg_node;
|
static struct dentry *bl_debug_verify_reg_node;
|
||||||
static struct dentry *bl_debug_profiler;
|
|
||||||
static struct dentry *bl_debug_boot_cfg;
|
static struct dentry *bl_debug_boot_cfg;
|
||||||
static void *tegra_bl_mapped_prof_start;
|
|
||||||
static void *tegra_bl_mapped_debug_data_start;
|
static void *tegra_bl_mapped_debug_data_start;
|
||||||
static int boot_cfg_show(struct seq_file *s, void *unused);
|
static int boot_cfg_show(struct seq_file *s, void *unused);
|
||||||
static int boot_cfg_open(struct inode *inode, struct file *file);
|
static int boot_cfg_open(struct inode *inode, struct file *file);
|
||||||
@@ -111,21 +113,13 @@ static const struct file_operations debug_gr_fops_cpu_bl = {
|
|||||||
.release = single_release,
|
.release = single_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static const struct file_operations profiler_fops = {
|
|
||||||
.open = profiler_open,
|
|
||||||
.read = seq_read,
|
|
||||||
.llseek = seq_lseek,
|
|
||||||
.release = single_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static const struct file_operations boot_cfg_fops = {
|
static const struct file_operations boot_cfg_fops = {
|
||||||
.open = boot_cfg_open,
|
.open = boot_cfg_open,
|
||||||
.read = seq_read,
|
.read = seq_read,
|
||||||
.llseek = seq_lseek,
|
.llseek = seq_lseek,
|
||||||
.release = single_release,
|
.release = single_release,
|
||||||
};
|
};
|
||||||
|
#endif /* CONFIG_DEBUG_FS */
|
||||||
|
|
||||||
#define MAX_PROFILE_STRLEN 55
|
#define MAX_PROFILE_STRLEN 55
|
||||||
|
|
||||||
@@ -134,15 +128,18 @@ struct profiler_record {
|
|||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
static int profiler_show(struct seq_file *s, void *unused)
|
static ssize_t profiler_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
char *buf)
|
||||||
{
|
{
|
||||||
|
ssize_t ret = 0;
|
||||||
struct profiler_record *profiler_data;
|
struct profiler_record *profiler_data;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int prof_data_section_valid = 0;
|
int prof_data_section_valid = 0;
|
||||||
|
|
||||||
if (!tegra_bl_mapped_prof_start || !tegra_bl_prof_size) {
|
if (!tegra_bl_mapped_prof_start || !tegra_bl_prof_size) {
|
||||||
seq_puts(s, "Error mapping profiling data\n");
|
ret += sprintf(buf + ret, "%s\n", "Error mapping profiling data\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,28 +150,28 @@ static int profiler_show(struct seq_file *s, void *unused)
|
|||||||
i++;
|
i++;
|
||||||
if (!profiler_data[i].timestamp) {
|
if (!profiler_data[i].timestamp) {
|
||||||
if (prof_data_section_valid) {
|
if (prof_data_section_valid) {
|
||||||
seq_puts(s, "\n");
|
ret += sprintf(buf + ret, "\n");
|
||||||
prof_data_section_valid = 0;
|
prof_data_section_valid = 0;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
seq_printf(s, "%-54s\t%16lld", profiler_data[i].str, profiler_data[i].timestamp);
|
ret += sprintf(buf + ret, "%-54s\t%16lld",
|
||||||
|
profiler_data[i].str, profiler_data[i].timestamp);
|
||||||
if (i > 0 && profiler_data[i - 1].timestamp) {
|
if (i > 0 && profiler_data[i - 1].timestamp) {
|
||||||
seq_printf(s, "\t%16lld",
|
ret += sprintf(buf + ret, "\t%16lld",
|
||||||
profiler_data[i].timestamp - profiler_data[i - 1].timestamp);
|
profiler_data[i].timestamp - profiler_data[i - 1].timestamp);
|
||||||
}
|
}
|
||||||
seq_puts(s, "\n");
|
ret += sprintf(buf + ret, "\n");
|
||||||
prof_data_section_valid = 1;
|
prof_data_section_valid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int profiler_open(struct inode *inode, struct file *file)
|
static struct kobj_attribute profiler_attribute =
|
||||||
{
|
__ATTR(profiler, 0400, profiler_show, NULL);
|
||||||
return single_open(file, profiler_show, &inode->i_private);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
static int dbg_golden_register_show(struct seq_file *s, void *unused)
|
static int dbg_golden_register_show(struct seq_file *s, void *unused)
|
||||||
{
|
{
|
||||||
struct gr_header *golden_reg_header = (struct gr_header *)tegra_bl_mapped_debug_data_start;
|
struct gr_header *golden_reg_header = (struct gr_header *)tegra_bl_mapped_debug_data_start;
|
||||||
@@ -231,10 +228,13 @@ static int dbg_golden_register_open_cpu_bl( __attribute((unused))struct inode *i
|
|||||||
{
|
{
|
||||||
return single_open(file, dbg_golden_register_show, (void *)&gr_cpu_bl);
|
return single_open(file, dbg_golden_register_show, (void *)&gr_cpu_bl);
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_DEBUG_FS */
|
||||||
|
|
||||||
static int __init tegra_bootloader_debuginit(void)
|
static int __init tegra_bootloader_debuginit(void)
|
||||||
{
|
{
|
||||||
void __iomem *ptr_bl_prof_start = NULL;
|
void __iomem *ptr_bl_prof_start = NULL;
|
||||||
|
int bl_debug_verify_file_entry;
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
void __iomem *ptr_bl_debug_data_start = NULL;
|
void __iomem *ptr_bl_debug_data_start = NULL;
|
||||||
void __iomem *ptr_bl_boot_cfg_start = NULL;
|
void __iomem *ptr_bl_boot_cfg_start = NULL;
|
||||||
|
|
||||||
@@ -274,33 +274,6 @@ static int __init tegra_bootloader_debuginit(void)
|
|||||||
module_name, PTR_ERR(bl_debug_verify_reg_node));
|
module_name, PTR_ERR(bl_debug_verify_reg_node));
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
bl_debug_profiler = debugfs_create_file(profiler, S_IRUGO,
|
|
||||||
bl_debug_node, NULL, &profiler_fops);
|
|
||||||
if (IS_ERR_OR_NULL(bl_debug_profiler)) {
|
|
||||||
pr_err("%s: failed to create debugfs entries: %ld\n",
|
|
||||||
module_name, PTR_ERR(bl_debug_profiler));
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
tegra_bl_mapped_prof_start = phys_to_virt(tegra_bl_prof_start);
|
|
||||||
if (tegra_bl_prof_start != 0
|
|
||||||
&& !pfn_valid(__phys_to_pfn(tegra_bl_prof_start))) {
|
|
||||||
ptr_bl_prof_start = ioremap(tegra_bl_prof_start, tegra_bl_prof_size);
|
|
||||||
|
|
||||||
WARN_ON(!ptr_bl_prof_start);
|
|
||||||
if (!ptr_bl_prof_start) {
|
|
||||||
pr_err("%s: Failed to map tegra_bl_prof_start%08x\n",
|
|
||||||
__func__, (unsigned int)tegra_bl_prof_start);
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
pr_info("Remapped tegra_bl_prof_start(0x%llx)"
|
|
||||||
" to address 0x%llx, size(0x%llx)\n",
|
|
||||||
(u64)tegra_bl_prof_start,
|
|
||||||
(u64)ptr_bl_prof_start,
|
|
||||||
(u64)tegra_bl_prof_size);
|
|
||||||
|
|
||||||
tegra_bl_mapped_prof_start = ptr_bl_prof_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
tegra_bl_mapped_debug_data_start =
|
tegra_bl_mapped_debug_data_start =
|
||||||
phys_to_virt(tegra_bl_debug_data_start);
|
phys_to_virt(tegra_bl_debug_data_start);
|
||||||
@@ -352,23 +325,65 @@ static int __init tegra_bootloader_debuginit(void)
|
|||||||
tegra_bl_mapped_boot_cfg_start = ptr_bl_boot_cfg_start;
|
tegra_bl_mapped_boot_cfg_start = ptr_bl_boot_cfg_start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_DEBUG_FS */
|
||||||
|
boot_profiler_kobj = kobject_create_and_add(dir_name, kernel_kobj);
|
||||||
|
if (IS_ERR_OR_NULL(boot_profiler_kobj)) {
|
||||||
|
pr_err("%s: failed to create sysfs entries: %ld\n",
|
||||||
|
module_name, PTR_ERR(boot_profiler_kobj));
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
bl_debug_verify_file_entry = sysfs_create_file(boot_profiler_kobj,
|
||||||
|
&profiler_attribute.attr);
|
||||||
|
if (bl_debug_verify_file_entry) {
|
||||||
|
pr_err("%s: failed to create sysfs file : %d\n",
|
||||||
|
module_name, bl_debug_verify_file_entry);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tegra_bl_prof_start != 0
|
||||||
|
&& !pfn_valid(__phys_to_pfn(tegra_bl_prof_start))) {
|
||||||
|
ptr_bl_prof_start = ioremap(tegra_bl_prof_start, tegra_bl_prof_size);
|
||||||
|
|
||||||
|
WARN_ON(!ptr_bl_prof_start);
|
||||||
|
if (!ptr_bl_prof_start) {
|
||||||
|
pr_err("%s: Failed to map tegra_bl_prof_start%08x\n",
|
||||||
|
__func__, (unsigned int)tegra_bl_prof_start);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
pr_info("Remapped tegra_bl_prof_start(0x%llx) "
|
||||||
|
"to address 0x%llx, size(0x%llx)\n",
|
||||||
|
(u64)tegra_bl_prof_start,
|
||||||
|
(u64)ptr_bl_prof_start,
|
||||||
|
(u64)tegra_bl_prof_size);
|
||||||
|
|
||||||
|
tegra_bl_mapped_prof_start = ptr_bl_prof_start;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_err:
|
out_err:
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
if (!IS_ERR_OR_NULL(bl_debug_node))
|
if (!IS_ERR_OR_NULL(bl_debug_node))
|
||||||
debugfs_remove_recursive(bl_debug_node);
|
debugfs_remove_recursive(bl_debug_node);
|
||||||
|
|
||||||
if (ptr_bl_prof_start)
|
|
||||||
iounmap(ptr_bl_prof_start);
|
|
||||||
if (ptr_bl_debug_data_start)
|
if (ptr_bl_debug_data_start)
|
||||||
iounmap(ptr_bl_debug_data_start);
|
iounmap(ptr_bl_debug_data_start);
|
||||||
if (ptr_bl_boot_cfg_start)
|
if (ptr_bl_boot_cfg_start)
|
||||||
iounmap(ptr_bl_boot_cfg_start);
|
iounmap(ptr_bl_boot_cfg_start);
|
||||||
|
#endif
|
||||||
|
if (ptr_bl_prof_start)
|
||||||
|
iounmap(ptr_bl_prof_start);
|
||||||
|
|
||||||
|
if (boot_profiler_kobj) {
|
||||||
|
sysfs_remove_file(boot_profiler_kobj,
|
||||||
|
&profiler_attribute.attr);
|
||||||
|
kobject_put(boot_profiler_kobj);
|
||||||
|
boot_profiler_kobj = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
static int boot_cfg_show(struct seq_file *s, void *unused)
|
static int boot_cfg_show(struct seq_file *s, void *unused)
|
||||||
{
|
{
|
||||||
uint8_t *data = tegra_bl_mapped_boot_cfg_start;
|
uint8_t *data = tegra_bl_mapped_boot_cfg_start;
|
||||||
@@ -413,6 +428,7 @@ static int boot_cfg_open(struct inode *inode, struct file *file)
|
|||||||
{
|
{
|
||||||
return single_open(file, boot_cfg_show, &inode->i_private);
|
return single_open(file, boot_cfg_show, &inode->i_private);
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_DEBUG_FS */
|
||||||
|
|
||||||
static int __init tegra_bl_debuginit_module_init(void)
|
static int __init tegra_bl_debuginit_module_init(void)
|
||||||
{
|
{
|
||||||
@@ -421,17 +437,25 @@ static int __init tegra_bl_debuginit_module_init(void)
|
|||||||
|
|
||||||
static void __exit tegra_bl_debuginit_module_exit(void)
|
static void __exit tegra_bl_debuginit_module_exit(void)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
if (!IS_ERR_OR_NULL(bl_debug_node))
|
if (!IS_ERR_OR_NULL(bl_debug_node))
|
||||||
debugfs_remove_recursive(bl_debug_node);
|
debugfs_remove_recursive(bl_debug_node);
|
||||||
|
|
||||||
if (tegra_bl_mapped_prof_start)
|
|
||||||
iounmap(tegra_bl_mapped_prof_start);
|
|
||||||
|
|
||||||
if (tegra_bl_mapped_debug_data_start)
|
if (tegra_bl_mapped_debug_data_start)
|
||||||
iounmap(tegra_bl_mapped_debug_data_start);
|
iounmap(tegra_bl_mapped_debug_data_start);
|
||||||
|
|
||||||
if (tegra_bl_mapped_boot_cfg_start)
|
if (tegra_bl_mapped_boot_cfg_start)
|
||||||
iounmap(tegra_bl_mapped_boot_cfg_start);
|
iounmap(tegra_bl_mapped_boot_cfg_start);
|
||||||
|
#endif
|
||||||
|
if (tegra_bl_mapped_prof_start)
|
||||||
|
iounmap(tegra_bl_mapped_prof_start);
|
||||||
|
|
||||||
|
if (boot_profiler_kobj) {
|
||||||
|
sysfs_remove_file(boot_profiler_kobj,
|
||||||
|
&profiler_attribute.attr);
|
||||||
|
kobject_put(boot_profiler_kobj);
|
||||||
|
boot_profiler_kobj = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(tegra_bl_debuginit_module_init);
|
module_init(tegra_bl_debuginit_module_init);
|
||||||
|
|||||||
Reference in New Issue
Block a user