diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-dummy-source b/Documentation/ABI/testing/sysfs-bus-coresight-devices-dummy-source new file mode 100644 index 000000000000..0830661ef656 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-dummy-source @@ -0,0 +1,15 @@ +What: /sys/bus/coresight/devices/dummy_source/enable_source +Date: Dec 2024 +KernelVersion: 6.14 +Contact: Mao Jinlong +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/traceid +Date: Dec 2024 +KernelVersion: 6.14 +Contact: Mao Jinlong +Description: (R) Show the trace ID that will appear in the trace stream + coming from this trace entity. diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-dummy-source.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-dummy-source.yaml index 04a8c37b4aff..742dc4e25d3b 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-dummy-source.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-dummy-source.yaml @@ -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 diff --git a/Documentation/devicetree/bindings/arm/arm,coresight-static-replicator.yaml b/Documentation/devicetree/bindings/arm/arm,coresight-static-replicator.yaml index 1892a091ac35..a6f793ea03b6 100644 --- a/Documentation/devicetree/bindings/arm/arm,coresight-static-replicator.yaml +++ b/Documentation/devicetree/bindings/arm/arm,coresight-static-replicator.yaml @@ -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>; }; }; }; diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index ea38ecf26fcb..0a9380350fb5 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -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; diff --git a/drivers/hwtracing/coresight/coresight-dummy.c b/drivers/hwtracing/coresight/coresight-dummy.c index 02ef2b945a0c..9be53be8964b 100644 --- a/drivers/hwtracing/coresight/coresight-dummy.c +++ b/drivers/hwtracing/coresight/coresight-dummy.c @@ -11,10 +11,12 @@ #include #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); } diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 33efe1acbef7..8faf51469bb8 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -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; diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index 64e171eaad82..8192ba3279f0 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -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) { diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 0fba87de6d1a..a1181c9048c0 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -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); diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index bfca103f9f84..189a4abc2561 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -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--; } diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index b7d99e91ab84..c38f9701665e 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -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 }, }; diff --git a/drivers/hwtracing/coresight/coresight-trace-id.c b/drivers/hwtracing/coresight/coresight-trace-id.c index d98e12cb30ec..378af743be45 100644 --- a/drivers/hwtracing/coresight/coresight-trace-id.c +++ b/drivers/hwtracing/coresight/coresight-trace-id.c @@ -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); diff --git a/drivers/hwtracing/coresight/coresight-trace-id.h b/drivers/hwtracing/coresight/coresight-trace-id.h index 9aae50a553ca..db68e1ec56b6 100644 --- a/drivers/hwtracing/coresight/coresight-trace-id.h +++ b/drivers/hwtracing/coresight/coresight-trace-id.h @@ -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. * diff --git a/include/linux/coresight.h b/include/linux/coresight.h index c13342594278..17276965ff1d 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -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 *