|
@@ -368,6 +368,52 @@ struct coresight_device *coresight_get_sink(struct list_head *path)
|
|
|
return csdev;
|
|
|
}
|
|
|
|
|
|
+static int coresight_enabled_sink(struct device *dev, void *data)
|
|
|
+{
|
|
|
+ bool *reset = data;
|
|
|
+ struct coresight_device *csdev = to_coresight_device(dev);
|
|
|
+
|
|
|
+ if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
|
|
|
+ csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
|
|
|
+ csdev->activated) {
|
|
|
+ /*
|
|
|
+ * Now that we have a handle on the sink for this session,
|
|
|
+ * disable the sysFS "enable_sink" flag so that possible
|
|
|
+ * concurrent perf session that wish to use another sink don't
|
|
|
+ * trip on it. Doing so has no ramification for the current
|
|
|
+ * session.
|
|
|
+ */
|
|
|
+ if (*reset)
|
|
|
+ csdev->activated = false;
|
|
|
+
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * coresight_get_enabled_sink - returns the first enabled sink found on the bus
|
|
|
+ * @deactivate: Whether the 'enable_sink' flag should be reset
|
|
|
+ *
|
|
|
+ * When operated from perf the deactivate parameter should be set to 'true'.
|
|
|
+ * That way the "enabled_sink" flag of the sink that was selected can be reset,
|
|
|
+ * allowing for other concurrent perf sessions to choose a different sink.
|
|
|
+ *
|
|
|
+ * When operated from sysFS users have full control and as such the deactivate
|
|
|
+ * parameter should be set to 'false', hence mandating users to explicitly
|
|
|
+ * clear the flag.
|
|
|
+ */
|
|
|
+struct coresight_device *coresight_get_enabled_sink(bool deactivate)
|
|
|
+{
|
|
|
+ struct device *dev = NULL;
|
|
|
+
|
|
|
+ dev = bus_find_device(&coresight_bustype, NULL, &deactivate,
|
|
|
+ coresight_enabled_sink);
|
|
|
+
|
|
|
+ return dev ? to_coresight_device(dev) : NULL;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* _coresight_build_path - recursively build a path from a @csdev to a sink.
|
|
|
* @csdev: The device to start from.
|
|
@@ -380,6 +426,7 @@ struct coresight_device *coresight_get_sink(struct list_head *path)
|
|
|
* last one.
|
|
|
*/
|
|
|
static int _coresight_build_path(struct coresight_device *csdev,
|
|
|
+ struct coresight_device *sink,
|
|
|
struct list_head *path)
|
|
|
{
|
|
|
int i;
|
|
@@ -387,15 +434,15 @@ static int _coresight_build_path(struct coresight_device *csdev,
|
|
|
struct coresight_node *node;
|
|
|
|
|
|
/* An activated sink has been found. Enqueue the element */
|
|
|
- if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
|
|
|
- csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && csdev->activated)
|
|
|
+ if (csdev == sink)
|
|
|
goto out;
|
|
|
|
|
|
/* Not a sink - recursively explore each port found on this element */
|
|
|
for (i = 0; i < csdev->nr_outport; i++) {
|
|
|
struct coresight_device *child_dev = csdev->conns[i].child_dev;
|
|
|
|
|
|
- if (child_dev && _coresight_build_path(child_dev, path) == 0) {
|
|
|
+ if (child_dev &&
|
|
|
+ _coresight_build_path(child_dev, sink, path) == 0) {
|
|
|
found = true;
|
|
|
break;
|
|
|
}
|
|
@@ -422,18 +469,22 @@ out:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-struct list_head *coresight_build_path(struct coresight_device *csdev)
|
|
|
+struct list_head *coresight_build_path(struct coresight_device *source,
|
|
|
+ struct coresight_device *sink)
|
|
|
{
|
|
|
struct list_head *path;
|
|
|
int rc;
|
|
|
|
|
|
+ if (!sink)
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
+
|
|
|
path = kzalloc(sizeof(struct list_head), GFP_KERNEL);
|
|
|
if (!path)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
INIT_LIST_HEAD(path);
|
|
|
|
|
|
- rc = _coresight_build_path(csdev, path);
|
|
|
+ rc = _coresight_build_path(source, sink, path);
|
|
|
if (rc) {
|
|
|
kfree(path);
|
|
|
return ERR_PTR(rc);
|
|
@@ -497,6 +548,7 @@ static int coresight_validate_source(struct coresight_device *csdev,
|
|
|
int coresight_enable(struct coresight_device *csdev)
|
|
|
{
|
|
|
int cpu, ret = 0;
|
|
|
+ struct coresight_device *sink;
|
|
|
struct list_head *path;
|
|
|
|
|
|
mutex_lock(&coresight_mutex);
|
|
@@ -508,7 +560,17 @@ int coresight_enable(struct coresight_device *csdev)
|
|
|
if (csdev->enable)
|
|
|
goto out;
|
|
|
|
|
|
- path = coresight_build_path(csdev);
|
|
|
+ /*
|
|
|
+ * Search for a valid sink for this session but don't reset the
|
|
|
+ * "enable_sink" flag in sysFS. Users get to do that explicitly.
|
|
|
+ */
|
|
|
+ sink = coresight_get_enabled_sink(false);
|
|
|
+ if (!sink) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ path = coresight_build_path(csdev, sink);
|
|
|
if (IS_ERR(path)) {
|
|
|
pr_err("building path(s) failed\n");
|
|
|
ret = PTR_ERR(path);
|