mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-28 00:32:00 +00:00
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git
This commit is contained in:
commit
80897984e4
@ -0,0 +1,15 @@
|
||||
What: /sys/bus/coresight/devices/dummy_source<N>/enable_source
|
||||
Date: Dec 2024
|
||||
KernelVersion: 6.14
|
||||
Contact: Mao Jinlong <quic_jinlmao@quicinc.com>
|
||||
Description: (RW) Enable/disable tracing of dummy source. A sink should be activated
|
||||
before enabling the source. The path of coresight components linking
|
||||
the source to the sink is configured and managed automatically by the
|
||||
coresight framework.
|
||||
|
||||
What: /sys/bus/coresight/devices/dummy_source<N>/traceid
|
||||
Date: Dec 2024
|
||||
KernelVersion: 6.14
|
||||
Contact: Mao Jinlong <quic_jinlmao@quicinc.com>
|
||||
Description: (R) Show the trace ID that will appear in the trace stream
|
||||
coming from this trace entity.
|
@ -38,6 +38,12 @@ properties:
|
||||
enum:
|
||||
- arm,coresight-dummy-source
|
||||
|
||||
arm,static-trace-id:
|
||||
description: If dummy source needs static id support, use this to set trace id.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 111
|
||||
|
||||
out-ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
|
@ -45,7 +45,22 @@ properties:
|
||||
patternProperties:
|
||||
'^port@[01]$':
|
||||
description: Output connections to CoreSight Trace bus
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/graph.yaml#/$defs/endpoint-base
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
filter-source:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
phandle to the coresight trace source device matching the
|
||||
hard coded filtering for this port
|
||||
|
||||
remote-endpoint: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
@ -72,6 +87,7 @@ examples:
|
||||
reg = <0>;
|
||||
replicator_out_port0: endpoint {
|
||||
remote-endpoint = <&etb_in_port>;
|
||||
filter-source = <&tpdm_video>;
|
||||
};
|
||||
};
|
||||
|
||||
@ -79,6 +95,7 @@ examples:
|
||||
reg = <1>;
|
||||
replicator_out_port1: endpoint {
|
||||
remote-endpoint = <&tpiu_in_port>;
|
||||
filter-source = <&tpdm_mdss>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -75,22 +75,54 @@ struct coresight_device *coresight_get_percpu_sink(int cpu)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_get_percpu_sink);
|
||||
|
||||
static struct coresight_device *coresight_get_source(struct list_head *path)
|
||||
{
|
||||
struct coresight_device *csdev;
|
||||
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
csdev = list_first_entry(path, struct coresight_node, link)->csdev;
|
||||
if (!coresight_is_device_source(csdev))
|
||||
return NULL;
|
||||
|
||||
return csdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* coresight_blocks_source - checks whether the connection matches the source
|
||||
* of path if connection is bound to specific source.
|
||||
* @src: The source device of the trace path
|
||||
* @conn: The connection of one outport
|
||||
*
|
||||
* Return false if the connection doesn't have a source binded or source of the
|
||||
* path matches the source binds to connection.
|
||||
*/
|
||||
static bool coresight_blocks_source(struct coresight_device *src,
|
||||
struct coresight_connection *conn)
|
||||
{
|
||||
return conn->filter_src_fwnode && (conn->filter_src_dev != src);
|
||||
}
|
||||
|
||||
static struct coresight_connection *
|
||||
coresight_find_out_connection(struct coresight_device *src_dev,
|
||||
struct coresight_device *dest_dev)
|
||||
coresight_find_out_connection(struct coresight_device *csdev,
|
||||
struct coresight_device *out_dev,
|
||||
struct coresight_device *trace_src)
|
||||
{
|
||||
int i;
|
||||
struct coresight_connection *conn;
|
||||
|
||||
for (i = 0; i < src_dev->pdata->nr_outconns; i++) {
|
||||
conn = src_dev->pdata->out_conns[i];
|
||||
if (conn->dest_dev == dest_dev)
|
||||
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
|
||||
conn = csdev->pdata->out_conns[i];
|
||||
if (coresight_blocks_source(trace_src, conn))
|
||||
continue;
|
||||
if (conn->dest_dev == out_dev)
|
||||
return conn;
|
||||
}
|
||||
|
||||
dev_err(&src_dev->dev,
|
||||
"couldn't find output connection, src_dev: %s, dest_dev: %s\n",
|
||||
dev_name(&src_dev->dev), dev_name(&dest_dev->dev));
|
||||
dev_err(&csdev->dev,
|
||||
"couldn't find output connection, csdev: %s, out_dev: %s\n",
|
||||
dev_name(&csdev->dev), dev_name(&out_dev->dev));
|
||||
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
@ -251,7 +283,8 @@ static void coresight_disable_sink(struct coresight_device *csdev)
|
||||
|
||||
static int coresight_enable_link(struct coresight_device *csdev,
|
||||
struct coresight_device *parent,
|
||||
struct coresight_device *child)
|
||||
struct coresight_device *child,
|
||||
struct coresight_device *source)
|
||||
{
|
||||
int link_subtype;
|
||||
struct coresight_connection *inconn, *outconn;
|
||||
@ -259,8 +292,8 @@ static int coresight_enable_link(struct coresight_device *csdev,
|
||||
if (!parent || !child)
|
||||
return -EINVAL;
|
||||
|
||||
inconn = coresight_find_out_connection(parent, csdev);
|
||||
outconn = coresight_find_out_connection(csdev, child);
|
||||
inconn = coresight_find_out_connection(parent, csdev, source);
|
||||
outconn = coresight_find_out_connection(csdev, child, source);
|
||||
link_subtype = csdev->subtype.link_subtype;
|
||||
|
||||
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && IS_ERR(inconn))
|
||||
@ -273,15 +306,16 @@ static int coresight_enable_link(struct coresight_device *csdev,
|
||||
|
||||
static void coresight_disable_link(struct coresight_device *csdev,
|
||||
struct coresight_device *parent,
|
||||
struct coresight_device *child)
|
||||
struct coresight_device *child,
|
||||
struct coresight_device *source)
|
||||
{
|
||||
struct coresight_connection *inconn, *outconn;
|
||||
|
||||
if (!parent || !child)
|
||||
return;
|
||||
|
||||
inconn = coresight_find_out_connection(parent, csdev);
|
||||
outconn = coresight_find_out_connection(csdev, child);
|
||||
inconn = coresight_find_out_connection(parent, csdev, source);
|
||||
outconn = coresight_find_out_connection(csdev, child, source);
|
||||
|
||||
link_ops(csdev)->disable(csdev, inconn, outconn);
|
||||
}
|
||||
@ -375,7 +409,8 @@ static void coresight_disable_path_from(struct list_head *path,
|
||||
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);
|
||||
coresight_disable_link(csdev, parent, child,
|
||||
coresight_get_source(path));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -418,7 +453,9 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode,
|
||||
u32 type;
|
||||
struct coresight_node *nd;
|
||||
struct coresight_device *csdev, *parent, *child;
|
||||
struct coresight_device *source;
|
||||
|
||||
source = coresight_get_source(path);
|
||||
list_for_each_entry_reverse(nd, path, link) {
|
||||
csdev = nd->csdev;
|
||||
type = csdev->type;
|
||||
@ -456,7 +493,7 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode,
|
||||
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);
|
||||
ret = coresight_enable_link(csdev, parent, child, source);
|
||||
if (ret)
|
||||
goto err;
|
||||
break;
|
||||
@ -619,6 +656,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
|
||||
/**
|
||||
* _coresight_build_path - recursively build a path from a @csdev to a sink.
|
||||
* @csdev: The device to start from.
|
||||
* @source: The trace source device of the path.
|
||||
* @sink: The final sink we want in this path.
|
||||
* @path: The list to add devices to.
|
||||
*
|
||||
@ -628,6 +666,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
|
||||
* the source is the first device and the sink the last one.
|
||||
*/
|
||||
static int _coresight_build_path(struct coresight_device *csdev,
|
||||
struct coresight_device *source,
|
||||
struct coresight_device *sink,
|
||||
struct list_head *path)
|
||||
{
|
||||
@ -641,7 +680,7 @@ static int _coresight_build_path(struct coresight_device *csdev,
|
||||
|
||||
if (coresight_is_percpu_source(csdev) && coresight_is_percpu_sink(sink) &&
|
||||
sink == per_cpu(csdev_sink, source_ops(csdev)->cpu_id(csdev))) {
|
||||
if (_coresight_build_path(sink, sink, path) == 0) {
|
||||
if (_coresight_build_path(sink, source, sink, path) == 0) {
|
||||
found = true;
|
||||
goto out;
|
||||
}
|
||||
@ -652,8 +691,12 @@ static int _coresight_build_path(struct coresight_device *csdev,
|
||||
struct coresight_device *child_dev;
|
||||
|
||||
child_dev = csdev->pdata->out_conns[i]->dest_dev;
|
||||
|
||||
if (coresight_blocks_source(source, csdev->pdata->out_conns[i]))
|
||||
continue;
|
||||
|
||||
if (child_dev &&
|
||||
_coresight_build_path(child_dev, sink, path) == 0) {
|
||||
_coresight_build_path(child_dev, source, sink, path) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@ -698,7 +741,7 @@ struct list_head *coresight_build_path(struct coresight_device *source,
|
||||
|
||||
INIT_LIST_HEAD(path);
|
||||
|
||||
rc = _coresight_build_path(source, sink, path);
|
||||
rc = _coresight_build_path(source, source, sink, path);
|
||||
if (rc) {
|
||||
kfree(path);
|
||||
return ERR_PTR(rc);
|
||||
@ -927,6 +970,16 @@ static int coresight_orphan_match(struct device *dev, void *data)
|
||||
for (i = 0; i < src_csdev->pdata->nr_outconns; i++) {
|
||||
conn = src_csdev->pdata->out_conns[i];
|
||||
|
||||
/* Fix filter source device before skip the port */
|
||||
if (conn->filter_src_fwnode && !conn->filter_src_dev) {
|
||||
if (dst_csdev &&
|
||||
(conn->filter_src_fwnode == dst_csdev->dev.fwnode) &&
|
||||
!WARN_ON_ONCE(!coresight_is_device_source(dst_csdev)))
|
||||
conn->filter_src_dev = dst_csdev;
|
||||
else
|
||||
still_orphan = true;
|
||||
}
|
||||
|
||||
/* Skip the port if it's already connected. */
|
||||
if (conn->dest_dev)
|
||||
continue;
|
||||
@ -977,18 +1030,40 @@ static int coresight_fixup_orphan_conns(struct coresight_device *csdev)
|
||||
csdev, coresight_orphan_match);
|
||||
}
|
||||
|
||||
static int coresight_clear_filter_source(struct device *dev, void *data)
|
||||
{
|
||||
int i;
|
||||
struct coresight_device *source = data;
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
|
||||
if (csdev->pdata->out_conns[i]->filter_src_dev == source)
|
||||
csdev->pdata->out_conns[i]->filter_src_dev = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* coresight_remove_conns - Remove other device's references to this device */
|
||||
static void coresight_remove_conns(struct coresight_device *csdev)
|
||||
{
|
||||
int i, j;
|
||||
struct coresight_connection *conn;
|
||||
|
||||
if (coresight_is_device_source(csdev))
|
||||
bus_for_each_dev(&coresight_bustype, NULL, csdev,
|
||||
coresight_clear_filter_source);
|
||||
|
||||
/*
|
||||
* Remove the input connection references from the destination device
|
||||
* for each output connection.
|
||||
*/
|
||||
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
|
||||
conn = csdev->pdata->out_conns[i];
|
||||
if (conn->filter_src_fwnode) {
|
||||
conn->filter_src_dev = NULL;
|
||||
fwnode_handle_put(conn->filter_src_fwnode);
|
||||
}
|
||||
|
||||
if (!conn->dest_dev)
|
||||
continue;
|
||||
|
||||
|
@ -11,10 +11,12 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "coresight-priv.h"
|
||||
#include "coresight-trace-id.h"
|
||||
|
||||
struct dummy_drvdata {
|
||||
struct device *dev;
|
||||
struct coresight_device *csdev;
|
||||
u8 traceid;
|
||||
};
|
||||
|
||||
DEFINE_CORESIGHT_DEVLIST(source_devs, "dummy_source");
|
||||
@ -72,6 +74,32 @@ static const struct coresight_ops dummy_sink_cs_ops = {
|
||||
.sink_ops = &dummy_sink_ops,
|
||||
};
|
||||
|
||||
/* User can get the trace id of dummy source from this node. */
|
||||
static ssize_t traceid_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
unsigned long val;
|
||||
struct dummy_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
val = drvdata->traceid;
|
||||
return sysfs_emit(buf, "%#lx\n", val);
|
||||
}
|
||||
static DEVICE_ATTR_RO(traceid);
|
||||
|
||||
static struct attribute *coresight_dummy_attrs[] = {
|
||||
&dev_attr_traceid.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group coresight_dummy_group = {
|
||||
.attrs = coresight_dummy_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *coresight_dummy_groups[] = {
|
||||
&coresight_dummy_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int dummy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -79,6 +107,11 @@ static int dummy_probe(struct platform_device *pdev)
|
||||
struct coresight_platform_data *pdata;
|
||||
struct dummy_drvdata *drvdata;
|
||||
struct coresight_desc desc = { 0 };
|
||||
int ret = 0, trace_id = 0;
|
||||
|
||||
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
|
||||
if (!drvdata)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_device_is_compatible(node, "arm,coresight-dummy-source")) {
|
||||
|
||||
@ -90,6 +123,26 @@ static int dummy_probe(struct platform_device *pdev)
|
||||
desc.subtype.source_subtype =
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS;
|
||||
desc.ops = &dummy_source_cs_ops;
|
||||
desc.groups = coresight_dummy_groups;
|
||||
|
||||
ret = coresight_get_static_trace_id(dev, &trace_id);
|
||||
if (!ret) {
|
||||
/* Get the static id if id is set in device tree. */
|
||||
ret = coresight_trace_id_get_static_system_id(trace_id);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Fail to get static id.\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
/* Get next available id if id is not set in device tree. */
|
||||
trace_id = coresight_trace_id_get_system_id();
|
||||
if (trace_id < 0) {
|
||||
ret = trace_id;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
drvdata->traceid = (u8)trace_id;
|
||||
|
||||
} else if (of_device_is_compatible(node, "arm,coresight-dummy-sink")) {
|
||||
desc.name = coresight_alloc_device_name(&sink_devs, dev);
|
||||
if (!desc.name)
|
||||
@ -104,27 +157,35 @@ static int dummy_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
pdata = coresight_get_platform_data(dev);
|
||||
if (IS_ERR(pdata))
|
||||
return PTR_ERR(pdata);
|
||||
if (IS_ERR(pdata)) {
|
||||
ret = PTR_ERR(pdata);
|
||||
goto free_id;
|
||||
}
|
||||
pdev->dev.platform_data = pdata;
|
||||
|
||||
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
|
||||
if (!drvdata)
|
||||
return -ENOMEM;
|
||||
|
||||
drvdata->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, drvdata);
|
||||
|
||||
desc.pdata = pdev->dev.platform_data;
|
||||
desc.dev = &pdev->dev;
|
||||
drvdata->csdev = coresight_register(&desc);
|
||||
if (IS_ERR(drvdata->csdev))
|
||||
return PTR_ERR(drvdata->csdev);
|
||||
if (IS_ERR(drvdata->csdev)) {
|
||||
ret = PTR_ERR(drvdata->csdev);
|
||||
goto free_id;
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
dev_dbg(dev, "Dummy device initialized\n");
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
goto out;
|
||||
|
||||
free_id:
|
||||
if (IS_VALID_CS_TRACE_ID(drvdata->traceid))
|
||||
coresight_trace_id_put_system_id(drvdata->traceid);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dummy_remove(struct platform_device *pdev)
|
||||
@ -132,6 +193,8 @@ static void dummy_remove(struct platform_device *pdev)
|
||||
struct dummy_drvdata *drvdata = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
if (IS_VALID_CS_TRACE_ID(drvdata->traceid))
|
||||
coresight_trace_id_put_system_id(drvdata->traceid);
|
||||
pm_runtime_disable(dev);
|
||||
coresight_unregister(drvdata->csdev);
|
||||
}
|
||||
|
@ -86,14 +86,14 @@ static int funnel_enable(struct coresight_device *csdev,
|
||||
bool first_enable = false;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
if (atomic_read(&in->dest_refcnt) == 0) {
|
||||
if (in->dest_refcnt == 0) {
|
||||
if (drvdata->base)
|
||||
rc = dynamic_funnel_enable_hw(drvdata, in->dest_port);
|
||||
if (!rc)
|
||||
first_enable = true;
|
||||
}
|
||||
if (!rc)
|
||||
atomic_inc(&in->dest_refcnt);
|
||||
in->dest_refcnt++;
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
|
||||
if (first_enable)
|
||||
@ -130,7 +130,7 @@ static void funnel_disable(struct coresight_device *csdev,
|
||||
bool last_disable = false;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
if (atomic_dec_return(&in->dest_refcnt) == 0) {
|
||||
if (--in->dest_refcnt == 0) {
|
||||
if (drvdata->base)
|
||||
dynamic_funnel_disable_hw(drvdata, in->dest_port);
|
||||
last_disable = true;
|
||||
|
@ -243,6 +243,27 @@ static int of_coresight_parse_endpoint(struct device *dev,
|
||||
conn.dest_fwnode = fwnode_handle_get(rdev_fwnode);
|
||||
conn.dest_port = rendpoint.port;
|
||||
|
||||
/*
|
||||
* Get the firmware node of the filter source through the
|
||||
* reference. This could be used to filter the source in
|
||||
* building path.
|
||||
*/
|
||||
conn.filter_src_fwnode =
|
||||
fwnode_find_reference(&ep->fwnode, "filter-source", 0);
|
||||
if (IS_ERR(conn.filter_src_fwnode)) {
|
||||
conn.filter_src_fwnode = NULL;
|
||||
} else {
|
||||
conn.filter_src_dev =
|
||||
coresight_find_csdev_by_fwnode(conn.filter_src_fwnode);
|
||||
if (conn.filter_src_dev &&
|
||||
!coresight_is_device_source(conn.filter_src_dev)) {
|
||||
dev_warn(dev, "port %d: Filter handle is not a trace source : %s\n",
|
||||
conn.src_port, dev_name(&conn.filter_src_dev->dev));
|
||||
conn.filter_src_dev = NULL;
|
||||
conn.filter_src_fwnode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
new_conn = coresight_add_out_conn(dev, pdata, &conn);
|
||||
if (IS_ERR_VALUE(new_conn)) {
|
||||
fwnode_handle_put(conn.dest_fwnode);
|
||||
@ -796,6 +817,12 @@ int coresight_get_cpu(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_get_cpu);
|
||||
|
||||
int coresight_get_static_trace_id(struct device *dev, u32 *id)
|
||||
{
|
||||
return fwnode_property_read_u32(dev_fwnode(dev), "arm,static-trace-id", id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_get_static_trace_id);
|
||||
|
||||
struct coresight_platform_data *
|
||||
coresight_get_platform_data(struct device *dev)
|
||||
{
|
||||
|
@ -126,7 +126,7 @@ static int replicator_enable(struct coresight_device *csdev,
|
||||
bool first_enable = false;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
if (atomic_read(&out->src_refcnt) == 0) {
|
||||
if (out->src_refcnt == 0) {
|
||||
if (drvdata->base)
|
||||
rc = dynamic_replicator_enable(drvdata, in->dest_port,
|
||||
out->src_port);
|
||||
@ -134,7 +134,7 @@ static int replicator_enable(struct coresight_device *csdev,
|
||||
first_enable = true;
|
||||
}
|
||||
if (!rc)
|
||||
atomic_inc(&out->src_refcnt);
|
||||
out->src_refcnt++;
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
|
||||
if (first_enable)
|
||||
@ -180,7 +180,7 @@ static void replicator_disable(struct coresight_device *csdev,
|
||||
bool last_disable = false;
|
||||
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
if (atomic_dec_return(&out->src_refcnt) == 0) {
|
||||
if (--out->src_refcnt == 0) {
|
||||
if (drvdata->base)
|
||||
dynamic_replicator_disable(drvdata, in->dest_port,
|
||||
out->src_port);
|
||||
|
@ -24,7 +24,7 @@ DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda");
|
||||
|
||||
static bool coresight_device_is_tpdm(struct coresight_device *csdev)
|
||||
{
|
||||
return (csdev->type == CORESIGHT_DEV_TYPE_SOURCE) &&
|
||||
return (coresight_is_device_source(csdev)) &&
|
||||
(csdev->subtype.source_subtype ==
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM);
|
||||
}
|
||||
@ -110,6 +110,16 @@ static int tpda_get_element_size(struct tpda_drvdata *drvdata,
|
||||
csdev->pdata->in_conns[i]->dest_port != inport)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If this port has a hardcoded filter, use the source
|
||||
* device directly.
|
||||
*/
|
||||
if (csdev->pdata->in_conns[i]->filter_src_fwnode) {
|
||||
in = csdev->pdata->in_conns[i]->filter_src_dev;
|
||||
if (!in)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (coresight_device_is_tpdm(in)) {
|
||||
if (drvdata->dsb_esize || drvdata->cmb_esize)
|
||||
return -EEXIST;
|
||||
@ -124,7 +134,6 @@ static int tpda_get_element_size(struct tpda_drvdata *drvdata,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -190,10 +199,10 @@ static int tpda_enable(struct coresight_device *csdev,
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
if (atomic_read(&in->dest_refcnt) == 0) {
|
||||
if (in->dest_refcnt == 0) {
|
||||
ret = __tpda_enable(drvdata, in->dest_port);
|
||||
if (!ret) {
|
||||
atomic_inc(&in->dest_refcnt);
|
||||
in->dest_refcnt++;
|
||||
csdev->refcnt++;
|
||||
dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
|
||||
}
|
||||
@ -223,7 +232,7 @@ static void tpda_disable(struct coresight_device *csdev,
|
||||
struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
if (atomic_dec_return(&in->dest_refcnt) == 0) {
|
||||
if (--in->dest_refcnt == 0) {
|
||||
__tpda_disable(drvdata, in->dest_port);
|
||||
csdev->refcnt--;
|
||||
}
|
||||
|
@ -640,8 +640,7 @@ static ssize_t dsb_mode_store(struct device *dev,
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val;
|
||||
|
||||
if ((kstrtoul(buf, 0, &val)) || (val < 0) ||
|
||||
(val & ~TPDM_DSB_MODE_MASK))
|
||||
if ((kstrtoul(buf, 0, &val)) || (val & ~TPDM_DSB_MODE_MASK))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
@ -1308,8 +1307,8 @@ static void tpdm_remove(struct amba_device *adev)
|
||||
*/
|
||||
static struct amba_id tpdm_ids[] = {
|
||||
{
|
||||
.id = 0x000f0e00,
|
||||
.mask = 0x000fff00,
|
||||
.id = 0x001f0e00,
|
||||
.mask = 0x00ffff00,
|
||||
},
|
||||
{ 0, 0, NULL },
|
||||
};
|
||||
|
@ -12,6 +12,12 @@
|
||||
|
||||
#include "coresight-trace-id.h"
|
||||
|
||||
enum trace_id_flags {
|
||||
TRACE_ID_ANY = 0x0,
|
||||
TRACE_ID_PREFER_ODD = 0x1,
|
||||
TRACE_ID_REQ_STATIC = 0x2,
|
||||
};
|
||||
|
||||
/* Default trace ID map. Used in sysfs mode and for system sources */
|
||||
static DEFINE_PER_CPU(atomic_t, id_map_default_cpu_ids) = ATOMIC_INIT(0);
|
||||
static struct coresight_trace_id_map id_map_default = {
|
||||
@ -74,21 +80,25 @@ static int coresight_trace_id_find_odd_id(struct coresight_trace_id_map *id_map)
|
||||
* Otherwise allocate next available ID.
|
||||
*/
|
||||
static int coresight_trace_id_alloc_new_id(struct coresight_trace_id_map *id_map,
|
||||
int preferred_id, bool prefer_odd_id)
|
||||
int preferred_id, unsigned int flags)
|
||||
{
|
||||
int id = 0;
|
||||
|
||||
/* for backwards compatibility, cpu IDs may use preferred value */
|
||||
if (IS_VALID_CS_TRACE_ID(preferred_id) &&
|
||||
!test_bit(preferred_id, id_map->used_ids)) {
|
||||
id = preferred_id;
|
||||
goto trace_id_allocated;
|
||||
} else if (prefer_odd_id) {
|
||||
if (IS_VALID_CS_TRACE_ID(preferred_id)) {
|
||||
if (!test_bit(preferred_id, id_map->used_ids)) {
|
||||
id = preferred_id;
|
||||
goto trace_id_allocated;
|
||||
} else if (flags & TRACE_ID_REQ_STATIC)
|
||||
return -EBUSY;
|
||||
} else if (flags & TRACE_ID_PREFER_ODD) {
|
||||
/* may use odd ids to avoid preferred legacy cpu IDs */
|
||||
id = coresight_trace_id_find_odd_id(id_map);
|
||||
if (id)
|
||||
goto trace_id_allocated;
|
||||
}
|
||||
} else if (!IS_VALID_CS_TRACE_ID(preferred_id) &&
|
||||
(flags & TRACE_ID_REQ_STATIC))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* skip reserved bit 0, look at bitmap length of
|
||||
@ -153,7 +163,7 @@ static int _coresight_trace_id_get_cpu_id(int cpu, struct coresight_trace_id_map
|
||||
*/
|
||||
id = coresight_trace_id_alloc_new_id(id_map,
|
||||
CORESIGHT_LEGACY_CPU_TRACE_ID(cpu),
|
||||
false);
|
||||
TRACE_ID_ANY);
|
||||
if (!IS_VALID_CS_TRACE_ID(id))
|
||||
goto get_cpu_id_out_unlock;
|
||||
|
||||
@ -188,14 +198,14 @@ static void _coresight_trace_id_put_cpu_id(int cpu, struct coresight_trace_id_ma
|
||||
DUMP_ID_MAP(id_map);
|
||||
}
|
||||
|
||||
static int coresight_trace_id_map_get_system_id(struct coresight_trace_id_map *id_map)
|
||||
static int coresight_trace_id_map_get_system_id(struct coresight_trace_id_map *id_map,
|
||||
int preferred_id, unsigned int traceid_flags)
|
||||
{
|
||||
unsigned long flags;
|
||||
int id;
|
||||
|
||||
spin_lock_irqsave(&id_map->lock, flags);
|
||||
/* prefer odd IDs for system components to avoid legacy CPU IDS */
|
||||
id = coresight_trace_id_alloc_new_id(id_map, 0, true);
|
||||
id = coresight_trace_id_alloc_new_id(id_map, preferred_id, traceid_flags);
|
||||
spin_unlock_irqrestore(&id_map->lock, flags);
|
||||
|
||||
DUMP_ID(id);
|
||||
@ -255,10 +265,19 @@ EXPORT_SYMBOL_GPL(coresight_trace_id_read_cpu_id_map);
|
||||
|
||||
int coresight_trace_id_get_system_id(void)
|
||||
{
|
||||
return coresight_trace_id_map_get_system_id(&id_map_default);
|
||||
/* prefer odd IDs for system components to avoid legacy CPU IDS */
|
||||
return coresight_trace_id_map_get_system_id(&id_map_default, 0,
|
||||
TRACE_ID_PREFER_ODD);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_trace_id_get_system_id);
|
||||
|
||||
int coresight_trace_id_get_static_system_id(int trace_id)
|
||||
{
|
||||
return coresight_trace_id_map_get_system_id(&id_map_default,
|
||||
trace_id, TRACE_ID_REQ_STATIC);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_trace_id_get_static_system_id);
|
||||
|
||||
void coresight_trace_id_put_system_id(int id)
|
||||
{
|
||||
coresight_trace_id_map_put_system_id(&id_map_default, id);
|
||||
|
@ -116,6 +116,15 @@ int coresight_trace_id_read_cpu_id_map(int cpu, struct coresight_trace_id_map *i
|
||||
*/
|
||||
int coresight_trace_id_get_system_id(void);
|
||||
|
||||
/**
|
||||
* Allocate a CoreSight static trace ID for a system component.
|
||||
*
|
||||
* Used to allocate static IDs for system trace sources such as dummy source.
|
||||
*
|
||||
* return: Trace ID or -EINVAL if allocation is impossible.
|
||||
*/
|
||||
int coresight_trace_id_get_static_system_id(int id);
|
||||
|
||||
/**
|
||||
* Release an allocated system trace ID.
|
||||
*
|
||||
|
@ -172,6 +172,9 @@ struct coresight_desc {
|
||||
* @dest_dev: a @coresight_device representation of the component
|
||||
connected to @src_port. NULL until the device is created
|
||||
* @link: Representation of the connection as a sysfs link.
|
||||
* @filter_src_fwnode: filter source component's fwnode handle.
|
||||
* @filter_src_dev: a @coresight_device representation of the component that
|
||||
needs to be filtered.
|
||||
*
|
||||
* The full connection structure looks like this, where in_conns store
|
||||
* references to same connection as the source device's out_conns.
|
||||
@ -200,8 +203,10 @@ struct coresight_connection {
|
||||
struct coresight_device *dest_dev;
|
||||
struct coresight_sysfs_link *link;
|
||||
struct coresight_device *src_dev;
|
||||
atomic_t src_refcnt;
|
||||
atomic_t dest_refcnt;
|
||||
struct fwnode_handle *filter_src_fwnode;
|
||||
struct coresight_device *filter_src_dev;
|
||||
int src_refcnt;
|
||||
int dest_refcnt;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -588,9 +593,14 @@ static inline void csdev_access_write64(struct csdev_access *csa, u64 val, u32 o
|
||||
}
|
||||
#endif /* CONFIG_64BIT */
|
||||
|
||||
static inline bool coresight_is_device_source(struct coresight_device *csdev)
|
||||
{
|
||||
return csdev && (csdev->type == CORESIGHT_DEV_TYPE_SOURCE);
|
||||
}
|
||||
|
||||
static inline bool coresight_is_percpu_source(struct coresight_device *csdev)
|
||||
{
|
||||
return csdev && (csdev->type == CORESIGHT_DEV_TYPE_SOURCE) &&
|
||||
return csdev && coresight_is_device_source(csdev) &&
|
||||
(csdev->subtype.source_subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_PROC);
|
||||
}
|
||||
|
||||
@ -662,6 +672,7 @@ void coresight_relaxed_write64(struct coresight_device *csdev,
|
||||
void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset);
|
||||
|
||||
extern int coresight_get_cpu(struct device *dev);
|
||||
extern int coresight_get_static_trace_id(struct device *dev, u32 *id);
|
||||
|
||||
struct coresight_platform_data *coresight_get_platform_data(struct device *dev);
|
||||
struct coresight_connection *
|
||||
|
Loading…
Reference in New Issue
Block a user