video: tegra: host: enable firmware gcov support

- add debugfs to enable firmware gcov and dump gcov data
- on request for enabling gcov, allocate gcov region and inform
  firmware about gcov PA
- gcda debugfs dumps gcda data stored by firmware

Change-Id: Ibca37048120eba21aa5f1d4936bd4ae5254fdddf
Signed-off-by: Shridhar Rasal <srasal@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1586783
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Shridhar Rasal
2017-10-27 12:08:14 +05:30
committed by Laxman Dewangan
parent d483e0b167
commit 7520eea4dd
4 changed files with 249 additions and 1 deletions

View File

@@ -250,6 +250,7 @@ enum dla_regions_e {
DLA_REGION_PRINTF = 1,
DLA_REGION_GOS = 2,
DLA_REGION_TRACE = 3,
DLA_REGION_GCOV = 4,
};
/**

View File

@@ -224,6 +224,118 @@ int nvdla_send_cmd(struct platform_device *pdev,
return ret;
}
static int nvdla_set_gcov_region(struct platform_device *pdev, bool unset_region)
{
int err = 0;
struct nvdla_cmd_mem_info gcov_cmd_mem_info;
struct nvdla_cmd_data cmd_data;
struct dla_region_printf *gcov_region = NULL;
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
struct nvdla_device *nvdla_dev = pdata->private_data;
if (!pdata->flcn_isr)
return 0;
err = nvhost_module_busy(pdev);
if (err) {
nvdla_dbg_err(pdev, "failed to power on\n");
err = -ENODEV;
goto fail_to_power_on;
}
/* assign memory for gcov command */
err = nvdla_get_cmd_memory(pdev, &gcov_cmd_mem_info);
if (err) {
nvdla_dbg_err(pdev,
"dma allocation failed for gcov command.");
goto alloc_gcov_cmd_failed;
}
gcov_region = (struct dla_region_printf *)(gcov_cmd_mem_info.va);
gcov_region->region = DLA_REGION_GCOV;
if (unset_region)
gcov_region->address = 0;
else
gcov_region->address = nvdla_dev->gcov_dump_pa;
gcov_region->size = GCOV_BUFFER_SIZE;
cmd_data.method_id = DLA_CMD_SET_REGIONS;
cmd_data.method_data = ALIGNED_DMA(gcov_cmd_mem_info.pa);
cmd_data.wait = true;
err = nvdla_send_cmd(pdev, &cmd_data);
/* release memory allocated for gcov command */
nvdla_put_cmd_memory(pdev, gcov_cmd_mem_info.index);
if (err != 0) {
nvdla_dbg_err(pdev, "failed to send gcov command");
goto gcov_send_cmd_failed;
}
nvhost_module_idle(pdev);
return err;
gcov_send_cmd_failed:
alloc_gcov_cmd_failed:
nvhost_module_idle(pdev);
fail_to_power_on:
return err;
}
int nvdla_free_gcov_region(struct platform_device *pdev, bool update_region)
{
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
struct nvdla_device *nvdla_dev = pdata->private_data;
int ret = 0;
if (update_region) {
ret = nvdla_set_gcov_region(pdev, true);
if (ret)
return ret;
}
if (nvdla_dev->gcov_dump_pa) {
dma_free_attrs(&pdev->dev, GCOV_BUFFER_SIZE,
nvdla_dev->gcov_dump_va,
nvdla_dev->gcov_dump_pa,
__DMA_ATTR(attrs));
nvdla_dev->gcov_dump_va = NULL;
nvdla_dev->gcov_dump_pa = 0;
}
return 0;
}
int nvdla_alloc_gcov_region(struct platform_device *pdev)
{
int err = 0;
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
struct nvdla_device *nvdla_dev = pdata->private_data;
/* Gcov buffer allocation must be done at once only. */
if (!nvdla_dev->gcov_dump_va) {
/* allocate gcov region */
nvdla_dev->gcov_dump_va = dma_alloc_attrs(&pdev->dev,
GCOV_BUFFER_SIZE, &nvdla_dev->gcov_dump_pa,
GFP_KERNEL, __DMA_ATTR(attrs));
if (!nvdla_dev->gcov_dump_va) {
nvdla_dbg_err(pdev,
"dma gcov memory allocation failed");
err = -ENOMEM;
goto fail_alloc_gcov_dma;
}
}
err = nvdla_set_gcov_region(pdev, false);
if (err)
nvdla_free_gcov_region(pdev, false);
fail_alloc_gcov_dma:
return err;
}
static int nvdla_alloc_trace_region(struct platform_device *pdev)
{
int err = 0;
@@ -644,6 +756,8 @@ static int __exit nvdla_remove(struct platform_device *pdev)
nvhost_queue_deinit(nvdla_dev->pool);
nvhost_client_device_release(pdev);
nvdla_free_gcov_region(pdev, false);
if (nvdla_dev->trace_dump_pa) {
dma_free_attrs(&pdev->dev, TRACE_BUFFER_SIZE,
nvdla_dev->trace_dump_va,

View File

@@ -87,6 +87,11 @@
*/
#define DEBUG_BUFFER_SIZE SZ_256
/**
* Firmware GCOV Buffer Size
*/
#define GCOV_BUFFER_SIZE SZ_64K
/*
* CMD submission timeout in msec
*/
@@ -167,6 +172,9 @@ struct nvdla_cmd_data {
* @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
*/
struct nvdla_device {
struct platform_device *pdev;
@@ -186,6 +194,9 @@ struct nvdla_device {
u32 *debug_dump_va;
dma_addr_t trace_dump_pa;
u32 *trace_dump_va;
u32 en_fw_gcov;
dma_addr_t gcov_dump_pa;
u32 *gcov_dump_va;
};
/**
@@ -350,5 +361,7 @@ int nvdla_get_task_mem(struct nvhost_queue *queue,
struct nvdla_task **task);
void nvdla_put_task_mem(struct nvdla_task *task);
size_t nvdla_get_max_task_size(void);
int nvdla_alloc_gcov_region(struct platform_device *pdev);
int nvdla_free_gcov_region(struct platform_device *pdev, bool update_region);
#endif /* End of __NVHOST_NVDLA_H__ */

View File

@@ -208,6 +208,87 @@ static int debug_dla_bintracedump_show(struct seq_file *s, void *data)
return 0;
}
static int debug_dla_en_fw_gcov_show(struct seq_file *s, void *data)
{
struct nvdla_device *nvdla_dev = (struct nvdla_device *)s->private;
seq_printf(s, "%u\n", nvdla_dev->en_fw_gcov);
return 0;
}
static ssize_t debug_dla_en_fw_gcov_alloc(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);
mutex_unlock(&p->lock);
if (ret != 1) {
nvdla_dbg_err(pdev, "Incorrect input!");
goto invalid_input;
}
/* alloc gcov region */
if (val == 1) {
ret = nvdla_alloc_gcov_region(pdev);
if (ret) {
nvdla_dbg_err(pdev, "failed to allocate gcov region.");
goto op_failed;
}
nvdla_dev->en_fw_gcov = 1;
} else if (val == 0) {
if (nvdla_dev->en_fw_gcov == 0)
return count;
ret = nvdla_free_gcov_region(pdev, true);
if (ret) {
nvdla_dbg_err(pdev, "failed to free gcov region.");
goto op_failed;
}
nvdla_dev->en_fw_gcov = 0;
} else {
nvdla_dbg_err(pdev, "inval i/p. Valid i/p: 0 and 1");
ret = -EINVAL;
goto op_failed;
}
return count;
op_failed:
invalid_input:
return ret;
}
static int debug_dla_fw_gcov_gcda_show(struct seq_file *s, void *data)
{
char *bufptr;
uint32_t datasize;
struct nvdla_device *nvdla_dev;
nvdla_dev = (struct nvdla_device *)s->private;
if (nvdla_dev->gcov_dump_va && nvdla_dev->en_fw_gcov) {
bufptr = (char *)nvdla_dev->gcov_dump_va;
datasize = (uint32_t)GCOV_BUFFER_SIZE;
seq_write(s, bufptr, datasize);
}
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);
@@ -233,6 +314,16 @@ static int debug_dla_bintrace_open(struct inode *inode, struct file *file)
return single_open(file, debug_dla_bintracedump_show, inode->i_private);
}
static int debug_dla_en_fw_gcov_open(struct inode *inode, struct file *file)
{
return single_open(file, debug_dla_en_fw_gcov_show, inode->i_private);
}
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_set_trace_event_config(struct platform_device *pdev,
u32 value, u32 sub_cmd)
{
@@ -430,9 +521,24 @@ static const struct file_operations debug_dla_bin_event_trace_fops = {
.release = single_release,
};
static const struct file_operations debug_dla_en_fw_gcov_fops = {
.open = debug_dla_en_fw_gcov_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = debug_dla_en_fw_gcov_alloc,
};
static const struct file_operations debug_dla_fw_gcov_gcda_fops = {
.open = debug_dla_fw_gcov_gcda_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 dentry *fw_dir, *fw_trace, *events, *fw_gcov;
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
struct nvdla_device *nvdla_dev = pdata->private_data;
struct dentry *dla_debugfs_root = pdata->debugfs;
@@ -478,8 +584,22 @@ static void dla_fw_debugfs_init(struct platform_device *pdev)
goto event_failed;
}
fw_gcov = debugfs_create_dir("gcov", fw_dir);
if (!fw_gcov)
goto gcov_failed;
if (!debugfs_create_file("enable", S_IRUGO | S_IWUSR, fw_gcov,
nvdla_dev, &debug_dla_en_fw_gcov_fops))
goto gcov_failed;
if (!debugfs_create_file("gcda", S_IRUGO, fw_gcov,
nvdla_dev, &debug_dla_fw_gcov_gcda_fops))
goto gcov_failed;
return;
gcov_failed:
debugfs_remove_recursive(fw_gcov);
event_failed:
debugfs_remove_recursive(events);
return;