summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.c125
1 files changed, 101 insertions, 24 deletions
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index a57c7ec1661f..d4ea26a7efc3 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -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;
}