2023-04-04 16:00:39

by James Clark

[permalink] [raw]
Subject: [PATCH v5 00/13] coresight: Fix CTI module refcount leak by making it a helper device

Changes since v4:

* Update commit message on patch 1
* Drop previous change that added lockdep checks to coresight_add_helper()
because they are already in mutex_lock(). But keep extra comment.
* Check for allocation failure in coresight_add_out_conn()

------------------

Changes since v3:

* Put connection loss fix at the beginning so that it can be backported
* Replace coresight_find_link_{x}() with coresight_find_out_connection()
* Reorder coresight_enable_source() arguments for consistency
* Add source and destination reference counts so that two link devices
connected together don't clash
* Add coresight_is_helper()
* Fix overwriting csdev bug in coresight_orphan_match()
* Don't clear conns[i]->dest_fwnode in coresight_remove_conns() in case
it's used again
* Use dev instead of adev->dev for devmem allocation in
acpi_coresight_parse_graph() so that it's consistent with DT mode and
doesn't cause a warning on free.
* Rename coresight_add_helper_mutex() -> coresight_add_helper()
* Ensure coresight_mutex isn't already held in coresight_add_helper()
* Return new connection from coresight_add_out_conn()
* Comment and formatting improvements

------------------

Changes since v2:

* Make out_conns array contiguous instead of sparse which simplifies
filling and using it. New connections are always added to the end
* Store pointers to individual connection objects so that they can be
shared between inputs and outputs
* Fix an existing bug where connection info was lost when unloading a
device
* Simplify connection fixup functions. Now the orphan mechanism is used
for inputs in the same way as outputs to guarantee that all
connections have both an input and an output set
* Use input connections to disconnect devices on unload instead of
iterating through them all
* Make refcount a property of the connection rather than use it's own
array based on the number of inputs and outputs
* Fix a bug in v2 where helpers attached to the source device weren't
disabled because coresight-etm-perf.c was making a raw call to
disable rather than using a helper.
* Change names of connection members to make direction explicit now
that the connection is shared between input and outputs

------------------

Changes since v1:

* Don't dereference handle in tmc_etr_get_buffer() when not in perf mode.
* Fix some W=1 warnings
* Add a commit to rename child/output in terms of local/remote

-------------------

Currently there is a refcount leak in CTI when using system wide mode
or tracing multithreaded applications. See the last commit for a
reproducer. This prevents the module from being unloaded.

Historically there have been a few issues and fixes attempted around
here which have resulted in some extra logic and a member to keep
track of CTI being enabled 'struct coresight_device->ect_enabled'.
The fix in commit 665c157e0204 ("coresight: cti: Fix hang in
cti_disable_hw()") was also related to CTI having its own
enable/disable path which came later than other devices.

If we make CTI a helper device and enable helper devices adjacent to
the path we get very similar enable/disable behavior to now, but with
more reuse of the existing reference counting logic in the coresight
core code. This also affects CATU which can have a little bit of
its hard coded enable/disable code removed.

Enabling CATU on the generic path does require that input connections
are tracked so that it can get its associated ETR buffer.

Applies to coresight/next (197b6b60ae7b) but also requires the
realloc_array patch here [1].

Also available in full here [2].

[1]: https://lore.kernel.org/linux-arm-kernel/[email protected]/
[2]: https://gitlab.arm.com/linux-arm/linux-jc/-/tree/james-cs-cti-module-refcount-fix-v5


James Clark (13):
coresight: Fix loss of connection info when a module is unloaded
coresight: Use enum type for cs_mode wherever possible
coresight: Change name of pdata->conns
coresight: Rename nr_outports to nr_outconns
coresight: Rename connection members to make the direction explicit
coresight: Dynamically add connections
coresight: Store pointers to connections rather than an array of them
coresight: Simplify connection fixup mechanism
coresight: Store in-connections as well as out-connections
coresight: Make refcount a property of the connection
coresight: Refactor out buffer allocation function for ETR
coresight: Enable and disable helper devices adjacent to the path
coresight: Fix CTI module refcount leak by making it a helper device

drivers/hwtracing/coresight/coresight-catu.c | 21 +-
drivers/hwtracing/coresight/coresight-core.c | 593 ++++++++++--------
.../hwtracing/coresight/coresight-cti-core.c | 52 +-
.../hwtracing/coresight/coresight-cti-sysfs.c | 4 +-
drivers/hwtracing/coresight/coresight-cti.h | 4 +-
drivers/hwtracing/coresight/coresight-etb10.c | 13 +-
.../hwtracing/coresight/coresight-etm-perf.c | 4 +-
.../coresight/coresight-etm3x-core.c | 6 +-
.../coresight/coresight-etm4x-core.c | 6 +-
.../hwtracing/coresight/coresight-funnel.c | 26 +-
.../hwtracing/coresight/coresight-platform.c | 269 ++++----
drivers/hwtracing/coresight/coresight-priv.h | 17 +-
.../coresight/coresight-replicator.c | 23 +-
drivers/hwtracing/coresight/coresight-stm.c | 6 +-
drivers/hwtracing/coresight/coresight-sysfs.c | 17 +-
.../hwtracing/coresight/coresight-tmc-etf.c | 26 +-
.../hwtracing/coresight/coresight-tmc-etr.c | 110 ++--
drivers/hwtracing/coresight/coresight-tmc.h | 2 +
drivers/hwtracing/coresight/coresight-tpda.c | 23 +-
drivers/hwtracing/coresight/coresight-tpdm.c | 4 +-
drivers/hwtracing/coresight/coresight-tpiu.c | 7 +-
drivers/hwtracing/coresight/coresight-trbe.c | 3 +-
drivers/hwtracing/coresight/ultrasoc-smb.c | 11 +-
drivers/hwtracing/coresight/ultrasoc-smb.h | 2 +-
include/linux/coresight.h | 127 ++--
25 files changed, 708 insertions(+), 668 deletions(-)

--
2.34.1


2023-04-04 16:00:40

by James Clark

[permalink] [raw]
Subject: [PATCH v5 01/13] coresight: Fix loss of connection info when a module is unloaded

child_fwnode should be a read only property based on the DT or ACPI. If
it's cleared on the parent device when a child is unloaded, then when
the child is loaded again the connection won't be remade.

child_dev should be cleared instead which signifies that the connection
should be remade when the child_fwnode registers a new coresight_device.

Similarly the reference count shouldn't be decremented as long as the
parent device exists. The correct place to drop the reference is in
coresight_release_platform_data() which is already done.

Reproducible on Juno with the following steps:

# load all coresight modules.
$ cd /sys/bus/coresight/devices/
$ echo 1 > tmc_etr0/enable_sink
$ echo 1 > etm0/enable_source
# Works fine ^

$ echo 0 > etm0/enable_source
$ rmmod coresight-funnel
$ modprobe coresight-funnel
$ echo 1 > etm0/enable_source
-bash: echo: write error: Invalid argument

Fixes: 37ea1ffddffa ("coresight: Use fwnode handle instead of device names")
Fixes: 2af89ebacf29 ("coresight: Clear the connection field properly")
Tested-by: Suzuki K Poulose <[email protected]>
Signed-off-by: James Clark <[email protected]>
---
drivers/hwtracing/coresight/coresight-core.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index d3bf82c0de1d..5733294ce5cd 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -1419,13 +1419,8 @@ static int coresight_remove_match(struct device *dev, void *data)
if (csdev->dev.fwnode == conn->child_fwnode) {
iterator->orphan = true;
coresight_remove_links(iterator, conn);
- /*
- * Drop the reference to the handle for the remote
- * device acquired in parsing the connections from
- * platform data.
- */
- fwnode_handle_put(conn->child_fwnode);
- conn->child_fwnode = NULL;
+
+ conn->child_dev = NULL;
/* No need to continue */
break;
}
--
2.34.1

2023-04-04 16:00:42

by James Clark

[permalink] [raw]
Subject: [PATCH v5 02/13] coresight: Use enum type for cs_mode wherever possible

mode is stored as a local_t, but it is also passed around a lot as a
plain u32, so use the correct type wherever local_t isn't currently
used. This helps a little bit with readability.

Reviewed-by: Mike Leach <[email protected]>
Signed-off-by: James Clark <[email protected]>
---
drivers/hwtracing/coresight/coresight-core.c | 7 ++++---
drivers/hwtracing/coresight/coresight-etb10.c | 3 ++-
drivers/hwtracing/coresight/coresight-etm3x-core.c | 6 +++---
drivers/hwtracing/coresight/coresight-etm4x-core.c | 6 +++---
drivers/hwtracing/coresight/coresight-priv.h | 9 ++-------
drivers/hwtracing/coresight/coresight-stm.c | 6 +++---
drivers/hwtracing/coresight/coresight-tmc-etf.c | 2 +-
drivers/hwtracing/coresight/coresight-tmc-etr.c | 7 +++----
drivers/hwtracing/coresight/coresight-tpdm.c | 4 ++--
drivers/hwtracing/coresight/coresight-tpiu.c | 3 ++-
drivers/hwtracing/coresight/coresight-trbe.c | 3 ++-
drivers/hwtracing/coresight/ultrasoc-smb.c | 3 ++-
drivers/hwtracing/coresight/ultrasoc-smb.h | 2 +-
include/linux/coresight.h | 13 ++++++++++---
14 files changed, 40 insertions(+), 34 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 5733294ce5cd..c891078dffc6 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -308,7 +308,7 @@ void coresight_set_assoc_ectdev_mutex(struct coresight_device *csdev,
EXPORT_SYMBOL_GPL(coresight_set_assoc_ectdev_mutex);

static int coresight_enable_sink(struct coresight_device *csdev,
- u32 mode, void *data)
+ enum cs_mode mode, void *data)
{
int ret;

@@ -416,7 +416,8 @@ static void coresight_disable_link(struct coresight_device *csdev,
csdev->enable = false;
}

-static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
+static int coresight_enable_source(struct coresight_device *csdev,
+ enum cs_mode mode)
{
int ret;

@@ -516,7 +517,7 @@ void coresight_disable_path(struct list_head *path)
}
EXPORT_SYMBOL_GPL(coresight_disable_path);

-int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data)
+int coresight_enable_path(struct list_head *path, enum cs_mode mode, void *sink_data)
{

int ret = 0;
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index 8aa6e4f83e42..eb99c445015a 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c
@@ -225,7 +225,8 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
return ret;
}

-static int etb_enable(struct coresight_device *csdev, u32 mode, void *data)
+static int etb_enable(struct coresight_device *csdev, enum cs_mode mode,
+ void *data)
{
int ret;

diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index afc57195ee52..116a91d90ac2 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -552,8 +552,8 @@ static int etm_enable_sysfs(struct coresight_device *csdev)
return ret;
}

-static int etm_enable(struct coresight_device *csdev,
- struct perf_event *event, u32 mode)
+static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
+ enum cs_mode mode)
{
int ret;
u32 val;
@@ -671,7 +671,7 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
static void etm_disable(struct coresight_device *csdev,
struct perf_event *event)
{
- u32 mode;
+ enum cs_mode mode;
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);

/*
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 1ea8f173cca0..2ff4c42ea688 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -822,8 +822,8 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
return ret;
}

-static int etm4_enable(struct coresight_device *csdev,
- struct perf_event *event, u32 mode)
+static int etm4_enable(struct coresight_device *csdev, struct perf_event *event,
+ enum cs_mode mode)
{
int ret;
u32 val;
@@ -989,7 +989,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
static void etm4_disable(struct coresight_device *csdev,
struct perf_event *event)
{
- u32 mode;
+ enum cs_mode mode;
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);

/*
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 595ce5862056..788ff19c60f6 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -82,12 +82,6 @@ enum etm_addr_type {
ETM_ADDR_TYPE_STOP,
};

-enum cs_mode {
- CS_MODE_DISABLED,
- CS_MODE_SYSFS,
- CS_MODE_PERF,
-};
-
/**
* struct cs_buffer - keep track of a recording session' specifics
* @cur: index of the current buffer
@@ -133,7 +127,8 @@ static inline void CS_UNLOCK(void __iomem *addr)
}

void coresight_disable_path(struct list_head *path);
-int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data);
+int coresight_enable_path(struct list_head *path, enum cs_mode mode,
+ void *sink_data);
struct coresight_device *coresight_get_sink(struct list_head *path);
struct coresight_device *
coresight_get_enabled_sink(struct coresight_device *source);
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index 66a614c5492c..a1c27c901ad1 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -119,7 +119,7 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
* @spinlock: only one at a time pls.
* @chs: the channels accociated to this STM.
* @stm: structure associated to the generic STM interface.
- * @mode: this tracer's mode, i.e sysFS, or disabled.
+ * @mode: this tracer's mode (enum cs_mode), i.e sysFS, or disabled.
* @traceid: value of the current ID for this component.
* @write_bytes: Maximus bytes this STM can write at a time.
* @stmsper: settings for register STMSPER.
@@ -192,8 +192,8 @@ static void stm_enable_hw(struct stm_drvdata *drvdata)
CS_LOCK(drvdata->base);
}

-static int stm_enable(struct coresight_device *csdev,
- struct perf_event *event, u32 mode)
+static int stm_enable(struct coresight_device *csdev, struct perf_event *event,
+ enum cs_mode mode)
{
u32 val;
struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 0ab1f73c2d06..14d3c1472455 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -302,7 +302,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
}

static int tmc_enable_etf_sink(struct coresight_device *csdev,
- u32 mode, void *data)
+ enum cs_mode mode, void *data)
{
int ret;

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 918d461fcf4a..ed589cfff1b5 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1666,17 +1666,16 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
}

static int tmc_enable_etr_sink(struct coresight_device *csdev,
- u32 mode, void *data)
+ enum cs_mode mode, void *data)
{
switch (mode) {
case CS_MODE_SYSFS:
return tmc_enable_etr_sink_sysfs(csdev);
case CS_MODE_PERF:
return tmc_enable_etr_sink_perf(csdev, data);
+ default:
+ return -EINVAL;
}
-
- /* We shouldn't be here */
- return -EINVAL;
}

static int tmc_disable_etr_sink(struct coresight_device *csdev)
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index 9479a5e8c672..f4854af0431e 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -42,8 +42,8 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata)
CS_LOCK(drvdata->base);
}

-static int tpdm_enable(struct coresight_device *csdev,
- struct perf_event *event, u32 mode)
+static int tpdm_enable(struct coresight_device *csdev, struct perf_event *event,
+ enum cs_mode mode)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);

diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c
index 34d37abd2c8d..b0179f761c98 100644
--- a/drivers/hwtracing/coresight/coresight-tpiu.c
+++ b/drivers/hwtracing/coresight/coresight-tpiu.c
@@ -69,7 +69,8 @@ static void tpiu_enable_hw(struct csdev_access *csa)
CS_LOCK(csa->base);
}

