/*
* Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#define _BullseyeCoverage 1
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define COV_MEM_SZ (24U*1024U) /* 24K */
/*
* Private driver data structure
*/
struct tegra_rtcpu_coverage {
struct device *dev;
/* memory */
void *coverage_memory;
u32 coverage_memory_size;
dma_addr_t dma_handle;
struct dentry *debugfs_root;
};
/*
* Coverage memory
*/
static int rtcpu_coverage_setup_memory(struct tegra_rtcpu_coverage *coverage)
{
struct device *dev = coverage->dev;
void *coverage_memory = NULL;
size_t mem_size;
dma_addr_t dma_addr = 0;
coverage->dma_handle = 0;
mem_size = COV_MEM_SZ;
coverage_memory = dma_alloc_coherent(dev, mem_size, &dma_addr,
GFP_KERNEL | __GFP_ZERO);
if (coverage_memory == NULL) {
dev_err(dev, "rtcpu_coverage_setup_memory ERROR\r\n");
return -ENOMEM;
}
/* Save the information */
coverage->coverage_memory = coverage_memory;
coverage->coverage_memory_size = mem_size;
coverage->dma_handle = dma_addr;
return 0;
}
static void rtcpu_coverage_init_memory(struct tegra_rtcpu_coverage *coverage)
{
struct camrtc_coverage_memory_header *header =
(struct camrtc_coverage_memory_header *)
coverage->coverage_memory;
/* header */
header->revision = 1;
header->coverage_buffer_size = coverage->coverage_memory_size;
header->coverage_total_bytes = 0;
header->length = sizeof(struct camrtc_coverage_memory_header);
/* validate */
header->signature = CAMRTC_TAG_NV_COVERAGE;
}
/*
* Debugfs
*/
#define DEFINE_SEQ_FOPS(_fops_, _show_) \
static int _fops_ ## _open(struct inode *inode, struct file *file) \
{ \
return single_open(file, _show_, inode->i_private); \
} \
static const struct file_operations _fops_ = { \
.open = _fops_ ## _open, \
.read = seq_read, \
.llseek = seq_lseek, \
.release = single_release }
static int rtcpu_coverage_debugfs_gcov_read(
struct seq_file *file, void *data)
{
struct tegra_rtcpu_coverage *coverage = file->private;
struct camrtc_coverage_memory_header *cov_header;
u8 *cov_data;
int i = 0;
cov_header = (struct camrtc_coverage_memory_header *)
(coverage->coverage_memory);
cov_data = (u8 *)coverage->coverage_memory +
sizeof(struct camrtc_coverage_memory_header);
/* RTCPU will tell us how many bytes to read */
for (i = 0; i < cov_header->coverage_total_bytes; i++)
seq_putc(file, cov_data[i]);
return 0;
}
DEFINE_SEQ_FOPS(rtcpu_coverage_debugfs_gcov, rtcpu_coverage_debugfs_gcov_read);
static void rtcpu_coverage_debugfs_deinit(struct tegra_rtcpu_coverage *coverage)
{
debugfs_remove_recursive(coverage->debugfs_root);
}
static int rtcpu_coverage_debugfs_init(struct tegra_rtcpu_coverage *coverage)
{
struct dentry *entry;
int err = 0;
coverage->debugfs_root = debugfs_create_dir("tegra_rtcpu_coverage",
NULL);
if (IS_ERR_OR_NULL(coverage->debugfs_root)) {
if (IS_ERR(coverage->debugfs_root))
err = PTR_ERR(coverage->debugfs_root);
else
err = -ENODEV;
return err;
}
entry = debugfs_create_file("cov_data", S_IRUGO,
coverage->debugfs_root, coverage, &rtcpu_coverage_debugfs_gcov);
if (IS_ERR_OR_NULL(entry)) {
if (IS_ERR(entry))
err = PTR_ERR(entry);
else
err = -ENODEV;
debugfs_remove_recursive(coverage->debugfs_root);
return err;
}
return err;
}
/*
* Init/Cleanup
* Cleanup first so init can call it in the event of an error.
*/
void tegra_rtcpu_coverage_destroy(struct tegra_rtcpu_coverage *coverage)
{
if (IS_ERR_OR_NULL(coverage))
return;
rtcpu_coverage_debugfs_deinit(coverage);
dma_free_coherent(coverage->dev, coverage->coverage_memory_size,
coverage->coverage_memory, coverage->dma_handle);
kfree(coverage);
}
EXPORT_SYMBOL(tegra_rtcpu_coverage_destroy);
struct tegra_rtcpu_coverage *tegra_rtcpu_coverage_create(struct device *dev)
{
struct tegra_rtcpu_coverage *coverage;
int ret;
coverage = kzalloc(sizeof(*coverage), GFP_KERNEL);
if (unlikely(coverage == NULL))
return NULL;
coverage->dev = dev;
/* Get the coverage memory */
ret = rtcpu_coverage_setup_memory(coverage);
if (ret < 0) {
dev_err(dev, "Coverage memory setup failed: %d\n", ret);
kfree(coverage);
return NULL;
}
/* Initialize the coverage memory */
rtcpu_coverage_init_memory(coverage);
/* Debugfs */
ret = rtcpu_coverage_debugfs_init(coverage);
if (ret < 0) {
tegra_rtcpu_coverage_destroy(coverage);
return NULL;
}
dev_dbg(dev, "Coverage buffer configured at IOVA=0x%08x\n",
(u32)coverage->dma_handle);
return coverage;
}
EXPORT_SYMBOL(tegra_rtcpu_coverage_create);
int tegra_rtcpu_coverage_boot_sync(struct tegra_rtcpu_coverage *coverage)
{
int ret = tegra_camrtc_iovm_setup(coverage->dev,
coverage->dma_handle);
if (ret == 0)
return 0;
dev_dbg(coverage->dev, "RTCPU coverage: IOVM setup error: %d\n", ret);
dev_dbg(coverage->dev,
"(expected if RTCPU was not built with coverage enabled)\n");
return -EIO;
}
EXPORT_SYMBOL(tegra_rtcpu_coverage_boot_sync);
MODULE_DESCRIPTION("NVIDIA Tegra RTCPU coverage driver");
MODULE_LICENSE("GPL v2");