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..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,13 +1143,17 @@ 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); } + 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; @@ -1188,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"); @@ -1633,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; } @@ -1657,11 +1665,14 @@ 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); drvdata->etr_buf = NULL; } + mutex_unlock(&drvdata->mem_lock); dev_info(&csdev->dev, "TMC-ETR disabled\n"); return 0; } @@ -1687,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; @@ -1715,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; } @@ -1727,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 */ @@ -1754,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 47218065881f..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; } @@ -493,6 +498,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); @@ -511,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); @@ -534,6 +541,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..25298c5b6e3d 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" @@ -203,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; @@ -213,6 +215,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 {