-static int tpiu_enable(struct coresight_device *csdev, u32 mode, void *__unused)
+static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode,
+ void *__unused)
{
tpiu_enable_hw(&csdev->access);
atomic_inc(csdev->refcnt);
diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 1fc4fd79a1c6..5406e338c280 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -1005,7 +1005,8 @@ static int __arm_trbe_enable(struct trbe_buf *buf,
return ret;
}

-static int arm_trbe_enable(struct coresight_device *csdev, u32 mode, void *data)
+static int arm_trbe_enable(struct coresight_device *csdev, enum cs_mode mode,
+ void *data)
{
struct trbe_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
struct trbe_cpudata *cpudata = dev_get_drvdata(&csdev->dev);
diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c
index b317342c7ce5..a2ced0b3c3cd 100644
--- a/drivers/hwtracing/coresight/ultrasoc-smb.c
+++ b/drivers/hwtracing/coresight/ultrasoc-smb.c
@@ -256,7 +256,8 @@ static int smb_enable_perf(struct coresight_device *csdev, void *data)
return 0;
}

-static int smb_enable(struct coresight_device *csdev, u32 mode, void *data)
+static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
+ void *data)
{
struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret = 0;
diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.h b/drivers/hwtracing/coresight/ultrasoc-smb.h
index 7dfbe42e37a0..d2e14e8d2c8a 100644
--- a/drivers/hwtracing/coresight/ultrasoc-smb.h
+++ b/drivers/hwtracing/coresight/ultrasoc-smb.h
@@ -119,7 +119,7 @@ struct smb_drv_data {
struct mutex mutex;
bool reading;
pid_t pid;
- u32 mode;
+ enum cs_mode mode;
};

#endif
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index f19a47b9bb5a..1f878e8ed8c4 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -272,6 +272,12 @@ static struct coresight_dev_list (var) = { \

#define to_coresight_device(d) container_of(d, struct coresight_device, dev)

+enum cs_mode {
+ CS_MODE_DISABLED,
+ CS_MODE_SYSFS,
+ CS_MODE_PERF,
+};
+
#define source_ops(csdev) csdev->ops->source_ops
#define sink_ops(csdev) csdev->ops->sink_ops
#define link_ops(csdev) csdev->ops->link_ops
@@ -288,7 +294,8 @@ static struct coresight_dev_list (var) = { \
* @update_buffer: update buffer pointers after a trace session.
*/
struct coresight_ops_sink {
- int (*enable)(struct coresight_device *csdev, u32 mode, void *data);
+ int (*enable)(struct coresight_device *csdev, enum cs_mode mode,
+ void *data);
int (*disable)(struct coresight_device *csdev);
void *(*alloc_buffer)(struct coresight_device *csdev,
struct perf_event *event, void **pages,
@@ -320,8 +327,8 @@ struct coresight_ops_link {
*/
struct coresight_ops_source {
int (*cpu_id)(struct coresight_device *csdev);
- int (*enable)(struct coresight_device *csdev,
- struct perf_event *event, u32 mode);
+ int (*enable)(struct coresight_device *csdev, struct perf_event *event,
+ enum cs_mode mode);
void (*disable)(struct coresight_device *csdev,
struct perf_event *event);
};
--
2.34.1

2023-04-04 16:00:43

by James Clark

[permalink] [raw]
Subject: [PATCH v5 03/13] coresight: Change name of pdata->conns

conns is actually for output connections. Change the name to make it
clearer and so that we can add input connections later.

No functional changes.

Reviewed-by: Mike Leach <[email protected]>
Signed-off-by: James Clark <[email protected]>
---
drivers/hwtracing/coresight/coresight-core.c | 26 +++++++++----------
.../hwtracing/coresight/coresight-platform.c | 12 ++++-----
.../hwtracing/coresight/coresight-tmc-etr.c | 2 +-
include/linux/coresight.h | 4 +--
4 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index c891078dffc6..04c9d52f8f4f 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -119,7 +119,7 @@ static int coresight_find_link_inport(struct coresight_device *csdev,
struct coresight_connection *conn;

for (i = 0; i < parent->pdata->nr_outport; i++) {
- conn = &parent->pdata->conns[i];
+ conn = &parent->pdata->out_conns[i];
if (conn->child_dev == csdev)
return conn->child_port;
}
@@ -137,7 +137,7 @@ static int coresight_find_link_outport(struct coresight_device *csdev,
struct coresight_connection *conn;

for (i = 0; i < csdev->pdata->nr_outport; i++) {
- conn = &csdev->pdata->conns[i];
+ conn = &csdev->pdata->out_conns[i];
if (conn->child_dev == child)
return conn->outport;
}
@@ -606,7 +606,7 @@ coresight_find_enabled_sink(struct coresight_device *csdev)
for (i = 0; i < csdev->pdata->nr_outport; i++) {
struct coresight_device *child_dev;

- child_dev = csdev->pdata->conns[i].child_dev;
+ child_dev = csdev->pdata->out_conns[i].child_dev;
if (child_dev)
sink = coresight_find_enabled_sink(child_dev);
if (sink)
@@ -722,7 +722,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
for (i = 0; i < csdev->pdata->nr_outport; i++) {
struct coresight_device *child;

- child = csdev->pdata->conns[i].child_dev;
+ child = csdev->pdata->out_conns[i].child_dev;
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
if (!coresight_get_ref(child))
goto err;
@@ -733,7 +733,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
for (i--; i >= 0; i--) {
struct coresight_device *child;

- child = csdev->pdata->conns[i].child_dev;
+ child = csdev->pdata->out_conns[i].child_dev;
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
coresight_put_ref(child);
}
@@ -752,7 +752,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
for (i = 0; i < csdev->pdata->nr_outport; i++) {
struct coresight_device *child;

- child = csdev->pdata->conns[i].child_dev;
+ child = csdev->pdata->out_conns[i].child_dev;
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
coresight_put_ref(child);
}
@@ -794,7 +794,7 @@ static int _coresight_build_path(struct coresight_device *csdev,
for (i = 0; i < csdev->pdata->nr_outport; i++) {
struct coresight_device *child_dev;

- child_dev = csdev->pdata->conns[i].child_dev;
+ child_dev = csdev->pdata->out_conns[i].child_dev;
if (child_dev &&
_coresight_build_path(child_dev, sink, path) == 0) {
found = true;
@@ -964,7 +964,7 @@ coresight_find_sink(struct coresight_device *csdev, int *depth)
struct coresight_device *child_dev, *sink = NULL;
int child_depth = curr_depth;

- child_dev = csdev->pdata->conns[i].child_dev;
+ child_dev = csdev->pdata->out_conns[i].child_dev;
if (child_dev)
sink = coresight_find_sink(child_dev, &child_depth);

@@ -1334,7 +1334,7 @@ static int coresight_orphan_match(struct device *dev, void *data)
* an orphan connection whose name matches @csdev, link it.
*/
for (i = 0; i < i_csdev->pdata->nr_outport; i++) {
- conn = &i_csdev->pdata->conns[i];
+ conn = &i_csdev->pdata->out_conns[i];

/* Skip the port if FW doesn't describe it */
if (!conn->child_fwnode)
@@ -1375,7 +1375,7 @@ static int coresight_fixup_device_conns(struct coresight_device *csdev)
int i, ret = 0;

for (i = 0; i < csdev->pdata->nr_outport; i++) {
- struct coresight_connection *conn = &csdev->pdata->conns[i];
+ struct coresight_connection *conn = &csdev->pdata->out_conns[i];

if (!conn->child_fwnode)
continue;
@@ -1412,7 +1412,7 @@ static int coresight_remove_match(struct device *dev, void *data)
* a connection whose name matches @csdev, remove it.
*/
for (i = 0; i < iterator->pdata->nr_outport; i++) {
- conn = &iterator->pdata->conns[i];
+ conn = &iterator->pdata->out_conns[i];

if (conn->child_dev == NULL || conn->child_fwnode == NULL)
continue;
@@ -1543,7 +1543,7 @@ void coresight_release_platform_data(struct coresight_device *csdev,
struct coresight_platform_data *pdata)
{
int i;
- struct coresight_connection *conns = pdata->conns;
+ struct coresight_connection *conns = pdata->out_conns;

for (i = 0; i < pdata->nr_outport; i++) {
/* If we have made the links, remove them now */
@@ -1555,7 +1555,7 @@ void coresight_release_platform_data(struct coresight_device *csdev,
*/
if (conns[i].child_fwnode) {
fwnode_handle_put(conns[i].child_fwnode);
- pdata->conns[i].child_fwnode = NULL;
+ conns[i].child_fwnode = NULL;
}
}
if (csdev)
diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
index 475899714104..5085525a32bb 100644
--- a/drivers/hwtracing/coresight/coresight-platform.c
+++ b/drivers/hwtracing/coresight/coresight-platform.c
@@ -27,9 +27,9 @@ static int coresight_alloc_conns(struct device *dev,
struct coresight_platform_data *pdata)
{
if (pdata->nr_outport) {
- pdata->conns = devm_kcalloc(dev, pdata->nr_outport,
- sizeof(*pdata->conns), GFP_KERNEL);
- if (!pdata->conns)
+ pdata->out_conns = devm_kcalloc(dev, pdata->nr_outport,
+ sizeof(*pdata->out_conns), GFP_KERNEL);
+ if (!pdata->out_conns)
return -ENOMEM;
}

@@ -251,7 +251,7 @@ static int of_coresight_parse_endpoint(struct device *dev,
break;
}

- conn = &pdata->conns[endpoint.port];
+ conn = &pdata->out_conns[endpoint.port];
if (conn->child_fwnode) {
dev_warn(dev, "Duplicate output port %d\n",
endpoint.port);
@@ -744,8 +744,8 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
int port = conns[i].outport;

/* Duplicate output port */
- WARN_ON(pdata->conns[port].child_fwnode);
- pdata->conns[port] = conns[i];
+ WARN_ON(pdata->out_conns[port].child_fwnode);
+ pdata->out_conns[port] = conns[i];
}

devm_kfree(&adev->dev, conns);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index ed589cfff1b5..86d4a08aa833 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -782,7 +782,7 @@ tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
return NULL;

for (i = 0; i < etr->pdata->nr_outport; i++) {
- tmp = etr->pdata->conns[i].child_dev;
+ tmp = etr->pdata->out_conns[i].child_dev;
if (tmp && coresight_is_catu_device(tmp))
return tmp;
}
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 1f878e8ed8c4..bf621d064ef8 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -104,12 +104,12 @@ union coresight_dev_subtype {
*
* @nr_inport: Number of elements for the input connections.
* @nr_outport: Number of elements for the output connections.
- * @conns: Sparse array of nr_outport connections from this component.
+ * @out_conns: Sparse array of nr_outport connections from this component.
*/
struct coresight_platform_data {
int nr_inport;
int nr_outport;
- struct coresight_connection *conns;
+ struct coresight_connection *out_conns;
};

/**
--
2.34.1

2023-04-04 16:00:55

by James Clark

[permalink] [raw]
Subject: [PATCH v5 07/13] coresight: Store pointers to connections rather than an array of them

This will allow the same connection object to be referenced via the
input connection list in a later commit rather than duplicating them.

Signed-off-by: James Clark <[email protected]>
---
drivers/hwtracing/coresight/coresight-core.c | 47 ++++++++++---------
.../hwtracing/coresight/coresight-platform.c | 19 ++++++--
drivers/hwtracing/coresight/coresight-priv.h | 1 +
.../hwtracing/coresight/coresight-tmc-etr.c | 2 +-
include/linux/coresight.h | 5 +-
5 files changed, 44 insertions(+), 30 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 91274e7e6944..0b738960973b 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -119,7 +119,7 @@ static int coresight_find_link_inport(struct coresight_device *csdev,
struct coresight_connection *conn;

for (i = 0; i < parent->pdata->nr_outconns; i++) {
- conn = &parent->pdata->out_conns[i];
+ conn = parent->pdata->out_conns[i];
if (conn->dest_dev == csdev)
return conn->dest_port;
}
@@ -137,7 +137,7 @@ static int coresight_find_link_outport(struct coresight_device *csdev,
struct coresight_connection *conn;

for (i = 0; i < csdev->pdata->nr_outconns; i++) {
- conn = &csdev->pdata->out_conns[i];
+ conn = csdev->pdata->out_conns[i];
if (conn->dest_dev == child)
return conn->src_port;
}
@@ -606,7 +606,7 @@ coresight_find_enabled_sink(struct coresight_device *csdev)
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child_dev;

- child_dev = csdev->pdata->out_conns[i].dest_dev;
+ child_dev = csdev->pdata->out_conns[i]->dest_dev;
if (child_dev)
sink = coresight_find_enabled_sink(child_dev);
if (sink)
@@ -722,7 +722,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child;

- child = csdev->pdata->out_conns[i].dest_dev;
+ child = csdev->pdata->out_conns[i]->dest_dev;
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
if (!coresight_get_ref(child))
goto err;
@@ -733,7 +733,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
for (i--; i >= 0; i--) {
struct coresight_device *child;

- child = csdev->pdata->out_conns[i].dest_dev;
+ child = csdev->pdata->out_conns[i]->dest_dev;
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
coresight_put_ref(child);
}
@@ -752,7 +752,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child;

- child = csdev->pdata->out_conns[i].dest_dev;
+ child = csdev->pdata->out_conns[i]->dest_dev;
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
coresight_put_ref(child);
}
@@ -794,7 +794,7 @@ static int _coresight_build_path(struct coresight_device *csdev,
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child_dev;

- child_dev = csdev->pdata->out_conns[i].dest_dev;
+ child_dev = csdev->pdata->out_conns[i]->dest_dev;
if (child_dev &&
_coresight_build_path(child_dev, sink, path) == 0) {
found = true;
@@ -964,7 +964,7 @@ coresight_find_sink(struct coresight_device *csdev, int *depth)
struct coresight_device *child_dev, *sink = NULL;
int child_depth = curr_depth;

- child_dev = csdev->pdata->out_conns[i].dest_dev;
+ child_dev = csdev->pdata->out_conns[i]->dest_dev;
if (child_dev)
sink = coresight_find_sink(child_dev, &child_depth);

@@ -1334,7 +1334,7 @@ static int coresight_orphan_match(struct device *dev, void *data)
* an orphan connection whose name matches @csdev, link it.
*/
for (i = 0; i < i_csdev->pdata->nr_outconns; i++) {
- conn = &i_csdev->pdata->out_conns[i];
+ conn = i_csdev->pdata->out_conns[i];

/* We have found at least one orphan connection */
if (conn->dest_dev == NULL) {
@@ -1372,7 +1372,7 @@ static int coresight_fixup_device_conns(struct coresight_device *csdev)
int i, ret = 0;

for (i = 0; i < csdev->pdata->nr_outconns; i++) {
- struct coresight_connection *conn = &csdev->pdata->out_conns[i];
+ struct coresight_connection *conn = csdev->pdata->out_conns[i];

conn->dest_dev =
coresight_find_csdev_by_fwnode(conn->dest_fwnode);
@@ -1406,15 +1406,12 @@ static int coresight_remove_match(struct device *dev, void *data)
* a connection whose name matches @csdev, remove it.
*/
for (i = 0; i < iterator->pdata->nr_outconns; i++) {
- conn = &iterator->pdata->out_conns[i];
+ conn = iterator->pdata->out_conns[i];

- if (conn->dest_dev == NULL)
- continue;
-
- if (csdev->dev.fwnode == conn->dest_fwnode) {
+ /* Child_dev being set signifies that the links were made */
+ if (csdev->dev.fwnode == conn->dest_fwnode && conn->dest_dev) {
iterator->orphan = true;
coresight_remove_links(iterator, conn);
-
conn->dest_dev = NULL;
/* No need to continue */
break;
@@ -1534,22 +1531,26 @@ void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset)
* to the output port of this device.
*/
void coresight_release_platform_data(struct coresight_device *csdev,
+ struct device *dev,
struct coresight_platform_data *pdata)
{
int i;
- struct coresight_connection *conns = pdata->out_conns;
+ struct coresight_connection **conns = pdata->out_conns;

for (i = 0; i < pdata->nr_outconns; i++) {
/* If we have made the links, remove them now */
- if (csdev && conns[i].dest_dev)
- coresight_remove_links(csdev, &conns[i]);
+ if (csdev && conns[i]->dest_dev)
+ coresight_remove_links(csdev, conns[i]);
/*
* Drop the refcount and clear the handle as this device
* is going away
*/
- fwnode_handle_put(conns[i].dest_fwnode);
- conns[i].dest_fwnode = NULL;
+ fwnode_handle_put(conns[i]->dest_fwnode);
+ conns[i]->dest_fwnode = NULL;
+ devm_kfree(dev, conns[i]);
}
+ devm_kfree(dev, pdata->out_conns);
+ devm_kfree(dev, pdata);
if (csdev)
coresight_remove_conns_sysfs_group(csdev);
}
@@ -1666,7 +1667,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)

err_out:
/* Cleanup the connection information */
- coresight_release_platform_data(NULL, desc->pdata);
+ coresight_release_platform_data(NULL, desc->dev, desc->pdata);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(coresight_register);
@@ -1679,7 +1680,7 @@ void coresight_unregister(struct coresight_device *csdev)
cti_assoc_ops->remove(csdev);
coresight_remove_conns(csdev);
coresight_clear_default_sink(csdev);
- coresight_release_platform_data(csdev, csdev->pdata);
+ coresight_release_platform_data(csdev, csdev->dev.parent, csdev->pdata);
device_unregister(&csdev->dev);
}
EXPORT_SYMBOL_GPL(coresight_unregister);
diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
index 8c2029336161..9c05f787278b 100644
--- a/drivers/hwtracing/coresight/coresight-platform.c
+++ b/drivers/hwtracing/coresight/coresight-platform.c
@@ -37,7 +37,7 @@ coresight_add_out_conn(struct device *dev,
* Warn on any existing duplicate output port.
*/
for (i = 0; i < pdata->nr_outconns; ++i) {
- conn = &pdata->out_conns[i];
+ conn = pdata->out_conns[i];
/* Output == -1 means ignore the port for example for helpers */
if (conn->src_port != -1 &&
conn->src_port == new_conn->src_port) {
@@ -54,8 +54,19 @@ coresight_add_out_conn(struct device *dev,
if (!pdata->out_conns)
return ERR_PTR(-ENOMEM);

- pdata->out_conns[pdata->nr_outconns - 1] = *new_conn;
- return &pdata->out_conns[pdata->nr_outconns - 1];
+ conn = devm_kmalloc(dev, sizeof(struct coresight_connection),
+ GFP_KERNEL);
+ if (!conn)
+ return ERR_PTR(-ENOMEM);
+
+ /*
+ * Copy the new connection into the allocation, save the pointer to the
+ * end of the connection array and also return it in case it needs to be
+ * used right away.
+ */
+ *conn = *new_conn;
+ pdata->out_conns[pdata->nr_outconns - 1] = conn;
+ return conn;
}
EXPORT_SYMBOL_GPL(coresight_add_out_conn);

@@ -863,7 +874,7 @@ coresight_get_platform_data(struct device *dev)
error:
if (!IS_ERR_OR_NULL(pdata))
/* Cleanup the connection information */
- coresight_release_platform_data(NULL, pdata);
+ coresight_release_platform_data(NULL, dev, pdata);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(coresight_get_platform_data);
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 788ff19c60f6..65ae6d161c57 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -207,6 +207,7 @@ static inline void *coresight_get_uci_data(const struct amba_id *id)
}

void coresight_release_platform_data(struct coresight_device *csdev,
+ struct device *dev,
struct coresight_platform_data *pdata);
struct coresight_device *
coresight_find_csdev_by_fwnode(struct fwnode_handle *r_fwnode);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 61234cb8052a..1bbe5410a23d 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -782,7 +782,7 @@ tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
return NULL;

for (i = 0; i < etr->pdata->nr_outconns; i++) {
- tmp = etr->pdata->out_conns[i].dest_dev;
+ tmp = etr->pdata->out_conns[i]->dest_dev;
if (tmp && coresight_is_catu_device(tmp))
return tmp;
}
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 12fdbd03e2f7..abf36a37fdb0 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -104,14 +104,15 @@ union coresight_dev_subtype {
*
* @nr_inconns: Number of elements for the input connections.
* @nr_outconns: Number of elements for the output connections.
- * @out_conns: Array of nr_outconns connections from this component.
+ * @out_conns: Array of nr_outconns pointers to connections from this
+ * component.
*/
struct coresight_platform_data {
int high_inport;
int high_outport;
int nr_inconns;
int nr_outconns;
- struct coresight_connection *out_conns;
+ struct coresight_connection **out_conns;
};

/**
--
2.34.1

2023-04-04 16:01:03

by James Clark

[permalink] [raw]
Subject: [PATCH v5 10/13] coresight: Make refcount a property of the connection

This removes the need to do an additional lookup for the total number
of ports used and also removes the need to allocate an array of
refcounts which is just another representation of a connection array.

This was only used for link type devices, for regular devices a single
refcount on the coresight device is used.

There is a both an input and output refcount in case two link type
devices are connected together so that they don't overwrite each other's
counts.

Signed-off-by: James Clark <[email protected]>
---
drivers/hwtracing/coresight/coresight-core.c | 116 ++++++------------
drivers/hwtracing/coresight/coresight-etb10.c | 10 +-
.../hwtracing/coresight/coresight-funnel.c | 26 ++--
.../hwtracing/coresight/coresight-platform.c | 109 +---------------
.../coresight/coresight-replicator.c | 23 ++--
.../hwtracing/coresight/coresight-tmc-etf.c | 24 ++--
.../hwtracing/coresight/coresight-tmc-etr.c | 12 +-
drivers/hwtracing/coresight/coresight-tpda.c | 23 ++--
drivers/hwtracing/coresight/coresight-tpiu.c | 4 +-
drivers/hwtracing/coresight/ultrasoc-smb.c | 8 +-
include/linux/coresight.h | 14 ++-
11 files changed, 126 insertions(+), 243 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index a0a0ea2c626b..939b7fb751b5 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -112,40 +112,24 @@ struct coresight_device *coresight_get_percpu_sink(int cpu)
}
EXPORT_SYMBOL_GPL(coresight_get_percpu_sink);

-static int coresight_find_link_inport(struct coresight_device *csdev,
- struct coresight_device *parent)
+static struct coresight_connection *
+coresight_find_out_connection(struct coresight_device *src_dev,
+ struct coresight_device *dest_dev)
{
int i;
struct coresight_connection *conn;

- for (i = 0; i < parent->pdata->nr_outconns; i++) {
- conn = parent->pdata->out_conns[i];
- if (conn->dest_dev == csdev)
- return conn->dest_port;
+ for (i = 0; i < src_dev->pdata->nr_outconns; i++) {
+ conn = src_dev->pdata->out_conns[i];
+ if (conn->dest_dev == dest_dev)
+ return conn;
}

- dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n",
- dev_name(&parent->dev), dev_name(&csdev->dev));
+ 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));

- return -ENODEV;
-}
-
-static int coresight_find_link_outport(struct coresight_device *csdev,
- struct coresight_device *child)
-{
- int i;
- struct coresight_connection *conn;
-
- for (i = 0; i < csdev->pdata->nr_outconns; i++) {
- conn = csdev->pdata->out_conns[i];
- if (conn->dest_dev == child)
- return conn->src_port;
- }
-
- dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n",
- dev_name(&csdev->dev), dev_name(&child->dev));
-
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
}

static inline u32 coresight_read_claim_tags(struct coresight_device *csdev)
@@ -352,24 +336,24 @@ static int coresight_enable_link(struct coresight_device *csdev,
{
int ret = 0;
int link_subtype;
- int inport, outport;
+ struct coresight_connection *inconn, *outconn;

if (!parent || !child)
return -EINVAL;

- inport = coresight_find_link_inport(csdev, parent);
- outport = coresight_find_link_outport(csdev, child);
+ inconn = coresight_find_out_connection(parent, csdev);
+ outconn = coresight_find_out_connection(csdev, child);
link_subtype = csdev->subtype.link_subtype;

- if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && inport < 0)
- return inport;
- if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && outport < 0)
- return outport;
+ if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && IS_ERR(inconn))
+ return PTR_ERR(inconn);
+ if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn))
+ return PTR_ERR(outconn);

if (link_ops(csdev)->enable) {
ret = coresight_control_assoc_ectdev(csdev, true);
if (!ret) {
- ret = link_ops(csdev)->enable(csdev, inport, outport);
+ ret = link_ops(csdev)->enable(csdev, inconn, outconn);
if (ret)
coresight_control_assoc_ectdev(csdev, false);
}
@@ -385,33 +369,36 @@ static void coresight_disable_link(struct coresight_device *csdev,
struct coresight_device *parent,
struct coresight_device *child)
{
- int i, nr_conns;
+ int i;
int link_subtype;
- int inport, outport;
+ struct coresight_connection *inconn, *outconn;

if (!parent || !child)
return;

- inport = coresight_find_link_inport(csdev, parent);
- outport = coresight_find_link_outport(csdev, child);
+ inconn = coresight_find_out_connection(parent, csdev);
+ outconn = coresight_find_out_connection(csdev, child);
link_subtype = csdev->subtype.link_subtype;

- if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
- nr_conns = csdev->pdata->high_inport;
- } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
- nr_conns = csdev->pdata->high_outport;
- } else {
- nr_conns = 1;
- }
-
if (link_ops(csdev)->disable) {
- link_ops(csdev)->disable(csdev, inport, outport);
+ link_ops(csdev)->disable(csdev, inconn, outconn);
coresight_control_assoc_ectdev(csdev, false);
}

- for (i = 0; i < nr_conns; i++)
- if (atomic_read(&csdev->refcnt[i]) != 0)
+ if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
+ for (i = 0; i < csdev->pdata->nr_inconns; i++)
+ if (atomic_read(&csdev->pdata->in_conns[i]->dest_refcnt) !=
+ 0)
+ return;
+ } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
+ for (i = 0; i < csdev->pdata->nr_outconns; i++)
+ if (atomic_read(&csdev->pdata->out_conns[i]->src_refcnt) !=
+ 0)
+ return;
+ } else {
+ if (atomic_read(&csdev->refcnt) != 0)
return;
+ }

csdev->enable = false;
}
@@ -435,7 +422,7 @@ static int coresight_enable_source(struct coresight_device *csdev,
csdev->enable = true;
}

- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);

return 0;
}
@@ -450,7 +437,7 @@ static int coresight_enable_source(struct coresight_device *csdev,
*/
static bool coresight_disable_source(struct coresight_device *csdev)
{
- if (atomic_dec_return(csdev->refcnt) == 0) {
+ if (atomic_dec_return(&csdev->refcnt) == 0) {
if (source_ops(csdev)->disable)
source_ops(csdev)->disable(csdev, NULL);
coresight_control_assoc_ectdev(csdev, false);
@@ -1094,7 +1081,7 @@ int coresight_enable(struct coresight_device *csdev)
* source is already enabled.
*/
if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
goto out;
}

@@ -1308,7 +1295,6 @@ static void coresight_device_release(struct device *dev)
struct coresight_device *csdev = to_coresight_device(dev);

fwnode_handle_put(csdev->dev.fwnode);
- kfree(csdev->refcnt);
kfree(csdev);
}

@@ -1537,9 +1523,6 @@ void coresight_release_platform_data(struct coresight_device *csdev,
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;
bool registered = false;

@@ -1549,25 +1532,6 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
goto err_out;
}

- 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->high_inport;
- else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
- nr_refcnts = desc->pdata->high_outport;
- }
-
- refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
- if (!refcnts) {
- ret = -ENOMEM;
- kfree(csdev);
- goto err_out;
- }
-
- csdev->refcnt = refcnts;
-
csdev->pdata = desc->pdata;

csdev->type = desc->type;
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index eb99c445015a..fa80039e0821 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c
@@ -163,7 +163,7 @@ static int etb_enable_sysfs(struct coresight_device *csdev)
drvdata->mode = CS_MODE_SYSFS;
}

- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret;
@@ -199,7 +199,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
* use for this session.
*/
if (drvdata->pid == pid) {
- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
goto out;
}

@@ -217,7 +217,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
/* Associate with monitored process. */
drvdata->pid = pid;
drvdata->mode = CS_MODE_PERF;
- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
}

out:
@@ -356,7 +356,7 @@ static int etb_disable(struct coresight_device *csdev)

spin_lock_irqsave(&drvdata->spinlock, flags);

- if (atomic_dec_return(csdev->refcnt)) {
+ if (atomic_dec_return(&csdev->refcnt)) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
@@ -447,7 +447,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
spin_lock_irqsave(&drvdata->spinlock, flags);

/* Don't do anything if another tracer is using this sink */
- if (atomic_read(csdev->refcnt) != 1)
+ if (atomic_read(&csdev->refcnt) != 1)
goto out;

__etb_disable_hw(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index b363dd6bc510..b8e150e45b27 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -74,8 +74,9 @@ static int dynamic_funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
return rc;
}

-static int funnel_enable(struct coresight_device *csdev, int inport,
- int outport)
+static int funnel_enable(struct coresight_device *csdev,
+ struct coresight_connection *in,
+ struct coresight_connection *out)
{
int rc = 0;
struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -83,18 +84,19 @@ static int funnel_enable(struct coresight_device *csdev, int inport,
bool first_enable = false;

spin_lock_irqsave(&drvdata->spinlock, flags);
- if (atomic_read(&csdev->refcnt[inport]) == 0) {
+ if (atomic_read(&in->dest_refcnt) == 0) {
if (drvdata->base)
- rc = dynamic_funnel_enable_hw(drvdata, inport);
+ rc = dynamic_funnel_enable_hw(drvdata, in->dest_port);
if (!rc)
first_enable = true;
}
if (!rc)
- atomic_inc(&csdev->refcnt[inport]);
+ atomic_inc(&in->dest_refcnt);
spin_unlock_irqrestore(&drvdata->spinlock, flags);

if (first_enable)
- dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", inport);
+ dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n",
+ in->dest_port);
return rc;
}

@@ -117,23 +119,25 @@ static void dynamic_funnel_disable_hw(struct funnel_drvdata *drvdata,
CS_LOCK(drvdata->base);
}

-static void funnel_disable(struct coresight_device *csdev, int inport,
- int outport)
+static void funnel_disable(struct coresight_device *csdev,
+ struct coresight_connection *in,
+ struct coresight_connection *out)
{
struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
unsigned long flags;
bool last_disable = false;

spin_lock_irqsave(&drvdata->spinlock, flags);
- if (atomic_dec_return(&csdev->refcnt[inport]) == 0) {
+ if (atomic_dec_return(&in->dest_refcnt) == 0) {
if (drvdata->base)
- dynamic_funnel_disable_hw(drvdata, inport);
+ dynamic_funnel_disable_hw(drvdata, in->dest_port);
last_disable = true;
}
spin_unlock_irqrestore(&drvdata->spinlock, flags);

if (last_disable)
- dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", inport);
+ dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n",
+ in->dest_port);
}

static const struct coresight_ops_link funnel_link_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
index 257ad48925a1..3e2e135cb8f6 100644
--- a/drivers/hwtracing/coresight/coresight-platform.c
+++ b/drivers/hwtracing/coresight/coresight-platform.c
@@ -146,41 +146,6 @@ static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
return of_property_read_bool(ep, "slave-mode");
}

-static void of_coresight_get_ports_legacy(const struct device_node *node,
- int *nr_inconns, int *nr_outconns)
-{
- struct device_node *ep = NULL;
- struct of_endpoint endpoint;
- int in = 0, out = 0;
-
- /*
- * Avoid warnings in of_graph_get_next_endpoint()
- * if the device doesn't have any graph connections
- */
- if (!of_graph_is_present(node))
- return;
- do {
- ep = of_graph_get_next_endpoint(node, ep);
- if (!ep)
- break;
-
- if (of_graph_parse_endpoint(ep, &endpoint))
- continue;
-
- if (of_coresight_legacy_ep_is_input(ep)) {
- in = (endpoint.port + 1 > in) ?
- endpoint.port + 1 : in;
- } else {
- out = (endpoint.port + 1) > out ?
- endpoint.port + 1 : out;
- }
-
- } while (ep);
-
- *nr_inconns = in;
- *nr_outconns = out;
-}
-
static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
{
struct device_node *parent = of_graph_get_port_parent(ep);
@@ -196,59 +161,12 @@ static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
return parent;
}

-static inline struct device_node *
-of_coresight_get_input_ports_node(const struct device_node *node)
-{
- return of_get_child_by_name(node, "in-ports");
-}
-
static inline struct device_node *
of_coresight_get_output_ports_node(const struct device_node *node)
{
return of_get_child_by_name(node, "out-ports");
}

-static inline int
-of_coresight_count_ports(struct device_node *port_parent)
-{
- int i = 0;
- struct device_node *ep = NULL;
- struct of_endpoint endpoint;
-
- while ((ep = of_graph_get_next_endpoint(port_parent, ep))) {
- /* Defer error handling to parsing */
- if (of_graph_parse_endpoint(ep, &endpoint))
- continue;
- if (endpoint.port + 1 > i)
- i = endpoint.port + 1;
- }
-
- return i;
-}
-
-static void of_coresight_get_ports(const struct device_node *node,
- int *nr_inconns, int *nr_outconns)
-{
- struct device_node *input_ports = NULL, *output_ports = NULL;
-
- input_ports = of_coresight_get_input_ports_node(node);
- output_ports = of_coresight_get_output_ports_node(node);
-
- if (input_ports || output_ports) {
- if (input_ports) {
- *nr_inconns = of_coresight_count_ports(input_ports);
- of_node_put(input_ports);
- }
- if (output_ports) {
- *nr_outconns = of_coresight_count_ports(output_ports);
- of_node_put(output_ports);
- }
- } else {
- /* Fall back to legacy DT bindings parsing */
- of_coresight_get_ports_legacy(node, nr_inconns, nr_outconns);
- }
-}
-
static int of_coresight_get_cpu(struct device *dev)
{
int cpu;
@@ -351,13 +269,6 @@ static int of_get_coresight_platform_data(struct device *dev,
bool legacy_binding = false;
struct device_node *node = dev->of_node;

- /* Get the number of input and output port for this component */
- of_coresight_get_ports(node, &pdata->high_inport, &pdata->high_outport);
-
- /* If there are no output connections, we are done */
- if (!pdata->high_outport)
- return 0;
-
parent = of_coresight_get_output_ports_node(node);
/*
* If the DT uses obsoleted bindings, the ports are listed
@@ -365,6 +276,12 @@ static int of_get_coresight_platform_data(struct device *dev,
* ports.
*/
if (!parent) {
+ /*
+ * Avoid warnings in of_graph_get_next_endpoint()
+ * if the device doesn't have any graph connections
+ */
+ if (!of_graph_is_present(node))
+ return 0;
legacy_binding = true;
parent = node;
dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n");
@@ -751,7 +668,6 @@ static int acpi_coresight_parse_graph(struct device *dev,
struct coresight_connection conn, zero_conn = {};
struct coresight_connection *new_conn;

- pdata->nr_inconns = pdata->nr_outconns = 0;
graph = acpi_get_coresight_graph(adev);
if (!graph)
return -ENOENT;
@@ -770,22 +686,9 @@ static int acpi_coresight_parse_graph(struct device *dev,
return dir;

if (dir == ACPI_CORESIGHT_LINK_MASTER) {
- if (conn.src_port >= pdata->high_outport)
- pdata->high_outport = conn.src_port + 1;
new_conn = coresight_add_out_conn(dev, pdata, &conn);
if (IS_ERR(new_conn))
return PTR_ERR(new_conn);
- } else {
- WARN_ON(pdata->high_inport == conn.dest_port + 1);
- /*
- * We do not track input port connections for a device.
- * However we need the highest port number described,
- * which can be recorded now and reuse this connection
- * record for an output connection. Hence, do not move
- * the ptr for input connections
- */
- if (conn.dest_port >= pdata->high_inport)
- pdata->high_inport = conn.dest_port + 1;
}
}

diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index 4dd50546d7e4..b6be73034996 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -114,8 +114,9 @@ static int dynamic_replicator_enable(struct replicator_drvdata *drvdata,
return rc;
}

-static int replicator_enable(struct coresight_device *csdev, int inport,
- int outport)
+static int replicator_enable(struct coresight_device *csdev,
+ struct coresight_connection *in,
+ struct coresight_connection *out)
{
int rc = 0;
struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -123,15 +124,15 @@ static int replicator_enable(struct coresight_device *csdev, int inport,
bool first_enable = false;

spin_lock_irqsave(&drvdata->spinlock, flags);
- if (atomic_read(&csdev->refcnt[outport]) == 0) {
+ if (atomic_read(&out->src_refcnt) == 0) {
if (drvdata->base)
- rc = dynamic_replicator_enable(drvdata, inport,
- outport);
+ rc = dynamic_replicator_enable(drvdata, in->dest_port,
+ out->src_port);
if (!rc)
first_enable = true;
}
if (!rc)
- atomic_inc(&csdev->refcnt[outport]);
+ atomic_inc(&out->src_refcnt);
spin_unlock_irqrestore(&drvdata->spinlock, flags);

if (first_enable)
@@ -168,17 +169,19 @@ static void dynamic_replicator_disable(struct replicator_drvdata *drvdata,
CS_LOCK(drvdata->base);
}

-static void replicator_disable(struct coresight_device *csdev, int inport,
- int outport)
+static void replicator_disable(struct coresight_device *csdev,
+ struct coresight_connection *in,
+ struct coresight_connection *out)
{
struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
unsigned long flags;
bool last_disable = false;

spin_lock_irqsave(&drvdata->spinlock, flags);
- if (atomic_dec_return(&csdev->refcnt[outport]) == 0) {
+ if (atomic_dec_return(&out->src_refcnt) == 0) {
if (drvdata->base)
- dynamic_replicator_disable(drvdata, inport, outport);
+ dynamic_replicator_disable(drvdata, in->dest_port,
+ out->src_port);
last_disable = true;
}
spin_unlock_irqrestore(&drvdata->spinlock, flags);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 14d3c1472455..79d8c64eac49 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -206,7 +206,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
* touched.
*/
if (drvdata->mode == CS_MODE_SYSFS) {
- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
goto out;
}

@@ -229,7 +229,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
ret = tmc_etb_enable_hw(drvdata);
if (!ret) {
drvdata->mode = CS_MODE_SYSFS;
- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
} else {
/* Free up the buffer if we failed to enable */
used = false;
@@ -284,7 +284,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
* use for this session.
*/
if (drvdata->pid == pid) {
- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
break;
}

@@ -293,7 +293,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
/* Associate with monitored process. */
drvdata->pid = pid;
drvdata->mode = CS_MODE_PERF;
- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
}
} while (0);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -338,7 +338,7 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
return -EBUSY;
}

- if (atomic_dec_return(csdev->refcnt)) {
+ if (atomic_dec_return(&csdev->refcnt)) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
@@ -357,7 +357,8 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
}

static int tmc_enable_etf_link(struct coresight_device *csdev,
- int inport, int outport)
+ struct coresight_connection *in,
+ struct coresight_connection *out)
{
int ret = 0;
unsigned long flags;
@@ -370,7 +371,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
return -EBUSY;
}

- if (atomic_read(&csdev->refcnt[0]) == 0) {
+ if (atomic_read(&csdev->refcnt) == 0) {
ret = tmc_etf_enable_hw(drvdata);
if (!ret) {
drvdata->mode = CS_MODE_SYSFS;
@@ -378,7 +379,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
}
}
if (!ret)
- atomic_inc(&csdev->refcnt[0]);
+ atomic_inc(&csdev->refcnt);
spin_unlock_irqrestore(&drvdata->spinlock, flags);

if (first_enable)
@@ -387,7 +388,8 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
}

static void tmc_disable_etf_link(struct coresight_device *csdev,
- int inport, int outport)
+ struct coresight_connection *in,
+ struct coresight_connection *out)
{
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -399,7 +401,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
return;
}

- if (atomic_dec_return(&csdev->refcnt[0]) == 0) {
+ if (atomic_dec_return(&csdev->refcnt) == 0) {
tmc_etf_disable_hw(drvdata);
drvdata->mode = CS_MODE_DISABLED;
last_disable = true;
@@ -487,7 +489,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
spin_lock_irqsave(&drvdata->spinlock, flags);

/* Don't do anything if another tracer is using this sink */
- if (atomic_read(csdev->refcnt) != 1)
+ if (atomic_read(&csdev->refcnt) != 1)
goto out;

CS_UNLOCK(drvdata->base);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 1bbe5410a23d..689ba6abc70b 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1209,7 +1209,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
* touched, even if the buffer size has changed.
*/
if (drvdata->mode == CS_MODE_SYSFS) {
- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
goto out;
}

@@ -1226,7 +1226,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
ret = tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf);
if (!ret) {
drvdata->mode = CS_MODE_SYSFS;
- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
}
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -1535,7 +1535,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
spin_lock_irqsave(&drvdata->spinlock, flags);

/* Don't do anything if another tracer is using this sink */
- if (atomic_read(csdev->refcnt) != 1) {
+ if (atomic_read(&csdev->refcnt) != 1) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
goto out;
}
@@ -1647,7 +1647,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
* use for this session.
*/
if (drvdata->pid == pid) {
- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
goto unlock_out;
}

@@ -1657,7 +1657,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
drvdata->pid = pid;
drvdata->mode = CS_MODE_PERF;
drvdata->perf_buf = etr_perf->etr_buf;
- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
}

unlock_out:
@@ -1690,7 +1690,7 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
return -EBUSY;
}

- if (atomic_dec_return(csdev->refcnt)) {
+ if (atomic_dec_return(&csdev->refcnt)) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index f712e112ecff..8d2b9d29237d 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -54,18 +54,20 @@ static void __tpda_enable(struct tpda_drvdata *drvdata, int port)
CS_LOCK(drvdata->base);
}

-static int tpda_enable(struct coresight_device *csdev, int inport, int outport)
+static int tpda_enable(struct coresight_device *csdev,
+ struct coresight_connection *in,
+ struct coresight_connection *out)
{
struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);

spin_lock(&drvdata->spinlock);
- if (atomic_read(&csdev->refcnt[inport]) == 0)
- __tpda_enable(drvdata, inport);
+ if (atomic_read(&in->dest_refcnt) == 0)
+ __tpda_enable(drvdata, in->dest_port);

- atomic_inc(&csdev->refcnt[inport]);
+ atomic_inc(&in->dest_refcnt);
spin_unlock(&drvdata->spinlock);

- dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", inport);
+ dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
return 0;
}

@@ -82,18 +84,19 @@ static void __tpda_disable(struct tpda_drvdata *drvdata, int port)
CS_LOCK(drvdata->base);
}

-static void tpda_disable(struct coresight_device *csdev, int inport,
- int outport)
+static void tpda_disable(struct coresight_device *csdev,
+ struct coresight_connection *in,
+ struct coresight_connection *out)
{
struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);

spin_lock(&drvdata->spinlock);
- if (atomic_dec_return(&csdev->refcnt[inport]) == 0)
- __tpda_disable(drvdata, inport);
+ if (atomic_dec_return(&in->dest_refcnt) == 0)
+ __tpda_disable(drvdata, in->dest_port);

spin_unlock(&drvdata->spinlock);

- dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", inport);
+ dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
}

static const struct coresight_ops_link tpda_link_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c
index b0179f761c98..59eac93fd6bb 100644
--- a/drivers/hwtracing/coresight/coresight-tpiu.c
+++ b/drivers/hwtracing/coresight/coresight-tpiu.c
@@ -73,7 +73,7 @@ static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode,
void *__unused)
{
tpiu_enable_hw(&csdev->access);
- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);
dev_dbg(&csdev->dev, "TPIU enabled\n");
return 0;
}
@@ -96,7 +96,7 @@ static void tpiu_disable_hw(struct csdev_access *csa)

static int tpiu_disable(struct coresight_device *csdev)
{
- if (atomic_dec_return(csdev->refcnt))
+ if (atomic_dec_return(&csdev->refcnt))
return -EBUSY;

tpiu_disable_hw(&csdev->access);
diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c
index a2ced0b3c3cd..e9a32a97fbee 100644
--- a/drivers/hwtracing/coresight/ultrasoc-smb.c
+++ b/drivers/hwtracing/coresight/ultrasoc-smb.c
@@ -106,7 +106,7 @@ static int smb_open(struct inode *inode, struct file *file)
goto out;
}

- if (atomic_read(drvdata->csdev->refcnt)) {
+ if (atomic_read(&drvdata->csdev->refcnt)) {
ret = -EBUSY;
goto out;
}
@@ -290,7 +290,7 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
if (ret)
goto out;

- atomic_inc(csdev->refcnt);
+ atomic_inc(&csdev->refcnt);

dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n");
out:
@@ -311,7 +311,7 @@ static int smb_disable(struct coresight_device *csdev)
goto out;
}

- if (atomic_dec_return(csdev->refcnt)) {
+ if (atomic_dec_return(&csdev->refcnt)) {
ret = -EBUSY;
goto out;
}
@@ -411,7 +411,7 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev,
mutex_lock(&drvdata->mutex);

/* Don't do anything if another tracer is using this sink. */
- if (atomic_read(csdev->refcnt) != 1)
+ if (atomic_read(&csdev->refcnt) != 1)
goto out;

smb_disable_hw(drvdata);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index e9c52c5ca7f3..b97edd24f3ec 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -111,8 +111,6 @@ union coresight_dev_subtype {
* unloaded the connection leaves an empty slot.
*/
struct coresight_platform_data {
- int high_inport;
- int high_outport;
int nr_inconns;
int nr_outconns;
struct coresight_connection **out_conns;
@@ -205,6 +203,8 @@ 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;
};

/**
@@ -256,7 +256,7 @@ struct coresight_device {
const struct coresight_ops *ops;
struct csdev_access access;
struct device dev;
- atomic_t *refcnt;
+ atomic_t refcnt;
bool orphan;
bool enable; /* true only if configured as part of a path */
/* sink specific fields */
@@ -341,8 +341,12 @@ struct coresight_ops_sink {
* @disable: disables flow between iport and oport.
*/
struct coresight_ops_link {
- int (*enable)(struct coresight_device *csdev, int iport, int oport);
- void (*disable)(struct coresight_device *csdev, int iport, int oport);
+ int (*enable)(struct coresight_device *csdev,
+ struct coresight_connection *in,
+ struct coresight_connection *out);
+ void (*disable)(struct coresight_device *csdev,
+ struct coresight_connection *in,
+ struct coresight_connection *out);
};

/**
--
2.34.1

2023-04-04 16:01:05

by James Clark

[permalink] [raw]
Subject: [PATCH v5 11/13] coresight: Refactor out buffer allocation function for ETR

When CATU is moved to the generic enable/disable path system in the
next commit, it will need to call into ETR and get it to pre-allocate
its buffer so add a function for it.

No functional changes

Signed-off-by: James Clark <[email protected]>
---
.../hwtracing/coresight/coresight-tmc-etr.c | 50 ++++++++++++++++---
drivers/hwtracing/coresight/coresight-tmc.h | 2 +
2 files changed, 45 insertions(+), 7 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 689ba6abc70b..00a0c2aa8481 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1169,7 +1169,7 @@ void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
drvdata->etr_buf = NULL;
}

-static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
+static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
{
int ret = 0;
unsigned long flags;
@@ -1192,7 +1192,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
/* Allocate memory with the locks released */
free_buf = new_buf = tmc_etr_setup_sysfs_buf(drvdata);
if (IS_ERR(new_buf))
- return PTR_ERR(new_buf);
+ return new_buf;

/* Let's try again */
spin_lock_irqsave(&drvdata->spinlock, flags);
@@ -1223,17 +1223,33 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
drvdata->sysfs_buf = new_buf;
}

- ret = tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf);
- if (!ret) {
- drvdata->mode = CS_MODE_SYSFS;
- atomic_inc(&csdev->refcnt);
- }
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);

/* Free memory outside the spinlock if need be */
if (free_buf)
tmc_etr_free_sysfs_buf(free_buf);
+ return ret ? ERR_PTR(ret) : drvdata->sysfs_buf;
+}
+
+static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
+{
+ int ret;
+ unsigned long flags;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ struct etr_buf *sysfs_buf = tmc_etr_get_sysfs_buffer(csdev);
+
+ if (IS_ERR(sysfs_buf))
+ return PTR_ERR(sysfs_buf);
+
+ spin_lock_irqsave(&drvdata->spinlock, flags);
+ ret = tmc_etr_enable_hw(drvdata, sysfs_buf);
+ if (!ret) {
+ drvdata->mode = CS_MODE_SYSFS;
+ atomic_inc(&csdev->refcnt);
+ }
+
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);

if (!ret)
dev_dbg(&csdev->dev, "TMC-ETR enabled\n");
@@ -1241,6 +1257,26 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
return ret;
}

+struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
+ enum cs_mode mode, void *data)
+{
+ struct perf_output_handle *handle = data;
+ struct etr_perf_buffer *etr_perf;
+
+ switch (mode) {
+ case CS_MODE_SYSFS:
+ return tmc_etr_get_sysfs_buffer(csdev);
+ case CS_MODE_PERF:
+ etr_perf = etm_perf_sink_config(handle);
+ if (WARN_ON(!etr_perf || !etr_perf->etr_buf))
+ return ERR_PTR(-EINVAL);
+ return etr_perf->etr_buf;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+}
+EXPORT_SYMBOL_GPL(tmc_etr_get_buffer);
+
/*
* alloc_etr_buf: Allocate ETR buffer for use by perf.
* The size of the hardware buffer is dependent on the size configured
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 01c0382a29c0..b97da39652d2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -332,5 +332,7 @@ struct coresight_device *tmc_etr_get_catu_device(struct tmc_drvdata *drvdata);

void tmc_etr_set_catu_ops(const struct etr_buf_operations *catu);
void tmc_etr_remove_catu_ops(void);
+struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
+ enum cs_mode mode, void *data);

#endif
--
2.34.1

2023-04-04 16:01:07

by James Clark

[permalink] [raw]
Subject: [PATCH v5 08/13] coresight: Simplify connection fixup mechanism

There is some duplication between coresight_fixup_device_conns() and
coresight_fixup_orphan_conns(). They both do the same thing except for
the fact that coresight_fixup_orphan_conns() can't handle iterating over
itself.

By making it able to handle fixing up it's own connections the other
function can be removed.

Signed-off-by: James Clark <[email protected]>
---
drivers/hwtracing/coresight/coresight-core.c | 84 ++++++++------------
1 file changed, 32 insertions(+), 52 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 0b738960973b..8d377a59e0be 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -1316,42 +1316,46 @@ static int coresight_orphan_match(struct device *dev, void *data)
{
int i, ret = 0;
bool still_orphan = false;
- struct coresight_device *csdev, *i_csdev;
+ struct coresight_device *dst_csdev = data;
+ struct coresight_device *src_csdev = to_coresight_device(dev);
struct coresight_connection *conn;
-
- csdev = data;
- i_csdev = to_coresight_device(dev);
-
- /* No need to check oneself */
- if (csdev == i_csdev)
- return 0;
+ bool fixup_self = (src_csdev == dst_csdev);

/* Move on to another component if no connection is orphan */
- if (!i_csdev->orphan)
+ if (!src_csdev->orphan)
return 0;
/*
- * Circle throuch all the connection of that component. If we find
- * an orphan connection whose name matches @csdev, link it.
+ * Circle through all the connections of that component. If we find
+ * an orphan connection whose name matches @dst_csdev, link it.
*/
- for (i = 0; i < i_csdev->pdata->nr_outconns; i++) {
- conn = i_csdev->pdata->out_conns[i];
-
- /* We have found at least one orphan connection */
- if (conn->dest_dev == NULL) {
- /* Does it match this newly added device? */
- if (conn->dest_fwnode == csdev->dev.fwnode) {
- ret = coresight_make_links(i_csdev,
- conn, csdev);
- if (ret)
- return ret;
- } else {
- /* This component still has an orphan */
- still_orphan = true;
- }
+ for (i = 0; i < src_csdev->pdata->nr_outconns; i++) {
+ conn = src_csdev->pdata->out_conns[i];
+
+ /* Skip the port if it's already connected. */
+ if (conn->dest_dev)
+ continue;
+
+ /*
+ * If we are at the "new" device, which triggered this search,
+ * we must find the remote device from the fwnode in the
+ * connection.
+ */
+ if (fixup_self)
+ dst_csdev = coresight_find_csdev_by_fwnode(
+ conn->dest_fwnode);
+
+ /* Does it match this newly added device? */
+ if (dst_csdev && conn->dest_fwnode == dst_csdev->dev.fwnode) {
+ ret = coresight_make_links(src_csdev, conn, dst_csdev);
+ if (ret)
+ return ret;
+ } else {
+ /* This component still has an orphan */
+ still_orphan = true;
}
}

- i_csdev->orphan = still_orphan;
+ src_csdev->orphan = still_orphan;

/*
* Returning '0' in case we didn't encounter any error,
@@ -1366,28 +1370,6 @@ static int coresight_fixup_orphan_conns(struct coresight_device *csdev)
csdev, coresight_orphan_match);
}

-
-static int coresight_fixup_device_conns(struct coresight_device *csdev)
-{
- int i, ret = 0;
-
- for (i = 0; i < csdev->pdata->nr_outconns; i++) {
- struct coresight_connection *conn = csdev->pdata->out_conns[i];
-
- conn->dest_dev =
- coresight_find_csdev_by_fwnode(conn->dest_fwnode);
- if (conn->dest_dev && conn->dest_dev->has_conns_grp) {
- ret = coresight_make_links(csdev, conn, conn->dest_dev);
- if (ret)
- break;
- } else {
- csdev->orphan = true;
- }
- }
-
- return ret;
-}
-
static int coresight_remove_match(struct device *dev, void *data)
{
int i;
@@ -1595,7 +1577,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
csdev->subtype = desc->subtype;
csdev->ops = desc->ops;
csdev->access = desc->access;
- csdev->orphan = false;
+ csdev->orphan = true;

csdev->dev.type = &coresight_dev_type[desc->type];
csdev->dev.groups = desc->groups;
@@ -1645,8 +1627,6 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
registered = true;

ret = coresight_create_conns_sysfs_group(csdev);
- if (!ret)
- ret = coresight_fixup_device_conns(csdev);
if (!ret)
ret = coresight_fixup_orphan_conns(csdev);

--
2.34.1

2023-04-04 16:01:08

by James Clark

[permalink] [raw]
Subject: [PATCH v5 09/13] coresight: Store in-connections as well as out-connections

This will allow CATU to get its associated ETR in a generic way where
currently the enable path has some hard coded searches which avoid
the need to store input connections.

This also means that the full search for connected devices on removal
can be replaced with a loop through only the input and output devices.

Signed-off-by: James Clark <[email protected]>
---
drivers/hwtracing/coresight/coresight-core.c | 81 +++++++++----------
.../hwtracing/coresight/coresight-platform.c | 31 ++++++-
drivers/hwtracing/coresight/coresight-sysfs.c | 7 --
include/linux/coresight.h | 26 ++++++
4 files changed, 95 insertions(+), 50 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 8d377a59e0be..a0a0ea2c626b 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -1349,6 +1349,17 @@ static int coresight_orphan_match(struct device *dev, void *data)
ret = coresight_make_links(src_csdev, conn, dst_csdev);
if (ret)
return ret;
+
+ /*
+ * Install the device connection. This also indicates that
+ * the links are operational on both ends.
+ */
+ conn->dest_dev = dst_csdev;
+ conn->src_dev = src_csdev;
+
+ ret = coresight_add_in_conn(conn);
+ if (ret)
+ return ret;
} else {
/* This component still has an orphan */
still_orphan = true;
@@ -1370,58 +1381,43 @@ static int coresight_fixup_orphan_conns(struct coresight_device *csdev)
csdev, coresight_orphan_match);
}

-static int coresight_remove_match(struct device *dev, void *data)
+/* coresight_remove_conns - Remove other device's references to this device */
+static void coresight_remove_conns(struct coresight_device *csdev)
{
- int i;
- struct coresight_device *csdev, *iterator;
+ int i, j;
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.
+ * Remove the input connection references from the destination device
+ * for each output connection.
*/
- for (i = 0; i < iterator->pdata->nr_outconns; i++) {
- conn = iterator->pdata->out_conns[i];
-
- /* Child_dev being set signifies that the links were made */
- if (csdev->dev.fwnode == conn->dest_fwnode && conn->dest_dev) {
- iterator->orphan = true;
- coresight_remove_links(iterator, conn);
- conn->dest_dev = NULL;
- /* No need to continue */
- break;
- }
+ for (i = 0; i < csdev->pdata->nr_outconns; i++) {
+ conn = csdev->pdata->out_conns[i];
+ if (!conn->dest_dev)
+ continue;
+
+ for (j = 0; j < conn->dest_dev->pdata->nr_inconns; ++j)
+ if (conn->dest_dev->pdata->in_conns[j] == conn) {
+ conn->dest_dev->pdata->in_conns[j] = NULL;
+ break;
+ }
}

/*
- * Returning '0' ensures that all known component on the
- * bus will be checked.
+ * For all input connections, remove references to this device.
+ * Connection objects are shared so modifying this device's input
+ * connections affects the other device's output connection.
*/
- return 0;
-}
+ for (i = 0; i < csdev->pdata->nr_inconns; ++i) {
+ conn = csdev->pdata->in_conns[i];
+ /* Input conns array is sparse */
+ if (!conn)
+ continue;

-/*
- * coresight_remove_conns - Remove references to this given devices
- * from the connections of other devices.
- */
-static void coresight_remove_conns(struct coresight_device *csdev)
-{
- /*
- * 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.
- */
- if (csdev->pdata->high_inport)
- bus_for_each_dev(&coresight_bustype, NULL,
- csdev, coresight_remove_match);
+ conn->src_dev->orphan = true;
+ coresight_remove_links(conn->src_dev, conn);
+ conn->dest_dev = NULL;
+ }
}

/**
@@ -1532,6 +1528,7 @@ void coresight_release_platform_data(struct coresight_device *csdev,
devm_kfree(dev, conns[i]);
}
devm_kfree(dev, pdata->out_conns);
+ devm_kfree(dev, pdata->in_conns);
devm_kfree(dev, pdata);
if (csdev)
coresight_remove_conns_sysfs_group(csdev);
diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
index 9c05f787278b..257ad48925a1 100644
--- a/drivers/hwtracing/coresight/coresight-platform.c
+++ b/drivers/hwtracing/coresight/coresight-platform.c
@@ -70,6 +70,35 @@ coresight_add_out_conn(struct device *dev,
}
EXPORT_SYMBOL_GPL(coresight_add_out_conn);

+/*
+ * Add an input connection reference to @out_conn in the target's in_conns array
+ *
+ * @out_conn: Existing output connection to store as an input on the
+ * connection's remote device.
+ */
+int coresight_add_in_conn(struct coresight_connection *out_conn)
+{
+ int i;
+ struct device *dev = out_conn->dest_dev->dev.parent;
+ struct coresight_platform_data *pdata = out_conn->dest_dev->pdata;
+
+ for (i = 0; i < pdata->nr_inconns; ++i)
+ if (!pdata->in_conns[i]) {
+ pdata->in_conns[i] = out_conn;
+ return 0;
+ }
+
+ pdata->nr_inconns++;
+ pdata->in_conns =
+ devm_krealloc_array(dev, pdata->in_conns, pdata->nr_inconns,
+ sizeof(*pdata->in_conns), GFP_KERNEL);
+ if (!pdata->in_conns)
+ return -ENOMEM;
+ pdata->in_conns[pdata->nr_inconns - 1] = out_conn;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(coresight_add_in_conn);
+
static struct device *
coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
{
@@ -240,7 +269,7 @@ static int of_coresight_get_cpu(struct device *dev)

/*
* of_coresight_parse_endpoint : Parse the given output endpoint @ep
- * and fill the connection information in @conn
+ * and fill the connection information in @pdata->out_conns
*
* Parses the local port, remote device name and the remote port.
*
diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
index a4a8e8e642e8..464ba5e1343b 100644
--- a/drivers/hwtracing/coresight/coresight-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-sysfs.c
@@ -173,12 +173,6 @@ int coresight_make_links(struct coresight_device *orig,
break;

conn->link = link;
-
- /*
- * Install the device connection. This also indicates that
- * the links are operational on both ends.
- */
- conn->dest_dev = target;
return 0;
} while (0);

@@ -202,5 +196,4 @@ void coresight_remove_links(struct coresight_device *orig,
devm_kfree(&orig->dev, conn->link->orig_name);
devm_kfree(&orig->dev, conn->link);
conn->link = NULL;
- conn->dest_dev = NULL;
}
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index abf36a37fdb0..e9c52c5ca7f3 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -106,6 +106,9 @@ union coresight_dev_subtype {
* @nr_outconns: Number of elements for the output connections.
* @out_conns: Array of nr_outconns pointers to connections from this
* component.
+ * @in_conns: Sparse array of pointers to input connections. Sparse
+ * because the source device owns the connection so when it's
+ * unloaded the connection leaves an empty slot.
*/
struct coresight_platform_data {
int high_inport;
@@ -113,6 +116,7 @@ struct coresight_platform_data {
int nr_inconns;
int nr_outconns;
struct coresight_connection **out_conns;
+ struct coresight_connection **in_conns;
};

/**
@@ -173,6 +177,26 @@ 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.
+ *
+ * The full connection structure looks like this, where in_conns store
+ * references to same connection as the source device's out_conns.
+ *
+ * +-----------------------------+ +-----------------------------+
+ * |coresight_device | |coresight_connection |
+ * |-----------------------------| |-----------------------------|
+ * | | | |
+ * | | | dest_dev*|<--
+ * |pdata->out_conns[nr_outconns]|<->|src_dev* | |
+ * | | | | |
+ * +-----------------------------+ +-----------------------------+ |
+ * |
+ * +-----------------------------+ |
+ * |coresight_device | |
+ * |------------------------------ |
+ * | | |
+ * | pdata->in_conns[nr_inconns]|<--
+ * | |
+ * +-----------------------------+
*/
struct coresight_connection {
int src_port;
@@ -180,6 +204,7 @@ struct coresight_connection {
struct fwnode_handle *dest_fwnode;
struct coresight_device *dest_dev;
struct coresight_sysfs_link *link;
+ struct coresight_device *src_dev;
};

/**
@@ -616,5 +641,6 @@ struct coresight_connection *
coresight_add_out_conn(struct device *dev,
struct coresight_platform_data *pdata,
const struct coresight_connection *new_conn);
+int coresight_add_in_conn(struct coresight_connection *conn);

#endif /* _LINUX_COREISGHT_H */
--
2.34.1

2023-04-04 16:01:20

by James Clark

[permalink] [raw]
Subject: [PATCH v5 12/13] coresight: Enable and disable helper devices adjacent to the path

Currently CATU is the only helper device, and its enable and disable
calls are hard coded. To allow more helper devices to be added in a
generic way, remove these hard coded calls and just enable and disable
all helper devices.

This has to apply to helpers adjacent to the path, because they will
never be in the path. CATU was already discovered in this way, so
there is no change there.

One change that is needed is for CATU to call back into ETR to allocate
the buffer. Because the enable call was previously hard coded, it was
done at a point where the buffer was already allocated, but this is no
longer the case.

Signed-off-by: James Clark <[email protected]>
---
drivers/hwtracing/coresight/coresight-catu.c | 21 ++-
drivers/hwtracing/coresight/coresight-core.c | 161 ++++++++++++++++--
.../hwtracing/coresight/coresight-etm-perf.c | 4 +-
drivers/hwtracing/coresight/coresight-priv.h | 3 +
.../hwtracing/coresight/coresight-tmc-etr.c | 43 +----
include/linux/coresight.h | 11 +-
6 files changed, 188 insertions(+), 55 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c
index bc90a03f478f..3949ded0d4fa 100644
--- a/drivers/hwtracing/coresight/coresight-catu.c
+++ b/drivers/hwtracing/coresight/coresight-catu.c
@@ -395,13 +395,18 @@ static inline int catu_wait_for_ready(struct catu_drvdata *drvdata)
return coresight_timeout(csa, CATU_STATUS, CATU_STATUS_READY, 1);
}

-static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
+static int catu_enable_hw(struct catu_drvdata *drvdata, enum cs_mode cs_mode,
+ void *data)
{
int rc;
u32 control, mode;
- struct etr_buf *etr_buf = data;
+ struct etr_buf *etr_buf = NULL;
struct device *dev = &drvdata->csdev->dev;
struct coresight_device *csdev = drvdata->csdev;
+ struct coresight_device *etrdev;
+ union coresight_dev_subtype etr_subtype = {
+ .sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM
+ };

if (catu_wait_for_ready(drvdata))
dev_warn(dev, "Timeout while waiting for READY\n");
@@ -416,6 +421,13 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
if (rc)
return rc;

+ etrdev = coresight_find_input_type(
+ csdev->pdata, CORESIGHT_DEV_TYPE_SINK, etr_subtype);
+ if (etrdev) {
+ etr_buf = tmc_etr_get_buffer(etrdev, cs_mode, data);
+ if (IS_ERR(etr_buf))
+ return PTR_ERR(etr_buf);
+ }
control |= BIT(CATU_CONTROL_ENABLE);

if (etr_buf && etr_buf->mode == ETR_MODE_CATU) {
@@ -441,13 +453,14 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
return 0;
}

-static int catu_enable(struct coresight_device *csdev, void *data)
+static int catu_enable(struct coresight_device *csdev, enum cs_mode mode,
+ void *data)
{
int rc;
struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev);

CS_UNLOCK(catu_drvdata->base);
- rc = catu_enable_hw(catu_drvdata, data);
+ rc = catu_enable_hw(catu_drvdata, mode, data);
CS_LOCK(catu_drvdata->base);
return rc;
}
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 939b7fb751b5..16689fe4ba98 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -403,8 +403,8 @@ static void coresight_disable_link(struct coresight_device *csdev,
csdev->enable = false;
}

-static int coresight_enable_source(struct coresight_device *csdev,
- enum cs_mode mode)
+int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
+ void *data)
{
int ret;

@@ -413,7 +413,7 @@ static int coresight_enable_source(struct coresight_device *csdev,
ret = coresight_control_assoc_ectdev(csdev, true);
if (ret)
return ret;
- ret = source_ops(csdev)->enable(csdev, NULL, mode);
+ ret = source_ops(csdev)->enable(csdev, data, mode);
if (ret) {
coresight_control_assoc_ectdev(csdev, false);
return ret;
@@ -426,25 +426,75 @@ static int coresight_enable_source(struct coresight_device *csdev,

return 0;
}
+EXPORT_SYMBOL_GPL(coresight_enable_source);
+
+static bool coresight_is_helper(struct coresight_device *csdev)
+{
+ return csdev->type == CORESIGHT_DEV_TYPE_HELPER;
+}
+
+static int coresight_enable_helper(struct coresight_device *csdev,
+ enum cs_mode mode, void *data)
+{
+ int ret;
+
+ if (!helper_ops(csdev)->enable)
+ return 0;
+ ret = helper_ops(csdev)->enable(csdev, mode, data);
+ if (ret)
+ return ret;
+
+ csdev->enable = true;
+ return 0;
+}
+
+static void coresight_disable_helper(struct coresight_device *csdev)
+{
+ int ret;
+
+ if (!helper_ops(csdev)->disable)
+ return;
+
+ ret = helper_ops(csdev)->disable(csdev, NULL);
+ if (ret)
+ return;
+ csdev->enable = false;
+}
+
+static void coresight_disable_helpers(struct coresight_device *csdev)
+{
+ int i;
+ struct coresight_device *helper;
+
+ for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
+ helper = csdev->pdata->out_conns[i]->dest_dev;
+ if (helper && coresight_is_helper(helper))
+ coresight_disable_helper(helper);
+ }
+}

/**
* coresight_disable_source - Drop the reference count by 1 and disable
* the device if there are no users left.
*
* @csdev: The coresight device to disable
+ * @data: Opaque data to pass on to the disable function of the source device.
+ * For example in perf mode this is a pointer to the struct perf_event.
*
* Returns true if the device has been disabled.
*/
-static bool coresight_disable_source(struct coresight_device *csdev)
+bool coresight_disable_source(struct coresight_device *csdev, void *data)
{
if (atomic_dec_return(&csdev->refcnt) == 0) {
if (source_ops(csdev)->disable)
- source_ops(csdev)->disable(csdev, NULL);
+ source_ops(csdev)->disable(csdev, data);
coresight_control_assoc_ectdev(csdev, false);
+ coresight_disable_helpers(csdev);
csdev->enable = false;
}
return !csdev->enable;
}
+EXPORT_SYMBOL_GPL(coresight_disable_source);

/*
* coresight_disable_path_from : Disable components in the given path beyond
@@ -495,6 +545,9 @@ static void coresight_disable_path_from(struct list_head *path,
default:
break;
}
+
+ /* Disable all helpers adjacent along the path last */
+ coresight_disable_helpers(csdev);
}
}

@@ -504,9 +557,28 @@ void coresight_disable_path(struct list_head *path)
}
EXPORT_SYMBOL_GPL(coresight_disable_path);

-int coresight_enable_path(struct list_head *path, enum cs_mode mode, void *sink_data)
+static int coresight_enable_helpers(struct coresight_device *csdev,
+ enum cs_mode mode, void *data)
{
+ int i, ret = 0;
+ struct coresight_device *helper;
+
+ for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
+ helper = csdev->pdata->out_conns[i]->dest_dev;
+ if (!helper || helper->type != CORESIGHT_DEV_TYPE_HELPER)
+ continue;
+
+ ret = coresight_enable_helper(helper, mode, data);
+ if (ret)
+ return ret;
+ }

+ return 0;
+}
+
+int coresight_enable_path(struct list_head *path, enum cs_mode mode,
+ void *sink_data)
+{
int ret = 0;
u32 type;
struct coresight_node *nd;
@@ -516,6 +588,10 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode, void *sink_
csdev = nd->csdev;
type = csdev->type;

+ /* Enable all helpers adjacent to the path first */
+ ret = coresight_enable_helpers(csdev, mode, sink_data);
+ if (ret)
+ goto err;
/*
* ETF devices are tricky... They can be a link or a sink,
* depending on how they are configured. If an ETF has been
@@ -710,7 +786,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
struct coresight_device *child;

child = csdev->pdata->out_conns[i]->dest_dev;
- if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
+ if (child && coresight_is_helper(child))
if (!coresight_get_ref(child))
goto err;
}
@@ -721,7 +797,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
struct coresight_device *child;

child = csdev->pdata->out_conns[i]->dest_dev;
- if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
+ if (child && coresight_is_helper(child))
coresight_put_ref(child);
}
return -ENODEV;
@@ -740,7 +816,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
struct coresight_device *child;

child = csdev->pdata->out_conns[i]->dest_dev;
- if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
+ if (child && coresight_is_helper(child))
coresight_put_ref(child);
}
}
@@ -1102,7 +1178,7 @@ int coresight_enable(struct coresight_device *csdev)
if (ret)
goto err_path;

- ret = coresight_enable_source(csdev, CS_MODE_SYSFS);
+ ret = coresight_enable_source(csdev, CS_MODE_SYSFS, NULL);
if (ret)
goto err_source;

@@ -1159,7 +1235,7 @@ void coresight_disable(struct coresight_device *csdev)
if (ret)
goto out;

- if (!csdev->enable || !coresight_disable_source(csdev))
+ if (!csdev->enable || !coresight_disable_source(csdev, NULL))
goto out;

switch (csdev->subtype.source_subtype) {
@@ -1644,6 +1720,69 @@ static inline int coresight_search_device_idx(struct coresight_dev_list *dict,
return -ENOENT;
}

+static bool coresight_compare_type(enum coresight_dev_type type_a,
+ union coresight_dev_subtype subtype_a,
+ enum coresight_dev_type type_b,
+ union coresight_dev_subtype subtype_b)
+{
+ if (type_a != type_b)
+ return false;
+
+ switch (type_a) {
+ case CORESIGHT_DEV_TYPE_SINK:
+ return subtype_a.sink_subtype == subtype_b.sink_subtype;
+ case CORESIGHT_DEV_TYPE_LINK:
+ return subtype_a.link_subtype == subtype_b.link_subtype;
+ case CORESIGHT_DEV_TYPE_LINKSINK:
+ return subtype_a.link_subtype == subtype_b.link_subtype &&
+ subtype_a.sink_subtype == subtype_b.sink_subtype;
+ case CORESIGHT_DEV_TYPE_SOURCE:
+ return subtype_a.source_subtype == subtype_b.source_subtype;
+ case CORESIGHT_DEV_TYPE_HELPER:
+ return subtype_a.helper_subtype == subtype_b.helper_subtype;
+ default:
+ return false;
+ }
+}
+
+struct coresight_device *
+coresight_find_input_type(struct coresight_platform_data *pdata,
+ enum coresight_dev_type type,
+ union coresight_dev_subtype subtype)
+{
+ int i;
+ struct coresight_connection *conn;
+
+ for (i = 0; i < pdata->nr_inconns; ++i) {
+ conn = pdata->in_conns[i];
+ if (conn &&
+ coresight_compare_type(type, subtype, conn->src_dev->type,
+ conn->src_dev->subtype))
+ return conn->src_dev;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(coresight_find_input_type);
+
+struct coresight_device *
+coresight_find_output_type(struct coresight_platform_data *pdata,
+ enum coresight_dev_type type,
+ union coresight_dev_subtype subtype)
+{
+ int i;
+ struct coresight_connection *conn;
+
+ for (i = 0; i < pdata->nr_outconns; ++i) {
+ conn = pdata->out_conns[i];
+ if (conn->dest_dev &&
+ coresight_compare_type(type, subtype, conn->dest_dev->type,
+ conn->dest_dev->subtype))
+ return conn->dest_dev;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(coresight_find_output_type);
+
bool coresight_loses_context_with_cpu(struct device *dev)
{
return fwnode_property_present(dev_fwnode(dev),
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index a48c97da8165..166adcf592cd 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -492,7 +492,7 @@ static void etm_event_start(struct perf_event *event, int flags)
goto fail_end_stop;

/* Finally enable the tracer */
- if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF))
+ if (coresight_enable_source(csdev, CS_MODE_PERF, event))
goto fail_disable_path;

/*
@@ -586,7 +586,7 @@ static void etm_event_stop(struct perf_event *event, int mode)
return;

/* stop tracer */
- source_ops(csdev)->disable(csdev, event);
+ coresight_disable_source(csdev, event);

/* tell the core */
event->hw.state = PERF_HES_STOPPED;
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 65ae6d161c57..5575014f73e0 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -216,5 +216,8 @@ void coresight_set_assoc_ectdev_mutex(struct coresight_device *csdev,

void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
struct coresight_device *coresight_get_percpu_sink(int cpu);
+int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
+ void *data);
+bool coresight_disable_source(struct coresight_device *csdev, void *data);

#endif
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 00a0c2aa8481..37afe8b52760 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -775,40 +775,19 @@ static const struct etr_buf_operations etr_sg_buf_ops = {
struct coresight_device *
tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
{
- int i;
- struct coresight_device *tmp, *etr = drvdata->csdev;
+ struct coresight_device *etr = drvdata->csdev;
+ union coresight_dev_subtype catu_subtype = {
+ .helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CATU
+ };

if (!IS_ENABLED(CONFIG_CORESIGHT_CATU))
return NULL;

- for (i = 0; i < etr->pdata->nr_outconns; i++) {
- tmp = etr->pdata->out_conns[i]->dest_dev;
- if (tmp && coresight_is_catu_device(tmp))
- return tmp;
- }
-
- return NULL;
+ return coresight_find_output_type(etr->pdata, CORESIGHT_DEV_TYPE_HELPER,
+ catu_subtype);
}
EXPORT_SYMBOL_GPL(tmc_etr_get_catu_device);

-static inline int tmc_etr_enable_catu(struct tmc_drvdata *drvdata,
- struct etr_buf *etr_buf)
-{
- struct coresight_device *catu = tmc_etr_get_catu_device(drvdata);
-
- if (catu && helper_ops(catu)->enable)
- return helper_ops(catu)->enable(catu, etr_buf);
- return 0;
-}
-
-static inline void tmc_etr_disable_catu(struct tmc_drvdata *drvdata)
-{
- struct coresight_device *catu = tmc_etr_get_catu_device(drvdata);
-
- if (catu && helper_ops(catu)->disable)
- helper_ops(catu)->disable(catu, drvdata->etr_buf);
-}
-
static const struct etr_buf_operations *etr_buf_ops[] = {
[ETR_MODE_FLAT] = &etr_flat_buf_ops,
[ETR_MODE_ETR_SG] = &etr_sg_buf_ops,
@@ -1058,13 +1037,6 @@ static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata,
if (WARN_ON(drvdata->etr_buf))
return -EBUSY;

- /*
- * If this ETR is connected to a CATU, enable it before we turn
- * this on.
- */
- rc = tmc_etr_enable_catu(drvdata, etr_buf);
- if (rc)
- return rc;
rc = coresight_claim_device(drvdata->csdev);
if (!rc) {
drvdata->etr_buf = etr_buf;
@@ -1072,7 +1044,6 @@ static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata,
if (rc) {
drvdata->etr_buf = NULL;
coresight_disclaim_device(drvdata->csdev);
- tmc_etr_disable_catu(drvdata);
}
}

@@ -1162,8 +1133,6 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
{
__tmc_etr_disable_hw(drvdata);
- /* Disable CATU device if this ETR is connected to one */
- tmc_etr_disable_catu(drvdata);
coresight_disclaim_device(drvdata->csdev);
/* Reset the ETR buf used by hardware */
drvdata->etr_buf = NULL;
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index b97edd24f3ec..61dfbab5fa98 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -375,7 +375,8 @@ struct coresight_ops_source {
* @disable : Disable the device
*/
struct coresight_ops_helper {
- int (*enable)(struct coresight_device *csdev, void *data);
+ int (*enable)(struct coresight_device *csdev, enum cs_mode mode,
+ void *data);
int (*disable)(struct coresight_device *csdev, void *data);
};

@@ -646,5 +647,13 @@ coresight_add_out_conn(struct device *dev,
struct coresight_platform_data *pdata,
const struct coresight_connection *new_conn);
int coresight_add_in_conn(struct coresight_connection *conn);
+struct coresight_device *
+coresight_find_input_type(struct coresight_platform_data *pdata,
+ enum coresight_dev_type type,
+ union coresight_dev_subtype subtype);
+struct coresight_device *
+coresight_find_output_type(struct coresight_platform_data *pdata,
+ enum coresight_dev_type type,
+ union coresight_dev_subtype subtype);

#endif /* _LINUX_COREISGHT_H */
--
2.34.1

2023-04-04 16:01:28

by James Clark

[permalink] [raw]
Subject: [PATCH v5 13/13] coresight: Fix CTI module refcount leak by making it a helper device

The CTI module has some hard coded refcounting code that has a leak.
For example running perf and then trying to unload it fails:

perf record -e cs_etm// -a -- ls
rmmod coresight_cti

rmmod: ERROR: Module coresight_cti is in use

The coresight core already handles references of devices in use, so by
making CTI a normal helper device, we get working refcounting for free.

Signed-off-by: James Clark <[email protected]>
---
drivers/hwtracing/coresight/coresight-core.c | 104 ++++++------------
.../hwtracing/coresight/coresight-cti-core.c | 52 +++++----
.../hwtracing/coresight/coresight-cti-sysfs.c | 4 +-
drivers/hwtracing/coresight/coresight-cti.h | 4 +-
drivers/hwtracing/coresight/coresight-priv.h | 4 +-
drivers/hwtracing/coresight/coresight-sysfs.c | 4 +
include/linux/coresight.h | 30 +----
7 files changed, 75 insertions(+), 127 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 16689fe4ba98..2af416bba983 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -236,60 +236,44 @@ void coresight_disclaim_device(struct coresight_device *csdev)
}
EXPORT_SYMBOL_GPL(coresight_disclaim_device);

-/* enable or disable an associated CTI device of the supplied CS device */
-static int
-coresight_control_assoc_ectdev(struct coresight_device *csdev, bool enable)
+/*
+ * Add a helper as an output device. This function takes the @coresight_mutex
+ * because it's assumed that it's called from the helper device, outside of the
+ * core code where the mutex would already be held. Don't add new calls to this
+ * from inside the core code, instead try to add the new helper to the DT and
+ * ACPI where it will be picked up and linked automatically.
+ */
+void coresight_add_helper(struct coresight_device *csdev,
+ struct coresight_device *helper)
{
- int ect_ret = 0;
- struct coresight_device *ect_csdev = csdev->ect_dev;
- struct module *mod;
+ int i;
+ struct coresight_connection conn = {};
+ struct coresight_connection *new_conn;

- if (!ect_csdev)
- return 0;
- if ((!ect_ops(ect_csdev)->enable) || (!ect_ops(ect_csdev)->disable))
- return 0;
+ mutex_lock(&coresight_mutex);
+ conn.dest_fwnode = fwnode_handle_get(dev_fwnode(&helper->dev));
+ conn.dest_dev = helper;
+ conn.dest_port = conn.src_port = -1;
+ conn.src_dev = csdev;

- mod = ect_csdev->dev.parent->driver->owner;
- if (enable) {
- 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;
- } else {
- if (csdev->ect_enabled) {
- ect_ret = ect_ops(ect_csdev)->disable(ect_csdev);
- put_device(ect_csdev->dev.parent);
- module_put(mod);
- csdev->ect_enabled = false;
- }
- }
+ /*
+ * Check for duplicates because this is called every time a helper
+ * device is re-loaded. Existing connections will get re-linked
+ * automatically.
+ */
+ for (i = 0; i < csdev->pdata->nr_outconns; ++i)
+ if (csdev->pdata->out_conns[i]->dest_fwnode == conn.dest_fwnode)
+ goto unlock;

- /* 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;
-}
+ new_conn =
+ coresight_add_out_conn(csdev->dev.parent, csdev->pdata, &conn);
+ if (!IS_ERR(new_conn))
+ coresight_add_in_conn(new_conn);

-/*
- * 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;
+unlock:
mutex_unlock(&coresight_mutex);
}
-EXPORT_SYMBOL_GPL(coresight_set_assoc_ectdev_mutex);
+EXPORT_SYMBOL_GPL(coresight_add_helper);

static int coresight_enable_sink(struct coresight_device *csdev,
enum cs_mode mode, void *data)
@@ -303,12 +287,8 @@ static int coresight_enable_sink(struct coresight_device *csdev,
if (!sink_ops(csdev)->enable)
return -EINVAL;

- ret = coresight_control_assoc_ectdev(csdev, true);
- if (ret)
- return ret;
ret = sink_ops(csdev)->enable(csdev, mode, data);
if (ret) {
- coresight_control_assoc_ectdev(csdev, false);
return ret;
}
csdev->enable = true;
@@ -326,7 +306,6 @@ static void coresight_disable_sink(struct coresight_device *csdev)
ret = sink_ops(csdev)->disable(csdev);
if (ret)
return;
- coresight_control_assoc_ectdev(csdev, false);
csdev->enable = false;
}

@@ -351,17 +330,11 @@ static int coresight_enable_link(struct coresight_device *csdev,
return PTR_ERR(outconn);

if (link_ops(csdev)->enable) {
- ret = coresight_control_assoc_ectdev(csdev, true);
- if (!ret) {
- ret = link_ops(csdev)->enable(csdev, inconn, outconn);
- if (ret)
- coresight_control_assoc_ectdev(csdev, false);
- }
+ ret = link_ops(csdev)->enable(csdev, inconn, outconn);
+ if (!ret)
+ csdev->enable = true;
}

- if (!ret)
- csdev->enable = true;
-
return ret;
}

@@ -382,7 +355,6 @@ static void coresight_disable_link(struct coresight_device *csdev,

if (link_ops(csdev)->disable) {
link_ops(csdev)->disable(csdev, inconn, outconn);
- coresight_control_assoc_ectdev(csdev, false);
}

if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
@@ -410,14 +382,9 @@ int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,

if (!csdev->enable) {
if (source_ops(csdev)->enable) {
- ret = coresight_control_assoc_ectdev(csdev, true);
- if (ret)
- return ret;
ret = source_ops(csdev)->enable(csdev, data, mode);
- if (ret) {
- coresight_control_assoc_ectdev(csdev, false);
+ if (ret)
return ret;
- }
}
csdev->enable = true;
}
@@ -488,7 +455,6 @@ bool coresight_disable_source(struct coresight_device *csdev, void *data)
if (atomic_dec_return(&csdev->refcnt) == 0) {
if (source_ops(csdev)->disable)
source_ops(csdev)->disable(csdev, data);
- coresight_control_assoc_ectdev(csdev, false);
coresight_disable_helpers(csdev);
csdev->enable = false;
}
diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
index 277c890a1f1f..7023ff70cc28 100644
--- a/drivers/hwtracing/coresight/coresight-cti-core.c
+++ b/drivers/hwtracing/coresight/coresight-cti-core.c
@@ -555,7 +555,10 @@ static void cti_add_assoc_to_csdev(struct coresight_device *csdev)
mutex_lock(&ect_mutex);

/* exit if current is an ECT device.*/
- if ((csdev->type == CORESIGHT_DEV_TYPE_ECT) || list_empty(&ect_net))
+ if ((csdev->type == CORESIGHT_DEV_TYPE_HELPER &&
+ csdev->subtype.helper_subtype ==
+ CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI) ||
+ list_empty(&ect_net))
goto cti_add_done;

/* if we didn't find the csdev previously we used the fwnode name */
@@ -571,8 +574,7 @@ static void cti_add_assoc_to_csdev(struct coresight_device *csdev)
* if we found a matching csdev then update the ECT
* association pointer for the device with this CTI.
*/
- coresight_set_assoc_ectdev_mutex(csdev,
- ect_item->csdev);
+ coresight_add_helper(csdev, ect_item->csdev);
break;
}
}
@@ -582,26 +584,30 @@ static void cti_add_assoc_to_csdev(struct coresight_device *csdev)

/*
* Removing the associated devices is easier.
- * A CTI will not have a value for csdev->ect_dev.
*/
static void cti_remove_assoc_from_csdev(struct coresight_device *csdev)
{
struct cti_drvdata *ctidrv;
struct cti_trig_con *tc;
struct cti_device *ctidev;
+ union coresight_dev_subtype cti_subtype = {
+ .helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI
+ };
+ struct coresight_device *cti_csdev = coresight_find_output_type(
+ csdev->pdata, CORESIGHT_DEV_TYPE_HELPER, cti_subtype);
+
+ if (!cti_csdev)
+ return;

mutex_lock(&ect_mutex);
- if (csdev->ect_dev) {
- ctidrv = csdev_to_cti_drvdata(csdev->ect_dev);
- ctidev = &ctidrv->ctidev;
- list_for_each_entry(tc, &ctidev->trig_cons, node) {
- if (tc->con_dev == csdev) {
- cti_remove_sysfs_link(ctidrv, tc);
- tc->con_dev = NULL;
- break;
- }
+ ctidrv = csdev_to_cti_drvdata(cti_csdev);
+ ctidev = &ctidrv->ctidev;
+ list_for_each_entry(tc, &ctidev->trig_cons, node) {
+ if (tc->con_dev == csdev) {
+ cti_remove_sysfs_link(ctidrv, tc);
+ tc->con_dev = NULL;
+ break;
}
- csdev->ect_dev = NULL;
}
mutex_unlock(&ect_mutex);
}
@@ -630,8 +636,8 @@ static void cti_update_conn_xrefs(struct cti_drvdata *drvdata)
/* if we can set the sysfs link */
if (cti_add_sysfs_link(drvdata, tc))
/* set the CTI/csdev association */
- coresight_set_assoc_ectdev_mutex(tc->con_dev,
- drvdata->csdev);
+ coresight_add_helper(tc->con_dev,
+ drvdata->csdev);
else
/* otherwise remove reference from CTI */
tc->con_dev = NULL;
@@ -646,8 +652,6 @@ static void cti_remove_conn_xrefs(struct cti_drvdata *drvdata)

list_for_each_entry(tc, &ctidev->trig_cons, node) {
if (tc->con_dev) {
- coresight_set_assoc_ectdev_mutex(tc->con_dev,
- NULL);
cti_remove_sysfs_link(drvdata, tc);
tc->con_dev = NULL;
}
@@ -795,27 +799,27 @@ static void cti_pm_release(struct cti_drvdata *drvdata)
}

/** cti ect operations **/
-int cti_enable(struct coresight_device *csdev)
+int cti_enable(struct coresight_device *csdev, enum cs_mode mode, void *data)
{
struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);

return cti_enable_hw(drvdata);
}

-int cti_disable(struct coresight_device *csdev)
+int cti_disable(struct coresight_device *csdev, void *data)
{
struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);

return cti_disable_hw(drvdata);
}

-static const struct coresight_ops_ect cti_ops_ect = {
+static const struct coresight_ops_helper cti_ops_ect = {
.enable = cti_enable,
.disable = cti_disable,
};

static const struct coresight_ops cti_ops = {
- .ect_ops = &cti_ops_ect,
+ .helper_ops = &cti_ops_ect,
};

/*
@@ -922,8 +926,8 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)

/* set up coresight component description */
cti_desc.pdata = pdata;
- cti_desc.type = CORESIGHT_DEV_TYPE_ECT;
- cti_desc.subtype.ect_subtype = CORESIGHT_DEV_SUBTYPE_ECT_CTI;
+ cti_desc.type = CORESIGHT_DEV_TYPE_HELPER;
+ cti_desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI;
cti_desc.ops = &cti_ops;
cti_desc.groups = drvdata->ctidev.con_groups;
cti_desc.dev = dev;
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
index e528cff9d4e2..d25dd2737b49 100644
--- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
@@ -112,11 +112,11 @@ static ssize_t enable_store(struct device *dev,
ret = pm_runtime_resume_and_get(dev->parent);
if (ret)
return ret;
- ret = cti_enable(drvdata->csdev);
+ ret = cti_enable(drvdata->csdev, CS_MODE_SYSFS, NULL);
if (ret)
pm_runtime_put(dev->parent);
} else {
- ret = cti_disable(drvdata->csdev);
+ ret = cti_disable(drvdata->csdev, NULL);
if (!ret)
pm_runtime_put(dev->parent);
}
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
index 8b106b13a244..cb9ee616d01f 100644
--- a/drivers/hwtracing/coresight/coresight-cti.h
+++ b/drivers/hwtracing/coresight/coresight-cti.h
@@ -215,8 +215,8 @@ int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
const char *assoc_dev_name);
struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
int out_sigs);
-int cti_enable(struct coresight_device *csdev);
-int cti_disable(struct coresight_device *csdev);
+int cti_enable(struct coresight_device *csdev, enum cs_mode mode, void *data);
+int cti_disable(struct coresight_device *csdev, void *data);
void cti_write_all_hw_regs(struct cti_drvdata *drvdata);
void cti_write_intack(struct device *dev, u32 ackval);
void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value);
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 5575014f73e0..1801ff4e467b 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -211,8 +211,8 @@ void coresight_release_platform_data(struct coresight_device *csdev,
struct coresight_platform_data *pdata);
struct coresight_device *
coresight_find_csdev_by_fwnode(struct fwnode_handle *r_fwnode);
-void coresight_set_assoc_ectdev_mutex(struct coresight_device *csdev,
- struct coresight_device *ect_csdev);
+void coresight_add_helper(struct coresight_device *csdev,
+ struct coresight_device *helper);

void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
struct coresight_device *coresight_get_percpu_sink(int cpu);
diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
index 464ba5e1343b..dd78e9fcfc4d 100644
--- a/drivers/hwtracing/coresight/coresight-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-sysfs.c
@@ -148,6 +148,10 @@ int coresight_make_links(struct coresight_device *orig,
char *outs = NULL, *ins = NULL;
struct coresight_sysfs_link *link = NULL;

+ /* Helper devices aren't shown in sysfs */
+ if (conn->dest_port == -1 && conn->src_port == -1)
+ return 0;
+
do {
outs = devm_kasprintf(&orig->dev, GFP_KERNEL,
"out:%d", conn->src_port);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 61dfbab5fa98..225a5fa71baf 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -40,8 +40,7 @@ enum coresight_dev_type {
CORESIGHT_DEV_TYPE_LINK,
CORESIGHT_DEV_TYPE_LINKSINK,
CORESIGHT_DEV_TYPE_SOURCE,
- CORESIGHT_DEV_TYPE_HELPER,
- CORESIGHT_DEV_TYPE_ECT,
+ CORESIGHT_DEV_TYPE_HELPER
};

enum coresight_dev_subtype_sink {
@@ -66,12 +65,7 @@ enum coresight_dev_subtype_source {

enum coresight_dev_subtype_helper {
CORESIGHT_DEV_SUBTYPE_HELPER_CATU,
-};
-
-/* Embedded Cross Trigger (ECT) sub-types */
-enum coresight_dev_subtype_ect {
- CORESIGHT_DEV_SUBTYPE_ECT_NONE,
- CORESIGHT_DEV_SUBTYPE_ECT_CTI,
+ CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI
};

/**
@@ -84,8 +78,6 @@ enum coresight_dev_subtype_ect {
* by @coresight_dev_subtype_source.
* @helper_subtype: type of helper this component is, as defined
* by @coresight_dev_subtype_helper.
- * @ect_subtype: type of cross trigger this component is, as
- * defined by @coresight_dev_subtype_ect
*/
union coresight_dev_subtype {
/* We have some devices which acts as LINK and SINK */
@@ -95,7 +87,6 @@ union coresight_dev_subtype {
};
enum coresight_dev_subtype_source source_subtype;
enum coresight_dev_subtype_helper helper_subtype;
- enum coresight_dev_subtype_ect ect_subtype;
};

/**
@@ -239,8 +230,6 @@ struct coresight_sysfs_link {
* from source to that sink.
* @ea: Device attribute for sink representation under PMU directory.
* @def_sink: cached reference to default sink found for this device.
- * @ect_dev: Associated cross trigger device. Not part of the trace data
- * path or connections.
* @nr_links: number of sysfs links created to other components from this
* device. These will appear in the "connections" group.
* @has_conns_grp: Have added a "connections" group for sysfs links.
@@ -263,12 +252,9 @@ struct coresight_device {
bool activated; /* true only if a sink is part of a path */
struct dev_ext_attribute *ea;
struct coresight_device *def_sink;
- /* cross trigger handling */
- struct coresight_device *ect_dev;
/* sysfs links between components */
int nr_links;
bool has_conns_grp;
- bool ect_enabled; /* true only if associated ect device is enabled */
/* system configuration and feature lists */
struct list_head feature_csdev_list;
struct list_head config_csdev_list;
@@ -380,23 +366,11 @@ struct coresight_ops_helper {
int (*disable)(struct coresight_device *csdev, void *data);
};

-/**
- * struct coresight_ops_ect - Ops for an embedded cross trigger device
- *
- * @enable : Enable the device
- * @disable : Disable the device
- */
-struct coresight_ops_ect {
- int (*enable)(struct coresight_device *csdev);
- int (*disable)(struct coresight_device *csdev);
-};
-
struct coresight_ops {
const struct coresight_ops_sink *sink_ops;
const struct coresight_ops_link *link_ops;
const struct coresight_ops_source *source_ops;
const struct coresight_ops_helper *helper_ops;
- const struct coresight_ops_ect *ect_ops;
};

#if IS_ENABLED(CONFIG_CORESIGHT)
--
2.34.1

2023-04-04 16:01:29

by James Clark

[permalink] [raw]
Subject: [PATCH v5 04/13] coresight: Rename nr_outports to nr_outconns

Rename to avoid confusion between port number and the index in the
connection array. The port number is already stored in the connection,
and in a later commit the connection array will be appended to, so
the length of it will no longer reflect the number of ports.

No functional changes.

Reviewed-by: Mike Leach <[email protected]>
Signed-off-by: James Clark <[email protected]>
---
drivers/hwtracing/coresight/coresight-core.c | 32 ++++++++---------
.../hwtracing/coresight/coresight-platform.c | 34 +++++++++----------
.../hwtracing/coresight/coresight-tmc-etr.c | 2 +-
include/linux/coresight.h | 10 +++---
4 files changed, 39 insertions(+), 39 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 04c9d52f8f4f..0f6712a6fba3 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -118,7 +118,7 @@ static int coresight_find_link_inport(struct coresight_device *csdev,
int i;
struct coresight_connection *conn;

- for (i = 0; i < parent->pdata->nr_outport; i++) {
+ for (i = 0; i < parent->pdata->nr_outconns; i++) {
conn = &parent->pdata->out_conns[i];
if (conn->child_dev == csdev)
return conn->child_port;
@@ -136,7 +136,7 @@ static int coresight_find_link_outport(struct coresight_device *csdev,
int i;
struct coresight_connection *conn;

- for (i = 0; i < csdev->pdata->nr_outport; i++) {
+ for (i = 0; i < csdev->pdata->nr_outconns; i++) {
conn = &csdev->pdata->out_conns[i];
if (conn->child_dev == child)
return conn->outport;
@@ -397,9 +397,9 @@ static void coresight_disable_link(struct coresight_device *csdev,
link_subtype = csdev->subtype.link_subtype;

if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
- nr_conns = csdev->pdata->nr_inport;
+ nr_conns = csdev->pdata->nr_inconns;
} else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
- nr_conns = csdev->pdata->nr_outport;
+ nr_conns = csdev->pdata->nr_outconns;
} else {
nr_conns = 1;
}
@@ -603,7 +603,7 @@ coresight_find_enabled_sink(struct coresight_device *csdev)
/*
* Recursively explore each port found on this element.
*/
- for (i = 0; i < csdev->pdata->nr_outport; i++) {
+ for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child_dev;

child_dev = csdev->pdata->out_conns[i].child_dev;
@@ -719,7 +719,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
{
int i;

- for (i = 0; i < csdev->pdata->nr_outport; i++) {
+ for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child;

child = csdev->pdata->out_conns[i].child_dev;
@@ -749,7 +749,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
int i;

coresight_put_ref(csdev);
- for (i = 0; i < csdev->pdata->nr_outport; i++) {
+ for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child;

child = csdev->pdata->out_conns[i].child_dev;
@@ -791,7 +791,7 @@ static int _coresight_build_path(struct coresight_device *csdev,
}

/* Not a sink - recursively explore each port found on this element */
- for (i = 0; i < csdev->pdata->nr_outport; i++) {
+ for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child_dev;

child_dev = csdev->pdata->out_conns[i].child_dev;
@@ -960,7 +960,7 @@ coresight_find_sink(struct coresight_device *csdev, int *depth)
* 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++) {
+ for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child_dev, *sink = NULL;
int child_depth = curr_depth;

@@ -1333,7 +1333,7 @@ static int coresight_orphan_match(struct device *dev, void *data)
* Circle throuch all the connection of that component. If we find
* an orphan connection whose name matches @csdev, link it.
*/
- for (i = 0; i < i_csdev->pdata->nr_outport; i++) {
+ for (i = 0; i < i_csdev->pdata->nr_outconns; i++) {
conn = &i_csdev->pdata->out_conns[i];

/* Skip the port if FW doesn't describe it */
@@ -1374,7 +1374,7 @@ static int coresight_fixup_device_conns(struct coresight_device *csdev)
{
int i, ret = 0;

- for (i = 0; i < csdev->pdata->nr_outport; i++) {
+ for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_connection *conn = &csdev->pdata->out_conns[i];

if (!conn->child_fwnode)
@@ -1411,7 +1411,7 @@ static int coresight_remove_match(struct device *dev, void *data)
* Circle throuch all the connection of that component. If we find
* a connection whose name matches @csdev, remove it.
*/
- for (i = 0; i < iterator->pdata->nr_outport; i++) {
+ for (i = 0; i < iterator->pdata->nr_outconns; i++) {
conn = &iterator->pdata->out_conns[i];

if (conn->child_dev == NULL || conn->child_fwnode == NULL)
@@ -1446,7 +1446,7 @@ static void coresight_remove_conns(struct coresight_device *csdev)
* doesn't have at least one input port, there is no point
* in searching all the devices.
*/
- if (csdev->pdata->nr_inport)
+ if (csdev->pdata->nr_inconns)
bus_for_each_dev(&coresight_bustype, NULL,
csdev, coresight_remove_match);
}
@@ -1545,7 +1545,7 @@ void coresight_release_platform_data(struct coresight_device *csdev,
int i;
struct coresight_connection *conns = pdata->out_conns;

- for (i = 0; i < pdata->nr_outport; i++) {
+ for (i = 0; i < pdata->nr_outconns; i++) {
/* If we have made the links, remove them now */
if (csdev && conns[i].child_dev)
coresight_remove_links(csdev, &conns[i]);
@@ -1582,9 +1582,9 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
link_subtype = desc->subtype.link_subtype;

if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
- nr_refcnts = desc->pdata->nr_inport;
+ nr_refcnts = desc->pdata->nr_inconns;
else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
- nr_refcnts = desc->pdata->nr_outport;
+ nr_refcnts = desc->pdata->nr_outconns;
}

refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
index 5085525a32bb..ed865e0621a9 100644
--- a/drivers/hwtracing/coresight/coresight-platform.c
+++ b/drivers/hwtracing/coresight/coresight-platform.c
@@ -26,8 +26,8 @@
static int coresight_alloc_conns(struct device *dev,
struct coresight_platform_data *pdata)
{
- if (pdata->nr_outport) {
- pdata->out_conns = devm_kcalloc(dev, pdata->nr_outport,
+ if (pdata->nr_outconns) {
+ pdata->out_conns = devm_kcalloc(dev, pdata->nr_outconns,
sizeof(*pdata->out_conns), GFP_KERNEL);
if (!pdata->out_conns)
return -ENOMEM;
@@ -84,7 +84,7 @@ static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
}

static void of_coresight_get_ports_legacy(const struct device_node *node,
- int *nr_inport, int *nr_outport)
+ int *nr_inconns, int *nr_outconns)
{
struct device_node *ep = NULL;
struct of_endpoint endpoint;
@@ -114,8 +114,8 @@ static void of_coresight_get_ports_legacy(const struct device_node *node,

} while (ep);

- *nr_inport = in;
- *nr_outport = out;
+ *nr_inconns = in;
+ *nr_outconns = out;
}

static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
@@ -164,7 +164,7 @@ of_coresight_count_ports(struct device_node *port_parent)
}

static void of_coresight_get_ports(const struct device_node *node,
- int *nr_inport, int *nr_outport)
+ int *nr_inconns, int *nr_outconns)
{
struct device_node *input_ports = NULL, *output_ports = NULL;

@@ -173,16 +173,16 @@ static void of_coresight_get_ports(const struct device_node *node,

if (input_ports || output_ports) {
if (input_ports) {
- *nr_inport = of_coresight_count_ports(input_ports);
+ *nr_inconns = of_coresight_count_ports(input_ports);
of_node_put(input_ports);
}
if (output_ports) {
- *nr_outport = of_coresight_count_ports(output_ports);
+ *nr_outconns = of_coresight_count_ports(output_ports);
of_node_put(output_ports);
}
} else {
/* Fall back to legacy DT bindings parsing */
- of_coresight_get_ports_legacy(node, nr_inport, nr_outport);
+ of_coresight_get_ports_legacy(node, nr_inconns, nr_outconns);
}
}

@@ -289,10 +289,10 @@ static int of_get_coresight_platform_data(struct device *dev,
struct device_node *node = dev->of_node;

/* Get the number of input and output port for this component */
- of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
+ of_coresight_get_ports(node, &pdata->nr_inconns, &pdata->nr_outconns);

/* If there are no output connections, we are done */
- if (!pdata->nr_outport)
+ if (!pdata->nr_outconns)
return 0;

ret = coresight_alloc_conns(dev, pdata);
@@ -690,7 +690,7 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
const union acpi_object *graph;
struct coresight_connection *conns, *ptr;

- pdata->nr_inport = pdata->nr_outport = 0;
+ pdata->nr_inconns = pdata->nr_outconns = 0;
graph = acpi_get_coresight_graph(adev);
if (!graph)
return -ENOENT;
@@ -718,11 +718,11 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
return dir;

if (dir == ACPI_CORESIGHT_LINK_MASTER) {
- if (ptr->outport >= pdata->nr_outport)
- pdata->nr_outport = ptr->outport + 1;
+ if (ptr->outport >= pdata->nr_outconns)
+ pdata->nr_outconns = ptr->outport + 1;
ptr++;
} else {
- WARN_ON(pdata->nr_inport == ptr->child_port + 1);
+ WARN_ON(pdata->nr_inconns == ptr->child_port + 1);
/*
* We do not track input port connections for a device.
* However we need the highest port number described,
@@ -730,8 +730,8 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
* record for an output connection. Hence, do not move
* the ptr for input connections
*/
- if (ptr->child_port >= pdata->nr_inport)
- pdata->nr_inport = ptr->child_port + 1;
+ if (ptr->child_port >= pdata->nr_inconns)
+ pdata->nr_inconns = ptr->child_port + 1;
}
}

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 86d4a08aa833..4711dfa7418c 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -781,7 +781,7 @@ tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
if (!IS_ENABLED(CONFIG_CORESIGHT_CATU))
return NULL;

- for (i = 0; i < etr->pdata->nr_outport; i++) {
+ for (i = 0; i < etr->pdata->nr_outconns; i++) {
tmp = etr->pdata->out_conns[i].child_dev;
if (tmp && coresight_is_catu_device(tmp))
return tmp;
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index bf621d064ef8..daf392fcb67a 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -102,13 +102,13 @@ union coresight_dev_subtype {
* struct coresight_platform_data - data harvested from the firmware
* specification.
*
- * @nr_inport: Number of elements for the input connections.
- * @nr_outport: Number of elements for the output connections.
- * @out_conns: Sparse array of nr_outport connections from this component.
+ * @nr_inconns: Number of elements for the input connections.
+ * @nr_outconns: Number of elements for the output connections.
+ * @out_conns: Sparse array of nr_outconns connections from this component.
*/
struct coresight_platform_data {
- int nr_inport;
- int nr_outport;
+ int nr_inconns;
+ int nr_outconns;
struct coresight_connection *out_conns;
};

--
2.34.1

2023-04-04 16:04:09

by James Clark

[permalink] [raw]
Subject: [PATCH v5 05/13] coresight: Rename connection members to make the direction explicit

When input connections are added they will use the same connection
object as the output so parent and child could be misinterpreted. Making
the direction unambiguous in the names should improve readability.

Signed-off-by: James Clark <[email protected]>
---
drivers/hwtracing/coresight/coresight-core.c | 51 +++++++++----------
.../hwtracing/coresight/coresight-platform.c | 30 +++++------
drivers/hwtracing/coresight/coresight-sysfs.c | 10 ++--
.../hwtracing/coresight/coresight-tmc-etr.c | 2 +-
include/linux/coresight.h | 18 +++----
5 files changed, 55 insertions(+), 56 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 0f6712a6fba3..f3dc320b374c 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -120,8 +120,8 @@ static int coresight_find_link_inport(struct coresight_device *csdev,

for (i = 0; i < parent->pdata->nr_outconns; i++) {
conn = &parent->pdata->out_conns[i];
- if (conn->child_dev == csdev)
- return conn->child_port;
+ if (conn->dest_dev == csdev)
+ return conn->dest_port;
}

dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n",
@@ -138,8 +138,8 @@ static int coresight_find_link_outport(struct coresight_device *csdev,

for (i = 0; i < csdev->pdata->nr_outconns; i++) {
conn = &csdev->pdata->out_conns[i];
- if (conn->child_dev == child)
- return conn->outport;
+ if (conn->dest_dev == child)
+ return conn->src_port;
}

dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n",
@@ -606,7 +606,7 @@ coresight_find_enabled_sink(struct coresight_device *csdev)
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child_dev;

- child_dev = csdev->pdata->out_conns[i].child_dev;
+ child_dev = csdev->pdata->out_conns[i].dest_dev;
if (child_dev)
sink = coresight_find_enabled_sink(child_dev);
if (sink)
@@ -722,7 +722,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child;

- child = csdev->pdata->out_conns[i].child_dev;
+ child = csdev->pdata->out_conns[i].dest_dev;
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
if (!coresight_get_ref(child))
goto err;
@@ -733,7 +733,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
for (i--; i >= 0; i--) {
struct coresight_device *child;

- child = csdev->pdata->out_conns[i].child_dev;
+ child = csdev->pdata->out_conns[i].dest_dev;
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
coresight_put_ref(child);
}
@@ -752,7 +752,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child;

- child = csdev->pdata->out_conns[i].child_dev;
+ child = csdev->pdata->out_conns[i].dest_dev;
if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
coresight_put_ref(child);
}
@@ -794,7 +794,7 @@ static int _coresight_build_path(struct coresight_device *csdev,
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_device *child_dev;

- child_dev = csdev->pdata->out_conns[i].child_dev;
+ child_dev = csdev->pdata->out_conns[i].dest_dev;
if (child_dev &&
_coresight_build_path(child_dev, sink, path) == 0) {
found = true;
@@ -964,7 +964,7 @@ coresight_find_sink(struct coresight_device *csdev, int *depth)
struct coresight_device *child_dev, *sink = NULL;
int child_depth = curr_depth;

- child_dev = csdev->pdata->out_conns[i].child_dev;
+ child_dev = csdev->pdata->out_conns[i].dest_dev;
if (child_dev)
sink = coresight_find_sink(child_dev, &child_depth);

@@ -1337,12 +1337,12 @@ static int coresight_orphan_match(struct device *dev, void *data)
conn = &i_csdev->pdata->out_conns[i];

/* Skip the port if FW doesn't describe it */
- if (!conn->child_fwnode)
+ if (!conn->dest_fwnode)
continue;
/* We have found at least one orphan connection */
- if (conn->child_dev == NULL) {
+ if (conn->dest_dev == NULL) {
/* Does it match this newly added device? */
- if (conn->child_fwnode == csdev->dev.fwnode) {
+ if (conn->dest_fwnode == csdev->dev.fwnode) {
ret = coresight_make_links(i_csdev,
conn, csdev);
if (ret)
@@ -1377,13 +1377,12 @@ static int coresight_fixup_device_conns(struct coresight_device *csdev)
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_connection *conn = &csdev->pdata->out_conns[i];

- if (!conn->child_fwnode)
+ if (!conn->dest_fwnode)
continue;
- conn->child_dev =
- coresight_find_csdev_by_fwnode(conn->child_fwnode);
- if (conn->child_dev && conn->child_dev->has_conns_grp) {
- ret = coresight_make_links(csdev, conn,
- conn->child_dev);
+ conn->dest_dev =
+ coresight_find_csdev_by_fwnode(conn->dest_fwnode);
+ if (conn->dest_dev && conn->dest_dev->has_conns_grp) {
+ ret = coresight_make_links(csdev, conn, conn->dest_dev);
if (ret)
break;
} else {
@@ -1414,14 +1413,14 @@ static int coresight_remove_match(struct device *dev, void *data)
for (i = 0; i < iterator->pdata->nr_outconns; i++) {
conn = &iterator->pdata->out_conns[i];

- if (conn->child_dev == NULL || conn->child_fwnode == NULL)
+ if (conn->dest_dev == NULL || conn->dest_fwnode == NULL)
continue;

- if (csdev->dev.fwnode == conn->child_fwnode) {
+ if (csdev->dev.fwnode == conn->dest_fwnode) {
iterator->orphan = true;
coresight_remove_links(iterator, conn);

- conn->child_dev = NULL;
+ conn->dest_dev = NULL;
/* No need to continue */
break;
}
@@ -1547,15 +1546,15 @@ void coresight_release_platform_data(struct coresight_device *csdev,

for (i = 0; i < pdata->nr_outconns; i++) {
/* If we have made the links, remove them now */
- if (csdev && conns[i].child_dev)
+ if (csdev && conns[i].dest_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);
- conns[i].child_fwnode = NULL;
+ if (conns[i].dest_fwnode) {
+ fwnode_handle_put(conns[i].dest_fwnode);
+ conns[i].dest_fwnode = NULL;
}
}
if (csdev)
diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
index ed865e0621a9..566cc99a2c34 100644
--- a/drivers/hwtracing/coresight/coresight-platform.c
+++ b/drivers/hwtracing/coresight/coresight-platform.c
@@ -252,13 +252,13 @@ static int of_coresight_parse_endpoint(struct device *dev,
}

conn = &pdata->out_conns[endpoint.port];
- if (conn->child_fwnode) {
+ if (conn->dest_fwnode) {
dev_warn(dev, "Duplicate output port %d\n",
endpoint.port);
ret = -EINVAL;
break;
}
- conn->outport = endpoint.port;
+ conn->src_port = endpoint.port;
/*
* Hold the refcount to the target device. This could be
* released via:
@@ -267,8 +267,8 @@ static int of_coresight_parse_endpoint(struct device *dev,
* 2) While removing the target device via
* coresight_remove_match()
*/
- conn->child_fwnode = fwnode_handle_get(rdev_fwnode);
- conn->child_port = rendpoint.port;
+ conn->dest_fwnode = fwnode_handle_get(rdev_fwnode);
+ conn->dest_port = rendpoint.port;
/* Connection record updated */
} while (0);

@@ -649,8 +649,8 @@ static int acpi_coresight_parse_link(struct acpi_device *adev,

dir = fields[3].integer.value;
if (dir == ACPI_CORESIGHT_LINK_MASTER) {
- conn->outport = fields[0].integer.value;
- conn->child_port = fields[1].integer.value;
+ conn->src_port = fields[0].integer.value;
+ conn->dest_port = fields[1].integer.value;
rdev = coresight_find_device_by_fwnode(&r_adev->fwnode);
if (!rdev)
return -EPROBE_DEFER;
@@ -662,14 +662,14 @@ static int acpi_coresight_parse_link(struct acpi_device *adev,
* 2) While removing the target device via
* coresight_remove_match().
*/
- conn->child_fwnode = fwnode_handle_get(&r_adev->fwnode);
+ conn->dest_fwnode = fwnode_handle_get(&r_adev->fwnode);
} else if (dir == ACPI_CORESIGHT_LINK_SLAVE) {
/*
* We are only interested in the port number
* for the input ports at this component.
* Store the port number in child_port.
*/
- conn->child_port = fields[0].integer.value;
+ conn->dest_port = fields[0].integer.value;
} else {
/* Invalid direction */
return -EINVAL;
@@ -718,11 +718,11 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
return dir;

if (dir == ACPI_CORESIGHT_LINK_MASTER) {
- if (ptr->outport >= pdata->nr_outconns)
- pdata->nr_outconns = ptr->outport + 1;
+ if (ptr->src_port >= pdata->nr_outconns)
+ pdata->nr_outconns = ptr->src_port + 1;
ptr++;
} else {
- WARN_ON(pdata->nr_inconns == ptr->child_port + 1);
+ WARN_ON(pdata->nr_inconns == ptr->dest_port + 1);
/*
* We do not track input port connections for a device.
* However we need the highest port number described,
@@ -730,8 +730,8 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
* record for an output connection. Hence, do not move
* the ptr for input connections
*/
- if (ptr->child_port >= pdata->nr_inconns)
- pdata->nr_inconns = ptr->child_port + 1;
+ if (ptr->dest_port >= pdata->nr_inconns)
+ pdata->nr_inconns = ptr->dest_port + 1;
}
}

@@ -741,10 +741,10 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,

/* Copy the connection information to the final location */
for (i = 0; conns + i < ptr; i++) {
- int port = conns[i].outport;
+ int port = conns[i].src_port;

/* Duplicate output port */
- WARN_ON(pdata->out_conns[port].child_fwnode);
+ WARN_ON(pdata->out_conns[port].dest_fwnode);
pdata->out_conns[port] = conns[i];
}

diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
index 34d2a2d31d00..a4a8e8e642e8 100644
--- a/drivers/hwtracing/coresight/coresight-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-sysfs.c
@@ -150,11 +150,11 @@ int coresight_make_links(struct coresight_device *orig,

do {
outs = devm_kasprintf(&orig->dev, GFP_KERNEL,
- "out:%d", conn->outport);
+ "out:%d", conn->src_port);
if (!outs)
break;
ins = devm_kasprintf(&target->dev, GFP_KERNEL,
- "in:%d", conn->child_port);
+ "in:%d", conn->dest_port);
if (!ins)
break;
link = devm_kzalloc(&orig->dev,
@@ -178,7 +178,7 @@ int coresight_make_links(struct coresight_device *orig,
* Install the device connection. This also indicates that
* the links are operational on both ends.
*/
- conn->child_dev = target;
+ conn->dest_dev = target;
return 0;
} while (0);

@@ -198,9 +198,9 @@ void coresight_remove_links(struct coresight_device *orig,

coresight_remove_sysfs_link(conn->link);

- devm_kfree(&conn->child_dev->dev, conn->link->target_name);
+ devm_kfree(&conn->dest_dev->dev, conn->link->target_name);
devm_kfree(&orig->dev, conn->link->orig_name);
devm_kfree(&orig->dev, conn->link);
conn->link = NULL;
- conn->child_dev = NULL;
+ conn->dest_dev = NULL;
}
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 4711dfa7418c..61234cb8052a 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -782,7 +782,7 @@ tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
return NULL;

for (i = 0; i < etr->pdata->nr_outconns; i++) {
- tmp = etr->pdata->out_conns[i].child_dev;
+ tmp = etr->pdata->out_conns[i].dest_dev;
if (tmp && coresight_is_catu_device(tmp))
return tmp;
}
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index daf392fcb67a..b6f444804bf3 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -164,18 +164,18 @@ struct coresight_desc {

/**
* struct coresight_connection - representation of a single connection
- * @outport: a connection's output port number.
- * @child_port: remote component's port number @output is connected to.
- * @chid_fwnode: remote component's fwnode handle.
- * @child_dev: a @coresight_device representation of the component
- connected to @outport.
+ * @src_port: a connection's output port number.
+ * @dest_port: destination's input port number @src_port is connected to.
+ * @dest_fwnode: destination component's fwnode handle.
+ * @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.
*/
struct coresight_connection {
- int outport;
- int child_port;
- struct fwnode_handle *child_fwnode;
- struct coresight_device *child_dev;
+ int src_port;
+ int dest_port;
+ struct fwnode_handle *dest_fwnode;
+ struct coresight_device *dest_dev;
struct coresight_sysfs_link *link;
};

--
2.34.1

2023-04-04 16:04:09

by James Clark

[permalink] [raw]
Subject: [PATCH v5 06/13] coresight: Dynamically add connections

Add a function for adding connections dynamically. This also removes
the 1:1 mapping between port number and the index into the connections
array. The only place this mapping was used was in the warning for
duplicate output ports, which has been replaced by a search. Other
uses of the port number already use the port member variable.

Being able to dynamically add connections will allow other devices like
CTI to re-use the connection mechanism despite not having explicit
connections described in the DT.

The connections array is now no longer sparse, so child_fwnode doesn't
need to be checked as all connections have a target node. Because the
array is no longer sparse, the high in and out port numbers are required
for the refcount arrays. But these will also be removed in a later
commit when the refcount is made a property of the connection.

Signed-off-by: James Clark <[email protected]>
---
drivers/hwtracing/coresight/coresight-core.c | 23 ++--
.../hwtracing/coresight/coresight-platform.c | 124 +++++++++---------
include/linux/coresight.h | 8 +-
3 files changed, 77 insertions(+), 78 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index f3dc320b374c..91274e7e6944 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -397,9 +397,9 @@ static void coresight_disable_link(struct coresight_device *csdev,
link_subtype = csdev->subtype.link_subtype;

if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
- nr_conns = csdev->pdata->nr_inconns;
+ nr_conns = csdev->pdata->high_inport;
} else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
- nr_conns = csdev->pdata->nr_outconns;
+ nr_conns = csdev->pdata->high_outport;
} else {
nr_conns = 1;
}
@@ -1336,9 +1336,6 @@ static int coresight_orphan_match(struct device *dev, void *data)
for (i = 0; i < i_csdev->pdata->nr_outconns; i++) {
conn = &i_csdev->pdata->out_conns[i];

- /* Skip the port if FW doesn't describe it */
- if (!conn->dest_fwnode)
- continue;
/* We have found at least one orphan connection */
if (conn->dest_dev == NULL) {
/* Does it match this newly added device? */
@@ -1377,8 +1374,6 @@ static int coresight_fixup_device_conns(struct coresight_device *csdev)
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
struct coresight_connection *conn = &csdev->pdata->out_conns[i];

- if (!conn->dest_fwnode)
- continue;
conn->dest_dev =
coresight_find_csdev_by_fwnode(conn->dest_fwnode);
if (conn->dest_dev && conn->dest_dev->has_conns_grp) {
@@ -1413,7 +1408,7 @@ static int coresight_remove_match(struct device *dev, void *data)
for (i = 0; i < iterator->pdata->nr_outconns; i++) {
conn = &iterator->pdata->out_conns[i];

- if (conn->dest_dev == NULL || conn->dest_fwnode == NULL)
+ if (conn->dest_dev == NULL)
continue;

if (csdev->dev.fwnode == conn->dest_fwnode) {
@@ -1445,7 +1440,7 @@ static void coresight_remove_conns(struct coresight_device *csdev)
* doesn't have at least one input port, there is no point
* in searching all the devices.
*/
- if (csdev->pdata->nr_inconns)
+ if (csdev->pdata->high_inport)
bus_for_each_dev(&coresight_bustype, NULL,
csdev, coresight_remove_match);
}
@@ -1552,10 +1547,8 @@ void coresight_release_platform_data(struct coresight_device *csdev,
* Drop the refcount and clear the handle as this device
* is going away
*/
- if (conns[i].dest_fwnode) {
- fwnode_handle_put(conns[i].dest_fwnode);
- conns[i].dest_fwnode = NULL;
- }
+ fwnode_handle_put(conns[i].dest_fwnode);
+ conns[i].dest_fwnode = NULL;
}
if (csdev)
coresight_remove_conns_sysfs_group(csdev);
@@ -1581,9 +1574,9 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
link_subtype = desc->subtype.link_subtype;

if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
- nr_refcnts = desc->pdata->nr_inconns;
+ nr_refcnts = desc->pdata->high_inport;
else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
- nr_refcnts = desc->pdata->nr_outconns;
+ nr_refcnts = desc->pdata->high_outport;
}

refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
index 566cc99a2c34..8c2029336161 100644
--- a/drivers/hwtracing/coresight/coresight-platform.c
+++ b/drivers/hwtracing/coresight/coresight-platform.c
@@ -19,22 +19,45 @@
#include <asm/smp_plat.h>

#include "coresight-priv.h"
+
/*
- * coresight_alloc_conns: Allocate connections record for each output
- * port from the device.
+ * Add an entry to the connection list and assign @conn's contents to it.
+ *
+ * If the output port is already assigned on this device, return -EINVAL
*/
-static int coresight_alloc_conns(struct device *dev,
- struct coresight_platform_data *pdata)
+struct coresight_connection *
+coresight_add_out_conn(struct device *dev,
+ struct coresight_platform_data *pdata,
+ const struct coresight_connection *new_conn)
{
- if (pdata->nr_outconns) {
- pdata->out_conns = devm_kcalloc(dev, pdata->nr_outconns,
- sizeof(*pdata->out_conns), GFP_KERNEL);
- if (!pdata->out_conns)
- return -ENOMEM;
+ int i;
+ struct coresight_connection *conn;
+
+ /*
+ * Warn on any existing duplicate output port.
+ */
+ for (i = 0; i < pdata->nr_outconns; ++i) {
+ conn = &pdata->out_conns[i];
+ /* Output == -1 means ignore the port for example for helpers */
+ if (conn->src_port != -1 &&
+ conn->src_port == new_conn->src_port) {
+ dev_warn(dev, "Duplicate output port %d\n",
+ conn->src_port);
+ return ERR_PTR(-EINVAL);
+ }
}

- return 0;
+ pdata->nr_outconns++;
+ pdata->out_conns =
+ devm_krealloc_array(dev, pdata->out_conns, pdata->nr_outconns,
+ sizeof(*pdata->out_conns), GFP_KERNEL);
+ if (!pdata->out_conns)
+ return ERR_PTR(-ENOMEM);
+
+ pdata->out_conns[pdata->nr_outconns - 1] = *new_conn;
+ return &pdata->out_conns[pdata->nr_outconns - 1];
}
+EXPORT_SYMBOL_GPL(coresight_add_out_conn);

static struct device *
coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
@@ -224,7 +247,8 @@ static int of_coresight_parse_endpoint(struct device *dev,
struct device_node *rep = NULL;
struct device *rdev = NULL;
struct fwnode_handle *rdev_fwnode;
- struct coresight_connection *conn;
+ struct coresight_connection conn = {};
+ struct coresight_connection *new_conn;

do {
/* Parse the local port details */
@@ -251,14 +275,7 @@ static int of_coresight_parse_endpoint(struct device *dev,
break;
}

- conn = &pdata->out_conns[endpoint.port];
- if (conn->dest_fwnode) {
- dev_warn(dev, "Duplicate output port %d\n",
- endpoint.port);
- ret = -EINVAL;
- break;
- }
- conn->src_port = endpoint.port;
+ conn.src_port = endpoint.port;
/*
* Hold the refcount to the target device. This could be
* released via:
@@ -267,8 +284,14 @@ static int of_coresight_parse_endpoint(struct device *dev,
* 2) While removing the target device via
* coresight_remove_match()
*/
- conn->dest_fwnode = fwnode_handle_get(rdev_fwnode);
- conn->dest_port = rendpoint.port;
+ conn.dest_fwnode = fwnode_handle_get(rdev_fwnode);
+ conn.dest_port = rendpoint.port;
+
+ new_conn = coresight_add_out_conn(dev, pdata, &conn);
+ if (IS_ERR_VALUE(new_conn)) {
+ fwnode_handle_put(conn.dest_fwnode);
+ return PTR_ERR(new_conn);
+ }
/* Connection record updated */
} while (0);

@@ -289,16 +312,12 @@ static int of_get_coresight_platform_data(struct device *dev,
struct device_node *node = dev->of_node;

/* Get the number of input and output port for this component */
- of_coresight_get_ports(node, &pdata->nr_inconns, &pdata->nr_outconns);
+ of_coresight_get_ports(node, &pdata->high_inport, &pdata->high_outport);

/* If there are no output connections, we are done */
- if (!pdata->nr_outconns)
+ if (!pdata->high_outport)
return 0;

- ret = coresight_alloc_conns(dev, pdata);
- if (ret)
- return ret;
-
parent = of_coresight_get_output_ports_node(node);
/*
* If the DT uses obsoleted bindings, the ports are listed
@@ -683,12 +702,14 @@ static int acpi_coresight_parse_link(struct acpi_device *adev,
* connection information and populate the supplied coresight_platform_data
* instance.
*/
-static int acpi_coresight_parse_graph(struct acpi_device *adev,
+static int acpi_coresight_parse_graph(struct device *dev,
+ struct acpi_device *adev,
struct coresight_platform_data *pdata)
{
- int rc, i, nlinks;
+ int i, nlinks;
const union acpi_object *graph;
- struct coresight_connection *conns, *ptr;
+ struct coresight_connection conn, zero_conn = {};
+ struct coresight_connection *new_conn;

pdata->nr_inconns = pdata->nr_outconns = 0;
graph = acpi_get_coresight_graph(adev);
@@ -699,30 +720,23 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
if (!nlinks)
return 0;

- /*
- * To avoid scanning the table twice (once for finding the number of
- * output links and then later for parsing the output links),
- * cache the links information in one go and then later copy
- * it to the pdata.
- */
- conns = devm_kcalloc(&adev->dev, nlinks, sizeof(*conns), GFP_KERNEL);
- if (!conns)
- return -ENOMEM;
- ptr = conns;
for (i = 0; i < nlinks; i++) {
const union acpi_object *link = &graph->package.elements[3 + i];
int dir;

- dir = acpi_coresight_parse_link(adev, link, ptr);
+ conn = zero_conn;
+ dir = acpi_coresight_parse_link(adev, link, &conn);
if (dir < 0)
return dir;

if (dir == ACPI_CORESIGHT_LINK_MASTER) {
- if (ptr->src_port >= pdata->nr_outconns)
- pdata->nr_outconns = ptr->src_port + 1;
- ptr++;
+ if (conn.src_port >= pdata->high_outport)
+ pdata->high_outport = conn.src_port + 1;
+ new_conn = coresight_add_out_conn(dev, pdata, &conn);
+ if (IS_ERR(new_conn))
+ return PTR_ERR(new_conn);
} else {
- WARN_ON(pdata->nr_inconns == ptr->dest_port + 1);
+ WARN_ON(pdata->high_inport == conn.dest_port + 1);
/*
* We do not track input port connections for a device.
* However we need the highest port number described,
@@ -730,25 +744,11 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
* record for an output connection. Hence, do not move
* the ptr for input connections
*/
- if (ptr->dest_port >= pdata->nr_inconns)
- pdata->nr_inconns = ptr->dest_port + 1;
+ if (conn.dest_port >= pdata->high_inport)
+ pdata->high_inport = conn.dest_port + 1;
}
}

- rc = coresight_alloc_conns(&adev->dev, pdata);
- if (rc)
- return rc;
-
- /* Copy the connection information to the final location */
- for (i = 0; conns + i < ptr; i++) {
- int port = conns[i].src_port;
-
- /* Duplicate output port */
- WARN_ON(pdata->out_conns[port].dest_fwnode);
- pdata->out_conns[port] = conns[i];
- }
-
- devm_kfree(&adev->dev, conns);
return 0;
}

@@ -809,7 +809,7 @@ acpi_get_coresight_platform_data(struct device *dev,
if (!adev)
return -EINVAL;

- return acpi_coresight_parse_graph(adev, pdata);
+ return acpi_coresight_parse_graph(dev, adev, pdata);
}

#else
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index b6f444804bf3..12fdbd03e2f7 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -104,9 +104,11 @@ union coresight_dev_subtype {
*
* @nr_inconns: Number of elements for the input connections.
* @nr_outconns: Number of elements for the output connections.
- * @out_conns: Sparse array of nr_outconns connections from this component.
+ * @out_conns: Array of nr_outconns connections from this component.
*/
struct coresight_platform_data {
+ int high_inport;
+ int high_outport;
int nr_inconns;
int nr_outconns;
struct coresight_connection *out_conns;
@@ -609,5 +611,9 @@ static inline void coresight_write64(struct coresight_device *csdev, u64 val, u3
extern int coresight_get_cpu(struct device *dev);

struct coresight_platform_data *coresight_get_platform_data(struct device *dev);
+struct coresight_connection *
+coresight_add_out_conn(struct device *dev,
+ struct coresight_platform_data *pdata,
+ const struct coresight_connection *new_conn);

#endif /* _LINUX_COREISGHT_H */
--
2.34.1

2023-04-12 13:13:18

by Mike Leach

[permalink] [raw]
Subject: Re: [PATCH v5 01/13] coresight: Fix loss of connection info when a module is unloaded

On Tue, 4 Apr 2023 at 16:51, James Clark <[email protected]> wrote:
>
> child_fwnode should be a read only property based on the DT or ACPI. If
> it's cleared on the parent device when a child is unloaded, then when
> the child is loaded again the connection won't be remade.
>
> child_dev should be cleared instead which signifies that the connection
> should be remade when the child_fwnode registers a new coresight_device.
>
> Similarly the reference count shouldn't be decremented as long as the
> parent device exists. The correct place to drop the reference is in
> coresight_release_platform_data() which is already done.
>
> Reproducible on Juno with the following steps:
>
> # load all coresight modules.
> $ cd /sys/bus/coresight/devices/
> $ echo 1 > tmc_etr0/enable_sink
> $ echo 1 > etm0/enable_source
> # Works fine ^
>
> $ echo 0 > etm0/enable_source
> $ rmmod coresight-funnel
> $ modprobe coresight-funnel
> $ echo 1 > etm0/enable_source
> -bash: echo: write error: Invalid argument
>
> Fixes: 37ea1ffddffa ("coresight: Use fwnode handle instead of device names")
> Fixes: 2af89ebacf29 ("coresight: Clear the connection field properly")
> Tested-by: Suzuki K Poulose <[email protected]>
> Signed-off-by: James Clark <[email protected]>
> ---
> drivers/hwtracing/coresight/coresight-core.c | 9 ++-------
> 1 file changed, 2 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index d3bf82c0de1d..5733294ce5cd 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -1419,13 +1419,8 @@ static int coresight_remove_match(struct device *dev, void *data)
> if (csdev->dev.fwnode == conn->child_fwnode) {
> iterator->orphan = true;
> coresight_remove_links(iterator, conn);
> - /*
> - * Drop the reference to the handle for the remote
> - * device acquired in parsing the connections from
> - * platform data.
> - */
> - fwnode_handle_put(conn->child_fwnode);
> - conn->child_fwnode = NULL;
> +
> + conn->child_dev = NULL;
> /* No need to continue */
> break;
> }
> --
> 2.34.1
>

Reviewed-by: Mike Leach <[email protected]>
--
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK

2023-04-12 13:40:58

by Mike Leach

[permalink] [raw]
Subject: Re: [PATCH v5 05/13] coresight: Rename connection members to make the direction explicit

On Tue, 4 Apr 2023 at 16:52, James Clark <[email protected]> wrote:
>
> When input connections are added they will use the same connection
> object as the output so parent and child could be misinterpreted. Making
> the direction unambiguous in the names should improve readability.
>
> Signed-off-by: James Clark <[email protected]>
> ---
> drivers/hwtracing/coresight/coresight-core.c | 51 +++++++++----------
> .../hwtracing/coresight/coresight-platform.c | 30 +++++------
> drivers/hwtracing/coresight/coresight-sysfs.c | 10 ++--
> .../hwtracing/coresight/coresight-tmc-etr.c | 2 +-
> include/linux/coresight.h | 18 +++----
> 5 files changed, 55 insertions(+), 56 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index 0f6712a6fba3..f3dc320b374c 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -120,8 +120,8 @@ static int coresight_find_link_inport(struct coresight_device *csdev,
>
> for (i = 0; i < parent->pdata->nr_outconns; i++) {
> conn = &parent->pdata->out_conns[i];
> - if (conn->child_dev == csdev)
> - return conn->child_port;
> + if (conn->dest_dev == csdev)
> + return conn->dest_port;
> }
>
> dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n",
> @@ -138,8 +138,8 @@ static int coresight_find_link_outport(struct coresight_device *csdev,
>
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> conn = &csdev->pdata->out_conns[i];
> - if (conn->child_dev == child)
> - return conn->outport;
> + if (conn->dest_dev == child)
> + return conn->src_port;
> }
>
> dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n",
> @@ -606,7 +606,7 @@ coresight_find_enabled_sink(struct coresight_device *csdev)
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> struct coresight_device *child_dev;
>
> - child_dev = csdev->pdata->out_conns[i].child_dev;
> + child_dev = csdev->pdata->out_conns[i].dest_dev;
> if (child_dev)
> sink = coresight_find_enabled_sink(child_dev);
> if (sink)
> @@ -722,7 +722,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> struct coresight_device *child;
>
> - child = csdev->pdata->out_conns[i].child_dev;
> + child = csdev->pdata->out_conns[i].dest_dev;
> if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
> if (!coresight_get_ref(child))
> goto err;
> @@ -733,7 +733,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
> for (i--; i >= 0; i--) {
> struct coresight_device *child;
>
> - child = csdev->pdata->out_conns[i].child_dev;
> + child = csdev->pdata->out_conns[i].dest_dev;
> if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
> coresight_put_ref(child);
> }
> @@ -752,7 +752,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> struct coresight_device *child;
>
> - child = csdev->pdata->out_conns[i].child_dev;
> + child = csdev->pdata->out_conns[i].dest_dev;
> if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
> coresight_put_ref(child);
> }
> @@ -794,7 +794,7 @@ static int _coresight_build_path(struct coresight_device *csdev,
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> struct coresight_device *child_dev;
>
> - child_dev = csdev->pdata->out_conns[i].child_dev;
> + child_dev = csdev->pdata->out_conns[i].dest_dev;
> if (child_dev &&
> _coresight_build_path(child_dev, sink, path) == 0) {
> found = true;
> @@ -964,7 +964,7 @@ coresight_find_sink(struct coresight_device *csdev, int *depth)
> struct coresight_device *child_dev, *sink = NULL;
> int child_depth = curr_depth;
>
> - child_dev = csdev->pdata->out_conns[i].child_dev;
> + child_dev = csdev->pdata->out_conns[i].dest_dev;
> if (child_dev)
> sink = coresight_find_sink(child_dev, &child_depth);
>
> @@ -1337,12 +1337,12 @@ static int coresight_orphan_match(struct device *dev, void *data)
> conn = &i_csdev->pdata->out_conns[i];
>
> /* Skip the port if FW doesn't describe it */
> - if (!conn->child_fwnode)
> + if (!conn->dest_fwnode)
> continue;
> /* We have found at least one orphan connection */
> - if (conn->child_dev == NULL) {
> + if (conn->dest_dev == NULL) {
> /* Does it match this newly added device? */
> - if (conn->child_fwnode == csdev->dev.fwnode) {
> + if (conn->dest_fwnode == csdev->dev.fwnode) {
> ret = coresight_make_links(i_csdev,
> conn, csdev);
> if (ret)
> @@ -1377,13 +1377,12 @@ static int coresight_fixup_device_conns(struct coresight_device *csdev)
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> struct coresight_connection *conn = &csdev->pdata->out_conns[i];
>
> - if (!conn->child_fwnode)
> + if (!conn->dest_fwnode)
> continue;
> - conn->child_dev =
> - coresight_find_csdev_by_fwnode(conn->child_fwnode);
> - if (conn->child_dev && conn->child_dev->has_conns_grp) {
> - ret = coresight_make_links(csdev, conn,
> - conn->child_dev);
> + conn->dest_dev =
> + coresight_find_csdev_by_fwnode(conn->dest_fwnode);
> + if (conn->dest_dev && conn->dest_dev->has_conns_grp) {
> + ret = coresight_make_links(csdev, conn, conn->dest_dev);
> if (ret)
> break;
> } else {
> @@ -1414,14 +1413,14 @@ static int coresight_remove_match(struct device *dev, void *data)
> for (i = 0; i < iterator->pdata->nr_outconns; i++) {
> conn = &iterator->pdata->out_conns[i];
>
> - if (conn->child_dev == NULL || conn->child_fwnode == NULL)
> + if (conn->dest_dev == NULL || conn->dest_fwnode == NULL)
> continue;
>
> - if (csdev->dev.fwnode == conn->child_fwnode) {
> + if (csdev->dev.fwnode == conn->dest_fwnode) {
> iterator->orphan = true;
> coresight_remove_links(iterator, conn);
>
> - conn->child_dev = NULL;
> + conn->dest_dev = NULL;
> /* No need to continue */
> break;
> }
> @@ -1547,15 +1546,15 @@ void coresight_release_platform_data(struct coresight_device *csdev,
>
> for (i = 0; i < pdata->nr_outconns; i++) {
> /* If we have made the links, remove them now */
> - if (csdev && conns[i].child_dev)
> + if (csdev && conns[i].dest_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);
> - conns[i].child_fwnode = NULL;
> + if (conns[i].dest_fwnode) {
> + fwnode_handle_put(conns[i].dest_fwnode);
> + conns[i].dest_fwnode = NULL;
> }
> }
> if (csdev)
> diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
> index ed865e0621a9..566cc99a2c34 100644
> --- a/drivers/hwtracing/coresight/coresight-platform.c
> +++ b/drivers/hwtracing/coresight/coresight-platform.c
> @@ -252,13 +252,13 @@ static int of_coresight_parse_endpoint(struct device *dev,
> }
>
> conn = &pdata->out_conns[endpoint.port];
> - if (conn->child_fwnode) {
> + if (conn->dest_fwnode) {
> dev_warn(dev, "Duplicate output port %d\n",
> endpoint.port);
> ret = -EINVAL;
> break;
> }
> - conn->outport = endpoint.port;
> + conn->src_port = endpoint.port;
> /*
> * Hold the refcount to the target device. This could be
> * released via:
> @@ -267,8 +267,8 @@ static int of_coresight_parse_endpoint(struct device *dev,
> * 2) While removing the target device via
> * coresight_remove_match()
> */
> - conn->child_fwnode = fwnode_handle_get(rdev_fwnode);
> - conn->child_port = rendpoint.port;
> + conn->dest_fwnode = fwnode_handle_get(rdev_fwnode);
> + conn->dest_port = rendpoint.port;
> /* Connection record updated */
> } while (0);
>
> @@ -649,8 +649,8 @@ static int acpi_coresight_parse_link(struct acpi_device *adev,
>
> dir = fields[3].integer.value;
> if (dir == ACPI_CORESIGHT_LINK_MASTER) {
> - conn->outport = fields[0].integer.value;
> - conn->child_port = fields[1].integer.value;
> + conn->src_port = fields[0].integer.value;
> + conn->dest_port = fields[1].integer.value;
> rdev = coresight_find_device_by_fwnode(&r_adev->fwnode);
> if (!rdev)
> return -EPROBE_DEFER;
> @@ -662,14 +662,14 @@ static int acpi_coresight_parse_link(struct acpi_device *adev,
> * 2) While removing the target device via
> * coresight_remove_match().
> */
> - conn->child_fwnode = fwnode_handle_get(&r_adev->fwnode);
> + conn->dest_fwnode = fwnode_handle_get(&r_adev->fwnode);
> } else if (dir == ACPI_CORESIGHT_LINK_SLAVE) {
> /*
> * We are only interested in the port number
> * for the input ports at this component.
> * Store the port number in child_port.
> */
> - conn->child_port = fields[0].integer.value;
> + conn->dest_port = fields[0].integer.value;
> } else {
> /* Invalid direction */
> return -EINVAL;
> @@ -718,11 +718,11 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
> return dir;
>
> if (dir == ACPI_CORESIGHT_LINK_MASTER) {
> - if (ptr->outport >= pdata->nr_outconns)
> - pdata->nr_outconns = ptr->outport + 1;
> + if (ptr->src_port >= pdata->nr_outconns)
> + pdata->nr_outconns = ptr->src_port + 1;
> ptr++;
> } else {
> - WARN_ON(pdata->nr_inconns == ptr->child_port + 1);
> + WARN_ON(pdata->nr_inconns == ptr->dest_port + 1);
> /*
> * We do not track input port connections for a device.
> * However we need the highest port number described,
> @@ -730,8 +730,8 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
> * record for an output connection. Hence, do not move
> * the ptr for input connections
> */
> - if (ptr->child_port >= pdata->nr_inconns)
> - pdata->nr_inconns = ptr->child_port + 1;
> + if (ptr->dest_port >= pdata->nr_inconns)
> + pdata->nr_inconns = ptr->dest_port + 1;
> }
> }
>
> @@ -741,10 +741,10 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
>
> /* Copy the connection information to the final location */
> for (i = 0; conns + i < ptr; i++) {
> - int port = conns[i].outport;
> + int port = conns[i].src_port;
>
> /* Duplicate output port */
> - WARN_ON(pdata->out_conns[port].child_fwnode);
> + WARN_ON(pdata->out_conns[port].dest_fwnode);
> pdata->out_conns[port] = conns[i];
> }
>
> diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
> index 34d2a2d31d00..a4a8e8e642e8 100644
> --- a/drivers/hwtracing/coresight/coresight-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-sysfs.c
> @@ -150,11 +150,11 @@ int coresight_make_links(struct coresight_device *orig,
>
> do {
> outs = devm_kasprintf(&orig->dev, GFP_KERNEL,
> - "out:%d", conn->outport);
> + "out:%d", conn->src_port);
> if (!outs)
> break;
> ins = devm_kasprintf(&target->dev, GFP_KERNEL,
> - "in:%d", conn->child_port);
> + "in:%d", conn->dest_port);
> if (!ins)
> break;
> link = devm_kzalloc(&orig->dev,
> @@ -178,7 +178,7 @@ int coresight_make_links(struct coresight_device *orig,
> * Install the device connection. This also indicates that
> * the links are operational on both ends.
> */
> - conn->child_dev = target;
> + conn->dest_dev = target;
> return 0;
> } while (0);
>
> @@ -198,9 +198,9 @@ void coresight_remove_links(struct coresight_device *orig,
>
> coresight_remove_sysfs_link(conn->link);
>
> - devm_kfree(&conn->child_dev->dev, conn->link->target_name);
> + devm_kfree(&conn->dest_dev->dev, conn->link->target_name);
> devm_kfree(&orig->dev, conn->link->orig_name);
> devm_kfree(&orig->dev, conn->link);
> conn->link = NULL;
> - conn->child_dev = NULL;
> + conn->dest_dev = NULL;
> }
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 4711dfa7418c..61234cb8052a 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -782,7 +782,7 @@ tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
> return NULL;
>
> for (i = 0; i < etr->pdata->nr_outconns; i++) {
> - tmp = etr->pdata->out_conns[i].child_dev;
> + tmp = etr->pdata->out_conns[i].dest_dev;
> if (tmp && coresight_is_catu_device(tmp))
> return tmp;
> }
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index daf392fcb67a..b6f444804bf3 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -164,18 +164,18 @@ struct coresight_desc {
>
> /**
> * struct coresight_connection - representation of a single connection
> - * @outport: a connection's output port number.
> - * @child_port: remote component's port number @output is connected to.
> - * @chid_fwnode: remote component's fwnode handle.
> - * @child_dev: a @coresight_device representation of the component
> - connected to @outport.
> + * @src_port: a connection's output port number.
> + * @dest_port: destination's input port number @src_port is connected to.
> + * @dest_fwnode: destination component's fwnode handle.
> + * @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.
> */
> struct coresight_connection {
> - int outport;
> - int child_port;
> - struct fwnode_handle *child_fwnode;
> - struct coresight_device *child_dev;
> + int src_port;
> + int dest_port;
> + struct fwnode_handle *dest_fwnode;
> + struct coresight_device *dest_dev;
> struct coresight_sysfs_link *link;
> };
>
> --
> 2.34.1
>

Reviewed-by: Mike Leach <[email protected]>

--
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK

2023-04-12 14:37:13

by Mike Leach

[permalink] [raw]
Subject: Re: [PATCH v5 06/13] coresight: Dynamically add connections

On Tue, 4 Apr 2023 at 16:52, James Clark <[email protected]> wrote:
>
> Add a function for adding connections dynamically. This also removes
> the 1:1 mapping between port number and the index into the connections
> array. The only place this mapping was used was in the warning for
> duplicate output ports, which has been replaced by a search. Other
> uses of the port number already use the port member variable.
>
> Being able to dynamically add connections will allow other devices like
> CTI to re-use the connection mechanism despite not having explicit
> connections described in the DT.
>
> The connections array is now no longer sparse, so child_fwnode doesn't
> need to be checked as all connections have a target node. Because the
> array is no longer sparse, the high in and out port numbers are required
> for the refcount arrays. But these will also be removed in a later
> commit when the refcount is made a property of the connection.
>
> Signed-off-by: James Clark <[email protected]>
> ---
> drivers/hwtracing/coresight/coresight-core.c | 23 ++--
> .../hwtracing/coresight/coresight-platform.c | 124 +++++++++---------
> include/linux/coresight.h | 8 +-
> 3 files changed, 77 insertions(+), 78 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index f3dc320b374c..91274e7e6944 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -397,9 +397,9 @@ static void coresight_disable_link(struct coresight_device *csdev,
> link_subtype = csdev->subtype.link_subtype;
>
> if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
> - nr_conns = csdev->pdata->nr_inconns;
> + nr_conns = csdev->pdata->high_inport;
> } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
> - nr_conns = csdev->pdata->nr_outconns;
> + nr_conns = csdev->pdata->high_outport;
> } else {
> nr_conns = 1;
> }
> @@ -1336,9 +1336,6 @@ static int coresight_orphan_match(struct device *dev, void *data)
> for (i = 0; i < i_csdev->pdata->nr_outconns; i++) {
> conn = &i_csdev->pdata->out_conns[i];
>
> - /* Skip the port if FW doesn't describe it */
> - if (!conn->dest_fwnode)
> - continue;
> /* We have found at least one orphan connection */
> if (conn->dest_dev == NULL) {
> /* Does it match this newly added device? */
> @@ -1377,8 +1374,6 @@ static int coresight_fixup_device_conns(struct coresight_device *csdev)
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> struct coresight_connection *conn = &csdev->pdata->out_conns[i];
>
> - if (!conn->dest_fwnode)
> - continue;
> conn->dest_dev =
> coresight_find_csdev_by_fwnode(conn->dest_fwnode);
> if (conn->dest_dev && conn->dest_dev->has_conns_grp) {
> @@ -1413,7 +1408,7 @@ static int coresight_remove_match(struct device *dev, void *data)
> for (i = 0; i < iterator->pdata->nr_outconns; i++) {
> conn = &iterator->pdata->out_conns[i];
>
> - if (conn->dest_dev == NULL || conn->dest_fwnode == NULL)
> + if (conn->dest_dev == NULL)
> continue;
>
> if (csdev->dev.fwnode == conn->dest_fwnode) {
> @@ -1445,7 +1440,7 @@ static void coresight_remove_conns(struct coresight_device *csdev)
> * doesn't have at least one input port, there is no point
> * in searching all the devices.
> */
> - if (csdev->pdata->nr_inconns)
> + if (csdev->pdata->high_inport)
> bus_for_each_dev(&coresight_bustype, NULL,
> csdev, coresight_remove_match);
> }
> @@ -1552,10 +1547,8 @@ void coresight_release_platform_data(struct coresight_device *csdev,
> * Drop the refcount and clear the handle as this device
> * is going away
> */
> - if (conns[i].dest_fwnode) {
> - fwnode_handle_put(conns[i].dest_fwnode);
> - conns[i].dest_fwnode = NULL;
> - }
> + fwnode_handle_put(conns[i].dest_fwnode);
> + conns[i].dest_fwnode = NULL;
> }
> if (csdev)
> coresight_remove_conns_sysfs_group(csdev);
> @@ -1581,9 +1574,9 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
> link_subtype = desc->subtype.link_subtype;
>
> if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
> - nr_refcnts = desc->pdata->nr_inconns;
> + nr_refcnts = desc->pdata->high_inport;
> else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
> - nr_refcnts = desc->pdata->nr_outconns;
> + nr_refcnts = desc->pdata->high_outport;
> }
>
> refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
> diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
> index 566cc99a2c34..8c2029336161 100644
> --- a/drivers/hwtracing/coresight/coresight-platform.c
> +++ b/drivers/hwtracing/coresight/coresight-platform.c
> @@ -19,22 +19,45 @@
> #include <asm/smp_plat.h>
>
> #include "coresight-priv.h"
> +
> /*
> - * coresight_alloc_conns: Allocate connections record for each output
> - * port from the device.
> + * Add an entry to the connection list and assign @conn's contents to it.
> + *
> + * If the output port is already assigned on this device, return -EINVAL
> */
> -static int coresight_alloc_conns(struct device *dev,
> - struct coresight_platform_data *pdata)
> +struct coresight_connection *
> +coresight_add_out_conn(struct device *dev,
> + struct coresight_platform_data *pdata,
> + const struct coresight_connection *new_conn)
> {
> - if (pdata->nr_outconns) {
> - pdata->out_conns = devm_kcalloc(dev, pdata->nr_outconns,
> - sizeof(*pdata->out_conns), GFP_KERNEL);
> - if (!pdata->out_conns)
> - return -ENOMEM;
> + int i;
> + struct coresight_connection *conn;
> +
> + /*
> + * Warn on any existing duplicate output port.
> + */
> + for (i = 0; i < pdata->nr_outconns; ++i) {
> + conn = &pdata->out_conns[i];
> + /* Output == -1 means ignore the port for example for helpers */
> + if (conn->src_port != -1 &&
> + conn->src_port == new_conn->src_port) {
> + dev_warn(dev, "Duplicate output port %d\n",
> + conn->src_port);
> + return ERR_PTR(-EINVAL);
> + }
> }
>
> - return 0;
> + pdata->nr_outconns++;
> + pdata->out_conns =
> + devm_krealloc_array(dev, pdata->out_conns, pdata->nr_outconns,
> + sizeof(*pdata->out_conns), GFP_KERNEL);
> + if (!pdata->out_conns)
> + return ERR_PTR(-ENOMEM);
> +
> + pdata->out_conns[pdata->nr_outconns - 1] = *new_conn;
> + return &pdata->out_conns[pdata->nr_outconns - 1];
> }
> +EXPORT_SYMBOL_GPL(coresight_add_out_conn);
>
> static struct device *
> coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
> @@ -224,7 +247,8 @@ static int of_coresight_parse_endpoint(struct device *dev,
> struct device_node *rep = NULL;
> struct device *rdev = NULL;
> struct fwnode_handle *rdev_fwnode;
> - struct coresight_connection *conn;
> + struct coresight_connection conn = {};
> + struct coresight_connection *new_conn;
>
> do {
> /* Parse the local port details */
> @@ -251,14 +275,7 @@ static int of_coresight_parse_endpoint(struct device *dev,
> break;
> }
>
> - conn = &pdata->out_conns[endpoint.port];
> - if (conn->dest_fwnode) {
> - dev_warn(dev, "Duplicate output port %d\n",
> - endpoint.port);
> - ret = -EINVAL;
> - break;
> - }
> - conn->src_port = endpoint.port;
> + conn.src_port = endpoint.port;
> /*
> * Hold the refcount to the target device. This could be
> * released via:
> @@ -267,8 +284,14 @@ static int of_coresight_parse_endpoint(struct device *dev,
> * 2) While removing the target device via
> * coresight_remove_match()
> */
> - conn->dest_fwnode = fwnode_handle_get(rdev_fwnode);
> - conn->dest_port = rendpoint.port;
> + conn.dest_fwnode = fwnode_handle_get(rdev_fwnode);
> + conn.dest_port = rendpoint.port;
> +
> + new_conn = coresight_add_out_conn(dev, pdata, &conn);
> + if (IS_ERR_VALUE(new_conn)) {
> + fwnode_handle_put(conn.dest_fwnode);
> + return PTR_ERR(new_conn);
> + }
> /* Connection record updated */
> } while (0);
>
> @@ -289,16 +312,12 @@ static int of_get_coresight_platform_data(struct device *dev,
> struct device_node *node = dev->of_node;
>
> /* Get the number of input and output port for this component */
> - of_coresight_get_ports(node, &pdata->nr_inconns, &pdata->nr_outconns);
> + of_coresight_get_ports(node, &pdata->high_inport, &pdata->high_outport);
>
> /* If there are no output connections, we are done */
> - if (!pdata->nr_outconns)
> + if (!pdata->high_outport)
> return 0;
>
> - ret = coresight_alloc_conns(dev, pdata);
> - if (ret)
> - return ret;
> -
> parent = of_coresight_get_output_ports_node(node);
> /*
> * If the DT uses obsoleted bindings, the ports are listed
> @@ -683,12 +702,14 @@ static int acpi_coresight_parse_link(struct acpi_device *adev,
> * connection information and populate the supplied coresight_platform_data
> * instance.
> */
> -static int acpi_coresight_parse_graph(struct acpi_device *adev,
> +static int acpi_coresight_parse_graph(struct device *dev,
> + struct acpi_device *adev,
> struct coresight_platform_data *pdata)
> {
> - int rc, i, nlinks;
> + int i, nlinks;
> const union acpi_object *graph;
> - struct coresight_connection *conns, *ptr;
> + struct coresight_connection conn, zero_conn = {};
> + struct coresight_connection *new_conn;
>
> pdata->nr_inconns = pdata->nr_outconns = 0;
> graph = acpi_get_coresight_graph(adev);
> @@ -699,30 +720,23 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
> if (!nlinks)
> return 0;
>
> - /*
> - * To avoid scanning the table twice (once for finding the number of
> - * output links and then later for parsing the output links),
> - * cache the links information in one go and then later copy
> - * it to the pdata.
> - */
> - conns = devm_kcalloc(&adev->dev, nlinks, sizeof(*conns), GFP_KERNEL);
> - if (!conns)
> - return -ENOMEM;
> - ptr = conns;
> for (i = 0; i < nlinks; i++) {
> const union acpi_object *link = &graph->package.elements[3 + i];
> int dir;
>
> - dir = acpi_coresight_parse_link(adev, link, ptr);
> + conn = zero_conn;
> + dir = acpi_coresight_parse_link(adev, link, &conn);
> if (dir < 0)
> return dir;
>
> if (dir == ACPI_CORESIGHT_LINK_MASTER) {
> - if (ptr->src_port >= pdata->nr_outconns)
> - pdata->nr_outconns = ptr->src_port + 1;
> - ptr++;
> + if (conn.src_port >= pdata->high_outport)
> + pdata->high_outport = conn.src_port + 1;
> + new_conn = coresight_add_out_conn(dev, pdata, &conn);
> + if (IS_ERR(new_conn))
> + return PTR_ERR(new_conn);
> } else {
> - WARN_ON(pdata->nr_inconns == ptr->dest_port + 1);
> + WARN_ON(pdata->high_inport == conn.dest_port + 1);
> /*
> * We do not track input port connections for a device.
> * However we need the highest port number described,
> @@ -730,25 +744,11 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
> * record for an output connection. Hence, do not move
> * the ptr for input connections
> */
> - if (ptr->dest_port >= pdata->nr_inconns)
> - pdata->nr_inconns = ptr->dest_port + 1;
> + if (conn.dest_port >= pdata->high_inport)
> + pdata->high_inport = conn.dest_port + 1;
> }
> }
>
> - rc = coresight_alloc_conns(&adev->dev, pdata);
> - if (rc)
> - return rc;
> -
> - /* Copy the connection information to the final location */
> - for (i = 0; conns + i < ptr; i++) {
> - int port = conns[i].src_port;
> -
> - /* Duplicate output port */
> - WARN_ON(pdata->out_conns[port].dest_fwnode);
> - pdata->out_conns[port] = conns[i];
> - }
> -
> - devm_kfree(&adev->dev, conns);
> return 0;
> }
>
> @@ -809,7 +809,7 @@ acpi_get_coresight_platform_data(struct device *dev,
> if (!adev)
> return -EINVAL;
>
> - return acpi_coresight_parse_graph(adev, pdata);
> + return acpi_coresight_parse_graph(dev, adev, pdata);
> }
>
> #else
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index b6f444804bf3..12fdbd03e2f7 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -104,9 +104,11 @@ union coresight_dev_subtype {
> *
> * @nr_inconns: Number of elements for the input connections.
> * @nr_outconns: Number of elements for the output connections.
> - * @out_conns: Sparse array of nr_outconns connections from this component.
> + * @out_conns: Array of nr_outconns connections from this component.
> */
> struct coresight_platform_data {
> + int high_inport;
> + int high_outport;
> int nr_inconns;
> int nr_outconns;
> struct coresight_connection *out_conns;
> @@ -609,5 +611,9 @@ static inline void coresight_write64(struct coresight_device *csdev, u64 val, u3
> extern int coresight_get_cpu(struct device *dev);
>
> struct coresight_platform_data *coresight_get_platform_data(struct device *dev);
> +struct coresight_connection *
> +coresight_add_out_conn(struct device *dev,
> + struct coresight_platform_data *pdata,
> + const struct coresight_connection *new_conn);
>
> #endif /* _LINUX_COREISGHT_H */
> --
> 2.34.1
>

Reviewed-by: Mike Leach <[email protected]>

--
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK

2023-04-12 14:57:31

by Mike Leach

[permalink] [raw]
Subject: Re: [PATCH v5 07/13] coresight: Store pointers to connections rather than an array of them

On Tue, 4 Apr 2023 at 16:52, James Clark <[email protected]> wrote:
>
> This will allow the same connection object to be referenced via the
> input connection list in a later commit rather than duplicating them.
>
> Signed-off-by: James Clark <[email protected]>
> ---
> drivers/hwtracing/coresight/coresight-core.c | 47 ++++++++++---------
> .../hwtracing/coresight/coresight-platform.c | 19 ++++++--
> drivers/hwtracing/coresight/coresight-priv.h | 1 +
> .../hwtracing/coresight/coresight-tmc-etr.c | 2 +-
> include/linux/coresight.h | 5 +-
> 5 files changed, 44 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index 91274e7e6944..0b738960973b 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -119,7 +119,7 @@ static int coresight_find_link_inport(struct coresight_device *csdev,
> struct coresight_connection *conn;
>
> for (i = 0; i < parent->pdata->nr_outconns; i++) {
> - conn = &parent->pdata->out_conns[i];
> + conn = parent->pdata->out_conns[i];
> if (conn->dest_dev == csdev)
> return conn->dest_port;
> }
> @@ -137,7 +137,7 @@ static int coresight_find_link_outport(struct coresight_device *csdev,
> struct coresight_connection *conn;
>
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> - conn = &csdev->pdata->out_conns[i];
> + conn = csdev->pdata->out_conns[i];
> if (conn->dest_dev == child)
> return conn->src_port;
> }
> @@ -606,7 +606,7 @@ coresight_find_enabled_sink(struct coresight_device *csdev)
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> struct coresight_device *child_dev;
>
> - child_dev = csdev->pdata->out_conns[i].dest_dev;
> + child_dev = csdev->pdata->out_conns[i]->dest_dev;
> if (child_dev)
> sink = coresight_find_enabled_sink(child_dev);
> if (sink)
> @@ -722,7 +722,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> struct coresight_device *child;
>
> - child = csdev->pdata->out_conns[i].dest_dev;
> + child = csdev->pdata->out_conns[i]->dest_dev;
> if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
> if (!coresight_get_ref(child))
> goto err;
> @@ -733,7 +733,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
> for (i--; i >= 0; i--) {
> struct coresight_device *child;
>
> - child = csdev->pdata->out_conns[i].dest_dev;
> + child = csdev->pdata->out_conns[i]->dest_dev;
> if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
> coresight_put_ref(child);
> }
> @@ -752,7 +752,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> struct coresight_device *child;
>
> - child = csdev->pdata->out_conns[i].dest_dev;
> + child = csdev->pdata->out_conns[i]->dest_dev;
> if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
> coresight_put_ref(child);
> }
> @@ -794,7 +794,7 @@ static int _coresight_build_path(struct coresight_device *csdev,
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> struct coresight_device *child_dev;
>
> - child_dev = csdev->pdata->out_conns[i].dest_dev;
> + child_dev = csdev->pdata->out_conns[i]->dest_dev;
> if (child_dev &&
> _coresight_build_path(child_dev, sink, path) == 0) {
> found = true;
> @@ -964,7 +964,7 @@ coresight_find_sink(struct coresight_device *csdev, int *depth)
> struct coresight_device *child_dev, *sink = NULL;
> int child_depth = curr_depth;
>
> - child_dev = csdev->pdata->out_conns[i].dest_dev;
> + child_dev = csdev->pdata->out_conns[i]->dest_dev;
> if (child_dev)
> sink = coresight_find_sink(child_dev, &child_depth);
>
> @@ -1334,7 +1334,7 @@ static int coresight_orphan_match(struct device *dev, void *data)
> * an orphan connection whose name matches @csdev, link it.
> */
> for (i = 0; i < i_csdev->pdata->nr_outconns; i++) {
> - conn = &i_csdev->pdata->out_conns[i];
> + conn = i_csdev->pdata->out_conns[i];
>
> /* We have found at least one orphan connection */
> if (conn->dest_dev == NULL) {
> @@ -1372,7 +1372,7 @@ static int coresight_fixup_device_conns(struct coresight_device *csdev)
> int i, ret = 0;
>
> for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> - struct coresight_connection *conn = &csdev->pdata->out_conns[i];
> + struct coresight_connection *conn = csdev->pdata->out_conns[i];
>
> conn->dest_dev =
> coresight_find_csdev_by_fwnode(conn->dest_fwnode);
> @@ -1406,15 +1406,12 @@ static int coresight_remove_match(struct device *dev, void *data)
> * a connection whose name matches @csdev, remove it.
> */
> for (i = 0; i < iterator->pdata->nr_outconns; i++) {
> - conn = &iterator->pdata->out_conns[i];
> + conn = iterator->pdata->out_conns[i];
>
> - if (conn->dest_dev == NULL)
> - continue;
> -
> - if (csdev->dev.fwnode == conn->dest_fwnode) {
> + /* Child_dev being set signifies that the links were made */
> + if (csdev->dev.fwnode == conn->dest_fwnode && conn->dest_dev) {
> iterator->orphan = true;
> coresight_remove_links(iterator, conn);
> -
> conn->dest_dev = NULL;
> /* No need to continue */
> break;
> @@ -1534,22 +1531,26 @@ void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset)
> * to the output port of this device.
> */
> void coresight_release_platform_data(struct coresight_device *csdev,
> + struct device *dev,
> struct coresight_platform_data *pdata)
> {
> int i;
> - struct coresight_connection *conns = pdata->out_conns;
> + struct coresight_connection **conns = pdata->out_conns;
>
> for (i = 0; i < pdata->nr_outconns; i++) {
> /* If we have made the links, remove them now */
> - if (csdev && conns[i].dest_dev)
> - coresight_remove_links(csdev, &conns[i]);
> + if (csdev && conns[i]->dest_dev)
> + coresight_remove_links(csdev, conns[i]);
> /*
> * Drop the refcount and clear the handle as this device
> * is going away
> */
> - fwnode_handle_put(conns[i].dest_fwnode);
> - conns[i].dest_fwnode = NULL;
> + fwnode_handle_put(conns[i]->dest_fwnode);
> + conns[i]->dest_fwnode = NULL;
> + devm_kfree(dev, conns[i]);
> }
> + devm_kfree(dev, pdata->out_conns);
> + devm_kfree(dev, pdata);
> if (csdev)
> coresight_remove_conns_sysfs_group(csdev);
> }
> @@ -1666,7 +1667,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
>
> err_out:
> /* Cleanup the connection information */
> - coresight_release_platform_data(NULL, desc->pdata);
> + coresight_release_platform_data(NULL, desc->dev, desc->pdata);
> return ERR_PTR(ret);
> }
> EXPORT_SYMBOL_GPL(coresight_register);
> @@ -1679,7 +1680,7 @@ void coresight_unregister(struct coresight_device *csdev)
> cti_assoc_ops->remove(csdev);
> coresight_remove_conns(csdev);
> coresight_clear_default_sink(csdev);
> - coresight_release_platform_data(csdev, csdev->pdata);
> + coresight_release_platform_data(csdev, csdev->dev.parent, csdev->pdata);
> device_unregister(&csdev->dev);
> }
> EXPORT_SYMBOL_GPL(coresight_unregister);
> diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
> index 8c2029336161..9c05f787278b 100644
> --- a/drivers/hwtracing/coresight/coresight-platform.c
> +++ b/drivers/hwtracing/coresight/coresight-platform.c
> @@ -37,7 +37,7 @@ coresight_add_out_conn(struct device *dev,
> * Warn on any existing duplicate output port.
> */
> for (i = 0; i < pdata->nr_outconns; ++i) {
> - conn = &pdata->out_conns[i];
> + conn = pdata->out_conns[i];
> /* Output == -1 means ignore the port for example for helpers */
> if (conn->src_port != -1 &&
> conn->src_port == new_conn->src_port) {
> @@ -54,8 +54,19 @@ coresight_add_out_conn(struct device *dev,
> if (!pdata->out_conns)
> return ERR_PTR(-ENOMEM);
>
> - pdata->out_conns[pdata->nr_outconns - 1] = *new_conn;
> - return &pdata->out_conns[pdata->nr_outconns - 1];
> + conn = devm_kmalloc(dev, sizeof(struct coresight_connection),
> + GFP_KERNEL);
> + if (!conn)
> + return ERR_PTR(-ENOMEM);
> +
> + /*
> + * Copy the new connection into the allocation, save the pointer to the
> + * end of the connection array and also return it in case it needs to be
> + * used right away.
> + */
> + *conn = *new_conn;
> + pdata->out_conns[pdata->nr_outconns - 1] = conn;
> + return conn;
> }
> EXPORT_SYMBOL_GPL(coresight_add_out_conn);
>
> @@ -863,7 +874,7 @@ coresight_get_platform_data(struct device *dev)
> error:
> if (!IS_ERR_OR_NULL(pdata))
> /* Cleanup the connection information */
> - coresight_release_platform_data(NULL, pdata);
> + coresight_release_platform_data(NULL, dev, pdata);
> return ERR_PTR(ret);
> }
> EXPORT_SYMBOL_GPL(coresight_get_platform_data);
> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
> index 788ff19c60f6..65ae6d161c57 100644
> --- a/drivers/hwtracing/coresight/coresight-priv.h
> +++ b/drivers/hwtracing/coresight/coresight-priv.h
> @@ -207,6 +207,7 @@ static inline void *coresight_get_uci_data(const struct amba_id *id)
> }
>
> void coresight_release_platform_data(struct coresight_device *csdev,
> + struct device *dev,
> struct coresight_platform_data *pdata);
> struct coresight_device *
> coresight_find_csdev_by_fwnode(struct fwnode_handle *r_fwnode);
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 61234cb8052a..1bbe5410a23d 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -782,7 +782,7 @@ tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
> return NULL;
>
> for (i = 0; i < etr->pdata->nr_outconns; i++) {
> - tmp = etr->pdata->out_conns[i].dest_dev;
> + tmp = etr->pdata->out_conns[i]->dest_dev;
> if (tmp && coresight_is_catu_device(tmp))
> return tmp;
> }
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index 12fdbd03e2f7..abf36a37fdb0 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -104,14 +104,15 @@ union coresight_dev_subtype {
> *
> * @nr_inconns: Number of elements for the input connections.
> * @nr_outconns: Number of elements for the output connections.
> - * @out_conns: Array of nr_outconns connections from this component.
> + * @out_conns: Array of nr_outconns pointers to connections from this
> + * component.
> */
> struct coresight_platform_data {
> int high_inport;
> int high_outport;
> int nr_inconns;
> int nr_outconns;
> - struct coresight_connection *out_conns;
> + struct coresight_connection **out_conns;
> };
>
> /**
> --
> 2.34.1
>

Reviewed-by: Mike Leach <[email protected]>

--
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK

2023-04-12 14:58:54

by Mike Leach

[permalink] [raw]
Subject: Re: [PATCH v5 08/13] coresight: Simplify connection fixup mechanism

On Tue, 4 Apr 2023 at 16:52, James Clark <[email protected]> wrote:
>
> There is some duplication between coresight_fixup_device_conns() and
> coresight_fixup_orphan_conns(). They both do the same thing except for
> the fact that coresight_fixup_orphan_conns() can't handle iterating over
> itself.
>
> By making it able to handle fixing up it's own connections the other
> function can be removed.
>
> Signed-off-by: James Clark <[email protected]>
> ---
> drivers/hwtracing/coresight/coresight-core.c | 84 ++++++++------------
> 1 file changed, 32 insertions(+), 52 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index 0b738960973b..8d377a59e0be 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -1316,42 +1316,46 @@ static int coresight_orphan_match(struct device *dev, void *data)
> {
> int i, ret = 0;
> bool still_orphan = false;
> - struct coresight_device *csdev, *i_csdev;
> + struct coresight_device *dst_csdev = data;
> + struct coresight_device *src_csdev = to_coresight_device(dev);
> struct coresight_connection *conn;
> -
> - csdev = data;
> - i_csdev = to_coresight_device(dev);
> -
> - /* No need to check oneself */
> - if (csdev == i_csdev)
> - return 0;
> + bool fixup_self = (src_csdev == dst_csdev);
>
> /* Move on to another component if no connection is orphan */
> - if (!i_csdev->orphan)
> + if (!src_csdev->orphan)
> return 0;
> /*
> - * Circle throuch all the connection of that component. If we find
> - * an orphan connection whose name matches @csdev, link it.
> + * Circle through all the connections of that component. If we find
> + * an orphan connection whose name matches @dst_csdev, link it.
> */
> - for (i = 0; i < i_csdev->pdata->nr_outconns; i++) {
> - conn = i_csdev->pdata->out_conns[i];
> -
> - /* We have found at least one orphan connection */
> - if (conn->dest_dev == NULL) {
> - /* Does it match this newly added device? */
> - if (conn->dest_fwnode == csdev->dev.fwnode) {
> - ret = coresight_make_links(i_csdev,
> - conn, csdev);
> - if (ret)
> - return ret;
> - } else {
> - /* This component still has an orphan */
> - still_orphan = true;
> - }
> + for (i = 0; i < src_csdev->pdata->nr_outconns; i++) {
> + conn = src_csdev->pdata->out_conns[i];
> +
> + /* Skip the port if it's already connected. */
> + if (conn->dest_dev)
> + continue;
> +
> + /*
> + * If we are at the "new" device, which triggered this search,
> + * we must find the remote device from the fwnode in the
> + * connection.
> + */
> + if (fixup_self)
> + dst_csdev = coresight_find_csdev_by_fwnode(
> + conn->dest_fwnode);
> +
> + /* Does it match this newly added device? */
> + if (dst_csdev && conn->dest_fwnode == dst_csdev->dev.fwnode) {
> + ret = coresight_make_links(src_csdev, conn, dst_csdev);
> + if (ret)
> + return ret;
> + } else {
> + /* This component still has an orphan */
> + still_orphan = true;
> }
> }
>
> - i_csdev->orphan = still_orphan;
> + src_csdev->orphan = still_orphan;
>
> /*
> * Returning '0' in case we didn't encounter any error,
> @@ -1366,28 +1370,6 @@ static int coresight_fixup_orphan_conns(struct coresight_device *csdev)
> csdev, coresight_orphan_match);
> }
>
> -
> -static int coresight_fixup_device_conns(struct coresight_device *csdev)
> -{
> - int i, ret = 0;
> -
> - for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> - struct coresight_connection *conn = csdev->pdata->out_conns[i];
> -
> - conn->dest_dev =
> - coresight_find_csdev_by_fwnode(conn->dest_fwnode);
> - if (conn->dest_dev && conn->dest_dev->has_conns_grp) {
> - ret = coresight_make_links(csdev, conn, conn->dest_dev);
> - if (ret)
> - break;
> - } else {
> - csdev->orphan = true;
> - }
> - }
> -
> - return ret;
> -}
> -
> static int coresight_remove_match(struct device *dev, void *data)
> {
> int i;
> @@ -1595,7 +1577,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
> csdev->subtype = desc->subtype;
> csdev->ops = desc->ops;
> csdev->access = desc->access;
> - csdev->orphan = false;
> + csdev->orphan = true;
>
> csdev->dev.type = &coresight_dev_type[desc->type];
> csdev->dev.groups = desc->groups;
> @@ -1645,8 +1627,6 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
> registered = true;
>
> ret = coresight_create_conns_sysfs_group(csdev);
> - if (!ret)
> - ret = coresight_fixup_device_conns(csdev);
> if (!ret)
> ret = coresight_fixup_orphan_conns(csdev);
>
> --
> 2.34.1
>

Reviewed-by: Mike Leach <[email protected]>

--
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK

2023-04-12 15:19:31

by Mike Leach

[permalink] [raw]
Subject: Re: [PATCH v5 09/13] coresight: Store in-connections as well as out-connections

On Tue, 4 Apr 2023 at 16:52, James Clark <[email protected]> wrote:
>
> This will allow CATU to get its associated ETR in a generic way where
> currently the enable path has some hard coded searches which avoid
> the need to store input connections.
>
> This also means that the full search for connected devices on removal
> can be replaced with a loop through only the input and output devices.
>
> Signed-off-by: James Clark <[email protected]>
> ---
> drivers/hwtracing/coresight/coresight-core.c | 81 +++++++++----------
> .../hwtracing/coresight/coresight-platform.c | 31 ++++++-
> drivers/hwtracing/coresight/coresight-sysfs.c | 7 --
> include/linux/coresight.h | 26 ++++++
> 4 files changed, 95 insertions(+), 50 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index 8d377a59e0be..a0a0ea2c626b 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -1349,6 +1349,17 @@ static int coresight_orphan_match(struct device *dev, void *data)
> ret = coresight_make_links(src_csdev, conn, dst_csdev);
> if (ret)
> return ret;
> +
> + /*
> + * Install the device connection. This also indicates that
> + * the links are operational on both ends.
> + */
> + conn->dest_dev = dst_csdev;
> + conn->src_dev = src_csdev;
> +
> + ret = coresight_add_in_conn(conn);
> + if (ret)
> + return ret;
> } else {
> /* This component still has an orphan */
> still_orphan = true;
> @@ -1370,58 +1381,43 @@ static int coresight_fixup_orphan_conns(struct coresight_device *csdev)
> csdev, coresight_orphan_match);
> }
>
> -static int coresight_remove_match(struct device *dev, void *data)
> +/* coresight_remove_conns - Remove other device's references to this device */
> +static void coresight_remove_conns(struct coresight_device *csdev)
> {
> - int i;
> - struct coresight_device *csdev, *iterator;
> + int i, j;
> 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.
> + * Remove the input connection references from the destination device
> + * for each output connection.
> */
> - for (i = 0; i < iterator->pdata->nr_outconns; i++) {
> - conn = iterator->pdata->out_conns[i];
> -
> - /* Child_dev being set signifies that the links were made */
> - if (csdev->dev.fwnode == conn->dest_fwnode && conn->dest_dev) {
> - iterator->orphan = true;
> - coresight_remove_links(iterator, conn);
> - conn->dest_dev = NULL;
> - /* No need to continue */
> - break;
> - }
> + for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> + conn = csdev->pdata->out_conns[i];
> + if (!conn->dest_dev)
> + continue;
> +
> + for (j = 0; j < conn->dest_dev->pdata->nr_inconns; ++j)
> + if (conn->dest_dev->pdata->in_conns[j] == conn) {
> + conn->dest_dev->pdata->in_conns[j] = NULL;
> + break;
> + }
> }
>
> /*
> - * Returning '0' ensures that all known component on the
> - * bus will be checked.
> + * For all input connections, remove references to this device.
> + * Connection objects are shared so modifying this device's input
> + * connections affects the other device's output connection.
> */
> - return 0;
> -}
> + for (i = 0; i < csdev->pdata->nr_inconns; ++i) {
> + conn = csdev->pdata->in_conns[i];
> + /* Input conns array is sparse */
> + if (!conn)
> + continue;
>
> -/*
> - * coresight_remove_conns - Remove references to this given devices
> - * from the connections of other devices.
> - */
> -static void coresight_remove_conns(struct coresight_device *csdev)
> -{
> - /*
> - * 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.
> - */
> - if (csdev->pdata->high_inport)
> - bus_for_each_dev(&coresight_bustype, NULL,
> - csdev, coresight_remove_match);
> + conn->src_dev->orphan = true;
> + coresight_remove_links(conn->src_dev, conn);
> + conn->dest_dev = NULL;
> + }
> }
>
> /**
> @@ -1532,6 +1528,7 @@ void coresight_release_platform_data(struct coresight_device *csdev,
> devm_kfree(dev, conns[i]);
> }
> devm_kfree(dev, pdata->out_conns);
> + devm_kfree(dev, pdata->in_conns);
> devm_kfree(dev, pdata);
> if (csdev)
> coresight_remove_conns_sysfs_group(csdev);
> diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
> index 9c05f787278b..257ad48925a1 100644
> --- a/drivers/hwtracing/coresight/coresight-platform.c
> +++ b/drivers/hwtracing/coresight/coresight-platform.c
> @@ -70,6 +70,35 @@ coresight_add_out_conn(struct device *dev,
> }
> EXPORT_SYMBOL_GPL(coresight_add_out_conn);
>
> +/*
> + * Add an input connection reference to @out_conn in the target's in_conns array
> + *
> + * @out_conn: Existing output connection to store as an input on the
> + * connection's remote device.
> + */
> +int coresight_add_in_conn(struct coresight_connection *out_conn)
> +{
> + int i;
> + struct device *dev = out_conn->dest_dev->dev.parent;
> + struct coresight_platform_data *pdata = out_conn->dest_dev->pdata;
> +
> + for (i = 0; i < pdata->nr_inconns; ++i)
> + if (!pdata->in_conns[i]) {
> + pdata->in_conns[i] = out_conn;
> + return 0;
> + }
> +
> + pdata->nr_inconns++;
> + pdata->in_conns =
> + devm_krealloc_array(dev, pdata->in_conns, pdata->nr_inconns,
> + sizeof(*pdata->in_conns), GFP_KERNEL);
> + if (!pdata->in_conns)
> + return -ENOMEM;
> + pdata->in_conns[pdata->nr_inconns - 1] = out_conn;
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(coresight_add_in_conn);
> +
> static struct device *
> coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
> {
> @@ -240,7 +269,7 @@ static int of_coresight_get_cpu(struct device *dev)
>
> /*
> * of_coresight_parse_endpoint : Parse the given output endpoint @ep
> - * and fill the connection information in @conn
> + * and fill the connection information in @pdata->out_conns
> *
> * Parses the local port, remote device name and the remote port.
> *
> diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
> index a4a8e8e642e8..464ba5e1343b 100644
> --- a/drivers/hwtracing/coresight/coresight-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-sysfs.c
> @@ -173,12 +173,6 @@ int coresight_make_links(struct coresight_device *orig,
> break;
>
> conn->link = link;
> -
> - /*
> - * Install the device connection. This also indicates that
> - * the links are operational on both ends.
> - */
> - conn->dest_dev = target;
> return 0;
> } while (0);
>
> @@ -202,5 +196,4 @@ void coresight_remove_links(struct coresight_device *orig,
> devm_kfree(&orig->dev, conn->link->orig_name);
> devm_kfree(&orig->dev, conn->link);
> conn->link = NULL;
> - conn->dest_dev = NULL;
> }
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index abf36a37fdb0..e9c52c5ca7f3 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -106,6 +106,9 @@ union coresight_dev_subtype {
> * @nr_outconns: Number of elements for the output connections.
> * @out_conns: Array of nr_outconns pointers to connections from this
> * component.
> + * @in_conns: Sparse array of pointers to input connections. Sparse
> + * because the source device owns the connection so when it's
> + * unloaded the connection leaves an empty slot.
> */
> struct coresight_platform_data {
> int high_inport;
> @@ -113,6 +116,7 @@ struct coresight_platform_data {
> int nr_inconns;
> int nr_outconns;
> struct coresight_connection **out_conns;
> + struct coresight_connection **in_conns;
> };
>
> /**
> @@ -173,6 +177,26 @@ 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.
> + *
> + * The full connection structure looks like this, where in_conns store
> + * references to same connection as the source device's out_conns.
> + *
> + * +-----------------------------+ +-----------------------------+
> + * |coresight_device | |coresight_connection |
> + * |-----------------------------| |-----------------------------|
> + * | | | |
> + * | | | dest_dev*|<--
> + * |pdata->out_conns[nr_outconns]|<->|src_dev* | |
> + * | | | | |
> + * +-----------------------------+ +-----------------------------+ |
> + * |
> + * +-----------------------------+ |
> + * |coresight_device | |
> + * |------------------------------ |
> + * | | |
> + * | pdata->in_conns[nr_inconns]|<--
> + * | |
> + * +-----------------------------+
> */
> struct coresight_connection {
> int src_port;
> @@ -180,6 +204,7 @@ struct coresight_connection {
> struct fwnode_handle *dest_fwnode;
> struct coresight_device *dest_dev;
> struct coresight_sysfs_link *link;
> + struct coresight_device *src_dev;
> };
>
> /**
> @@ -616,5 +641,6 @@ struct coresight_connection *
> coresight_add_out_conn(struct device *dev,
> struct coresight_platform_data *pdata,
> const struct coresight_connection *new_conn);
> +int coresight_add_in_conn(struct coresight_connection *conn);
>
> #endif /* _LINUX_COREISGHT_H */
> --
> 2.34.1
>

Reviewed-by: Mike Leach <[email protected]>

--
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK

2023-04-12 16:00:34

by Mike Leach

[permalink] [raw]
Subject: Re: [PATCH v5 10/13] coresight: Make refcount a property of the connection

On Tue, 4 Apr 2023 at 16:52, James Clark <[email protected]> wrote:
>
> This removes the need to do an additional lookup for the total number
> of ports used and also removes the need to allocate an array of
> refcounts which is just another representation of a connection array.
>
> This was only used for link type devices, for regular devices a single
> refcount on the coresight device is used.
>
> There is a both an input and output refcount in case two link type
> devices are connected together so that they don't overwrite each other's
> counts.
>
> Signed-off-by: James Clark <[email protected]>
> ---
> drivers/hwtracing/coresight/coresight-core.c | 116 ++++++------------
> drivers/hwtracing/coresight/coresight-etb10.c | 10 +-
> .../hwtracing/coresight/coresight-funnel.c | 26 ++--
> .../hwtracing/coresight/coresight-platform.c | 109 +---------------
> .../coresight/coresight-replicator.c | 23 ++--
> .../hwtracing/coresight/coresight-tmc-etf.c | 24 ++--
> .../hwtracing/coresight/coresight-tmc-etr.c | 12 +-
> drivers/hwtracing/coresight/coresight-tpda.c | 23 ++--
> drivers/hwtracing/coresight/coresight-tpiu.c | 4 +-
> drivers/hwtracing/coresight/ultrasoc-smb.c | 8 +-
> include/linux/coresight.h | 14 ++-
> 11 files changed, 126 insertions(+), 243 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index a0a0ea2c626b..939b7fb751b5 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -112,40 +112,24 @@ struct coresight_device *coresight_get_percpu_sink(int cpu)
> }
> EXPORT_SYMBOL_GPL(coresight_get_percpu_sink);
>
> -static int coresight_find_link_inport(struct coresight_device *csdev,
> - struct coresight_device *parent)
> +static struct coresight_connection *
> +coresight_find_out_connection(struct coresight_device *src_dev,
> + struct coresight_device *dest_dev)
> {
> int i;
> struct coresight_connection *conn;
>
> - for (i = 0; i < parent->pdata->nr_outconns; i++) {
> - conn = parent->pdata->out_conns[i];
> - if (conn->dest_dev == csdev)
> - return conn->dest_port;
> + for (i = 0; i < src_dev->pdata->nr_outconns; i++) {
> + conn = src_dev->pdata->out_conns[i];
> + if (conn->dest_dev == dest_dev)
> + return conn;
> }
>
> - dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n",
> - dev_name(&parent->dev), dev_name(&csdev->dev));
> + 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));
>
> - return -ENODEV;
> -}
> -
> -static int coresight_find_link_outport(struct coresight_device *csdev,
> - struct coresight_device *child)
> -{
> - int i;
> - struct coresight_connection *conn;
> -
> - for (i = 0; i < csdev->pdata->nr_outconns; i++) {
> - conn = csdev->pdata->out_conns[i];
> - if (conn->dest_dev == child)
> - return conn->src_port;
> - }
> -
> - dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n",
> - dev_name(&csdev->dev), dev_name(&child->dev));
> -
> - return -ENODEV;
> + return ERR_PTR(-ENODEV);
> }
>
> static inline u32 coresight_read_claim_tags(struct coresight_device *csdev)
> @@ -352,24 +336,24 @@ static int coresight_enable_link(struct coresight_device *csdev,
> {
> int ret = 0;
> int link_subtype;
> - int inport, outport;
> + struct coresight_connection *inconn, *outconn;
>
> if (!parent || !child)
> return -EINVAL;
>
> - inport = coresight_find_link_inport(csdev, parent);
> - outport = coresight_find_link_outport(csdev, child);
> + inconn = coresight_find_out_connection(parent, csdev);
> + outconn = coresight_find_out_connection(csdev, child);
> link_subtype = csdev->subtype.link_subtype;
>
> - if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && inport < 0)
> - return inport;
> - if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && outport < 0)
> - return outport;
> + if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && IS_ERR(inconn))
> + return PTR_ERR(inconn);
> + if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn))
> + return PTR_ERR(outconn);
>
> if (link_ops(csdev)->enable) {
> ret = coresight_control_assoc_ectdev(csdev, true);
> if (!ret) {
> - ret = link_ops(csdev)->enable(csdev, inport, outport);
> + ret = link_ops(csdev)->enable(csdev, inconn, outconn);
> if (ret)
> coresight_control_assoc_ectdev(csdev, false);
> }
> @@ -385,33 +369,36 @@ static void coresight_disable_link(struct coresight_device *csdev,
> struct coresight_device *parent,
> struct coresight_device *child)
> {
> - int i, nr_conns;
> + int i;
> int link_subtype;
> - int inport, outport;
> + struct coresight_connection *inconn, *outconn;
>
> if (!parent || !child)
> return;
>
> - inport = coresight_find_link_inport(csdev, parent);
> - outport = coresight_find_link_outport(csdev, child);
> + inconn = coresight_find_out_connection(parent, csdev);
> + outconn = coresight_find_out_connection(csdev, child);
> link_subtype = csdev->subtype.link_subtype;
>
> - if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
> - nr_conns = csdev->pdata->high_inport;
> - } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
> - nr_conns = csdev->pdata->high_outport;
> - } else {
> - nr_conns = 1;
> - }
> -
> if (link_ops(csdev)->disable) {
> - link_ops(csdev)->disable(csdev, inport, outport);
> + link_ops(csdev)->disable(csdev, inconn, outconn);
> coresight_control_assoc_ectdev(csdev, false);
> }
>
> - for (i = 0; i < nr_conns; i++)
> - if (atomic_read(&csdev->refcnt[i]) != 0)
> + if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
> + for (i = 0; i < csdev->pdata->nr_inconns; i++)
> + if (atomic_read(&csdev->pdata->in_conns[i]->dest_refcnt) !=
> + 0)
> + return;
> + } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
> + for (i = 0; i < csdev->pdata->nr_outconns; i++)
> + if (atomic_read(&csdev->pdata->out_conns[i]->src_refcnt) !=
> + 0)
> + return;
> + } else {
> + if (atomic_read(&csdev->refcnt) != 0)
> return;
> + }
>
> csdev->enable = false;
> }
> @@ -435,7 +422,7 @@ static int coresight_enable_source(struct coresight_device *csdev,
> csdev->enable = true;
> }
>
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
>
> return 0;
> }
> @@ -450,7 +437,7 @@ static int coresight_enable_source(struct coresight_device *csdev,
> */
> static bool coresight_disable_source(struct coresight_device *csdev)
> {
> - if (atomic_dec_return(csdev->refcnt) == 0) {
> + if (atomic_dec_return(&csdev->refcnt) == 0) {
> if (source_ops(csdev)->disable)
> source_ops(csdev)->disable(csdev, NULL);
> coresight_control_assoc_ectdev(csdev, false);
> @@ -1094,7 +1081,7 @@ int coresight_enable(struct coresight_device *csdev)
> * source is already enabled.
> */
> if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> goto out;
> }
>
> @@ -1308,7 +1295,6 @@ static void coresight_device_release(struct device *dev)
> struct coresight_device *csdev = to_coresight_device(dev);
>
> fwnode_handle_put(csdev->dev.fwnode);
> - kfree(csdev->refcnt);
> kfree(csdev);
> }
>
> @@ -1537,9 +1523,6 @@ void coresight_release_platform_data(struct coresight_device *csdev,
> 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;
> bool registered = false;
>
> @@ -1549,25 +1532,6 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
> goto err_out;
> }
>
> - 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->high_inport;
> - else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
> - nr_refcnts = desc->pdata->high_outport;
> - }
> -
> - refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
> - if (!refcnts) {
> - ret = -ENOMEM;
> - kfree(csdev);
> - goto err_out;
> - }
> -
> - csdev->refcnt = refcnts;
> -
> csdev->pdata = desc->pdata;
>
> csdev->type = desc->type;
> diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
> index eb99c445015a..fa80039e0821 100644
> --- a/drivers/hwtracing/coresight/coresight-etb10.c
> +++ b/drivers/hwtracing/coresight/coresight-etb10.c
> @@ -163,7 +163,7 @@ static int etb_enable_sysfs(struct coresight_device *csdev)
> drvdata->mode = CS_MODE_SYSFS;
> }
>
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> out:
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
> return ret;
> @@ -199,7 +199,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
> * use for this session.
> */
> if (drvdata->pid == pid) {
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> goto out;
> }
>
> @@ -217,7 +217,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
> /* Associate with monitored process. */
> drvdata->pid = pid;
> drvdata->mode = CS_MODE_PERF;
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> }
>
> out:
> @@ -356,7 +356,7 @@ static int etb_disable(struct coresight_device *csdev)
>
> spin_lock_irqsave(&drvdata->spinlock, flags);
>
> - if (atomic_dec_return(csdev->refcnt)) {
> + if (atomic_dec_return(&csdev->refcnt)) {
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
> return -EBUSY;
> }
> @@ -447,7 +447,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
> spin_lock_irqsave(&drvdata->spinlock, flags);
>
> /* Don't do anything if another tracer is using this sink */
> - if (atomic_read(csdev->refcnt) != 1)
> + if (atomic_read(&csdev->refcnt) != 1)
> goto out;
>
> __etb_disable_hw(drvdata);
> diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
> index b363dd6bc510..b8e150e45b27 100644
> --- a/drivers/hwtracing/coresight/coresight-funnel.c
> +++ b/drivers/hwtracing/coresight/coresight-funnel.c
> @@ -74,8 +74,9 @@ static int dynamic_funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
> return rc;
> }
>
> -static int funnel_enable(struct coresight_device *csdev, int inport,
> - int outport)
> +static int funnel_enable(struct coresight_device *csdev,
> + struct coresight_connection *in,
> + struct coresight_connection *out)
> {
> int rc = 0;
> struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> @@ -83,18 +84,19 @@ static int funnel_enable(struct coresight_device *csdev, int inport,
> bool first_enable = false;
>
> spin_lock_irqsave(&drvdata->spinlock, flags);
> - if (atomic_read(&csdev->refcnt[inport]) == 0) {
> + if (atomic_read(&in->dest_refcnt) == 0) {
> if (drvdata->base)
> - rc = dynamic_funnel_enable_hw(drvdata, inport);
> + rc = dynamic_funnel_enable_hw(drvdata, in->dest_port);
> if (!rc)
> first_enable = true;
> }
> if (!rc)
> - atomic_inc(&csdev->refcnt[inport]);
> + atomic_inc(&in->dest_refcnt);
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> if (first_enable)
> - dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", inport);
> + dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n",
> + in->dest_port);
> return rc;
> }
>
> @@ -117,23 +119,25 @@ static void dynamic_funnel_disable_hw(struct funnel_drvdata *drvdata,
> CS_LOCK(drvdata->base);
> }
>
> -static void funnel_disable(struct coresight_device *csdev, int inport,
> - int outport)
> +static void funnel_disable(struct coresight_device *csdev,
> + struct coresight_connection *in,
> + struct coresight_connection *out)
> {
> struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> unsigned long flags;
> bool last_disable = false;
>
> spin_lock_irqsave(&drvdata->spinlock, flags);
> - if (atomic_dec_return(&csdev->refcnt[inport]) == 0) {
> + if (atomic_dec_return(&in->dest_refcnt) == 0) {
> if (drvdata->base)
> - dynamic_funnel_disable_hw(drvdata, inport);
> + dynamic_funnel_disable_hw(drvdata, in->dest_port);
> last_disable = true;
> }
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> if (last_disable)
> - dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", inport);
> + dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n",
> + in->dest_port);
> }
>
> static const struct coresight_ops_link funnel_link_ops = {
> diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
> index 257ad48925a1..3e2e135cb8f6 100644
> --- a/drivers/hwtracing/coresight/coresight-platform.c
> +++ b/drivers/hwtracing/coresight/coresight-platform.c
> @@ -146,41 +146,6 @@ static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
> return of_property_read_bool(ep, "slave-mode");
> }
>
> -static void of_coresight_get_ports_legacy(const struct device_node *node,
> - int *nr_inconns, int *nr_outconns)
> -{
> - struct device_node *ep = NULL;
> - struct of_endpoint endpoint;
> - int in = 0, out = 0;
> -
> - /*
> - * Avoid warnings in of_graph_get_next_endpoint()
> - * if the device doesn't have any graph connections
> - */
> - if (!of_graph_is_present(node))
> - return;
> - do {
> - ep = of_graph_get_next_endpoint(node, ep);
> - if (!ep)
> - break;
> -
> - if (of_graph_parse_endpoint(ep, &endpoint))
> - continue;
> -
> - if (of_coresight_legacy_ep_is_input(ep)) {
> - in = (endpoint.port + 1 > in) ?
> - endpoint.port + 1 : in;
> - } else {
> - out = (endpoint.port + 1) > out ?
> - endpoint.port + 1 : out;
> - }
> -
> - } while (ep);
> -
> - *nr_inconns = in;
> - *nr_outconns = out;
> -}
> -
> static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
> {
> struct device_node *parent = of_graph_get_port_parent(ep);
> @@ -196,59 +161,12 @@ static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
> return parent;
> }
>
> -static inline struct device_node *
> -of_coresight_get_input_ports_node(const struct device_node *node)
> -{
> - return of_get_child_by_name(node, "in-ports");
> -}
> -
> static inline struct device_node *
> of_coresight_get_output_ports_node(const struct device_node *node)
> {
> return of_get_child_by_name(node, "out-ports");
> }
>
> -static inline int
> -of_coresight_count_ports(struct device_node *port_parent)
> -{
> - int i = 0;
> - struct device_node *ep = NULL;
> - struct of_endpoint endpoint;
> -
> - while ((ep = of_graph_get_next_endpoint(port_parent, ep))) {
> - /* Defer error handling to parsing */
> - if (of_graph_parse_endpoint(ep, &endpoint))
> - continue;
> - if (endpoint.port + 1 > i)
> - i = endpoint.port + 1;
> - }
> -
> - return i;
> -}
> -
> -static void of_coresight_get_ports(const struct device_node *node,
> - int *nr_inconns, int *nr_outconns)
> -{
> - struct device_node *input_ports = NULL, *output_ports = NULL;
> -
> - input_ports = of_coresight_get_input_ports_node(node);
> - output_ports = of_coresight_get_output_ports_node(node);
> -
> - if (input_ports || output_ports) {
> - if (input_ports) {
> - *nr_inconns = of_coresight_count_ports(input_ports);
> - of_node_put(input_ports);
> - }
> - if (output_ports) {
> - *nr_outconns = of_coresight_count_ports(output_ports);
> - of_node_put(output_ports);
> - }
> - } else {
> - /* Fall back to legacy DT bindings parsing */
> - of_coresight_get_ports_legacy(node, nr_inconns, nr_outconns);
> - }
> -}
> -
> static int of_coresight_get_cpu(struct device *dev)
> {
> int cpu;
> @@ -351,13 +269,6 @@ static int of_get_coresight_platform_data(struct device *dev,
> bool legacy_binding = false;
> struct device_node *node = dev->of_node;
>
> - /* Get the number of input and output port for this component */
> - of_coresight_get_ports(node, &pdata->high_inport, &pdata->high_outport);
> -
> - /* If there are no output connections, we are done */
> - if (!pdata->high_outport)
> - return 0;
> -
> parent = of_coresight_get_output_ports_node(node);
> /*
> * If the DT uses obsoleted bindings, the ports are listed
> @@ -365,6 +276,12 @@ static int of_get_coresight_platform_data(struct device *dev,
> * ports.
> */
> if (!parent) {
> + /*
> + * Avoid warnings in of_graph_get_next_endpoint()
> + * if the device doesn't have any graph connections
> + */
> + if (!of_graph_is_present(node))
> + return 0;
> legacy_binding = true;
> parent = node;
> dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n");
> @@ -751,7 +668,6 @@ static int acpi_coresight_parse_graph(struct device *dev,
> struct coresight_connection conn, zero_conn = {};
> struct coresight_connection *new_conn;
>
> - pdata->nr_inconns = pdata->nr_outconns = 0;
> graph = acpi_get_coresight_graph(adev);
> if (!graph)
> return -ENOENT;
> @@ -770,22 +686,9 @@ static int acpi_coresight_parse_graph(struct device *dev,
> return dir;
>
> if (dir == ACPI_CORESIGHT_LINK_MASTER) {
> - if (conn.src_port >= pdata->high_outport)
> - pdata->high_outport = conn.src_port + 1;
> new_conn = coresight_add_out_conn(dev, pdata, &conn);
> if (IS_ERR(new_conn))
> return PTR_ERR(new_conn);
> - } else {
> - WARN_ON(pdata->high_inport == conn.dest_port + 1);
> - /*
> - * We do not track input port connections for a device.
> - * However we need the highest port number described,
> - * which can be recorded now and reuse this connection
> - * record for an output connection. Hence, do not move
> - * the ptr for input connections
> - */
> - if (conn.dest_port >= pdata->high_inport)
> - pdata->high_inport = conn.dest_port + 1;
> }
> }
>
> diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
> index 4dd50546d7e4..b6be73034996 100644
> --- a/drivers/hwtracing/coresight/coresight-replicator.c
> +++ b/drivers/hwtracing/coresight/coresight-replicator.c
> @@ -114,8 +114,9 @@ static int dynamic_replicator_enable(struct replicator_drvdata *drvdata,
> return rc;
> }
>
> -static int replicator_enable(struct coresight_device *csdev, int inport,
> - int outport)
> +static int replicator_enable(struct coresight_device *csdev,
> + struct coresight_connection *in,
> + struct coresight_connection *out)
> {
> int rc = 0;
> struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> @@ -123,15 +124,15 @@ static int replicator_enable(struct coresight_device *csdev, int inport,
> bool first_enable = false;
>
> spin_lock_irqsave(&drvdata->spinlock, flags);
> - if (atomic_read(&csdev->refcnt[outport]) == 0) {
> + if (atomic_read(&out->src_refcnt) == 0) {
> if (drvdata->base)
> - rc = dynamic_replicator_enable(drvdata, inport,
> - outport);
> + rc = dynamic_replicator_enable(drvdata, in->dest_port,
> + out->src_port);
> if (!rc)
> first_enable = true;
> }
> if (!rc)
> - atomic_inc(&csdev->refcnt[outport]);
> + atomic_inc(&out->src_refcnt);
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> if (first_enable)
> @@ -168,17 +169,19 @@ static void dynamic_replicator_disable(struct replicator_drvdata *drvdata,
> CS_LOCK(drvdata->base);
> }
>
> -static void replicator_disable(struct coresight_device *csdev, int inport,
> - int outport)
> +static void replicator_disable(struct coresight_device *csdev,
> + struct coresight_connection *in,
> + struct coresight_connection *out)
> {
> struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> unsigned long flags;
> bool last_disable = false;
>
> spin_lock_irqsave(&drvdata->spinlock, flags);
> - if (atomic_dec_return(&csdev->refcnt[outport]) == 0) {
> + if (atomic_dec_return(&out->src_refcnt) == 0) {
> if (drvdata->base)
> - dynamic_replicator_disable(drvdata, inport, outport);
> + dynamic_replicator_disable(drvdata, in->dest_port,
> + out->src_port);
> last_disable = true;
> }
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index 14d3c1472455..79d8c64eac49 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -206,7 +206,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
> * touched.
> */
> if (drvdata->mode == CS_MODE_SYSFS) {
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> goto out;
> }
>
> @@ -229,7 +229,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
> ret = tmc_etb_enable_hw(drvdata);
> if (!ret) {
> drvdata->mode = CS_MODE_SYSFS;
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> } else {
> /* Free up the buffer if we failed to enable */
> used = false;
> @@ -284,7 +284,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
> * use for this session.
> */
> if (drvdata->pid == pid) {
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> break;
> }
>
> @@ -293,7 +293,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
> /* Associate with monitored process. */
> drvdata->pid = pid;
> drvdata->mode = CS_MODE_PERF;
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> }
> } while (0);
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
> @@ -338,7 +338,7 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
> return -EBUSY;
> }
>
> - if (atomic_dec_return(csdev->refcnt)) {
> + if (atomic_dec_return(&csdev->refcnt)) {
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
> return -EBUSY;
> }
> @@ -357,7 +357,8 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
> }
>
> static int tmc_enable_etf_link(struct coresight_device *csdev,
> - int inport, int outport)
> + struct coresight_connection *in,
> + struct coresight_connection *out)
> {
> int ret = 0;
> unsigned long flags;
> @@ -370,7 +371,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
> return -EBUSY;
> }
>
> - if (atomic_read(&csdev->refcnt[0]) == 0) {
> + if (atomic_read(&csdev->refcnt) == 0) {
> ret = tmc_etf_enable_hw(drvdata);
> if (!ret) {
> drvdata->mode = CS_MODE_SYSFS;
> @@ -378,7 +379,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
> }
> }
> if (!ret)
> - atomic_inc(&csdev->refcnt[0]);
> + atomic_inc(&csdev->refcnt);
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> if (first_enable)
> @@ -387,7 +388,8 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
> }
>
> static void tmc_disable_etf_link(struct coresight_device *csdev,
> - int inport, int outport)
> + struct coresight_connection *in,
> + struct coresight_connection *out)
> {
> unsigned long flags;
> struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> @@ -399,7 +401,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
> return;
> }
>
> - if (atomic_dec_return(&csdev->refcnt[0]) == 0) {
> + if (atomic_dec_return(&csdev->refcnt) == 0) {
> tmc_etf_disable_hw(drvdata);
> drvdata->mode = CS_MODE_DISABLED;
> last_disable = true;
> @@ -487,7 +489,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
> spin_lock_irqsave(&drvdata->spinlock, flags);
>
> /* Don't do anything if another tracer is using this sink */
> - if (atomic_read(csdev->refcnt) != 1)
> + if (atomic_read(&csdev->refcnt) != 1)
> goto out;
>
> CS_UNLOCK(drvdata->base);
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 1bbe5410a23d..689ba6abc70b 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -1209,7 +1209,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
> * touched, even if the buffer size has changed.
> */
> if (drvdata->mode == CS_MODE_SYSFS) {
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> goto out;
> }
>
> @@ -1226,7 +1226,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
> ret = tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf);
> if (!ret) {
> drvdata->mode = CS_MODE_SYSFS;
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> }
> out:
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
> @@ -1535,7 +1535,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
> spin_lock_irqsave(&drvdata->spinlock, flags);
>
> /* Don't do anything if another tracer is using this sink */
> - if (atomic_read(csdev->refcnt) != 1) {
> + if (atomic_read(&csdev->refcnt) != 1) {
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
> goto out;
> }
> @@ -1647,7 +1647,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
> * use for this session.
> */
> if (drvdata->pid == pid) {
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> goto unlock_out;
> }
>
> @@ -1657,7 +1657,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
> drvdata->pid = pid;
> drvdata->mode = CS_MODE_PERF;
> drvdata->perf_buf = etr_perf->etr_buf;
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> }
>
> unlock_out:
> @@ -1690,7 +1690,7 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
> return -EBUSY;
> }
>
> - if (atomic_dec_return(csdev->refcnt)) {
> + if (atomic_dec_return(&csdev->refcnt)) {
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
> return -EBUSY;
> }
> diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
> index f712e112ecff..8d2b9d29237d 100644
> --- a/drivers/hwtracing/coresight/coresight-tpda.c
> +++ b/drivers/hwtracing/coresight/coresight-tpda.c
> @@ -54,18 +54,20 @@ static void __tpda_enable(struct tpda_drvdata *drvdata, int port)
> CS_LOCK(drvdata->base);
> }
>
> -static int tpda_enable(struct coresight_device *csdev, int inport, int outport)
> +static int tpda_enable(struct coresight_device *csdev,
> + struct coresight_connection *in,
> + struct coresight_connection *out)
> {
> struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>
> spin_lock(&drvdata->spinlock);
> - if (atomic_read(&csdev->refcnt[inport]) == 0)
> - __tpda_enable(drvdata, inport);
> + if (atomic_read(&in->dest_refcnt) == 0)
> + __tpda_enable(drvdata, in->dest_port);
>
> - atomic_inc(&csdev->refcnt[inport]);
> + atomic_inc(&in->dest_refcnt);
> spin_unlock(&drvdata->spinlock);
>
> - dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", inport);
> + dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
> return 0;
> }
>
> @@ -82,18 +84,19 @@ static void __tpda_disable(struct tpda_drvdata *drvdata, int port)
> CS_LOCK(drvdata->base);
> }
>
> -static void tpda_disable(struct coresight_device *csdev, int inport,
> - int outport)
> +static void tpda_disable(struct coresight_device *csdev,
> + struct coresight_connection *in,
> + struct coresight_connection *out)
> {
> struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>
> spin_lock(&drvdata->spinlock);
> - if (atomic_dec_return(&csdev->refcnt[inport]) == 0)
> - __tpda_disable(drvdata, inport);
> + if (atomic_dec_return(&in->dest_refcnt) == 0)
> + __tpda_disable(drvdata, in->dest_port);
>
> spin_unlock(&drvdata->spinlock);
>
> - dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", inport);
> + dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
> }
>
> static const struct coresight_ops_link tpda_link_ops = {
> diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c
> index b0179f761c98..59eac93fd6bb 100644
> --- a/drivers/hwtracing/coresight/coresight-tpiu.c
> +++ b/drivers/hwtracing/coresight/coresight-tpiu.c
> @@ -73,7 +73,7 @@ static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode,
> void *__unused)
> {
> tpiu_enable_hw(&csdev->access);
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
> dev_dbg(&csdev->dev, "TPIU enabled\n");
> return 0;
> }
> @@ -96,7 +96,7 @@ static void tpiu_disable_hw(struct csdev_access *csa)
>
> static int tpiu_disable(struct coresight_device *csdev)
> {
> - if (atomic_dec_return(csdev->refcnt))
> + if (atomic_dec_return(&csdev->refcnt))
> return -EBUSY;
>
> tpiu_disable_hw(&csdev->access);
> diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c
> index a2ced0b3c3cd..e9a32a97fbee 100644
> --- a/drivers/hwtracing/coresight/ultrasoc-smb.c
> +++ b/drivers/hwtracing/coresight/ultrasoc-smb.c
> @@ -106,7 +106,7 @@ static int smb_open(struct inode *inode, struct file *file)
> goto out;
> }
>
> - if (atomic_read(drvdata->csdev->refcnt)) {
> + if (atomic_read(&drvdata->csdev->refcnt)) {
> ret = -EBUSY;
> goto out;
> }
> @@ -290,7 +290,7 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
> if (ret)
> goto out;
>
> - atomic_inc(csdev->refcnt);
> + atomic_inc(&csdev->refcnt);
>
> dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n");
> out:
> @@ -311,7 +311,7 @@ static int smb_disable(struct coresight_device *csdev)
> goto out;
> }
>
> - if (atomic_dec_return(csdev->refcnt)) {
> + if (atomic_dec_return(&csdev->refcnt)) {
> ret = -EBUSY;
> goto out;
> }
> @@ -411,7 +411,7 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev,
> mutex_lock(&drvdata->mutex);
>
> /* Don't do anything if another tracer is using this sink. */
> - if (atomic_read(csdev->refcnt) != 1)
> + if (atomic_read(&csdev->refcnt) != 1)
> goto out;
>
> smb_disable_hw(drvdata);
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index e9c52c5ca7f3..b97edd24f3ec 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -111,8 +111,6 @@ union coresight_dev_subtype {
> * unloaded the connection leaves an empty slot.
> */
> struct coresight_platform_data {
> - int high_inport;
> - int high_outport;
> int nr_inconns;
> int nr_outconns;
> struct coresight_connection **out_conns;
> @@ -205,6 +203,8 @@ 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;
> };
>
> /**
> @@ -256,7 +256,7 @@ struct coresight_device {
> const struct coresight_ops *ops;
> struct csdev_access access;
> struct device dev;
> - atomic_t *refcnt;
> + atomic_t refcnt;
> bool orphan;
> bool enable; /* true only if configured as part of a path */
> /* sink specific fields */
> @@ -341,8 +341,12 @@ struct coresight_ops_sink {
> * @disable: disables flow between iport and oport.
> */
> struct coresight_ops_link {
> - int (*enable)(struct coresight_device *csdev, int iport, int oport);
> - void (*disable)(struct coresight_device *csdev, int iport, int oport);
> + int (*enable)(struct coresight_device *csdev,
> + struct coresight_connection *in,
> + struct coresight_connection *out);
> + void (*disable)(struct coresight_device *csdev,
> + struct coresight_connection *in,
> + struct coresight_connection *out);
> };
>
> /**
> --
> 2.34.1
>

Reviewed-by: Mike Leach <[email protected]>

--
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK

2023-04-12 16:08:39

by Mike Leach

[permalink] [raw]
Subject: Re: [PATCH v5 11/13] coresight: Refactor out buffer allocation function for ETR

On Tue, 4 Apr 2023 at 16:52, James Clark <[email protected]> wrote:
>
> When CATU is moved to the generic enable/disable path system in the
> next commit, it will need to call into ETR and get it to pre-allocate
> its buffer so add a function for it.
>
> No functional changes
>
> Signed-off-by: James Clark <[email protected]>
> ---
> .../hwtracing/coresight/coresight-tmc-etr.c | 50 ++++++++++++++++---
> drivers/hwtracing/coresight/coresight-tmc.h | 2 +
> 2 files changed, 45 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 689ba6abc70b..00a0c2aa8481 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -1169,7 +1169,7 @@ void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
> drvdata->etr_buf = NULL;
> }
>
> -static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
> +static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
> {
> int ret = 0;
> unsigned long flags;
> @@ -1192,7 +1192,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
> /* Allocate memory with the locks released */
> free_buf = new_buf = tmc_etr_setup_sysfs_buf(drvdata);
> if (IS_ERR(new_buf))
> - return PTR_ERR(new_buf);
> + return new_buf;
>
> /* Let's try again */
> spin_lock_irqsave(&drvdata->spinlock, flags);
> @@ -1223,17 +1223,33 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
> drvdata->sysfs_buf = new_buf;
> }
>
> - ret = tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf);
> - if (!ret) {
> - drvdata->mode = CS_MODE_SYSFS;
> - atomic_inc(&csdev->refcnt);
> - }
> out:
> spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> /* Free memory outside the spinlock if need be */
> if (free_buf)
> tmc_etr_free_sysfs_buf(free_buf);
> + return ret ? ERR_PTR(ret) : drvdata->sysfs_buf;
> +}
> +
> +static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
> +{
> + int ret;
> + unsigned long flags;
> + struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> + struct etr_buf *sysfs_buf = tmc_etr_get_sysfs_buffer(csdev);
> +
> + if (IS_ERR(sysfs_buf))
> + return PTR_ERR(sysfs_buf);
> +
> + spin_lock_irqsave(&drvdata->spinlock, flags);
> + ret = tmc_etr_enable_hw(drvdata, sysfs_buf);
> + if (!ret) {
> + drvdata->mode = CS_MODE_SYSFS;
> + atomic_inc(&csdev->refcnt);
> + }
> +
> + spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> if (!ret)
> dev_dbg(&csdev->dev, "TMC-ETR enabled\n");
> @@ -1241,6 +1257,26 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
> return ret;
> }
>
> +struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
> + enum cs_mode mode, void *data)
> +{
> + struct perf_output_handle *handle = data;
> + struct etr_perf_buffer *etr_perf;
> +
> + switch (mode) {
> + case CS_MODE_SYSFS:
> + return tmc_etr_get_sysfs_buffer(csdev);
> + case CS_MODE_PERF:
> + etr_perf = etm_perf_sink_config(handle);
> + if (WARN_ON(!etr_perf || !etr_perf->etr_buf))
> + return ERR_PTR(-EINVAL);
> + return etr_perf->etr_buf;
> + default:
> + return ERR_PTR(-EINVAL);
> + }
> +}
> +EXPORT_SYMBOL_GPL(tmc_etr_get_buffer);
> +
> /*
> * alloc_etr_buf: Allocate ETR buffer for use by perf.
> * The size of the hardware buffer is dependent on the size configured
> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
> index 01c0382a29c0..b97da39652d2 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.h
> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
> @@ -332,5 +332,7 @@ struct coresight_device *tmc_etr_get_catu_device(struct tmc_drvdata *drvdata);
>
> void tmc_etr_set_catu_ops(const struct etr_buf_operations *catu);
> void tmc_etr_remove_catu_ops(void);
> +struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
> + enum cs_mode mode, void *data);
>
> #endif
> --
> 2.34.1
>

Reviewed-by: Mike Leach <[email protected]>


--
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK

2023-04-17 12:10:48

by Mike Leach

[permalink] [raw]
Subject: Re: [PATCH v5 12/13] coresight: Enable and disable helper devices adjacent to the path

Hi James

On Tue, 4 Apr 2023 at 16:52, James Clark <[email protected]> wrote:
>
> Currently CATU is the only helper device, and its enable and disable
> calls are hard coded. To allow more helper devices to be added in a
> generic way, remove these hard coded calls and just enable and disable
> all helper devices.
>
> This has to apply to helpers adjacent to the path, because they will
> never be in the path. CATU was already discovered in this way, so
> there is no change there.
>
> One change that is needed is for CATU to call back into ETR to allocate
> the buffer. Because the enable call was previously hard coded, it was
> done at a point where the buffer was already allocated, but this is no
> longer the case.
>
> Signed-off-by: James Clark <[email protected]>
> ---
> drivers/hwtracing/coresight/coresight-catu.c | 21 ++-
> drivers/hwtracing/coresight/coresight-core.c | 161 ++++++++++++++++--
> .../hwtracing/coresight/coresight-etm-perf.c | 4 +-
> drivers/hwtracing/coresight/coresight-priv.h | 3 +
> .../hwtracing/coresight/coresight-tmc-etr.c | 43 +----
> include/linux/coresight.h | 11 +-
> 6 files changed, 188 insertions(+), 55 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c
> index bc90a03f478f..3949ded0d4fa 100644
> --- a/drivers/hwtracing/coresight/coresight-catu.c
> +++ b/drivers/hwtracing/coresight/coresight-catu.c
> @@ -395,13 +395,18 @@ static inline int catu_wait_for_ready(struct catu_drvdata *drvdata)
> return coresight_timeout(csa, CATU_STATUS, CATU_STATUS_READY, 1);
> }
>
> -static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
> +static int catu_enable_hw(struct catu_drvdata *drvdata, enum cs_mode cs_mode,
> + void *data)
> {
> int rc;
> u32 control, mode;
> - struct etr_buf *etr_buf = data;
> + struct etr_buf *etr_buf = NULL;
> struct device *dev = &drvdata->csdev->dev;
> struct coresight_device *csdev = drvdata->csdev;
> + struct coresight_device *etrdev;
> + union coresight_dev_subtype etr_subtype = {
> + .sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM
> + };
>
> if (catu_wait_for_ready(drvdata))
> dev_warn(dev, "Timeout while waiting for READY\n");
> @@ -416,6 +421,13 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
> if (rc)
> return rc;
>
> + etrdev = coresight_find_input_type(
> + csdev->pdata, CORESIGHT_DEV_TYPE_SINK, etr_subtype);
> + if (etrdev) {
> + etr_buf = tmc_etr_get_buffer(etrdev, cs_mode, data);
> + if (IS_ERR(etr_buf))
> + return PTR_ERR(etr_buf);
> + }
> control |= BIT(CATU_CONTROL_ENABLE);
>
> if (etr_buf && etr_buf->mode == ETR_MODE_CATU) {
> @@ -441,13 +453,14 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
> return 0;
> }
>
> -static int catu_enable(struct coresight_device *csdev, void *data)
> +static int catu_enable(struct coresight_device *csdev, enum cs_mode mode,
> + void *data)
> {
> int rc;
> struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev);
>
> CS_UNLOCK(catu_drvdata->base);
> - rc = catu_enable_hw(catu_drvdata, data);
> + rc = catu_enable_hw(catu_drvdata, mode, data);
> CS_LOCK(catu_drvdata->base);
> return rc;
> }
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index 939b7fb751b5..16689fe4ba98 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -403,8 +403,8 @@ static void coresight_disable_link(struct coresight_device *csdev,
> csdev->enable = false;
> }
>
> -static int coresight_enable_source(struct coresight_device *csdev,
> - enum cs_mode mode)
> +int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
> + void *data)
> {
> int ret;
>
> @@ -413,7 +413,7 @@ static int coresight_enable_source(struct coresight_device *csdev,
> ret = coresight_control_assoc_ectdev(csdev, true);
> if (ret)
> return ret;
> - ret = source_ops(csdev)->enable(csdev, NULL, mode);
> + ret = source_ops(csdev)->enable(csdev, data, mode);
> if (ret) {
> coresight_control_assoc_ectdev(csdev, false);
> return ret;
> @@ -426,25 +426,75 @@ static int coresight_enable_source(struct coresight_device *csdev,
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(coresight_enable_source);
> +
> +static bool coresight_is_helper(struct coresight_device *csdev)
> +{
> + return csdev->type == CORESIGHT_DEV_TYPE_HELPER;
> +}
> +
> +static int coresight_enable_helper(struct coresight_device *csdev,
> + enum cs_mode mode, void *data)
> +{
> + int ret;
> +
> + if (!helper_ops(csdev)->enable)
> + return 0;
> + ret = helper_ops(csdev)->enable(csdev, mode, data);
> + if (ret)
> + return ret;
> +
> + csdev->enable = true;
> + return 0;
> +}
> +
> +static void coresight_disable_helper(struct coresight_device *csdev)
> +{
> + int ret;
> +
> + if (!helper_ops(csdev)->disable)
> + return;
> +
> + ret = helper_ops(csdev)->disable(csdev, NULL);
> + if (ret)
> + return;
> + csdev->enable = false;
> +}
> +
> +static void coresight_disable_helpers(struct coresight_device *csdev)
> +{
> + int i;
> + struct coresight_device *helper;
> +
> + for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
> + helper = csdev->pdata->out_conns[i]->dest_dev;
> + if (helper && coresight_is_helper(helper))
> + coresight_disable_helper(helper);
> + }
> +}
>
> /**
> * coresight_disable_source - Drop the reference count by 1 and disable
> * the device if there are no users left.
> *
> * @csdev: The coresight device to disable
> + * @data: Opaque data to pass on to the disable function of the source device.
> + * For example in perf mode this is a pointer to the struct perf_event.
> *
> * Returns true if the device has been disabled.
> */
> -static bool coresight_disable_source(struct coresight_device *csdev)
> +bool coresight_disable_source(struct coresight_device *csdev, void *data)
> {
> if (atomic_dec_return(&csdev->refcnt) == 0) {
> if (source_ops(csdev)->disable)
> - source_ops(csdev)->disable(csdev, NULL);
> + source_ops(csdev)->disable(csdev, data);
> coresight_control_assoc_ectdev(csdev, false);
> + coresight_disable_helpers(csdev);
> csdev->enable = false;
> }
> return !csdev->enable;
> }
> +EXPORT_SYMBOL_GPL(coresight_disable_source);
>
> /*
> * coresight_disable_path_from : Disable components in the given path beyond
> @@ -495,6 +545,9 @@ static void coresight_disable_path_from(struct list_head *path,
> default:
> break;
> }
> +
> + /* Disable all helpers adjacent along the path last */
> + coresight_disable_helpers(csdev);
> }
> }
>
> @@ -504,9 +557,28 @@ void coresight_disable_path(struct list_head *path)
> }
> EXPORT_SYMBOL_GPL(coresight_disable_path);
>
> -int coresight_enable_path(struct list_head *path, enum cs_mode mode, void *sink_data)
> +static int coresight_enable_helpers(struct coresight_device *csdev,
> + enum cs_mode mode, void *data)
> {
> + int i, ret = 0;
> + struct coresight_device *helper;
> +
> + for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
> + helper = csdev->pdata->out_conns[i]->dest_dev;
> + if (!helper || helper->type != CORESIGHT_DEV_TYPE_HELPER)

minor issue: Use coresight_is_helper() here too?

> + continue;
> +
> + ret = coresight_enable_helper(helper, mode, data);
> + if (ret)
> + return ret;
> + }
>
> + return 0;
> +}
> +
> +int coresight_enable_path(struct list_head *path, enum cs_mode mode,
> + void *sink_data)
> +{
> int ret = 0;
> u32 type;
> struct coresight_node *nd;
> @@ -516,6 +588,10 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode, void *sink_
> csdev = nd->csdev;
> type = csdev->type;
>
> + /* Enable all helpers adjacent to the path first */
> + ret = coresight_enable_helpers(csdev, mode, sink_data);
> + if (ret)
> + goto err;
> /*
> * ETF devices are tricky... They can be a link or a sink,
> * depending on how they are configured. If an ETF has been
> @@ -710,7 +786,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
> struct coresight_device *child;
>
> child = csdev->pdata->out_conns[i]->dest_dev;
> - if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
> + if (child && coresight_is_helper(child))
> if (!coresight_get_ref(child))
> goto err;
> }
> @@ -721,7 +797,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
> struct coresight_device *child;
>
> child = csdev->pdata->out_conns[i]->dest_dev;
> - if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
> + if (child && coresight_is_helper(child))
> coresight_put_ref(child);
> }
> return -ENODEV;
> @@ -740,7 +816,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
> struct coresight_device *child;
>
> child = csdev->pdata->out_conns[i]->dest_dev;
> - if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
> + if (child && coresight_is_helper(child))
> coresight_put_ref(child);
> }
> }
> @@ -1102,7 +1178,7 @@ int coresight_enable(struct coresight_device *csdev)
> if (ret)
> goto err_path;
>
> - ret = coresight_enable_source(csdev, CS_MODE_SYSFS);
> + ret = coresight_enable_source(csdev, CS_MODE_SYSFS, NULL);
> if (ret)
> goto err_source;
>
> @@ -1159,7 +1235,7 @@ void coresight_disable(struct coresight_device *csdev)
> if (ret)
> goto out;
>
> - if (!csdev->enable || !coresight_disable_source(csdev))
> + if (!csdev->enable || !coresight_disable_source(csdev, NULL))
> goto out;
>
> switch (csdev->subtype.source_subtype) {
> @@ -1644,6 +1720,69 @@ static inline int coresight_search_device_idx(struct coresight_dev_list *dict,
> return -ENOENT;
> }
>
> +static bool coresight_compare_type(enum coresight_dev_type type_a,
> + union coresight_dev_subtype subtype_a,
> + enum coresight_dev_type type_b,
> + union coresight_dev_subtype subtype_b)
> +{
> + if (type_a != type_b)
> + return false;
> +
> + switch (type_a) {
> + case CORESIGHT_DEV_TYPE_SINK:
> + return subtype_a.sink_subtype == subtype_b.sink_subtype;
> + case CORESIGHT_DEV_TYPE_LINK:
> + return subtype_a.link_subtype == subtype_b.link_subtype;
> + case CORESIGHT_DEV_TYPE_LINKSINK:
> + return subtype_a.link_subtype == subtype_b.link_subtype &&
> + subtype_a.sink_subtype == subtype_b.sink_subtype;
> + case CORESIGHT_DEV_TYPE_SOURCE:
> + return subtype_a.source_subtype == subtype_b.source_subtype;
> + case CORESIGHT_DEV_TYPE_HELPER:
> + return subtype_a.helper_subtype == subtype_b.helper_subtype;
> + default:
> + return false;
> + }
> +}
> +
> +struct coresight_device *
> +coresight_find_input_type(struct coresight_platform_data *pdata,
> + enum coresight_dev_type type,
> + union coresight_dev_subtype subtype)
> +{
> + int i;
> + struct coresight_connection *conn;
> +
> + for (i = 0; i < pdata->nr_inconns; ++i) {
> + conn = pdata->in_conns[i];
> + if (conn &&
> + coresight_compare_type(type, subtype, conn->src_dev->type,
> + conn->src_dev->subtype))
> + return conn->src_dev;
> + }
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(coresight_find_input_type);
> +
> +struct coresight_device *
> +coresight_find_output_type(struct coresight_platform_data *pdata,
> + enum coresight_dev_type type,
> + union coresight_dev_subtype subtype)
> +{
> + int i;
> + struct coresight_connection *conn;
> +
> + for (i = 0; i < pdata->nr_outconns; ++i) {
> + conn = pdata->out_conns[i];
> + if (conn->dest_dev &&
> + coresight_compare_type(type, subtype, conn->dest_dev->type,
> + conn->dest_dev->subtype))
> + return conn->dest_dev;
> + }
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(coresight_find_output_type);
> +
> bool coresight_loses_context_with_cpu(struct device *dev)
> {
> return fwnode_property_present(dev_fwnode(dev),
> diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
> index a48c97da8165..166adcf592cd 100644
> --- a/drivers/hwtracing/coresight/coresight-etm-perf.c
> +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
> @@ -492,7 +492,7 @@ static void etm_event_start(struct perf_event *event, int flags)
> goto fail_end_stop;
>
> /* Finally enable the tracer */
> - if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF))
> + if (coresight_enable_source(csdev, CS_MODE_PERF, event))
> goto fail_disable_path;
>
> /*
> @@ -586,7 +586,7 @@ static void etm_event_stop(struct perf_event *event, int mode)
> return;
>
> /* stop tracer */
> - source_ops(csdev)->disable(csdev, event);
> + coresight_disable_source(csdev, event);
>
> /* tell the core */
> event->hw.state = PERF_HES_STOPPED;
> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
> index 65ae6d161c57..5575014f73e0 100644
> --- a/drivers/hwtracing/coresight/coresight-priv.h
> +++ b/drivers/hwtracing/coresight/coresight-priv.h
> @@ -216,5 +216,8 @@ void coresight_set_assoc_ectdev_mutex(struct coresight_device *csdev,
>
> void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
> struct coresight_device *coresight_get_percpu_sink(int cpu);
> +int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
> + void *data);
> +bool coresight_disable_source(struct coresight_device *csdev, void *data);
>
> #endif
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 00a0c2aa8481..37afe8b52760 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -775,40 +775,19 @@ static const struct etr_buf_operations etr_sg_buf_ops = {
> struct coresight_device *
> tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
> {
> - int i;
> - struct coresight_device *tmp, *etr = drvdata->csdev;
> + struct coresight_device *etr = drvdata->csdev;
> + union coresight_dev_subtype catu_subtype = {
> + .helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CATU
> + };
>
> if (!IS_ENABLED(CONFIG_CORESIGHT_CATU))
> return NULL;
>
> - for (i = 0; i < etr->pdata->nr_outconns; i++) {
> - tmp = etr->pdata->out_conns[i]->dest_dev;
> - if (tmp && coresight_is_catu_device(tmp))
> - return tmp;
> - }
> -
> - return NULL;
> + return coresight_find_output_type(etr->pdata, CORESIGHT_DEV_TYPE_HELPER,
> + catu_subtype);
> }
> EXPORT_SYMBOL_GPL(tmc_etr_get_catu_device);
>
> -static inline int tmc_etr_enable_catu(struct tmc_drvdata *drvdata,
> - struct etr_buf *etr_buf)
> -{
> - struct coresight_device *catu = tmc_etr_get_catu_device(drvdata);
> -
> - if (catu && helper_ops(catu)->enable)
> - return helper_ops(catu)->enable(catu, etr_buf);
> - return 0;
> -}
> -
> -static inline void tmc_etr_disable_catu(struct tmc_drvdata *drvdata)
> -{
> - struct coresight_device *catu = tmc_etr_get_catu_device(drvdata);
> -
> - if (catu && helper_ops(catu)->disable)
> - helper_ops(catu)->disable(catu, drvdata->etr_buf);
> -}
> -
> static const struct etr_buf_operations *etr_buf_ops[] = {
> [ETR_MODE_FLAT] = &etr_flat_buf_ops,
> [ETR_MODE_ETR_SG] = &etr_sg_buf_ops,
> @@ -1058,13 +1037,6 @@ static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata,
> if (WARN_ON(drvdata->etr_buf))
> return -EBUSY;
>
> - /*
> - * If this ETR is connected to a CATU, enable it before we turn
> - * this on.
> - */
> - rc = tmc_etr_enable_catu(drvdata, etr_buf);
> - if (rc)
> - return rc;
> rc = coresight_claim_device(drvdata->csdev);
> if (!rc) {
> drvdata->etr_buf = etr_buf;
> @@ -1072,7 +1044,6 @@ static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata,
> if (rc) {
> drvdata->etr_buf = NULL;
> coresight_disclaim_device(drvdata->csdev);
> - tmc_etr_disable_catu(drvdata);
> }
> }
>
> @@ -1162,8 +1133,6 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
> void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
> {
> __tmc_etr_disable_hw(drvdata);
> - /* Disable CATU device if this ETR is connected to one */
> - tmc_etr_disable_catu(drvdata);
> coresight_disclaim_device(drvdata->csdev);
> /* Reset the ETR buf used by hardware */
> drvdata->etr_buf = NULL;
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index b97edd24f3ec..61dfbab5fa98 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -375,7 +375,8 @@ struct coresight_ops_source {
> * @disable : Disable the device
> */
> struct coresight_ops_helper {
> - int (*enable)(struct coresight_device *csdev, void *data);
> + int (*enable)(struct coresight_device *csdev, enum cs_mode mode,
> + void *data);
> int (*disable)(struct coresight_device *csdev, void *data);
> };
>
> @@ -646,5 +647,13 @@ coresight_add_out_conn(struct device *dev,
> struct coresight_platform_data *pdata,
> const struct coresight_connection *new_conn);
> int coresight_add_in_conn(struct coresight_connection *conn);
> +struct coresight_device *
> +coresight_find_input_type(struct coresight_platform_data *pdata,
> + enum coresight_dev_type type,
> + union coresight_dev_subtype subtype);
> +struct coresight_device *
> +coresight_find_output_type(struct coresight_platform_data *pdata,
> + enum coresight_dev_type type,
> + union coresight_dev_subtype subtype);
>
> #endif /* _LINUX_COREISGHT_H */
> --
> 2.34.1
>

Reviewed-by: Mike Leach <[email protected]>


--
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK

2023-04-17 13:38:27

by Mike Leach

[permalink] [raw]
Subject: Re: [PATCH v5 13/13] coresight: Fix CTI module refcount leak by making it a helper device

Hi James

On Tue, 4 Apr 2023 at 16:52, James Clark <[email protected]> wrote:
>
> The CTI module has some hard coded refcounting code that has a leak.
> For example running perf and then trying to unload it fails:
>
> perf record -e cs_etm// -a -- ls
> rmmod coresight_cti
>
> rmmod: ERROR: Module coresight_cti is in use
>
> The coresight core already handles references of devices in use, so by
> making CTI a normal helper device, we get working refcounting for free.
>
> Signed-off-by: James Clark <[email protected]>
> ---
> drivers/hwtracing/coresight/coresight-core.c | 104 ++++++------------
> .../hwtracing/coresight/coresight-cti-core.c | 52 +++++----
> .../hwtracing/coresight/coresight-cti-sysfs.c | 4 +-
> drivers/hwtracing/coresight/coresight-cti.h | 4 +-
> drivers/hwtracing/coresight/coresight-priv.h | 4 +-
> drivers/hwtracing/coresight/coresight-sysfs.c | 4 +
> include/linux/coresight.h | 30 +----
> 7 files changed, 75 insertions(+), 127 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index 16689fe4ba98..2af416bba983 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -236,60 +236,44 @@ void coresight_disclaim_device(struct coresight_device *csdev)
> }
> EXPORT_SYMBOL_GPL(coresight_disclaim_device);
>
> -/* enable or disable an associated CTI device of the supplied CS device */
> -static int
> -coresight_control_assoc_ectdev(struct coresight_device *csdev, bool enable)
> +/*
> + * Add a helper as an output device. This function takes the @coresight_mutex
> + * because it's assumed that it's called from the helper device, outside of the
> + * core code where the mutex would already be held. Don't add new calls to this
> + * from inside the core code, instead try to add the new helper to the DT and
> + * ACPI where it will be picked up and linked automatically.
> + */
> +void coresight_add_helper(struct coresight_device *csdev,
> + struct coresight_device *helper)
> {
> - int ect_ret = 0;
> - struct coresight_device *ect_csdev = csdev->ect_dev;
> - struct module *mod;
> + int i;
> + struct coresight_connection conn = {};
> + struct coresight_connection *new_conn;
>
> - if (!ect_csdev)
> - return 0;
> - if ((!ect_ops(ect_csdev)->enable) || (!ect_ops(ect_csdev)->disable))
> - return 0;
> + mutex_lock(&coresight_mutex);
> + conn.dest_fwnode = fwnode_handle_get(dev_fwnode(&helper->dev));
> + conn.dest_dev = helper;
> + conn.dest_port = conn.src_port = -1;
> + conn.src_dev = csdev;
>
> - mod = ect_csdev->dev.parent->driver->owner;
> - if (enable) {
> - 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;
> - } else {
> - if (csdev->ect_enabled) {
> - ect_ret = ect_ops(ect_csdev)->disable(ect_csdev);
> - put_device(ect_csdev->dev.parent);
> - module_put(mod);
> - csdev->ect_enabled = false;
> - }
> - }
> + /*
> + * Check for duplicates because this is called every time a helper
> + * device is re-loaded. Existing connections will get re-linked
> + * automatically.
> + */
> + for (i = 0; i < csdev->pdata->nr_outconns; ++i)
> + if (csdev->pdata->out_conns[i]->dest_fwnode == conn.dest_fwnode)
> + goto unlock;
>
> - /* 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;
> -}
> + new_conn =
> + coresight_add_out_conn(csdev->dev.parent, csdev->pdata, &conn);
> + if (!IS_ERR(new_conn))
> + coresight_add_in_conn(new_conn);
>
> -/*
> - * 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;
> +unlock:
> mutex_unlock(&coresight_mutex);
> }
> -EXPORT_SYMBOL_GPL(coresight_set_assoc_ectdev_mutex);
> +EXPORT_SYMBOL_GPL(coresight_add_helper);
>
> static int coresight_enable_sink(struct coresight_device *csdev,
> enum cs_mode mode, void *data)
> @@ -303,12 +287,8 @@ static int coresight_enable_sink(struct coresight_device *csdev,
> if (!sink_ops(csdev)->enable)
> return -EINVAL;
>
> - ret = coresight_control_assoc_ectdev(csdev, true);
> - if (ret)
> - return ret;
> ret = sink_ops(csdev)->enable(csdev, mode, data);
> if (ret) {
> - coresight_control_assoc_ectdev(csdev, false);
> return ret;
> }

minor nit: should drop {} here

> csdev->enable = true;
> @@ -326,7 +306,6 @@ static void coresight_disable_sink(struct coresight_device *csdev)
> ret = sink_ops(csdev)->disable(csdev);
> if (ret)
> return;
> - coresight_control_assoc_ectdev(csdev, false);
> csdev->enable = false;
> }
>
> @@ -351,17 +330,11 @@ static int coresight_enable_link(struct coresight_device *csdev,
> return PTR_ERR(outconn);
>
> if (link_ops(csdev)->enable) {
> - ret = coresight_control_assoc_ectdev(csdev, true);
> - if (!ret) {
> - ret = link_ops(csdev)->enable(csdev, inconn, outconn);
> - if (ret)
> - coresight_control_assoc_ectdev(csdev, false);
> - }
> + ret = link_ops(csdev)->enable(csdev, inconn, outconn);
> + if (!ret)
> + csdev->enable = true;
> }
>
> - if (!ret)
> - csdev->enable = true;
> -
> return ret;
> }
>
> @@ -382,7 +355,6 @@ static void coresight_disable_link(struct coresight_device *csdev,
>
> if (link_ops(csdev)->disable) {
> link_ops(csdev)->disable(csdev, inconn, outconn);
> - coresight_control_assoc_ectdev(csdev, false);
> }
>
> if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
> @@ -410,14 +382,9 @@ int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
>
> if (!csdev->enable) {
> if (source_ops(csdev)->enable) {
> - ret = coresight_control_assoc_ectdev(csdev, true);
> - if (ret)
> - return ret;
> ret = source_ops(csdev)->enable(csdev, data, mode);
> - if (ret) {
> - coresight_control_assoc_ectdev(csdev, false);
> + if (ret)
> return ret;
> - }
> }
> csdev->enable = true;
> }
> @@ -488,7 +455,6 @@ bool coresight_disable_source(struct coresight_device *csdev, void *data)
> if (atomic_dec_return(&csdev->refcnt) == 0) {
> if (source_ops(csdev)->disable)
> source_ops(csdev)->disable(csdev, data);
> - coresight_control_assoc_ectdev(csdev, false);
> coresight_disable_helpers(csdev);
> csdev->enable = false;
> }
> diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
> index 277c890a1f1f..7023ff70cc28 100644
> --- a/drivers/hwtracing/coresight/coresight-cti-core.c
> +++ b/drivers/hwtracing/coresight/coresight-cti-core.c
> @@ -555,7 +555,10 @@ static void cti_add_assoc_to_csdev(struct coresight_device *csdev)
> mutex_lock(&ect_mutex);
>
> /* exit if current is an ECT device.*/
> - if ((csdev->type == CORESIGHT_DEV_TYPE_ECT) || list_empty(&ect_net))
> + if ((csdev->type == CORESIGHT_DEV_TYPE_HELPER &&
> + csdev->subtype.helper_subtype ==
> + CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI) ||
> + list_empty(&ect_net))
> goto cti_add_done;
>
> /* if we didn't find the csdev previously we used the fwnode name */
> @@ -571,8 +574,7 @@ static void cti_add_assoc_to_csdev(struct coresight_device *csdev)
> * if we found a matching csdev then update the ECT
> * association pointer for the device with this CTI.
> */
> - coresight_set_assoc_ectdev_mutex(csdev,
> - ect_item->csdev);
> + coresight_add_helper(csdev, ect_item->csdev);
> break;
> }
> }
> @@ -582,26 +584,30 @@ static void cti_add_assoc_to_csdev(struct coresight_device *csdev)
>
> /*
> * Removing the associated devices is easier.
> - * A CTI will not have a value for csdev->ect_dev.
> */
> static void cti_remove_assoc_from_csdev(struct coresight_device *csdev)
> {
> struct cti_drvdata *ctidrv;
> struct cti_trig_con *tc;
> struct cti_device *ctidev;
> + union coresight_dev_subtype cti_subtype = {
> + .helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI
> + };
> + struct coresight_device *cti_csdev = coresight_find_output_type(
> + csdev->pdata, CORESIGHT_DEV_TYPE_HELPER, cti_subtype);
> +
> + if (!cti_csdev)
> + return;
>
> mutex_lock(&ect_mutex);
> - if (csdev->ect_dev) {
> - ctidrv = csdev_to_cti_drvdata(csdev->ect_dev);
> - ctidev = &ctidrv->ctidev;
> - list_for_each_entry(tc, &ctidev->trig_cons, node) {
> - if (tc->con_dev == csdev) {
> - cti_remove_sysfs_link(ctidrv, tc);
> - tc->con_dev = NULL;
> - break;
> - }
> + ctidrv = csdev_to_cti_drvdata(cti_csdev);
> + ctidev = &ctidrv->ctidev;
> + list_for_each_entry(tc, &ctidev->trig_cons, node) {
> + if (tc->con_dev == csdev) {
> + cti_remove_sysfs_link(ctidrv, tc);
> + tc->con_dev = NULL;
> + break;
> }
> - csdev->ect_dev = NULL;
> }
> mutex_unlock(&ect_mutex);
> }
> @@ -630,8 +636,8 @@ static void cti_update_conn_xrefs(struct cti_drvdata *drvdata)
> /* if we can set the sysfs link */
> if (cti_add_sysfs_link(drvdata, tc))
> /* set the CTI/csdev association */
> - coresight_set_assoc_ectdev_mutex(tc->con_dev,
> - drvdata->csdev);
> + coresight_add_helper(tc->con_dev,
> + drvdata->csdev);
> else
> /* otherwise remove reference from CTI */
> tc->con_dev = NULL;
> @@ -646,8 +652,6 @@ static void cti_remove_conn_xrefs(struct cti_drvdata *drvdata)
>
> list_for_each_entry(tc, &ctidev->trig_cons, node) {
> if (tc->con_dev) {
> - coresight_set_assoc_ectdev_mutex(tc->con_dev,
> - NULL);
> cti_remove_sysfs_link(drvdata, tc);
> tc->con_dev = NULL;
> }
> @@ -795,27 +799,27 @@ static void cti_pm_release(struct cti_drvdata *drvdata)
> }
>
> /** cti ect operations **/
> -int cti_enable(struct coresight_device *csdev)
> +int cti_enable(struct coresight_device *csdev, enum cs_mode mode, void *data)
> {
> struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
>
> return cti_enable_hw(drvdata);
> }
>
> -int cti_disable(struct coresight_device *csdev)
> +int cti_disable(struct coresight_device *csdev, void *data)
> {
> struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
>
> return cti_disable_hw(drvdata);
> }
>
> -static const struct coresight_ops_ect cti_ops_ect = {
> +static const struct coresight_ops_helper cti_ops_ect = {
> .enable = cti_enable,
> .disable = cti_disable,
> };
>
> static const struct coresight_ops cti_ops = {
> - .ect_ops = &cti_ops_ect,
> + .helper_ops = &cti_ops_ect,
> };
>
> /*
> @@ -922,8 +926,8 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
>
> /* set up coresight component description */
> cti_desc.pdata = pdata;
> - cti_desc.type = CORESIGHT_DEV_TYPE_ECT;
> - cti_desc.subtype.ect_subtype = CORESIGHT_DEV_SUBTYPE_ECT_CTI;
> + cti_desc.type = CORESIGHT_DEV_TYPE_HELPER;
> + cti_desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI;
> cti_desc.ops = &cti_ops;
> cti_desc.groups = drvdata->ctidev.con_groups;
> cti_desc.dev = dev;
> diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> index e528cff9d4e2..d25dd2737b49 100644
> --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
> @@ -112,11 +112,11 @@ static ssize_t enable_store(struct device *dev,
> ret = pm_runtime_resume_and_get(dev->parent);
> if (ret)
> return ret;
> - ret = cti_enable(drvdata->csdev);
> + ret = cti_enable(drvdata->csdev, CS_MODE_SYSFS, NULL);
> if (ret)
> pm_runtime_put(dev->parent);
> } else {
> - ret = cti_disable(drvdata->csdev);
> + ret = cti_disable(drvdata->csdev, NULL);
> if (!ret)
> pm_runtime_put(dev->parent);
> }
> diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
> index 8b106b13a244..cb9ee616d01f 100644
> --- a/drivers/hwtracing/coresight/coresight-cti.h
> +++ b/drivers/hwtracing/coresight/coresight-cti.h
> @@ -215,8 +215,8 @@ int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
> const char *assoc_dev_name);
> struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
> int out_sigs);
> -int cti_enable(struct coresight_device *csdev);
> -int cti_disable(struct coresight_device *csdev);
> +int cti_enable(struct coresight_device *csdev, enum cs_mode mode, void *data);
> +int cti_disable(struct coresight_device *csdev, void *data);
> void cti_write_all_hw_regs(struct cti_drvdata *drvdata);
> void cti_write_intack(struct device *dev, u32 ackval);
> void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value);
> diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
> index 5575014f73e0..1801ff4e467b 100644
> --- a/drivers/hwtracing/coresight/coresight-priv.h
> +++ b/drivers/hwtracing/coresight/coresight-priv.h
> @@ -211,8 +211,8 @@ void coresight_release_platform_data(struct coresight_device *csdev,
> struct coresight_platform_data *pdata);
> struct coresight_device *
> coresight_find_csdev_by_fwnode(struct fwnode_handle *r_fwnode);
> -void coresight_set_assoc_ectdev_mutex(struct coresight_device *csdev,
> - struct coresight_device *ect_csdev);
> +void coresight_add_helper(struct coresight_device *csdev,
> + struct coresight_device *helper);
>
> void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
> struct coresight_device *coresight_get_percpu_sink(int cpu);
> diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
> index 464ba5e1343b..dd78e9fcfc4d 100644
> --- a/drivers/hwtracing/coresight/coresight-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-sysfs.c
> @@ -148,6 +148,10 @@ int coresight_make_links(struct coresight_device *orig,
> char *outs = NULL, *ins = NULL;
> struct coresight_sysfs_link *link = NULL;
>
> + /* Helper devices aren't shown in sysfs */
> + if (conn->dest_port == -1 && conn->src_port == -1)
> + return 0;
> +
> do {
> outs = devm_kasprintf(&orig->dev, GFP_KERNEL,
> "out:%d", conn->src_port);
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index 61dfbab5fa98..225a5fa71baf 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -40,8 +40,7 @@ enum coresight_dev_type {
> CORESIGHT_DEV_TYPE_LINK,
> CORESIGHT_DEV_TYPE_LINKSINK,
> CORESIGHT_DEV_TYPE_SOURCE,
> - CORESIGHT_DEV_TYPE_HELPER,
> - CORESIGHT_DEV_TYPE_ECT,
> + CORESIGHT_DEV_TYPE_HELPER
> };
>
> enum coresight_dev_subtype_sink {
> @@ -66,12 +65,7 @@ enum coresight_dev_subtype_source {
>
> enum coresight_dev_subtype_helper {
> CORESIGHT_DEV_SUBTYPE_HELPER_CATU,
> -};
> -
> -/* Embedded Cross Trigger (ECT) sub-types */
> -enum coresight_dev_subtype_ect {
> - CORESIGHT_DEV_SUBTYPE_ECT_NONE,
> - CORESIGHT_DEV_SUBTYPE_ECT_CTI,
> + CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI
> };
>
> /**
> @@ -84,8 +78,6 @@ enum coresight_dev_subtype_ect {
> * by @coresight_dev_subtype_source.
> * @helper_subtype: type of helper this component is, as defined
> * by @coresight_dev_subtype_helper.
> - * @ect_subtype: type of cross trigger this component is, as
> - * defined by @coresight_dev_subtype_ect
> */
> union coresight_dev_subtype {
> /* We have some devices which acts as LINK and SINK */
> @@ -95,7 +87,6 @@ union coresight_dev_subtype {
> };
> enum coresight_dev_subtype_source source_subtype;
> enum coresight_dev_subtype_helper helper_subtype;
> - enum coresight_dev_subtype_ect ect_subtype;
> };
>
> /**
> @@ -239,8 +230,6 @@ struct coresight_sysfs_link {
> * from source to that sink.
> * @ea: Device attribute for sink representation under PMU directory.
> * @def_sink: cached reference to default sink found for this device.
> - * @ect_dev: Associated cross trigger device. Not part of the trace data
> - * path or connections.
> * @nr_links: number of sysfs links created to other components from this
> * device. These will appear in the "connections" group.
> * @has_conns_grp: Have added a "connections" group for sysfs links.
> @@ -263,12 +252,9 @@ struct coresight_device {
> bool activated; /* true only if a sink is part of a path */
> struct dev_ext_attribute *ea;
> struct coresight_device *def_sink;
> - /* cross trigger handling */
> - struct coresight_device *ect_dev;
> /* sysfs links between components */
> int nr_links;
> bool has_conns_grp;
> - bool ect_enabled; /* true only if associated ect device is enabled */
> /* system configuration and feature lists */
> struct list_head feature_csdev_list;
> struct list_head config_csdev_list;
> @@ -380,23 +366,11 @@ struct coresight_ops_helper {
> int (*disable)(struct coresight_device *csdev, void *data);
> };
>
> -/**
> - * struct coresight_ops_ect - Ops for an embedded cross trigger device
> - *
> - * @enable : Enable the device
> - * @disable : Disable the device
> - */
> -struct coresight_ops_ect {
> - int (*enable)(struct coresight_device *csdev);
> - int (*disable)(struct coresight_device *csdev);
> -};
> -
> struct coresight_ops {
> const struct coresight_ops_sink *sink_ops;
> const struct coresight_ops_link *link_ops;
> const struct coresight_ops_source *source_ops;
> const struct coresight_ops_helper *helper_ops;
> - const struct coresight_ops_ect *ect_ops;
> };
>
> #if IS_ENABLED(CONFIG_CORESIGHT)
> --
> 2.34.1
>

Reviewed-by: Mike Leach <[email protected]>

--
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK

2023-04-24 10:50:53

by Suzuki K Poulose

[permalink] [raw]
Subject: Re: [PATCH v5 13/13] coresight: Fix CTI module refcount leak by making it a helper device

On 04/04/2023 16:51, James Clark wrote:
> The CTI module has some hard coded refcounting code that has a leak.
> For example running perf and then trying to unload it fails:
>
> perf record -e cs_etm// -a -- ls
> rmmod coresight_cti
>
> rmmod: ERROR: Module coresight_cti is in use
>
> The coresight core already handles references of devices in use, so by
> making CTI a normal helper device, we get working refcounting for free.
>
> Signed-off-by: James Clark <[email protected]>
> ---
> drivers/hwtracing/coresight/coresight-core.c | 104 ++++++------------
> .../hwtracing/coresight/coresight-cti-core.c | 52 +++++----
> .../hwtracing/coresight/coresight-cti-sysfs.c | 4 +-
> drivers/hwtracing/coresight/coresight-cti.h | 4 +-
> drivers/hwtracing/coresight/coresight-priv.h | 4 +-
> drivers/hwtracing/coresight/coresight-sysfs.c | 4 +
> include/linux/coresight.h | 30 +----
> 7 files changed, 75 insertions(+), 127 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index 16689fe4ba98..2af416bba983 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -236,60 +236,44 @@ void coresight_disclaim_device(struct coresight_device *csdev)
> }
> EXPORT_SYMBOL_GPL(coresight_disclaim_device);
>
> -/* enable or disable an associated CTI device of the supplied CS device */
> -static int
> -coresight_control_assoc_ectdev(struct coresight_device *csdev, bool enable)
> +/*
> + * Add a helper as an output device. This function takes the @coresight_mutex
> + * because it's assumed that it's called from the helper device, outside of the
> + * core code where the mutex would already be held. Don't add new calls to this
> + * from inside the core code, instead try to add the new helper to the DT and
> + * ACPI where it will be picked up and linked automatically.
> + */
> +void coresight_add_helper(struct coresight_device *csdev,
> + struct coresight_device *helper)
> {
> - int ect_ret = 0;
> - struct coresight_device *ect_csdev = csdev->ect_dev;
> - struct module *mod;
> + int i;
> + struct coresight_connection conn = {};
> + struct coresight_connection *new_conn;
>
> - if (!ect_csdev)
> - return 0;
> - if ((!ect_ops(ect_csdev)->enable) || (!ect_ops(ect_csdev)->disable))
> - return 0;
> + mutex_lock(&coresight_mutex);
> + conn.dest_fwnode = fwnode_handle_get(dev_fwnode(&helper->dev));
> + conn.dest_dev = helper;
> + conn.dest_port = conn.src_port = -1;
> + conn.src_dev = csdev;
>
> - mod = ect_csdev->dev.parent->driver->owner;
> - if (enable) {
> - 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;
> - } else {
> - if (csdev->ect_enabled) {
> - ect_ret = ect_ops(ect_csdev)->disable(ect_csdev);
> - put_device(ect_csdev->dev.parent);
> - module_put(mod);
> - csdev->ect_enabled = false;
> - }
> - }
> + /*
> + * Check for duplicates because this is called every time a helper
> + * device is re-loaded. Existing connections will get re-linked
> + * automatically.
> + */
> + for (i = 0; i < csdev->pdata->nr_outconns; ++i)
> + if (csdev->pdata->out_conns[i]->dest_fwnode == conn.dest_fwnode)
> + goto unlock;
>
> - /* 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;
> -}
> + new_conn =
> + coresight_add_out_conn(csdev->dev.parent, csdev->pdata, &conn);

ultra minor nit:
new_conn = coresight_add_out_conn(....,
.... );

> + if (!IS_ERR(new_conn))
> + coresight_add_in_conn(new_conn);
>
> -/*
> - * 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;
> +unlock:
> mutex_unlock(&coresight_mutex);
> }
> -EXPORT_SYMBOL_GPL(coresight_set_assoc_ectdev_mutex);
> +EXPORT_SYMBOL_GPL(coresight_add_helper);
>
> static int coresight_enable_sink(struct coresight_device *csdev,
> enum cs_mode mode, void *data)
> @@ -303,12 +287,8 @@ static int coresight_enable_sink(struct coresight_device *csdev,
> if (!sink_ops(csdev)->enable)
> return -EINVAL;
>
> - ret = coresight_control_assoc_ectdev(csdev, true);
> - if (ret)
> - return ret;
> ret = sink_ops(csdev)->enable(csdev, mode, data);
> if (ret) {
> - coresight_control_assoc_ectdev(csdev, false);
> return ret;
> }
> csdev->enable = true;
> @@ -326,7 +306,6 @@ static void coresight_disable_sink(struct coresight_device *csdev)
> ret = sink_ops(csdev)->disable(csdev);
> if (ret)
> return;
> - coresight_control_assoc_ectdev(csdev, false);
> csdev->enable = false;
> }
>
> @@ -351,17 +330,11 @@ static int coresight_enable_link(struct coresight_device *csdev,
> return PTR_ERR(outconn);
>
> if (link_ops(csdev)->enable) {
> - ret = coresight_control_assoc_ectdev(csdev, true);
> - if (!ret) {
> - ret = link_ops(csdev)->enable(csdev, inconn, outconn);
> - if (ret)
> - coresight_control_assoc_ectdev(csdev, false);
> - }
> + ret = link_ops(csdev)->enable(csdev, inconn, outconn);
> + if (!ret)
> + csdev->enable = true;
> }
>
> - if (!ret)
> - csdev->enable = true;
> -
> return ret;
> }
>
> @@ -382,7 +355,6 @@ static void coresight_disable_link(struct coresight_device *csdev,
>
> if (link_ops(csdev)->disable) {
> link_ops(csdev)->disable(csdev, inconn, outconn);
> - coresight_control_assoc_ectdev(csdev, false);
> }
>
> if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
> @@ -410,14 +382,9 @@ int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
>
> if (!csdev->enable) {
> if (source_ops(csdev)->enable) {
> - ret = coresight_control_assoc_ectdev(csdev, true);
> - if (ret)
> - return ret;
> ret = source_ops(csdev)->enable(csdev, data, mode);
> - if (ret) {
> - coresight_control_assoc_ectdev(csdev, false);
> + if (ret)
> return ret;
> - }
> }
> csdev->enable = true;
> }
> @@ -488,7 +455,6 @@ bool coresight_disable_source(struct coresight_device *csdev, void *data)
> if (atomic_dec_return(&csdev->refcnt) == 0) {
> if (source_ops(csdev)->disable)
> source_ops(csdev)->disable(csdev, data);
> - coresight_control_assoc_ectdev(csdev, false);
> coresight_disable_helpers(csdev);
> csdev->enable = false;
> }

You may also remove the "ect" from the

static struct device_type coresight_dev_type[]

Suzuki


2023-04-24 11:15:11

by James Clark

[permalink] [raw]
Subject: Re: [PATCH v5 13/13] coresight: Fix CTI module refcount leak by making it a helper device



On 24/04/2023 11:43, Suzuki K Poulose wrote:
> On 04/04/2023 16:51, James Clark wrote:
>> The CTI module has some hard coded refcounting code that has a leak.
>> For example running perf and then trying to unload it fails:
>>
>>    perf record -e cs_etm// -a -- ls
>>    rmmod coresight_cti
>>
>>    rmmod: ERROR: Module coresight_cti is in use
>>
>> The coresight core already handles references of devices in use, so by
>> making CTI a normal helper device, we get working refcounting for free.
>>
>> Signed-off-by: James Clark <[email protected]>
>> ---
>>   drivers/hwtracing/coresight/coresight-core.c  | 104 ++++++------------
>>   .../hwtracing/coresight/coresight-cti-core.c  |  52 +++++----
>>   .../hwtracing/coresight/coresight-cti-sysfs.c |   4 +-
>>   drivers/hwtracing/coresight/coresight-cti.h   |   4 +-
>>   drivers/hwtracing/coresight/coresight-priv.h  |   4 +-
>>   drivers/hwtracing/coresight/coresight-sysfs.c |   4 +
>>   include/linux/coresight.h                     |  30 +----
>>   7 files changed, 75 insertions(+), 127 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-core.c
>> b/drivers/hwtracing/coresight/coresight-core.c
>> index 16689fe4ba98..2af416bba983 100644
>> --- a/drivers/hwtracing/coresight/coresight-core.c
>> +++ b/drivers/hwtracing/coresight/coresight-core.c
>> @@ -236,60 +236,44 @@ void coresight_disclaim_device(struct
>> coresight_device *csdev)
>>   }
>>   EXPORT_SYMBOL_GPL(coresight_disclaim_device);
>>   -/* enable or disable an associated CTI device of the supplied CS
>> device */
>> -static int
>> -coresight_control_assoc_ectdev(struct coresight_device *csdev, bool
>> enable)
>> +/*
>> + * Add a helper as an output device. This function takes the
>> @coresight_mutex
>> + * because it's assumed that it's called from the helper device,
>> outside of the
>> + * core code where the mutex would already be held. Don't add new
>> calls to this
>> + * from inside the core code, instead try to add the new helper to
>> the DT and
>> + * ACPI where it will be picked up and linked automatically.
>> + */
>> +void coresight_add_helper(struct coresight_device *csdev,
>> +              struct coresight_device *helper)
>>   {
>> -    int ect_ret = 0;
>> -    struct coresight_device *ect_csdev = csdev->ect_dev;
>> -    struct module *mod;
>> +    int i;
>> +    struct coresight_connection conn = {};
>> +    struct coresight_connection *new_conn;
>>   -    if (!ect_csdev)
>> -        return 0;
>> -    if ((!ect_ops(ect_csdev)->enable) || (!ect_ops(ect_csdev)->disable))
>> -        return 0;
>> +    mutex_lock(&coresight_mutex);
>> +    conn.dest_fwnode = fwnode_handle_get(dev_fwnode(&helper->dev));
>> +    conn.dest_dev = helper;
>> +    conn.dest_port = conn.src_port = -1;
>> +    conn.src_dev = csdev;
>>   -    mod = ect_csdev->dev.parent->driver->owner;
>> -    if (enable) {
>> -        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;
>> -    } else {
>> -        if (csdev->ect_enabled) {
>> -            ect_ret = ect_ops(ect_csdev)->disable(ect_csdev);
>> -            put_device(ect_csdev->dev.parent);
>> -            module_put(mod);
>> -            csdev->ect_enabled = false;
>> -        }
>> -    }
>> +    /*
>> +     * Check for duplicates because this is called every time a helper
>> +     * device is re-loaded. Existing connections will get re-linked
>> +     * automatically.
>> +     */
>> +    for (i = 0; i < csdev->pdata->nr_outconns; ++i)
>> +        if (csdev->pdata->out_conns[i]->dest_fwnode == conn.dest_fwnode)
>> +            goto unlock;
>>   -    /* 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;
>> -}
>> +    new_conn =
>> +        coresight_add_out_conn(csdev->dev.parent, csdev->pdata, &conn);
>
> ultra minor nit:
>     new_conn = coresight_add_out_conn(....,
>                       .... );

This whole patchset is now formatted with the kernel clang-format rules.
Are you sure this one is against the conventions?

The problem is running the formatter on all changed lines makes it
almost impossible to go back and undo indents like this.

>
>> +    if (!IS_ERR(new_conn))
>> +        coresight_add_in_conn(new_conn);
>>   -/*
>> - * 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;
>> +unlock:
>>       mutex_unlock(&coresight_mutex);
>>   }
>> -EXPORT_SYMBOL_GPL(coresight_set_assoc_ectdev_mutex);
>> +EXPORT_SYMBOL_GPL(coresight_add_helper);
>>     static int coresight_enable_sink(struct coresight_device *csdev,
>>                    enum cs_mode mode, void *data)
>> @@ -303,12 +287,8 @@ static int coresight_enable_sink(struct
>> coresight_device *csdev,
>>       if (!sink_ops(csdev)->enable)
>>           return -EINVAL;
>>   -    ret = coresight_control_assoc_ectdev(csdev, true);
>> -    if (ret)
>> -        return ret;
>>       ret = sink_ops(csdev)->enable(csdev, mode, data);
>>       if (ret) {
>> -        coresight_control_assoc_ectdev(csdev, false);
>>           return ret;
>>       }
>>       csdev->enable = true;
>> @@ -326,7 +306,6 @@ static void coresight_disable_sink(struct
>> coresight_device *csdev)
>>       ret = sink_ops(csdev)->disable(csdev);
>>       if (ret)
>>           return;
>> -    coresight_control_assoc_ectdev(csdev, false);
>>       csdev->enable = false;
>>   }
>>   @@ -351,17 +330,11 @@ static int coresight_enable_link(struct
>> coresight_device *csdev,
>>           return PTR_ERR(outconn);
>>         if (link_ops(csdev)->enable) {
>> -        ret = coresight_control_assoc_ectdev(csdev, true);
>> -        if (!ret) {
>> -            ret = link_ops(csdev)->enable(csdev, inconn, outconn);
>> -            if (ret)
>> -                coresight_control_assoc_ectdev(csdev, false);
>> -        }
>> +        ret = link_ops(csdev)->enable(csdev, inconn, outconn);
>> +        if (!ret)
>> +            csdev->enable = true;
>>       }
>>   -    if (!ret)
>> -        csdev->enable = true;
>> -
>>       return ret;
>>   }
>>   @@ -382,7 +355,6 @@ static void coresight_disable_link(struct
>> coresight_device *csdev,
>>         if (link_ops(csdev)->disable) {
>>           link_ops(csdev)->disable(csdev, inconn, outconn);
>> -        coresight_control_assoc_ectdev(csdev, false);
>>       }
>>         if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
>> @@ -410,14 +382,9 @@ int coresight_enable_source(struct
>> coresight_device *csdev, enum cs_mode mode,
>>         if (!csdev->enable) {
>>           if (source_ops(csdev)->enable) {
>> -            ret = coresight_control_assoc_ectdev(csdev, true);
>> -            if (ret)
>> -                return ret;
>>               ret = source_ops(csdev)->enable(csdev, data, mode);
>> -            if (ret) {
>> -                coresight_control_assoc_ectdev(csdev, false);
>> +            if (ret)
>>                   return ret;
>> -            }
>>           }
>>           csdev->enable = true;
>>       }
>> @@ -488,7 +455,6 @@ bool coresight_disable_source(struct
>> coresight_device *csdev, void *data)
>>       if (atomic_dec_return(&csdev->refcnt) == 0) {
>>           if (source_ops(csdev)->disable)
>>               source_ops(csdev)->disable(csdev, data);
>> -        coresight_control_assoc_ectdev(csdev, false);
>>           coresight_disable_helpers(csdev);
>>           csdev->enable = false;
>>       }
>
> You may also remove the "ect" from the
>
> static struct device_type coresight_dev_type[]
>

Will fix this and Mike's last comments and send a v6

> Suzuki
>
>

2023-04-24 13:24:06

by Suzuki K Poulose

[permalink] [raw]
Subject: Re: [PATCH v5 13/13] coresight: Fix CTI module refcount leak by making it a helper device

On 24/04/2023 12:09, James Clark wrote:
>
>
> On 24/04/2023 11:43, Suzuki K Poulose wrote:
>> On 04/04/2023 16:51, James Clark wrote:
>>> The CTI module has some hard coded refcounting code that has a leak.
>>> For example running perf and then trying to unload it fails:
>>>
>>>    perf record -e cs_etm// -a -- ls
>>>    rmmod coresight_cti
>>>
>>>    rmmod: ERROR: Module coresight_cti is in use
>>>
>>> The coresight core already handles references of devices in use, so by
>>> making CTI a normal helper device, we get working refcounting for free.
>>>
>>> Signed-off-by: James Clark <[email protected]>
>>> ---
>>>   drivers/hwtracing/coresight/coresight-core.c  | 104 ++++++------------
>>>   .../hwtracing/coresight/coresight-cti-core.c  |  52 +++++----
>>>   .../hwtracing/coresight/coresight-cti-sysfs.c |   4 +-
>>>   drivers/hwtracing/coresight/coresight-cti.h   |   4 +-
>>>   drivers/hwtracing/coresight/coresight-priv.h  |   4 +-
>>>   drivers/hwtracing/coresight/coresight-sysfs.c |   4 +
>>>   include/linux/coresight.h                     |  30 +----
>>>   7 files changed, 75 insertions(+), 127 deletions(-)
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-core.c
>>> b/drivers/hwtracing/coresight/coresight-core.c
>>> index 16689fe4ba98..2af416bba983 100644
>>> --- a/drivers/hwtracing/coresight/coresight-core.c
>>> +++ b/drivers/hwtracing/coresight/coresight-core.c
>>> @@ -236,60 +236,44 @@ void coresight_disclaim_device(struct
>>> coresight_device *csdev)
>>>   }
>>>   EXPORT_SYMBOL_GPL(coresight_disclaim_device);
>>>   -/* enable or disable an associated CTI device of the supplied CS
>>> device */
>>> -static int
>>> -coresight_control_assoc_ectdev(struct coresight_device *csdev, bool
>>> enable)
>>> +/*
>>> + * Add a helper as an output device. This function takes the
>>> @coresight_mutex
>>> + * because it's assumed that it's called from the helper device,
>>> outside of the
>>> + * core code where the mutex would already be held. Don't add new
>>> calls to this
>>> + * from inside the core code, instead try to add the new helper to
>>> the DT and
>>> + * ACPI where it will be picked up and linked automatically.
>>> + */
>>> +void coresight_add_helper(struct coresight_device *csdev,
>>> +              struct coresight_device *helper)
>>>   {
>>> -    int ect_ret = 0;
>>> -    struct coresight_device *ect_csdev = csdev->ect_dev;
>>> -    struct module *mod;
>>> +    int i;
>>> +    struct coresight_connection conn = {};
>>> +    struct coresight_connection *new_conn;
>>>   -    if (!ect_csdev)
>>> -        return 0;
>>> -    if ((!ect_ops(ect_csdev)->enable) || (!ect_ops(ect_csdev)->disable))
>>> -        return 0;
>>> +    mutex_lock(&coresight_mutex);
>>> +    conn.dest_fwnode = fwnode_handle_get(dev_fwnode(&helper->dev));
>>> +    conn.dest_dev = helper;
>>> +    conn.dest_port = conn.src_port = -1;
>>> +    conn.src_dev = csdev;
>>>   -    mod = ect_csdev->dev.parent->driver->owner;
>>> -    if (enable) {
>>> -        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;
>>> -    } else {
>>> -        if (csdev->ect_enabled) {
>>> -            ect_ret = ect_ops(ect_csdev)->disable(ect_csdev);
>>> -            put_device(ect_csdev->dev.parent);
>>> -            module_put(mod);
>>> -            csdev->ect_enabled = false;
>>> -        }
>>> -    }
>>> +    /*
>>> +     * Check for duplicates because this is called every time a helper
>>> +     * device is re-loaded. Existing connections will get re-linked
>>> +     * automatically.
>>> +     */
>>> +    for (i = 0; i < csdev->pdata->nr_outconns; ++i)
>>> +        if (csdev->pdata->out_conns[i]->dest_fwnode == conn.dest_fwnode)
>>> +            goto unlock;
>>>   -    /* 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;
>>> -}
>>> +    new_conn =
>>> +        coresight_add_out_conn(csdev->dev.parent, csdev->pdata, &conn);
>>
>> ultra minor nit:
>>     new_conn = coresight_add_out_conn(....,
>>                       .... );
>
> This whole patchset is now formatted with the kernel clang-format rules.
> Are you sure this one is against the conventions?

It is not against convention, but there are no hard line rules for
these.

The only suggestion is to split the lines sensibly with
readability stressed.

https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings

"Statements longer than 80 columns should be broken into sensible
chunks, unless exceeding 80 columns significantly increases readability
and does not hide information.

Descendants are always substantially shorter than the parent and are
placed substantially to the right. A very commonly used style is to
align descendants to a function open parenthesis."


I personally find it :

result = rather_long_function_statement(arg1, arg2,
........);

way better readable than :

result =
rather_long_function_statement(.....);

>
> The problem is running the formatter on all changed lines makes it
> almost impossible to go back and undo indents like this.

Haven't used it, but it does seem to say it may not be perfect ;-).
That said, I am not too strict about this. You may leave it unchanged
if it is painful.

Suzuki


2023-04-25 14:42:25

by James Clark

[permalink] [raw]
Subject: Re: [PATCH v5 13/13] coresight: Fix CTI module refcount leak by making it a helper device



On 24/04/2023 14:22, Suzuki K Poulose wrote:
> On 24/04/2023 12:09, James Clark wrote:
>>
>>
>> On 24/04/2023 11:43, Suzuki K Poulose wrote:
>>> On 04/04/2023 16:51, James Clark wrote:
>>>> The CTI module has some hard coded refcounting code that has a leak.
>>>> For example running perf and then trying to unload it fails:
>>>>
>>>>     perf record -e cs_etm// -a -- ls
>>>>     rmmod coresight_cti
>>>>
>>>>     rmmod: ERROR: Module coresight_cti is in use
>>>>
>>>> The coresight core already handles references of devices in use, so by
>>>> making CTI a normal helper device, we get working refcounting for free.
>>>>
>>>> Signed-off-by: James Clark <[email protected]>
>>>> ---
>>>>    drivers/hwtracing/coresight/coresight-core.c  | 104
>>>> ++++++------------
>>>>    .../hwtracing/coresight/coresight-cti-core.c  |  52 +++++----
>>>>    .../hwtracing/coresight/coresight-cti-sysfs.c |   4 +-
>>>>    drivers/hwtracing/coresight/coresight-cti.h   |   4 +-
>>>>    drivers/hwtracing/coresight/coresight-priv.h  |   4 +-
>>>>    drivers/hwtracing/coresight/coresight-sysfs.c |   4 +
>>>>    include/linux/coresight.h                     |  30 +----
>>>>    7 files changed, 75 insertions(+), 127 deletions(-)
>>>>
>>>> diff --git a/drivers/hwtracing/coresight/coresight-core.c
>>>> b/drivers/hwtracing/coresight/coresight-core.c
>>>> index 16689fe4ba98..2af416bba983 100644
>>>> --- a/drivers/hwtracing/coresight/coresight-core.c
>>>> +++ b/drivers/hwtracing/coresight/coresight-core.c
>>>> @@ -236,60 +236,44 @@ void coresight_disclaim_device(struct
>>>> coresight_device *csdev)
>>>>    }
>>>>    EXPORT_SYMBOL_GPL(coresight_disclaim_device);
>>>>    -/* enable or disable an associated CTI device of the supplied CS
>>>> device */
>>>> -static int
>>>> -coresight_control_assoc_ectdev(struct coresight_device *csdev, bool
>>>> enable)
>>>> +/*
>>>> + * Add a helper as an output device. This function takes the
>>>> @coresight_mutex
>>>> + * because it's assumed that it's called from the helper device,
>>>> outside of the
>>>> + * core code where the mutex would already be held. Don't add new
>>>> calls to this
>>>> + * from inside the core code, instead try to add the new helper to
>>>> the DT and
>>>> + * ACPI where it will be picked up and linked automatically.
>>>> + */
>>>> +void coresight_add_helper(struct coresight_device *csdev,
>>>> +              struct coresight_device *helper)
>>>>    {
>>>> -    int ect_ret = 0;
>>>> -    struct coresight_device *ect_csdev = csdev->ect_dev;
>>>> -    struct module *mod;
>>>> +    int i;
>>>> +    struct coresight_connection conn = {};
>>>> +    struct coresight_connection *new_conn;
>>>>    -    if (!ect_csdev)
>>>> -        return 0;
>>>> -    if ((!ect_ops(ect_csdev)->enable) ||
>>>> (!ect_ops(ect_csdev)->disable))
>>>> -        return 0;
>>>> +    mutex_lock(&coresight_mutex);
>>>> +    conn.dest_fwnode = fwnode_handle_get(dev_fwnode(&helper->dev));
>>>> +    conn.dest_dev = helper;
>>>> +    conn.dest_port = conn.src_port = -1;
>>>> +    conn.src_dev = csdev;
>>>>    -    mod = ect_csdev->dev.parent->driver->owner;
>>>> -    if (enable) {
>>>> -        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;
>>>> -    } else {
>>>> -        if (csdev->ect_enabled) {
>>>> -            ect_ret = ect_ops(ect_csdev)->disable(ect_csdev);
>>>> -            put_device(ect_csdev->dev.parent);
>>>> -            module_put(mod);
>>>> -            csdev->ect_enabled = false;
>>>> -        }
>>>> -    }
>>>> +    /*
>>>> +     * Check for duplicates because this is called every time a helper
>>>> +     * device is re-loaded. Existing connections will get re-linked
>>>> +     * automatically.
>>>> +     */
>>>> +    for (i = 0; i < csdev->pdata->nr_outconns; ++i)
>>>> +        if (csdev->pdata->out_conns[i]->dest_fwnode ==
>>>> conn.dest_fwnode)
>>>> +            goto unlock;
>>>>    -    /* 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;
>>>> -}
>>>> +    new_conn =
>>>> +        coresight_add_out_conn(csdev->dev.parent, csdev->pdata,
>>>> &conn);
>>>
>>> ultra minor nit:
>>>      new_conn = coresight_add_out_conn(....,
>>>                        .... );
>>
>> This whole patchset is now formatted with the kernel clang-format rules.
>> Are you sure this one is against the conventions?
>
> It is not against convention, but there are no hard line rules for
> these.
>
> The only suggestion is to split the lines sensibly with
> readability stressed.
>
> https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings
>
> "Statements longer than 80 columns should be broken into sensible
> chunks, unless exceeding 80 columns significantly increases readability
> and does not hide information.
>
> Descendants are always substantially shorter than the parent and are
> placed substantially to the right. A very commonly used style is to
> align descendants to a function open parenthesis."
>
>
> I personally find it :
>
>     result = rather_long_function_statement(arg1, arg2,
>                             ........);
>
> way better readable than :
>
>     result =
>         rather_long_function_statement(.....);
>
>>
>> The problem is running the formatter on all changed lines makes it
>> almost impossible to go back and undo indents like this.
>
> Haven't used it, but it does seem to say it may not be perfect ;-).
> That said, I am not too strict about this. You may leave it unchanged
> if it is painful.
> > Suzuki
>

Upon further inspection I think it might actually be a bug in
clang-format. When only the ); falls over the column limit it doesn't
know that it needs to wrap the previous token to stick with the rules.
Or something like that.

I'll probably leave that debugging rabbit hole for another time. Anyway
I fixed this one in v6.