tsec: add debugfs support

add a debugfs file to read-out firmware log messages

Change-Id: I3501b117884a822bd835beecd8e3956481c37386
Signed-off-by: Mayuresh Kulkarni <mkulkarni@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2884815
(cherry picked from commit 590640045e9ba26914cad055000f7ce3618640b9)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2895857
Tested-by: Bharat Nihalani <bnihalani@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Mayuresh Kulkarni
2023-04-09 07:40:33 +00:00
committed by mobile promotions
parent df86f78c76
commit d3bc17ca8b
4 changed files with 167 additions and 0 deletions

View File

@@ -103,6 +103,134 @@ static void tsec_set_cg_regs(struct tsec_device_data *pdata)
tsec_writel(pdata, tsec_riscv_cg_r(), 0x3); tsec_writel(pdata, tsec_riscv_cg_r(), 0x3);
} }
#ifdef CONFIG_DEBUG_FS
struct nvriscv_log_buffer {
/* read offset updated by client RM */
uint32_t read_offset;
/* write offset updated by firmware RM */
uint32_t write_offset;
/* buffer size configured by client RM */
uint32_t buffer_size;
/* magic number for header validation in nvwatch */
uint32_t magic;
};
#define LOG_BUF_SIZE ((4 * SZ_1K) - sizeof(struct nvriscv_log_buffer))
#define INFO_BUF_SIZE (SZ_128)
static u8 log_buf[LOG_BUF_SIZE]; /* Read from DMEM into local buffer */
static u8 info_buf[INFO_BUF_SIZE];
static int tsec_debug_show(struct seq_file *s, void *unused)
{
int info_len = 0;
struct tsec_device_data *pdata = (struct tsec_device_data *)s->private;
/* Do not attempt to read DMEM if TSEC is power-down */
if (pdata->power_on) {
#define DMEM_PORT (0)
/* Offset of Log Buffer in DMEM */
u32 log_bug_off = tsec_dmem_logbuf_offset_f();
u32 dmemC = tsec_falcon_dmemc_r(DMEM_PORT);
u32 dmemD = tsec_falcon_dmemd_r(DMEM_PORT);
struct nvriscv_log_buffer log_buf_info;
/* Auto Increment Read */
u32 loop_index = 0;
tsec_writel(pdata, dmemC, log_bug_off | 0x02000000);
while (loop_index < LOG_BUF_SIZE) {
u32 reg_val;
reg_val = tsec_readl(pdata, dmemD);
log_buf[loop_index++] = (u8)((reg_val >> 0) & 0xFF);
log_buf[loop_index++] = (u8)((reg_val >> 8) & 0xFF);
log_buf[loop_index++] = (u8)((reg_val >> 16) & 0xFF);
log_buf[loop_index++] = (u8)((reg_val >> 24) & 0xFF);
}
log_buf_info.read_offset = tsec_readl(pdata, dmemD);
log_buf_info.write_offset = tsec_readl(pdata, dmemD);
log_buf_info.buffer_size = tsec_readl(pdata, dmemD);
log_buf_info.magic = tsec_readl(pdata, dmemD);
/*
* Replace any null charecter with new line because tsec ucode
* does the reverse before dumping the logs in the buffer
*/
for (loop_index = 0; loop_index < LOG_BUF_SIZE; loop_index++) {
if (log_buf[loop_index] == 0)
log_buf[loop_index] = 0xA;
}
/* Insert null charecter at end of log buffer */
log_buf[log_buf_info.write_offset] = 0;
/* Print log_buf */
info_len = sprintf(info_buf,
"Tsec Logs Start: read_offset=%d write_offset=%d buffer_size=%d magic=0x%x\n",
log_buf_info.read_offset, log_buf_info.write_offset,
log_buf_info.buffer_size, log_buf_info.magic);
if (info_len > 0)
seq_write(s, info_buf, info_len);
seq_write(s, log_buf,
(log_buf_info.write_offset - log_buf_info.read_offset));
info_len = strlen("Tsec Logs End\n");
strcpy(info_buf, "Tsec Logs End\n");
info_buf[info_len] = '\0';
seq_write(s, info_buf, info_len);
} else {
info_len = strlen("Tsec power-down\n");
strcpy(info_buf, "Tsec power-down\n");
info_buf[info_len] = '\0';
seq_write(s, info_buf, info_len);
}
return 0;
}
static int tsec_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, tsec_debug_show, inode->i_private);
}
static const struct file_operations tsec_debug_fops = {
.open = tsec_debug_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/*
* TSEC debugfs interface
* create: /sys/kernel/debug/tegra_tsec/fw_logs.
* cat /sys/kernel/debug/tegra_tsec/fw_logs will read the DMEM reserved for
* debug messages and print it on console.
*/
static int tsec_module_init_debugfs(struct platform_device *dev)
{
struct tsec_device_data *pdata = platform_get_drvdata(dev);
pdata->debug_root = debugfs_create_dir("tegra_tsec", NULL);
if (!pdata->debug_root)
return -ENOMEM;
debugfs_create_file("fw_logs", 0444, pdata->debug_root,
pdata, &tsec_debug_fops);
return 0;
}
static void tsec_module_deinit_debugfs(struct platform_device *dev)
{
struct tsec_device_data *pdata = platform_get_drvdata(dev);
debugfs_remove_recursive(pdata->debug_root);
}
#endif /* CONFIG_DEBUG_FS */
/* /*
* TSEC Power Management Operations * TSEC Power Management Operations
*/ */
@@ -286,11 +414,25 @@ static int tsec_probe(struct platform_device *dev)
return err; return err;
} }
#ifdef CONFIG_DEBUG_FS
if (debugfs_initialized()) {
err = tsec_module_init_debugfs(dev);
if (err) {
dev_err(&dev->dev, "error %d in tsec_module_init_debugfs\n", err);
return err;
}
}
#endif /* CONFIG_DEBUG_FS */
return tsec_kickoff_boot(dev); return tsec_kickoff_boot(dev);
} }
static int tsec_remove(struct platform_device *dev) static int tsec_remove(struct platform_device *dev)
{ {
#ifdef CONFIG_DEBUG_FS
tsec_module_deinit_debugfs(dev);
#endif /* CONFIG_DEBUG_FS */
return tsec_poweroff(&dev->dev); return tsec_poweroff(&dev->dev);
} }

