2018-05-10 02:06:04 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2012, The Linux Foundation. All rights reserved.
|
2014-11-04 02:07:35 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/device.h>
|
|
|
|
#include <linux/io.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
#include <linux/export.h>
|
|
|
|
#include <linux/slab.h>
|
2019-02-01 02:47:10 +08:00
|
|
|
#include <linux/stringhash.h>
|
2014-11-04 02:07:35 +08:00
|
|
|
#include <linux/mutex.h>
|
|
|
|
#include <linux/clk.h>
|
|
|
|
#include <linux/coresight.h>
|
|
|
|
#include <linux/of_platform.h>
|
|
|
|
#include <linux/delay.h>
|
2016-02-18 08:51:47 +08:00
|
|
|
#include <linux/pm_runtime.h>
|
2014-11-04 02:07:35 +08:00
|
|
|
|
coresight: perf: Add "sinks" group to PMU directory
Add a "sinks" directory entry so that users can see all the sinks
available in the system in a single place. Individual sink are added
as they are registered with the coresight bus.
Committer tests:
Test built on a ubuntu 18.04 container with a cross build environment to
arm64, the new field is there, need to find a machine with this feature
to do further testing in the future.
root@d15263e5734a:/git/perf# grep CORESIGHT /tmp/build/v5.0-rc2+/.config
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_LINKS_AND_SINKS=y
CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
CONFIG_CORESIGHT_CATU=y
CONFIG_CORESIGHT_SINK_TPIU=y
CONFIG_CORESIGHT_SINK_ETBV10=y
CONFIG_CORESIGHT_SOURCE_ETM4X=y
CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
CONFIG_CORESIGHT_CPU_DEBUG=m
root@d15263e5734a:/git/perf#
root@d15263e5734a:/git/perf# file /tmp/build/v5.0-rc2+/drivers/hwtracing/coresight/*.o
.../coresight/coresight-catu.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-cpu-debug.mod.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-cpu-debug.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-dynamic-replicator.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-etb10.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-etm-perf.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-etm4x-sysfs.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-etm4x.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-funnel.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-replicator.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-stm.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-tmc-etf.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-tmc-etr.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-tmc.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-tpiu.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/of_coresight.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
root@d15263e5734a:/git/perf#
root@d15263e5734a:/git/perf# pahole -C coresight_device /tmp/build/v5.0-rc2+/drivers/hwtracing/coresight/coresight.o
struct coresight_device {
struct coresight_connection * conns; /* 0 8 */
int nr_inport; /* 8 4 */
int nr_outport; /* 12 4 */
enum coresight_dev_type type; /* 16 4 */
union coresight_dev_subtype subtype; /* 20 8 */
/* XXX 4 bytes hole, try to pack */
const struct coresight_ops * ops; /* 32 8 */
struct device dev; /* 40 1408 */
/* XXX last struct has 7 bytes of padding */
/* --- cacheline 22 boundary (1408 bytes) was 40 bytes ago --- */
atomic_t * refcnt; /* 1448 8 */
bool orphan; /* 1456 1 */
bool enable; /* 1457 1 */
bool activated; /* 1458 1 */
/* XXX 5 bytes hole, try to pack */
struct dev_ext_attribute * ea; /* 1464 8 */
/* size: 1472, cachelines: 23, members: 12 */
/* sum members: 1463, holes: 2, sum holes: 9 */
/* paddings: 1, sum paddings: 7 */
};
root@d15263e5734a:/git/perf#
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will.deacon@arm.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-s390@vger.kernel.org
Link: http://lkml.kernel.org/r/20190131184714.20388-3-mathieu.poirier@linaro.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-01 02:47:09 +08:00
|
|
|
#include "coresight-etm-perf.h"
|
2014-11-04 02:07:35 +08:00
|
|
|
#include "coresight-priv.h"
|
|
|
|
|
|
|
|
static DEFINE_MUTEX(coresight_mutex);
|
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
/**
|
|
|
|
* struct coresight_node - elements of a path, from source to sink
|
|
|
|
* @csdev: Address of an element.
|
|
|
|
* @link: hook to the list.
|
|
|
|
*/
|
|
|
|
struct coresight_node {
|
|
|
|
struct coresight_device *csdev;
|
|
|
|
struct list_head link;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When operating Coresight drivers from the sysFS interface, only a single
|
|
|
|
* path can exist from a tracer (associated to a CPU) to a sink.
|
|
|
|
*/
|
2016-05-04 01:33:38 +08:00
|
|
|
static DEFINE_PER_CPU(struct list_head *, tracer_path);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* As of this writing only a single STM can be found in CS topologies. Since
|
|
|
|
* there is no way to know if we'll ever see more and what kind of
|
|
|
|
* configuration they will enact, for the time being only define a single path
|
|
|
|
* for STM.
|
|
|
|
*/
|
|
|
|
static struct list_head *stm_path;
|
2016-02-18 08:51:45 +08:00
|
|
|
|
2017-08-03 00:21:57 +08:00
|
|
|
/*
|
|
|
|
* When losing synchronisation a new barrier packet needs to be inserted at the
|
|
|
|
* beginning of the data collected in a buffer. That way the decoder knows that
|
|
|
|
* it needs to look for another sync sequence.
|
|
|
|
*/
|
2020-09-29 00:34:52 +08:00
|
|
|
const u32 coresight_barrier_pkt[4] = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff};
|
2020-09-29 00:34:53 +08:00
|
|
|
EXPORT_SYMBOL_GPL(coresight_barrier_pkt);
|
2017-08-03 00:21:57 +08:00
|
|
|
|
2020-09-29 00:35:04 +08:00
|
|
|
static const struct cti_assoc_op *cti_assoc_ops;
|
|
|
|
|
|
|
|
void coresight_set_cti_ops(const struct cti_assoc_op *cti_op)
|
|
|
|
{
|
|
|
|
cti_assoc_ops = cti_op;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(coresight_set_cti_ops);
|
|
|
|
|
|
|
|
void coresight_remove_cti_ops(void)
|
|
|
|
{
|
|
|
|
cti_assoc_ops = NULL;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(coresight_remove_cti_ops);
|
|
|
|
|
2014-11-04 02:07:35 +08:00
|
|
|
static int coresight_id_match(struct device *dev, void *data)
|
|
|
|
{
|
|
|
|
int trace_id, i_trace_id;
|
|
|
|
struct coresight_device *csdev, *i_csdev;
|
|
|
|
|
|
|
|
csdev = data;
|
|
|
|
i_csdev = to_coresight_device(dev);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No need to care about oneself and components that are not
|
|
|
|
* sources or not enabled
|
|
|
|
*/
|
|
|
|
if (i_csdev == csdev || !i_csdev->enable ||
|
|
|
|
i_csdev->type != CORESIGHT_DEV_TYPE_SOURCE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Get the source ID for both compoment */
|
|
|
|
trace_id = source_ops(csdev)->trace_id(csdev);
|
|
|
|
i_trace_id = source_ops(i_csdev)->trace_id(i_csdev);
|
|
|
|
|
|
|
|
/* All you need is one */
|
|
|
|
if (trace_id == i_trace_id)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int coresight_source_is_unique(struct coresight_device *csdev)
|
|
|
|
{
|
|
|
|
int trace_id = source_ops(csdev)->trace_id(csdev);
|
|
|
|
|
|
|
|
/* this shouldn't happen */
|
|
|
|
if (trace_id < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return !bus_for_each_dev(&coresight_bustype, NULL,
|
|
|
|
csdev, coresight_id_match);
|
|
|
|
}
|
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
static int coresight_find_link_inport(struct coresight_device *csdev,
|
|
|
|
struct coresight_device *parent)
|
2014-11-04 02:07:35 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct coresight_connection *conn;
|
|
|
|
|
2019-06-20 03:52:59 +08:00
|
|
|
for (i = 0; i < parent->pdata->nr_outport; i++) {
|
|
|
|
conn = &parent->pdata->conns[i];
|
2014-11-04 02:07:35 +08:00
|
|
|
if (conn->child_dev == csdev)
|
|
|
|
return conn->child_port;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n",
|
|
|
|
dev_name(&parent->dev), dev_name(&csdev->dev));
|
|
|
|
|
2018-07-12 03:40:28 +08:00
|
|
|
return -ENODEV;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
static int coresight_find_link_outport(struct coresight_device *csdev,
|
|
|
|
struct coresight_device *child)
|
2014-11-04 02:07:35 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct coresight_connection *conn;
|
|
|
|
|
2019-06-20 03:52:59 +08:00
|
|
|
for (i = 0; i < csdev->pdata->nr_outport; i++) {
|
|
|
|
conn = &csdev->pdata->conns[i];
|
2014-11-04 02:07:35 +08:00
|
|
|
if (conn->child_dev == child)
|
|
|
|
return conn->outport;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n",
|
|
|
|
dev_name(&csdev->dev), dev_name(&child->dev));
|
|
|
|
|
2018-07-12 03:40:28 +08:00
|
|
|
return -ENODEV;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
2018-09-21 03:18:11 +08:00
|
|
|
static inline u32 coresight_read_claim_tags(void __iomem *base)
|
|
|
|
{
|
|
|
|
return readl_relaxed(base + CORESIGHT_CLAIMCLR);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool coresight_is_claimed_self_hosted(void __iomem *base)
|
|
|
|
{
|
|
|
|
return coresight_read_claim_tags(base) == CORESIGHT_CLAIM_SELF_HOSTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool coresight_is_claimed_any(void __iomem *base)
|
|
|
|
{
|
|
|
|
return coresight_read_claim_tags(base) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void coresight_set_claim_tags(void __iomem *base)
|
|
|
|
{
|
|
|
|
writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, base + CORESIGHT_CLAIMSET);
|
|
|
|
isb();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void coresight_clear_claim_tags(void __iomem *base)
|
|
|
|
{
|
|
|
|
writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, base + CORESIGHT_CLAIMCLR);
|
|
|
|
isb();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* coresight_claim_device_unlocked : Claim the device for self-hosted usage
|
|
|
|
* to prevent an external tool from touching this device. As per PSCI
|
|
|
|
* standards, section "Preserving the execution context" => "Debug and Trace
|
|
|
|
* save and Restore", DBGCLAIM[1] is reserved for Self-hosted debug/trace and
|
|
|
|
* DBGCLAIM[0] is reserved for external tools.
|
|
|
|
*
|
|
|
|
* Called with CS_UNLOCKed for the component.
|
|
|
|
* Returns : 0 on success
|
|
|
|
*/
|
|
|
|
int coresight_claim_device_unlocked(void __iomem *base)
|
|
|
|
{
|
|
|
|
if (coresight_is_claimed_any(base))
|
|
|
|
return -EBUSY;
|
|
|
|
|
|
|
|
coresight_set_claim_tags(base);
|
|
|
|
if (coresight_is_claimed_self_hosted(base))
|
|
|
|
return 0;
|
|
|
|
/* There was a race setting the tags, clean up and fail */
|
|
|
|
coresight_clear_claim_tags(base);
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
2020-09-29 00:34:53 +08:00
|
|
|
EXPORT_SYMBOL_GPL(coresight_claim_device_unlocked);
|
2018-09-21 03:18:11 +08:00
|
|
|
|
|
|
|
int coresight_claim_device(void __iomem *base)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
CS_UNLOCK(base);
|
|
|
|
rc = coresight_claim_device_unlocked(base);
|
|
|
|
CS_LOCK(base);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2020-09-29 00:34:53 +08:00
|
|
|
EXPORT_SYMBOL_GPL(coresight_claim_device);
|
2018-09-21 03:18:11 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* coresight_disclaim_device_unlocked : Clear the claim tags for the device.
|
|
|
|
* Called with CS_UNLOCKed for the component.
|
|
|
|
*/
|
|
|
|
void coresight_disclaim_device_unlocked(void __iomem *base)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (coresight_is_claimed_self_hosted(base))
|
|
|
|
coresight_clear_claim_tags(base);
|
|
|
|
else
|
|
|
|
/*
|
|
|
|
* The external agent may have not honoured our claim
|
|
|
|
* and has manipulated it. Or something else has seriously
|
|
|
|
* gone wrong in our driver.
|
|
|
|
*/
|
|
|
|
WARN_ON_ONCE(1);
|
|
|
|
}
|
2020-09-29 00:34:53 +08:00
|
|
|
EXPORT_SYMBOL_GPL(coresight_disclaim_device_unlocked);
|
2018-09-21 03:18:11 +08:00
|
|
|
|
|
|
|
void coresight_disclaim_device(void __iomem *base)
|
|
|
|
{
|
|
|
|
CS_UNLOCK(base);
|
|
|
|
coresight_disclaim_device_unlocked(base);
|
|
|
|
CS_LOCK(base);
|
|
|
|
}
|
2020-09-29 00:34:53 +08:00
|
|
|
EXPORT_SYMBOL_GPL(coresight_disclaim_device);
|
2018-09-21 03:18:11 +08:00
|
|
|
|
2020-03-21 00:52:59 +08:00
|
|
|
/* enable or disable an associated CTI device of the supplied CS device */
|
|
|
|
static int
|
|
|
|
coresight_control_assoc_ectdev(struct coresight_device *csdev, bool enable)
|
|
|
|
{
|
|
|
|
int ect_ret = 0;
|
|
|
|
struct coresight_device *ect_csdev = csdev->ect_dev;
|
2020-09-29 00:35:08 +08:00
|
|
|
struct module *mod;
|
2020-03-21 00:52:59 +08:00
|
|
|
|
|
|
|
if (!ect_csdev)
|
|
|
|
return 0;
|
2020-09-29 00:35:07 +08:00
|
|
|
if ((!ect_ops(ect_csdev)->enable) || (!ect_ops(ect_csdev)->disable))
|
|
|
|
return 0;
|
2020-03-21 00:52:59 +08:00
|
|
|
|
2020-09-29 00:35:08 +08:00
|
|
|
mod = ect_csdev->dev.parent->driver->owner;
|
2020-03-21 00:52:59 +08:00
|
|
|
if (enable) {
|
2020-09-29 00:35:08 +08:00
|
|
|
if (try_module_get(mod)) {
|
|
|
|
ect_ret = ect_ops(ect_csdev)->enable(ect_csdev);
|
|
|
|
if (ect_ret) {
|
|
|
|
module_put(mod);
|
|
|
|
} else {
|
|
|
|
get_device(ect_csdev->dev.parent);
|
|
|
|
csdev->ect_enabled = true;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
ect_ret = -ENODEV;
|
2020-03-21 00:52:59 +08:00
|
|
|
} else {
|
2020-09-29 00:35:07 +08:00
|
|
|
if (csdev->ect_enabled) {
|
2020-03-21 00:52:59 +08:00
|
|
|
ect_ret = ect_ops(ect_csdev)->disable(ect_csdev);
|
2020-09-29 00:35:08 +08:00
|
|
|
put_device(ect_csdev->dev.parent);
|
|
|
|
module_put(mod);
|
2020-09-29 00:35:07 +08:00
|
|
|
csdev->ect_enabled = false;
|
|
|
|
}
|
2020-03-21 00:52:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the associated ect / cti device while holding the coresight_mutex
|
|
|
|
* to avoid a race with coresight_enable that may try to use this value.
|
|
|
|
*/
|
|
|
|
void coresight_set_assoc_ectdev_mutex(struct coresight_device *csdev,
|
|
|
|
struct coresight_device *ect_csdev)
|
|
|
|
{
|
|
|
|
mutex_lock(&coresight_mutex);
|
|
|
|
csdev->ect_dev = ect_csdev;
|
|
|
|
mutex_unlock(&coresight_mutex);
|
|
|
|
}
|
2020-09-29 00:35:09 +08:00
|
|
|
EXPORT_SYMBOL_GPL(coresight_set_assoc_ectdev_mutex);
|
2020-03-21 00:52:59 +08:00
|
|
|
|
2018-09-21 03:17:56 +08:00
|
|
|
static int coresight_enable_sink(struct coresight_device *csdev,
|
|
|
|
u32 mode, void *data)
|
2014-11-04 02:07:35 +08:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2018-09-21 03:17:45 +08:00
|
|
|
/*
|
|
|
|
* We need to make sure the "new" session is compatible with the
|
|
|
|
* existing "mode" of operation.
|
|
|
|
*/
|
2019-04-26 03:52:56 +08:00
|
|
|
if (!sink_ops(csdev)->enable)
|
|
|
|
return -EINVAL;
|
2014-11-04 02:07:35 +08:00
|
|
|
|
2020-03-21 00:52:59 +08:00
|
|
|
ret = coresight_control_assoc_ectdev(csdev, true);
|
2019-04-26 03:52:56 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2020-03-21 00:52:59 +08:00
|
|
|
ret = sink_ops(csdev)->enable(csdev, mode, data);
|
|
|
|
if (ret) {
|
|
|
|
coresight_control_assoc_ectdev(csdev, false);
|
|
|
|
return ret;
|
|
|
|
}
|
2019-04-26 03:52:56 +08:00
|
|
|
csdev->enable = true;
|
2014-11-04 02:07:35 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void coresight_disable_sink(struct coresight_device *csdev)
|
|
|
|
{
|
2019-04-26 03:52:55 +08:00
|
|
|
int ret;
|
|
|
|
|
2019-04-26 03:52:56 +08:00
|
|
|
if (!sink_ops(csdev)->disable)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ret = sink_ops(csdev)->disable(csdev);
|
|
|
|
if (ret)
|
|
|
|
return;
|
2020-03-21 00:52:59 +08:00
|
|
|
coresight_control_assoc_ectdev(csdev, false);
|
2019-04-26 03:52:56 +08:00
|
|
|
csdev->enable = false;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
static int coresight_enable_link(struct coresight_device *csdev,
|
|
|
|
struct coresight_device *parent,
|
|
|
|
struct coresight_device *child)
|
2014-11-04 02:07:35 +08:00
|
|
|
{
|
2019-11-05 02:12:50 +08:00
|
|
|
int ret = 0;
|
2014-11-04 02:07:35 +08:00
|
|
|
int link_subtype;
|
2019-11-05 02:12:50 +08:00
|
|
|
int inport, outport;
|
2014-11-04 02:07:35 +08:00
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
if (!parent || !child)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
inport = coresight_find_link_inport(csdev, parent);
|
|
|
|
outport = coresight_find_link_outport(csdev, child);
|
2014-11-04 02:07:35 +08:00
|
|
|
link_subtype = csdev->subtype.link_subtype;
|
|
|
|
|
2019-11-05 02:12:50 +08:00
|
|
|
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && inport < 0)
|
|
|
|
return inport;
|
|
|
|
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && outport < 0)
|
|
|
|
return outport;
|
2018-07-12 03:40:28 +08:00
|
|
|
|
2020-03-21 00:52:59 +08:00
|
|
|
if (link_ops(csdev)->enable) {
|
|
|
|
ret = coresight_control_assoc_ectdev(csdev, true);
|
|
|
|
if (!ret) {
|
|
|
|
ret = link_ops(csdev)->enable(csdev, inport, outport);
|
|
|
|
if (ret)
|
|
|
|
coresight_control_assoc_ectdev(csdev, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-05 02:12:50 +08:00
|
|
|
if (!ret)
|
|
|
|
csdev->enable = true;
|
2014-11-04 02:07:35 +08:00
|
|
|
|
2019-11-05 02:12:50 +08:00
|
|
|
return ret;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
static void coresight_disable_link(struct coresight_device *csdev,
|
|
|
|
struct coresight_device *parent,
|
|
|
|
struct coresight_device *child)
|
2014-11-04 02:07:35 +08:00
|
|
|
{
|
|
|
|
int i, nr_conns;
|
|
|
|
int link_subtype;
|
2019-11-05 02:12:50 +08:00
|
|
|
int inport, outport;
|
2014-11-04 02:07:35 +08:00
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
if (!parent || !child)
|
|
|
|
return;
|
|
|
|
|
|
|
|
inport = coresight_find_link_inport(csdev, parent);
|
|
|
|
outport = coresight_find_link_outport(csdev, child);
|
2014-11-04 02:07:35 +08:00
|
|
|
link_subtype = csdev->subtype.link_subtype;
|
|
|
|
|
|
|
|
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
|
2019-06-20 03:52:59 +08:00
|
|
|
nr_conns = csdev->pdata->nr_inport;
|
2014-11-04 02:07:35 +08:00
|
|
|
} else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
|
2019-06-20 03:52:59 +08:00
|
|
|
nr_conns = csdev->pdata->nr_outport;
|
2014-11-04 02:07:35 +08:00
|
|
|
} else {
|
|
|
|
nr_conns = 1;
|
|
|
|
}
|
|
|
|
|
2020-03-21 00:52:59 +08:00
|
|
|
if (link_ops(csdev)->disable) {
|
2019-11-05 02:12:50 +08:00
|
|
|
link_ops(csdev)->disable(csdev, inport, outport);
|
2020-03-21 00:52:59 +08:00
|
|
|
coresight_control_assoc_ectdev(csdev, false);
|
|
|
|
}
|
2014-11-04 02:07:35 +08:00
|
|
|
|
|
|
|
for (i = 0; i < nr_conns; i++)
|
|
|
|
if (atomic_read(&csdev->refcnt[i]) != 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
csdev->enable = false;
|
|
|
|
}
|
|
|
|
|
2016-02-18 08:51:52 +08:00
|
|
|
static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
|
2014-11-04 02:07:35 +08:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!coresight_source_is_unique(csdev)) {
|
|
|
|
dev_warn(&csdev->dev, "traceID %d not unique\n",
|
|
|
|
source_ops(csdev)->trace_id(csdev));
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!csdev->enable) {
|
|
|
|
if (source_ops(csdev)->enable) {
|
2020-03-21 00:52:59 +08:00
|
|
|
ret = coresight_control_assoc_ectdev(csdev, true);
|
2014-11-04 02:07:35 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2020-03-21 00:52:59 +08:00
|
|
|
ret = source_ops(csdev)->enable(csdev, NULL, mode);
|
|
|
|
if (ret) {
|
|
|
|
coresight_control_assoc_ectdev(csdev, false);
|
|
|
|
return ret;
|
2020-11-28 01:52:43 +08:00
|
|
|
}
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
csdev->enable = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_inc(csdev->refcnt);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-06-06 04:15:02 +08:00
|
|
|
/**
|
|
|
|
* coresight_disable_source - Drop the reference count by 1 and disable
|
|
|
|
* the device if there are no users left.
|
|
|
|
*
|
2020-11-28 01:52:54 +08:00
|
|
|
* @csdev: The coresight device to disable
|
2017-06-06 04:15:02 +08:00
|
|
|
*
|
|
|
|
* Returns true if the device has been disabled.
|
|
|
|
*/
|
|
|
|
static bool coresight_disable_source(struct coresight_device *csdev)
|
2014-11-04 02:07:35 +08:00
|
|
|
{
|
|
|
|
if (atomic_dec_return(csdev->refcnt) == 0) {
|
2017-06-06 04:15:02 +08:00
|
|
|
if (source_ops(csdev)->disable)
|
2016-08-26 05:19:10 +08:00
|
|
|
source_ops(csdev)->disable(csdev, NULL);
|
2020-03-21 00:52:59 +08:00
|
|
|
coresight_control_assoc_ectdev(csdev, false);
|
2017-06-06 04:15:02 +08:00
|
|
|
csdev->enable = false;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
2017-06-06 04:15:02 +08:00
|
|
|
return !csdev->enable;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
coresight: Handle failures in enabling a trace path
coresight_enable_path() enables the components in a trace
path from a given source to a sink, excluding the source.
The operation is performed in the reverse order; the sink
first and then backwards in the list. However, if we encounter
an error in enabling any of the component, we simply disable
all the components in the given path irrespective of whether
we enabled some of the components in the enable iteration.
This could interfere with another trace session if one of the
link devices is turned off (e.g, TMC-ETF). So, we need to
make sure that we only disable those components which were
actually enabled from the iteration.
This patch achieves the same by refactoring the coresight_disable_path
to accept a "node" to start from in the forward order, which can
then be used from the error path of coresight_enable_path().
With this change, we don't issue a disable call back for a component
which didn't get enabled. This change of behavior triggers
a bug in coresight_enable_link(), where we leave the refcount
on the device and will prevent the device from being enabled
forever. So, we also drop the refcount in the coresight_enable_link()
if the operation failed.
Also, with the refactoring, we always start after the first node (which
is the "SOURCE" device) for disabling the entire path. This implies,
we must not find a "SOURCE" in the middle of the path. Hence, added
a WARN_ON() to make sure the paths we get are sane, rather than
simply ignoring them.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-09-21 03:18:03 +08:00
|
|
|
/*
|
|
|
|
* coresight_disable_path_from : Disable components in the given path beyond
|
|
|
|
* @nd in the list. If @nd is NULL, all the components, except the SOURCE are
|
|
|
|
* disabled.
|
|
|
|
*/
|
|
|
|
static void coresight_disable_path_from(struct list_head *path,
|
|
|
|
struct coresight_node *nd)
|
2014-11-04 02:07:35 +08:00
|
|
|
{
|
2016-05-04 01:34:00 +08:00
|
|
|
u32 type;
|
2016-02-18 08:51:45 +08:00
|
|
|
struct coresight_device *csdev, *parent, *child;
|
|
|
|
|
coresight: Handle failures in enabling a trace path
coresight_enable_path() enables the components in a trace
path from a given source to a sink, excluding the source.
The operation is performed in the reverse order; the sink
first and then backwards in the list. However, if we encounter
an error in enabling any of the component, we simply disable
all the components in the given path irrespective of whether
we enabled some of the components in the enable iteration.
This could interfere with another trace session if one of the
link devices is turned off (e.g, TMC-ETF). So, we need to
make sure that we only disable those components which were
actually enabled from the iteration.
This patch achieves the same by refactoring the coresight_disable_path
to accept a "node" to start from in the forward order, which can
then be used from the error path of coresight_enable_path().
With this change, we don't issue a disable call back for a component
which didn't get enabled. This change of behavior triggers
a bug in coresight_enable_link(), where we leave the refcount
on the device and will prevent the device from being enabled
forever. So, we also drop the refcount in the coresight_enable_link()
if the operation failed.
Also, with the refactoring, we always start after the first node (which
is the "SOURCE" device) for disabling the entire path. This implies,
we must not find a "SOURCE" in the middle of the path. Hence, added
a WARN_ON() to make sure the paths we get are sane, rather than
simply ignoring them.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-09-21 03:18:03 +08:00
|
|
|
if (!nd)
|
|
|
|
nd = list_first_entry(path, struct coresight_node, link);
|
|
|
|
|
|
|
|
list_for_each_entry_continue(nd, path, link) {
|
2016-02-18 08:51:45 +08:00
|
|
|
csdev = nd->csdev;
|
2016-05-04 01:34:00 +08:00
|
|
|
type = csdev->type;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ETF devices are tricky... They can be a link or a sink,
|
|
|
|
* depending on how they are configured. If an ETF has been
|
|
|
|
* "activated" it will be configured as a sink, otherwise
|
|
|
|
* go ahead with the link configuration.
|
|
|
|
*/
|
|
|
|
if (type == CORESIGHT_DEV_TYPE_LINKSINK)
|
|
|
|
type = (csdev == coresight_get_sink(path)) ?
|
|
|
|
CORESIGHT_DEV_TYPE_SINK :
|
|
|
|
CORESIGHT_DEV_TYPE_LINK;
|
|
|
|
|
|
|
|
switch (type) {
|
2016-02-18 08:51:45 +08:00
|
|
|
case CORESIGHT_DEV_TYPE_SINK:
|
|
|
|
coresight_disable_sink(csdev);
|
|
|
|
break;
|
|
|
|
case CORESIGHT_DEV_TYPE_SOURCE:
|
coresight: Handle failures in enabling a trace path
coresight_enable_path() enables the components in a trace
path from a given source to a sink, excluding the source.
The operation is performed in the reverse order; the sink
first and then backwards in the list. However, if we encounter
an error in enabling any of the component, we simply disable
all the components in the given path irrespective of whether
we enabled some of the components in the enable iteration.
This could interfere with another trace session if one of the
link devices is turned off (e.g, TMC-ETF). So, we need to
make sure that we only disable those components which were
actually enabled from the iteration.
This patch achieves the same by refactoring the coresight_disable_path
to accept a "node" to start from in the forward order, which can
then be used from the error path of coresight_enable_path().
With this change, we don't issue a disable call back for a component
which didn't get enabled. This change of behavior triggers
a bug in coresight_enable_link(), where we leave the refcount
on the device and will prevent the device from being enabled
forever. So, we also drop the refcount in the coresight_enable_link()
if the operation failed.
Also, with the refactoring, we always start after the first node (which
is the "SOURCE" device) for disabling the entire path. This implies,
we must not find a "SOURCE" in the middle of the path. Hence, added
a WARN_ON() to make sure the paths we get are sane, rather than
simply ignoring them.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-09-21 03:18:03 +08:00
|
|
|
/*
|
|
|
|
* We skip the first node in the path assuming that it
|
|
|
|
* is the source. So we don't expect a source device in
|
|
|
|
* the middle of a path.
|
|
|
|
*/
|
|
|
|
WARN_ON(1);
|
2016-02-18 08:51:45 +08:00
|
|
|
break;
|
|
|
|
case CORESIGHT_DEV_TYPE_LINK:
|
|
|
|
parent = list_prev_entry(nd, link)->csdev;
|
|
|
|
child = list_next_entry(nd, link)->csdev;
|
|
|
|
coresight_disable_link(csdev, parent, child);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
}
|
2016-02-18 08:51:45 +08:00
|
|
|
}
|
2014-11-04 02:07:35 +08:00
|
|
|
|
coresight: Handle failures in enabling a trace path
coresight_enable_path() enables the components in a trace
path from a given source to a sink, excluding the source.
The operation is performed in the reverse order; the sink
first and then backwards in the list. However, if we encounter
an error in enabling any of the component, we simply disable
all the components in the given path irrespective of whether
we enabled some of the components in the enable iteration.
This could interfere with another trace session if one of the
link devices is turned off (e.g, TMC-ETF). So, we need to
make sure that we only disable those components which were
actually enabled from the iteration.
This patch achieves the same by refactoring the coresight_disable_path
to accept a "node" to start from in the forward order, which can
then be used from the error path of coresight_enable_path().
With this change, we don't issue a disable call back for a component
which didn't get enabled. This change of behavior triggers
a bug in coresight_enable_link(), where we leave the refcount
on the device and will prevent the device from being enabled
forever. So, we also drop the refcount in the coresight_enable_link()
if the operation failed.
Also, with the refactoring, we always start after the first node (which
is the "SOURCE" device) for disabling the entire path. This implies,
we must not find a "SOURCE" in the middle of the path. Hence, added
a WARN_ON() to make sure the paths we get are sane, rather than
simply ignoring them.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-09-21 03:18:03 +08:00
|
|
|
void coresight_disable_path(struct list_head *path)
|
|
|
|
{
|
|
|
|
coresight_disable_path_from(path, NULL);
|
|
|
|
}
|
2020-09-29 00:34:53 +08:00
|
|
|
EXPORT_SYMBOL_GPL(coresight_disable_path);
|
coresight: Handle failures in enabling a trace path
coresight_enable_path() enables the components in a trace
path from a given source to a sink, excluding the source.
The operation is performed in the reverse order; the sink
first and then backwards in the list. However, if we encounter
an error in enabling any of the component, we simply disable
all the components in the given path irrespective of whether
we enabled some of the components in the enable iteration.
This could interfere with another trace session if one of the
link devices is turned off (e.g, TMC-ETF). So, we need to
make sure that we only disable those components which were
actually enabled from the iteration.
This patch achieves the same by refactoring the coresight_disable_path
to accept a "node" to start from in the forward order, which can
then be used from the error path of coresight_enable_path().
With this change, we don't issue a disable call back for a component
which didn't get enabled. This change of behavior triggers
a bug in coresight_enable_link(), where we leave the refcount
on the device and will prevent the device from being enabled
forever. So, we also drop the refcount in the coresight_enable_link()
if the operation failed.
Also, with the refactoring, we always start after the first node (which
is the "SOURCE" device) for disabling the entire path. This implies,
we must not find a "SOURCE" in the middle of the path. Hence, added
a WARN_ON() to make sure the paths we get are sane, rather than
simply ignoring them.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-09-21 03:18:03 +08:00
|
|
|
|
2018-09-21 03:17:56 +08:00
|
|
|
int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data)
|
2016-02-18 08:51:45 +08:00
|
|
|
{
|
|
|
|
|
|
|
|
int ret = 0;
|
2016-05-04 01:34:00 +08:00
|
|
|
u32 type;
|
2016-02-18 08:51:45 +08:00
|
|
|
struct coresight_node *nd;
|
|
|
|
struct coresight_device *csdev, *parent, *child;
|
|
|
|
|
|
|
|
list_for_each_entry_reverse(nd, path, link) {
|
|
|
|
csdev = nd->csdev;
|
2016-05-04 01:34:00 +08:00
|
|
|
type = csdev->type;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ETF devices are tricky... They can be a link or a sink,
|
|
|
|
* depending on how they are configured. If an ETF has been
|
|
|
|
* "activated" it will be configured as a sink, otherwise
|
|
|
|
* go ahead with the link configuration.
|
|
|
|
*/
|
|
|
|
if (type == CORESIGHT_DEV_TYPE_LINKSINK)
|
|
|
|
type = (csdev == coresight_get_sink(path)) ?
|
|
|
|
CORESIGHT_DEV_TYPE_SINK :
|
|
|
|
CORESIGHT_DEV_TYPE_LINK;
|
|
|
|
|
|
|
|
switch (type) {
|
2016-02-18 08:51:45 +08:00
|
|
|
case CORESIGHT_DEV_TYPE_SINK:
|
2018-09-21 03:17:56 +08:00
|
|
|
ret = coresight_enable_sink(csdev, mode, sink_data);
|
2018-09-21 03:17:45 +08:00
|
|
|
/*
|
|
|
|
* Sink is the first component turned on. If we
|
|
|
|
* failed to enable the sink, there are no components
|
|
|
|
* that need disabling. Disabling the path here
|
|
|
|
* would mean we could disrupt an existing session.
|
|
|
|
*/
|
2016-02-18 08:51:45 +08:00
|
|
|
if (ret)
|
2018-09-21 03:17:45 +08:00
|
|
|
goto out;
|
2016-02-18 08:51:45 +08:00
|
|
|
break;
|
|
|
|
case CORESIGHT_DEV_TYPE_SOURCE:
|
|
|
|
/* sources are enabled from either sysFS or Perf */
|
|
|
|
break;
|
|
|
|
case CORESIGHT_DEV_TYPE_LINK:
|
|
|
|
parent = list_prev_entry(nd, link)->csdev;
|
|
|
|
child = list_next_entry(nd, link)->csdev;
|
|
|
|
ret = coresight_enable_link(csdev, parent, child);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto err;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
out:
|
2014-11-04 02:07:35 +08:00
|
|
|
return ret;
|
2016-02-18 08:51:45 +08:00
|
|
|
err:
|
coresight: Handle failures in enabling a trace path
coresight_enable_path() enables the components in a trace
path from a given source to a sink, excluding the source.
The operation is performed in the reverse order; the sink
first and then backwards in the list. However, if we encounter
an error in enabling any of the component, we simply disable
all the components in the given path irrespective of whether
we enabled some of the components in the enable iteration.
This could interfere with another trace session if one of the
link devices is turned off (e.g, TMC-ETF). So, we need to
make sure that we only disable those components which were
actually enabled from the iteration.
This patch achieves the same by refactoring the coresight_disable_path
to accept a "node" to start from in the forward order, which can
then be used from the error path of coresight_enable_path().
With this change, we don't issue a disable call back for a component
which didn't get enabled. This change of behavior triggers
a bug in coresight_enable_link(), where we leave the refcount
on the device and will prevent the device from being enabled
forever. So, we also drop the refcount in the coresight_enable_link()
if the operation failed.
Also, with the refactoring, we always start after the first node (which
is the "SOURCE" device) for disabling the entire path. This implies,
we must not find a "SOURCE" in the middle of the path. Hence, added
a WARN_ON() to make sure the paths we get are sane, rather than
simply ignoring them.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-09-21 03:18:03 +08:00
|
|
|
coresight_disable_path_from(path, nd);
|
2016-02-18 08:51:45 +08:00
|
|
|
goto out;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
2016-02-18 08:51:46 +08:00
|
|
|
struct coresight_device *coresight_get_sink(struct list_head *path)
|
|
|
|
{
|
|
|
|
struct coresight_device *csdev;
|
|
|
|
|
|
|
|
if (!path)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
csdev = list_last_entry(path, struct coresight_node, link)->csdev;
|
|
|
|
if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
|
|
|
|
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return csdev;
|
|
|
|
}
|
|
|
|
|
2020-09-17 03:17:35 +08:00
|
|
|
static struct coresight_device *
|
|
|
|
coresight_find_enabled_sink(struct coresight_device *csdev)
|
2016-11-30 00:47:14 +08:00
|
|
|
{
|
2020-09-17 03:17:35 +08:00
|
|
|
int i;
|
|
|
|
struct coresight_device *sink;
|
2016-11-30 00:47:14 +08:00
|
|
|
|
|
|
|
if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
|
|
|
|
csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
|
2020-09-17 03:17:35 +08:00
|
|
|
csdev->activated)
|
|
|
|
return csdev;
|
2016-11-30 00:47:14 +08:00
|
|
|
|
2020-09-17 03:17:35 +08:00
|
|
|
/*
|
|
|
|
* Recursively explore each port found on this element.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < csdev->pdata->nr_outport; i++) {
|
|
|
|
struct coresight_device *child_dev;
|
|
|
|
|
|
|
|
child_dev = csdev->pdata->conns[i].child_dev;
|
|
|
|
if (child_dev)
|
|
|
|
sink = coresight_find_enabled_sink(child_dev);
|
|
|
|
if (sink)
|
|
|
|
return sink;
|
2016-11-30 00:47:14 +08:00
|
|
|
}
|
|
|
|
|
2020-09-17 03:17:35 +08:00
|
|
|
return NULL;
|
2016-11-30 00:47:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-09-17 03:17:35 +08:00
|
|
|
* coresight_get_enabled_sink - returns the first enabled sink using
|
|
|
|
* connection based search starting from the source reference
|
2016-11-30 00:47:14 +08:00
|
|
|
*
|
2020-09-17 03:17:35 +08:00
|
|
|
* @source: Coresight source device reference
|
2016-11-30 00:47:14 +08:00
|
|
|
*/
|
2020-09-17 03:17:35 +08:00
|
|
|
struct coresight_device *
|
|
|
|
coresight_get_enabled_sink(struct coresight_device *source)
|
2016-11-30 00:47:14 +08:00
|
|
|
{
|
2020-09-17 03:17:35 +08:00
|
|
|
if (!source)
|
|
|
|
return NULL;
|
2016-11-30 00:47:14 +08:00
|
|
|
|
2020-09-17 03:17:35 +08:00
|
|
|
return coresight_find_enabled_sink(source);
|
2016-11-30 00:47:14 +08:00
|
|
|
}
|
|
|
|
|
2019-06-15 01:53:59 +08:00
|
|
|
static int coresight_sink_by_id(struct device *dev, const void *data)
|
2019-02-01 02:47:10 +08:00
|
|
|
{
|
|
|
|
struct coresight_device *csdev = to_coresight_device(dev);
|
|
|
|
unsigned long hash;
|
|
|
|
|
|
|
|
if (csdev->type == CORESIGHT_DEV_TYPE_SINK ||
|
|
|
|
csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) {
|
|
|
|
|
|
|
|
if (!csdev->ea)
|
|
|
|
return 0;
|
|
|
|
/*
|
|
|
|
* See function etm_perf_add_symlink_sink() to know where
|
|
|
|
* this comes from.
|
|
|
|
*/
|
|
|
|
hash = (unsigned long)csdev->ea->var;
|
|
|
|
|
|
|
|
if ((u32)hash == *(u32 *)data)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* coresight_get_sink_by_id - returns the sink that matches the id
|
|
|
|
* @id: Id of the sink to match
|
|
|
|
*
|
|
|
|
* The name of a sink is unique, whether it is found on the AMBA bus or
|
|
|
|
* otherwise. As such the hash of that name can easily be used to identify
|
|
|
|
* a sink.
|
|
|
|
*/
|
|
|
|
struct coresight_device *coresight_get_sink_by_id(u32 id)
|
|
|
|
{
|
|
|
|
struct device *dev = NULL;
|
|
|
|
|
|
|
|
dev = bus_find_device(&coresight_bustype, NULL, &id,
|
|
|
|
coresight_sink_by_id);
|
|
|
|
|
|
|
|
return dev ? to_coresight_device(dev) : NULL;
|
|
|
|
}
|
|
|
|
|
2020-09-29 00:34:54 +08:00
|
|
|
/**
|
|
|
|
* coresight_get_ref- Helper function to increase reference count to module
|
|
|
|
* and device.
|
2020-11-28 01:52:54 +08:00
|
|
|
*
|
|
|
|
* @csdev: The coresight device to get a reference on.
|
|
|
|
*
|
2020-09-29 00:34:54 +08:00
|
|
|
* Return true in successful case and power up the device.
|
|
|
|
* Return false when failed to get reference of module.
|
|
|
|
*/
|
|
|
|
static inline bool coresight_get_ref(struct coresight_device *csdev)
|
|
|
|
{
|
|
|
|
struct device *dev = csdev->dev.parent;
|
|
|
|
|
|
|
|
/* Make sure the driver can't be removed */
|
|
|
|
if (!try_module_get(dev->driver->owner))
|
|
|
|
return false;
|
|
|
|
/* Make sure the device can't go away */
|
|
|
|
get_device(dev);
|
|
|
|
pm_runtime_get_sync(dev);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* coresight_put_ref- Helper function to decrease reference count to module
|
|
|
|
* and device. Power off the device.
|
2020-11-28 01:52:54 +08:00
|
|
|
*
|
|
|
|
* @csdev: The coresight device to decrement a reference from.
|
2020-09-29 00:34:54 +08:00
|
|
|
*/
|
|
|
|
static inline void coresight_put_ref(struct coresight_device *csdev)
|
|
|
|
{
|
|
|
|
struct device *dev = csdev->dev.parent;
|
|
|
|
|
|
|
|
pm_runtime_put(dev);
|
|
|
|
put_device(dev);
|
|
|
|
module_put(dev->driver->owner);
|
|
|
|
}
|
|
|
|
|
coresight: Add helper device type
Add a new coresight device type, which do not belong to any
of the existing types, i.e, source, sink, link etc. A helper
device could be connected to a coresight device, which could
augment the functionality of the coresight device.
This is intended to cover Coresight Address Translation Unit (CATU)
devices, which provide improved Scatter Gather mechanism for TMC
ETR. The idea is that the helper device could be controlled by
the driver of the device it is attached to (in this case ETR),
transparent to the generic coresight driver (and paths).
The operations include enable(), disable(), both of which could
accept a device specific "data" which the driving device and
the helper device could share. Since they don't appear in the
coresight "path" tracked by software, we have to ensure that
they are powered up/down whenever the master device is turned
on.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-12 03:40:30 +08:00
|
|
|
/*
|
|
|
|
* coresight_grab_device - Power up this device and any of the helper
|
|
|
|
* devices connected to it for trace operation. Since the helper devices
|
|
|
|
* don't appear on the trace path, they should be handled along with the
|
|
|
|
* the master device.
|
|
|
|
*/
|
2020-09-29 00:34:54 +08:00
|
|
|
static int coresight_grab_device(struct coresight_device *csdev)
|
coresight: Add helper device type
Add a new coresight device type, which do not belong to any
of the existing types, i.e, source, sink, link etc. A helper
device could be connected to a coresight device, which could
augment the functionality of the coresight device.
This is intended to cover Coresight Address Translation Unit (CATU)
devices, which provide improved Scatter Gather mechanism for TMC
ETR. The idea is that the helper device could be controlled by
the driver of the device it is attached to (in this case ETR),
transparent to the generic coresight driver (and paths).
The operations include enable(), disable(), both of which could
accept a device specific "data" which the driving device and
the helper device could share. Since they don't appear in the
coresight "path" tracked by software, we have to ensure that
they are powered up/down whenever the master device is turned
on.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-12 03:40:30 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2019-06-20 03:52:59 +08:00
|
|
|
for (i = 0; i < csdev->pdata->nr_outport; i++) {
|
|
|
|
struct coresight_device *child;
|
coresight: Add helper device type
Add a new coresight device type, which do not belong to any
of the existing types, i.e, source, sink, link etc. A helper
device could be connected to a coresight device, which could
augment the functionality of the coresight device.
This is intended to cover Coresight Address Translation Unit (CATU)
devices, which provide improved Scatter Gather mechanism for TMC
ETR. The idea is that the helper device could be controlled by
the driver of the device it is attached to (in this case ETR),
transparent to the generic coresight driver (and paths).
The operations include enable(), disable(), both of which could
accept a device specific "data" which the driving device and
the helper device could share. Since they don't appear in the
coresight "path" tracked by software, we have to ensure that
they are powered up/down whenever the master device is turned
on.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-12 03:40:30 +08:00
|
|
|
|
2019-06-20 03:52:59 +08:00
|
|
|
child = csdev->pdata->conns[i].child_dev;
|
coresight: Add helper device type
Add a new coresight device type, which do not belong to any
of the existing types, i.e, source, sink, link etc. A helper
device could be connected to a coresight device, which could
augment the functionality of the coresight device.
This is intended to cover Coresight Address Translation Unit (CATU)
devices, which provide improved Scatter Gather mechanism for TMC
ETR. The idea is that the helper device could be controlled by
the driver of the device it is attached to (in this case ETR),
transparent to the generic coresight driver (and paths).
The operations include enable(), disable(), both of which could
accept a device specific "data" which the driving device and
the helper device could share. Since they don't appear in the
coresight "path" tracked by software, we have to ensure that
they are powered up/down whenever the master device is turned
on.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-12 03:40:30 +08:00
|
|
|
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
|
2020-09-29 00:34:54 +08:00
|
|
|
if (!coresight_get_ref(child))
|
|
|
|
goto err;
|
coresight: Add helper device type
Add a new coresight device type, which do not belong to any
of the existing types, i.e, source, sink, link etc. A helper
device could be connected to a coresight device, which could
augment the functionality of the coresight device.
This is intended to cover Coresight Address Translation Unit (CATU)
devices, which provide improved Scatter Gather mechanism for TMC
ETR. The idea is that the helper device could be controlled by
the driver of the device it is attached to (in this case ETR),
transparent to the generic coresight driver (and paths).
The operations include enable(), disable(), both of which could
accept a device specific "data" which the driving device and
the helper device could share. Since they don't appear in the
coresight "path" tracked by software, we have to ensure that
they are powered up/down whenever the master device is turned
on.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-12 03:40:30 +08:00
|
|
|
}
|
2020-09-29 00:34:54 +08:00
|
|
|
if (coresight_get_ref(csdev))
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
for (i--; i >= 0; i--) {
|
|
|
|
struct coresight_device *child;
|
|
|
|
|
|
|
|
child = csdev->pdata->conns[i].child_dev;
|
|
|
|
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
|
|
|
|
coresight_put_ref(child);
|
|
|
|
}
|
|
|
|
return -ENODEV;
|
coresight: Add helper device type
Add a new coresight device type, which do not belong to any
of the existing types, i.e, source, sink, link etc. A helper
device could be connected to a coresight device, which could
augment the functionality of the coresight device.
This is intended to cover Coresight Address Translation Unit (CATU)
devices, which provide improved Scatter Gather mechanism for TMC
ETR. The idea is that the helper device could be controlled by
the driver of the device it is attached to (in this case ETR),
transparent to the generic coresight driver (and paths).
The operations include enable(), disable(), both of which could
accept a device specific "data" which the driving device and
the helper device could share. Since they don't appear in the
coresight "path" tracked by software, we have to ensure that
they are powered up/down whenever the master device is turned
on.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-12 03:40:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* coresight_drop_device - Release this device and any of the helper
|
|
|
|
* devices connected to it.
|
|
|
|
*/
|
|
|
|
static void coresight_drop_device(struct coresight_device *csdev)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2020-09-29 00:34:54 +08:00
|
|
|
coresight_put_ref(csdev);
|
2019-06-20 03:52:59 +08:00
|
|
|
for (i = 0; i < csdev->pdata->nr_outport; i++) {
|
|
|
|
struct coresight_device *child;
|
coresight: Add helper device type
Add a new coresight device type, which do not belong to any
of the existing types, i.e, source, sink, link etc. A helper
device could be connected to a coresight device, which could
augment the functionality of the coresight device.
This is intended to cover Coresight Address Translation Unit (CATU)
devices, which provide improved Scatter Gather mechanism for TMC
ETR. The idea is that the helper device could be controlled by
the driver of the device it is attached to (in this case ETR),
transparent to the generic coresight driver (and paths).
The operations include enable(), disable(), both of which could
accept a device specific "data" which the driving device and
the helper device could share. Since they don't appear in the
coresight "path" tracked by software, we have to ensure that
they are powered up/down whenever the master device is turned
on.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-12 03:40:30 +08:00
|
|
|
|
2019-06-20 03:52:59 +08:00
|
|
|
child = csdev->pdata->conns[i].child_dev;
|
coresight: Add helper device type
Add a new coresight device type, which do not belong to any
of the existing types, i.e, source, sink, link etc. A helper
device could be connected to a coresight device, which could
augment the functionality of the coresight device.
This is intended to cover Coresight Address Translation Unit (CATU)
devices, which provide improved Scatter Gather mechanism for TMC
ETR. The idea is that the helper device could be controlled by
the driver of the device it is attached to (in this case ETR),
transparent to the generic coresight driver (and paths).
The operations include enable(), disable(), both of which could
accept a device specific "data" which the driving device and
the helper device could share. Since they don't appear in the
coresight "path" tracked by software, we have to ensure that
they are powered up/down whenever the master device is turned
on.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-12 03:40:30 +08:00
|
|
|
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
|
2020-09-29 00:34:54 +08:00
|
|
|
coresight_put_ref(child);
|
coresight: Add helper device type
Add a new coresight device type, which do not belong to any
of the existing types, i.e, source, sink, link etc. A helper
device could be connected to a coresight device, which could
augment the functionality of the coresight device.
This is intended to cover Coresight Address Translation Unit (CATU)
devices, which provide improved Scatter Gather mechanism for TMC
ETR. The idea is that the helper device could be controlled by
the driver of the device it is attached to (in this case ETR),
transparent to the generic coresight driver (and paths).
The operations include enable(), disable(), both of which could
accept a device specific "data" which the driving device and
the helper device could share. Since they don't appear in the
coresight "path" tracked by software, we have to ensure that
they are powered up/down whenever the master device is turned
on.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-12 03:40:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
/**
|
|
|
|
* _coresight_build_path - recursively build a path from a @csdev to a sink.
|
|
|
|
* @csdev: The device to start from.
|
2020-11-28 01:52:54 +08:00
|
|
|
* @sink: The final sink we want in this path.
|
2016-02-18 08:51:45 +08:00
|
|
|
* @path: The list to add devices to.
|
|
|
|
*
|
|
|
|
* The tree of Coresight device is traversed until an activated sink is
|
|
|
|
* found. From there the sink is added to the list along with all the
|
|
|
|
* devices that led to that point - the end result is a list from source
|
|
|
|
* to sink. In that list the source is the first device and the sink the
|
|
|
|
* last one.
|
|
|
|
*/
|
|
|
|
static int _coresight_build_path(struct coresight_device *csdev,
|
2016-11-30 00:47:14 +08:00
|
|
|
struct coresight_device *sink,
|
2016-02-18 08:51:45 +08:00
|
|
|
struct list_head *path)
|
2014-11-04 02:07:35 +08:00
|
|
|
{
|
2020-09-29 00:34:54 +08:00
|
|
|
int i, ret;
|
2016-02-18 08:51:45 +08:00
|
|
|
bool found = false;
|
|
|
|
struct coresight_node *node;
|
|
|
|
|
|
|
|
/* An activated sink has been found. Enqueue the element */
|
2016-11-30 00:47:14 +08:00
|
|
|
if (csdev == sink)
|
2016-02-18 08:51:45 +08:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* Not a sink - recursively explore each port found on this element */
|
2019-06-20 03:52:59 +08:00
|
|
|
for (i = 0; i < csdev->pdata->nr_outport; i++) {
|
|
|
|
struct coresight_device *child_dev;
|
2016-06-15 01:17:12 +08:00
|
|
|
|
2019-06-20 03:52:59 +08:00
|
|
|
child_dev = csdev->pdata->conns[i].child_dev;
|
2016-11-30 00:47:14 +08:00
|
|
|
if (child_dev &&
|
|
|
|
_coresight_build_path(child_dev, sink, path) == 0) {
|
2016-02-18 08:51:45 +08:00
|
|
|
found = true;
|
|
|
|
break;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
if (!found)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
out:
|
|
|
|
/*
|
|
|
|
* A path from this element to a sink has been found. The elements
|
|
|
|
* leading to the sink are already enqueued, all that is left to do
|
2016-02-18 08:51:47 +08:00
|
|
|
* is tell the PM runtime core we need this element and add a node
|
|
|
|
* for it.
|
2016-02-18 08:51:45 +08:00
|
|
|
*/
|
2020-09-29 00:34:54 +08:00
|
|
|
ret = coresight_grab_device(csdev);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
node = kzalloc(sizeof(struct coresight_node), GFP_KERNEL);
|
|
|
|
if (!node)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
node->csdev = csdev;
|
|
|
|
list_add(&node->link, path);
|
|
|
|
|
2014-11-04 02:07:35 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-30 00:47:14 +08:00
|
|
|
struct list_head *coresight_build_path(struct coresight_device *source,
|
|
|
|
struct coresight_device *sink)
|
2014-11-04 02:07:35 +08:00
|
|
|
{
|
2016-02-18 08:51:45 +08:00
|
|
|
struct list_head *path;
|
2016-05-06 22:35:50 +08:00
|
|
|
int rc;
|
2014-11-04 02:07:35 +08:00
|
|
|
|
2016-11-30 00:47:14 +08:00
|
|
|
if (!sink)
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
path = kzalloc(sizeof(struct list_head), GFP_KERNEL);
|
|
|
|
if (!path)
|
2016-09-09 06:50:38 +08:00
|
|
|
return ERR_PTR(-ENOMEM);
|
2014-11-04 02:07:35 +08:00
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
INIT_LIST_HEAD(path);
|
|
|
|
|
2016-11-30 00:47:14 +08:00
|
|
|
rc = _coresight_build_path(source, sink, path);
|
2016-05-06 22:35:50 +08:00
|
|
|
if (rc) {
|
2016-02-18 08:51:45 +08:00
|
|
|
kfree(path);
|
2016-05-06 22:35:50 +08:00
|
|
|
return ERR_PTR(rc);
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
return path;
|
|
|
|
}
|
2014-11-04 02:07:35 +08:00
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
/**
|
|
|
|
* coresight_release_path - release a previously built path.
|
|
|
|
* @path: the path to release.
|
|
|
|
*
|
|
|
|
* Go through all the elements of a path and 1) removed it from the list and
|
|
|
|
* 2) free the memory allocated for each node.
|
|
|
|
*/
|
|
|
|
void coresight_release_path(struct list_head *path)
|
|
|
|
{
|
2016-02-18 08:51:47 +08:00
|
|
|
struct coresight_device *csdev;
|
2016-02-18 08:51:45 +08:00
|
|
|
struct coresight_node *nd, *next;
|
2014-11-04 02:07:35 +08:00
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
list_for_each_entry_safe(nd, next, path, link) {
|
2016-02-18 08:51:47 +08:00
|
|
|
csdev = nd->csdev;
|
|
|
|
|
coresight: Add helper device type
Add a new coresight device type, which do not belong to any
of the existing types, i.e, source, sink, link etc. A helper
device could be connected to a coresight device, which could
augment the functionality of the coresight device.
This is intended to cover Coresight Address Translation Unit (CATU)
devices, which provide improved Scatter Gather mechanism for TMC
ETR. The idea is that the helper device could be controlled by
the driver of the device it is attached to (in this case ETR),
transparent to the generic coresight driver (and paths).
The operations include enable(), disable(), both of which could
accept a device specific "data" which the driving device and
the helper device could share. Since they don't appear in the
coresight "path" tracked by software, we have to ensure that
they are powered up/down whenever the master device is turned
on.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-12 03:40:30 +08:00
|
|
|
coresight_drop_device(csdev);
|
2016-02-18 08:51:45 +08:00
|
|
|
list_del(&nd->link);
|
|
|
|
kfree(nd);
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(path);
|
|
|
|
path = NULL;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
2020-07-17 01:57:43 +08:00
|
|
|
/* return true if the device is a suitable type for a default sink */
|
|
|
|
static inline bool coresight_is_def_sink_type(struct coresight_device *csdev)
|
|
|
|
{
|
|
|
|
/* sink & correct subtype */
|
|
|
|
if (((csdev->type == CORESIGHT_DEV_TYPE_SINK) ||
|
|
|
|
(csdev->type == CORESIGHT_DEV_TYPE_LINKSINK)) &&
|
|
|
|
(csdev->subtype.sink_subtype >= CORESIGHT_DEV_SUBTYPE_SINK_BUFFER))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* coresight_select_best_sink - return the best sink for use as default from
|
|
|
|
* the two provided.
|
|
|
|
*
|
|
|
|
* @sink: current best sink.
|
|
|
|
* @depth: search depth where current sink was found.
|
|
|
|
* @new_sink: new sink for comparison with current sink.
|
|
|
|
* @new_depth: search depth where new sink was found.
|
|
|
|
*
|
|
|
|
* Sinks prioritised according to coresight_dev_subtype_sink, with only
|
|
|
|
* subtypes CORESIGHT_DEV_SUBTYPE_SINK_BUFFER or higher being used.
|
|
|
|
*
|
|
|
|
* Where two sinks of equal priority are found, the sink closest to the
|
|
|
|
* source is used (smallest search depth).
|
|
|
|
*
|
|
|
|
* return @new_sink & update @depth if better than @sink, else return @sink.
|
|
|
|
*/
|
|
|
|
static struct coresight_device *
|
|
|
|
coresight_select_best_sink(struct coresight_device *sink, int *depth,
|
|
|
|
struct coresight_device *new_sink, int new_depth)
|
|
|
|
{
|
|
|
|
bool update = false;
|
|
|
|
|
|
|
|
if (!sink) {
|
|
|
|
/* first found at this level */
|
|
|
|
update = true;
|
|
|
|
} else if (new_sink->subtype.sink_subtype >
|
|
|
|
sink->subtype.sink_subtype) {
|
|
|
|
/* found better sink */
|
|
|
|
update = true;
|
|
|
|
} else if ((new_sink->subtype.sink_subtype ==
|
|
|
|
sink->subtype.sink_subtype) &&
|
|
|
|
(*depth > new_depth)) {
|
|
|
|
/* found same but closer sink */
|
|
|
|
update = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (update)
|
|
|
|
*depth = new_depth;
|
|
|
|
return update ? new_sink : sink;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* coresight_find_sink - recursive function to walk trace connections from
|
|
|
|
* source to find a suitable default sink.
|
|
|
|
*
|
|
|
|
* @csdev: source / current device to check.
|
|
|
|
* @depth: [in] search depth of calling dev, [out] depth of found sink.
|
|
|
|
*
|
|
|
|
* This will walk the connection path from a source (ETM) till a suitable
|
|
|
|
* sink is encountered and return that sink to the original caller.
|
|
|
|
*
|
|
|
|
* If current device is a plain sink return that & depth, otherwise recursively
|
|
|
|
* call child connections looking for a sink. Select best possible using
|
|
|
|
* coresight_select_best_sink.
|
|
|
|
*
|
|
|
|
* return best sink found, or NULL if not found at this node or child nodes.
|
|
|
|
*/
|
|
|
|
static struct coresight_device *
|
|
|
|
coresight_find_sink(struct coresight_device *csdev, int *depth)
|
|
|
|
{
|
|
|
|
int i, curr_depth = *depth + 1, found_depth = 0;
|
|
|
|
struct coresight_device *found_sink = NULL;
|
|
|
|
|
|
|
|
if (coresight_is_def_sink_type(csdev)) {
|
|
|
|
found_depth = curr_depth;
|
|
|
|
found_sink = csdev;
|
|
|
|
if (csdev->type == CORESIGHT_DEV_TYPE_SINK)
|
|
|
|
goto return_def_sink;
|
|
|
|
/* look past LINKSINK for something better */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Not a sink we want - or possible child sink may be better.
|
|
|
|
* recursively explore each port found on this element.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < csdev->pdata->nr_outport; i++) {
|
|
|
|
struct coresight_device *child_dev, *sink = NULL;
|
|
|
|
int child_depth = curr_depth;
|
|
|
|
|
|
|
|
child_dev = csdev->pdata->conns[i].child_dev;
|
|
|
|
if (child_dev)
|
|
|
|
sink = coresight_find_sink(child_dev, &child_depth);
|
|
|
|
|
|
|
|
if (sink)
|
|
|
|
found_sink = coresight_select_best_sink(found_sink,
|
|
|
|
&found_depth,
|
|
|
|
sink,
|
|
|
|
child_depth);
|
|
|
|
}
|
|
|
|
|
|
|
|
return_def_sink:
|
|
|
|
/* return found sink and depth */
|
|
|
|
if (found_sink)
|
|
|
|
*depth = found_depth;
|
|
|
|
return found_sink;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* coresight_find_default_sink: Find a sink suitable for use as a
|
|
|
|
* default sink.
|
|
|
|
*
|
|
|
|
* @csdev: starting source to find a connected sink.
|
|
|
|
*
|
|
|
|
* Walks connections graph looking for a suitable sink to enable for the
|
|
|
|
* supplied source. Uses CoreSight device subtypes and distance from source
|
|
|
|
* to select the best sink.
|
|
|
|
*
|
|
|
|
* If a sink is found, then the default sink for this device is set and
|
|
|
|
* will be automatically used in future.
|
|
|
|
*
|
|
|
|
* Used in cases where the CoreSight user (perf / sysfs) has not selected a
|
|
|
|
* sink.
|
|
|
|
*/
|
|
|
|
struct coresight_device *
|
|
|
|
coresight_find_default_sink(struct coresight_device *csdev)
|
|
|
|
{
|
|
|
|
int depth = 0;
|
|
|
|
|
|
|
|
/* look for a default sink if we have not found for this device */
|
|
|
|
if (!csdev->def_sink)
|
|
|
|
csdev->def_sink = coresight_find_sink(csdev, &depth);
|
|
|
|
return csdev->def_sink;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int coresight_remove_sink_ref(struct device *dev, void *data)
|
|
|
|
{
|
|
|
|
struct coresight_device *sink = data;
|
|
|
|
struct coresight_device *source = to_coresight_device(dev);
|
|
|
|
|
|
|
|
if (source->def_sink == sink)
|
|
|
|
source->def_sink = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* coresight_clear_default_sink: Remove all default sink references to the
|
|
|
|
* supplied sink.
|
|
|
|
*
|
|
|
|
* If supplied device is a sink, then check all the bus devices and clear
|
|
|
|
* out all the references to this sink from the coresight_device def_sink
|
|
|
|
* parameter.
|
|
|
|
*
|
|
|
|
* @csdev: coresight sink - remove references to this from all sources.
|
|
|
|
*/
|
|
|
|
static void coresight_clear_default_sink(struct coresight_device *csdev)
|
|
|
|
{
|
|
|
|
if ((csdev->type == CORESIGHT_DEV_TYPE_SINK) ||
|
|
|
|
(csdev->type == CORESIGHT_DEV_TYPE_LINKSINK)) {
|
|
|
|
bus_for_each_dev(&coresight_bustype, NULL, csdev,
|
|
|
|
coresight_remove_sink_ref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-04 01:33:38 +08:00
|
|
|
/** coresight_validate_source - make sure a source has the right credentials
|
|
|
|
* @csdev: the device structure for a source.
|
|
|
|
* @function: the function this was called from.
|
|
|
|
*
|
|
|
|
* Assumes the coresight_mutex is held.
|
|
|
|
*/
|
|
|
|
static int coresight_validate_source(struct coresight_device *csdev,
|
|
|
|
const char *function)
|
|
|
|
{
|
|
|
|
u32 type, subtype;
|
|
|
|
|
|
|
|
type = csdev->type;
|
|
|
|
subtype = csdev->subtype.source_subtype;
|
|
|
|
|
|
|
|
if (type != CORESIGHT_DEV_TYPE_SOURCE) {
|
|
|
|
dev_err(&csdev->dev, "wrong device type in %s\n", function);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
|
|
|
|
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) {
|
|
|
|
dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-04 02:07:35 +08:00
|
|
|
int coresight_enable(struct coresight_device *csdev)
|
|
|
|
{
|
2016-05-04 01:33:38 +08:00
|
|
|
int cpu, ret = 0;
|
2016-11-30 00:47:14 +08:00
|
|
|
struct coresight_device *sink;
|
2016-02-18 08:51:45 +08:00
|
|
|
struct list_head *path;
|
2017-06-06 04:15:03 +08:00
|
|
|
enum coresight_dev_subtype_source subtype;
|
|
|
|
|
|
|
|
subtype = csdev->subtype.source_subtype;
|
2014-11-04 02:07:35 +08:00
|
|
|
|
|
|
|
mutex_lock(&coresight_mutex);
|
2016-05-04 01:33:38 +08:00
|
|
|
|
|
|
|
ret = coresight_validate_source(csdev, __func__);
|
|
|
|
if (ret)
|
2014-11-04 02:07:35 +08:00
|
|
|
goto out;
|
2016-05-04 01:33:38 +08:00
|
|
|
|
2017-06-06 04:15:03 +08:00
|
|
|
if (csdev->enable) {
|
|
|
|
/*
|
|
|
|
* There could be multiple applications driving the software
|
|
|
|
* source. So keep the refcount for each such user when the
|
|
|
|
* source is already enabled.
|
|
|
|
*/
|
|
|
|
if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
|
|
|
|
atomic_inc(csdev->refcnt);
|
2014-11-04 02:07:35 +08:00
|
|
|
goto out;
|
2017-06-06 04:15:03 +08:00
|
|
|
}
|
2014-11-04 02:07:35 +08:00
|
|
|
|
2020-09-17 03:17:35 +08:00
|
|
|
sink = coresight_get_enabled_sink(csdev);
|
2016-11-30 00:47:14 +08:00
|
|
|
if (!sink) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
path = coresight_build_path(csdev, sink);
|
2016-05-06 22:35:50 +08:00
|
|
|
if (IS_ERR(path)) {
|
2016-02-18 08:51:45 +08:00
|
|
|
pr_err("building path(s) failed\n");
|
2016-05-06 22:35:50 +08:00
|
|
|
ret = PTR_ERR(path);
|
2014-11-04 02:07:35 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-09-21 03:17:56 +08:00
|
|
|
ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
|
2016-02-18 08:51:45 +08:00
|
|
|
if (ret)
|
|
|
|
goto err_path;
|
|
|
|
|
2016-02-18 08:51:52 +08:00
|
|
|
ret = coresight_enable_source(csdev, CS_MODE_SYSFS);
|
2016-02-18 08:51:45 +08:00
|
|
|
if (ret)
|
|
|
|
goto err_source;
|
|
|
|
|
2017-06-06 04:15:03 +08:00
|
|
|
switch (subtype) {
|
2016-05-04 01:33:38 +08:00
|
|
|
case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
|
|
|
|
/*
|
|
|
|
* When working from sysFS it is important to keep track
|
|
|
|
* of the paths that were created so that they can be
|
|
|
|
* undone in 'coresight_disable()'. Since there can only
|
|
|
|
* be a single session per tracer (when working from sysFS)
|
|
|
|
* a per-cpu variable will do just fine.
|
|
|
|
*/
|
|
|
|
cpu = source_ops(csdev)->cpu_id(csdev);
|
|
|
|
per_cpu(tracer_path, cpu) = path;
|
|
|
|
break;
|
|
|
|
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
|
|
|
|
stm_path = path;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* We can't be here */
|
|
|
|
break;
|
|
|
|
}
|
2016-02-18 08:51:45 +08:00
|
|
|
|
2014-11-04 02:07:35 +08:00
|
|
|
out:
|
|
|
|
mutex_unlock(&coresight_mutex);
|
|
|
|
return ret;
|
2016-02-18 08:51:45 +08:00
|
|
|
|
|
|
|
err_source:
|
|
|
|
coresight_disable_path(path);
|
|
|
|
|
|
|
|
err_path:
|
|
|
|
coresight_release_path(path);
|
|
|
|
goto out;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(coresight_enable);
|
|
|
|
|
|
|
|
void coresight_disable(struct coresight_device *csdev)
|
|
|
|
{
|
2016-05-04 01:33:38 +08:00
|
|
|
int cpu, ret;
|
|
|
|
struct list_head *path = NULL;
|
2014-11-04 02:07:35 +08:00
|
|
|
|
|
|
|
mutex_lock(&coresight_mutex);
|
2016-05-04 01:33:38 +08:00
|
|
|
|
|
|
|
ret = coresight_validate_source(csdev, __func__);
|
|
|
|
if (ret)
|
2014-11-04 02:07:35 +08:00
|
|
|
goto out;
|
2016-05-04 01:33:38 +08:00
|
|
|
|
2017-06-06 04:15:02 +08:00
|
|
|
if (!csdev->enable || !coresight_disable_source(csdev))
|
2014-11-04 02:07:35 +08:00
|
|
|
goto out;
|
|
|
|
|
2016-05-04 01:33:38 +08:00
|
|
|
switch (csdev->subtype.source_subtype) {
|
|
|
|
case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
|
|
|
|
cpu = source_ops(csdev)->cpu_id(csdev);
|
|
|
|
path = per_cpu(tracer_path, cpu);
|
|
|
|
per_cpu(tracer_path, cpu) = NULL;
|
|
|
|
break;
|
|
|
|
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
|
|
|
|
path = stm_path;
|
|
|
|
stm_path = NULL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* We can't be here */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-02-18 08:51:45 +08:00
|
|
|
coresight_disable_path(path);
|
|
|
|
coresight_release_path(path);
|
2014-11-04 02:07:35 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
mutex_unlock(&coresight_mutex);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(coresight_disable);
|
|
|
|
|
|
|
|
static ssize_t enable_sink_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct coresight_device *csdev = to_coresight_device(dev);
|
|
|
|
|
2016-05-04 01:33:35 +08:00
|
|
|
return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->activated);
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t enable_sink_store(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
const char *buf, size_t size)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
unsigned long val;
|
|
|
|
struct coresight_device *csdev = to_coresight_device(dev);
|
|
|
|
|
|
|
|
ret = kstrtoul(buf, 10, &val);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (val)
|
|
|
|
csdev->activated = true;
|
|
|
|
else
|
|
|
|
csdev->activated = false;
|
|
|
|
|
|
|
|
return size;
|
|
|
|
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RW(enable_sink);
|
|
|
|
|
|
|
|
static ssize_t enable_source_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct coresight_device *csdev = to_coresight_device(dev);
|
|
|
|
|
2016-05-04 01:33:35 +08:00
|
|
|
return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->enable);
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t enable_source_store(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
const char *buf, size_t size)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
unsigned long val;
|
|
|
|
struct coresight_device *csdev = to_coresight_device(dev);
|
|
|
|
|
|
|
|
ret = kstrtoul(buf, 10, &val);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (val) {
|
|
|
|
ret = coresight_enable(csdev);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
} else {
|
|
|
|
coresight_disable(csdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RW(enable_source);
|
|
|
|
|
|
|
|
static struct attribute *coresight_sink_attrs[] = {
|
|
|
|
&dev_attr_enable_sink.attr,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
ATTRIBUTE_GROUPS(coresight_sink);
|
|
|
|
|
|
|
|
static struct attribute *coresight_source_attrs[] = {
|
|
|
|
&dev_attr_enable_source.attr,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
ATTRIBUTE_GROUPS(coresight_source);
|
|
|
|
|
|
|
|
static struct device_type coresight_dev_type[] = {
|
|
|
|
{
|
|
|
|
.name = "none",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "sink",
|
|
|
|
.groups = coresight_sink_groups,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "link",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "linksink",
|
|
|
|
.groups = coresight_sink_groups,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "source",
|
|
|
|
.groups = coresight_source_groups,
|
|
|
|
},
|
coresight: Add helper device type
Add a new coresight device type, which do not belong to any
of the existing types, i.e, source, sink, link etc. A helper
device could be connected to a coresight device, which could
augment the functionality of the coresight device.
This is intended to cover Coresight Address Translation Unit (CATU)
devices, which provide improved Scatter Gather mechanism for TMC
ETR. The idea is that the helper device could be controlled by
the driver of the device it is attached to (in this case ETR),
transparent to the generic coresight driver (and paths).
The operations include enable(), disable(), both of which could
accept a device specific "data" which the driving device and
the helper device could share. Since they don't appear in the
coresight "path" tracked by software, we have to ensure that
they are powered up/down whenever the master device is turned
on.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-12 03:40:30 +08:00
|
|
|
{
|
|
|
|
.name = "helper",
|
|
|
|
},
|
2020-03-21 00:52:52 +08:00
|
|
|
{
|
|
|
|
.name = "ect",
|
|
|
|
},
|
2014-11-04 02:07:35 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static void coresight_device_release(struct device *dev)
|
|
|
|
{
|
|
|
|
struct coresight_device *csdev = to_coresight_device(dev);
|
|
|
|
|
2019-06-20 03:53:03 +08:00
|
|
|
fwnode_handle_put(csdev->dev.fwnode);
|
2016-02-03 05:13:57 +08:00
|
|
|
kfree(csdev->refcnt);
|
2014-11-04 02:07:35 +08:00
|
|
|
kfree(csdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int coresight_orphan_match(struct device *dev, void *data)
|
|
|
|
{
|
2020-05-19 02:02:23 +08:00
|
|
|
int i, ret = 0;
|
2014-11-04 02:07:35 +08:00
|
|
|
bool still_orphan = false;
|
|
|
|
struct coresight_device *csdev, *i_csdev;
|
|
|
|
struct coresight_connection *conn;
|
|
|
|
|
|
|
|
csdev = data;
|
|
|
|
i_csdev = to_coresight_device(dev);
|
|
|
|
|
|
|
|
/* No need to check oneself */
|
|
|
|
if (csdev == i_csdev)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Move on to another component if no connection is orphan */
|
|
|
|
if (!i_csdev->orphan)
|
|
|
|
return 0;
|
|
|
|
/*
|
|
|
|
* Circle throuch all the connection of that component. If we find
|
|
|
|
* an orphan connection whose name matches @csdev, link it.
|
|
|
|
*/
|
2019-06-20 03:52:59 +08:00
|
|
|
for (i = 0; i < i_csdev->pdata->nr_outport; i++) {
|
|
|
|
conn = &i_csdev->pdata->conns[i];
|
2014-11-04 02:07:35 +08:00
|
|
|
|
coresight: Fix support for sparsely populated ports
On some systems the firmware may not describe all the ports
connected to a component (e.g, for security reasons). This
could be especially problematic for "funnels" where we could
end up in modifying memory beyond the allocated space for
refcounts.
e.g, for a funnel with input ports listed 0, 3, 5, nr_inport = 3.
However the we could access refcnts[5] while checking for
references, like :
[ 526.110401] ==================================================================
[ 526.117988] BUG: KASAN: slab-out-of-bounds in funnel_enable+0x54/0x1b0
[ 526.124706] Read of size 4 at addr ffffff8135f9549c by task bash/1114
[ 526.131324]
[ 526.132886] CPU: 3 PID: 1114 Comm: bash Tainted: G S 5.4.25 #232
[ 526.140397] Hardware name: Qualcomm Technologies, Inc. SC7180 IDP (DT)
[ 526.147113] Call trace:
[ 526.149653] dump_backtrace+0x0/0x188
[ 526.153431] show_stack+0x20/0x2c
[ 526.156852] dump_stack+0xdc/0x144
[ 526.160370] print_address_description+0x3c/0x494
[ 526.165211] __kasan_report+0x144/0x168
[ 526.169170] kasan_report+0x10/0x18
[ 526.172769] check_memory_region+0x1a4/0x1b4
[ 526.177164] __kasan_check_read+0x18/0x24
[ 526.181292] funnel_enable+0x54/0x1b0
[ 526.185072] coresight_enable_path+0x104/0x198
[ 526.189649] coresight_enable+0x118/0x26c
...
[ 526.237782] Allocated by task 280:
[ 526.241298] __kasan_kmalloc+0xf0/0x1ac
[ 526.245249] kasan_kmalloc+0xc/0x14
[ 526.248849] __kmalloc+0x28c/0x3b4
[ 526.252361] coresight_register+0x88/0x250
[ 526.256587] funnel_probe+0x15c/0x228
[ 526.260365] dynamic_funnel_probe+0x20/0x2c
[ 526.264679] amba_probe+0xbc/0x158
[ 526.268193] really_probe+0x144/0x408
[ 526.271970] driver_probe_device+0x70/0x140
...
[ 526.316810]
[ 526.318364] Freed by task 0:
[ 526.321344] (stack is not available)
[ 526.325024]
[ 526.326580] The buggy address belongs to the object at ffffff8135f95480
[ 526.326580] which belongs to the cache kmalloc-128 of size 128
[ 526.339439] The buggy address is located 28 bytes inside of
[ 526.339439] 128-byte region [ffffff8135f95480, ffffff8135f95500)
[ 526.351399] The buggy address belongs to the page:
[ 526.356342] page:ffffffff04b7e500 refcount:1 mapcount:0 mapping:ffffff814b00c380 index:0x0 compound_mapcount: 0
[ 526.366711] flags: 0x4000000000010200(slab|head)
[ 526.371475] raw: 4000000000010200 ffffffff05034008 ffffffff0501eb08 ffffff814b00c380
[ 526.379435] raw: 0000000000000000 0000000000190019 00000001ffffffff 0000000000000000
[ 526.387393] page dumped because: kasan: bad access detected
[ 526.393128]
[ 526.394681] Memory state around the buggy address:
[ 526.399619] ffffff8135f95380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.407046] ffffff8135f95400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.414473] >ffffff8135f95480: 04 fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.421900] ^
[ 526.426029] ffffff8135f95500: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.433456] ffffff8135f95580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.440883] ==================================================================
To keep the code simple, we now track the maximum number of
possible input/output connections to/from this component
@ nr_inport and nr_outport in platform_data, respectively.
Thus the output connections could be sparse and code is
adjusted to skip the unspecified connections.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Mike Leach <mike.leach@linaro.org>
Reported-by: Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
Tested-by: Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
Tested-by: Stephen Boyd <swboyd@chromium.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Link: https://lore.kernel.org/r/20200518180242.7916-13-mathieu.poirier@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-05-19 02:02:31 +08:00
|
|
|
/* Skip the port if FW doesn't describe it */
|
|
|
|
if (!conn->child_fwnode)
|
|
|
|
continue;
|
2014-11-04 02:07:35 +08:00
|
|
|
/* We have found at least one orphan connection */
|
|
|
|
if (conn->child_dev == NULL) {
|
|
|
|
/* Does it match this newly added device? */
|
2020-05-19 02:02:23 +08:00
|
|
|
if (conn->child_fwnode == csdev->dev.fwnode) {
|
|
|
|
ret = coresight_make_links(i_csdev,
|
|
|
|
conn, csdev);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
} else {
|
2015-01-27 00:22:19 +08:00
|
|
|
/* This component still has an orphan */
|
|
|
|
still_orphan = true;
|
2020-05-19 02:02:23 +08:00
|
|
|
}
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
i_csdev->orphan = still_orphan;
|
|
|
|
|
|
|
|
/*
|
2020-05-19 02:02:23 +08:00
|
|
|
* Returning '0' in case we didn't encounter any error,
|
|
|
|
* ensures that all known component on the bus will be checked.
|
2014-11-04 02:07:35 +08:00
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-19 02:02:21 +08:00
|
|
|
static int coresight_fixup_orphan_conns(struct coresight_device *csdev)
|
2014-11-04 02:07:35 +08:00
|
|
|
{
|
2020-05-19 02:02:21 +08:00
|
|
|
return bus_for_each_dev(&coresight_bustype, NULL,
|
2016-02-03 05:13:55 +08:00
|
|
|
csdev, coresight_orphan_match);
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-05-19 02:02:21 +08:00
|
|
|
static int coresight_fixup_device_conns(struct coresight_device *csdev)
|
2014-11-04 02:07:35 +08:00
|
|
|
{
|
2020-05-19 02:02:23 +08:00
|
|
|
int i, ret = 0;
|
2014-11-04 02:07:35 +08:00
|
|
|
|
2019-06-20 03:52:59 +08:00
|
|
|
for (i = 0; i < csdev->pdata->nr_outport; i++) {
|
|
|
|
struct coresight_connection *conn = &csdev->pdata->conns[i];
|
2020-03-21 00:52:57 +08:00
|
|
|
|
coresight: Fix support for sparsely populated ports
On some systems the firmware may not describe all the ports
connected to a component (e.g, for security reasons). This
could be especially problematic for "funnels" where we could
end up in modifying memory beyond the allocated space for
refcounts.
e.g, for a funnel with input ports listed 0, 3, 5, nr_inport = 3.
However the we could access refcnts[5] while checking for
references, like :
[ 526.110401] ==================================================================
[ 526.117988] BUG: KASAN: slab-out-of-bounds in funnel_enable+0x54/0x1b0
[ 526.124706] Read of size 4 at addr ffffff8135f9549c by task bash/1114
[ 526.131324]
[ 526.132886] CPU: 3 PID: 1114 Comm: bash Tainted: G S 5.4.25 #232
[ 526.140397] Hardware name: Qualcomm Technologies, Inc. SC7180 IDP (DT)
[ 526.147113] Call trace:
[ 526.149653] dump_backtrace+0x0/0x188
[ 526.153431] show_stack+0x20/0x2c
[ 526.156852] dump_stack+0xdc/0x144
[ 526.160370] print_address_description+0x3c/0x494
[ 526.165211] __kasan_report+0x144/0x168
[ 526.169170] kasan_report+0x10/0x18
[ 526.172769] check_memory_region+0x1a4/0x1b4
[ 526.177164] __kasan_check_read+0x18/0x24
[ 526.181292] funnel_enable+0x54/0x1b0
[ 526.185072] coresight_enable_path+0x104/0x198
[ 526.189649] coresight_enable+0x118/0x26c
...
[ 526.237782] Allocated by task 280:
[ 526.241298] __kasan_kmalloc+0xf0/0x1ac
[ 526.245249] kasan_kmalloc+0xc/0x14
[ 526.248849] __kmalloc+0x28c/0x3b4
[ 526.252361] coresight_register+0x88/0x250
[ 526.256587] funnel_probe+0x15c/0x228
[ 526.260365] dynamic_funnel_probe+0x20/0x2c
[ 526.264679] amba_probe+0xbc/0x158
[ 526.268193] really_probe+0x144/0x408
[ 526.271970] driver_probe_device+0x70/0x140
...
[ 526.316810]
[ 526.318364] Freed by task 0:
[ 526.321344] (stack is not available)
[ 526.325024]
[ 526.326580] The buggy address belongs to the object at ffffff8135f95480
[ 526.326580] which belongs to the cache kmalloc-128 of size 128
[ 526.339439] The buggy address is located 28 bytes inside of
[ 526.339439] 128-byte region [ffffff8135f95480, ffffff8135f95500)
[ 526.351399] The buggy address belongs to the page:
[ 526.356342] page:ffffffff04b7e500 refcount:1 mapcount:0 mapping:ffffff814b00c380 index:0x0 compound_mapcount: 0
[ 526.366711] flags: 0x4000000000010200(slab|head)
[ 526.371475] raw: 4000000000010200 ffffffff05034008 ffffffff0501eb08 ffffff814b00c380
[ 526.379435] raw: 0000000000000000 0000000000190019 00000001ffffffff 0000000000000000
[ 526.387393] page dumped because: kasan: bad access detected
[ 526.393128]
[ 526.394681] Memory state around the buggy address:
[ 526.399619] ffffff8135f95380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.407046] ffffff8135f95400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.414473] >ffffff8135f95480: 04 fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.421900] ^
[ 526.426029] ffffff8135f95500: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.433456] ffffff8135f95580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.440883] ==================================================================
To keep the code simple, we now track the maximum number of
possible input/output connections to/from this component
@ nr_inport and nr_outport in platform_data, respectively.
Thus the output connections could be sparse and code is
adjusted to skip the unspecified connections.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Mike Leach <mike.leach@linaro.org>
Reported-by: Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
Tested-by: Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
Tested-by: Stephen Boyd <swboyd@chromium.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Link: https://lore.kernel.org/r/20200518180242.7916-13-mathieu.poirier@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-05-19 02:02:31 +08:00
|
|
|
if (!conn->child_fwnode)
|
|
|
|
continue;
|
2020-03-21 00:52:57 +08:00
|
|
|
conn->child_dev =
|
|
|
|
coresight_find_csdev_by_fwnode(conn->child_fwnode);
|
2020-05-19 02:02:23 +08:00
|
|
|
if (conn->child_dev) {
|
|
|
|
ret = coresight_make_links(csdev, conn,
|
|
|
|
conn->child_dev);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
} else {
|
2014-11-04 02:07:35 +08:00
|
|
|
csdev->orphan = true;
|
2020-05-19 02:02:23 +08:00
|
|
|
}
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
2020-05-19 02:02:21 +08:00
|
|
|
|
|
|
|
return 0;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
2016-02-03 05:13:59 +08:00
|
|
|
static int coresight_remove_match(struct device *dev, void *data)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct coresight_device *csdev, *iterator;
|
|
|
|
struct coresight_connection *conn;
|
|
|
|
|
|
|
|
csdev = data;
|
|
|
|
iterator = to_coresight_device(dev);
|
|
|
|
|
|
|
|
/* No need to check oneself */
|
|
|
|
if (csdev == iterator)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Circle throuch all the connection of that component. If we find
|
|
|
|
* a connection whose name matches @csdev, remove it.
|
|
|
|
*/
|
2019-06-20 03:52:59 +08:00
|
|
|
for (i = 0; i < iterator->pdata->nr_outport; i++) {
|
|
|
|
conn = &iterator->pdata->conns[i];
|
2016-02-03 05:13:59 +08:00
|
|
|
|
coresight: Fix support for sparsely populated ports
On some systems the firmware may not describe all the ports
connected to a component (e.g, for security reasons). This
could be especially problematic for "funnels" where we could
end up in modifying memory beyond the allocated space for
refcounts.
e.g, for a funnel with input ports listed 0, 3, 5, nr_inport = 3.
However the we could access refcnts[5] while checking for
references, like :
[ 526.110401] ==================================================================
[ 526.117988] BUG: KASAN: slab-out-of-bounds in funnel_enable+0x54/0x1b0
[ 526.124706] Read of size 4 at addr ffffff8135f9549c by task bash/1114
[ 526.131324]
[ 526.132886] CPU: 3 PID: 1114 Comm: bash Tainted: G S 5.4.25 #232
[ 526.140397] Hardware name: Qualcomm Technologies, Inc. SC7180 IDP (DT)
[ 526.147113] Call trace:
[ 526.149653] dump_backtrace+0x0/0x188
[ 526.153431] show_stack+0x20/0x2c
[ 526.156852] dump_stack+0xdc/0x144
[ 526.160370] print_address_description+0x3c/0x494
[ 526.165211] __kasan_report+0x144/0x168
[ 526.169170] kasan_report+0x10/0x18
[ 526.172769] check_memory_region+0x1a4/0x1b4
[ 526.177164] __kasan_check_read+0x18/0x24
[ 526.181292] funnel_enable+0x54/0x1b0
[ 526.185072] coresight_enable_path+0x104/0x198
[ 526.189649] coresight_enable+0x118/0x26c
...
[ 526.237782] Allocated by task 280:
[ 526.241298] __kasan_kmalloc+0xf0/0x1ac
[ 526.245249] kasan_kmalloc+0xc/0x14
[ 526.248849] __kmalloc+0x28c/0x3b4
[ 526.252361] coresight_register+0x88/0x250
[ 526.256587] funnel_probe+0x15c/0x228
[ 526.260365] dynamic_funnel_probe+0x20/0x2c
[ 526.264679] amba_probe+0xbc/0x158
[ 526.268193] really_probe+0x144/0x408
[ 526.271970] driver_probe_device+0x70/0x140
...
[ 526.316810]
[ 526.318364] Freed by task 0:
[ 526.321344] (stack is not available)
[ 526.325024]
[ 526.326580] The buggy address belongs to the object at ffffff8135f95480
[ 526.326580] which belongs to the cache kmalloc-128 of size 128
[ 526.339439] The buggy address is located 28 bytes inside of
[ 526.339439] 128-byte region [ffffff8135f95480, ffffff8135f95500)
[ 526.351399] The buggy address belongs to the page:
[ 526.356342] page:ffffffff04b7e500 refcount:1 mapcount:0 mapping:ffffff814b00c380 index:0x0 compound_mapcount: 0
[ 526.366711] flags: 0x4000000000010200(slab|head)
[ 526.371475] raw: 4000000000010200 ffffffff05034008 ffffffff0501eb08 ffffff814b00c380
[ 526.379435] raw: 0000000000000000 0000000000190019 00000001ffffffff 0000000000000000
[ 526.387393] page dumped because: kasan: bad access detected
[ 526.393128]
[ 526.394681] Memory state around the buggy address:
[ 526.399619] ffffff8135f95380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.407046] ffffff8135f95400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.414473] >ffffff8135f95480: 04 fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.421900] ^
[ 526.426029] ffffff8135f95500: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.433456] ffffff8135f95580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 526.440883] ==================================================================
To keep the code simple, we now track the maximum number of
possible input/output connections to/from this component
@ nr_inport and nr_outport in platform_data, respectively.
Thus the output connections could be sparse and code is
adjusted to skip the unspecified connections.
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Mike Leach <mike.leach@linaro.org>
Reported-by: Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
Tested-by: Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
Tested-by: Stephen Boyd <swboyd@chromium.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Link: https://lore.kernel.org/r/20200518180242.7916-13-mathieu.poirier@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-05-19 02:02:31 +08:00
|
|
|
if (conn->child_dev == NULL || conn->child_fwnode == NULL)
|
2016-02-03 05:13:59 +08:00
|
|
|
continue;
|
|
|
|
|
2019-06-20 03:53:03 +08:00
|
|
|
if (csdev->dev.fwnode == conn->child_fwnode) {
|
2016-02-03 05:13:59 +08:00
|
|
|
iterator->orphan = true;
|
2020-05-19 02:02:23 +08:00
|
|
|
coresight_remove_links(iterator, conn);
|
2019-06-20 03:53:03 +08:00
|
|
|
/*
|
|
|
|
* Drop the reference to the handle for the remote
|
|
|
|
* device acquired in parsing the connections from
|
|
|
|
* platform data.
|
|
|
|
*/
|
|
|
|
fwnode_handle_put(conn->child_fwnode);
|
2016-02-03 05:13:59 +08:00
|
|
|
/* No need to continue */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returning '0' ensures that all known component on the
|
|
|
|
* bus will be checked.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-20 03:52:58 +08:00
|
|
|
/*
|
|
|
|
* coresight_remove_conns - Remove references to this given devices
|
|
|
|
* from the connections of other devices.
|
|
|
|
*/
|
2016-02-03 05:13:59 +08:00
|
|
|
static void coresight_remove_conns(struct coresight_device *csdev)
|
|
|
|
{
|
2019-06-20 03:52:58 +08:00
|
|
|
/*
|
|
|
|
* Another device will point to this device only if there is
|
|
|
|
* an output port connected to this one. i.e, if the device
|
|
|
|
* doesn't have at least one input port, there is no point
|
|
|
|
* in searching all the devices.
|
|
|
|
*/
|
2019-06-20 03:52:59 +08:00
|
|
|
if (csdev->pdata->nr_inport)
|
2019-06-20 03:52:58 +08:00
|
|
|
bus_for_each_dev(&coresight_bustype, NULL,
|
|
|
|
csdev, coresight_remove_match);
|
2016-02-03 05:13:59 +08:00
|
|
|
}
|
|
|
|
|
2014-11-04 02:07:35 +08:00
|
|
|
/**
|
|
|
|
* coresight_timeout - loop until a bit has changed to a specific state.
|
|
|
|
* @addr: base address of the area of interest.
|
|
|
|
* @offset: address of a register, starting from @addr.
|
|
|
|
* @position: the position of the bit of interest.
|
|
|
|
* @value: the value the bit should have.
|
|
|
|
*
|
|
|
|
* Return: 0 as soon as the bit has taken the desired state or -EAGAIN if
|
|
|
|
* TIMEOUT_US has elapsed, which ever happens first.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int coresight_timeout(void __iomem *addr, u32 offset, int position, int value)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
for (i = TIMEOUT_US; i > 0; i--) {
|
|
|
|
val = __raw_readl(addr + offset);
|
|
|
|
/* waiting on the bit to go from 0 to 1 */
|
|
|
|
if (value) {
|
|
|
|
if (val & BIT(position))
|
|
|
|
return 0;
|
|
|
|
/* waiting on the bit to go from 1 to 0 */
|
|
|
|
} else {
|
|
|
|
if (!(val & BIT(position)))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delay is arbitrary - the specification doesn't say how long
|
|
|
|
* we are expected to wait. Extra check required to make sure
|
|
|
|
* we don't wait needlessly on the last iteration.
|
|
|
|
*/
|
|
|
|
if (i - 1)
|
|
|
|
udelay(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EAGAIN;
|
|
|
|
}
|
2020-09-29 00:34:53 +08:00
|
|
|
EXPORT_SYMBOL_GPL(coresight_timeout);
|
2014-11-04 02:07:35 +08:00
|
|
|
|
2019-06-20 03:53:03 +08:00
|
|
|
/*
|
|
|
|
* coresight_release_platform_data: Release references to the devices connected
|
|
|
|
* to the output port of this device.
|
|
|
|
*/
|
2020-05-19 02:02:20 +08:00
|
|
|
void coresight_release_platform_data(struct coresight_device *csdev,
|
|
|
|
struct coresight_platform_data *pdata)
|
2019-06-20 03:53:03 +08:00
|
|
|
{
|
|
|
|
int i;
|
2020-05-19 02:02:23 +08:00
|
|
|
struct coresight_connection *conns = pdata->conns;
|
2019-06-20 03:53:03 +08:00
|
|
|
|
|
|
|
for (i = 0; i < pdata->nr_outport; i++) {
|
2020-05-19 02:02:23 +08:00
|
|
|
/* If we have made the links, remove them now */
|
|
|
|
if (csdev && conns[i].child_dev)
|
|
|
|
coresight_remove_links(csdev, &conns[i]);
|
|
|
|
/*
|
|
|
|
* Drop the refcount and clear the handle as this device
|
|
|
|
* is going away
|
|
|
|
*/
|
|
|
|
if (conns[i].child_fwnode) {
|
|
|
|
fwnode_handle_put(conns[i].child_fwnode);
|
2019-06-20 03:53:03 +08:00
|
|
|
pdata->conns[i].child_fwnode = NULL;
|
|
|
|
}
|
|
|
|
}
|
2020-05-19 02:02:23 +08:00
|
|
|
if (csdev)
|
|
|
|
coresight_remove_conns_sysfs_group(csdev);
|
2019-06-20 03:53:03 +08:00
|
|
|
}
|
|
|
|
|
2014-11-04 02:07:35 +08:00
|
|
|
struct coresight_device *coresight_register(struct coresight_desc *desc)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int link_subtype;
|
|
|
|
int nr_refcnts = 1;
|
|
|
|
atomic_t *refcnts = NULL;
|
|
|
|
struct coresight_device *csdev;
|
|
|
|
|
|
|
|
csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
|
|
|
|
if (!csdev) {
|
|
|
|
ret = -ENOMEM;
|
2018-09-21 03:17:36 +08:00
|
|
|
goto err_out;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
|
|
|
|
desc->type == CORESIGHT_DEV_TYPE_LINKSINK) {
|
|
|
|
link_subtype = desc->subtype.link_subtype;
|
|
|
|
|
|
|
|
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
|
|
|
|
nr_refcnts = desc->pdata->nr_inport;
|
|
|
|
else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
|
|
|
|
nr_refcnts = desc->pdata->nr_outport;
|
|
|
|
}
|
|
|
|
|
|
|
|
refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
|
|
|
|
if (!refcnts) {
|
|
|
|
ret = -ENOMEM;
|
2018-09-21 03:17:36 +08:00
|
|
|
goto err_free_csdev;
|
2014-11-04 02:07:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
csdev->refcnt = refcnts;
|
|
|
|
|
2019-06-20 03:52:59 +08:00
|
|
|
csdev->pdata = desc->pdata;
|
2014-11-04 02:07:35 +08:00
|
|
|
|
|
|
|
csdev->type = desc->type;
|
|
|
|
csdev->subtype = desc->subtype;
|
|
|
|
csdev->ops = desc->ops;
|
|
|
|
csdev->orphan = false;
|
|
|
|
|
|
|
|
csdev->dev.type = &coresight_dev_type[desc->type];
|
|
|
|
csdev->dev.groups = desc->groups;
|
|
|
|
csdev->dev.parent = desc->dev;
|
|
|
|
csdev->dev.release = coresight_device_release;
|
|
|
|
csdev->dev.bus = &coresight_bustype;
|
2019-06-20 03:53:03 +08:00
|
|
|
/*
|
|
|
|
* Hold the reference to our parent device. This will be
|
|
|
|
* dropped only in coresight_device_release().
|
|
|
|
*/
|
|
|
|
csdev->dev.fwnode = fwnode_handle_get(dev_fwnode(desc->dev));
|
2019-06-20 03:52:57 +08:00
|
|
|
dev_set_name(&csdev->dev, "%s", desc->name);
|
2014-11-04 02:07:35 +08:00
|
|
|
|
|
|
|
ret = device_register(&csdev->dev);
|
2018-05-10 02:06:03 +08:00
|
|
|
if (ret) {
|
|
|
|
put_device(&csdev->dev);
|
2018-09-21 03:17:36 +08:00
|
|
|
/*
|
|
|
|
* All resources are free'd explicitly via
|
|
|
|
* coresight_device_release(), triggered from put_device().
|
|
|
|
*/
|
|
|
|
goto err_out;
|
2018-05-10 02:06:03 +08:00
|
|
|
}
|
2014-11-04 02:07:35 +08:00
|
|
|
|
coresight: perf: Add "sinks" group to PMU directory
Add a "sinks" directory entry so that users can see all the sinks
available in the system in a single place. Individual sink are added
as they are registered with the coresight bus.
Committer tests:
Test built on a ubuntu 18.04 container with a cross build environment to
arm64, the new field is there, need to find a machine with this feature
to do further testing in the future.
root@d15263e5734a:/git/perf# grep CORESIGHT /tmp/build/v5.0-rc2+/.config
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_LINKS_AND_SINKS=y
CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
CONFIG_CORESIGHT_CATU=y
CONFIG_CORESIGHT_SINK_TPIU=y
CONFIG_CORESIGHT_SINK_ETBV10=y
CONFIG_CORESIGHT_SOURCE_ETM4X=y
CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
CONFIG_CORESIGHT_CPU_DEBUG=m
root@d15263e5734a:/git/perf#
root@d15263e5734a:/git/perf# file /tmp/build/v5.0-rc2+/drivers/hwtracing/coresight/*.o
.../coresight/coresight-catu.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-cpu-debug.mod.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-cpu-debug.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-dynamic-replicator.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-etb10.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-etm-perf.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-etm4x-sysfs.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-etm4x.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-funnel.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-replicator.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-stm.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-tmc-etf.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-tmc-etr.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-tmc.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-tpiu.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/of_coresight.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
root@d15263e5734a:/git/perf#
root@d15263e5734a:/git/perf# pahole -C coresight_device /tmp/build/v5.0-rc2+/drivers/hwtracing/coresight/coresight.o
struct coresight_device {
struct coresight_connection * conns; /* 0 8 */
int nr_inport; /* 8 4 */
int nr_outport; /* 12 4 */
enum coresight_dev_type type; /* 16 4 */
union coresight_dev_subtype subtype; /* 20 8 */
/* XXX 4 bytes hole, try to pack */
const struct coresight_ops * ops; /* 32 8 */
struct device dev; /* 40 1408 */
/* XXX last struct has 7 bytes of padding */
/* --- cacheline 22 boundary (1408 bytes) was 40 bytes ago --- */
atomic_t * refcnt; /* 1448 8 */
bool orphan; /* 1456 1 */
bool enable; /* 1457 1 */
bool activated; /* 1458 1 */
/* XXX 5 bytes hole, try to pack */
struct dev_ext_attribute * ea; /* 1464 8 */
/* size: 1472, cachelines: 23, members: 12 */
/* sum members: 1463, holes: 2, sum holes: 9 */
/* paddings: 1, sum paddings: 7 */
};
root@d15263e5734a:/git/perf#
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will.deacon@arm.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-s390@vger.kernel.org
Link: http://lkml.kernel.org/r/20190131184714.20388-3-mathieu.poirier@linaro.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-01 02:47:09 +08:00
|
|
|
if (csdev->type == CORESIGHT_DEV_TYPE_SINK ||
|
|
|
|
csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) {
|
|
|
|
ret = etm_perf_add_symlink_sink(csdev);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
device_unregister(&csdev->dev);
|
|
|
|
/*
|
|
|
|
* As with the above, all resources are free'd
|
|
|
|
* explicitly via coresight_device_release() triggered
|
|
|
|
* from put_device(), which is in turn called from
|
|
|
|
* function device_unregister().
|
|
|
|
*/
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-04 02:07:35 +08:00
|
|
|
mutex_lock(&coresight_mutex);
|
|
|
|
|
2020-05-19 02:02:23 +08:00
|
|
|
ret = coresight_create_conns_sysfs_group(csdev);
|
|
|
|
if (!ret)
|
|
|
|
ret = coresight_fixup_device_conns(csdev);
|
2020-05-19 02:02:21 +08:00
|
|
|
if (!ret)
|
|
|
|
ret = coresight_fixup_orphan_conns(csdev);
|
2020-09-29 00:35:04 +08:00
|
|
|
if (!ret && cti_assoc_ops && cti_assoc_ops->add)
|
|
|
|
cti_assoc_ops->add(csdev);
|
2014-11-04 02:07:35 +08:00
|
|
|
|
|
|
|
mutex_unlock(&coresight_mutex);
|
2020-05-19 02:02:21 +08:00
|
|
|
if (ret) {
|
|
|
|
coresight_unregister(csdev);
|
|
|
|
return ERR_PTR(ret);
|
|
|
|
}
|
2014-11-04 02:07:35 +08:00
|
|
|
|
|
|
|
return csdev;
|
|
|
|
|
2018-09-21 03:17:36 +08:00
|
|
|
err_free_csdev:
|
2014-11-04 02:07:35 +08:00
|
|
|
kfree(csdev);
|
2018-09-21 03:17:36 +08:00
|
|
|
err_out:
|
2019-06-20 03:53:01 +08:00
|
|
|
/* Cleanup the connection information */
|
2020-05-19 02:02:20 +08:00
|
|
|
coresight_release_platform_data(NULL, desc->pdata);
|
2014-11-04 02:07:35 +08:00
|
|
|
return ERR_PTR(ret);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(coresight_register);
|
|
|
|
|
|
|
|
void coresight_unregister(struct coresight_device *csdev)
|
|
|
|
{
|
coresight: perf: Add "sinks" group to PMU directory
Add a "sinks" directory entry so that users can see all the sinks
available in the system in a single place. Individual sink are added
as they are registered with the coresight bus.
Committer tests:
Test built on a ubuntu 18.04 container with a cross build environment to
arm64, the new field is there, need to find a machine with this feature
to do further testing in the future.
root@d15263e5734a:/git/perf# grep CORESIGHT /tmp/build/v5.0-rc2+/.config
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_LINKS_AND_SINKS=y
CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
CONFIG_CORESIGHT_CATU=y
CONFIG_CORESIGHT_SINK_TPIU=y
CONFIG_CORESIGHT_SINK_ETBV10=y
CONFIG_CORESIGHT_SOURCE_ETM4X=y
CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
CONFIG_CORESIGHT_CPU_DEBUG=m
root@d15263e5734a:/git/perf#
root@d15263e5734a:/git/perf# file /tmp/build/v5.0-rc2+/drivers/hwtracing/coresight/*.o
.../coresight/coresight-catu.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-cpu-debug.mod.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-cpu-debug.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-dynamic-replicator.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-etb10.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-etm-perf.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-etm4x-sysfs.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-etm4x.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-funnel.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-replicator.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-stm.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-tmc-etf.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-tmc-etr.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-tmc.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight-tpiu.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/coresight.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
.../coresight/of_coresight.o: ELF 64-bit MSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
root@d15263e5734a:/git/perf#
root@d15263e5734a:/git/perf# pahole -C coresight_device /tmp/build/v5.0-rc2+/drivers/hwtracing/coresight/coresight.o
struct coresight_device {
struct coresight_connection * conns; /* 0 8 */
int nr_inport; /* 8 4 */
int nr_outport; /* 12 4 */
enum coresight_dev_type type; /* 16 4 */
union coresight_dev_subtype subtype; /* 20 8 */
/* XXX 4 bytes hole, try to pack */
const struct coresight_ops * ops; /* 32 8 */
struct device dev; /* 40 1408 */
/* XXX last struct has 7 bytes of padding */
/* --- cacheline 22 boundary (1408 bytes) was 40 bytes ago --- */
atomic_t * refcnt; /* 1448 8 */
bool orphan; /* 1456 1 */
bool enable; /* 1457 1 */
bool activated; /* 1458 1 */
/* XXX 5 bytes hole, try to pack */
struct dev_ext_attribute * ea; /* 1464 8 */
/* size: 1472, cachelines: 23, members: 12 */
/* sum members: 1463, holes: 2, sum holes: 9 */
/* paddings: 1, sum paddings: 7 */
};
root@d15263e5734a:/git/perf#
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will.deacon@arm.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-s390@vger.kernel.org
Link: http://lkml.kernel.org/r/20190131184714.20388-3-mathieu.poirier@linaro.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-02-01 02:47:09 +08:00
|
|
|
etm_perf_del_symlink_sink(csdev);
|
2016-02-03 05:13:59 +08:00
|
|
|
/* Remove references of that device in the topology */
|
2020-09-29 00:35:06 +08:00
|
|
|
if (cti_assoc_ops && cti_assoc_ops->remove)
|
|
|
|
cti_assoc_ops->remove(csdev);
|
2016-02-03 05:13:59 +08:00
|
|
|
coresight_remove_conns(csdev);
|
2020-07-17 01:57:43 +08:00
|
|
|
coresight_clear_default_sink(csdev);
|
2020-05-19 02:02:20 +08:00
|
|
|
coresight_release_platform_data(csdev, csdev->pdata);
|
2014-11-04 02:07:35 +08:00
|
|
|
device_unregister(&csdev->dev);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(coresight_unregister);
|
2019-06-20 03:53:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* coresight_search_device_idx - Search the fwnode handle of a device
|
|
|
|
* in the given dev_idx list. Must be called with the coresight_mutex held.
|
|
|
|
*
|
|
|
|
* Returns the index of the entry, when found. Otherwise, -ENOENT.
|
|
|
|
*/
|
|
|
|
static inline int coresight_search_device_idx(struct coresight_dev_list *dict,
|
|
|
|
struct fwnode_handle *fwnode)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < dict->nr_idx; i++)
|
|
|
|
if (dict->fwnode_list[i] == fwnode)
|
|
|
|
return i;
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2019-11-05 02:12:38 +08:00
|
|
|
bool coresight_loses_context_with_cpu(struct device *dev)
|
|
|
|
{
|
|
|
|
return fwnode_property_present(dev_fwnode(dev),
|
|
|
|
"arm,coresight-loses-context-with-cpu");
|
|
|
|
}
|
2020-09-29 00:34:53 +08:00
|
|
|
EXPORT_SYMBOL_GPL(coresight_loses_context_with_cpu);
|
2019-11-05 02:12:38 +08:00
|
|
|
|
2019-06-20 03:53:04 +08:00
|
|
|
/*
|
|
|
|
* coresight_alloc_device_name - Get an index for a given device in the
|
|
|
|
* device index list specific to a driver. An index is allocated for a
|
|
|
|
* device and is tracked with the fwnode_handle to prevent allocating
|
|
|
|
* duplicate indices for the same device (e.g, if we defer probing of
|
|
|
|
* a device due to dependencies), in case the index is requested again.
|
|
|
|
*/
|
|
|
|
char *coresight_alloc_device_name(struct coresight_dev_list *dict,
|
|
|
|
struct device *dev)
|
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
char *name = NULL;
|
|
|
|
struct fwnode_handle **list;
|
|
|
|
|
|
|
|
mutex_lock(&coresight_mutex);
|
|
|
|
|
|
|
|
idx = coresight_search_device_idx(dict, dev_fwnode(dev));
|
|
|
|
if (idx < 0) {
|
|
|
|
/* Make space for the new entry */
|
|
|
|
idx = dict->nr_idx;
|
|
|
|
list = krealloc(dict->fwnode_list,
|
|
|
|
(idx + 1) * sizeof(*dict->fwnode_list),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (ZERO_OR_NULL_PTR(list)) {
|
|
|
|
idx = -ENOMEM;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
list[idx] = dev_fwnode(dev);
|
|
|
|
dict->fwnode_list = list;
|
|
|
|
dict->nr_idx = idx + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
name = devm_kasprintf(dev, GFP_KERNEL, "%s%d", dict->pfx, idx);
|
|
|
|
done:
|
|
|
|
mutex_unlock(&coresight_mutex);
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
|
2020-09-29 00:35:12 +08:00
|
|
|
|
|
|
|
struct bus_type coresight_bustype = {
|
|
|
|
.name = "coresight",
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init coresight_init(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = bus_register(&coresight_bustype);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = etm_perf_init();
|
|
|
|
if (ret)
|
|
|
|
bus_unregister(&coresight_bustype);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit coresight_exit(void)
|
|
|
|
{
|
|
|
|
etm_perf_exit();
|
|
|
|
bus_unregister(&coresight_bustype);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(coresight_init);
|
|
|
|
module_exit(coresight_exit);
|
|
|
|
|
2020-10-27 00:01:54 +08:00
|
|
|
MODULE_LICENSE("GPL v2");
|
2020-09-29 00:35:12 +08:00
|
|
|
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
|
|
|
|
MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");
|
|
|
|
MODULE_DESCRIPTION("Arm CoreSight tracer driver");
|