From c5f22206b8246aad4a9df5c9ac2ca6ec0a8c282a Mon Sep 17 00:00:00 2001 From: Rama Aparna Mallavarapu Date: Thu, 2 Nov 2017 15:50:21 -0700 Subject: [PATCH 1/2] coresight-tmc: add support to configure flush and reset CTIs Add support to map/unmap TMC flush and reset CTIs as part of TMC enable/disable. Change-Id: Icfb55f4cfaa944de396514e4792f88bcfb7eb7b6 Signed-off-by: Satyajit Desai Signed-off-by: Rama Aparna Mallavarapu Signed-off-by: Mulu He Signed-off-by: Tingwei Zhang --- .../hwtracing/coresight/coresight-common.h | 8 +++- drivers/hwtracing/coresight/coresight-cti.c | 42 +++++++++++++++++++ .../hwtracing/coresight/coresight-tmc-etf.c | 8 ++++ .../hwtracing/coresight/coresight-tmc-etr.c | 5 +++ drivers/hwtracing/coresight/coresight-tmc.c | 18 ++++++++ drivers/hwtracing/coresight/coresight-tmc.h | 3 ++ 6 files changed, 83 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-common.h b/drivers/hwtracing/coresight/coresight-common.h index 99f427d2d302..3cd0c4e97543 100644 --- a/drivers/hwtracing/coresight/coresight-common.h +++ b/drivers/hwtracing/coresight/coresight-common.h @@ -44,5 +44,11 @@ static inline struct coresight_csr *coresight_csr_get(const char *name) static inline int of_get_coresight_csr_name(struct device_node *node, const char **csr_name){ return -EINVAL; } #endif - +#if IS_ENABLED(CONFIG_CORESIGHT_CTI) && IS_ENABLED(CONFIG_OF) +extern struct coresight_cti_data *of_get_coresight_cti_data( + struct device *dev, struct device_node *node); +#else +static inline struct coresight_cti_data *of_get_coresight_cti_data( + struct device *dev, struct device_node *node) { return NULL; } +#endif #endif diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index bb483063cc83..9ec2d152919f 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -1466,6 +1466,48 @@ static int cti_init_save(struct cti_drvdata *drvdata, return 0; } +struct coresight_cti_data *of_get_coresight_cti_data( + struct device *dev, struct device_node *node) +{ + int i, ret; + uint32_t ctis_len; + struct device_node *child_node; + struct coresight_cti_data *ctidata; + + ctidata = devm_kzalloc(dev, sizeof(*ctidata), GFP_KERNEL); + if (!ctidata) + return ERR_PTR(-ENOMEM); + + if (of_get_property(node, "coresight-ctis", &ctis_len)) + ctidata->nr_ctis = ctis_len/sizeof(uint32_t); + else + return ERR_PTR(-EINVAL); + + if (ctidata->nr_ctis) { + ctidata->names = devm_kzalloc(dev, ctidata->nr_ctis * + sizeof(*ctidata->names), + GFP_KERNEL); + if (!ctidata->names) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < ctidata->nr_ctis; i++) { + child_node = of_parse_phandle(node, "coresight-ctis", + i); + if (!child_node) + return ERR_PTR(-EINVAL); + + ret = of_property_read_string(child_node, + "coresight-name", + &ctidata->names[i]); + of_node_put(child_node); + if (ret) + return ERR_PTR(ret); + } + } + return ctidata; +} +EXPORT_SYMBOL(of_get_coresight_cti_data); + static int cti_probe(struct amba_device *adev, const struct amba_id *id) { int ret; diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index a7351f9f3659..160744fd97f4 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -217,6 +217,12 @@ out: if (!used) kfree(buf); + if (!ret) { + coresight_cti_map_trigin(drvdata->cti_reset, 0, 0); + coresight_cti_map_trigout(drvdata->cti_flush, 1, 0); + dev_info(&csdev->dev, "TMC-ETB/ETF enabled\n"); + } + return ret; } @@ -327,6 +333,8 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev) spin_unlock_irqrestore(&drvdata->spinlock, flags); + coresight_cti_unmap_trigin(drvdata->cti_reset, 0, 0); + coresight_cti_unmap_trigout(drvdata->cti_flush, 1, 0); dev_dbg(&csdev->dev, "TMC-ETB/ETF disabled\n"); return 0; } diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index d38d6de97808..895a0eced083 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1149,6 +1149,9 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) spin_lock_irqsave(&drvdata->spinlock, flags); } + coresight_cti_map_trigout(drvdata->cti_flush, 3, 0); + coresight_cti_map_trigin(drvdata->cti_reset, 2, 0); + if (drvdata->reading || drvdata->mode == CS_MODE_PERF) { ret = -EBUSY; goto out; @@ -1657,6 +1660,8 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) spin_unlock_irqrestore(&drvdata->spinlock, flags); tmc_etr_byte_cntr_stop(drvdata->byte_cntr); + coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0); + coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0); /* Free memory outside the spinlock if need be */ if (drvdata->etr_buf) { tmc_etr_free_sysfs_buf(drvdata->etr_buf); diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 47218065881f..bd6cf3801b24 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -493,6 +493,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) struct resource *res = &adev->res; struct coresight_desc desc = { 0 }; struct coresight_dev_list *dev_list = NULL; + struct coresight_cti_data *ctidata; ret = -ENOMEM; drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); @@ -534,6 +535,23 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) } } + ctidata = of_get_coresight_cti_data(dev, adev->dev.of_node); + if (IS_ERR(ctidata)) { + dev_err(dev, "invalid cti data\n"); + } else if (ctidata && ctidata->nr_ctis == 2) { + drvdata->cti_flush = coresight_cti_get(ctidata->names[0]); + if (IS_ERR(drvdata->cti_flush)) { + dev_err(dev, "failed to get flush cti, defer probe\n"); + return -EPROBE_DEFER; + } + + drvdata->cti_reset = coresight_cti_get(ctidata->names[1]); + if (IS_ERR(drvdata->cti_reset)) { + dev_err(dev, "failed to get reset cti, defer probe\n"); + return -EPROBE_DEFER; + } + } + desc.dev = dev; desc.groups = coresight_tmc_groups; diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 4ea270c7743b..bd99cb6c016d 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "coresight-byte-cntr.h" @@ -213,6 +214,8 @@ struct tmc_drvdata { const char *csr_name; bool enable; struct byte_cntr *byte_cntr; + struct coresight_cti *cti_flush; + struct coresight_cti *cti_reset; }; struct etr_buf_operations { From a8928b2c6dc64a41941a4d776d30db8f4fff7cfd Mon Sep 17 00:00:00 2001 From: Satyajit Desai Date: Thu, 1 Jun 2017 18:41:33 -0700 Subject: [PATCH 2/2] coresight-tmc: Re-use ETR buffer across use cases We can run into use after free scenario for the buffer memory if enable and read operations happen simultaneously. Add mutex protection in order to prevent such a scenario. Change-Id: I3106564a46a9cffc0db8808ba03f78d76c925eca Signed-off-by: Satyajit Desai Signed-off-by: Rama Aparna Mallavarapu Signed-off-by: Mulu He Signed-off-by: Tingwei Zhang --- drivers/hwtracing/coresight/coresight-tmc-etr.c | 16 +++++++++++++--- drivers/hwtracing/coresight/coresight-tmc.c | 8 +++++++- drivers/hwtracing/coresight/coresight-tmc.h | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 895a0eced083..a1f2e64171ed 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1135,6 +1135,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) * buffer, provided the size matches. Any allocation has to be done * with the lock released. */ + mutex_lock(&drvdata->mem_lock); spin_lock_irqsave(&drvdata->spinlock, flags); sysfs_buf = READ_ONCE(drvdata->sysfs_buf); if (!sysfs_buf || (sysfs_buf->size != drvdata->size)) { @@ -1142,9 +1143,10 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) /* Allocate memory with the locks released */ free_buf = new_buf = tmc_etr_setup_sysfs_buf(drvdata); - if (IS_ERR(new_buf)) + if (IS_ERR(new_buf)) { + mutex_unlock(&drvdata->mem_lock); return PTR_ERR(new_buf); - + } /* Let's try again */ spin_lock_irqsave(&drvdata->spinlock, flags); } @@ -1191,6 +1193,7 @@ out: tmc_etr_free_sysfs_buf(free_buf); tmc_etr_byte_cntr_start(drvdata->byte_cntr); + mutex_unlock(&drvdata->mem_lock); if (!ret) dev_dbg(&csdev->dev, "TMC-ETR enabled\n"); @@ -1636,10 +1639,12 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) unsigned long flags; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + mutex_lock(&drvdata->mem_lock); spin_lock_irqsave(&drvdata->spinlock, flags); if (drvdata->reading) { spin_unlock_irqrestore(&drvdata->spinlock, flags); + mutex_unlock(&drvdata->mem_lock); return -EBUSY; } @@ -1667,6 +1672,7 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) tmc_etr_free_sysfs_buf(drvdata->etr_buf); drvdata->etr_buf = NULL; } + mutex_unlock(&drvdata->mem_lock); dev_info(&csdev->dev, "TMC-ETR disabled\n"); return 0; } @@ -1692,6 +1698,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR)) return -EINVAL; + mutex_lock(&drvdata->mem_lock); spin_lock_irqsave(&drvdata->spinlock, flags); if (drvdata->reading) { ret = -EBUSY; @@ -1720,6 +1727,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) drvdata->reading = true; out: spin_unlock_irqrestore(&drvdata->spinlock, flags); + mutex_unlock(&drvdata->mem_lock); return ret; } @@ -1732,7 +1740,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) /* config types are set a boot time and never change */ if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR)) return -EINVAL; - + mutex_lock(&drvdata->mem_lock); spin_lock_irqsave(&drvdata->spinlock, flags); /* RE-enable the TMC if need be */ @@ -1759,5 +1767,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) if (sysfs_buf) tmc_etr_free_sysfs_buf(sysfs_buf); + + mutex_unlock(&drvdata->mem_lock); return 0; } diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index bd6cf3801b24..d7b5fcf88d60 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -184,19 +184,24 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, ssize_t actual; struct tmc_drvdata *drvdata = container_of(file->private_data, struct tmc_drvdata, miscdev); + mutex_lock(&drvdata->mem_lock); actual = tmc_get_sysfs_trace(drvdata, *ppos, len, &bufp); - if (actual <= 0) + if (actual <= 0) { + mutex_unlock(&drvdata->mem_lock); return 0; + } if (copy_to_user(data, bufp, actual)) { dev_dbg(&drvdata->csdev->dev, "%s: copy_to_user failed\n", __func__); + mutex_unlock(&drvdata->mem_lock); return -EFAULT; } *ppos += actual; dev_dbg(&drvdata->csdev->dev, "%zu bytes copied\n", actual); + mutex_unlock(&drvdata->mem_lock); return actual; } @@ -512,6 +517,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); diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index bd99cb6c016d..25298c5b6e3d 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -204,6 +204,7 @@ struct tmc_drvdata { u32 mode; enum tmc_config_type config_type; enum tmc_mem_intf_width memwidth; + struct mutex mem_lock; u32 trigger_cntr; u32 etr_caps; struct idr idr;