View File

@@ -47,6 +47,10 @@ struct tsec_device_data {
char *riscv_desc_bin; char *riscv_desc_bin;
/* name of riscv image binary */ /* name of riscv image binary */
char *riscv_image_bin; char *riscv_image_bin;
#ifdef CONFIG_DEBUG_FS
struct dentry *debug_root;
#endif /* CONFIG_DEBUG_FS */
}; };
/* /*

View File

@@ -29,5 +29,9 @@
#include <linux/platform/tegra/tegra_mc.h> /* for mc_get_carveout_info */ #include <linux/platform/tegra/tegra_mc.h> /* for mc_get_carveout_info */
#include <asm/cacheflush.h> /* for __flush_dcache_area */ #include <asm/cacheflush.h> /* for __flush_dcache_area */
#endif #endif
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h> /* for debugfs APIs */
#endif
#include <linux/sizes.h> /* for SZ_* size macros */
#endif /* TSEC_LINUX_H */ #endif /* TSEC_LINUX_H */

View File

@@ -251,4 +251,21 @@ static inline u32 tsec_riscv_br_retcode_result_pass_v(void)
return 0x00000003; return 0x00000003;
} }
static inline u32 tsec_falcon_dmemc_r(u32 r)
{
/* NV_PSEC_FALCON_DMEMC_0 */
return (0x11c0 + (r) * 8);
}
static inline u32 tsec_falcon_dmemd_r(u32 r)
{
/* NV_PSEC_FALCON_DMEMD_0 */
return (0x11c4 + (r) * 8);
}
static inline u32 tsec_dmem_logbuf_offset_f(void)
{
return 0x14000;
}
#endif /* TSEC_REGS_H */ #endif /* TSEC_REGS_H */