coresight: tmc: add support to configure etr mem size

Add support to expose a node for user to configure memory buffer size
for an ETR device.

Change-Id: Ide175ca8eeb5b9c2d7213dfff4c81b5314ce61f6
Signed-off-by: Shashank Mittal <mittals@codeaurora.org>
This commit is contained in:
Shashank Mittal 2016-01-04 10:00:07 -08:00 committed by David Keitel
parent 2548d68098
commit babde2831d

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012, 2016 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -126,6 +126,8 @@ struct tmc_drvdata {
dma_addr_t paddr;
void __iomem *vaddr;
u32 size;
struct mutex mem_lock;
u32 mem_size;
bool enable;
enum tmc_config_type config_type;
u32 trigger_cntr;
@ -191,6 +193,41 @@ static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
CS_LOCK(drvdata->base);
}
static int tmc_etr_alloc_mem(struct tmc_drvdata *drvdata)
{
int ret;
if (!drvdata->vaddr) {
drvdata->vaddr = dma_zalloc_coherent(drvdata->dev,
drvdata->size,
&drvdata->paddr,
GFP_KERNEL);
if (!drvdata->vaddr) {
ret = -ENOMEM;
goto err;
}
}
/*
* Need to reinitialize buf for each tmc enable session since it is
* getting modified during tmc etr dump.
*/
drvdata->buf = drvdata->vaddr;
return 0;
err:
dev_err(drvdata->dev, "etr ddr memory allocation failed\n");
return ret;
}
static void tmc_etr_free_mem(struct tmc_drvdata *drvdata)
{
if (drvdata->vaddr) {
dma_free_coherent(drvdata->dev, drvdata->size,
drvdata->vaddr, drvdata->paddr);
drvdata->vaddr = 0;
drvdata->paddr = 0;
}
}
static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
{
u32 axictl;
@ -240,10 +277,34 @@ static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
{
int ret;
unsigned long flags;
pm_runtime_get_sync(drvdata->dev);
mutex_lock(&drvdata->mem_lock);
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
/*
* ETR DDR memory is not allocated until user enables
* tmc at least once. If user specifies different ETR
* DDR size than the default size or switches between
* contiguous or scatter-gather memory type after
* enabling tmc; the new selection will be honored from
* next tmc enable session.
*/
if (drvdata->size != drvdata->mem_size) {
tmc_etr_free_mem(drvdata);
drvdata->size = drvdata->mem_size;
}
ret = tmc_etr_alloc_mem(drvdata);
if (ret) {
pm_runtime_put(drvdata->dev);
mutex_unlock(&drvdata->mem_lock);
return ret;
}
}
mutex_unlock(&drvdata->mem_lock);
spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@ -634,6 +695,35 @@ static ssize_t trigger_cntr_store(struct device *dev,
}
static DEVICE_ATTR_RW(trigger_cntr);
static ssize_t mem_size_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val = drvdata->mem_size;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static ssize_t mem_size_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
mutex_lock(&drvdata->mem_lock);
if (kstrtoul(buf, 16, &val) != 1) {
return -EINVAL;
mutex_unlock(&drvdata->mem_lock);
}
drvdata->mem_size = val;
mutex_unlock(&drvdata->mem_lock);
return size;
}
static DEVICE_ATTR_RW(mem_size);
static struct attribute *coresight_etb_attrs[] = {
&dev_attr_trigger_cntr.attr,
&dev_attr_status.attr,
@ -642,6 +732,7 @@ static struct attribute *coresight_etb_attrs[] = {
ATTRIBUTE_GROUPS(coresight_etb);
static struct attribute *coresight_etr_attrs[] = {
&dev_attr_mem_size.attr,
&dev_attr_trigger_cntr.attr,
&dev_attr_status.attr,
NULL,
@ -689,6 +780,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
drvdata->base = base;
spin_lock_init(&drvdata->spinlock);
mutex_init(&drvdata->mem_lock);
devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
drvdata->config_type = BMVAL(devid, 6, 7);
@ -700,31 +792,23 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
&drvdata->size);
if (ret)
drvdata->size = SZ_1M;
drvdata->mem_size = drvdata->size;
} else {
drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
}
pm_runtime_put(&adev->dev);
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
drvdata->vaddr = dma_alloc_coherent(dev, drvdata->size,
&drvdata->paddr, GFP_KERNEL);
if (!drvdata->vaddr)
return -ENOMEM;
memset(drvdata->vaddr, 0, drvdata->size);
drvdata->buf = drvdata->vaddr;
} else {
if (drvdata->config_type != TMC_CONFIG_TYPE_ETR) {
drvdata->buf = devm_kzalloc(dev, drvdata->size, GFP_KERNEL);
if (!drvdata->buf)
return -ENOMEM;
}
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc) {
ret = -ENOMEM;
goto err_devm_kzalloc;
}
if (!desc)
return -ENOMEM;
desc->pdata = pdata;
desc->dev = dev;
@ -746,10 +830,8 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
}
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
goto err_devm_kzalloc;
}
if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
drvdata->miscdev.name = pdata->name;
drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
@ -763,10 +845,6 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
err_misc_register:
coresight_unregister(drvdata->csdev);
err_devm_kzalloc:
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
dma_free_coherent(dev, drvdata->size,
&drvdata->paddr, GFP_KERNEL);
return ret;
}
@ -777,8 +855,7 @@ static int tmc_remove(struct amba_device *adev)
misc_deregister(&drvdata->miscdev);
coresight_unregister(drvdata->csdev);
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
dma_free_coherent(drvdata->dev, drvdata->size,
&drvdata->paddr, GFP_KERNEL);
tmc_etr_free_mem(drvdata);
return 0;
}