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:
Amit Sharma (SW-Tegra)
2016-11-08 18:53:05 +05:30
committed by Laxman Dewangan
parent bc8bf342a7
commit b79f6e271a
4 changed files with 208 additions and 19 deletions

View File

@@ -157,6 +157,7 @@ struct dla_action_semaphore {
enum dla_regions_e {
DLA_REGION_PRINTF = 1,
DLA_REGION_GOS = 2,
DLA_REGION_TRACE = 3,
};
/**

View File

@@ -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;

View File

@@ -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;

View File

@@ -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");
}