mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 10:11:26 +03:00
video: tegra: host: nvdla: add trace support
- Add debugfs to read the traces
- Add support for trace buffer reading
- Add DLA_REGION_TRACE region
- Use Trace Buffer of size 1MB
- Pass wait param to nvdla_send_cmd() for printf cmd
and correct buffer freeing logic for it.
JIRA DLA-94
Change-Id: I42c0b1cb5b3cb1d4866deb80b7636964795d6de5
Signed-off-by: Amit Sharma (SW-Tegra) <amisharma@nvidia.com>
Reviewed-on: http://git-master/r/1229942
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Shridhar Rasal <srasal@nvidia.com>
This commit is contained in:
committed by
Laxman Dewangan
parent
bc8bf342a7
commit
b79f6e271a
@@ -157,6 +157,7 @@ struct dla_action_semaphore {
|
||||
enum dla_regions_e {
|
||||
DLA_REGION_PRINTF = 1,
|
||||
DLA_REGION_GOS = 2,
|
||||
DLA_REGION_TRACE = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -143,13 +143,12 @@ int nvdla_send_cmd(struct platform_device *pdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nvdla_alloc_dump_region(struct platform_device *pdev)
|
||||
static int nvdla_alloc_trace_region(struct platform_device *pdev)
|
||||
{
|
||||
int err = 0;
|
||||
struct flcn *m;
|
||||
dma_addr_t region_pa;
|
||||
struct dla_region_printf *region;
|
||||
u32 timeout = FLCN_IDLE_TIMEOUT_DEFAULT * 5;
|
||||
dma_addr_t tregion_pa;
|
||||
struct dla_region_printf *trace_region = NULL;
|
||||
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
|
||||
|
||||
if (!pdata->flcn_isr)
|
||||
@@ -158,6 +157,80 @@ static int nvdla_alloc_dump_region(struct platform_device *pdev)
|
||||
nvdla_dbg_fn(pdev, "");
|
||||
|
||||
m = get_flcn(pdev);
|
||||
if (!m)
|
||||
return -ENXIO;
|
||||
|
||||
/* Trace buffer allocation must be done at once only. */
|
||||
if (!m->trace_dump_va) {
|
||||
/* allocate trace region */
|
||||
m->trace_dump_va = dma_alloc_attrs(&pdev->dev,
|
||||
TRACE_BUFFER_SIZE, &m->trace_dump_pa,
|
||||
GFP_KERNEL, &attrs);
|
||||
|
||||
if (!m->trace_dump_va) {
|
||||
nvdla_dbg_err(pdev,
|
||||
"dma trace memory allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate memory for trace command */
|
||||
trace_region = (struct dla_region_printf *)
|
||||
dma_alloc_attrs(&pdev->dev,
|
||||
sizeof(struct dla_region_printf),
|
||||
&tregion_pa, GFP_KERNEL, &attrs);
|
||||
if (!trace_region) {
|
||||
nvdla_dbg_err(pdev,
|
||||
"dma allocation failed for trace command.");
|
||||
err = -ENOMEM;
|
||||
goto alloc_trace_cmd_failed;
|
||||
}
|
||||
|
||||
trace_region->region = DLA_REGION_TRACE;
|
||||
trace_region->address = m->trace_dump_pa;
|
||||
trace_region->size = TRACE_BUFFER_SIZE;
|
||||
|
||||
err = nvdla_send_cmd(pdev, DLA_CMD_SET_REGIONS,
|
||||
ALIGNED_DMA(tregion_pa), true);
|
||||
|
||||
/* free memory allocated for trace command */
|
||||
dma_free_attrs(&pdev->dev, sizeof(struct dla_region_printf),
|
||||
trace_region, tregion_pa, &attrs);
|
||||
|
||||
if (err != 0) {
|
||||
nvdla_dbg_err(pdev, "failed to send trace command");
|
||||
goto trace_send_cmd_failed;
|
||||
}
|
||||
|
||||
return err;
|
||||
|
||||
trace_send_cmd_failed:
|
||||
alloc_trace_cmd_failed:
|
||||
dma_free_attrs(&pdev->dev, TRACE_BUFFER_SIZE,
|
||||
m->trace_dump_va, m->trace_dump_pa, &attrs);
|
||||
m->trace_dump_va = NULL;
|
||||
m->trace_dump_pa = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nvdla_alloc_dump_region(struct platform_device *pdev)
|
||||
{
|
||||
int err = 0;
|
||||
struct flcn *m;
|
||||
dma_addr_t region_pa;
|
||||
struct dla_region_printf *region;
|
||||
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
|
||||
|
||||
if (!pdata->flcn_isr)
|
||||
return 0;
|
||||
|
||||
nvdla_dbg_fn(pdev, "");
|
||||
|
||||
m = get_flcn(pdev);
|
||||
if (!m)
|
||||
return -ENXIO;
|
||||
|
||||
/* allocate dump region */
|
||||
m->debug_dump_va = dma_alloc_attrs(&pdev->dev,
|
||||
DEBUG_BUFFER_SIZE, &m->debug_dump_pa,
|
||||
@@ -182,25 +255,27 @@ static int nvdla_alloc_dump_region(struct platform_device *pdev)
|
||||
region->size = DEBUG_BUFFER_SIZE;
|
||||
|
||||
/* pass dump region to falcon */
|
||||
nvdla_send_cmd(pdev, DLA_CMD_SET_REGIONS,
|
||||
ALIGNED_DMA(region_pa), false);
|
||||
err = nvdla_send_cmd(pdev, DLA_CMD_SET_REGIONS,
|
||||
ALIGNED_DMA(region_pa), true);
|
||||
|
||||
/* wait for falcon to idle */
|
||||
err = flcn_wait_idle(pdev, &timeout);
|
||||
if (err != 0)
|
||||
dev_err(&pdev->dev, "failed for wait for idle in timeout");
|
||||
|
||||
/* free memory allocated for command */
|
||||
/* free memory allocated for debug print command */
|
||||
dma_free_attrs(&pdev->dev, sizeof(struct dla_region_printf),
|
||||
region, region_pa,
|
||||
&attrs);
|
||||
region, region_pa, &attrs);
|
||||
|
||||
if (err != 0) {
|
||||
nvdla_dbg_err(pdev, "failed to send printf command");
|
||||
goto region_send_cmd_failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
region_send_cmd_failed:
|
||||
set_region_failed:
|
||||
dma_free_attrs(&pdev->dev, DEBUG_BUFFER_SIZE,
|
||||
m->debug_dump_va, m->debug_dump_pa,
|
||||
&attrs);
|
||||
m->debug_dump_va, m->debug_dump_pa, &attrs);
|
||||
m->debug_dump_va = NULL;
|
||||
m->debug_dump_pa = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -216,7 +291,7 @@ static void nvdla_free_dump_region(struct platform_device *pdev)
|
||||
return;
|
||||
|
||||
m = get_flcn(pdev);
|
||||
if (m->debug_dump_pa) {
|
||||
if (m && m->debug_dump_pa) {
|
||||
dma_free_attrs(&pdev->dev, DEBUG_BUFFER_SIZE,
|
||||
m->debug_dump_va, m->debug_dump_pa,
|
||||
&attrs);
|
||||
@@ -262,6 +337,10 @@ int nvhost_nvdla_finalize_poweron(struct platform_device *pdev)
|
||||
if (ret)
|
||||
nvhost_nvdla_prepare_poweroff(pdev);
|
||||
|
||||
ret = nvdla_alloc_trace_region(pdev);
|
||||
if (ret)
|
||||
nvhost_nvdla_prepare_poweroff(pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -402,10 +481,23 @@ static int __exit nvdla_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
|
||||
struct nvdla_device *nvdla_dev = pdata->private_data;
|
||||
struct flcn *m;
|
||||
|
||||
nvhost_queue_deinit(nvdla_dev->pool);
|
||||
nvhost_client_device_release(pdev);
|
||||
|
||||
m = get_flcn(pdev);
|
||||
if (!m)
|
||||
return -ENXIO;
|
||||
|
||||
if (m->trace_dump_pa) {
|
||||
dma_free_attrs(&pdev->dev, TRACE_BUFFER_SIZE,
|
||||
m->trace_dump_va, m->trace_dump_pa,
|
||||
&attrs);
|
||||
m->trace_dump_va = NULL;
|
||||
m->trace_dump_pa = 0;
|
||||
}
|
||||
|
||||
nvdla_dbg_fn(pdev, "");
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -54,6 +54,11 @@
|
||||
*/
|
||||
#define MAX_NVDLA_QUEUE_COUNT 16
|
||||
|
||||
/**
|
||||
* Trace Buffer Size
|
||||
*/
|
||||
#define TRACE_BUFFER_SIZE 0x100000
|
||||
|
||||
/**
|
||||
* data structure to keep per DLA engine device data
|
||||
*
|
||||
@@ -61,7 +66,6 @@
|
||||
* @pool pointer to queue table
|
||||
* @dbg_mask debug mask for print level
|
||||
* @en_trace flag to enable tracing
|
||||
*
|
||||
*/
|
||||
struct nvdla_device {
|
||||
struct platform_device *pdev;
|
||||
|
||||
@@ -19,8 +19,21 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/nvhost.h>
|
||||
#include "host1x/host1x.h"
|
||||
#include "flcn/flcn.h"
|
||||
#include "flcn/hw_flcn.h"
|
||||
#include "dla_os_interface.h"
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "nvdla/nvdla.h"
|
||||
#include "nvdla_debug.h"
|
||||
|
||||
/*
|
||||
* Header in ring buffer consist (start, end) two uint32_t values.
|
||||
* Trace data content starts from the offset below.
|
||||
*/
|
||||
#define TRACE_DATA_OFFSET (2 * sizeof(uint32_t))
|
||||
|
||||
static int nvdla_fw_ver_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct nvdla_device *nvdla_dev;
|
||||
@@ -57,8 +70,83 @@ static const struct file_operations nvdla_fw_ver_fops = {
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int debug_dla_dump_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, cindex = 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) {
|
||||
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;
|
||||
|
||||
while (cindex < datasize) {
|
||||
seq_printf(s, "%c", bufptr[i]);
|
||||
i++;
|
||||
i = ((i - offset) % (TRACE_BUFFER_SIZE - offset)) +
|
||||
offset;
|
||||
cindex++;
|
||||
|
||||
if ((bufptr[i] == '\n') && (cindex < datasize)) {
|
||||
seq_printf(s, "%c", bufptr[i]);
|
||||
|
||||
/* skip extra new line chars */
|
||||
while ((bufptr[i] == '\n') &&
|
||||
(cindex < datasize)) {
|
||||
i++;
|
||||
i = ((i - offset) %
|
||||
(TRACE_BUFFER_SIZE - offset)) +
|
||||
offset;
|
||||
cindex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
seq_printf(s, "%c", '\n');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int debug_dla_trace_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, debug_dla_dump_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations debug_dla_trace_fops = {
|
||||
.open = debug_dla_trace_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
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;
|
||||
@@ -66,10 +154,14 @@ void nvdla_debug_init(struct platform_device *pdev)
|
||||
if (!de)
|
||||
return;
|
||||
|
||||
debugfs_create_u32("debug_mask", S_IRUGO|S_IWUSR, de,
|
||||
debugfs_create_u32("debug_mask", S_IRUGO | S_IWUSR, de,
|
||||
&nvdla_dev->dbg_mask);
|
||||
debugfs_create_u32("en_trace", S_IRUGO|S_IWUSR, de,
|
||||
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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user