The CoreSight subsystem enables a path of devices from source to sink. Any CTI devices associated with the path devices must be enabled at the same time.
This patch adds an associated device element to the main coresight device structure, and uses this to create associations between the CTI and other devices based on the device tree data. The assoc dev element is used to enable CTI in conjunction with the path elements. CTI are reference counted so where a single CTI is associated with multiple elements on the path, it will be enabled on the first associated device enable, and disabled with the last associated device disable.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../coresight/coresight-cti-platform.c | 22 +++++ drivers/hwtracing/coresight/coresight-cti.c | 90 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 1 + drivers/hwtracing/coresight/coresight-priv.h | 3 + drivers/hwtracing/coresight/coresight.c | 56 ++++++++++-- include/linux/coresight.h | 4 + 6 files changed, 171 insertions(+), 5 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c index 806941e1011e..215e9f2f6d48 100644 --- a/drivers/hwtracing/coresight/coresight-cti-platform.c +++ b/drivers/hwtracing/coresight/coresight-cti-platform.c @@ -443,6 +443,12 @@ int of_get_coresight_cti_platform_data(struct device *dev,
return ret; } + +inline const char *of_cti_get_node_name(struct device *dev) +{ + return dev->of_node->full_name; +} + #else inline int of_get_coresight_cti_platform_data(struct device *dev, @@ -451,6 +457,11 @@ of_get_coresight_cti_platform_data(struct device *dev, return -ENOENT; }
+inline const char *of_get_node_name(struct device *dev) +{ + return NULL; +} + #endif
struct coresight_platform_data * @@ -477,3 +488,14 @@ coresight_cti_get_platform_data(struct device *dev) error: return ERR_PTR(ret); } + +const char *coresight_cti_get_node_name(struct device *dev) +{ + const char *node_name = NULL; + struct fwnode_handle *fwnode = dev_fwnode(dev); + + if (is_of_node(fwnode)) + node_name = of_cti_get_node_name(dev); + + return node_name; +} diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index a4e349984ab8..6fb924f70af2 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -471,6 +471,93 @@ int cti_channel_setop(struct device *dev, return err; }
+/* + * Look for a matching connection device name in the list of + * connections. If found then swap in the csdev name and return + * found. + */ +static int +cti_match_con_name(struct cti_device *ctidev, const char *node_name, + const char *csdev_name) +{ + int found = 0; + struct cti_trig_con *trig_con; + + list_for_each_entry(trig_con, &ctidev->trig_cons, node) { + if (trig_con->con_dev_name) { + if (!strcmp(node_name, trig_con->con_dev_name)) { + found = 1; + /* match: so swap in csdev name */ + kfree(trig_con->con_dev_name); + trig_con->con_dev_name = + kstrdup(csdev_name, GFP_KERNEL); + goto cti_con_name_match; + } + } + } +cti_con_name_match: + return found; +} + +/* + * Search the cti list to add an associated CTI into the supplied CS device + * This will set the association if CTI declared before the CS device + */ +void cti_add_assoc_to_csdev(struct coresight_device *csdev) +{ + struct ect_node *ect_item; + struct cti_device *ctidev; + const char *node_name = NULL, *csdev_name; + + /* protect the list */ + mutex_lock(&ect_mutex); + + /* exit if current is an ECT device.*/ + if ((csdev->type == CORESIGHT_DEV_TYPE_ECT) || list_empty(&ect_net)) + goto cti_add_done; + + /* if we didn't find the csdev previously we used the fwnode name */ + node_name = coresight_cti_get_node_name(csdev->dev.parent); + + if (!node_name) + goto cti_add_done; + + /* this is the name we want to use for the association */ + csdev_name = dev_name(&csdev->dev); + + /* for each CTI in list... */ + list_for_each_entry(ect_item, &ect_net, next) { + ctidev = &ect_item->cti_drv->ctidev; + if (cti_match_con_name(ctidev, node_name, csdev_name)) { + /* + * if we found a matching name then update the + * association pointers. + */ + csdev->ect_dev = ect_item->cti_drv->csdev; + goto cti_add_done; + } + } +cti_add_done: + mutex_unlock(&ect_mutex); +} +EXPORT_SYMBOL_GPL(cti_add_assoc_to_csdev); + +/* + * Update the cross references where the associated device was found + * while we were building the connection info. This will occur if the + * assoc device was registered before the CTI. + */ +static void cti_update_conn_xrefs(struct cti_drvdata *drvdata) +{ + struct cti_trig_con *tc; + struct cti_device *ctidev = &drvdata->ctidev; + + list_for_each_entry(tc, &ctidev->trig_cons, node) { + if (tc->con_dev) + tc->con_dev->ect_dev = drvdata->csdev; + } +} + /** cti ect operations **/ int cti_enable(struct coresight_device *csdev, void *__unused) { @@ -587,6 +674,9 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) list_add(&ect_nd->next, &ect_net); mutex_unlock(&ect_mutex);
+ /* set any cross references */ + cti_update_conn_xrefs(drvdata); + /* all done - dec pm refcount */ pm_runtime_put(&adev->dev); if (drvdata->ctidev.cpu >= 0) { diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index b87cc67543e0..ab1be67eb704 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -250,6 +250,7 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); +const char *coresight_cti_get_node_name(struct device *dev);
/* cti powered and enabled */ #define CTI_PWR_ENA(p_cfg) (p_cfg->hw_enabled && p_cfg->hw_powered) diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 64a888cc620f..9c4fd7eb56eb 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -164,8 +164,11 @@ static inline int etm_writel_cp14(u32 off, u32 val) { return 0; }
#ifdef CONFIG_CORESIGHT_CTI extern void cti_device_release(struct device *dev); +extern void cti_add_assoc_to_csdev(struct coresight_device *csdev); #else static inline void cti_device_release(struct device *dev) {}; +static inline int cti_add_assoc_to_csdev(struct coresight_device *csdev) +{ return 0; } #endif
/* diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 1c9ba2fd6879..74661fabe098 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -216,6 +216,31 @@ void coresight_disclaim_device(void __iomem *base) CS_LOCK(base); }
+/* enable or disable an associated CTI device of the supplied CS device */ +static int +coresight_control_assoc_ectdev(struct coresight_device *csdev, int enable) +{ + int ect_ret = 0; + struct coresight_device *ect_csdev = csdev->ect_dev; + + if (!ect_csdev) + return 0; + + if (enable) { + if (ect_ops(ect_csdev)->enable) + ect_ret = ect_ops(ect_csdev)->enable(ect_csdev, NULL); + } else { + if (ect_ops(ect_csdev)->disable) + ect_ret = ect_ops(ect_csdev)->disable(ect_csdev, NULL); + } + + /* output warning if ECT enable is preventing trace operation */ + if (ect_ret) + dev_info(&csdev->dev, "Associated ECT device (%s) %s failed\n", + dev_name(&ect_csdev->dev), enable ? "enable" : "disable"); + return ect_ret; +} + static int coresight_enable_sink(struct coresight_device *csdev, u32 mode, void *data) { @@ -228,11 +253,15 @@ static int coresight_enable_sink(struct coresight_device *csdev, if (!sink_ops(csdev)->enable) return -EINVAL;
- ret = sink_ops(csdev)->enable(csdev, mode, data); + ret = coresight_control_assoc_ectdev(csdev, 1); if (ret) return ret; + ret = sink_ops(csdev)->enable(csdev, mode, data); + if (ret) { + coresight_control_assoc_ectdev(csdev, 0); + return ret; + } csdev->enable = true; - return 0; }
@@ -246,6 +275,7 @@ static void coresight_disable_sink(struct coresight_device *csdev) ret = sink_ops(csdev)->disable(csdev); if (ret) return; + coresight_control_assoc_ectdev(csdev, 0); csdev->enable = false; }
@@ -276,7 +306,14 @@ static int coresight_enable_link(struct coresight_device *csdev,
if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (link_ops(csdev)->enable) { - ret = link_ops(csdev)->enable(csdev, inport, outport); + ret = coresight_control_assoc_ectdev(csdev, 1); + if (!ret) { + ret = link_ops(csdev)->enable(csdev, inport, + outport); + if (ret) + coresight_control_assoc_ectdev(csdev, + 0); + } if (ret) { atomic_dec(&csdev->refcnt[refport]); return ret; @@ -316,8 +353,10 @@ static void coresight_disable_link(struct coresight_device *csdev, }
if (atomic_dec_return(&csdev->refcnt[refport]) == 0) { - if (link_ops(csdev)->disable) + if (link_ops(csdev)->disable) { link_ops(csdev)->disable(csdev, inport, outport); + coresight_control_assoc_ectdev(csdev, 0); + } }
for (i = 0; i < nr_conns; i++) @@ -339,9 +378,14 @@ static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
if (!csdev->enable) { if (source_ops(csdev)->enable) { - ret = source_ops(csdev)->enable(csdev, NULL, mode); + ret = coresight_control_assoc_ectdev(csdev, 1); if (ret) return ret; + ret = source_ops(csdev)->enable(csdev, NULL, mode); + if (ret) { + coresight_control_assoc_ectdev(csdev, 0); + return ret; + }; } csdev->enable = true; } @@ -364,6 +408,7 @@ static bool coresight_disable_source(struct coresight_device *csdev) if (atomic_dec_return(csdev->refcnt) == 0) { if (source_ops(csdev)->disable) source_ops(csdev)->disable(csdev, NULL); + coresight_control_assoc_ectdev(csdev, 0); csdev->enable = false; } return !csdev->enable; @@ -1277,6 +1322,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
coresight_fixup_device_conns(csdev); coresight_fixup_orphan_conns(csdev); + cti_add_assoc_to_csdev(csdev);
mutex_unlock(&coresight_mutex);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 0a2a69b5ade8..936dc138dbbb 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -163,6 +163,8 @@ struct coresight_connection { * activated but not yet enabled. Enabling for a _sink_ * appens when a source has been selected for that it. * @ea: Device attribute for sink representation under PMU directory. + * @ect_dev: Associated cross trigger device. Not part of the trace data + * path or connections. */ struct coresight_device { struct coresight_platform_data *pdata; @@ -176,6 +178,8 @@ struct coresight_device { /* sink specific fields */ bool activated; /* true only if a sink is part of a path */ struct dev_ext_attribute *ea; + /* cross trigger handling */ + struct coresight_device *ect_dev; };
/*