Skip to content

Commit

Permalink
coresight: reset "enable_sink" flag when need be
Browse files Browse the repository at this point in the history
When using coresight from the perf interface sinks are specified
as part of the perf command line.  As such the sink needs to be
disabled once it has been acknowledged by the coresight framework.
Otherwise the sink stays enabled, which may interfere with other
sessions.

This patch removes the sink selection check from the build path
process and make it a function on it's own.  The function is
then used when operating from sysFS or perf to determine what
sink has been selected.

If operated from perf the status of the "enable_sink" flag is
reset so that concurrent session can use a different sink.  When
used from sysFS the status of the flag is left untouched since
users have full control.

The implementation doesn't handle a scenario where a sink has
been enabled from sysFS and another sink is selected from the
perf command line as both modes of operation are mutually
exclusive.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
mathieupoirier authored and gregkh committed Nov 29, 2016
1 parent a39f841 commit d52c975
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 22 deletions.
31 changes: 16 additions & 15 deletions drivers/hwtracing/coresight/coresight-etm-perf.c
Expand Up @@ -202,6 +202,21 @@ static void *etm_setup_aux(int event_cpu, void **pages,
if (!event_data)
return NULL;

/*
* In theory nothing prevent tracers in a trace session from being
* associated with different sinks, nor having a sink per tracer. But
* until we have HW with this kind of topology we need to assume tracers
* in a trace session are using the same sink. Therefore go through
* the coresight bus and pick the first enabled sink.
*
* When operated from sysFS users are responsible to enable the sink
* while from perf, the perf tools will do it based on the choice made
* on the cmd line. As such the "enable_sink" flag in sysFS is reset.
*/
sink = coresight_get_enabled_sink(true);
if (!sink)
return NULL;

INIT_WORK(&event_data->work, free_event_data);

mask = &event_data->mask;
Expand All @@ -219,25 +234,11 @@ static void *etm_setup_aux(int event_cpu, void **pages,
* list of devices from source to sink that can be
* referenced later when the path is actually needed.
*/
event_data->path[cpu] = coresight_build_path(csdev);
event_data->path[cpu] = coresight_build_path(csdev, sink);
if (IS_ERR(event_data->path[cpu]))
goto err;
}

/*
* In theory nothing prevent tracers in a trace session from being
* associated with different sinks, nor having a sink per tracer. But
* until we have HW with this kind of topology and a way to convey
* sink assignement from the perf cmd line we need to assume tracers
* in a trace session are using the same sink. Therefore pick the sink
* found at the end of the first available path.
*/
cpu = cpumask_first(mask);
/* Grab the sink at the end of the path */
sink = coresight_get_sink(event_data->path[cpu]);
if (!sink)
goto err;

if (!sink_ops(sink)->alloc_buffer)
goto err;

Expand Down
4 changes: 3 additions & 1 deletion drivers/hwtracing/coresight/coresight-priv.h
Expand Up @@ -111,7 +111,9 @@ static inline void CS_UNLOCK(void __iomem *addr)
void coresight_disable_path(struct list_head *path);
int coresight_enable_path(struct list_head *path, u32 mode);
struct coresight_device *coresight_get_sink(struct list_head *path);
struct list_head *coresight_build_path(struct coresight_device *csdev);
struct coresight_device *coresight_get_enabled_sink(bool reset);
struct list_head *coresight_build_path(struct coresight_device *csdev,
struct coresight_device *sink);
void coresight_release_path(struct list_head *path);

#ifdef CONFIG_CORESIGHT_SOURCE_ETM3X
Expand Down
74 changes: 68 additions & 6 deletions drivers/hwtracing/coresight/coresight.c
Expand Up @@ -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.
Expand All @@ -380,22 +426,23 @@ 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;
bool found = false;
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;
}
Expand All @@ -422,18 +469,22 @@ static int _coresight_build_path(struct coresight_device *csdev,
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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down

0 comments on commit d52c975

Please sign in to comment.