From 55bf8be6f4a80d44c7f10e9d39b583e9645edf93 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 24 Feb 2026 10:56:14 +0000 Subject: [PATCH 01/25] coresight: cti: Move resource release to cti_remove() Currently, CTI driver releases resource by deferring cti_device_release() to the device unregistration: cti_remove() `> coresight_unregister() `> cti_remove_assoc_from_csdev() `> device_unregister() `> cti_device_release() `> mutex_lock(&ect_mutex) `> release CTI resource `> mutex_unlock(&ect_mutex) In the above flow, two different CTI release callbacks are involved: cti_remove_assoc_from_csdev() and cti_device_release(). The former is used by a CoreSight device to unbind its associated CTI helper device, while the latter releases resources for the CTI device itself. Since there is no dependency between them, it is unnecessary to defer the CTI resource release until device unregistration. This commit releases the resources directly in cti_remove() and remove the injected release callback. Signed-off-by: Leo Yan Reviewed-by: Mike Leach Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260224-arm_coresight_refactor_cti_resource_release-v1-1-ff1b2bca9176@arm.com --- .../hwtracing/coresight/coresight-cti-core.c | 24 +++---------------- drivers/hwtracing/coresight/coresight-cti.h | 2 -- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index bfbc365bb2ef..7a8f1ef6b94e 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -823,16 +823,13 @@ static const struct coresight_ops cti_ops = { .helper_ops = &cti_ops_ect, }; -/* - * Free up CTI specific resources - * called by dev->release, need to call down to underlying csdev release. - */ -static void cti_device_release(struct device *dev) +static void cti_remove(struct amba_device *adev) { - struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_drvdata *drvdata = dev_get_drvdata(&adev->dev); struct cti_drvdata *ect_item, *ect_tmp; mutex_lock(&ect_mutex); + cti_remove_conn_xrefs(drvdata); cti_pm_release(drvdata); /* remove from the list */ @@ -844,17 +841,6 @@ static void cti_device_release(struct device *dev) } mutex_unlock(&ect_mutex); - if (drvdata->csdev_release) - drvdata->csdev_release(dev); -} -static void cti_remove(struct amba_device *adev) -{ - struct cti_drvdata *drvdata = dev_get_drvdata(&adev->dev); - - mutex_lock(&ect_mutex); - cti_remove_conn_xrefs(drvdata); - mutex_unlock(&ect_mutex); - coresight_unregister(drvdata->csdev); } @@ -947,10 +933,6 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) cti_update_conn_xrefs(drvdata); mutex_unlock(&ect_mutex); - /* set up release chain */ - drvdata->csdev_release = drvdata->csdev->dev.release; - drvdata->csdev->dev.release = cti_device_release; - /* all done - dec pm refcount */ pm_runtime_put(&adev->dev); dev_info(&drvdata->csdev->dev, "CTI initialized\n"); diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 4f89091ee93f..daff9e32a6da 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -170,7 +170,6 @@ struct cti_config { * @spinlock: Control data access to one at a time. * @config: Configuration data for this CTI device. * @node: List entry of this device in the list of CTI devices. - * @csdev_release: release function for underlying coresight_device. */ struct cti_drvdata { void __iomem *base; @@ -179,7 +178,6 @@ struct cti_drvdata { raw_spinlock_t spinlock; struct cti_config config; struct list_head node; - void (*csdev_release)(struct device *dev); }; /* From 0289ada4a31661016a0611a41a4886bb958e9985 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 9 Feb 2026 12:44:33 +0000 Subject: [PATCH 02/25] coresight: Fix memory leak in coresight_alloc_device_name() The memory leak detector reports: echo clear > /sys/kernel/debug/kmemleak modprobe coresight_funnel rmmod coresight_funnel # Scan memory leak and report it echo scan > /sys/kernel/debug/kmemleak cat /sys/kernel/debug/kmemleak unreferenced object 0xffff0008020c7200 (size 64): comm "modprobe", pid 410, jiffies 4295333721 hex dump (first 32 bytes): d8 da fe 7e 09 00 ff ff e8 2e ff 7e 09 00 ff ff ...~.......~.... b0 6c ff 7e 09 00 ff ff 30 83 00 7f 09 00 ff ff .l.~....0....... backtrace (crc 4116a690): kmemleak_alloc+0xd8/0xf8 __kmalloc_node_track_caller_noprof+0x2c8/0x6f0 krealloc_node_align_noprof+0x13c/0x2c8 coresight_alloc_device_name+0xe4/0x158 [coresight] 0xffffd327ecef8394 0xffffd327ecef85ec amba_probe+0x118/0x1c8 really_probe+0xc8/0x3f0 __driver_probe_device+0x88/0x190 driver_probe_device+0x44/0x120 __driver_attach+0x100/0x238 bus_for_each_dev+0x84/0xf0 driver_attach+0x2c/0x40 bus_add_driver+0x128/0x258 driver_register+0x64/0x138 __amba_driver_register+0x2c/0x48 The memory leak is caused by not freeing the device list that maintains device indices. This device list preserves stable device indices across unbind and rebind device operations, so it does not share the same lifetime as a device instances and must only be freed when the module is unloaded. Some modules do not implement a module exit callback because they are registered using module_platform_driver(). As a result, the device list cannot be released during module exit for those modules. Fix this by moving the device list into the core layer. As a general solution, instead of maintaining a static list in each driver, drivers now allocate device lists via coresight_allocate_device_list() and device indices via coresight_allocate_device_idx(). The list is released only when the core module is unloaded by calling coresight_release_device_list(), avoiding the leak. Fixes: 0f5f9b6ba9e1 ("coresight: Use platform agnostic names") Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260209-arm_coresight_refactor_dev_register-v4-1-62d6042f76f7@arm.com --- drivers/hwtracing/coresight/coresight-catu.c | 4 +- drivers/hwtracing/coresight/coresight-core.c | 129 +++++++++++++----- .../hwtracing/coresight/coresight-ctcu-core.c | 4 +- .../hwtracing/coresight/coresight-cti-core.c | 19 ++- drivers/hwtracing/coresight/coresight-dummy.c | 7 +- drivers/hwtracing/coresight/coresight-etb10.c | 4 +- .../hwtracing/coresight/coresight-funnel.c | 4 +- .../coresight/coresight-replicator.c | 4 +- drivers/hwtracing/coresight/coresight-stm.c | 4 +- .../hwtracing/coresight/coresight-tmc-core.c | 12 +- drivers/hwtracing/coresight/coresight-tnoc.c | 4 +- drivers/hwtracing/coresight/coresight-tpda.c | 4 +- drivers/hwtracing/coresight/coresight-tpdm.c | 4 +- drivers/hwtracing/coresight/coresight-tpiu.c | 4 +- drivers/hwtracing/coresight/ultrasoc-smb.c | 4 +- include/linux/coresight.h | 14 +- 16 files changed, 121 insertions(+), 104 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index dfd035852b12..ce71dcddfca2 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -30,8 +30,6 @@ #define catu_dbg(x, ...) do {} while (0) #endif -DEFINE_CORESIGHT_DEVLIST(catu_devs, "catu"); - struct catu_etr_buf { struct tmc_sg_table *catu_table; dma_addr_t sladdr; @@ -530,7 +528,7 @@ static int __catu_probe(struct device *dev, struct resource *res) if (ret) return ret; - catu_desc.name = coresight_alloc_device_name(&catu_devs, dev); + catu_desc.name = coresight_alloc_device_name("catu", dev); if (!catu_desc.name) return -ENOMEM; diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 80e26396ad0a..6881fdc5da92 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -53,6 +53,9 @@ struct coresight_node { const u32 coresight_barrier_pkt[4] = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff}; EXPORT_SYMBOL_GPL(coresight_barrier_pkt); +/* List maintains the device index */ +static LIST_HEAD(coresight_dev_idx_list); + static const struct cti_assoc_op *cti_assoc_ops; void coresight_set_cti_ops(const struct cti_assoc_op *cti_op) @@ -1438,22 +1441,55 @@ void coresight_unregister(struct coresight_device *csdev) } EXPORT_SYMBOL_GPL(coresight_unregister); - -/* - * coresight_search_device_idx - Search the fwnode handle of a device - * in the given dev_idx list. Must be called with the coresight_mutex held. - * - * Returns the index of the entry, when found. Otherwise, -ENOENT. - */ -static int coresight_search_device_idx(struct coresight_dev_list *dict, - struct fwnode_handle *fwnode) +static struct coresight_dev_list * +coresight_allocate_device_list(const char *prefix) { - int i; + struct coresight_dev_list *list; - for (i = 0; i < dict->nr_idx; i++) - if (dict->fwnode_list[i] == fwnode) - return i; - return -ENOENT; + /* Check if have already allocated */ + list_for_each_entry(list, &coresight_dev_idx_list, node) { + if (!strcmp(list->pfx, prefix)) + return list; + } + + list = kzalloc(sizeof(*list), GFP_KERNEL); + if (!list) + return NULL; + + list->pfx = kstrdup(prefix, GFP_KERNEL); + if (!list->pfx) { + kfree(list); + return NULL; + } + + list_add(&list->node, &coresight_dev_idx_list); + return list; +} + +static int coresight_allocate_device_idx(struct coresight_dev_list *list, + struct device *dev) +{ + struct fwnode_handle **fwnode_list; + struct fwnode_handle *fwnode = dev_fwnode(dev); + int idx; + + for (idx = 0; idx < list->nr_idx; idx++) + if (list->fwnode_list[idx] == fwnode) + return idx; + + /* Make space for the new entry */ + idx = list->nr_idx; + fwnode_list = krealloc_array(list->fwnode_list, + idx + 1, sizeof(*list->fwnode_list), + GFP_KERNEL); + if (!fwnode_list) + return -ENOMEM; + + fwnode_list[idx] = fwnode; + list->fwnode_list = fwnode_list; + list->nr_idx = idx + 1; + + return idx; } static bool coresight_compare_type(enum coresight_dev_type type_a, @@ -1527,45 +1563,63 @@ bool coresight_loses_context_with_cpu(struct device *dev) EXPORT_SYMBOL_GPL(coresight_loses_context_with_cpu); /* - * coresight_alloc_device_name - Get an index for a given device in the - * device index list specific to a driver. An index is allocated for a - * device and is tracked with the fwnode_handle to prevent allocating + * coresight_alloc_device_name - Get an index for a given device in the list + * specific to a driver (presented by the prefix string). An index is allocated + * for a device and is tracked with the fwnode_handle to prevent allocating * duplicate indices for the same device (e.g, if we defer probing of * a device due to dependencies), in case the index is requested again. */ -char *coresight_alloc_device_name(struct coresight_dev_list *dict, - struct device *dev) +char *coresight_alloc_device_name(const char *prefix, struct device *dev) { - int idx; + struct coresight_dev_list *list; char *name = NULL; - struct fwnode_handle **list; + int idx; mutex_lock(&coresight_mutex); - idx = coresight_search_device_idx(dict, dev_fwnode(dev)); - if (idx < 0) { - /* Make space for the new entry */ - idx = dict->nr_idx; - list = krealloc_array(dict->fwnode_list, - idx + 1, sizeof(*dict->fwnode_list), - GFP_KERNEL); - if (ZERO_OR_NULL_PTR(list)) { - idx = -ENOMEM; - goto done; - } + list = coresight_allocate_device_list(prefix); + if (!list) + goto done; - list[idx] = dev_fwnode(dev); - dict->fwnode_list = list; - dict->nr_idx = idx + 1; - } + idx = coresight_allocate_device_idx(list, dev); - name = devm_kasprintf(dev, GFP_KERNEL, "%s%d", dict->pfx, idx); + /* + * If index allocation fails, the device list is not released here; + * it is instead freed later by coresight_release_device_list() when + * the coresight_core module is unloaded. + */ + if (idx < 0) + goto done; + + name = devm_kasprintf(dev, GFP_KERNEL, "%s%d", list->pfx, idx); done: mutex_unlock(&coresight_mutex); return name; } EXPORT_SYMBOL_GPL(coresight_alloc_device_name); +static void coresight_release_device_list(void) +{ + struct coresight_dev_list *list, *next; + int i; + + /* + * Here is no need to take coresight_mutex; this is during core module + * unloading, no race condition with other modules. + */ + + list_for_each_entry_safe(list, next, &coresight_dev_idx_list, node) { + for (i = 0; i < list->nr_idx; i++) + list->fwnode_list[i] = NULL; + list->nr_idx = 0; + list_del(&list->node); + + kfree(list->pfx); + kfree(list->fwnode_list); + kfree(list); + } +} + const struct bus_type coresight_bustype = { .name = "coresight", }; @@ -1639,6 +1693,7 @@ static void __exit coresight_exit(void) &coresight_notifier); etm_perf_exit(); bus_unregister(&coresight_bustype); + coresight_release_device_list(); } module_init(coresight_init); diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c index abed15eb72b4..6813ae6e929b 100644 --- a/drivers/hwtracing/coresight/coresight-ctcu-core.c +++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c @@ -19,8 +19,6 @@ #include "coresight-ctcu.h" #include "coresight-priv.h" -DEFINE_CORESIGHT_DEVLIST(ctcu_devs, "ctcu"); - #define ctcu_writel(drvdata, val, offset) __raw_writel((val), drvdata->base + offset) #define ctcu_readl(drvdata, offset) __raw_readl(drvdata->base + offset) @@ -187,7 +185,7 @@ static int ctcu_probe(struct platform_device *pdev) void __iomem *base; int i, ret; - desc.name = coresight_alloc_device_name(&ctcu_devs, dev); + desc.name = coresight_alloc_device_name("ctcu", dev); if (!desc.name) return -ENOMEM; diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index 7a8f1ef6b94e..fddc8f31b91d 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -48,15 +48,6 @@ static int nr_cti_cpu; /* quick lookup list for CPU bound CTIs when power handling */ static struct cti_drvdata *cti_cpu_drvdata[NR_CPUS]; -/* - * CTI naming. CTI bound to cores will have the name cti_cpu where - * N is the CPU ID. System CTIs will have the name cti_sys where I - * is an index allocated by order of discovery. - * - * CTI device name list - for CTI not bound to cores. - */ -DEFINE_CORESIGHT_DEVLIST(cti_sys_devs, "cti_sys"); - /* write set of regs to hardware - call with spinlock claimed */ void cti_write_all_hw_regs(struct cti_drvdata *drvdata) { @@ -889,12 +880,18 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) /* default to powered - could change on PM notifications */ drvdata->config.hw_powered = true; - /* set up device name - will depend if cpu bound or otherwise */ + /* + * Set up device name - will depend if cpu bound or otherwise. + * + * CTI bound to cores will have the name cti_cpu where N is th + * eCPU ID. System CTIs will have the name cti_sys where I is an + * index allocated by order of discovery. + */ if (drvdata->ctidev.cpu >= 0) cti_desc.name = devm_kasprintf(dev, GFP_KERNEL, "cti_cpu%d", drvdata->ctidev.cpu); else - cti_desc.name = coresight_alloc_device_name(&cti_sys_devs, dev); + cti_desc.name = coresight_alloc_device_name("cti_sys", dev); if (!cti_desc.name) return -ENOMEM; diff --git a/drivers/hwtracing/coresight/coresight-dummy.c b/drivers/hwtracing/coresight/coresight-dummy.c index 14322c99e29d..c176a2f57300 100644 --- a/drivers/hwtracing/coresight/coresight-dummy.c +++ b/drivers/hwtracing/coresight/coresight-dummy.c @@ -19,9 +19,6 @@ struct dummy_drvdata { u8 traceid; }; -DEFINE_CORESIGHT_DEVLIST(source_devs, "dummy_source"); -DEFINE_CORESIGHT_DEVLIST(sink_devs, "dummy_sink"); - static int dummy_source_enable(struct coresight_device *csdev, struct perf_event *event, enum cs_mode mode, __maybe_unused struct coresight_path *path) @@ -126,7 +123,7 @@ static int dummy_probe(struct platform_device *pdev) if (of_device_is_compatible(node, "arm,coresight-dummy-source")) { - desc.name = coresight_alloc_device_name(&source_devs, dev); + desc.name = coresight_alloc_device_name("dummy_source", dev); if (!desc.name) return -ENOMEM; @@ -155,7 +152,7 @@ static int dummy_probe(struct platform_device *pdev) drvdata->traceid = (u8)trace_id; } else if (of_device_is_compatible(node, "arm,coresight-dummy-sink")) { - desc.name = coresight_alloc_device_name(&sink_devs, dev); + desc.name = coresight_alloc_device_name("dummy_sink", dev); if (!desc.name) return -ENOMEM; diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 6657602d8f2e..b952a1d47f12 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -63,8 +63,6 @@ #define ETB_FFSR_BIT 1 #define ETB_FRAME_SIZE_WORDS 4 -DEFINE_CORESIGHT_DEVLIST(etb_devs, "etb"); - /** * struct etb_drvdata - specifics associated to an ETB component * @base: memory mapped base address for this component. @@ -722,7 +720,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) struct resource *res = &adev->res; struct coresight_desc desc = { 0 }; - desc.name = coresight_alloc_device_name(&etb_devs, dev); + desc.name = coresight_alloc_device_name("etb", dev); if (!desc.name) return -ENOMEM; diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 3b248e54471a..3f56ceccd8c9 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -30,8 +30,6 @@ #define FUNNEL_HOLDTIME (0x7 << FUNNEL_HOLDTIME_SHFT) #define FUNNEL_ENSx_MASK 0xff -DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel"); - /** * struct funnel_drvdata - specifics associated to a funnel component * @base: memory mapped base address for this component. @@ -223,7 +221,7 @@ static int funnel_probe(struct device *dev, struct resource *res) of_device_is_compatible(dev->of_node, "arm,coresight-funnel")) dev_warn_once(dev, "Uses OBSOLETE CoreSight funnel binding\n"); - desc.name = coresight_alloc_device_name(&funnel_devs, dev); + desc.name = coresight_alloc_device_name("funnel", dev); if (!desc.name) return -ENOMEM; diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index e6472658235d..07fc04f53b88 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -24,8 +24,6 @@ #define REPLICATOR_IDFILTER0 0x000 #define REPLICATOR_IDFILTER1 0x004 -DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator"); - /** * struct replicator_drvdata - specifics associated to a replicator component * @base: memory mapped base address for this component. Also indicates @@ -230,7 +228,7 @@ static int replicator_probe(struct device *dev, struct resource *res) dev_warn_once(dev, "Uses OBSOLETE CoreSight replicator binding\n"); - desc.name = coresight_alloc_device_name(&replicator_devs, dev); + desc.name = coresight_alloc_device_name("replicator", dev); if (!desc.name) return -ENOMEM; diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index e68529bf89c9..aca6cec7885a 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -110,8 +110,6 @@ struct channel_space { unsigned long *guaranteed; }; -DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm"); - /** * struct stm_drvdata - specifics associated to an STM component * @base: memory mapped base address for this component. @@ -834,7 +832,7 @@ static int __stm_probe(struct device *dev, struct resource *res) struct resource ch_res; struct coresight_desc desc = { 0 }; - desc.name = coresight_alloc_device_name(&stm_devs, dev); + desc.name = coresight_alloc_device_name("stm", dev); if (!desc.name) return -ENOMEM; diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 36599c431be6..58b469ee73b4 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -32,10 +32,6 @@ #include "coresight-priv.h" #include "coresight-tmc.h" -DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb"); -DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf"); -DEFINE_CORESIGHT_DEVLIST(etr_devs, "tmc_etr"); - int tmc_wait_for_tmcready(struct tmc_drvdata *drvdata) { struct coresight_device *csdev = drvdata->csdev; @@ -777,7 +773,7 @@ static int __tmc_probe(struct device *dev, struct resource *res) struct coresight_platform_data *pdata = NULL; struct tmc_drvdata *drvdata; struct coresight_desc desc = { 0 }; - struct coresight_dev_list *dev_list = NULL; + const char *dev_list = NULL; drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) @@ -827,7 +823,7 @@ static int __tmc_probe(struct device *dev, struct resource *res) desc.type = CORESIGHT_DEV_TYPE_SINK; desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; desc.ops = &tmc_etb_cs_ops; - dev_list = &etb_devs; + dev_list = "tmc_etb"; break; case TMC_CONFIG_TYPE_ETR: desc.groups = coresight_etr_groups; @@ -839,7 +835,7 @@ static int __tmc_probe(struct device *dev, struct resource *res) goto out; idr_init(&drvdata->idr); mutex_init(&drvdata->idr_mutex); - dev_list = &etr_devs; + dev_list = "tmc_etr"; break; case TMC_CONFIG_TYPE_ETF: desc.groups = coresight_etf_groups; @@ -847,7 +843,7 @@ static int __tmc_probe(struct device *dev, struct resource *res) desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO; desc.ops = &tmc_etf_cs_ops; - dev_list = &etf_devs; + dev_list = "tmc_etf"; break; default: pr_err("%s: Unsupported TMC config\n", desc.name); diff --git a/drivers/hwtracing/coresight/coresight-tnoc.c b/drivers/hwtracing/coresight/coresight-tnoc.c index 1128612e70a7..96a25877b824 100644 --- a/drivers/hwtracing/coresight/coresight-tnoc.c +++ b/drivers/hwtracing/coresight/coresight-tnoc.c @@ -47,8 +47,6 @@ struct trace_noc_drvdata { int atid; }; -DEFINE_CORESIGHT_DEVLIST(trace_noc_devs, "traceNoc"); - static void trace_noc_enable_hw(struct trace_noc_drvdata *drvdata) { u32 val; @@ -191,7 +189,7 @@ static int _tnoc_probe(struct device *dev, struct resource *res) struct coresight_desc desc = { 0 }; int ret; - desc.name = coresight_alloc_device_name(&trace_noc_devs, dev); + desc.name = coresight_alloc_device_name("traceNoc", dev); if (!desc.name) return -ENOMEM; diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index 7055f8f13427..89c8f71f0aff 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -20,8 +20,6 @@ #include "coresight-trace-id.h" #include "coresight-tpdm.h" -DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda"); - static void tpda_clear_element_size(struct coresight_device *csdev) { struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); @@ -585,7 +583,7 @@ static int tpda_probe(struct amba_device *adev, const struct amba_id *id) if (ret) return ret; - desc.name = coresight_alloc_device_name(&tpda_devs, dev); + desc.name = coresight_alloc_device_name("tpda", dev); if (!desc.name) return -ENOMEM; desc.type = CORESIGHT_DEV_TYPE_LINK; diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 06e0a905a67d..da77bdaad0a4 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -19,8 +19,6 @@ #include "coresight-priv.h" #include "coresight-tpdm.h" -DEFINE_CORESIGHT_DEVLIST(tpdm_devs, "tpdm"); - static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata) { return (drvdata->datasets & TPDM_PIDR0_DS_DSB); @@ -1416,7 +1414,7 @@ static int tpdm_probe(struct device *dev, struct resource *res) } /* Set up coresight component description */ - desc.name = coresight_alloc_device_name(&tpdm_devs, dev); + desc.name = coresight_alloc_device_name("tpdm", dev); if (!desc.name) return -ENOMEM; desc.type = CORESIGHT_DEV_TYPE_SOURCE; diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index aaa44bc521c3..b8560b140e0f 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -49,8 +49,6 @@ #define FFCR_FON_MAN BIT(6) #define FFCR_STOP_FI BIT(12) -DEFINE_CORESIGHT_DEVLIST(tpiu_devs, "tpiu"); - /* * @base: memory mapped base address for this component. * @atclk: optional clock for the core parts of the TPIU. @@ -134,7 +132,7 @@ static int __tpiu_probe(struct device *dev, struct resource *res) struct coresight_desc desc = { 0 }; int ret; - desc.name = coresight_alloc_device_name(&tpiu_devs, dev); + desc.name = coresight_alloc_device_name("tpiu", dev); if (!desc.name) return -ENOMEM; diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c index 8f7922a5e534..5776f63468fa 100644 --- a/drivers/hwtracing/coresight/ultrasoc-smb.c +++ b/drivers/hwtracing/coresight/ultrasoc-smb.c @@ -17,8 +17,6 @@ #include "coresight-priv.h" #include "ultrasoc-smb.h" -DEFINE_CORESIGHT_DEVLIST(sink_devs, "ultra_smb"); - #define ULTRASOC_SMB_DSM_UUID "82ae1283-7f6a-4cbe-aa06-53e8fb24db18" static bool smb_buffer_not_empty(struct smb_drv_data *drvdata) @@ -478,7 +476,7 @@ static int smb_register_sink(struct platform_device *pdev, desc.pdata = pdata; desc.dev = &pdev->dev; desc.groups = smb_sink_groups; - desc.name = coresight_alloc_device_name(&sink_devs, &pdev->dev); + desc.name = coresight_alloc_device_name("ultra_smb", &pdev->dev); if (!desc.name) { dev_err(&pdev->dev, "Failed to alloc coresight device name"); return -ENOMEM; diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 2b48be97fcd0..2131febebee9 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -306,24 +306,19 @@ struct coresight_device { * coresight_dev_list - Mapping for devices to "name" index for device * names. * + * @node: Node on the global device index list. * @nr_idx: Number of entries already allocated. * @pfx: Prefix pattern for device name. * @fwnode_list: Array of fwnode_handles associated with each allocated * index, upto nr_idx entries. */ struct coresight_dev_list { + struct list_head node; int nr_idx; - const char *pfx; + char *pfx; struct fwnode_handle **fwnode_list; }; -#define DEFINE_CORESIGHT_DEVLIST(var, dev_pfx) \ -static struct coresight_dev_list (var) = { \ - .pfx = dev_pfx, \ - .nr_idx = 0, \ - .fwnode_list = NULL, \ -} - #define to_coresight_device(d) container_of(d, struct coresight_device, dev) /** @@ -663,8 +658,7 @@ void coresight_clear_self_claim_tag(struct csdev_access *csa); void coresight_clear_self_claim_tag_unlocked(struct csdev_access *csa); void coresight_disclaim_device(struct coresight_device *csdev); void coresight_disclaim_device_unlocked(struct coresight_device *csdev); -char *coresight_alloc_device_name(struct coresight_dev_list *devs, - struct device *dev); +char *coresight_alloc_device_name(const char *prefix, struct device *dev); bool coresight_loses_context_with_cpu(struct device *dev); From 2f322f0392814a1b704e14927d282f4b2edb9e98 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 9 Feb 2026 12:44:34 +0000 Subject: [PATCH 03/25] coresight: Get parent device reference after sink ID map allocation The parent device's reference count is incremented before allocating the sink ID map. If the allocation fails, the reference count is not decremented, preventing proper cleanup. Fix this by incrementing the reference count only after the sink ID map is successfully allocated. Fixes: 5ad628a76176 ("coresight: Use per-sink trace ID maps for Perf sessions") Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260209-arm_coresight_refactor_dev_register-v4-2-62d6042f76f7@arm.com --- drivers/hwtracing/coresight/coresight-core.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 6881fdc5da92..e2c0f971eccf 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1349,12 +1349,6 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) csdev->dev.parent = desc->dev; csdev->dev.release = coresight_device_release; csdev->dev.bus = &coresight_bustype; - /* - * Hold the reference to our parent device. This will be - * dropped only in coresight_device_release(). - */ - csdev->dev.fwnode = fwnode_handle_get(dev_fwnode(desc->dev)); - dev_set_name(&csdev->dev, "%s", desc->name); if (csdev->type == CORESIGHT_DEV_TYPE_SINK || csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) { @@ -1366,6 +1360,14 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) goto err_out; } } + + /* + * Hold the reference to our parent device. This will be + * dropped only in coresight_device_release(). + */ + csdev->dev.fwnode = fwnode_handle_get(dev_fwnode(desc->dev)); + dev_set_name(&csdev->dev, "%s", desc->name); + /* * Make sure the device registration and the connection fixup * are synchronised, so that we don't see uninitialised devices From a6c4da4b95a3cfe4f6031bef2d913331dc186142 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 9 Feb 2026 12:44:35 +0000 Subject: [PATCH 04/25] coresight: Protect unregistration with mutex The device registration is protected by CoreSight mutex to ensure the atomic operations when adding a device onto bus. One the other hand, the locking is absent when unregister a device. Use mutex to ensure atomicity on device unregistration. During unregistration, unbinding the associated CTI device is not included in the locking region, as CTI has its own locking mechanism. Fixes: 8c1d3f79d9ca ("coresight: core: Fix coresight device probe failure issue") Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260209-arm_coresight_refactor_dev_register-v4-3-62d6042f76f7@arm.com --- drivers/hwtracing/coresight/coresight-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index e2c0f971eccf..c228c27e8517 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1432,14 +1432,17 @@ EXPORT_SYMBOL_GPL(coresight_register); void coresight_unregister(struct coresight_device *csdev) { - etm_perf_del_symlink_sink(csdev); /* Remove references of that device in the topology */ if (cti_assoc_ops && cti_assoc_ops->remove) cti_assoc_ops->remove(csdev); + + mutex_lock(&coresight_mutex); + etm_perf_del_symlink_sink(csdev); coresight_remove_conns(csdev); coresight_clear_default_sink(csdev); coresight_release_platform_data(csdev, csdev->dev.parent, csdev->pdata); device_unregister(&csdev->dev); + mutex_unlock(&coresight_mutex); } EXPORT_SYMBOL_GPL(coresight_unregister); From 32c225491ed8dc90c9ba4a8d07f064133d52a179 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 9 Feb 2026 12:44:36 +0000 Subject: [PATCH 05/25] coresight: Refactor output connection sysfs link cleanup To use a central place for releasing connections, move the output connection sysfs link cleanup into coresight_remove_conns(). Also update the comments accordingly. Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260209-arm_coresight_refactor_dev_register-v4-4-62d6042f76f7@arm.com --- drivers/hwtracing/coresight/coresight-core.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index c228c27e8517..2185a8f869ad 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1152,7 +1152,6 @@ static int coresight_clear_filter_source(struct device *dev, void *data) return 0; } -/* coresight_remove_conns - Remove other device's references to this device */ static void coresight_remove_conns(struct coresight_device *csdev) { int i, j; @@ -1162,10 +1161,6 @@ static void coresight_remove_conns(struct coresight_device *csdev) bus_for_each_dev(&coresight_bustype, NULL, csdev, coresight_clear_filter_source); - /* - * Remove the input connection references from the destination device - * for each output connection. - */ for (i = 0; i < csdev->pdata->nr_outconns; i++) { conn = csdev->pdata->out_conns[i]; if (conn->filter_src_fwnode) { @@ -1176,6 +1171,13 @@ static void coresight_remove_conns(struct coresight_device *csdev) if (!conn->dest_dev) continue; + /* Remove sysfs links for the output connection */ + coresight_remove_links(csdev, conn); + + /* + * Remove the input connection references from the destination + * device for each output connection. + */ 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; @@ -1306,9 +1308,6 @@ void coresight_release_platform_data(struct coresight_device *csdev, 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]); /* * Drop the refcount and clear the handle as this device * is going away @@ -1424,7 +1423,6 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) } err_out: - /* Cleanup the connection information */ coresight_release_platform_data(NULL, desc->dev, desc->pdata); return ERR_PTR(ret); } From babb987968d3610f8953f24b26154bf03c169811 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 9 Feb 2026 12:44:37 +0000 Subject: [PATCH 06/25] coresight: Refactor sysfs connection group cleanup Move the sysfs connection group cleanup into coresight_remove_conns(), so that the driver removes connections and related sysfs resources in one go. As side effect, the csdev argument to coresight_release_platform_data() is no longer needed; adjust the code for this. Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260209-arm_coresight_refactor_dev_register-v4-5-62d6042f76f7@arm.com --- drivers/hwtracing/coresight/coresight-core.c | 11 +++++------ drivers/hwtracing/coresight/coresight-platform.c | 2 +- drivers/hwtracing/coresight/coresight-priv.h | 3 +-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 2185a8f869ad..34439ca98d8d 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1200,6 +1200,8 @@ static void coresight_remove_conns(struct coresight_device *csdev) coresight_remove_links(conn->src_dev, conn); conn->dest_dev = NULL; } + + coresight_remove_conns_sysfs_group(csdev); } /** @@ -1300,8 +1302,7 @@ void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset) * coresight_release_platform_data: Release references to the devices connected * to the output port of this device. */ -void coresight_release_platform_data(struct coresight_device *csdev, - struct device *dev, +void coresight_release_platform_data(struct device *dev, struct coresight_platform_data *pdata) { int i; @@ -1319,8 +1320,6 @@ void coresight_release_platform_data(struct coresight_device *csdev, devm_kfree(dev, pdata->out_conns); devm_kfree(dev, pdata->in_conns); devm_kfree(dev, pdata); - if (csdev) - coresight_remove_conns_sysfs_group(csdev); } struct coresight_device *coresight_register(struct coresight_desc *desc) @@ -1423,7 +1422,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) } err_out: - coresight_release_platform_data(NULL, desc->dev, desc->pdata); + coresight_release_platform_data(desc->dev, desc->pdata); return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(coresight_register); @@ -1438,7 +1437,7 @@ void coresight_unregister(struct coresight_device *csdev) etm_perf_del_symlink_sink(csdev); coresight_remove_conns(csdev); coresight_clear_default_sink(csdev); - coresight_release_platform_data(csdev, csdev->dev.parent, csdev->pdata); + coresight_release_platform_data(csdev->dev.parent, csdev->pdata); device_unregister(&csdev->dev); mutex_unlock(&coresight_mutex); } diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index 0db64c5f4995..0ca3bd762454 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -849,7 +849,7 @@ coresight_get_platform_data(struct device *dev) error: if (!IS_ERR_OR_NULL(pdata)) /* Cleanup the connection information */ - coresight_release_platform_data(NULL, dev, pdata); + coresight_release_platform_data(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 fd896ac07942..1ea882dffd70 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -239,8 +239,7 @@ static inline void *coresight_get_uci_data_from_amba(const struct amba_id *table return NULL; } -void coresight_release_platform_data(struct coresight_device *csdev, - struct device *dev, +void coresight_release_platform_data(struct device *dev, struct coresight_platform_data *pdata); struct coresight_device * coresight_find_csdev_by_fwnode(struct fwnode_handle *r_fwnode); From 6b1ffc542850e5dd1c71394f6205582a9c8ad9c8 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 9 Feb 2026 12:44:38 +0000 Subject: [PATCH 07/25] coresight: Move sink validation into etm_perf_add_symlink_sink() Move the sink device type checks into etm_perf_add_symlink_sink(), and return -EOPNOTSUPP for unsupported devices. This simplifies the registration flow to invoke etm_perf_add_symlink_sink() unconditionally. Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260209-arm_coresight_refactor_dev_register-v4-6-62d6042f76f7@arm.com --- drivers/hwtracing/coresight/coresight-core.c | 23 ++++++++----------- .../hwtracing/coresight/coresight-etm-perf.c | 5 +++- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 34439ca98d8d..6ddbc773330e 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1383,21 +1383,16 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) goto out_unlock; } - if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || - csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && - sink_ops(csdev)->alloc_buffer) { - ret = etm_perf_add_symlink_sink(csdev); + ret = etm_perf_add_symlink_sink(csdev); - if (ret) { - device_unregister(&csdev->dev); - /* - * As with the above, all resources are free'd - * explicitly via coresight_device_release() triggered - * from put_device(), which is in turn called from - * function device_unregister(). - */ - goto out_unlock; - } + /* + * As with the above, all resources are free'd explicitly via + * coresight_device_release() triggered from put_device(), which is in + * turn called from function device_unregister(). + */ + if (ret && ret != -EOPNOTSUPP) { + device_unregister(&csdev->dev); + goto out_unlock; } /* Device is now registered */ registered = true; diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 72017dcc3b7f..f85dedf89a3f 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -902,7 +902,10 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev) if (csdev->type != CORESIGHT_DEV_TYPE_SINK && csdev->type != CORESIGHT_DEV_TYPE_LINKSINK) - return -EINVAL; + return -EOPNOTSUPP; + + if (!sink_ops(csdev)->alloc_buffer) + return -EOPNOTSUPP; if (csdev->ea != NULL) return -EINVAL; From 8573756b235ddfa005837a958241caf204696a0a Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 9 Feb 2026 12:44:39 +0000 Subject: [PATCH 08/25] coresight: Do not mix success path with failure handling Separate the failure handling path from the successful case. Use the 'out_unlock' label only for failure handling. Reviewed-by: James Clark Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260209-arm_coresight_refactor_dev_register-v4-7-62d6042f76f7@arm.com --- drivers/hwtracing/coresight/coresight-core.c | 21 ++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 6ddbc773330e..e04545295240 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1398,17 +1398,22 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) registered = true; ret = coresight_create_conns_sysfs_group(csdev); - if (!ret) - ret = coresight_fixup_orphan_conns(csdev); + if (ret) + goto out_unlock; + + ret = coresight_fixup_orphan_conns(csdev); + if (ret) + goto out_unlock; + + mutex_unlock(&coresight_mutex); + + if (cti_assoc_ops && cti_assoc_ops->add) + cti_assoc_ops->add(csdev); + + return csdev; out_unlock: mutex_unlock(&coresight_mutex); - /* Success */ - if (!ret) { - if (cti_assoc_ops && cti_assoc_ops->add) - cti_assoc_ops->add(csdev); - return csdev; - } /* Unregister the device if needed */ if (registered) { From eef33a7cce239783d0422526a4d786289a936f1b Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 9 Feb 2026 12:44:40 +0000 Subject: [PATCH 09/25] coresight: Unify bus unregistration via coresight_unregister() Once a device is successfully registered, set the "registered" flag to true. After that point, all failures jump to the out_unlock label to unwind the flow via coresight_unregister(). Since failure handling is unified, the comment about resource release for the etm_perf_add_symlink_sink() failure is no need, remove it. Signed-off-by: Leo Yan Reviewed-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260209-arm_coresight_refactor_dev_register-v4-8-62d6042f76f7@arm.com --- drivers/hwtracing/coresight/coresight-core.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index e04545295240..46f247f73cf6 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1383,20 +1383,13 @@ struct coresight_device *coresight_register(struct coresight_desc *desc) goto out_unlock; } - ret = etm_perf_add_symlink_sink(csdev); - - /* - * As with the above, all resources are free'd explicitly via - * coresight_device_release() triggered from put_device(), which is in - * turn called from function device_unregister(). - */ - if (ret && ret != -EOPNOTSUPP) { - device_unregister(&csdev->dev); - goto out_unlock; - } /* Device is now registered */ registered = true; + ret = etm_perf_add_symlink_sink(csdev); + if (ret && ret != -EOPNOTSUPP) + goto out_unlock; + ret = coresight_create_conns_sysfs_group(csdev); if (ret) goto out_unlock; From 36ffbbc2b387bc5320e9caa90c0313743b87ba51 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Thu, 19 Feb 2026 22:46:57 +0800 Subject: [PATCH 10/25] coresight: ctcu: fix the spin_bug Acquiring an uninitialized raw_spin_lock is invalid and may trigger unexpected behavior or spin_bug. Fixes: f78d206f3d73 ("Coresight: Add Coresight TMC Control Unit driver") Signed-off-by: Jie Gan Reviewed-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260219-fix-spin-lock-issue-v1-1-557f7d513d7e@oss.qualcomm.com --- drivers/hwtracing/coresight/coresight-ctcu-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwtracing/coresight/coresight-ctcu-core.c b/drivers/hwtracing/coresight/coresight-ctcu-core.c index 6813ae6e929b..9043cad42f01 100644 --- a/drivers/hwtracing/coresight/coresight-ctcu-core.c +++ b/drivers/hwtracing/coresight/coresight-ctcu-core.c @@ -226,6 +226,7 @@ static int ctcu_probe(struct platform_device *pdev) desc.dev = dev; desc.ops = &ctcu_ops; desc.access = CSDEV_ACCESS_IOMEM(base); + raw_spin_lock_init(&drvdata->spin_lock); drvdata->csdev = coresight_register(&desc); if (IS_ERR(drvdata->csdev)) From 87c266bb30dc09979b7b7e8f962598367d626b57 Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Thu, 26 Feb 2026 14:13:53 +0000 Subject: [PATCH 11/25] MAINTAINERS: Change e-mail address for reviewer My e-mail address for linux work is changing to mike.leach@arm.com from 1st Jan 2026. Update MAINTAINERS file accordingly Updated .mailmap file accordingly. Signed-off-by: Mike Leach Signed-off-by: Mike Leach Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260226141354.638962-1-mike.leach@arm.com --- .mailmap | 1 + MAINTAINERS | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.mailmap b/.mailmap index e1cf6bb85d33..c27d1d5b49bd 100644 --- a/.mailmap +++ b/.mailmap @@ -565,6 +565,7 @@ Michel Lespinasse Michel Lespinasse Mickaël Salaün Miguel Ojeda +Mike Leach Mike Rapoport Mike Rapoport Mike Rapoport diff --git a/MAINTAINERS b/MAINTAINERS index 55af015174a5..9c5491001908 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2708,7 +2708,7 @@ N: digicolor ARM/CORESIGHT FRAMEWORK AND DRIVERS M: Suzuki K Poulose -R: Mike Leach +R: Mike Leach R: James Clark L: coresight@lists.linaro.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -20715,7 +20715,7 @@ PERFORMANCE EVENTS TOOLING ARM64 R: John Garry R: Will Deacon R: James Clark -R: Mike Leach +R: Mike Leach R: Leo Yan L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported From 061c39a17136376f368a6082d4948301641f7db1 Mon Sep 17 00:00:00 2001 From: Elsanti Date: Sat, 28 Feb 2026 18:23:44 -0400 Subject: [PATCH 12/25] drivers/hwtracing/coresight: remove unneeded variable in tmc_crashdata_release() The variable 'ret' is initialized to 0, never modified, and returned directly. Remove it and return 0 explicitly. Signed-off-by: Elsanti Reviewed-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260228222344.288639-1-santiagojoseleal27@gmail.com --- drivers/hwtracing/coresight/coresight-tmc-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 58b469ee73b4..c89fe996af23 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -397,7 +397,6 @@ static ssize_t tmc_crashdata_read(struct file *file, char __user *data, static int tmc_crashdata_release(struct inode *inode, struct file *file) { - int ret = 0; unsigned long flags; struct tmc_resrv_buf *rbuf; struct tmc_drvdata *drvdata = container_of(file->private_data, @@ -410,7 +409,7 @@ static int tmc_crashdata_release(struct inode *inode, struct file *file) raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); dev_dbg(&drvdata->csdev->dev, "%s: released\n", __func__); - return ret; + return 0; } static const struct file_operations tmc_crashdata_fops = { From ef7d4aaf686785b8b0f70c9fe373fb5455d3e5b5 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 26 Feb 2026 09:23:49 +0000 Subject: [PATCH 13/25] coresight: cti: Make spinlock usage consistent The spinlock is acquired sometimes with IRQs disabled and sometimes without. This leads to inconsistent semantics: the lock can be either HARDIRQ-safe or HARDIRQ-unsafe, which may trigger lockdep complaints. Make spinlock usage consistent by acquiring it with disabling IRQs. It is possible for sysfs knobs to acquire the spinlock for accessing a CTI device, while at the same time a perf session sends an IPI to enable the same CTI device. In this case, the spinlock must be IRQ-safe, which is why all lock acquisitions are changed to disable IRQs. Use guard() and scoped_guard() for spinlock to tidy up the code. Fixes: 984f37efa385 ("coresight: cti: Write regsiters directly in cti_enable_hw()") Tested-by: James Clark Reviewed-by: Mike Leach Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260226-arm_coresight_cti_refactor_v1-v2-1-b30fada3cfec@arm.com --- .../hwtracing/coresight/coresight-cti-core.c | 74 ++++----- .../hwtracing/coresight/coresight-cti-sysfs.c | 145 +++++++++--------- 2 files changed, 103 insertions(+), 116 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index fddc8f31b91d..e3c98d89c987 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -81,10 +81,9 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata) static int cti_enable_hw(struct cti_drvdata *drvdata) { struct cti_config *config = &drvdata->config; - unsigned long flags; - int rc = 0; + int rc; - raw_spin_lock_irqsave(&drvdata->spinlock, flags); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* no need to do anything if enabled or unpowered*/ if (config->hw_enabled || !config->hw_powered) @@ -93,22 +92,15 @@ static int cti_enable_hw(struct cti_drvdata *drvdata) /* claim the device */ rc = coresight_claim_device(drvdata->csdev); if (rc) - goto cti_err_not_enabled; + return rc; cti_write_all_hw_regs(drvdata); config->hw_enabled = true; - drvdata->config.enable_req_count++; - raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); - return rc; cti_state_unchanged: drvdata->config.enable_req_count++; - - /* cannot enable due to error */ -cti_err_not_enabled: - raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); - return rc; + return 0; } /* re-enable CTI on CPU when using CPU hotplug */ @@ -116,25 +108,21 @@ static void cti_cpuhp_enable_hw(struct cti_drvdata *drvdata) { struct cti_config *config = &drvdata->config; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); + config->hw_powered = true; /* no need to do anything if no enable request */ if (!drvdata->config.enable_req_count) - goto cti_hp_not_enabled; + return; /* try to claim the device */ if (coresight_claim_device(drvdata->csdev)) - goto cti_hp_not_enabled; + return; cti_write_all_hw_regs(drvdata); config->hw_enabled = true; - raw_spin_unlock(&drvdata->spinlock); return; - - /* did not re-enable due to no claim / no request */ -cti_hp_not_enabled: - raw_spin_unlock(&drvdata->spinlock); } /* disable hardware */ @@ -142,23 +130,20 @@ static int cti_disable_hw(struct cti_drvdata *drvdata) { struct cti_config *config = &drvdata->config; struct coresight_device *csdev = drvdata->csdev; - int ret = 0; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* don't allow negative refcounts, return an error */ - if (!drvdata->config.enable_req_count) { - ret = -EINVAL; - goto cti_not_disabled; - } + if (!drvdata->config.enable_req_count) + return -EINVAL; /* check refcount - disable on 0 */ if (--drvdata->config.enable_req_count > 0) - goto cti_not_disabled; + return 0; /* no need to do anything if disabled or cpu unpowered */ if (!config->hw_enabled || !config->hw_powered) - goto cti_not_disabled; + return 0; CS_UNLOCK(drvdata->base); @@ -168,13 +153,7 @@ static int cti_disable_hw(struct cti_drvdata *drvdata) coresight_disclaim_device_unlocked(csdev); CS_LOCK(drvdata->base); - raw_spin_unlock(&drvdata->spinlock); - return ret; - - /* not disabled this call */ -cti_not_disabled: - raw_spin_unlock(&drvdata->spinlock); - return ret; + return 0; } void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value) @@ -189,11 +168,11 @@ void cti_write_intack(struct device *dev, u32 ackval) struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *config = &drvdata->config; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); + /* write if enabled */ if (cti_active(config)) cti_write_single_reg(drvdata, CTIINTACK, ackval); - raw_spin_unlock(&drvdata->spinlock); } /* @@ -360,7 +339,7 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op, reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) : CTIOUTEN(trigger_idx)); - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* read - modify write - the trigger / channel enable value */ reg_value = direction == CTI_TRIG_IN ? config->ctiinen[trigger_idx] : @@ -379,7 +358,7 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op, /* write through if enabled */ if (cti_active(config)) cti_write_single_reg(drvdata, reg_offset, reg_value); - raw_spin_unlock(&drvdata->spinlock); + return 0; } @@ -397,7 +376,8 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op, chan_bitmask = BIT(channel_idx); - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); + reg_value = config->ctigate; switch (op) { case CTI_GATE_CHAN_ENABLE: @@ -417,7 +397,7 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op, if (cti_active(config)) cti_write_single_reg(drvdata, CTIGATE, reg_value); } - raw_spin_unlock(&drvdata->spinlock); + return err; } @@ -436,7 +416,8 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, chan_bitmask = BIT(channel_idx); - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); + reg_value = config->ctiappset; switch (op) { case CTI_CHAN_SET: @@ -464,7 +445,6 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, if ((err == 0) && cti_active(config)) cti_write_single_reg(drvdata, reg_offset, reg_value); - raw_spin_unlock(&drvdata->spinlock); return err; } @@ -667,7 +647,7 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd, if (WARN_ON_ONCE(drvdata->ctidev.cpu != cpu)) return NOTIFY_BAD; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); switch (cmd) { case CPU_PM_ENTER: @@ -707,7 +687,6 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd, } cti_notify_exit: - raw_spin_unlock(&drvdata->spinlock); return notify_res; } @@ -734,11 +713,12 @@ static int cti_dying_cpu(unsigned int cpu) if (!drvdata) return 0; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); + drvdata->config.hw_powered = false; if (drvdata->config.hw_enabled) coresight_disclaim_device(drvdata->csdev); - raw_spin_unlock(&drvdata->spinlock); + return 0; } diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 572b80ee96fb..455d08bcccd4 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -84,11 +84,11 @@ static ssize_t enable_show(struct device *dev, bool enabled, powered; struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); - raw_spin_lock(&drvdata->spinlock); - enable_req = drvdata->config.enable_req_count; - powered = drvdata->config.hw_powered; - enabled = drvdata->config.hw_enabled; - raw_spin_unlock(&drvdata->spinlock); + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { + enable_req = drvdata->config.enable_req_count; + powered = drvdata->config.hw_powered; + enabled = drvdata->config.hw_enabled; + } if (powered) return sprintf(buf, "%d\n", enabled); @@ -134,9 +134,8 @@ static ssize_t powered_show(struct device *dev, bool powered; struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); - raw_spin_lock(&drvdata->spinlock); - powered = drvdata->config.hw_powered; - raw_spin_unlock(&drvdata->spinlock); + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) + powered = drvdata->config.hw_powered; return sprintf(buf, "%d\n", powered); } @@ -181,10 +180,12 @@ static ssize_t coresight_cti_reg_show(struct device *dev, u32 val = 0; pm_runtime_get_sync(dev->parent); - raw_spin_lock(&drvdata->spinlock); - if (drvdata->config.hw_powered) - val = readl_relaxed(drvdata->base + cti_attr->off); - raw_spin_unlock(&drvdata->spinlock); + + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { + if (drvdata->config.hw_powered) + val = readl_relaxed(drvdata->base + cti_attr->off); + } + pm_runtime_put_sync(dev->parent); return sysfs_emit(buf, "0x%x\n", val); } @@ -202,10 +203,12 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev, return -EINVAL; pm_runtime_get_sync(dev->parent); - raw_spin_lock(&drvdata->spinlock); - if (drvdata->config.hw_powered) - cti_write_single_reg(drvdata, cti_attr->off, val); - raw_spin_unlock(&drvdata->spinlock); + + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { + if (drvdata->config.hw_powered) + cti_write_single_reg(drvdata, cti_attr->off, val); + } + pm_runtime_put_sync(dev->parent); return size; } @@ -264,17 +267,18 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf, struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *config = &drvdata->config; - raw_spin_lock(&drvdata->spinlock); - if ((reg_offset >= 0) && cti_active(config)) { - CS_UNLOCK(drvdata->base); - val = readl_relaxed(drvdata->base + reg_offset); - if (pcached_val) - *pcached_val = val; - CS_LOCK(drvdata->base); - } else if (pcached_val) { - val = *pcached_val; + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { + if ((reg_offset >= 0) && cti_active(config)) { + CS_UNLOCK(drvdata->base); + val = readl_relaxed(drvdata->base + reg_offset); + if (pcached_val) + *pcached_val = val; + CS_LOCK(drvdata->base); + } else if (pcached_val) { + val = *pcached_val; + } } - raw_spin_unlock(&drvdata->spinlock); + return sprintf(buf, "%#x\n", val); } @@ -293,15 +297,16 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf, if (kstrtoul(buf, 0, &val)) return -EINVAL; - raw_spin_lock(&drvdata->spinlock); - /* local store */ - if (pcached_val) - *pcached_val = (u32)val; + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { + /* local store */ + if (pcached_val) + *pcached_val = (u32)val; + + /* write through if offset and enabled */ + if ((reg_offset >= 0) && cti_active(config)) + cti_write_single_reg(drvdata, reg_offset, val); + } - /* write through if offset and enabled */ - if ((reg_offset >= 0) && cti_active(config)) - cti_write_single_reg(drvdata, reg_offset, val); - raw_spin_unlock(&drvdata->spinlock); return size; } @@ -349,9 +354,9 @@ static ssize_t inout_sel_store(struct device *dev, if (val > (CTIINOUTEN_MAX - 1)) return -EINVAL; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); + drvdata->config.ctiinout_sel = val; - raw_spin_unlock(&drvdata->spinlock); return size; } static DEVICE_ATTR_RW(inout_sel); @@ -364,10 +369,11 @@ static ssize_t inen_show(struct device *dev, int index; struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); - raw_spin_lock(&drvdata->spinlock); - index = drvdata->config.ctiinout_sel; - val = drvdata->config.ctiinen[index]; - raw_spin_unlock(&drvdata->spinlock); + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { + index = drvdata->config.ctiinout_sel; + val = drvdata->config.ctiinen[index]; + } + return sprintf(buf, "%#lx\n", val); } @@ -383,14 +389,15 @@ static ssize_t inen_store(struct device *dev, if (kstrtoul(buf, 0, &val)) return -EINVAL; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); + index = config->ctiinout_sel; config->ctiinen[index] = val; /* write through if enabled */ if (cti_active(config)) cti_write_single_reg(drvdata, CTIINEN(index), val); - raw_spin_unlock(&drvdata->spinlock); + return size; } static DEVICE_ATTR_RW(inen); @@ -403,10 +410,11 @@ static ssize_t outen_show(struct device *dev, int index; struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); - raw_spin_lock(&drvdata->spinlock); - index = drvdata->config.ctiinout_sel; - val = drvdata->config.ctiouten[index]; - raw_spin_unlock(&drvdata->spinlock); + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { + index = drvdata->config.ctiinout_sel; + val = drvdata->config.ctiouten[index]; + } + return sprintf(buf, "%#lx\n", val); } @@ -422,14 +430,15 @@ static ssize_t outen_store(struct device *dev, if (kstrtoul(buf, 0, &val)) return -EINVAL; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); + index = config->ctiinout_sel; config->ctiouten[index] = val; /* write through if enabled */ if (cti_active(config)) cti_write_single_reg(drvdata, CTIOUTEN(index), val); - raw_spin_unlock(&drvdata->spinlock); + return size; } static DEVICE_ATTR_RW(outen); @@ -463,7 +472,7 @@ static ssize_t appclear_store(struct device *dev, if (kstrtoul(buf, 0, &val)) return -EINVAL; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* a 1'b1 in appclr clears down the same bit in appset*/ config->ctiappset &= ~val; @@ -471,7 +480,7 @@ static ssize_t appclear_store(struct device *dev, /* write through if enabled */ if (cti_active(config)) cti_write_single_reg(drvdata, CTIAPPCLEAR, val); - raw_spin_unlock(&drvdata->spinlock); + return size; } static DEVICE_ATTR_WO(appclear); @@ -487,12 +496,12 @@ static ssize_t apppulse_store(struct device *dev, if (kstrtoul(buf, 0, &val)) return -EINVAL; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* write through if enabled */ if (cti_active(config)) cti_write_single_reg(drvdata, CTIAPPPULSE, val); - raw_spin_unlock(&drvdata->spinlock); + return size; } static DEVICE_ATTR_WO(apppulse); @@ -681,9 +690,9 @@ static ssize_t trig_filter_enable_show(struct device *dev, u32 val; struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); - raw_spin_lock(&drvdata->spinlock); - val = drvdata->config.trig_filter_enable; - raw_spin_unlock(&drvdata->spinlock); + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) + val = drvdata->config.trig_filter_enable; + return sprintf(buf, "%d\n", val); } @@ -697,9 +706,9 @@ static ssize_t trig_filter_enable_store(struct device *dev, if (kstrtoul(buf, 0, &val)) return -EINVAL; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); + drvdata->config.trig_filter_enable = !!val; - raw_spin_unlock(&drvdata->spinlock); return size; } static DEVICE_ATTR_RW(trig_filter_enable); @@ -728,7 +737,7 @@ static ssize_t chan_xtrigs_reset_store(struct device *dev, struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *config = &drvdata->config; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* clear the CTI trigger / channel programming registers */ for (i = 0; i < config->nr_trig_max; i++) { @@ -747,7 +756,6 @@ static ssize_t chan_xtrigs_reset_store(struct device *dev, if (cti_active(config)) cti_write_all_hw_regs(drvdata); - raw_spin_unlock(&drvdata->spinlock); return size; } static DEVICE_ATTR_WO(chan_xtrigs_reset); @@ -768,9 +776,9 @@ static ssize_t chan_xtrigs_sel_store(struct device *dev, if (val > (drvdata->config.nr_ctm_channels - 1)) return -EINVAL; - raw_spin_lock(&drvdata->spinlock); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); + drvdata->config.xtrig_rchan_sel = val; - raw_spin_unlock(&drvdata->spinlock); return size; } @@ -781,9 +789,8 @@ static ssize_t chan_xtrigs_sel_show(struct device *dev, unsigned long val; struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); - raw_spin_lock(&drvdata->spinlock); - val = drvdata->config.xtrig_rchan_sel; - raw_spin_unlock(&drvdata->spinlock); + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) + val = drvdata->config.xtrig_rchan_sel; return sprintf(buf, "%ld\n", val); } @@ -838,12 +845,12 @@ static ssize_t print_chan_list(struct device *dev, unsigned long inuse_bits = 0, chan_mask; /* scan regs to get bitmap of channels in use. */ - raw_spin_lock(&drvdata->spinlock); - for (i = 0; i < config->nr_trig_max; i++) { - inuse_bits |= config->ctiinen[i]; - inuse_bits |= config->ctiouten[i]; + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { + for (i = 0; i < config->nr_trig_max; i++) { + inuse_bits |= config->ctiinen[i]; + inuse_bits |= config->ctiouten[i]; + } } - raw_spin_unlock(&drvdata->spinlock); /* inverse bits if printing free channels */ if (!inuse) From 6582fe69ac4b1b575e023f5110427c15fbf5ad36 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 26 Feb 2026 09:23:50 +0000 Subject: [PATCH 14/25] coresight: cti: Fix register reads Introduce cti_read_single_reg() as an interface for reading registers with unlocking the CS lock. Consolidate register read in sysfs interfaces using this new helper. Fixes: b5213376c240 ("coresight: cti: Add sysfs access to program function registers") Fixes: 1a556ca6cc24 ("coresight: cti: Add sysfs coresight mgmt register access") Reviewed-by: Mike Leach Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260226-arm_coresight_cti_refactor_v1-v2-2-b30fada3cfec@arm.com --- drivers/hwtracing/coresight/coresight-cti-core.c | 11 +++++++++++ drivers/hwtracing/coresight/coresight-cti-sysfs.c | 6 ++---- drivers/hwtracing/coresight/coresight-cti.h | 1 + 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index e3c98d89c987..6a53c3ceebf4 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -156,6 +156,17 @@ static int cti_disable_hw(struct cti_drvdata *drvdata) return 0; } +u32 cti_read_single_reg(struct cti_drvdata *drvdata, int offset) +{ + int val; + + CS_UNLOCK(drvdata->base); + val = readl_relaxed(drvdata->base + offset); + CS_LOCK(drvdata->base); + + return val; +} + void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value) { CS_UNLOCK(drvdata->base); diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 455d08bcccd4..9a997b2f0904 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -183,7 +183,7 @@ static ssize_t coresight_cti_reg_show(struct device *dev, scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { if (drvdata->config.hw_powered) - val = readl_relaxed(drvdata->base + cti_attr->off); + val = cti_read_single_reg(drvdata, cti_attr->off); } pm_runtime_put_sync(dev->parent); @@ -269,11 +269,9 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf, scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { if ((reg_offset >= 0) && cti_active(config)) { - CS_UNLOCK(drvdata->base); - val = readl_relaxed(drvdata->base + reg_offset); + val = cti_read_single_reg(drvdata, reg_offset); if (pcached_val) *pcached_val = val; - CS_LOCK(drvdata->base); } else if (pcached_val) { val = *pcached_val; } diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index daff9e32a6da..45735526fe55 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -220,6 +220,7 @@ int cti_disable(struct coresight_device *csdev, struct coresight_path *path); 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); +u32 cti_read_single_reg(struct cti_drvdata *drvdata, int offset); int cti_channel_trig_op(struct device *dev, enum cti_chan_op op, enum cti_trig_dir direction, u32 channel_idx, u32 trigger_idx); From b4d9ef475ec71e13e1ec395e9b9e6b165506a564 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 26 Feb 2026 09:23:51 +0000 Subject: [PATCH 15/25] coresight: cti: Access ASICCTL only when implemented According to the Arm ARM (DDI 0487 L.b), ASICCTL is implemented only when CTIDEVID.EXTMUXNUM is non-zero. Based on CTIDEVID.EXTMUXNUM, add a flag 'asicctl_impl' to indicate whether the register is implemented, and access ASICCTL conditionally based on the flag. Allow the sysfs node to be visible only when the register is implemented. Reviewed-by: Mike Leach Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260226-arm_coresight_cti_refactor_v1-v2-3-b30fada3cfec@arm.com --- drivers/hwtracing/coresight/coresight-cti-core.c | 5 ++++- drivers/hwtracing/coresight/coresight-cti-sysfs.c | 13 +++++++++++++ drivers/hwtracing/coresight/coresight-cti.h | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index 6a53c3ceebf4..726970d852de 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -68,7 +68,8 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata) /* other regs */ writel_relaxed(config->ctigate, drvdata->base + CTIGATE); - writel_relaxed(config->asicctl, drvdata->base + ASICCTL); + if (config->asicctl_impl) + writel_relaxed(config->asicctl, drvdata->base + ASICCTL); writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET); /* re-enable CTI */ @@ -221,6 +222,8 @@ static void cti_set_default_config(struct device *dev, config->trig_filter_enable = true; config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0); config->enable_req_count = 0; + + config->asicctl_impl = !!FIELD_GET(GENMASK(4, 0), devid); } /* diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 9a997b2f0904..c15a580f6e90 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -537,6 +537,18 @@ static struct attribute *coresight_cti_regs_attrs[] = { NULL, }; +static umode_t coresight_cti_regs_is_visible(struct kobject *kobj, + struct attribute *attr, int idx) +{ + struct device *dev = kobj_to_dev(kobj); + struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (attr == &dev_attr_asicctl.attr && !drvdata->config.asicctl_impl) + return 0; + + return attr->mode; +} + /* CTI channel x-trigger programming */ static int cti_trig_op_parse(struct device *dev, enum cti_chan_op op, @@ -1174,6 +1186,7 @@ static const struct attribute_group coresight_cti_mgmt_group = { static const struct attribute_group coresight_cti_regs_group = { .attrs = coresight_cti_regs_attrs, + .is_visible = coresight_cti_regs_is_visible, .name = "regs", }; diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 45735526fe55..a4b3968d8d3d 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -119,6 +119,7 @@ struct cti_device { * @nr_trig_max: Max number of trigger signals implemented on device. * (max of trig_in or trig_out) - from ID register. * @nr_ctm_channels: number of available CTM channels - from ID register. + * @asicctl_impl: true if asicctl is implemented. * @enable_req_count: CTI is enabled alongside >=1 associated devices. * @hw_enabled: true if hw is currently enabled. * @hw_powered: true if associated cpu powered on, or no cpu. @@ -140,6 +141,7 @@ struct cti_config { /* hardware description */ int nr_ctm_channels; int nr_trig_max; + bool asicctl_impl; /* cti enable control */ int enable_req_count; From 59213b4be5c109414f8240f6389b3fc3a7f48b4d Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 26 Feb 2026 09:23:52 +0000 Subject: [PATCH 16/25] coresight: cti: Remove CPU power management code According Arm ARM, the CTI ASICCTL register: "It is IMPLEMENTATION DEFINED whether ASICCTL is implemented in the Core power domain or in the Debug power domain." This is the only CTI register that may reside in the core power domain. However, it has been confirmed that Arm designed CTIs place ASICCTL in the debug power domain. Furthermore, ASICCTL is implemented only when CTIDEVID.EXTMUXNUM is non-zero, which is a rare case for CPU CTIs. For these reasons, it is safe to conclude that all CTI registers are not located in the CPU power domain. Therefore, the CTI driver does not need CPU power management. This commit removes the CPU power management from CTI driver. Reviewed-by: Mike Leach Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260226-arm_coresight_cti_refactor_v1-v2-4-b30fada3cfec@arm.com --- .../hwtracing/coresight/coresight-cti-core.c | 186 +----------------- 1 file changed, 3 insertions(+), 183 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index 726970d852de..3aa081f28a18 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -42,12 +42,6 @@ static DEFINE_MUTEX(ect_mutex); #define csdev_to_cti_drvdata(csdev) \ dev_get_drvdata(csdev->dev.parent) -/* power management handling */ -static int nr_cti_cpu; - -/* quick lookup list for CPU bound CTIs when power handling */ -static struct cti_drvdata *cti_cpu_drvdata[NR_CPUS]; - /* write set of regs to hardware - call with spinlock claimed */ void cti_write_all_hw_regs(struct cti_drvdata *drvdata) { @@ -104,28 +98,6 @@ static int cti_enable_hw(struct cti_drvdata *drvdata) return 0; } -/* re-enable CTI on CPU when using CPU hotplug */ -static void cti_cpuhp_enable_hw(struct cti_drvdata *drvdata) -{ - struct cti_config *config = &drvdata->config; - - guard(raw_spinlock_irqsave)(&drvdata->spinlock); - - config->hw_powered = true; - - /* no need to do anything if no enable request */ - if (!drvdata->config.enable_req_count) - return; - - /* try to claim the device */ - if (coresight_claim_device(drvdata->csdev)) - return; - - cti_write_all_hw_regs(drvdata); - config->hw_enabled = true; - return; -} - /* disable hardware */ static int cti_disable_hw(struct cti_drvdata *drvdata) { @@ -643,146 +615,6 @@ static void cti_remove_conn_xrefs(struct cti_drvdata *drvdata) } } -/** cti PM callbacks **/ -static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd, - void *v) -{ - struct cti_drvdata *drvdata; - struct coresight_device *csdev; - unsigned int cpu = smp_processor_id(); - int notify_res = NOTIFY_OK; - - if (!cti_cpu_drvdata[cpu]) - return NOTIFY_OK; - - drvdata = cti_cpu_drvdata[cpu]; - csdev = drvdata->csdev; - - if (WARN_ON_ONCE(drvdata->ctidev.cpu != cpu)) - return NOTIFY_BAD; - - guard(raw_spinlock_irqsave)(&drvdata->spinlock); - - switch (cmd) { - case CPU_PM_ENTER: - /* CTI regs all static - we have a copy & nothing to save */ - drvdata->config.hw_powered = false; - if (drvdata->config.hw_enabled) - coresight_disclaim_device(csdev); - break; - - case CPU_PM_ENTER_FAILED: - drvdata->config.hw_powered = true; - if (drvdata->config.hw_enabled) { - if (coresight_claim_device(csdev)) - drvdata->config.hw_enabled = false; - } - break; - - case CPU_PM_EXIT: - /* write hardware registers to re-enable. */ - drvdata->config.hw_powered = true; - drvdata->config.hw_enabled = false; - - /* check enable reference count to enable HW */ - if (drvdata->config.enable_req_count) { - /* check we can claim the device as we re-power */ - if (coresight_claim_device(csdev)) - goto cti_notify_exit; - - drvdata->config.hw_enabled = true; - cti_write_all_hw_regs(drvdata); - } - break; - - default: - notify_res = NOTIFY_DONE; - break; - } - -cti_notify_exit: - return notify_res; -} - -static struct notifier_block cti_cpu_pm_nb = { - .notifier_call = cti_cpu_pm_notify, -}; - -/* CPU HP handlers */ -static int cti_starting_cpu(unsigned int cpu) -{ - struct cti_drvdata *drvdata = cti_cpu_drvdata[cpu]; - - if (!drvdata) - return 0; - - cti_cpuhp_enable_hw(drvdata); - return 0; -} - -static int cti_dying_cpu(unsigned int cpu) -{ - struct cti_drvdata *drvdata = cti_cpu_drvdata[cpu]; - - if (!drvdata) - return 0; - - guard(raw_spinlock_irqsave)(&drvdata->spinlock); - - drvdata->config.hw_powered = false; - if (drvdata->config.hw_enabled) - coresight_disclaim_device(drvdata->csdev); - - return 0; -} - -static int cti_pm_setup(struct cti_drvdata *drvdata) -{ - int ret; - - if (drvdata->ctidev.cpu == -1) - return 0; - - if (nr_cti_cpu) - goto done; - - cpus_read_lock(); - ret = cpuhp_setup_state_nocalls_cpuslocked( - CPUHP_AP_ARM_CORESIGHT_CTI_STARTING, - "arm/coresight_cti:starting", - cti_starting_cpu, cti_dying_cpu); - if (ret) { - cpus_read_unlock(); - return ret; - } - - ret = cpu_pm_register_notifier(&cti_cpu_pm_nb); - cpus_read_unlock(); - if (ret) { - cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_CTI_STARTING); - return ret; - } - -done: - nr_cti_cpu++; - cti_cpu_drvdata[drvdata->ctidev.cpu] = drvdata; - - return 0; -} - -/* release PM registrations */ -static void cti_pm_release(struct cti_drvdata *drvdata) -{ - if (drvdata->ctidev.cpu == -1) - return; - - cti_cpu_drvdata[drvdata->ctidev.cpu] = NULL; - if (--nr_cti_cpu == 0) { - cpu_pm_unregister_notifier(&cti_cpu_pm_nb); - cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_CTI_STARTING); - } -} - /** cti ect operations **/ int cti_enable(struct coresight_device *csdev, enum cs_mode mode, struct coresight_path *path) @@ -815,7 +647,6 @@ static void cti_remove(struct amba_device *adev) mutex_lock(&ect_mutex); cti_remove_conn_xrefs(drvdata); - cti_pm_release(drvdata); /* remove from the list */ list_for_each_entry_safe(ect_item, ect_tmp, &ect_net, node) { @@ -889,17 +720,12 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) if (!cti_desc.name) return -ENOMEM; - /* setup CPU power management handling for CPU bound CTI devices. */ - ret = cti_pm_setup(drvdata); - if (ret) - return ret; - /* create dynamic attributes for connections */ ret = cti_create_cons_sysfs(dev, drvdata); if (ret) { dev_err(dev, "%s: create dynamic sysfs entries failed\n", cti_desc.name); - goto pm_release; + return ret; } /* set up coresight component description */ @@ -912,10 +738,8 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) coresight_clear_self_claim_tag(&cti_desc.access); drvdata->csdev = coresight_register(&cti_desc); - if (IS_ERR(drvdata->csdev)) { - ret = PTR_ERR(drvdata->csdev); - goto pm_release; - } + if (IS_ERR(drvdata->csdev)) + return PTR_ERR(drvdata->csdev); /* add to list of CTI devices */ mutex_lock(&ect_mutex); @@ -928,10 +752,6 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) pm_runtime_put(&adev->dev); dev_info(&drvdata->csdev->dev, "CTI initialized\n"); return 0; - -pm_release: - cti_pm_release(drvdata); - return ret; } static struct amba_cs_uci_id uci_id_cti[] = { From b727e7bba3ff2b4da3e71628c85f2c2dd9ef471a Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 26 Feb 2026 09:23:53 +0000 Subject: [PATCH 17/25] coresight: cti: Rename cti_active() to cti_is_active() Rename cti_active() to cti_is_active() to clarify that it checks whether the CTI device is active. Reviewed-by: Mike Leach Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260226-arm_coresight_cti_refactor_v1-v2-5-b30fada3cfec@arm.com --- drivers/hwtracing/coresight/coresight-cti-core.c | 8 ++++---- drivers/hwtracing/coresight/coresight-cti-sysfs.c | 14 +++++++------- drivers/hwtracing/coresight/coresight-cti.h | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index 3aa081f28a18..28f995263433 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -155,7 +155,7 @@ void cti_write_intack(struct device *dev, u32 ackval) guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* write if enabled */ - if (cti_active(config)) + if (cti_is_active(config)) cti_write_single_reg(drvdata, CTIINTACK, ackval); } @@ -342,7 +342,7 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op, config->ctiouten[trigger_idx] = reg_value; /* write through if enabled */ - if (cti_active(config)) + if (cti_is_active(config)) cti_write_single_reg(drvdata, reg_offset, reg_value); return 0; @@ -380,7 +380,7 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op, } if (err == 0) { config->ctigate = reg_value; - if (cti_active(config)) + if (cti_is_active(config)) cti_write_single_reg(drvdata, CTIGATE, reg_value); } @@ -429,7 +429,7 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op, break; } - if ((err == 0) && cti_active(config)) + if ((err == 0) && cti_is_active(config)) cti_write_single_reg(drvdata, reg_offset, reg_value); return err; diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index c15a580f6e90..a22cc9a2bee2 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -268,7 +268,7 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf, struct cti_config *config = &drvdata->config; scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { - if ((reg_offset >= 0) && cti_active(config)) { + if ((reg_offset >= 0) && cti_is_active(config)) { val = cti_read_single_reg(drvdata, reg_offset); if (pcached_val) *pcached_val = val; @@ -301,7 +301,7 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf, *pcached_val = (u32)val; /* write through if offset and enabled */ - if ((reg_offset >= 0) && cti_active(config)) + if ((reg_offset >= 0) && cti_is_active(config)) cti_write_single_reg(drvdata, reg_offset, val); } @@ -393,7 +393,7 @@ static ssize_t inen_store(struct device *dev, config->ctiinen[index] = val; /* write through if enabled */ - if (cti_active(config)) + if (cti_is_active(config)) cti_write_single_reg(drvdata, CTIINEN(index), val); return size; @@ -434,7 +434,7 @@ static ssize_t outen_store(struct device *dev, config->ctiouten[index] = val; /* write through if enabled */ - if (cti_active(config)) + if (cti_is_active(config)) cti_write_single_reg(drvdata, CTIOUTEN(index), val); return size; @@ -476,7 +476,7 @@ static ssize_t appclear_store(struct device *dev, config->ctiappset &= ~val; /* write through if enabled */ - if (cti_active(config)) + if (cti_is_active(config)) cti_write_single_reg(drvdata, CTIAPPCLEAR, val); return size; @@ -497,7 +497,7 @@ static ssize_t apppulse_store(struct device *dev, guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* write through if enabled */ - if (cti_active(config)) + if (cti_is_active(config)) cti_write_single_reg(drvdata, CTIAPPPULSE, val); return size; @@ -763,7 +763,7 @@ static ssize_t chan_xtrigs_reset_store(struct device *dev, config->xtrig_rchan_sel = 0; /* if enabled then write through */ - if (cti_active(config)) + if (cti_is_active(config)) cti_write_all_hw_regs(drvdata); return size; diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index a4b3968d8d3d..2edc0d01812c 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -236,7 +236,7 @@ coresight_cti_get_platform_data(struct device *dev); const char *cti_plat_get_node_name(struct fwnode_handle *fwnode); /* cti powered and enabled */ -static inline bool cti_active(struct cti_config *cfg) +static inline bool cti_is_active(struct cti_config *cfg) { return cfg->hw_powered && cfg->hw_enabled; } From daedb30fd6ac68a100912407aba3a4fdba8a4080 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 26 Feb 2026 09:23:54 +0000 Subject: [PATCH 18/25] coresight: cti: Remove hw_powered flag Since the CPU PM code has been removed from the CTI driver and the device is enabled via runtime PM, pm_runtime_active() can be used to check whether the device is powered. As a result, the hw_powered flag is redundant, remove it. Reviewed-by: Mike Leach Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260226-arm_coresight_cti_refactor_v1-v2-6-b30fada3cfec@arm.com --- .../hwtracing/coresight/coresight-cti-core.c | 11 +++---- .../hwtracing/coresight/coresight-cti-sysfs.c | 29 +++++-------------- drivers/hwtracing/coresight/coresight-cti.h | 6 ++-- 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index 28f995263433..5ac36f077618 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -80,8 +80,8 @@ static int cti_enable_hw(struct cti_drvdata *drvdata) guard(raw_spinlock_irqsave)(&drvdata->spinlock); - /* no need to do anything if enabled or unpowered*/ - if (config->hw_enabled || !config->hw_powered) + /* no need to do anything if enabled */ + if (config->hw_enabled) goto cti_state_unchanged; /* claim the device */ @@ -114,8 +114,8 @@ static int cti_disable_hw(struct cti_drvdata *drvdata) if (--drvdata->config.enable_req_count > 0) return 0; - /* no need to do anything if disabled or cpu unpowered */ - if (!config->hw_enabled || !config->hw_powered) + /* no need to do anything if disabled */ + if (!config->hw_enabled) return 0; CS_UNLOCK(drvdata->base); @@ -702,9 +702,6 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) return PTR_ERR(pdata); } - /* default to powered - could change on PM notifications */ - drvdata->config.hw_powered = true; - /* * Set up device name - will depend if cpu bound or otherwise. * diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index a22cc9a2bee2..9ab586a5c9a4 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -81,19 +81,12 @@ static ssize_t enable_show(struct device *dev, char *buf) { int enable_req; - bool enabled, powered; struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); - scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) enable_req = drvdata->config.enable_req_count; - powered = drvdata->config.hw_powered; - enabled = drvdata->config.hw_enabled; - } - if (powered) - return sprintf(buf, "%d\n", enabled); - else - return sprintf(buf, "%d\n", !!enable_req); + return sprintf(buf, "%d\n", !!enable_req); } static ssize_t enable_store(struct device *dev, @@ -131,11 +124,7 @@ static ssize_t powered_show(struct device *dev, struct device_attribute *attr, char *buf) { - bool powered; - struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); - - scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) - powered = drvdata->config.hw_powered; + bool powered = pm_runtime_active(dev->parent); return sprintf(buf, "%d\n", powered); } @@ -181,10 +170,8 @@ static ssize_t coresight_cti_reg_show(struct device *dev, pm_runtime_get_sync(dev->parent); - scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { - if (drvdata->config.hw_powered) - val = cti_read_single_reg(drvdata, cti_attr->off); - } + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) + val = cti_read_single_reg(drvdata, cti_attr->off); pm_runtime_put_sync(dev->parent); return sysfs_emit(buf, "0x%x\n", val); @@ -204,10 +191,8 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev, pm_runtime_get_sync(dev->parent); - scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { - if (drvdata->config.hw_powered) - cti_write_single_reg(drvdata, cti_attr->off, val); - } + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) + cti_write_single_reg(drvdata, cti_attr->off, val); pm_runtime_put_sync(dev->parent); return size; diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 2edc0d01812c..8754cb5def79 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -122,7 +122,6 @@ struct cti_device { * @asicctl_impl: true if asicctl is implemented. * @enable_req_count: CTI is enabled alongside >=1 associated devices. * @hw_enabled: true if hw is currently enabled. - * @hw_powered: true if associated cpu powered on, or no cpu. * @trig_in_use: bitfield of in triggers registered as in use. * @trig_out_use: bitfield of out triggers registered as in use. * @trig_out_filter: bitfield of out triggers that are blocked if filter @@ -146,7 +145,6 @@ struct cti_config { /* cti enable control */ int enable_req_count; bool hw_enabled; - bool hw_powered; /* registered triggers and filtering */ u32 trig_in_use; @@ -235,10 +233,10 @@ struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); const char *cti_plat_get_node_name(struct fwnode_handle *fwnode); -/* cti powered and enabled */ +/* Check if a cti device is enabled */ static inline bool cti_is_active(struct cti_config *cfg) { - return cfg->hw_powered && cfg->hw_enabled; + return cfg->hw_enabled; } #endif /* _CORESIGHT_CORESIGHT_CTI_H */ From d5e57babdffb961ca8b51910d00c2c0ddb03c54a Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 26 Feb 2026 09:23:55 +0000 Subject: [PATCH 19/25] coresight: cti: Remove hw_enabled flag The enable_req_count field already tracks whether the CTI device is enabled. A non-zero value indicates that the device is active, the hw_enabled flag is redundant if so. Remove hw_enabled and update cti_is_active() to check enable_req_count. Replace open-coded enable_req_count checks with cti_is_active(). Reviewed-by: Mike Leach Signed-off-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260226-arm_coresight_cti_refactor_v1-v2-7-b30fada3cfec@arm.com --- drivers/hwtracing/coresight/coresight-cti-core.c | 11 ++--------- drivers/hwtracing/coresight/coresight-cti-sysfs.c | 2 +- drivers/hwtracing/coresight/coresight-cti.h | 4 +--- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index 5ac36f077618..2f4c9362709a 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -81,7 +81,7 @@ static int cti_enable_hw(struct cti_drvdata *drvdata) guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* no need to do anything if enabled */ - if (config->hw_enabled) + if (cti_is_active(config)) goto cti_state_unchanged; /* claim the device */ @@ -91,8 +91,6 @@ static int cti_enable_hw(struct cti_drvdata *drvdata) cti_write_all_hw_regs(drvdata); - config->hw_enabled = true; - cti_state_unchanged: drvdata->config.enable_req_count++; return 0; @@ -107,22 +105,17 @@ static int cti_disable_hw(struct cti_drvdata *drvdata) guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* don't allow negative refcounts, return an error */ - if (!drvdata->config.enable_req_count) + if (!cti_is_active(config)) return -EINVAL; /* check refcount - disable on 0 */ if (--drvdata->config.enable_req_count > 0) return 0; - /* no need to do anything if disabled */ - if (!config->hw_enabled) - return 0; - CS_UNLOCK(drvdata->base); /* disable CTI */ writel_relaxed(0, drvdata->base + CTICONTROL); - config->hw_enabled = false; coresight_disclaim_device_unlocked(csdev); CS_LOCK(drvdata->base); diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 9ab586a5c9a4..9ef44956ebdc 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -84,7 +84,7 @@ static ssize_t enable_show(struct device *dev, struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) - enable_req = drvdata->config.enable_req_count; + enable_req = cti_is_active(&drvdata->config); return sprintf(buf, "%d\n", !!enable_req); } diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 8754cb5def79..c5f9e79fabc6 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -121,7 +121,6 @@ struct cti_device { * @nr_ctm_channels: number of available CTM channels - from ID register. * @asicctl_impl: true if asicctl is implemented. * @enable_req_count: CTI is enabled alongside >=1 associated devices. - * @hw_enabled: true if hw is currently enabled. * @trig_in_use: bitfield of in triggers registered as in use. * @trig_out_use: bitfield of out triggers registered as in use. * @trig_out_filter: bitfield of out triggers that are blocked if filter @@ -144,7 +143,6 @@ struct cti_config { /* cti enable control */ int enable_req_count; - bool hw_enabled; /* registered triggers and filtering */ u32 trig_in_use; @@ -236,7 +234,7 @@ const char *cti_plat_get_node_name(struct fwnode_handle *fwnode); /* Check if a cti device is enabled */ static inline bool cti_is_active(struct cti_config *cfg) { - return cfg->hw_enabled; + return !!cfg->enable_req_count; } #endif /* _CORESIGHT_CORESIGHT_CTI_H */ From 9c5ef7a30d9044f8706bd02bfdc4eff7266f3e25 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 26 Feb 2026 09:23:56 +0000 Subject: [PATCH 20/25] coresight: cti: Properly handle negative offsets in cti_reg32_{show|store}() Return an error when the offset is negative. Signed-off-by: Leo Yan Reviewed-by: Mike Leach Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260226-arm_coresight_cti_refactor_v1-v2-8-b30fada3cfec@arm.com --- drivers/hwtracing/coresight/coresight-cti-sysfs.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 9ef44956ebdc..4c0a60840efb 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -252,8 +252,11 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf, struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *config = &drvdata->config; + if (reg_offset < 0) + return -EINVAL; + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { - if ((reg_offset >= 0) && cti_is_active(config)) { + if (cti_is_active(config)) { val = cti_read_single_reg(drvdata, reg_offset); if (pcached_val) *pcached_val = val; @@ -280,13 +283,16 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf, if (kstrtoul(buf, 0, &val)) return -EINVAL; + if (reg_offset < 0) + return -EINVAL; + scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) { /* local store */ if (pcached_val) *pcached_val = (u32)val; /* write through if offset and enabled */ - if ((reg_offset >= 0) && cti_is_active(config)) + if (cti_is_active(config)) cti_write_single_reg(drvdata, reg_offset, val); } From a90863095f84f6d17c49716e4e2212d28a6b25b5 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Fri, 13 Mar 2026 10:21:33 +0000 Subject: [PATCH 21/25] MAINTAINERS: coresight: Add Leo Yan as Reviewer Leo has been an active contributor and reviewer for CoreSight subsystem for years. Add him as a Reviewer for CORESIGHT. Cc: Leo Yan Acked-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260313102133.2298330-1-suzuki.poulose@arm.com --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9c5491001908..eaf928246aaf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2710,6 +2710,7 @@ ARM/CORESIGHT FRAMEWORK AND DRIVERS M: Suzuki K Poulose R: Mike Leach R: James Clark +R: Leo Yan L: coresight@lists.linaro.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained From 08643a8760e81fe0bf91c58f7ee9e19b4db3a24f Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Fri, 27 Mar 2026 14:24:14 +0800 Subject: [PATCH 22/25] coresight: cti: fix the check condition in inout_sel_store Correct the upper bound from CTIINOUTEN_MAX to config->nr_trig_max, since nr_trig_max varies across CTI devices. An out-of-bounds issue occurs when a value greater than config->nr_trig_max is provided, leading to unexpected errors. Fixes: b5213376c240 ("coresight: cti: Add sysfs access to program function registers") Signed-off-by: Jie Gan Reviewed-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260327-fix-cti-issue-v1-1-2c8921e21fc8@oss.qualcomm.com --- drivers/hwtracing/coresight/coresight-cti-sysfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 4c0a60840efb..bf3c73607c1c 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -337,10 +337,11 @@ static ssize_t inout_sel_store(struct device *dev, { unsigned long val; struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct cti_config *config = &drvdata->config; if (kstrtoul(buf, 0, &val)) return -EINVAL; - if (val > (CTIINOUTEN_MAX - 1)) + if (val >= config->nr_trig_max) return -EINVAL; guard(raw_spinlock_irqsave)(&drvdata->spinlock); From ada4280812a7a40455a842b1de24f8450e04254e Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Fri, 20 Mar 2026 15:31:12 +0800 Subject: [PATCH 23/25] coresight: platform: check the availability of the endpoint before parse Check endpoint availability before parsing it. If parsing a connected endpoint fails, the probe is deferred until the endpoint becomes available, or eventually fails. In some legacy cases, a replicator has two output ports where one is disabled and the other is available. The replicator probe always fails because the disabled endpoint never becomes available for parsing. In addition, there is no need to defer probing a device that is connected to a disabled device, which improves probe performance. Signed-off-by: Jie Gan Reviewed-by: Leo Yan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260320-add-availability-check-v1-1-b2e39cdeb6e0@oss.qualcomm.com --- drivers/hwtracing/coresight/coresight-platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index 0ca3bd762454..e337b6e2bf32 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -220,6 +220,8 @@ static int of_coresight_parse_endpoint(struct device *dev, rparent = of_coresight_get_port_parent(rep); if (!rparent) break; + if (!of_device_is_available(rparent)) + break; if (of_graph_parse_endpoint(rep, &rendpoint)) break; From ec687ba84000d7d50cf243558041f6729d1d8119 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Tue, 31 Mar 2026 18:05:22 +0800 Subject: [PATCH 24/25] coresight: tpdm: add traceid_show for checking traceid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Save the trace ID in drvdata during TPDM enablement and expose it to userspace to support trace data parsing. The TPDM device’s trace ID corresponds to the trace ID allocated to the connected TPDA device. Signed-off-by: Jie Gan Reviewed-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260331-add-traceid-show-for-tpdm-v4-1-ed3dda24a562@oss.qualcomm.com --- .../testing/sysfs-bus-coresight-devices-tpdm | 10 ++++++ drivers/hwtracing/coresight/coresight-tpdm.c | 34 ++++++++++++++++++- drivers/hwtracing/coresight/coresight-tpdm.h | 2 ++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm index f8016df64532..bc36ba32c900 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm @@ -278,3 +278,13 @@ Date: Aug 2025 KernelVersion 6.18 Contact: Mao Jinlong Description: (Read) Show hardware context information of device. + +What: /sys/bus/coresight/devices//traceid +Date: March 2026 +KernelVersion: 7.1 +Contact: Jie Gan +Description: + (R) Show the trace ID that will appear in the trace stream + coming from this TPDM. The trace ID is inherited from the + connected TPDA device and is fixed for the lifetime of the + device. Returns -EINVAL if the device has not been enabled yet. diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index da77bdaad0a4..9b16f368a58b 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -481,7 +481,7 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata) static int tpdm_enable(struct coresight_device *csdev, struct perf_event *event, enum cs_mode mode, - __maybe_unused struct coresight_path *path) + struct coresight_path *path) { struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); @@ -497,6 +497,7 @@ static int tpdm_enable(struct coresight_device *csdev, struct perf_event *event, } __tpdm_enable(drvdata); + drvdata->traceid = path->trace_id; drvdata->enable = true; spin_unlock(&drvdata->spinlock); @@ -693,6 +694,29 @@ static struct attribute_group tpdm_attr_grp = { .attrs = tpdm_attrs, }; +static ssize_t traceid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long val; + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + val = drvdata->traceid; + if (!val) + return -EINVAL; + + return sysfs_emit(buf, "%#lx\n", val); +} +static DEVICE_ATTR_RO(traceid); + +static struct attribute *traceid_attrs[] = { + &dev_attr_traceid.attr, + NULL, +}; + +static struct attribute_group traceid_attr_grp = { + .attrs = traceid_attrs, +}; + static ssize_t dsb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1367,6 +1391,12 @@ static const struct attribute_group *tpdm_attr_grps[] = { &tpdm_cmb_patt_grp, &tpdm_cmb_msr_grp, &tpdm_mcmb_attr_grp, + &traceid_attr_grp, + NULL, +}; + +static const struct attribute_group *static_tpdm_attr_grps[] = { + &traceid_attr_grp, NULL, }; @@ -1425,6 +1455,8 @@ static int tpdm_probe(struct device *dev, struct resource *res) desc.access = CSDEV_ACCESS_IOMEM(base); if (res) desc.groups = tpdm_attr_grps; + else + desc.groups = static_tpdm_attr_grps; drvdata->csdev = coresight_register(&desc); if (IS_ERR(drvdata->csdev)) return PTR_ERR(drvdata->csdev); diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index 2867f3ab8186..11da64e1ade8 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -300,6 +300,7 @@ struct cmb_dataset { * @cmb Specifics associated to TPDM CMB. * @dsb_msr_num Number of MSR supported by DSB TPDM * @cmb_msr_num Number of MSR supported by CMB TPDM + * @traceid Trace ID of the path. */ struct tpdm_drvdata { @@ -313,6 +314,7 @@ struct tpdm_drvdata { struct cmb_dataset *cmb; u32 dsb_msr_num; u32 cmb_msr_num; + u8 traceid; }; /* Enumerate members of various datasets */ From 971f3474f8898ae8bbab19a9b547819a5e6fbcf1 Mon Sep 17 00:00:00 2001 From: Jie Gan Date: Tue, 7 Apr 2026 19:09:05 +0800 Subject: [PATCH 25/25] coresight: tpdm: fix invalid MMIO access issue Create the csdev_access struct only when a valid MMIO resource is available. In tpdm_probe(), base is uninitialized for static TPDM instances that lack an MMIO resource, causing csdev_access to be created with a garbage address. So far there has no register access for static instance, but this change helps mitigate potential risks in the future. Fixes: 14ae052f7947 ("coresight: tpdm: add static tpdm support") Reviewed-by: Leo Yan Signed-off-by: Jie Gan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20260407-fix-potential-issue-in-tpdm-v2-1-1d0e0d3cb793@oss.qualcomm.com --- drivers/hwtracing/coresight/coresight-tpdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 9b16f368a58b..eaf7210af648 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -1430,6 +1430,7 @@ static int tpdm_probe(struct device *dev, struct resource *res) if (ret) return ret; + desc.access = CSDEV_ACCESS_IOMEM(base); if (tpdm_has_dsb_dataset(drvdata)) of_property_read_u32(drvdata->dev->of_node, "qcom,dsb-msrs-num", &drvdata->dsb_msr_num); @@ -1452,7 +1453,6 @@ static int tpdm_probe(struct device *dev, struct resource *res) desc.ops = &tpdm_cs_ops; desc.pdata = dev->platform_data; desc.dev = dev; - desc.access = CSDEV_ACCESS_IOMEM(base); if (res) desc.groups = tpdm_attr_grps; else