From 8a519235c3c37663e54e37a89d05a86c0a2c90c8 Mon Sep 17 00:00:00 2001 From: James Clark Date: Thu, 23 Nov 2023 12:04:56 +0000 Subject: [PATCH 01/32] coresight: Fix uninitialized struct warnings These warnings would be hit with the following W=1 build change so initialize all structs properly. Signed-off-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20231123120459.287578-2-james.clark@arm.com --- drivers/hwtracing/coresight/coresight-cti-core.c | 2 +- drivers/hwtracing/coresight/coresight-etb10.c | 2 +- drivers/hwtracing/coresight/coresight-etm3x-core.c | 2 +- drivers/hwtracing/coresight/coresight-etm4x-core.c | 2 +- drivers/hwtracing/coresight/coresight-funnel.c | 4 ++-- drivers/hwtracing/coresight/coresight-replicator.c | 2 +- drivers/hwtracing/coresight/coresight-stm.c | 2 +- drivers/hwtracing/coresight/coresight-tmc-core.c | 2 +- drivers/hwtracing/coresight/coresight-tpda.c | 2 +- drivers/hwtracing/coresight/coresight-tpdm.c | 2 +- drivers/hwtracing/coresight/coresight-tpiu.c | 2 +- drivers/hwtracing/coresight/ultrasoc-smb.c | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c index 3999d0a2cb602..e805617020d06 100644 --- a/drivers/hwtracing/coresight/coresight-cti-core.c +++ b/drivers/hwtracing/coresight/coresight-cti-core.c @@ -974,7 +974,7 @@ static const struct amba_id cti_ids[] = { CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */ CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */ CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */ - { 0, 0}, + { 0, 0, NULL }, }; MODULE_DEVICE_TABLE(amba, cti_ids); diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index fa80039e0821f..05e21cffd33bd 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -837,7 +837,7 @@ static const struct amba_id etb_ids[] = { .id = 0x000bb907, .mask = 0x000fffff, }, - { 0, 0}, + { 0, 0, NULL }, }; MODULE_DEVICE_TABLE(amba, etb_ids); diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index 116a91d90ac20..8da1622e0837a 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -1003,7 +1003,7 @@ static const struct amba_id etm_ids[] = { CS_AMBA_ID_DATA(0x000bb95f, "PTM 1.1"), /* PTM 1.1 Qualcomm */ CS_AMBA_ID_DATA(0x000b006f, "PTM 1.1"), - { 0, 0}, + { 0, 0, NULL}, }; MODULE_DEVICE_TABLE(amba, etm_ids); diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index ce1995a2827f0..c5ea808ea6623 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -2390,7 +2390,7 @@ static const struct of_device_id etm4_sysreg_match[] = { #ifdef CONFIG_ACPI static const struct acpi_device_id etm4x_acpi_ids[] = { - {"ARMHC500", 0}, /* ARM CoreSight ETM4x */ + {"ARMHC500", 0, 0, 0}, /* ARM CoreSight ETM4x */ {} }; MODULE_DEVICE_TABLE(acpi, etm4x_acpi_ids); diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index a5b1fc787766a..ef1a0abfee4e9 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -350,7 +350,7 @@ MODULE_DEVICE_TABLE(of, static_funnel_match); #ifdef CONFIG_ACPI static const struct acpi_device_id static_funnel_ids[] = { - {"ARMHC9FE", 0}, + {"ARMHC9FE", 0, 0, 0}, {}, }; @@ -391,7 +391,7 @@ static const struct amba_id dynamic_funnel_ids[] = { .id = 0x000bb9eb, .mask = 0x000fffff, }, - { 0, 0}, + { 0, 0, NULL }, }; MODULE_DEVICE_TABLE(amba, dynamic_funnel_ids); diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 91d93060dda53..73452d9dc13b2 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -363,7 +363,7 @@ MODULE_DEVICE_TABLE(of, static_replicator_match); #ifdef CONFIG_ACPI static const struct acpi_device_id static_replicator_acpi_ids[] = { - {"ARMHC985", 0}, /* ARM CoreSight Static Replicator */ + {"ARMHC985", 0, 0, 0}, /* ARM CoreSight Static Replicator */ {} }; diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index a1c27c901ad17..891ee64efed87 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -950,7 +950,7 @@ static const struct dev_pm_ops stm_dev_pm_ops = { static const struct amba_id stm_ids[] = { CS_AMBA_ID_DATA(0x000bb962, "STM32"), CS_AMBA_ID_DATA(0x000bb963, "STM500"), - { 0, 0}, + { 0, 0, NULL }, }; MODULE_DEVICE_TABLE(amba, stm_ids); diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 7ec5365e2b642..39bae35d4ffd3 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -594,7 +594,7 @@ static const struct amba_id tmc_ids[] = { CS_AMBA_ID(0x000bb9e9), /* Coresight SoC 600 TMC-ETF */ CS_AMBA_ID(0x000bb9ea), - { 0, 0}, + { 0, 0, NULL }, }; MODULE_DEVICE_TABLE(amba, tmc_ids); diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index 5f82737c37bba..4ac954f4bc136 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -300,7 +300,7 @@ static struct amba_id tpda_ids[] = { .id = 0x000f0f00, .mask = 0x000fff00, }, - { 0, 0}, + { 0, 0, NULL }, }; static struct amba_driver tpda_driver = { diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 97654aa4b772a..bd13a548375ca 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -933,7 +933,7 @@ static struct amba_id tpdm_ids[] = { .id = 0x000f0e00, .mask = 0x000fff00, }, - { 0, 0}, + { 0, 0, NULL }, }; static struct amba_driver tpdm_driver = { diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 59eac93fd6bb9..7e69048ac9449 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -218,7 +218,7 @@ static const struct amba_id tpiu_ids[] = { .id = 0x000bb9e7, .mask = 0x000fffff, }, - { 0, 0}, + { 0, 0, NULL }, }; MODULE_DEVICE_TABLE(amba, tpiu_ids); diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c index 10e886455b8b7..f0b6806202d19 100644 --- a/drivers/hwtracing/coresight/ultrasoc-smb.c +++ b/drivers/hwtracing/coresight/ultrasoc-smb.c @@ -586,7 +586,7 @@ static void smb_remove(struct platform_device *pdev) #ifdef CONFIG_ACPI static const struct acpi_device_id ultrasoc_smb_acpi_match[] = { - {"HISI03A1", 0}, + {"HISI03A1", 0, 0, 0}, {} }; MODULE_DEVICE_TABLE(acpi, ultrasoc_smb_acpi_match); From 54daf07e63321d98473777527ce4853fa8eac33d Mon Sep 17 00:00:00 2001 From: James Clark Date: Thu, 23 Nov 2023 12:04:57 +0000 Subject: [PATCH 02/32] coresight: etm3x: Fix build warning The missing * in the comment block causes the following warning, so fix it: hwtracing/coresight/coresight-etm3x-core.c:118: warning: bad line: Signed-off-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20231123120459.287578-3-james.clark@arm.com --- drivers/hwtracing/coresight/coresight-etm3x-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index 8da1622e0837a..74ae26911b8a8 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -115,7 +115,7 @@ static void etm_clr_pwrup(struct etm_drvdata *drvdata) * * Basically the same as @coresight_timeout except for the register access * method where we have to account for CP14 configurations. - + * * Return: 0 as soon as the bit has taken the desired state or -EAGAIN if * TIMEOUT_US has elapsed, which ever happens first. */ From a7195f3f93836f518e07da11d0b068e71149d17e Mon Sep 17 00:00:00 2001 From: James Clark Date: Thu, 23 Nov 2023 12:04:58 +0000 Subject: [PATCH 03/32] coresight: Fix undeclared variable warnings from sparse checker Including the header with the declarations fixes the following warning with a C=1 build: coresight-cfg-afdo.c:102:27: warning: symbol 'strobe_etm4x' was not declared. Should it be static? coresight-cfg-afdo.c:141:26: warning: symbol 'afdo_etm4x' was not declared. Should it be static? Signed-off-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20231123120459.287578-4-james.clark@arm.com --- drivers/hwtracing/coresight/coresight-cfg-afdo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwtracing/coresight/coresight-cfg-afdo.c b/drivers/hwtracing/coresight/coresight-cfg-afdo.c index 84b31184252bb..e794f2e145fad 100644 --- a/drivers/hwtracing/coresight/coresight-cfg-afdo.c +++ b/drivers/hwtracing/coresight/coresight-cfg-afdo.c @@ -9,6 +9,7 @@ /* ETMv4 includes and features */ #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) #include "coresight-etm4x-cfg.h" +#include "coresight-cfg-preload.h" /* preload configurations and features */ From d999c7dd52790e294d78d06e6535e318275c1ea5 Mon Sep 17 00:00:00 2001 From: James Clark Date: Thu, 23 Nov 2023 12:04:59 +0000 Subject: [PATCH 04/32] coresight: Make current W=1 warnings default Similarly to drivers/gpu/drm/amd/amdgpu/Makefile and fs/btrfs/Makefile, copy the current set of W=1 warnings from Makefile.extrawarn to the coresight makefile to make them default. Unfortunately there is no easy way to do this without copying. In addition to the default set of warnings, add -Wno-sign-compare to disable that warning. That's because Makefile.extrawarn does some extra steps to disable some -Wextra warnings unless W=2 or W=3 are used. That's the only one that's needed for Coresight, so disable it. Signed-off-by: James Clark Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20231123120459.287578-5-james.clark@arm.com --- drivers/hwtracing/coresight/Makefile | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 995d3b2c76df2..4ba478211b318 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -2,6 +2,26 @@ # # Makefile for CoreSight drivers. # + +# Current W=1 warnings +subdir-ccflags-y += -Wextra -Wunused -Wno-unused-parameter +subdir-ccflags-y += -Wmissing-declarations +subdir-ccflags-y += -Wmissing-format-attribute +subdir-ccflags-y += -Wmissing-prototypes +subdir-ccflags-y += -Wold-style-definition +subdir-ccflags-y += -Wmissing-include-dirs +subdir-ccflags-y += -Wno-sign-compare +condflags := \ + $(call cc-option, -Wrestrict) \ + $(call cc-option, -Wunused-but-set-variable) \ + $(call cc-option, -Wunused-const-variable) \ + $(call cc-option, -Wpacked-not-aligned) \ + $(call cc-option, -Wformat-overflow) \ + $(call cc-option, -Wformat-truncation) \ + $(call cc-option, -Wstringop-overflow) \ + $(call cc-option, -Wstringop-truncation) +subdir-ccflags-y += $(condflags) + obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ coresight-sysfs.o coresight-syscfg.o coresight-config.o \ From dd95255d44c05c9977f962bf0f2afe5e11f8ab3e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 5 Jan 2024 13:33:32 +0100 Subject: [PATCH 05/32] coresight: make coresight_bustype const Now that the driver core can properly handle constant struct bus_type, move the coresight_bustype variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Suzuki K Poulose Cc: Mike Leach Cc: James Clark Cc: Leo Yan Cc: Alexander Shishkin Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/2024010531-tinfoil-avert-4a57@gregkh --- drivers/hwtracing/coresight/coresight-core.c | 2 +- include/linux/coresight.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index d7f0e231feb99..5dde597403b37 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1799,7 +1799,7 @@ char *coresight_alloc_device_name(struct coresight_dev_list *dict, } EXPORT_SYMBOL_GPL(coresight_alloc_device_name); -struct bus_type coresight_bustype = { +const struct bus_type coresight_bustype = { .name = "coresight", }; diff --git a/include/linux/coresight.h b/include/linux/coresight.h index a4cb7dd6ca237..e8b6e388218cb 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -35,7 +35,7 @@ #define CORESIGHT_UNLOCK 0xc5acce55 -extern struct bus_type coresight_bustype; +extern const struct bus_type coresight_bustype; enum coresight_dev_type { CORESIGHT_DEV_TYPE_SINK, From f68bbe4dcfa303164922bc331d2e8d38ed2d4f23 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 29 Jan 2024 15:40:32 +0000 Subject: [PATCH 06/32] coresight: Fix issue where a source device's helpers aren't disabled The linked commit reverts the change that accidentally used some sysfs enable/disable functions from Perf which broke the refcounting, but it also removes the fact that the sysfs disable function disabled the helpers. Add a new wrapper function that does both which is used by both Perf and sysfs, and label the sysfs disable function appropriately. The naming of all of the functions will be tidied up later to avoid this happening again. Fixes: 287e82cf69aa ("coresight: Fix crash when Perf and sysfs modes are used concurrently") Signed-off-by: James Clark Link: https://lore.kernel.org/r/20240129154050.569566-2-james.clark@arm.com Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-core.c | 30 ++++++++++++++----- .../hwtracing/coresight/coresight-etm-perf.c | 2 +- drivers/hwtracing/coresight/coresight-priv.h | 2 +- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 5dde597403b37..1dd3cd46fda48 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -441,8 +441,26 @@ static void coresight_disable_helpers(struct coresight_device *csdev) } } +/* + * Helper function to call source_ops(csdev)->disable and also disable the + * helpers. + * + * There is an imbalance between coresight_enable_path() and + * coresight_disable_path(). Enabling also enables the source's helpers as part + * of the path, but disabling always skips the first item in the path (which is + * the source), so sources and their helpers don't get disabled as part of that + * function and we need the extra step here. + */ +void coresight_disable_source(struct coresight_device *csdev, void *data) +{ + if (source_ops(csdev)->disable) + source_ops(csdev)->disable(csdev, data); + coresight_disable_helpers(csdev); +} +EXPORT_SYMBOL_GPL(coresight_disable_source); + /** - * coresight_disable_source - Drop the reference count by 1 and disable + * coresight_disable_source_sysfs - Drop the reference count by 1 and disable * the device if there are no users left. * * @csdev: The coresight device to disable @@ -451,17 +469,15 @@ static void coresight_disable_helpers(struct coresight_device *csdev) * * Returns true if the device has been disabled. */ -bool coresight_disable_source(struct coresight_device *csdev, void *data) +static bool coresight_disable_source_sysfs(struct coresight_device *csdev, + void *data) { if (atomic_dec_return(&csdev->refcnt) == 0) { - if (source_ops(csdev)->disable) - source_ops(csdev)->disable(csdev, data); - coresight_disable_helpers(csdev); + coresight_disable_source(csdev, data); csdev->enable = false; } return !csdev->enable; } -EXPORT_SYMBOL_GPL(coresight_disable_source); /* * coresight_disable_path_from : Disable components in the given path beyond @@ -1204,7 +1220,7 @@ void coresight_disable(struct coresight_device *csdev) if (ret) goto out; - if (!csdev->enable || !coresight_disable_source(csdev, NULL)) + if (!csdev->enable || !coresight_disable_source_sysfs(csdev, NULL)) goto out; switch (csdev->subtype.source_subtype) { diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index a52cfcce25d6d..c0c60e6a1703e 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -589,7 +589,7 @@ static void etm_event_stop(struct perf_event *event, int mode) return; /* stop tracer */ - source_ops(csdev)->disable(csdev, event); + coresight_disable_source(csdev, event); /* tell the core */ event->hw.state = PERF_HES_STOPPED; diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 767076e079701..30c051055e54b 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -233,6 +233,6 @@ void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev); struct coresight_device *coresight_get_percpu_sink(int cpu); int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, void *data); -bool coresight_disable_source(struct coresight_device *csdev, void *data); +void coresight_disable_source(struct coresight_device *csdev, void *data); #endif From a0fef3f05cf36338d471e8f35a9ced88a054d583 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 29 Jan 2024 15:40:33 +0000 Subject: [PATCH 07/32] coresight: Make language around "activated" sinks consistent Activated has the specific meaning of a sink that's selected for use by the user via sysfs. But comments in some code that's shared by Perf use the same word, so in those cases change them to just say "selected" instead. With selected implying either via Perf or "activated" via sysfs. coresight_get_enabled_sink() doesn't actually get an enabled sink, it only gets an activated one, so change that too. And change the activated variable name to include "sysfs" so it can't be confused as a general status. Signed-off-by: James Clark Link: https://lore.kernel.org/r/20240129154050.569566-3-james.clark@arm.com Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-core.c | 51 ++++++++------------ drivers/hwtracing/coresight/coresight-priv.h | 2 - include/linux/coresight.h | 14 +++--- 3 files changed, 27 insertions(+), 40 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 1dd3cd46fda48..37e59052e8777 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -500,7 +500,7 @@ static void coresight_disable_path_from(struct list_head *path, /* * ETF devices are tricky... They can be a link or a sink, * depending on how they are configured. If an ETF has been - * "activated" it will be configured as a sink, otherwise + * selected as a sink it will be configured as a sink, otherwise * go ahead with the link configuration. */ if (type == CORESIGHT_DEV_TYPE_LINKSINK) @@ -578,7 +578,7 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode, /* * ETF devices are tricky... They can be a link or a sink, * depending on how they are configured. If an ETF has been - * "activated" it will be configured as a sink, otherwise + * selected as a sink it will be configured as a sink, otherwise * go ahead with the link configuration. */ if (type == CORESIGHT_DEV_TYPE_LINKSINK) @@ -635,15 +635,21 @@ struct coresight_device *coresight_get_sink(struct list_head *path) return csdev; } +/** + * coresight_find_activated_sysfs_sink - returns the first sink activated via + * sysfs using connection based search starting from the source reference. + * + * @csdev: Coresight source device reference + */ static struct coresight_device * -coresight_find_enabled_sink(struct coresight_device *csdev) +coresight_find_activated_sysfs_sink(struct coresight_device *csdev) { int i; struct coresight_device *sink = NULL; if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && - csdev->activated) + csdev->sysfs_sink_activated) return csdev; /* @@ -654,7 +660,7 @@ coresight_find_enabled_sink(struct coresight_device *csdev) child_dev = csdev->pdata->out_conns[i]->dest_dev; if (child_dev) - sink = coresight_find_enabled_sink(child_dev); + sink = coresight_find_activated_sysfs_sink(child_dev); if (sink) return sink; } @@ -662,21 +668,6 @@ coresight_find_enabled_sink(struct coresight_device *csdev) return NULL; } -/** - * coresight_get_enabled_sink - returns the first enabled sink using - * connection based search starting from the source reference - * - * @source: Coresight source device reference - */ -struct coresight_device * -coresight_get_enabled_sink(struct coresight_device *source) -{ - if (!source) - return NULL; - - return coresight_find_enabled_sink(source); -} - static int coresight_sink_by_id(struct device *dev, const void *data) { struct coresight_device *csdev = to_coresight_device(dev); @@ -810,11 +801,10 @@ static void coresight_drop_device(struct coresight_device *csdev) * @sink: The final sink we want in this path. * @path: The list to add devices to. * - * The tree of Coresight device is traversed until an activated sink is - * found. From there the sink is added to the list along with all the - * devices that led to that point - the end result is a list from source - * to sink. In that list the source is the first device and the sink the - * last one. + * The tree of Coresight device is traversed until @sink is found. + * From there the sink is added to the list along with all the devices that led + * to that point - the end result is a list from source to sink. In that list + * the source is the first device and the sink the last one. */ static int _coresight_build_path(struct coresight_device *csdev, struct coresight_device *sink, @@ -824,7 +814,7 @@ static int _coresight_build_path(struct coresight_device *csdev, bool found = false; struct coresight_node *node; - /* An activated sink has been found. Enqueue the element */ + /* The sink has been found. Enqueue the element */ if (csdev == sink) goto out; @@ -1145,7 +1135,7 @@ int coresight_enable(struct coresight_device *csdev) goto out; } - sink = coresight_get_enabled_sink(csdev); + sink = coresight_find_activated_sysfs_sink(csdev); if (!sink) { ret = -EINVAL; goto out; @@ -1259,7 +1249,7 @@ static ssize_t enable_sink_show(struct device *dev, { struct coresight_device *csdev = to_coresight_device(dev); - return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->activated); + return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->sysfs_sink_activated); } static ssize_t enable_sink_store(struct device *dev, @@ -1274,10 +1264,7 @@ static ssize_t enable_sink_store(struct device *dev, if (ret) return ret; - if (val) - csdev->activated = true; - else - csdev->activated = false; + csdev->sysfs_sink_activated = !!val; return size; diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 30c051055e54b..ced5be05a527e 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -130,8 +130,6 @@ void coresight_disable_path(struct list_head *path); int coresight_enable_path(struct list_head *path, enum cs_mode mode, void *sink_data); struct coresight_device *coresight_get_sink(struct list_head *path); -struct coresight_device * -coresight_get_enabled_sink(struct coresight_device *source); struct coresight_device *coresight_get_sink_by_id(u32 id); struct coresight_device * coresight_find_default_sink(struct coresight_device *csdev); diff --git a/include/linux/coresight.h b/include/linux/coresight.h index e8b6e388218cb..516ab45ff3c28 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -229,10 +229,12 @@ struct coresight_sysfs_link { * @refcnt: keep track of what is in use. * @orphan: true if the component has connections that haven't been linked. * @enable: 'true' if component is currently part of an active path. - * @activated: 'true' only if a _sink_ has been activated. A sink can be - * activated but not yet enabled. Enabling for a _sink_ - * happens when a source has been selected and a path is enabled - * from source to that sink. + * @sysfs_sink_activated: 'true' when a sink has been selected for use via sysfs + * by writing a 1 to the 'enable_sink' file. A sink can be + * activated but not yet enabled. Enabling for a _sink_ happens + * when a source has been selected and a path is enabled from + * source to that sink. A sink can also become enabled but not + * activated if it's used via Perf. * @ea: Device attribute for sink representation under PMU directory. * @def_sink: cached reference to default sink found for this device. * @nr_links: number of sysfs links created to other components from this @@ -252,9 +254,9 @@ struct coresight_device { struct device dev; atomic_t refcnt; bool orphan; - bool enable; /* true only if configured as part of a path */ + bool enable; /* sink specific fields */ - bool activated; /* true only if a sink is part of a path */ + bool sysfs_sink_activated; struct dev_ext_attribute *ea; struct coresight_device *def_sink; /* sysfs links between components */ From a11ebe138b8ddb119b1b75c143429f64d605a54e Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 29 Jan 2024 15:40:34 +0000 Subject: [PATCH 08/32] coresight: Remove ops callback checks The check for the existence of callbacks before using them implies that this happens and is supported. There are no devices without enable/disable callbacks, and it wouldn't be possible to add a new working device without adding them either, so just remove them. Furthermore, there are more callbacks than just enable and disable that are already used unguarded in other places. The comment about new session compatibility doesn't seem to match up to the line of code that it's on so remove it. I think it's alluding to the fact that sinks will check if they were already enabled via sysfs or Perf and fail the enable. But there are more detailed comments at those places, and this one isn't very useful. Signed-off-by: James Clark Link: https://lore.kernel.org/r/20240129154050.569566-4-james.clark@arm.com Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-core.c | 51 +++++--------------- 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 37e59052e8777..5e93b52df105a 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -279,16 +279,8 @@ EXPORT_SYMBOL_GPL(coresight_add_helper); static int coresight_enable_sink(struct coresight_device *csdev, enum cs_mode mode, void *data) { - int ret; - - /* - * We need to make sure the "new" session is compatible with the - * existing "mode" of operation. - */ - if (!sink_ops(csdev)->enable) - return -EINVAL; + int ret = sink_ops(csdev)->enable(csdev, mode, data); - ret = sink_ops(csdev)->enable(csdev, mode, data); if (ret) return ret; @@ -299,12 +291,7 @@ static int coresight_enable_sink(struct coresight_device *csdev, static void coresight_disable_sink(struct coresight_device *csdev) { - int ret; - - if (!sink_ops(csdev)->disable) - return; - - ret = sink_ops(csdev)->disable(csdev); + int ret = sink_ops(csdev)->disable(csdev); if (ret) return; csdev->enable = false; @@ -330,11 +317,9 @@ static int coresight_enable_link(struct coresight_device *csdev, if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn)) return PTR_ERR(outconn); - if (link_ops(csdev)->enable) { - ret = link_ops(csdev)->enable(csdev, inconn, outconn); - if (!ret) - csdev->enable = true; - } + ret = link_ops(csdev)->enable(csdev, inconn, outconn); + if (!ret) + csdev->enable = true; return ret; } @@ -354,9 +339,7 @@ static void coresight_disable_link(struct coresight_device *csdev, outconn = coresight_find_out_connection(csdev, child); link_subtype = csdev->subtype.link_subtype; - if (link_ops(csdev)->disable) { - link_ops(csdev)->disable(csdev, inconn, outconn); - } + link_ops(csdev)->disable(csdev, inconn, outconn); if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) { for (i = 0; i < csdev->pdata->nr_inconns; i++) @@ -382,11 +365,9 @@ int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, int ret; if (!csdev->enable) { - if (source_ops(csdev)->enable) { - ret = source_ops(csdev)->enable(csdev, data, mode); - if (ret) - return ret; - } + ret = source_ops(csdev)->enable(csdev, data, mode); + if (ret) + return ret; csdev->enable = true; } @@ -404,11 +385,8 @@ static bool coresight_is_helper(struct coresight_device *csdev) static int coresight_enable_helper(struct coresight_device *csdev, enum cs_mode mode, void *data) { - int ret; + int ret = helper_ops(csdev)->enable(csdev, mode, data); - if (!helper_ops(csdev)->enable) - return 0; - ret = helper_ops(csdev)->enable(csdev, mode, data); if (ret) return ret; @@ -418,12 +396,8 @@ static int coresight_enable_helper(struct coresight_device *csdev, static void coresight_disable_helper(struct coresight_device *csdev) { - int ret; - - if (!helper_ops(csdev)->disable) - return; + int ret = helper_ops(csdev)->disable(csdev, NULL); - ret = helper_ops(csdev)->disable(csdev, NULL); if (ret) return; csdev->enable = false; @@ -453,8 +427,7 @@ static void coresight_disable_helpers(struct coresight_device *csdev) */ void coresight_disable_source(struct coresight_device *csdev, void *data) { - if (source_ops(csdev)->disable) - source_ops(csdev)->disable(csdev, data); + source_ops(csdev)->disable(csdev, data); coresight_disable_helpers(csdev); } EXPORT_SYMBOL_GPL(coresight_disable_source); From 9cae77cf23e317f31de036ced7ad2c261317dc76 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 29 Jan 2024 15:40:35 +0000 Subject: [PATCH 09/32] coresight: Move mode to struct coresight_device Most devices use mode, so move the mode definition out of the individual devices and up to the Coresight device. This will allow the core code to also know the mode which will be useful in a later commit. This also fixes the inconsistency of the documentation of the mode field on the individual device types. For example ETB10 had "this ETB is being used". Two devices didn't require an atomic mode type, so these usages have been converted to atomic_get() and atomic_set() only to make it compile, but the documentation of the field in struct coresight_device explains this type of usage. In the future, manipulation of the mode could be completely moved out of the individual devices and into the core code because it's almost all duplicate code, and this change is a step towards that. Signed-off-by: James Clark Link: https://lore.kernel.org/r/20240129154050.569566-5-james.clark@arm.com Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-etb10.c | 18 ++++++------- drivers/hwtracing/coresight/coresight-etm.h | 2 -- .../coresight/coresight-etm3x-core.c | 13 +++++----- .../coresight/coresight-etm3x-sysfs.c | 4 +-- .../coresight/coresight-etm4x-core.c | 16 +++++------- drivers/hwtracing/coresight/coresight-etm4x.h | 1 - drivers/hwtracing/coresight/coresight-stm.c | 20 +++++++------- .../hwtracing/coresight/coresight-tmc-core.c | 2 +- .../hwtracing/coresight/coresight-tmc-etf.c | 26 +++++++++---------- .../hwtracing/coresight/coresight-tmc-etr.c | 20 +++++++------- drivers/hwtracing/coresight/coresight-tmc.h | 2 -- drivers/hwtracing/coresight/ultrasoc-smb.c | 13 +++++----- drivers/hwtracing/coresight/ultrasoc-smb.h | 2 -- include/linux/coresight.h | 6 +++++ 14 files changed, 69 insertions(+), 76 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 05e21cffd33bd..145fb815ec1cf 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -76,7 +76,6 @@ DEFINE_CORESIGHT_DEVLIST(etb_devs, "etb"); * @pid: Process ID of the process being monitored by the session * that is using this component. * @buf: area of memory where ETB buffer content gets sent. - * @mode: this ETB is being used. * @buffer_depth: size of @buf. * @trigger_cntr: amount of words to store after a trigger. */ @@ -89,7 +88,6 @@ struct etb_drvdata { local_t reading; pid_t pid; u8 *buf; - u32 mode; u32 buffer_depth; u32 trigger_cntr; }; @@ -150,17 +148,17 @@ static int etb_enable_sysfs(struct coresight_device *csdev) spin_lock_irqsave(&drvdata->spinlock, flags); /* Don't messup with perf sessions. */ - if (drvdata->mode == CS_MODE_PERF) { + if (local_read(&csdev->mode) == CS_MODE_PERF) { ret = -EBUSY; goto out; } - if (drvdata->mode == CS_MODE_DISABLED) { + if (local_read(&csdev->mode) == CS_MODE_DISABLED) { ret = etb_enable_hw(drvdata); if (ret) goto out; - drvdata->mode = CS_MODE_SYSFS; + local_set(&csdev->mode, CS_MODE_SYSFS); } atomic_inc(&csdev->refcnt); @@ -181,7 +179,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) spin_lock_irqsave(&drvdata->spinlock, flags); /* No need to continue if the component is already in used by sysFS. */ - if (drvdata->mode == CS_MODE_SYSFS) { + if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) { ret = -EBUSY; goto out; } @@ -216,7 +214,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) if (!ret) { /* Associate with monitored process. */ drvdata->pid = pid; - drvdata->mode = CS_MODE_PERF; + local_set(&drvdata->csdev->mode, CS_MODE_PERF); atomic_inc(&csdev->refcnt); } @@ -362,11 +360,11 @@ static int etb_disable(struct coresight_device *csdev) } /* Complain if we (somehow) got out of sync */ - WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED); + WARN_ON_ONCE(local_read(&csdev->mode) == CS_MODE_DISABLED); etb_disable_hw(drvdata); /* Dissociate from monitored process. */ drvdata->pid = -1; - drvdata->mode = CS_MODE_DISABLED; + local_set(&csdev->mode, CS_MODE_DISABLED); spin_unlock_irqrestore(&drvdata->spinlock, flags); dev_dbg(&csdev->dev, "ETB disabled\n"); @@ -589,7 +587,7 @@ static void etb_dump(struct etb_drvdata *drvdata) unsigned long flags; spin_lock_irqsave(&drvdata->spinlock, flags); - if (drvdata->mode == CS_MODE_SYSFS) { + if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) { __etb_disable_hw(drvdata); etb_dump_hw(drvdata); __etb_enable_hw(drvdata); diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h index 9a0d08b092ae7..e02c3ea972c92 100644 --- a/drivers/hwtracing/coresight/coresight-etm.h +++ b/drivers/hwtracing/coresight/coresight-etm.h @@ -215,7 +215,6 @@ struct etm_config { * @port_size: port size as reported by ETMCR bit 4-6 and 21. * @arch: ETM/PTM version number. * @use_cpu14: true if management registers need to be accessed via CP14. - * @mode: this tracer's mode, i.e sysFS, Perf or disabled. * @sticky_enable: true if ETM base configuration has been done. * @boot_enable:true if we should start tracing at boot time. * @os_unlock: true if access to management registers is allowed. @@ -238,7 +237,6 @@ struct etm_drvdata { int port_size; u8 arch; bool use_cp14; - local_t mode; bool sticky_enable; bool boot_enable; bool os_unlock; diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index 74ae26911b8a8..333d0a32c95c8 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -559,7 +559,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event, u32 val; struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode); + val = local_cmpxchg(&drvdata->csdev->mode, CS_MODE_DISABLED, mode); /* Someone is already using the tracer */ if (val) @@ -578,7 +578,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event, /* The tracer didn't start */ if (ret) - local_set(&drvdata->mode, CS_MODE_DISABLED); + local_set(&drvdata->csdev->mode, CS_MODE_DISABLED); return ret; } @@ -672,14 +672,13 @@ static void etm_disable(struct coresight_device *csdev, struct perf_event *event) { enum cs_mode mode; - struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); /* * For as long as the tracer isn't disabled another entity can't * change its status. As such we can read the status here without * fearing it will change under us. */ - mode = local_read(&drvdata->mode); + mode = local_read(&csdev->mode); switch (mode) { case CS_MODE_DISABLED: @@ -696,7 +695,7 @@ static void etm_disable(struct coresight_device *csdev, } if (mode) - local_set(&drvdata->mode, CS_MODE_DISABLED); + local_set(&csdev->mode, CS_MODE_DISABLED); } static const struct coresight_ops_source etm_source_ops = { @@ -730,7 +729,7 @@ static int etm_starting_cpu(unsigned int cpu) etmdrvdata[cpu]->os_unlock = true; } - if (local_read(&etmdrvdata[cpu]->mode)) + if (local_read(&etmdrvdata[cpu]->csdev->mode)) etm_enable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; @@ -742,7 +741,7 @@ static int etm_dying_cpu(unsigned int cpu) return 0; spin_lock(&etmdrvdata[cpu]->spinlock); - if (local_read(&etmdrvdata[cpu]->mode)) + if (local_read(&etmdrvdata[cpu]->csdev->mode)) etm_disable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c index 2f271b7fb048c..6c8429c980b14 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c @@ -722,7 +722,7 @@ static ssize_t cntr_val_show(struct device *dev, struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; - if (!local_read(&drvdata->mode)) { + if (!local_read(&drvdata->csdev->mode)) { spin_lock(&drvdata->spinlock); for (i = 0; i < drvdata->nr_cntr; i++) ret += sprintf(buf, "counter %d: %x\n", @@ -941,7 +941,7 @@ static ssize_t seq_curr_state_show(struct device *dev, struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; - if (!local_read(&drvdata->mode)) { + if (!local_read(&drvdata->csdev->mode)) { val = config->seq_curr_state; goto out; } diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index c5ea808ea6623..7ceff627cd958 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -841,9 +841,8 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, { int ret; u32 val; - struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode); + val = local_cmpxchg(&csdev->mode, CS_MODE_DISABLED, mode); /* Someone is already using the tracer */ if (val) @@ -862,7 +861,7 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, /* The tracer didn't start */ if (ret) - local_set(&drvdata->mode, CS_MODE_DISABLED); + local_set(&csdev->mode, CS_MODE_DISABLED); return ret; } @@ -1004,14 +1003,13 @@ static void etm4_disable(struct coresight_device *csdev, struct perf_event *event) { enum cs_mode mode; - struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); /* * For as long as the tracer isn't disabled another entity can't * change its status. As such we can read the status here without * fearing it will change under us. */ - mode = local_read(&drvdata->mode); + mode = local_read(&csdev->mode); switch (mode) { case CS_MODE_DISABLED: @@ -1025,7 +1023,7 @@ static void etm4_disable(struct coresight_device *csdev, } if (mode) - local_set(&drvdata->mode, CS_MODE_DISABLED); + local_set(&csdev->mode, CS_MODE_DISABLED); } static const struct coresight_ops_source etm4_source_ops = { @@ -1663,7 +1661,7 @@ static int etm4_starting_cpu(unsigned int cpu) if (!etmdrvdata[cpu]->os_unlock) etm4_os_unlock(etmdrvdata[cpu]); - if (local_read(&etmdrvdata[cpu]->mode)) + if (local_read(&etmdrvdata[cpu]->csdev->mode)) etm4_enable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; @@ -1675,7 +1673,7 @@ static int etm4_dying_cpu(unsigned int cpu) return 0; spin_lock(&etmdrvdata[cpu]->spinlock); - if (local_read(&etmdrvdata[cpu]->mode)) + if (local_read(&etmdrvdata[cpu]->csdev->mode)) etm4_disable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; @@ -1833,7 +1831,7 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata) * Save and restore the ETM Trace registers only if * the ETM is active. */ - if (local_read(&drvdata->mode) && drvdata->save_state) + if (local_read(&drvdata->csdev->mode) && drvdata->save_state) ret = __etm4_cpu_save(drvdata); return ret; } diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index da17b6c49b0f1..9ea678bc2e8e5 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -1016,7 +1016,6 @@ struct etmv4_drvdata { void __iomem *base; struct coresight_device *csdev; spinlock_t spinlock; - local_t mode; int cpu; u8 arch; u8 nr_pe; diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 891ee64efed87..f7fc645ea7a48 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -119,7 +119,6 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm"); * @spinlock: only one at a time pls. * @chs: the channels accociated to this STM. * @stm: structure associated to the generic STM interface. - * @mode: this tracer's mode (enum cs_mode), i.e sysFS, or disabled. * @traceid: value of the current ID for this component. * @write_bytes: Maximus bytes this STM can write at a time. * @stmsper: settings for register STMSPER. @@ -136,7 +135,6 @@ struct stm_drvdata { spinlock_t spinlock; struct channel_space chs; struct stm_data stm; - local_t mode; u8 traceid; u32 write_bytes; u32 stmsper; @@ -201,7 +199,7 @@ static int stm_enable(struct coresight_device *csdev, struct perf_event *event, if (mode != CS_MODE_SYSFS) return -EINVAL; - val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode); + val = local_cmpxchg(&csdev->mode, CS_MODE_DISABLED, mode); /* Someone is already using the tracer */ if (val) @@ -266,7 +264,7 @@ static void stm_disable(struct coresight_device *csdev, * change its status. As such we can read the status here without * fearing it will change under us. */ - if (local_read(&drvdata->mode) == CS_MODE_SYSFS) { + if (local_read(&csdev->mode) == CS_MODE_SYSFS) { spin_lock(&drvdata->spinlock); stm_disable_hw(drvdata); spin_unlock(&drvdata->spinlock); @@ -276,7 +274,7 @@ static void stm_disable(struct coresight_device *csdev, pm_runtime_put(csdev->dev.parent); - local_set(&drvdata->mode, CS_MODE_DISABLED); + local_set(&csdev->mode, CS_MODE_DISABLED); dev_dbg(&csdev->dev, "STM tracing disabled\n"); } } @@ -373,7 +371,7 @@ static long stm_generic_set_options(struct stm_data *stm_data, { struct stm_drvdata *drvdata = container_of(stm_data, struct stm_drvdata, stm); - if (!(drvdata && local_read(&drvdata->mode))) + if (!(drvdata && local_read(&drvdata->csdev->mode))) return -EINVAL; if (channel >= drvdata->numsp) @@ -408,7 +406,7 @@ static ssize_t notrace stm_generic_packet(struct stm_data *stm_data, struct stm_drvdata, stm); unsigned int stm_flags; - if (!(drvdata && local_read(&drvdata->mode))) + if (!(drvdata && local_read(&drvdata->csdev->mode))) return -EACCES; if (channel >= drvdata->numsp) @@ -515,7 +513,7 @@ static ssize_t port_select_show(struct device *dev, struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); unsigned long val; - if (!local_read(&drvdata->mode)) { + if (!local_read(&drvdata->csdev->mode)) { val = drvdata->stmspscr; } else { spin_lock(&drvdata->spinlock); @@ -541,7 +539,7 @@ static ssize_t port_select_store(struct device *dev, spin_lock(&drvdata->spinlock); drvdata->stmspscr = val; - if (local_read(&drvdata->mode)) { + if (local_read(&drvdata->csdev->mode)) { CS_UNLOCK(drvdata->base); /* Process as per ARM's TRM recommendation */ stmsper = readl_relaxed(drvdata->base + STMSPER); @@ -562,7 +560,7 @@ static ssize_t port_enable_show(struct device *dev, struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); unsigned long val; - if (!local_read(&drvdata->mode)) { + if (!local_read(&drvdata->csdev->mode)) { val = drvdata->stmsper; } else { spin_lock(&drvdata->spinlock); @@ -588,7 +586,7 @@ static ssize_t port_enable_store(struct device *dev, spin_lock(&drvdata->spinlock); drvdata->stmsper = val; - if (local_read(&drvdata->mode)) { + if (local_read(&drvdata->csdev->mode)) { CS_UNLOCK(drvdata->base); writel_relaxed(drvdata->stmsper, drvdata->base + STMSPER); CS_LOCK(drvdata->base); diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 39bae35d4ffd3..e8b2bbed047f1 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -558,7 +558,7 @@ static void tmc_shutdown(struct amba_device *adev) spin_lock_irqsave(&drvdata->spinlock, flags); - if (drvdata->mode == CS_MODE_DISABLED) + if (local_read(&drvdata->csdev->mode) == CS_MODE_DISABLED) goto out; if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 7406b65e2cdda..2a7e516052a29 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -89,7 +89,7 @@ static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata) * When operating in sysFS mode the content of the buffer needs to be * read before the TMC is disabled. */ - if (drvdata->mode == CS_MODE_SYSFS) + if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) tmc_etb_dump_hw(drvdata); tmc_disable_hw(drvdata); @@ -205,7 +205,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) * sink is already enabled no memory is needed and the HW need not be * touched. */ - if (drvdata->mode == CS_MODE_SYSFS) { + if (local_read(&csdev->mode) == CS_MODE_SYSFS) { atomic_inc(&csdev->refcnt); goto out; } @@ -228,7 +228,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) ret = tmc_etb_enable_hw(drvdata); if (!ret) { - drvdata->mode = CS_MODE_SYSFS; + local_set(&csdev->mode, CS_MODE_SYSFS); atomic_inc(&csdev->refcnt); } else { /* Free up the buffer if we failed to enable */ @@ -262,7 +262,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) * No need to continue if the ETB/ETF is already operated * from sysFS. */ - if (drvdata->mode == CS_MODE_SYSFS) { + if (local_read(&csdev->mode) == CS_MODE_SYSFS) { ret = -EBUSY; break; } @@ -292,7 +292,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) if (!ret) { /* Associate with monitored process. */ drvdata->pid = pid; - drvdata->mode = CS_MODE_PERF; + local_set(&csdev->mode, CS_MODE_PERF); atomic_inc(&csdev->refcnt); } } while (0); @@ -344,11 +344,11 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev) } /* Complain if we (somehow) got out of sync */ - WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED); + WARN_ON_ONCE(local_read(&csdev->mode) == CS_MODE_DISABLED); tmc_etb_disable_hw(drvdata); /* Dissociate from monitored process. */ drvdata->pid = -1; - drvdata->mode = CS_MODE_DISABLED; + local_set(&csdev->mode, CS_MODE_DISABLED); spin_unlock_irqrestore(&drvdata->spinlock, flags); @@ -374,7 +374,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, if (atomic_read(&csdev->refcnt) == 0) { ret = tmc_etf_enable_hw(drvdata); if (!ret) { - drvdata->mode = CS_MODE_SYSFS; + local_set(&csdev->mode, CS_MODE_SYSFS); first_enable = true; } } @@ -403,7 +403,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev, if (atomic_dec_return(&csdev->refcnt) == 0) { tmc_etf_disable_hw(drvdata); - drvdata->mode = CS_MODE_DISABLED; + local_set(&csdev->mode, CS_MODE_DISABLED); last_disable = true; } spin_unlock_irqrestore(&drvdata->spinlock, flags); @@ -483,7 +483,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev, return 0; /* This shouldn't happen */ - if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF)) + if (WARN_ON_ONCE(local_read(&csdev->mode) != CS_MODE_PERF)) return 0; spin_lock_irqsave(&drvdata->spinlock, flags); @@ -629,7 +629,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) } /* Don't interfere if operated from Perf */ - if (drvdata->mode == CS_MODE_PERF) { + if (local_read(&drvdata->csdev->mode) == CS_MODE_PERF) { ret = -EINVAL; goto out; } @@ -641,7 +641,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) } /* Disable the TMC if need be */ - if (drvdata->mode == CS_MODE_SYSFS) { + if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) { /* There is no point in reading a TMC in HW FIFO mode */ mode = readl_relaxed(drvdata->base + TMC_MODE); if (mode != TMC_MODE_CIRCULAR_BUFFER) { @@ -673,7 +673,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata) spin_lock_irqsave(&drvdata->spinlock, flags); /* Re-enable the TMC if need be */ - if (drvdata->mode == CS_MODE_SYSFS) { + if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) { /* There is no point in reading a TMC in HW FIFO mode */ mode = readl_relaxed(drvdata->base + TMC_MODE); if (mode != TMC_MODE_CIRCULAR_BUFFER) { diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index af02ba5d5f15d..3dc989d4fcabc 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1143,7 +1143,7 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata) * When operating in sysFS mode the content of the buffer needs to be * read before the TMC is disabled. */ - if (drvdata->mode == CS_MODE_SYSFS) + if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) tmc_etr_sync_sysfs_buf(drvdata); tmc_disable_hw(drvdata); @@ -1189,7 +1189,7 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev) spin_lock_irqsave(&drvdata->spinlock, flags); } - if (drvdata->reading || drvdata->mode == CS_MODE_PERF) { + if (drvdata->reading || local_read(&csdev->mode) == CS_MODE_PERF) { ret = -EBUSY; goto out; } @@ -1230,14 +1230,14 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) * sink is already enabled no memory is needed and the HW need not be * touched, even if the buffer size has changed. */ - if (drvdata->mode == CS_MODE_SYSFS) { + if (local_read(&csdev->mode) == CS_MODE_SYSFS) { atomic_inc(&csdev->refcnt); goto out; } ret = tmc_etr_enable_hw(drvdata, sysfs_buf); if (!ret) { - drvdata->mode = CS_MODE_SYSFS; + local_set(&csdev->mode, CS_MODE_SYSFS); atomic_inc(&csdev->refcnt); } @@ -1652,7 +1652,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) spin_lock_irqsave(&drvdata->spinlock, flags); /* Don't use this sink if it is already claimed by sysFS */ - if (drvdata->mode == CS_MODE_SYSFS) { + if (local_read(&csdev->mode) == CS_MODE_SYSFS) { rc = -EBUSY; goto unlock_out; } @@ -1684,7 +1684,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) if (!rc) { /* Associate with monitored process. */ drvdata->pid = pid; - drvdata->mode = CS_MODE_PERF; + local_set(&csdev->mode, CS_MODE_PERF); drvdata->perf_buf = etr_perf->etr_buf; atomic_inc(&csdev->refcnt); } @@ -1725,11 +1725,11 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) } /* Complain if we (somehow) got out of sync */ - WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED); + WARN_ON_ONCE(local_read(&csdev->mode) == CS_MODE_DISABLED); tmc_etr_disable_hw(drvdata); /* Dissociate from monitored process. */ drvdata->pid = -1; - drvdata->mode = CS_MODE_DISABLED; + local_set(&csdev->mode, CS_MODE_DISABLED); /* Reset perf specific data */ drvdata->perf_buf = NULL; @@ -1777,7 +1777,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) } /* Disable the TMC if we are trying to read from a running session. */ - if (drvdata->mode == CS_MODE_SYSFS) + if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) __tmc_etr_disable_hw(drvdata); drvdata->reading = true; @@ -1799,7 +1799,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) spin_lock_irqsave(&drvdata->spinlock, flags); /* RE-enable the TMC if need be */ - if (drvdata->mode == CS_MODE_SYSFS) { + if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) { /* * The trace run will continue with the same allocated trace * buffer. Since the tracer is still enabled drvdata::buf can't diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 8dcb426ac3e7a..cef979c897e62 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -178,7 +178,6 @@ struct etr_buf { * @size: trace buffer size for this TMC (common for all modes). * @max_burst_size: The maximum burst size that can be initiated by * TMC-ETR on AXI bus. - * @mode: how this TMC is being used. * @config_type: TMC variant, must be of type @tmc_config_type. * @memwidth: width of the memory interface databus, in bytes. * @trigger_cntr: amount of words to store after a trigger. @@ -203,7 +202,6 @@ struct tmc_drvdata { u32 len; u32 size; u32 max_burst_size; - u32 mode; enum tmc_config_type config_type; enum tmc_mem_intf_width memwidth; u32 trigger_cntr; diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c index f0b6806202d19..bef633960173e 100644 --- a/drivers/hwtracing/coresight/ultrasoc-smb.c +++ b/drivers/hwtracing/coresight/ultrasoc-smb.c @@ -207,11 +207,11 @@ static void smb_enable_sysfs(struct coresight_device *csdev) { struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent); - if (drvdata->mode != CS_MODE_DISABLED) + if (local_read(&csdev->mode) != CS_MODE_DISABLED) return; smb_enable_hw(drvdata); - drvdata->mode = CS_MODE_SYSFS; + local_set(&csdev->mode, CS_MODE_SYSFS); } static int smb_enable_perf(struct coresight_device *csdev, void *data) @@ -234,7 +234,7 @@ static int smb_enable_perf(struct coresight_device *csdev, void *data) if (drvdata->pid == -1) { smb_enable_hw(drvdata); drvdata->pid = pid; - drvdata->mode = CS_MODE_PERF; + local_set(&csdev->mode, CS_MODE_PERF); } return 0; @@ -253,7 +253,8 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode, return -EBUSY; /* Do nothing, the SMB is already enabled as other mode */ - if (drvdata->mode != CS_MODE_DISABLED && drvdata->mode != mode) + if (local_read(&csdev->mode) != CS_MODE_DISABLED && + local_read(&csdev->mode) != mode) return -EBUSY; switch (mode) { @@ -289,13 +290,13 @@ static int smb_disable(struct coresight_device *csdev) return -EBUSY; /* Complain if we (somehow) got out of sync */ - WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED); + WARN_ON_ONCE(local_read(&csdev->mode) == CS_MODE_DISABLED); smb_disable_hw(drvdata); /* Dissociate from the target process. */ drvdata->pid = -1; - drvdata->mode = CS_MODE_DISABLED; + local_set(&csdev->mode, CS_MODE_DISABLED); dev_dbg(&csdev->dev, "Ultrasoc SMB disabled\n"); return 0; diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.h b/drivers/hwtracing/coresight/ultrasoc-smb.h index 82a44c14a8829..a91d39cfccb8f 100644 --- a/drivers/hwtracing/coresight/ultrasoc-smb.h +++ b/drivers/hwtracing/coresight/ultrasoc-smb.h @@ -109,7 +109,6 @@ struct smb_data_buffer { * @reading: Synchronise user space access to SMB buffer. * @pid: Process ID of the process being monitored by the * session that is using this component. - * @mode: How this SMB is being used, perf mode or sysfs mode. */ struct smb_drv_data { void __iomem *base; @@ -119,7 +118,6 @@ struct smb_drv_data { spinlock_t spinlock; bool reading; pid_t pid; - enum cs_mode mode; }; #endif diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 516ab45ff3c28..01f67862ea2f1 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -226,6 +226,11 @@ struct coresight_sysfs_link { * by @coresight_ops. * @access: Device i/o access abstraction for this device. * @dev: The device entity associated to this component. + * @mode: This tracer's mode, i.e sysFS, Perf or disabled. This is + * actually an 'enum cs_mode', but is stored in an atomic type. + * This is always accessed through local_read() and local_set(), + * but wherever it's done from within the Coresight device's lock, + * a non-atomic read would also work. * @refcnt: keep track of what is in use. * @orphan: true if the component has connections that haven't been linked. * @enable: 'true' if component is currently part of an active path. @@ -252,6 +257,7 @@ struct coresight_device { const struct coresight_ops *ops; struct csdev_access access; struct device dev; + local_t mode; atomic_t refcnt; bool orphan; bool enable; From d5e83f97eb5669bfdd894ec980083f65517df2fb Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 29 Jan 2024 15:40:36 +0000 Subject: [PATCH 10/32] coresight: Remove the 'enable' field. 'enable', which probably should have been 'enabled', is only ever read in the core code in relation to controlling sources, and specifically only sources in sysfs mode. Confusingly it's not labelled as such and relying on it can be a source of bugs like the one fixed by commit 078dbba3f0c9 ("coresight: Fix crash when Perf and sysfs modes are used concurrently"). Most importantly, it can only be used when the coresight_mutex is held which is only done when enabling and disabling paths in sysfs mode, and not Perf mode. So to prevent its usage spreading and leaking out to other devices, remove it. It's use is equivalent to checking if the mode is currently sysfs, as due to the coresight_mutex lock, mode == CS_MODE_SYSFS can only become true or untrue when that lock is held, and when mode == CS_MODE_SYSFS the device is both enabled and in sysfs mode. The one place it was used outside of the core code is in TPDA, but that pattern is more appropriately represented using refcounts inside the device's own spinlock. Signed-off-by: James Clark Link: https://lore.kernel.org/r/20240129154050.569566-6-james.clark@arm.com Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-core.c | 86 +++++++------------- drivers/hwtracing/coresight/coresight-tpda.c | 12 ++- include/linux/coresight.h | 2 - 3 files changed, 38 insertions(+), 62 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 5e93b52df105a..b8d6520d47c94 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -279,29 +279,18 @@ EXPORT_SYMBOL_GPL(coresight_add_helper); static int coresight_enable_sink(struct coresight_device *csdev, enum cs_mode mode, void *data) { - int ret = sink_ops(csdev)->enable(csdev, mode, data); - - if (ret) - return ret; - - csdev->enable = true; - - return 0; + return sink_ops(csdev)->enable(csdev, mode, data); } static void coresight_disable_sink(struct coresight_device *csdev) { - int ret = sink_ops(csdev)->disable(csdev); - if (ret) - return; - csdev->enable = false; + sink_ops(csdev)->disable(csdev); } static int coresight_enable_link(struct coresight_device *csdev, struct coresight_device *parent, struct coresight_device *child) { - int ret = 0; int link_subtype; struct coresight_connection *inconn, *outconn; @@ -317,19 +306,13 @@ static int coresight_enable_link(struct coresight_device *csdev, if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn)) return PTR_ERR(outconn); - ret = link_ops(csdev)->enable(csdev, inconn, outconn); - if (!ret) - csdev->enable = true; - - return ret; + return link_ops(csdev)->enable(csdev, inconn, outconn); } static void coresight_disable_link(struct coresight_device *csdev, struct coresight_device *parent, struct coresight_device *child) { - int i; - int link_subtype; struct coresight_connection *inconn, *outconn; if (!parent || !child) @@ -337,26 +320,8 @@ static void coresight_disable_link(struct coresight_device *csdev, inconn = coresight_find_out_connection(parent, csdev); outconn = coresight_find_out_connection(csdev, child); - link_subtype = csdev->subtype.link_subtype; link_ops(csdev)->disable(csdev, inconn, outconn); - - if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) { - for (i = 0; i < csdev->pdata->nr_inconns; i++) - if (atomic_read(&csdev->pdata->in_conns[i]->dest_refcnt) != - 0) - return; - } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) { - for (i = 0; i < csdev->pdata->nr_outconns; i++) - if (atomic_read(&csdev->pdata->out_conns[i]->src_refcnt) != - 0) - return; - } else { - if (atomic_read(&csdev->refcnt) != 0) - return; - } - - csdev->enable = false; } int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, @@ -364,11 +329,16 @@ int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, { int ret; - if (!csdev->enable) { + /* + * Comparison with CS_MODE_SYSFS works without taking any device + * specific spinlock because the truthyness of that comparison can only + * change with coresight_mutex held, which we already have here. + */ + lockdep_assert_held(&coresight_mutex); + if (local_read(&csdev->mode) != CS_MODE_SYSFS) { ret = source_ops(csdev)->enable(csdev, data, mode); if (ret) return ret; - csdev->enable = true; } atomic_inc(&csdev->refcnt); @@ -385,22 +355,12 @@ static bool coresight_is_helper(struct coresight_device *csdev) static int coresight_enable_helper(struct coresight_device *csdev, enum cs_mode mode, void *data) { - int ret = helper_ops(csdev)->enable(csdev, mode, data); - - if (ret) - return ret; - - csdev->enable = true; - return 0; + return helper_ops(csdev)->enable(csdev, mode, data); } static void coresight_disable_helper(struct coresight_device *csdev) { - int ret = helper_ops(csdev)->disable(csdev, NULL); - - if (ret) - return; - csdev->enable = false; + helper_ops(csdev)->disable(csdev, NULL); } static void coresight_disable_helpers(struct coresight_device *csdev) @@ -445,11 +405,15 @@ EXPORT_SYMBOL_GPL(coresight_disable_source); static bool coresight_disable_source_sysfs(struct coresight_device *csdev, void *data) { + lockdep_assert_held(&coresight_mutex); + if (local_read(&csdev->mode) != CS_MODE_SYSFS) + return false; + if (atomic_dec_return(&csdev->refcnt) == 0) { coresight_disable_source(csdev, data); - csdev->enable = false; + return true; } - return !csdev->enable; + return false; } /* @@ -1097,7 +1061,13 @@ int coresight_enable(struct coresight_device *csdev) if (ret) goto out; - if (csdev->enable) { + /* + * mode == SYSFS implies that it's already enabled. Don't look at the + * refcount to determine this because we don't claim the source until + * coresight_enable_source() so can still race with Perf mode which + * doesn't hold coresight_mutex. + */ + if (local_read(&csdev->mode) == CS_MODE_SYSFS) { /* * There could be multiple applications driving the software * source. So keep the refcount for each such user when the @@ -1183,7 +1153,7 @@ void coresight_disable(struct coresight_device *csdev) if (ret) goto out; - if (!csdev->enable || !coresight_disable_source_sysfs(csdev, NULL)) + if (!coresight_disable_source_sysfs(csdev, NULL)) goto out; switch (csdev->subtype.source_subtype) { @@ -1249,7 +1219,9 @@ static ssize_t enable_source_show(struct device *dev, { struct coresight_device *csdev = to_coresight_device(dev); - return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->enable); + guard(mutex)(&coresight_mutex); + return scnprintf(buf, PAGE_SIZE, "%u\n", + local_read(&csdev->mode) == CS_MODE_SYSFS); } static ssize_t enable_source_store(struct device *dev, diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index 4ac954f4bc136..c813ec427b8db 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -148,7 +148,11 @@ static int __tpda_enable(struct tpda_drvdata *drvdata, int port) CS_UNLOCK(drvdata->base); - if (!drvdata->csdev->enable) + /* + * Only do pre-port enable for first port that calls enable when the + * device's main refcount is still 0 + */ + if (!atomic_read(&drvdata->csdev->refcnt)) tpda_enable_pre_port(drvdata); ret = tpda_enable_port(drvdata, port); @@ -169,6 +173,7 @@ static int tpda_enable(struct coresight_device *csdev, ret = __tpda_enable(drvdata, in->dest_port); if (!ret) { atomic_inc(&in->dest_refcnt); + atomic_inc(&csdev->refcnt); dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port); } } @@ -197,9 +202,10 @@ static void tpda_disable(struct coresight_device *csdev, struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); spin_lock(&drvdata->spinlock); - if (atomic_dec_return(&in->dest_refcnt) == 0) + if (atomic_dec_return(&in->dest_refcnt) == 0) { __tpda_disable(drvdata, in->dest_port); - + atomic_dec(&csdev->refcnt); + } spin_unlock(&drvdata->spinlock); dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port); diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 01f67862ea2f1..d1fd7070099c4 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -233,7 +233,6 @@ struct coresight_sysfs_link { * a non-atomic read would also work. * @refcnt: keep track of what is in use. * @orphan: true if the component has connections that haven't been linked. - * @enable: 'true' if component is currently part of an active path. * @sysfs_sink_activated: 'true' when a sink has been selected for use via sysfs * by writing a 1 to the 'enable_sink' file. A sink can be * activated but not yet enabled. Enabling for a _sink_ happens @@ -260,7 +259,6 @@ struct coresight_device { local_t mode; atomic_t refcnt; bool orphan; - bool enable; /* sink specific fields */ bool sysfs_sink_activated; struct dev_ext_attribute *ea; From 1f5149c7751c50aba1a871143ffa6cb36af3fb49 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 29 Jan 2024 15:40:37 +0000 Subject: [PATCH 11/32] coresight: Move all sysfs code to sysfs file At the moment the core file contains both sysfs functionality and core functionality, while the Perf mode is in a separate file in coresight-etm-perf.c Many of the functions have ambiguous names like coresight_enable_source() which actually only work in relation to the sysfs mode. To avoid further confusion, move everything that isn't core functionality into the sysfs file and append _sysfs to the ambiguous functions. Signed-off-by: James Clark Link: https://lore.kernel.org/r/20240129154050.569566-7-james.clark@arm.com Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-core.c | 394 +----------------- .../coresight/coresight-etm3x-core.c | 4 +- .../coresight/coresight-etm4x-core.c | 4 +- drivers/hwtracing/coresight/coresight-priv.h | 5 +- drivers/hwtracing/coresight/coresight-stm.c | 4 +- drivers/hwtracing/coresight/coresight-sysfs.c | 390 +++++++++++++++++ include/linux/coresight.h | 8 +- 7 files changed, 407 insertions(+), 402 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index b8d6520d47c94..b83613e342891 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -25,15 +24,12 @@ #include "coresight-priv.h" #include "coresight-syscfg.h" -static DEFINE_MUTEX(coresight_mutex); -static DEFINE_PER_CPU(struct coresight_device *, csdev_sink); - /* - * Use IDR to map the hash of the source's device name - * to the pointer of path for the source. The idr is for - * the sources which aren't associated with CPU. + * Mutex used to lock all sysfs enable and disable actions and loading and + * unloading devices by the Coresight core. */ -static DEFINE_IDR(path_idr); +DEFINE_MUTEX(coresight_mutex); +static DEFINE_PER_CPU(struct coresight_device *, csdev_sink); /** * struct coresight_node - elements of a path, from source to sink @@ -45,12 +41,6 @@ struct coresight_node { struct list_head link; }; -/* - * When operating Coresight drivers from the sysFS interface, only a single - * path can exist from a tracer (associated to a CPU) to a sink. - */ -static DEFINE_PER_CPU(struct list_head *, tracer_path); - /* * When losing synchronisation a new barrier packet needs to be inserted at the * beginning of the data collected in a buffer. That way the decoder knows that @@ -61,34 +51,6 @@ EXPORT_SYMBOL_GPL(coresight_barrier_pkt); static const struct cti_assoc_op *cti_assoc_ops; -ssize_t coresight_simple_show_pair(struct device *_dev, - struct device_attribute *attr, char *buf) -{ - struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); - struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr); - u64 val; - - pm_runtime_get_sync(_dev->parent); - val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off); - pm_runtime_put_sync(_dev->parent); - return sysfs_emit(buf, "0x%llx\n", val); -} -EXPORT_SYMBOL_GPL(coresight_simple_show_pair); - -ssize_t coresight_simple_show32(struct device *_dev, - struct device_attribute *attr, char *buf) -{ - struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); - struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr); - u64 val; - - pm_runtime_get_sync(_dev->parent); - val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off); - pm_runtime_put_sync(_dev->parent); - return sysfs_emit(buf, "0x%llx\n", val); -} -EXPORT_SYMBOL_GPL(coresight_simple_show32); - void coresight_set_cti_ops(const struct cti_assoc_op *cti_op) { cti_assoc_ops = cti_op; @@ -324,29 +286,6 @@ static void coresight_disable_link(struct coresight_device *csdev, link_ops(csdev)->disable(csdev, inconn, outconn); } -int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, - void *data) -{ - int ret; - - /* - * Comparison with CS_MODE_SYSFS works without taking any device - * specific spinlock because the truthyness of that comparison can only - * change with coresight_mutex held, which we already have here. - */ - lockdep_assert_held(&coresight_mutex); - if (local_read(&csdev->mode) != CS_MODE_SYSFS) { - ret = source_ops(csdev)->enable(csdev, data, mode); - if (ret) - return ret; - } - - atomic_inc(&csdev->refcnt); - - return 0; -} -EXPORT_SYMBOL_GPL(coresight_enable_source); - static bool coresight_is_helper(struct coresight_device *csdev) { return csdev->type == CORESIGHT_DEV_TYPE_HELPER; @@ -392,30 +331,6 @@ void coresight_disable_source(struct coresight_device *csdev, void *data) } EXPORT_SYMBOL_GPL(coresight_disable_source); -/** - * coresight_disable_source_sysfs - Drop the reference count by 1 and disable - * the device if there are no users left. - * - * @csdev: The coresight device to disable - * @data: Opaque data to pass on to the disable function of the source device. - * For example in perf mode this is a pointer to the struct perf_event. - * - * Returns true if the device has been disabled. - */ -static bool coresight_disable_source_sysfs(struct coresight_device *csdev, - void *data) -{ - lockdep_assert_held(&coresight_mutex); - if (local_read(&csdev->mode) != CS_MODE_SYSFS) - return false; - - if (atomic_dec_return(&csdev->refcnt) == 0) { - coresight_disable_source(csdev, data); - return true; - } - return false; -} - /* * coresight_disable_path_from : Disable components in the given path beyond * @nd in the list. If @nd is NULL, all the components, except the SOURCE are @@ -572,39 +487,6 @@ struct coresight_device *coresight_get_sink(struct list_head *path) return csdev; } -/** - * coresight_find_activated_sysfs_sink - returns the first sink activated via - * sysfs using connection based search starting from the source reference. - * - * @csdev: Coresight source device reference - */ -static struct coresight_device * -coresight_find_activated_sysfs_sink(struct coresight_device *csdev) -{ - int i; - struct coresight_device *sink = NULL; - - if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || - csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && - csdev->sysfs_sink_activated) - return csdev; - - /* - * Recursively explore each port found on this element. - */ - for (i = 0; i < csdev->pdata->nr_outconns; i++) { - struct coresight_device *child_dev; - - child_dev = csdev->pdata->out_conns[i]->dest_dev; - if (child_dev) - sink = coresight_find_activated_sysfs_sink(child_dev); - if (sink) - return sink; - } - - return NULL; -} - static int coresight_sink_by_id(struct device *dev, const void *data) { struct coresight_device *csdev = to_coresight_device(dev); @@ -1015,274 +897,6 @@ static void coresight_clear_default_sink(struct coresight_device *csdev) } } -/** coresight_validate_source - make sure a source has the right credentials - * @csdev: the device structure for a source. - * @function: the function this was called from. - * - * Assumes the coresight_mutex is held. - */ -static int coresight_validate_source(struct coresight_device *csdev, - const char *function) -{ - u32 type, subtype; - - type = csdev->type; - subtype = csdev->subtype.source_subtype; - - if (type != CORESIGHT_DEV_TYPE_SOURCE) { - dev_err(&csdev->dev, "wrong device type in %s\n", function); - return -EINVAL; - } - - if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC && - subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE && - subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM && - subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) { - dev_err(&csdev->dev, "wrong device subtype in %s\n", function); - return -EINVAL; - } - - return 0; -} - -int coresight_enable(struct coresight_device *csdev) -{ - int cpu, ret = 0; - struct coresight_device *sink; - struct list_head *path; - enum coresight_dev_subtype_source subtype; - u32 hash; - - subtype = csdev->subtype.source_subtype; - - mutex_lock(&coresight_mutex); - - ret = coresight_validate_source(csdev, __func__); - if (ret) - goto out; - - /* - * mode == SYSFS implies that it's already enabled. Don't look at the - * refcount to determine this because we don't claim the source until - * coresight_enable_source() so can still race with Perf mode which - * doesn't hold coresight_mutex. - */ - if (local_read(&csdev->mode) == CS_MODE_SYSFS) { - /* - * There could be multiple applications driving the software - * source. So keep the refcount for each such user when the - * source is already enabled. - */ - if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) - atomic_inc(&csdev->refcnt); - goto out; - } - - sink = coresight_find_activated_sysfs_sink(csdev); - if (!sink) { - ret = -EINVAL; - goto out; - } - - path = coresight_build_path(csdev, sink); - if (IS_ERR(path)) { - pr_err("building path(s) failed\n"); - ret = PTR_ERR(path); - goto out; - } - - ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL); - if (ret) - goto err_path; - - ret = coresight_enable_source(csdev, CS_MODE_SYSFS, NULL); - if (ret) - goto err_source; - - switch (subtype) { - case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: - /* - * When working from sysFS it is important to keep track - * of the paths that were created so that they can be - * undone in 'coresight_disable()'. Since there can only - * be a single session per tracer (when working from sysFS) - * a per-cpu variable will do just fine. - */ - cpu = source_ops(csdev)->cpu_id(csdev); - per_cpu(tracer_path, cpu) = path; - break; - case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: - case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM: - case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS: - /* - * Use the hash of source's device name as ID - * and map the ID to the pointer of the path. - */ - hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev))); - ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL); - if (ret) - goto err_source; - break; - default: - /* We can't be here */ - break; - } - -out: - mutex_unlock(&coresight_mutex); - return ret; - -err_source: - coresight_disable_path(path); - -err_path: - coresight_release_path(path); - goto out; -} -EXPORT_SYMBOL_GPL(coresight_enable); - -void coresight_disable(struct coresight_device *csdev) -{ - int cpu, ret; - struct list_head *path = NULL; - u32 hash; - - mutex_lock(&coresight_mutex); - - ret = coresight_validate_source(csdev, __func__); - if (ret) - goto out; - - if (!coresight_disable_source_sysfs(csdev, NULL)) - goto out; - - switch (csdev->subtype.source_subtype) { - case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: - cpu = source_ops(csdev)->cpu_id(csdev); - path = per_cpu(tracer_path, cpu); - per_cpu(tracer_path, cpu) = NULL; - break; - case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: - case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM: - case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS: - hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev))); - /* Find the path by the hash. */ - path = idr_find(&path_idr, hash); - if (path == NULL) { - pr_err("Path is not found for %s\n", dev_name(&csdev->dev)); - goto out; - } - idr_remove(&path_idr, hash); - break; - default: - /* We can't be here */ - break; - } - - coresight_disable_path(path); - coresight_release_path(path); - -out: - mutex_unlock(&coresight_mutex); -} -EXPORT_SYMBOL_GPL(coresight_disable); - -static ssize_t enable_sink_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct coresight_device *csdev = to_coresight_device(dev); - - return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->sysfs_sink_activated); -} - -static ssize_t enable_sink_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - int ret; - unsigned long val; - struct coresight_device *csdev = to_coresight_device(dev); - - ret = kstrtoul(buf, 10, &val); - if (ret) - return ret; - - csdev->sysfs_sink_activated = !!val; - - return size; - -} -static DEVICE_ATTR_RW(enable_sink); - -static ssize_t enable_source_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct coresight_device *csdev = to_coresight_device(dev); - - guard(mutex)(&coresight_mutex); - return scnprintf(buf, PAGE_SIZE, "%u\n", - local_read(&csdev->mode) == CS_MODE_SYSFS); -} - -static ssize_t enable_source_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - int ret = 0; - unsigned long val; - struct coresight_device *csdev = to_coresight_device(dev); - - ret = kstrtoul(buf, 10, &val); - if (ret) - return ret; - - if (val) { - ret = coresight_enable(csdev); - if (ret) - return ret; - } else { - coresight_disable(csdev); - } - - return size; -} -static DEVICE_ATTR_RW(enable_source); - -static struct attribute *coresight_sink_attrs[] = { - &dev_attr_enable_sink.attr, - NULL, -}; -ATTRIBUTE_GROUPS(coresight_sink); - -static struct attribute *coresight_source_attrs[] = { - &dev_attr_enable_source.attr, - NULL, -}; -ATTRIBUTE_GROUPS(coresight_source); - -static struct device_type coresight_dev_type[] = { - { - .name = "sink", - .groups = coresight_sink_groups, - }, - { - .name = "link", - }, - { - .name = "linksink", - .groups = coresight_sink_groups, - }, - { - .name = "source", - .groups = coresight_source_groups, - }, - { - .name = "helper", - } -}; -/* Ensure the enum matches the names and groups */ -static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX); - static void coresight_device_release(struct device *dev) { struct coresight_device *csdev = to_coresight_device(dev); diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index 333d0a32c95c8..de53c3e8db291 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -714,7 +714,7 @@ static int etm_online_cpu(unsigned int cpu) return 0; if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) - coresight_enable(etmdrvdata[cpu]->csdev); + coresight_enable_sysfs(etmdrvdata[cpu]->csdev); return 0; } @@ -924,7 +924,7 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id) dev_info(&drvdata->csdev->dev, "%s initialized\n", (char *)coresight_get_uci_data(id)); if (boot_enable) { - coresight_enable(drvdata->csdev); + coresight_enable_sysfs(drvdata->csdev); drvdata->boot_enable = true; } diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 7ceff627cd958..1c64b54459d7e 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1648,7 +1648,7 @@ static int etm4_online_cpu(unsigned int cpu) return etm4_probe_cpu(cpu); if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) - coresight_enable(etmdrvdata[cpu]->csdev); + coresight_enable_sysfs(etmdrvdata[cpu]->csdev); return 0; } @@ -2096,7 +2096,7 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg) drvdata->cpu, type_name, major, minor); if (boot_enable) { - coresight_enable(drvdata->csdev); + coresight_enable_sysfs(drvdata->csdev); drvdata->boot_enable = true; } diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index ced5be05a527e..eb365236f9a97 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -12,6 +12,9 @@ #include #include +extern struct mutex coresight_mutex; +extern struct device_type coresight_dev_type[]; + /* * Coresight management registers (0xf00-0xfcc) * 0xfa0 - 0xfa4: Management registers in PFTv1.0 @@ -229,8 +232,6 @@ void coresight_add_helper(struct coresight_device *csdev, void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev); struct coresight_device *coresight_get_percpu_sink(int cpu); -int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, - void *data); void coresight_disable_source(struct coresight_device *csdev, void *data); #endif diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index f7fc645ea7a48..b2ccbe989ff81 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -332,7 +332,7 @@ static int stm_generic_link(struct stm_data *stm_data, if (!drvdata || !drvdata->csdev) return -EINVAL; - return coresight_enable(drvdata->csdev); + return coresight_enable_sysfs(drvdata->csdev); } static void stm_generic_unlink(struct stm_data *stm_data, @@ -343,7 +343,7 @@ static void stm_generic_unlink(struct stm_data *stm_data, if (!drvdata || !drvdata->csdev) return; - coresight_disable(drvdata->csdev); + coresight_disable_sysfs(drvdata->csdev); } static phys_addr_t diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c index dd78e9fcfc4dc..92cdf8139f23f 100644 --- a/drivers/hwtracing/coresight/coresight-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-sysfs.c @@ -5,10 +5,400 @@ */ #include +#include #include #include "coresight-priv.h" +/* + * Use IDR to map the hash of the source's device name + * to the pointer of path for the source. The idr is for + * the sources which aren't associated with CPU. + */ +static DEFINE_IDR(path_idr); + +/* + * When operating Coresight drivers from the sysFS interface, only a single + * path can exist from a tracer (associated to a CPU) to a sink. + */ +static DEFINE_PER_CPU(struct list_head *, tracer_path); + +ssize_t coresight_simple_show_pair(struct device *_dev, + struct device_attribute *attr, char *buf) +{ + struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); + struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr); + u64 val; + + pm_runtime_get_sync(_dev->parent); + val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off); + pm_runtime_put_sync(_dev->parent); + return sysfs_emit(buf, "0x%llx\n", val); +} +EXPORT_SYMBOL_GPL(coresight_simple_show_pair); + +ssize_t coresight_simple_show32(struct device *_dev, + struct device_attribute *attr, char *buf) +{ + struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); + struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr); + u64 val; + + pm_runtime_get_sync(_dev->parent); + val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off); + pm_runtime_put_sync(_dev->parent); + return sysfs_emit(buf, "0x%llx\n", val); +} +EXPORT_SYMBOL_GPL(coresight_simple_show32); + +static int coresight_enable_source_sysfs(struct coresight_device *csdev, + enum cs_mode mode, void *data) +{ + int ret; + + /* + * Comparison with CS_MODE_SYSFS works without taking any device + * specific spinlock because the truthyness of that comparison can only + * change with coresight_mutex held, which we already have here. + */ + lockdep_assert_held(&coresight_mutex); + if (local_read(&csdev->mode) != CS_MODE_SYSFS) { + ret = source_ops(csdev)->enable(csdev, data, mode); + if (ret) + return ret; + } + + atomic_inc(&csdev->refcnt); + + return 0; +} + +/** + * coresight_disable_source_sysfs - Drop the reference count by 1 and disable + * the device if there are no users left. + * + * @csdev: The coresight device to disable + * @data: Opaque data to pass on to the disable function of the source device. + * For example in perf mode this is a pointer to the struct perf_event. + * + * Returns true if the device has been disabled. + */ +static bool coresight_disable_source_sysfs(struct coresight_device *csdev, + void *data) +{ + lockdep_assert_held(&coresight_mutex); + if (local_read(&csdev->mode) != CS_MODE_SYSFS) + return false; + + if (atomic_dec_return(&csdev->refcnt) == 0) { + coresight_disable_source(csdev, data); + return true; + } + return false; +} + +/** + * coresight_find_activated_sysfs_sink - returns the first sink activated via + * sysfs using connection based search starting from the source reference. + * + * @csdev: Coresight source device reference + */ +static struct coresight_device * +coresight_find_activated_sysfs_sink(struct coresight_device *csdev) +{ + int i; + struct coresight_device *sink = NULL; + + if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || + csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && + csdev->sysfs_sink_activated) + return csdev; + + /* + * Recursively explore each port found on this element. + */ + for (i = 0; i < csdev->pdata->nr_outconns; i++) { + struct coresight_device *child_dev; + + child_dev = csdev->pdata->out_conns[i]->dest_dev; + if (child_dev) + sink = coresight_find_activated_sysfs_sink(child_dev); + if (sink) + return sink; + } + + return NULL; +} + +/** coresight_validate_source - make sure a source has the right credentials to + * be used via sysfs. + * @csdev: the device structure for a source. + * @function: the function this was called from. + * + * Assumes the coresight_mutex is held. + */ +static int coresight_validate_source_sysfs(struct coresight_device *csdev, + const char *function) +{ + u32 type, subtype; + + type = csdev->type; + subtype = csdev->subtype.source_subtype; + + if (type != CORESIGHT_DEV_TYPE_SOURCE) { + dev_err(&csdev->dev, "wrong device type in %s\n", function); + return -EINVAL; + } + + if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC && + subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE && + subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM && + subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) { + dev_err(&csdev->dev, "wrong device subtype in %s\n", function); + return -EINVAL; + } + + return 0; +} + +int coresight_enable_sysfs(struct coresight_device *csdev) +{ + int cpu, ret = 0; + struct coresight_device *sink; + struct list_head *path; + enum coresight_dev_subtype_source subtype; + u32 hash; + + subtype = csdev->subtype.source_subtype; + + mutex_lock(&coresight_mutex); + + ret = coresight_validate_source_sysfs(csdev, __func__); + if (ret) + goto out; + + /* + * mode == SYSFS implies that it's already enabled. Don't look at the + * refcount to determine this because we don't claim the source until + * coresight_enable_source() so can still race with Perf mode which + * doesn't hold coresight_mutex. + */ + if (local_read(&csdev->mode) == CS_MODE_SYSFS) { + /* + * There could be multiple applications driving the software + * source. So keep the refcount for each such user when the + * source is already enabled. + */ + if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) + atomic_inc(&csdev->refcnt); + goto out; + } + + sink = coresight_find_activated_sysfs_sink(csdev); + if (!sink) { + ret = -EINVAL; + goto out; + } + + path = coresight_build_path(csdev, sink); + if (IS_ERR(path)) { + pr_err("building path(s) failed\n"); + ret = PTR_ERR(path); + goto out; + } + + ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL); + if (ret) + goto err_path; + + ret = coresight_enable_source_sysfs(csdev, CS_MODE_SYSFS, NULL); + if (ret) + goto err_source; + + switch (subtype) { + case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: + /* + * When working from sysFS it is important to keep track + * of the paths that were created so that they can be + * undone in 'coresight_disable()'. Since there can only + * be a single session per tracer (when working from sysFS) + * a per-cpu variable will do just fine. + */ + cpu = source_ops(csdev)->cpu_id(csdev); + per_cpu(tracer_path, cpu) = path; + break; + case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: + case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM: + case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS: + /* + * Use the hash of source's device name as ID + * and map the ID to the pointer of the path. + */ + hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev))); + ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL); + if (ret) + goto err_source; + break; + default: + /* We can't be here */ + break; + } + +out: + mutex_unlock(&coresight_mutex); + return ret; + +err_source: + coresight_disable_path(path); + +err_path: + coresight_release_path(path); + goto out; +} +EXPORT_SYMBOL_GPL(coresight_enable_sysfs); + +void coresight_disable_sysfs(struct coresight_device *csdev) +{ + int cpu, ret; + struct list_head *path = NULL; + u32 hash; + + mutex_lock(&coresight_mutex); + + ret = coresight_validate_source_sysfs(csdev, __func__); + if (ret) + goto out; + + if (!coresight_disable_source_sysfs(csdev, NULL)) + goto out; + + switch (csdev->subtype.source_subtype) { + case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: + cpu = source_ops(csdev)->cpu_id(csdev); + path = per_cpu(tracer_path, cpu); + per_cpu(tracer_path, cpu) = NULL; + break; + case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: + case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM: + case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS: + hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev))); + /* Find the path by the hash. */ + path = idr_find(&path_idr, hash); + if (path == NULL) { + pr_err("Path is not found for %s\n", dev_name(&csdev->dev)); + goto out; + } + idr_remove(&path_idr, hash); + break; + default: + /* We can't be here */ + break; + } + + coresight_disable_path(path); + coresight_release_path(path); + +out: + mutex_unlock(&coresight_mutex); +} +EXPORT_SYMBOL_GPL(coresight_disable_sysfs); + +static ssize_t enable_sink_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct coresight_device *csdev = to_coresight_device(dev); + + return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->sysfs_sink_activated); +} + +static ssize_t enable_sink_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int ret; + unsigned long val; + struct coresight_device *csdev = to_coresight_device(dev); + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + csdev->sysfs_sink_activated = !!val; + + return size; + +} +static DEVICE_ATTR_RW(enable_sink); + +static ssize_t enable_source_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct coresight_device *csdev = to_coresight_device(dev); + + guard(mutex)(&coresight_mutex); + return scnprintf(buf, PAGE_SIZE, "%u\n", + local_read(&csdev->mode) == CS_MODE_SYSFS); +} + +static ssize_t enable_source_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int ret = 0; + unsigned long val; + struct coresight_device *csdev = to_coresight_device(dev); + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + if (val) { + ret = coresight_enable_sysfs(csdev); + if (ret) + return ret; + } else { + coresight_disable_sysfs(csdev); + } + + return size; +} +static DEVICE_ATTR_RW(enable_source); + +static struct attribute *coresight_sink_attrs[] = { + &dev_attr_enable_sink.attr, + NULL, +}; +ATTRIBUTE_GROUPS(coresight_sink); + +static struct attribute *coresight_source_attrs[] = { + &dev_attr_enable_source.attr, + NULL, +}; +ATTRIBUTE_GROUPS(coresight_source); + +struct device_type coresight_dev_type[] = { + { + .name = "sink", + .groups = coresight_sink_groups, + }, + { + .name = "link", + }, + { + .name = "linksink", + .groups = coresight_sink_groups, + }, + { + .name = "source", + .groups = coresight_source_groups, + }, + { + .name = "helper", + } +}; +/* Ensure the enum matches the names and groups */ +static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX); + /* * Connections group - links attribute. * Count of created links between coresight components in the group. diff --git a/include/linux/coresight.h b/include/linux/coresight.h index d1fd7070099c4..365b28022c5b8 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -578,8 +578,8 @@ static inline bool coresight_is_percpu_sink(struct coresight_device *csdev) extern struct coresight_device * coresight_register(struct coresight_desc *desc); extern void coresight_unregister(struct coresight_device *csdev); -extern int coresight_enable(struct coresight_device *csdev); -extern void coresight_disable(struct coresight_device *csdev); +extern int coresight_enable_sysfs(struct coresight_device *csdev); +extern void coresight_disable_sysfs(struct coresight_device *csdev); extern int coresight_timeout(struct csdev_access *csa, u32 offset, int position, int value); @@ -609,8 +609,8 @@ static inline struct coresight_device * coresight_register(struct coresight_desc *desc) { return NULL; } static inline void coresight_unregister(struct coresight_device *csdev) {} static inline int -coresight_enable(struct coresight_device *csdev) { return -ENOSYS; } -static inline void coresight_disable(struct coresight_device *csdev) {} +coresight_enable_sysfs(struct coresight_device *csdev) { return -ENOSYS; } +static inline void coresight_disable_sysfs(struct coresight_device *csdev) {} static inline int coresight_timeout(struct csdev_access *csa, u32 offset, int position, int value) From 4545b38ef004a586295750ea49a505b6396a7c90 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 29 Jan 2024 15:40:38 +0000 Subject: [PATCH 12/32] coresight: Remove atomic type from refcnt Refcnt is only ever accessed from either inside the coresight_mutex, or the device's spinlock, making the atomic type and atomic_dec_return() calls confusing and unnecessary. The only point of synchronisation outside of these two types of locks is already done with a compare and swap on 'mode', which a comment has been added for. There was one instance of refcnt being used outside of a lock in TPIU, but that can easily be fixed by making it the same as all the other devices and adding a spinlock. Potentially in the future all the refcounting and locking can be moved up into the core code, and all the mostly duplicate code from the individual devices can be removed. Signed-off-by: James Clark Link: https://lore.kernel.org/r/20240129154050.569566-8-james.clark@arm.com Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-etb10.c | 11 +++++----- drivers/hwtracing/coresight/coresight-sysfs.c | 7 ++++--- .../hwtracing/coresight/coresight-tmc-etf.c | 20 ++++++++++--------- .../hwtracing/coresight/coresight-tmc-etr.c | 13 ++++++------ drivers/hwtracing/coresight/coresight-tpda.c | 7 ++++--- drivers/hwtracing/coresight/coresight-tpiu.c | 14 +++++++++++-- drivers/hwtracing/coresight/ultrasoc-smb.c | 9 +++++---- include/linux/coresight.h | 13 +++++++++--- 8 files changed, 59 insertions(+), 35 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 145fb815ec1cf..306d2af47d632 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -161,7 +161,7 @@ static int etb_enable_sysfs(struct coresight_device *csdev) local_set(&csdev->mode, CS_MODE_SYSFS); } - atomic_inc(&csdev->refcnt); + csdev->refcnt++; out: spin_unlock_irqrestore(&drvdata->spinlock, flags); return ret; @@ -197,7 +197,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) * use for this session. */ if (drvdata->pid == pid) { - atomic_inc(&csdev->refcnt); + csdev->refcnt++; goto out; } @@ -215,7 +215,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) /* Associate with monitored process. */ drvdata->pid = pid; local_set(&drvdata->csdev->mode, CS_MODE_PERF); - atomic_inc(&csdev->refcnt); + csdev->refcnt++; } out: @@ -354,7 +354,8 @@ static int etb_disable(struct coresight_device *csdev) spin_lock_irqsave(&drvdata->spinlock, flags); - if (atomic_dec_return(&csdev->refcnt)) { + csdev->refcnt--; + if (csdev->refcnt) { spin_unlock_irqrestore(&drvdata->spinlock, flags); return -EBUSY; } @@ -445,7 +446,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev, spin_lock_irqsave(&drvdata->spinlock, flags); /* Don't do anything if another tracer is using this sink */ - if (atomic_read(&csdev->refcnt) != 1) + if (csdev->refcnt != 1) goto out; __etb_disable_hw(drvdata); diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c index 92cdf8139f23f..5992f2c2200a4 100644 --- a/drivers/hwtracing/coresight/coresight-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-sysfs.c @@ -68,7 +68,7 @@ static int coresight_enable_source_sysfs(struct coresight_device *csdev, return ret; } - atomic_inc(&csdev->refcnt); + csdev->refcnt++; return 0; } @@ -90,7 +90,8 @@ static bool coresight_disable_source_sysfs(struct coresight_device *csdev, if (local_read(&csdev->mode) != CS_MODE_SYSFS) return false; - if (atomic_dec_return(&csdev->refcnt) == 0) { + csdev->refcnt--; + if (csdev->refcnt == 0) { coresight_disable_source(csdev, data); return true; } @@ -190,7 +191,7 @@ int coresight_enable_sysfs(struct coresight_device *csdev) * source is already enabled. */ if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) - atomic_inc(&csdev->refcnt); + csdev->refcnt++; goto out; } diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 2a7e516052a29..f3281c958a570 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -206,7 +206,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) * touched. */ if (local_read(&csdev->mode) == CS_MODE_SYSFS) { - atomic_inc(&csdev->refcnt); + csdev->refcnt++; goto out; } @@ -229,7 +229,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) ret = tmc_etb_enable_hw(drvdata); if (!ret) { local_set(&csdev->mode, CS_MODE_SYSFS); - atomic_inc(&csdev->refcnt); + csdev->refcnt++; } else { /* Free up the buffer if we failed to enable */ used = false; @@ -284,7 +284,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) * use for this session. */ if (drvdata->pid == pid) { - atomic_inc(&csdev->refcnt); + csdev->refcnt++; break; } @@ -293,7 +293,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) /* Associate with monitored process. */ drvdata->pid = pid; local_set(&csdev->mode, CS_MODE_PERF); - atomic_inc(&csdev->refcnt); + csdev->refcnt++; } } while (0); spin_unlock_irqrestore(&drvdata->spinlock, flags); @@ -338,7 +338,8 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev) return -EBUSY; } - if (atomic_dec_return(&csdev->refcnt)) { + csdev->refcnt--; + if (csdev->refcnt) { spin_unlock_irqrestore(&drvdata->spinlock, flags); return -EBUSY; } @@ -371,7 +372,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, return -EBUSY; } - if (atomic_read(&csdev->refcnt) == 0) { + if (csdev->refcnt == 0) { ret = tmc_etf_enable_hw(drvdata); if (!ret) { local_set(&csdev->mode, CS_MODE_SYSFS); @@ -379,7 +380,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, } } if (!ret) - atomic_inc(&csdev->refcnt); + csdev->refcnt++; spin_unlock_irqrestore(&drvdata->spinlock, flags); if (first_enable) @@ -401,7 +402,8 @@ static void tmc_disable_etf_link(struct coresight_device *csdev, return; } - if (atomic_dec_return(&csdev->refcnt) == 0) { + csdev->refcnt--; + if (csdev->refcnt == 0) { tmc_etf_disable_hw(drvdata); local_set(&csdev->mode, CS_MODE_DISABLED); last_disable = true; @@ -489,7 +491,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev, spin_lock_irqsave(&drvdata->spinlock, flags); /* Don't do anything if another tracer is using this sink */ - if (atomic_read(&csdev->refcnt) != 1) + if (csdev->refcnt != 1) goto out; CS_UNLOCK(drvdata->base); diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 3dc989d4fcabc..88a0fc375b4db 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1231,14 +1231,14 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) * touched, even if the buffer size has changed. */ if (local_read(&csdev->mode) == CS_MODE_SYSFS) { - atomic_inc(&csdev->refcnt); + csdev->refcnt++; goto out; } ret = tmc_etr_enable_hw(drvdata, sysfs_buf); if (!ret) { local_set(&csdev->mode, CS_MODE_SYSFS); - atomic_inc(&csdev->refcnt); + csdev->refcnt++; } out: @@ -1564,7 +1564,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev, spin_lock_irqsave(&drvdata->spinlock, flags); /* Don't do anything if another tracer is using this sink */ - if (atomic_read(&csdev->refcnt) != 1) { + if (csdev->refcnt != 1) { spin_unlock_irqrestore(&drvdata->spinlock, flags); goto out; } @@ -1676,7 +1676,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) * use for this session. */ if (drvdata->pid == pid) { - atomic_inc(&csdev->refcnt); + csdev->refcnt++; goto unlock_out; } @@ -1686,7 +1686,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) drvdata->pid = pid; local_set(&csdev->mode, CS_MODE_PERF); drvdata->perf_buf = etr_perf->etr_buf; - atomic_inc(&csdev->refcnt); + csdev->refcnt++; } unlock_out: @@ -1719,7 +1719,8 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) return -EBUSY; } - if (atomic_dec_return(&csdev->refcnt)) { + csdev->refcnt--; + if (csdev->refcnt) { spin_unlock_irqrestore(&drvdata->spinlock, flags); return -EBUSY; } diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index c813ec427b8db..f8f6413cc7116 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -152,7 +152,8 @@ static int __tpda_enable(struct tpda_drvdata *drvdata, int port) * Only do pre-port enable for first port that calls enable when the * device's main refcount is still 0 */ - if (!atomic_read(&drvdata->csdev->refcnt)) + lockdep_assert_held(&drvdata->spinlock); + if (!drvdata->csdev->refcnt) tpda_enable_pre_port(drvdata); ret = tpda_enable_port(drvdata, port); @@ -173,7 +174,7 @@ static int tpda_enable(struct coresight_device *csdev, ret = __tpda_enable(drvdata, in->dest_port); if (!ret) { atomic_inc(&in->dest_refcnt); - atomic_inc(&csdev->refcnt); + csdev->refcnt++; dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port); } } @@ -204,7 +205,7 @@ static void tpda_disable(struct coresight_device *csdev, spin_lock(&drvdata->spinlock); if (atomic_dec_return(&in->dest_refcnt) == 0) { __tpda_disable(drvdata, in->dest_port); - atomic_dec(&csdev->refcnt); + csdev->refcnt--; } spin_unlock(&drvdata->spinlock); diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 7e69048ac9449..29024f880fda7 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -58,6 +58,7 @@ struct tpiu_drvdata { void __iomem *base; struct clk *atclk; struct coresight_device *csdev; + spinlock_t spinlock; }; static void tpiu_enable_hw(struct csdev_access *csa) @@ -72,8 +73,11 @@ static void tpiu_enable_hw(struct csdev_access *csa) static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode, void *__unused) { + struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + guard(spinlock)(&drvdata->spinlock); tpiu_enable_hw(&csdev->access); - atomic_inc(&csdev->refcnt); + csdev->refcnt++; dev_dbg(&csdev->dev, "TPIU enabled\n"); return 0; } @@ -96,7 +100,11 @@ static void tpiu_disable_hw(struct csdev_access *csa) static int tpiu_disable(struct coresight_device *csdev) { - if (atomic_dec_return(&csdev->refcnt)) + struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + guard(spinlock)(&drvdata->spinlock); + csdev->refcnt--; + if (csdev->refcnt) return -EBUSY; tpiu_disable_hw(&csdev->access); @@ -132,6 +140,8 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id) if (!drvdata) return -ENOMEM; + spin_lock_init(&drvdata->spinlock); + drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ if (!IS_ERR(drvdata->atclk)) { ret = clk_prepare_enable(drvdata->atclk); diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c index bef633960173e..a92c5b750f81e 100644 --- a/drivers/hwtracing/coresight/ultrasoc-smb.c +++ b/drivers/hwtracing/coresight/ultrasoc-smb.c @@ -103,7 +103,7 @@ static int smb_open(struct inode *inode, struct file *file) if (drvdata->reading) return -EBUSY; - if (atomic_read(&drvdata->csdev->refcnt)) + if (drvdata->csdev->refcnt) return -EBUSY; smb_update_data_size(drvdata); @@ -271,7 +271,7 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode, if (ret) return ret; - atomic_inc(&csdev->refcnt); + csdev->refcnt++; dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n"); return ret; @@ -286,7 +286,8 @@ static int smb_disable(struct coresight_device *csdev) if (drvdata->reading) return -EBUSY; - if (atomic_dec_return(&csdev->refcnt)) + csdev->refcnt--; + if (csdev->refcnt) return -EBUSY; /* Complain if we (somehow) got out of sync */ @@ -381,7 +382,7 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev, guard(spinlock)(&drvdata->spinlock); /* Don't do anything if another tracer is using this sink. */ - if (atomic_read(&csdev->refcnt) != 1) + if (csdev->refcnt != 1) return 0; smb_disable_hw(drvdata); diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 365b28022c5b8..74bcec526aa91 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -230,8 +230,15 @@ struct coresight_sysfs_link { * actually an 'enum cs_mode', but is stored in an atomic type. * This is always accessed through local_read() and local_set(), * but wherever it's done from within the Coresight device's lock, - * a non-atomic read would also work. - * @refcnt: keep track of what is in use. + * a non-atomic read would also work. This is the main point of + * synchronisation between code happening inside the sysfs mode's + * coresight_mutex and outside when running in Perf mode. A compare + * and exchange swap is done to atomically claim one mode or the + * other. + * @refcnt: keep track of what is in use. Only access this outside of the + * device's spinlock when the coresight_mutex held and mode == + * CS_MODE_SYSFS. Otherwise it must be accessed from inside the + * spinlock. * @orphan: true if the component has connections that haven't been linked. * @sysfs_sink_activated: 'true' when a sink has been selected for use via sysfs * by writing a 1 to the 'enable_sink' file. A sink can be @@ -257,7 +264,7 @@ struct coresight_device { struct csdev_access access; struct device dev; local_t mode; - atomic_t refcnt; + int refcnt; bool orphan; /* sink specific fields */ bool sysfs_sink_activated; From 053ad9ad1d13f253605d7644de3aa20d958569ef Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 29 Jan 2024 15:40:39 +0000 Subject: [PATCH 13/32] coresight: Remove unused stubs These are a bit annoying to keep up to date when the function signatures change. But if CONFIG_CORESIGHT isn't enabled, then they're not used anyway so just delete them. Signed-off-by: James Clark Link: https://lore.kernel.org/r/20240129154050.569566-9-james.clark@arm.com Signed-off-by: Suzuki K Poulose --- include/linux/coresight.h | 79 --------------------------------------- 1 file changed, 79 deletions(-) diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 74bcec526aa91..ecf4b8aecca8a 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -391,8 +391,6 @@ struct coresight_ops { const struct coresight_ops_helper *helper_ops; }; -#if IS_ENABLED(CONFIG_CORESIGHT) - static inline u32 csdev_access_relaxed_read32(struct csdev_access *csa, u32 offset) { @@ -611,83 +609,6 @@ void coresight_relaxed_write64(struct coresight_device *csdev, u64 val, u32 offset); void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset); -#else -static inline struct coresight_device * -coresight_register(struct coresight_desc *desc) { return NULL; } -static inline void coresight_unregister(struct coresight_device *csdev) {} -static inline int -coresight_enable_sysfs(struct coresight_device *csdev) { return -ENOSYS; } -static inline void coresight_disable_sysfs(struct coresight_device *csdev) {} - -static inline int coresight_timeout(struct csdev_access *csa, u32 offset, - int position, int value) -{ - return 1; -} - -static inline int coresight_claim_device_unlocked(struct coresight_device *csdev) -{ - return -EINVAL; -} - -static inline int coresight_claim_device(struct coresight_device *csdev) -{ - return -EINVAL; -} - -static inline void coresight_disclaim_device(struct coresight_device *csdev) {} -static inline void coresight_disclaim_device_unlocked(struct coresight_device *csdev) {} - -static inline bool coresight_loses_context_with_cpu(struct device *dev) -{ - return false; -} - -static inline u32 coresight_relaxed_read32(struct coresight_device *csdev, u32 offset) -{ - WARN_ON_ONCE(1); - return 0; -} - -static inline u32 coresight_read32(struct coresight_device *csdev, u32 offset) -{ - WARN_ON_ONCE(1); - return 0; -} - -static inline void coresight_write32(struct coresight_device *csdev, u32 val, u32 offset) -{ -} - -static inline void coresight_relaxed_write32(struct coresight_device *csdev, - u32 val, u32 offset) -{ -} - -static inline u64 coresight_relaxed_read64(struct coresight_device *csdev, - u32 offset) -{ - WARN_ON_ONCE(1); - return 0; -} - -static inline u64 coresight_read64(struct coresight_device *csdev, u32 offset) -{ - WARN_ON_ONCE(1); - return 0; -} - -static inline void coresight_relaxed_write64(struct coresight_device *csdev, - u64 val, u32 offset) -{ -} - -static inline void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset) -{ -} - -#endif /* IS_ENABLED(CONFIG_CORESIGHT) */ - extern int coresight_get_cpu(struct device *dev); struct coresight_platform_data *coresight_get_platform_data(struct device *dev); From 812265e26ed3ac76d3a131709d8755bafcf31b58 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 29 Jan 2024 15:40:40 +0000 Subject: [PATCH 14/32] coresight: Add explicit member initializers to coresight_dev_type These could potentially become wrong silently if the enum is changed, so explicitly initialize them. Signed-off-by: James Clark Link: https://lore.kernel.org/r/20240129154050.569566-10-james.clark@arm.com Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-sysfs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c index 5992f2c2200a4..fa52297c73d2f 100644 --- a/drivers/hwtracing/coresight/coresight-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-sysfs.c @@ -378,22 +378,22 @@ static struct attribute *coresight_source_attrs[] = { ATTRIBUTE_GROUPS(coresight_source); struct device_type coresight_dev_type[] = { - { + [CORESIGHT_DEV_TYPE_SINK] = { .name = "sink", .groups = coresight_sink_groups, }, - { + [CORESIGHT_DEV_TYPE_LINK] = { .name = "link", }, - { + [CORESIGHT_DEV_TYPE_LINKSINK] = { .name = "linksink", .groups = coresight_sink_groups, }, - { + [CORESIGHT_DEV_TYPE_SOURCE] = { .name = "source", .groups = coresight_source_groups, }, - { + [CORESIGHT_DEV_TYPE_HELPER] = { .name = "helper", } }; From d724f65218b994da234081df5dfe417c23802a65 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 29 Jan 2024 15:40:41 +0000 Subject: [PATCH 15/32] coresight: Add helper for atomically taking the device Now that mode is in struct coresight_device, this pattern can be wrapped in a helper. Signed-off-by: James Clark Link: https://lore.kernel.org/r/20240129154050.569566-11-james.clark@arm.com Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-etm3x-core.c | 8 +++----- drivers/hwtracing/coresight/coresight-etm4x-core.c | 8 +++----- drivers/hwtracing/coresight/coresight-stm.c | 8 +++----- include/linux/coresight.h | 11 +++++++++++ 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index de53c3e8db291..c301f6a5f0658 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -556,14 +556,12 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event, enum cs_mode mode) { int ret; - u32 val; struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - val = local_cmpxchg(&drvdata->csdev->mode, CS_MODE_DISABLED, mode); - - /* Someone is already using the tracer */ - if (val) + if (!coresight_take_mode(csdev, mode)) { + /* Someone is already using the tracer */ return -EBUSY; + } switch (mode) { case CS_MODE_SYSFS: diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 1c64b54459d7e..572ac4a5e4ff9 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -840,13 +840,11 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, enum cs_mode mode) { int ret; - u32 val; - val = local_cmpxchg(&csdev->mode, CS_MODE_DISABLED, mode); - - /* Someone is already using the tracer */ - if (val) + if (!coresight_take_mode(csdev, mode)) { + /* Someone is already using the tracer */ return -EBUSY; + } switch (mode) { case CS_MODE_SYSFS: diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index b2ccbe989ff81..ff578762f6bf3 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -193,17 +193,15 @@ static void stm_enable_hw(struct stm_drvdata *drvdata) static int stm_enable(struct coresight_device *csdev, struct perf_event *event, enum cs_mode mode) { - u32 val; struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); if (mode != CS_MODE_SYSFS) return -EINVAL; - val = local_cmpxchg(&csdev->mode, CS_MODE_DISABLED, mode); - - /* Someone is already using the tracer */ - if (val) + if (!coresight_take_mode(csdev, mode)) { + /* Someone is already using the tracer */ return -EBUSY; + } pm_runtime_get_sync(csdev->dev.parent); diff --git a/include/linux/coresight.h b/include/linux/coresight.h index ecf4b8aecca8a..414bcbbdaf62e 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -580,6 +580,17 @@ static inline bool coresight_is_percpu_sink(struct coresight_device *csdev) (csdev->subtype.sink_subtype == CORESIGHT_DEV_SUBTYPE_SINK_PERCPU_SYSMEM); } +/* + * Atomically try to take the device and set a new mode. Returns true on + * success, false if the device is already taken by someone else. + */ +static inline bool coresight_take_mode(struct coresight_device *csdev, + enum cs_mode new_mode) +{ + return local_cmpxchg(&csdev->mode, CS_MODE_DISABLED, new_mode) == + CS_MODE_DISABLED; +} + extern struct coresight_device * coresight_register(struct coresight_desc *desc); extern void coresight_unregister(struct coresight_device *csdev); From c95c2733e5feb1f6848923f166849b2d1c7bf682 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 29 Jan 2024 15:40:42 +0000 Subject: [PATCH 16/32] coresight: Add a helper for getting csdev->mode Now that mode is in struct coresight_device accesses can be wrapped. Signed-off-by: James Clark Link: https://lore.kernel.org/r/20240129154050.569566-12-james.clark@arm.com Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-etb10.c | 10 +++++----- .../hwtracing/coresight/coresight-etm3x-core.c | 6 +++--- .../hwtracing/coresight/coresight-etm3x-sysfs.c | 4 ++-- .../hwtracing/coresight/coresight-etm4x-core.c | 8 ++++---- drivers/hwtracing/coresight/coresight-stm.c | 14 +++++++------- drivers/hwtracing/coresight/coresight-sysfs.c | 8 ++++---- drivers/hwtracing/coresight/coresight-tmc-core.c | 2 +- drivers/hwtracing/coresight/coresight-tmc-etf.c | 16 ++++++++-------- drivers/hwtracing/coresight/coresight-tmc-etr.c | 14 +++++++------- drivers/hwtracing/coresight/ultrasoc-smb.c | 8 ++++---- include/linux/coresight.h | 5 +++++ 11 files changed, 50 insertions(+), 45 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 306d2af47d632..e3a54f7038ad4 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -148,12 +148,12 @@ static int etb_enable_sysfs(struct coresight_device *csdev) spin_lock_irqsave(&drvdata->spinlock, flags); /* Don't messup with perf sessions. */ - if (local_read(&csdev->mode) == CS_MODE_PERF) { + if (coresight_get_mode(csdev) == CS_MODE_PERF) { ret = -EBUSY; goto out; } - if (local_read(&csdev->mode) == CS_MODE_DISABLED) { + if (coresight_get_mode(csdev) == CS_MODE_DISABLED) { ret = etb_enable_hw(drvdata); if (ret) goto out; @@ -179,7 +179,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) spin_lock_irqsave(&drvdata->spinlock, flags); /* No need to continue if the component is already in used by sysFS. */ - if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) { + if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { ret = -EBUSY; goto out; } @@ -361,7 +361,7 @@ static int etb_disable(struct coresight_device *csdev) } /* Complain if we (somehow) got out of sync */ - WARN_ON_ONCE(local_read(&csdev->mode) == CS_MODE_DISABLED); + WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED); etb_disable_hw(drvdata); /* Dissociate from monitored process. */ drvdata->pid = -1; @@ -588,7 +588,7 @@ static void etb_dump(struct etb_drvdata *drvdata) unsigned long flags; spin_lock_irqsave(&drvdata->spinlock, flags); - if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) { + if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { __etb_disable_hw(drvdata); etb_dump_hw(drvdata); __etb_enable_hw(drvdata); diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index c301f6a5f0658..64ff53887ef58 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -676,7 +676,7 @@ static void etm_disable(struct coresight_device *csdev, * change its status. As such we can read the status here without * fearing it will change under us. */ - mode = local_read(&csdev->mode); + mode = coresight_get_mode(csdev); switch (mode) { case CS_MODE_DISABLED: @@ -727,7 +727,7 @@ static int etm_starting_cpu(unsigned int cpu) etmdrvdata[cpu]->os_unlock = true; } - if (local_read(&etmdrvdata[cpu]->csdev->mode)) + if (coresight_get_mode(etmdrvdata[cpu]->csdev)) etm_enable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; @@ -739,7 +739,7 @@ static int etm_dying_cpu(unsigned int cpu) return 0; spin_lock(&etmdrvdata[cpu]->spinlock); - if (local_read(&etmdrvdata[cpu]->csdev->mode)) + if (coresight_get_mode(etmdrvdata[cpu]->csdev)) etm_disable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c index 6c8429c980b14..68c644be9813b 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c @@ -722,7 +722,7 @@ static ssize_t cntr_val_show(struct device *dev, struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; - if (!local_read(&drvdata->csdev->mode)) { + if (!coresight_get_mode(drvdata->csdev)) { spin_lock(&drvdata->spinlock); for (i = 0; i < drvdata->nr_cntr; i++) ret += sprintf(buf, "counter %d: %x\n", @@ -941,7 +941,7 @@ static ssize_t seq_curr_state_show(struct device *dev, struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct etm_config *config = &drvdata->config; - if (!local_read(&drvdata->csdev->mode)) { + if (!coresight_get_mode(drvdata->csdev)) { val = config->seq_curr_state; goto out; } diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 572ac4a5e4ff9..e65232e982a78 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1007,7 +1007,7 @@ static void etm4_disable(struct coresight_device *csdev, * change its status. As such we can read the status here without * fearing it will change under us. */ - mode = local_read(&csdev->mode); + mode = coresight_get_mode(csdev); switch (mode) { case CS_MODE_DISABLED: @@ -1659,7 +1659,7 @@ static int etm4_starting_cpu(unsigned int cpu) if (!etmdrvdata[cpu]->os_unlock) etm4_os_unlock(etmdrvdata[cpu]); - if (local_read(&etmdrvdata[cpu]->csdev->mode)) + if (coresight_get_mode(etmdrvdata[cpu]->csdev)) etm4_enable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; @@ -1671,7 +1671,7 @@ static int etm4_dying_cpu(unsigned int cpu) return 0; spin_lock(&etmdrvdata[cpu]->spinlock); - if (local_read(&etmdrvdata[cpu]->csdev->mode)) + if (coresight_get_mode(etmdrvdata[cpu]->csdev)) etm4_disable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; @@ -1829,7 +1829,7 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata) * Save and restore the ETM Trace registers only if * the ETM is active. */ - if (local_read(&drvdata->csdev->mode) && drvdata->save_state) + if (coresight_get_mode(drvdata->csdev) && drvdata->save_state) ret = __etm4_cpu_save(drvdata); return ret; } diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index ff578762f6bf3..1d02d42bea83f 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -262,7 +262,7 @@ static void stm_disable(struct coresight_device *csdev, * change its status. As such we can read the status here without * fearing it will change under us. */ - if (local_read(&csdev->mode) == CS_MODE_SYSFS) { + if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { spin_lock(&drvdata->spinlock); stm_disable_hw(drvdata); spin_unlock(&drvdata->spinlock); @@ -369,7 +369,7 @@ static long stm_generic_set_options(struct stm_data *stm_data, { struct stm_drvdata *drvdata = container_of(stm_data, struct stm_drvdata, stm); - if (!(drvdata && local_read(&drvdata->csdev->mode))) + if (!(drvdata && coresight_get_mode(drvdata->csdev))) return -EINVAL; if (channel >= drvdata->numsp) @@ -404,7 +404,7 @@ static ssize_t notrace stm_generic_packet(struct stm_data *stm_data, struct stm_drvdata, stm); unsigned int stm_flags; - if (!(drvdata && local_read(&drvdata->csdev->mode))) + if (!(drvdata && coresight_get_mode(drvdata->csdev))) return -EACCES; if (channel >= drvdata->numsp) @@ -511,7 +511,7 @@ static ssize_t port_select_show(struct device *dev, struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); unsigned long val; - if (!local_read(&drvdata->csdev->mode)) { + if (!coresight_get_mode(drvdata->csdev)) { val = drvdata->stmspscr; } else { spin_lock(&drvdata->spinlock); @@ -537,7 +537,7 @@ static ssize_t port_select_store(struct device *dev, spin_lock(&drvdata->spinlock); drvdata->stmspscr = val; - if (local_read(&drvdata->csdev->mode)) { + if (coresight_get_mode(drvdata->csdev)) { CS_UNLOCK(drvdata->base); /* Process as per ARM's TRM recommendation */ stmsper = readl_relaxed(drvdata->base + STMSPER); @@ -558,7 +558,7 @@ static ssize_t port_enable_show(struct device *dev, struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); unsigned long val; - if (!local_read(&drvdata->csdev->mode)) { + if (!coresight_get_mode(drvdata->csdev)) { val = drvdata->stmsper; } else { spin_lock(&drvdata->spinlock); @@ -584,7 +584,7 @@ static ssize_t port_enable_store(struct device *dev, spin_lock(&drvdata->spinlock); drvdata->stmsper = val; - if (local_read(&drvdata->csdev->mode)) { + if (coresight_get_mode(drvdata->csdev)) { CS_UNLOCK(drvdata->base); writel_relaxed(drvdata->stmsper, drvdata->base + STMSPER); CS_LOCK(drvdata->base); diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c index fa52297c73d2f..f9444e2cb1d9f 100644 --- a/drivers/hwtracing/coresight/coresight-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-sysfs.c @@ -62,7 +62,7 @@ static int coresight_enable_source_sysfs(struct coresight_device *csdev, * change with coresight_mutex held, which we already have here. */ lockdep_assert_held(&coresight_mutex); - if (local_read(&csdev->mode) != CS_MODE_SYSFS) { + if (coresight_get_mode(csdev) != CS_MODE_SYSFS) { ret = source_ops(csdev)->enable(csdev, data, mode); if (ret) return ret; @@ -87,7 +87,7 @@ static bool coresight_disable_source_sysfs(struct coresight_device *csdev, void *data) { lockdep_assert_held(&coresight_mutex); - if (local_read(&csdev->mode) != CS_MODE_SYSFS) + if (coresight_get_mode(csdev) != CS_MODE_SYSFS) return false; csdev->refcnt--; @@ -184,7 +184,7 @@ int coresight_enable_sysfs(struct coresight_device *csdev) * coresight_enable_source() so can still race with Perf mode which * doesn't hold coresight_mutex. */ - if (local_read(&csdev->mode) == CS_MODE_SYSFS) { + if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { /* * There could be multiple applications driving the software * source. So keep the refcount for each such user when the @@ -338,7 +338,7 @@ static ssize_t enable_source_show(struct device *dev, guard(mutex)(&coresight_mutex); return scnprintf(buf, PAGE_SIZE, "%u\n", - local_read(&csdev->mode) == CS_MODE_SYSFS); + coresight_get_mode(csdev) == CS_MODE_SYSFS); } static ssize_t enable_source_store(struct device *dev, diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index e8b2bbed047f1..72005b0c633e5 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -558,7 +558,7 @@ static void tmc_shutdown(struct amba_device *adev) spin_lock_irqsave(&drvdata->spinlock, flags); - if (local_read(&drvdata->csdev->mode) == CS_MODE_DISABLED) + if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED) goto out; if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index f3281c958a570..77ef67c976e92 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -89,7 +89,7 @@ static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata) * When operating in sysFS mode the content of the buffer needs to be * read before the TMC is disabled. */ - if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) + if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) tmc_etb_dump_hw(drvdata); tmc_disable_hw(drvdata); @@ -205,7 +205,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) * sink is already enabled no memory is needed and the HW need not be * touched. */ - if (local_read(&csdev->mode) == CS_MODE_SYSFS) { + if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { csdev->refcnt++; goto out; } @@ -262,7 +262,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) * No need to continue if the ETB/ETF is already operated * from sysFS. */ - if (local_read(&csdev->mode) == CS_MODE_SYSFS) { + if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { ret = -EBUSY; break; } @@ -345,7 +345,7 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev) } /* Complain if we (somehow) got out of sync */ - WARN_ON_ONCE(local_read(&csdev->mode) == CS_MODE_DISABLED); + WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED); tmc_etb_disable_hw(drvdata); /* Dissociate from monitored process. */ drvdata->pid = -1; @@ -485,7 +485,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev, return 0; /* This shouldn't happen */ - if (WARN_ON_ONCE(local_read(&csdev->mode) != CS_MODE_PERF)) + if (WARN_ON_ONCE(coresight_get_mode(csdev) != CS_MODE_PERF)) return 0; spin_lock_irqsave(&drvdata->spinlock, flags); @@ -631,7 +631,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) } /* Don't interfere if operated from Perf */ - if (local_read(&drvdata->csdev->mode) == CS_MODE_PERF) { + if (coresight_get_mode(drvdata->csdev) == CS_MODE_PERF) { ret = -EINVAL; goto out; } @@ -643,7 +643,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) } /* Disable the TMC if need be */ - if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) { + if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { /* There is no point in reading a TMC in HW FIFO mode */ mode = readl_relaxed(drvdata->base + TMC_MODE); if (mode != TMC_MODE_CIRCULAR_BUFFER) { @@ -675,7 +675,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata) spin_lock_irqsave(&drvdata->spinlock, flags); /* Re-enable the TMC if need be */ - if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) { + if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { /* There is no point in reading a TMC in HW FIFO mode */ mode = readl_relaxed(drvdata->base + TMC_MODE); if (mode != TMC_MODE_CIRCULAR_BUFFER) { diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 88a0fc375b4db..383cb8647589d 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1143,7 +1143,7 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata) * When operating in sysFS mode the content of the buffer needs to be * read before the TMC is disabled. */ - if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) + if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) tmc_etr_sync_sysfs_buf(drvdata); tmc_disable_hw(drvdata); @@ -1189,7 +1189,7 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev) spin_lock_irqsave(&drvdata->spinlock, flags); } - if (drvdata->reading || local_read(&csdev->mode) == CS_MODE_PERF) { + if (drvdata->reading || coresight_get_mode(csdev) == CS_MODE_PERF) { ret = -EBUSY; goto out; } @@ -1230,7 +1230,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) * sink is already enabled no memory is needed and the HW need not be * touched, even if the buffer size has changed. */ - if (local_read(&csdev->mode) == CS_MODE_SYSFS) { + if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { csdev->refcnt++; goto out; } @@ -1652,7 +1652,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) spin_lock_irqsave(&drvdata->spinlock, flags); /* Don't use this sink if it is already claimed by sysFS */ - if (local_read(&csdev->mode) == CS_MODE_SYSFS) { + if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { rc = -EBUSY; goto unlock_out; } @@ -1726,7 +1726,7 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) } /* Complain if we (somehow) got out of sync */ - WARN_ON_ONCE(local_read(&csdev->mode) == CS_MODE_DISABLED); + WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED); tmc_etr_disable_hw(drvdata); /* Dissociate from monitored process. */ drvdata->pid = -1; @@ -1778,7 +1778,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) } /* Disable the TMC if we are trying to read from a running session. */ - if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) + if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) __tmc_etr_disable_hw(drvdata); drvdata->reading = true; @@ -1800,7 +1800,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) spin_lock_irqsave(&drvdata->spinlock, flags); /* RE-enable the TMC if need be */ - if (local_read(&drvdata->csdev->mode) == CS_MODE_SYSFS) { + if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { /* * The trace run will continue with the same allocated trace * buffer. Since the tracer is still enabled drvdata::buf can't diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c index a92c5b750f81e..903cfffe0bcd7 100644 --- a/drivers/hwtracing/coresight/ultrasoc-smb.c +++ b/drivers/hwtracing/coresight/ultrasoc-smb.c @@ -207,7 +207,7 @@ static void smb_enable_sysfs(struct coresight_device *csdev) { struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent); - if (local_read(&csdev->mode) != CS_MODE_DISABLED) + if (coresight_get_mode(csdev) != CS_MODE_DISABLED) return; smb_enable_hw(drvdata); @@ -253,8 +253,8 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode, return -EBUSY; /* Do nothing, the SMB is already enabled as other mode */ - if (local_read(&csdev->mode) != CS_MODE_DISABLED && - local_read(&csdev->mode) != mode) + if (coresight_get_mode(csdev) != CS_MODE_DISABLED && + coresight_get_mode(csdev) != mode) return -EBUSY; switch (mode) { @@ -291,7 +291,7 @@ static int smb_disable(struct coresight_device *csdev) return -EBUSY; /* Complain if we (somehow) got out of sync */ - WARN_ON_ONCE(local_read(&csdev->mode) == CS_MODE_DISABLED); + WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED); smb_disable_hw(drvdata); diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 414bcbbdaf62e..a49e4e20e8998 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -591,6 +591,11 @@ static inline bool coresight_take_mode(struct coresight_device *csdev, CS_MODE_DISABLED; } +static inline enum cs_mode coresight_get_mode(struct coresight_device *csdev) +{ + return local_read(&csdev->mode); +} + extern struct coresight_device * coresight_register(struct coresight_desc *desc); extern void coresight_unregister(struct coresight_device *csdev); From bcaabb95f0c9883fb8e1112bd13eaba9cfd62c15 Mon Sep 17 00:00:00 2001 From: James Clark Date: Mon, 29 Jan 2024 15:40:43 +0000 Subject: [PATCH 17/32] coresight: Add helper for setting csdev->mode Now that mode is in struct coresight_device, sets can be wrapped. This also allows us to add a sanity check that there have been no concurrent modifications of mode. Currently all usages of local_set() were inside the device's spin locks so this new warning shouldn't be triggered. coresight_take_mode() could maybe have been used in place of adding the warning, but there may be use cases which set the mode to the same mode which are valid but would fail in coresight_take_mode() because it requires the device to only be in the disabled state. Signed-off-by: James Clark Link: https://lore.kernel.org/r/20240129154050.569566-13-james.clark@arm.com Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-etb10.c | 6 +++--- .../hwtracing/coresight/coresight-etm3x-core.c | 4 ++-- .../hwtracing/coresight/coresight-etm4x-core.c | 4 ++-- drivers/hwtracing/coresight/coresight-stm.c | 2 +- drivers/hwtracing/coresight/coresight-tmc-etf.c | 10 +++++----- drivers/hwtracing/coresight/coresight-tmc-etr.c | 6 +++--- drivers/hwtracing/coresight/ultrasoc-smb.c | 6 +++--- include/linux/coresight.h | 16 ++++++++++++++++ 8 files changed, 35 insertions(+), 19 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index e3a54f7038ad4..3aab182b562f1 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -158,7 +158,7 @@ static int etb_enable_sysfs(struct coresight_device *csdev) if (ret) goto out; - local_set(&csdev->mode, CS_MODE_SYSFS); + coresight_set_mode(csdev, CS_MODE_SYSFS); } csdev->refcnt++; @@ -214,7 +214,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) if (!ret) { /* Associate with monitored process. */ drvdata->pid = pid; - local_set(&drvdata->csdev->mode, CS_MODE_PERF); + coresight_set_mode(drvdata->csdev, CS_MODE_PERF); csdev->refcnt++; } @@ -365,7 +365,7 @@ static int etb_disable(struct coresight_device *csdev) etb_disable_hw(drvdata); /* Dissociate from monitored process. */ drvdata->pid = -1; - local_set(&csdev->mode, CS_MODE_DISABLED); + coresight_set_mode(csdev, CS_MODE_DISABLED); spin_unlock_irqrestore(&drvdata->spinlock, flags); dev_dbg(&csdev->dev, "ETB disabled\n"); diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index 64ff53887ef58..9d5c1391ffb12 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -576,7 +576,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event, /* The tracer didn't start */ if (ret) - local_set(&drvdata->csdev->mode, CS_MODE_DISABLED); + coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED); return ret; } @@ -693,7 +693,7 @@ static void etm_disable(struct coresight_device *csdev, } if (mode) - local_set(&csdev->mode, CS_MODE_DISABLED); + coresight_set_mode(csdev, CS_MODE_DISABLED); } static const struct coresight_ops_source etm_source_ops = { diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index e65232e982a78..f087bc8d1da6b 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -859,7 +859,7 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, /* The tracer didn't start */ if (ret) - local_set(&csdev->mode, CS_MODE_DISABLED); + coresight_set_mode(csdev, CS_MODE_DISABLED); return ret; } @@ -1021,7 +1021,7 @@ static void etm4_disable(struct coresight_device *csdev, } if (mode) - local_set(&csdev->mode, CS_MODE_DISABLED); + coresight_set_mode(csdev, CS_MODE_DISABLED); } static const struct coresight_ops_source etm4_source_ops = { diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 1d02d42bea83f..974d37e5f94c0 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -272,7 +272,7 @@ static void stm_disable(struct coresight_device *csdev, pm_runtime_put(csdev->dev.parent); - local_set(&csdev->mode, CS_MODE_DISABLED); + coresight_set_mode(csdev, CS_MODE_DISABLED); dev_dbg(&csdev->dev, "STM tracing disabled\n"); } } diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 77ef67c976e92..d4f641cd9de69 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -228,7 +228,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) ret = tmc_etb_enable_hw(drvdata); if (!ret) { - local_set(&csdev->mode, CS_MODE_SYSFS); + coresight_set_mode(csdev, CS_MODE_SYSFS); csdev->refcnt++; } else { /* Free up the buffer if we failed to enable */ @@ -292,7 +292,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) if (!ret) { /* Associate with monitored process. */ drvdata->pid = pid; - local_set(&csdev->mode, CS_MODE_PERF); + coresight_set_mode(csdev, CS_MODE_PERF); csdev->refcnt++; } } while (0); @@ -349,7 +349,7 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev) tmc_etb_disable_hw(drvdata); /* Dissociate from monitored process. */ drvdata->pid = -1; - local_set(&csdev->mode, CS_MODE_DISABLED); + coresight_set_mode(csdev, CS_MODE_DISABLED); spin_unlock_irqrestore(&drvdata->spinlock, flags); @@ -375,7 +375,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, if (csdev->refcnt == 0) { ret = tmc_etf_enable_hw(drvdata); if (!ret) { - local_set(&csdev->mode, CS_MODE_SYSFS); + coresight_set_mode(csdev, CS_MODE_SYSFS); first_enable = true; } } @@ -405,7 +405,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev, csdev->refcnt--; if (csdev->refcnt == 0) { tmc_etf_disable_hw(drvdata); - local_set(&csdev->mode, CS_MODE_DISABLED); + coresight_set_mode(csdev, CS_MODE_DISABLED); last_disable = true; } spin_unlock_irqrestore(&drvdata->spinlock, flags); diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 383cb8647589d..e75428fa1592a 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1237,7 +1237,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) ret = tmc_etr_enable_hw(drvdata, sysfs_buf); if (!ret) { - local_set(&csdev->mode, CS_MODE_SYSFS); + coresight_set_mode(csdev, CS_MODE_SYSFS); csdev->refcnt++; } @@ -1684,7 +1684,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) if (!rc) { /* Associate with monitored process. */ drvdata->pid = pid; - local_set(&csdev->mode, CS_MODE_PERF); + coresight_set_mode(csdev, CS_MODE_PERF); drvdata->perf_buf = etr_perf->etr_buf; csdev->refcnt++; } @@ -1730,7 +1730,7 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) tmc_etr_disable_hw(drvdata); /* Dissociate from monitored process. */ drvdata->pid = -1; - local_set(&csdev->mode, CS_MODE_DISABLED); + coresight_set_mode(csdev, CS_MODE_DISABLED); /* Reset perf specific data */ drvdata->perf_buf = NULL; diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c index 903cfffe0bcd7..f9ebf20c91e63 100644 --- a/drivers/hwtracing/coresight/ultrasoc-smb.c +++ b/drivers/hwtracing/coresight/ultrasoc-smb.c @@ -211,7 +211,7 @@ static void smb_enable_sysfs(struct coresight_device *csdev) return; smb_enable_hw(drvdata); - local_set(&csdev->mode, CS_MODE_SYSFS); + coresight_set_mode(csdev, CS_MODE_SYSFS); } static int smb_enable_perf(struct coresight_device *csdev, void *data) @@ -234,7 +234,7 @@ static int smb_enable_perf(struct coresight_device *csdev, void *data) if (drvdata->pid == -1) { smb_enable_hw(drvdata); drvdata->pid = pid; - local_set(&csdev->mode, CS_MODE_PERF); + coresight_set_mode(csdev, CS_MODE_PERF); } return 0; @@ -297,7 +297,7 @@ static int smb_disable(struct coresight_device *csdev) /* Dissociate from the target process. */ drvdata->pid = -1; - local_set(&csdev->mode, CS_MODE_DISABLED); + coresight_set_mode(csdev, CS_MODE_DISABLED); dev_dbg(&csdev->dev, "Ultrasoc SMB disabled\n"); return 0; diff --git a/include/linux/coresight.h b/include/linux/coresight.h index a49e4e20e8998..5f288d475490c 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -596,6 +596,22 @@ static inline enum cs_mode coresight_get_mode(struct coresight_device *csdev) return local_read(&csdev->mode); } +static inline void coresight_set_mode(struct coresight_device *csdev, + enum cs_mode new_mode) +{ + enum cs_mode current_mode = coresight_get_mode(csdev); + + /* + * Changing to a new mode must be done from an already disabled state + * unless it's synchronized with coresight_take_mode(). Otherwise the + * device is already in use and signifies a locking issue. + */ + WARN(new_mode != CS_MODE_DISABLED && current_mode != CS_MODE_DISABLED && + current_mode != new_mode, "Device already in use\n"); + + local_set(&csdev->mode, new_mode); +} + extern struct coresight_device * coresight_register(struct coresight_desc *desc); extern void coresight_unregister(struct coresight_device *csdev); From 9f0ea8e8344b8549af404f2f1ddb25e22d6b09e1 Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Sun, 4 Feb 2024 13:30:32 +0800 Subject: [PATCH 18/32] coresight-tpdm: Optimize the store function of tpdm simple dataset Replace spin lock/unlock to avoid forgetting to unlock when the function exits. And refine methods for handling various conditions. Signed-off-by: Tao Zhang Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/1707024641-22460-2-git-send-email-quic_taozha@quicinc.com --- drivers/hwtracing/coresight/coresight-tpdm.c | 39 ++++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index bd13a548375ca..0427c0fc0bf33 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -77,51 +77,50 @@ static ssize_t tpdm_simple_dataset_store(struct device *dev, size_t size) { unsigned long val; - ssize_t ret = size; + ssize_t ret = -EINVAL; struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct tpdm_dataset_attribute *tpdm_attr = container_of(attr, struct tpdm_dataset_attribute, attr); if (kstrtoul(buf, 0, &val)) - return -EINVAL; + return ret; - spin_lock(&drvdata->spinlock); + guard(spinlock)(&drvdata->spinlock); switch (tpdm_attr->mem) { case DSB_TRIG_PATT: - if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) + if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) { drvdata->dsb->trig_patt[tpdm_attr->idx] = val; - else - ret = -EINVAL; + ret = size; + } break; case DSB_TRIG_PATT_MASK: - if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) + if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) { drvdata->dsb->trig_patt_mask[tpdm_attr->idx] = val; - else - ret = -EINVAL; + ret = size; + } break; case DSB_PATT: - if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) + if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) { drvdata->dsb->patt_val[tpdm_attr->idx] = val; - else - ret = -EINVAL; + ret = size; + } break; case DSB_PATT_MASK: - if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) + if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) { drvdata->dsb->patt_mask[tpdm_attr->idx] = val; - else - ret = -EINVAL; + ret = size; + } break; case DSB_MSR: - if (tpdm_attr->idx < drvdata->dsb_msr_num) + if (tpdm_attr->idx < drvdata->dsb_msr_num) { drvdata->dsb->msr[tpdm_attr->idx] = val; - else - ret = -EINVAL; + ret = size; + } break; default: - ret = -EINVAL; + break; } - spin_unlock(&drvdata->spinlock); return ret; } From f021801c418e7a81455a410a5b195961349d8e93 Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Sun, 4 Feb 2024 13:30:33 +0800 Subject: [PATCH 19/32] coresight-tpdm: Optimize the useage of tpdm_has_dsb_dataset Since the function tpdm_has_dsb_dataset will be called by TPDA driver in subsequent patches, it is moved to the header file. And move this judgement form the function __tpdm_{enable/disable} to the beginning of the function tpdm_{enable/disable}_dsb. Signed-off-by: Tao Zhang Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/1707024641-22460-3-git-send-email-quic_taozha@quicinc.com --- drivers/hwtracing/coresight/coresight-tpdm.c | 30 +++++++++----------- drivers/hwtracing/coresight/coresight-tpdm.h | 4 +++ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 0427c0fc0bf33..4b1296d11360b 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -125,11 +125,6 @@ static ssize_t tpdm_simple_dataset_store(struct device *dev, return ret; } -static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata) -{ - return (drvdata->datasets & TPDM_PIDR0_DS_DSB); -} - static umode_t tpdm_dsb_is_visible(struct kobject *kobj, struct attribute *attr, int n) { @@ -232,25 +227,27 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) { u32 val, i; + if (!tpdm_has_dsb_dataset(drvdata)) + return; + for (i = 0; i < TPDM_DSB_MAX_EDCR; i++) writel_relaxed(drvdata->dsb->edge_ctrl[i], - drvdata->base + TPDM_DSB_EDCR(i)); + drvdata->base + TPDM_DSB_EDCR(i)); for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++) writel_relaxed(drvdata->dsb->edge_ctrl_mask[i], - drvdata->base + TPDM_DSB_EDCMR(i)); + drvdata->base + TPDM_DSB_EDCMR(i)); for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { writel_relaxed(drvdata->dsb->patt_val[i], - drvdata->base + TPDM_DSB_TPR(i)); + drvdata->base + TPDM_DSB_TPR(i)); writel_relaxed(drvdata->dsb->patt_mask[i], - drvdata->base + TPDM_DSB_TPMR(i)); + drvdata->base + TPDM_DSB_TPMR(i)); writel_relaxed(drvdata->dsb->trig_patt[i], - drvdata->base + TPDM_DSB_XPR(i)); + drvdata->base + TPDM_DSB_XPR(i)); writel_relaxed(drvdata->dsb->trig_patt_mask[i], - drvdata->base + TPDM_DSB_XPMR(i)); + drvdata->base + TPDM_DSB_XPMR(i)); } set_dsb_tier(drvdata); - set_dsb_msr(drvdata); val = readl_relaxed(drvdata->base + TPDM_DSB_CR); @@ -278,8 +275,7 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata) { CS_UNLOCK(drvdata->base); - if (tpdm_has_dsb_dataset(drvdata)) - tpdm_enable_dsb(drvdata); + tpdm_enable_dsb(drvdata); CS_LOCK(drvdata->base); } @@ -307,6 +303,9 @@ static void tpdm_disable_dsb(struct tpdm_drvdata *drvdata) { u32 val; + if (!tpdm_has_dsb_dataset(drvdata)) + return; + /* Set the enable bit of DSB control register to 0 */ val = readl_relaxed(drvdata->base + TPDM_DSB_CR); val &= ~TPDM_DSB_CR_ENA; @@ -318,8 +317,7 @@ static void __tpdm_disable(struct tpdm_drvdata *drvdata) { CS_UNLOCK(drvdata->base); - if (tpdm_has_dsb_dataset(drvdata)) - tpdm_disable_dsb(drvdata); + tpdm_disable_dsb(drvdata); CS_LOCK(drvdata->base); } diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index 4115b2a17b8d8..ddaf333fa1c25 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -220,4 +220,8 @@ struct tpdm_dataset_attribute { u32 idx; }; +static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata) +{ + return (drvdata->datasets & TPDM_PIDR0_DS_DSB); +} #endif /* _CORESIGHT_CORESIGHT_TPDM_H */ From 4ed57f75898ce466ed60ce3c146290742985aa95 Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Sun, 4 Feb 2024 13:30:34 +0800 Subject: [PATCH 20/32] dt-bindings: arm: qcom,coresight-tpdm: Add support for CMB element size Add property "qcom,cmb-elem-bits" to support CMB(Continuous Multi-Bit) element for TPDM. The associated aggregator will read this size before it is enabled. CMB element size currently only supports 8-bit, 32-bit and 64-bit. Because the existing example tpdm "tpdm@684c000" which only supports dsb sub-unit, I introduce a new example "tpdm@6c29000" to describe the usage of this new property. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Tao Zhang Signed-off-by: Mao Jinlong Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/1707024641-22460-4-git-send-email-quic_taozha@quicinc.com --- .../bindings/arm/qcom,coresight-tpdm.yaml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml index 61ddc3b5b247b..2320b54459006 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml @@ -52,6 +52,14 @@ properties: $ref: /schemas/types.yaml#/definitions/uint8 enum: [32, 64] + qcom,cmb-element-bits: + description: + Specifies the CMB(Continuous Multi-Bit) element size supported by + the monitor. The associated aggregator will read this size before it + is enabled. CMB element size currently only supports 8-bit, 32-bit + and 64-bit. + enum: [8, 32, 64] + qcom,dsb-msrs-num: description: Specifies the number of DSB(Discrete Single Bit) MSR(mux select register) @@ -110,4 +118,21 @@ examples: }; }; + tpdm@6c29000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x06c29000 0x1000>; + + qcom,cmb-element-bits = <64>; + + clocks = <&aoss_qmp>; + clock-names = "apb_pclk"; + + out-ports { + port { + tpdm_ipcc_out_funnel_center: endpoint { + remote-endpoint = <&funnel_center_in_tpdm_ipcc>; + }; + }; + }; + }; ... From a1705ffcce5268eb95a5e716ee32c9d181b8c228 Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Sun, 4 Feb 2024 13:30:35 +0800 Subject: [PATCH 21/32] coresight-tpdm: Add CMB dataset support CMB (continuous multi-bit) is one of TPDM's dataset type. CMB subunit can be enabled for data collection by writing 1 to the first bit of CMB_CR register. This change is to add enable/disable function for CMB dataset by writing CMB_CR register. Reviewed-by: James Clark Signed-off-by: Tao Zhang Signed-off-by: Jinlong Mao Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/1707024641-22460-5-git-send-email-quic_taozha@quicinc.com --- drivers/hwtracing/coresight/coresight-tpdm.c | 28 ++++++++++++++++++++ drivers/hwtracing/coresight/coresight-tpdm.h | 13 +++++++++ 2 files changed, 41 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 4b1296d11360b..1bb1d8e83501a 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -263,6 +263,19 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) writel_relaxed(val, drvdata->base + TPDM_DSB_CR); } +static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata) +{ + u32 val; + + if (!tpdm_has_cmb_dataset(drvdata)) + return; + + val = readl_relaxed(drvdata->base + TPDM_CMB_CR); + /* Set the enable bit of CMB control register to 1 */ + val |= TPDM_CMB_CR_ENA; + writel_relaxed(val, drvdata->base + TPDM_CMB_CR); +} + /* * TPDM enable operations * The TPDM or Monitor serves as data collection component for various @@ -276,6 +289,7 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata) CS_UNLOCK(drvdata->base); tpdm_enable_dsb(drvdata); + tpdm_enable_cmb(drvdata); CS_LOCK(drvdata->base); } @@ -312,12 +326,26 @@ static void tpdm_disable_dsb(struct tpdm_drvdata *drvdata) writel_relaxed(val, drvdata->base + TPDM_DSB_CR); } +static void tpdm_disable_cmb(struct tpdm_drvdata *drvdata) +{ + u32 val; + + if (!tpdm_has_cmb_dataset(drvdata)) + return; + + val = readl_relaxed(drvdata->base + TPDM_CMB_CR); + /* Set the enable bit of CMB control register to 0 */ + val &= ~TPDM_CMB_CR_ENA; + writel_relaxed(val, drvdata->base + TPDM_CMB_CR); +} + /* TPDM disable operations */ static void __tpdm_disable(struct tpdm_drvdata *drvdata) { CS_UNLOCK(drvdata->base); tpdm_disable_dsb(drvdata); + tpdm_disable_cmb(drvdata); CS_LOCK(drvdata->base); } diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index ddaf333fa1c25..a442d9c6e4ac4 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -9,6 +9,12 @@ /* The max number of the datasets that TPDM supports */ #define TPDM_DATASETS 7 +/* CMB Subunit Registers */ +#define TPDM_CMB_CR (0xA00) + +/* Enable bit for CMB subunit */ +#define TPDM_CMB_CR_ENA BIT(0) + /* DSB Subunit Registers */ #define TPDM_DSB_CR (0x780) #define TPDM_DSB_TIER (0x784) @@ -79,10 +85,12 @@ * * PERIPHIDR0[0] : Fix to 1 if ImplDef subunit present, else 0 * PERIPHIDR0[1] : Fix to 1 if DSB subunit present, else 0 + * PERIPHIDR0[2] : Fix to 1 if CMB subunit present, else 0 */ #define TPDM_PIDR0_DS_IMPDEF BIT(0) #define TPDM_PIDR0_DS_DSB BIT(1) +#define TPDM_PIDR0_DS_CMB BIT(2) #define TPDM_DSB_MAX_LINES 256 /* MAX number of EDCR registers */ @@ -224,4 +232,9 @@ static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata) { return (drvdata->datasets & TPDM_PIDR0_DS_DSB); } + +static bool tpdm_has_cmb_dataset(struct tpdm_drvdata *drvdata) +{ + return (drvdata->datasets & TPDM_PIDR0_DS_CMB); +} #endif /* _CORESIGHT_CORESIGHT_TPDM_H */ From e6d7f5252f73cf21d3676de794916204524f51b5 Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Sun, 4 Feb 2024 13:30:36 +0800 Subject: [PATCH 22/32] coresight-tpda: Add support to configure CMB element Read the CMB element size from the device tree. Set the register bit that controls the CMB element size of the corresponding port. Reviewed-by: James Clark Signed-off-by: Tao Zhang Signed-off-by: Mao Jinlong Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/1707024641-22460-6-git-send-email-quic_taozha@quicinc.com --- drivers/hwtracing/coresight/coresight-tpda.c | 130 +++++++++++-------- drivers/hwtracing/coresight/coresight-tpda.h | 6 + 2 files changed, 81 insertions(+), 55 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index f8f6413cc7116..6863afe7ca940 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -18,6 +18,7 @@ #include "coresight-priv.h" #include "coresight-tpda.h" #include "coresight-trace-id.h" +#include "coresight-tpdm.h" DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda"); @@ -28,24 +29,59 @@ static bool coresight_device_is_tpdm(struct coresight_device *csdev) CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM); } +static void tpda_clear_element_size(struct coresight_device *csdev) +{ + struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + + drvdata->dsb_esize = 0; + drvdata->cmb_esize = 0; +} + +static void tpda_set_element_size(struct tpda_drvdata *drvdata, u32 *val) +{ + /* Clear all relevant fields */ + *val &= ~(TPDA_Pn_CR_DSBSIZE | TPDA_Pn_CR_CMBSIZE); + + if (drvdata->dsb_esize == 64) + *val |= TPDA_Pn_CR_DSBSIZE; + else if (drvdata->dsb_esize == 32) + *val &= ~TPDA_Pn_CR_DSBSIZE; + + if (drvdata->cmb_esize == 64) + *val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x2); + else if (drvdata->cmb_esize == 32) + *val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x1); + else if (drvdata->cmb_esize == 8) + *val &= ~TPDA_Pn_CR_CMBSIZE; +} + /* - * Read the DSB element size from the TPDM device + * Read the element size from the TPDM device. One TPDM must have at least one of the + * element size property. * Returns - * The dsb element size read from the devicetree if available. - * 0 - Otherwise, with a warning once. + * 0 - The element size property is read + * Others - Cannot read the property of the element size */ -static int tpdm_read_dsb_element_size(struct coresight_device *csdev) +static int tpdm_read_element_size(struct tpda_drvdata *drvdata, + struct coresight_device *csdev) { - int rc = 0; - u8 size = 0; + int rc = -EINVAL; + struct tpdm_drvdata *tpdm_data = dev_get_drvdata(csdev->dev.parent); + + if (tpdm_has_dsb_dataset(tpdm_data)) { + rc = fwnode_property_read_u8(dev_fwnode(csdev->dev.parent), + "qcom,dsb-element-size", &drvdata->dsb_esize); + } + if (tpdm_has_cmb_dataset(tpdm_data)) { + rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent), + "qcom,cmb-element-bits", &drvdata->cmb_esize); + } - rc = fwnode_property_read_u8(dev_fwnode(csdev->dev.parent), - "qcom,dsb-element-size", &size); if (rc) dev_warn_once(&csdev->dev, - "Failed to read TPDM DSB Element size: %d\n", rc); + "Failed to read TPDM Element size: %d\n", rc); - return size; + return rc; } /* @@ -56,11 +92,12 @@ static int tpdm_read_dsb_element_size(struct coresight_device *csdev) * Parameter "inport" is used to pass in the input port number * of TPDA, and it is set to -1 in the recursize call. */ -static int tpda_get_element_size(struct coresight_device *csdev, +static int tpda_get_element_size(struct tpda_drvdata *drvdata, + struct coresight_device *csdev, int inport) { - int dsb_size = -ENOENT; - int i, size; + int rc = 0; + int i; struct coresight_device *in; for (i = 0; i < csdev->pdata->nr_inconns; i++) { @@ -69,30 +106,26 @@ static int tpda_get_element_size(struct coresight_device *csdev, continue; /* Ignore the paths that do not match port */ - if (inport > 0 && + if (inport >= 0 && csdev->pdata->in_conns[i]->dest_port != inport) continue; if (coresight_device_is_tpdm(in)) { - size = tpdm_read_dsb_element_size(in); + if (drvdata->dsb_esize || drvdata->cmb_esize) + return -EEXIST; + rc = tpdm_read_element_size(drvdata, in); + if (rc) + return rc; } else { /* Recurse down the path */ - size = tpda_get_element_size(in, -1); - } - - if (size < 0) - return size; - - if (dsb_size < 0) { - /* Found a size, save it. */ - dsb_size = size; - } else { - /* Found duplicate TPDMs */ - return -EEXIST; + rc = tpda_get_element_size(drvdata, in, -1); + if (rc) + return rc; } } - return dsb_size; + + return rc; } /* Settings pre enabling port control register */ @@ -109,37 +142,24 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata) static int tpda_enable_port(struct tpda_drvdata *drvdata, int port) { u32 val; - int size; + int rc; val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port)); - /* - * Configure aggregator port n DSB data set element size - * Set the bit to 0 if the size is 32 - * Set the bit to 1 if the size is 64 - */ - size = tpda_get_element_size(drvdata->csdev, port); - switch (size) { - case 32: - val &= ~TPDA_Pn_CR_DSBSIZE; - break; - case 64: - val |= TPDA_Pn_CR_DSBSIZE; - break; - case 0: - return -EEXIST; - case -EEXIST: + tpda_clear_element_size(drvdata->csdev); + rc = tpda_get_element_size(drvdata, drvdata->csdev, port); + if (!rc && (drvdata->dsb_esize || drvdata->cmb_esize)) { + tpda_set_element_size(drvdata, &val); + /* Enable the port */ + val |= TPDA_Pn_CR_ENA; + writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port)); + } else if (rc == -EEXIST) dev_warn_once(&drvdata->csdev->dev, - "Detected multiple TPDMs on port %d", -EEXIST); - return -EEXIST; - default: - return -EINVAL; - } - - /* Enable the port */ - val |= TPDA_Pn_CR_ENA; - writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port)); + "Detected multiple TPDMs on port %d", port); + else + dev_warn_once(&drvdata->csdev->dev, + "Didn't find TPDM element size"); - return 0; + return rc; } static int __tpda_enable(struct tpda_drvdata *drvdata, int port) diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h index b3b38fd41b64b..19af64120fcfb 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.h +++ b/drivers/hwtracing/coresight/coresight-tpda.h @@ -10,6 +10,8 @@ #define TPDA_Pn_CR(n) (0x004 + (n * 4)) /* Aggregator port enable bit */ #define TPDA_Pn_CR_ENA BIT(0) +/* Aggregator port CMB data set element size bit */ +#define TPDA_Pn_CR_CMBSIZE GENMASK(7, 6) /* Aggregator port DSB data set element size bit */ #define TPDA_Pn_CR_DSBSIZE BIT(8) @@ -25,6 +27,8 @@ * @csdev: component vitals needed by the framework. * @spinlock: lock for the drvdata value. * @enable: enable status of the component. + * @dsb_esize Record the DSB element size. + * @cmb_esize Record the CMB element size. */ struct tpda_drvdata { void __iomem *base; @@ -32,6 +36,8 @@ struct tpda_drvdata { struct coresight_device *csdev; spinlock_t spinlock; u8 atid; + u8 dsb_esize; + u32 cmb_esize; }; #endif /* _CORESIGHT_CORESIGHT_TPDA_H */ From 2d9ab11c262e39f3bc829d0679257ab942d5878f Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Sun, 4 Feb 2024 13:30:37 +0800 Subject: [PATCH 23/32] coresight-tpdm: Add support to configure CMB TPDM CMB subunits support two forms of CMB data set element creation: continuous and trace-on-change collection mode. Continuous change creates CMB data set elements on every CMBCLK edge. Trace-on-change creates CMB data set elements only when a new data set element differs in value from the previous element in a CMB data set. Set CMB_CR.MODE to 0 for continuous CMB collection mode. Set CMB_CR.MODE to 1 for trace-on-change CMB collection mode. Reviewed-by: James Clark Signed-off-by: Tao Zhang Signed-off-by: Jinlong Mao Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/1707024641-22460-7-git-send-email-quic_taozha@quicinc.com --- .../testing/sysfs-bus-coresight-devices-tpdm | 14 +++++ drivers/hwtracing/coresight/coresight-tpdm.c | 60 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-tpdm.h | 12 ++++ 3 files changed, 86 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm index 4dd49b159543b..6dfb18d6d64ae 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm @@ -170,3 +170,17 @@ Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) /cmb_mode +Date: January 2024 +KernelVersion 6.9 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: (Write) Set the data collection mode of CMB tpdm. Continuous + change creates CMB data set elements on every CMBCLK edge. + Trace-on-change creates CMB data set elements only when a new + data set element differs in value from the previous element + in a CMB data set. + + Accepts only one of the 2 values - 0 or 1. + 0 : Continuous CMB collection mode. + 1 : Trace-on-change CMB collection mode. diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 1bb1d8e83501a..b200714603754 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -137,6 +137,18 @@ static umode_t tpdm_dsb_is_visible(struct kobject *kobj, return 0; } +static umode_t tpdm_cmb_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (drvdata && tpdm_has_cmb_dataset(drvdata)) + return attr->mode; + + return 0; +} + static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { @@ -161,6 +173,9 @@ static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata) drvdata->dsb->trig_ts = true; drvdata->dsb->trig_type = false; } + + if (drvdata->cmb) + memset(drvdata->cmb, 0, sizeof(struct cmb_dataset)); } static void set_dsb_mode(struct tpdm_drvdata *drvdata, u32 *val) @@ -391,6 +406,12 @@ static int tpdm_datasets_setup(struct tpdm_drvdata *drvdata) if (!drvdata->dsb) return -ENOMEM; } + if (tpdm_has_cmb_dataset(drvdata) && (!drvdata->cmb)) { + drvdata->cmb = devm_kzalloc(drvdata->dev, + sizeof(*drvdata->cmb), GFP_KERNEL); + if (!drvdata->cmb) + return -ENOMEM; + } tpdm_reset_datasets(drvdata); return 0; @@ -729,6 +750,34 @@ static ssize_t dsb_trig_ts_store(struct device *dev, } static DEVICE_ATTR_RW(dsb_trig_ts); +static ssize_t cmb_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return sysfs_emit(buf, "%x\n", drvdata->cmb->trace_mode); + +} + +static ssize_t cmb_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long trace_mode; + + if (kstrtoul(buf, 0, &trace_mode) || (trace_mode & ~1UL)) + return -EINVAL; + + spin_lock(&drvdata->spinlock); + drvdata->cmb->trace_mode = trace_mode; + spin_unlock(&drvdata->spinlock); + return size; +} +static DEVICE_ATTR_RW(cmb_mode); + static struct attribute *tpdm_dsb_edge_attrs[] = { &dev_attr_ctrl_idx.attr, &dev_attr_ctrl_val.attr, @@ -845,6 +894,11 @@ static struct attribute *tpdm_dsb_attrs[] = { NULL, }; +static struct attribute *tpdm_cmb_attrs[] = { + &dev_attr_cmb_mode.attr, + NULL, +}; + static struct attribute_group tpdm_dsb_attr_grp = { .attrs = tpdm_dsb_attrs, .is_visible = tpdm_dsb_is_visible, @@ -874,6 +928,11 @@ static struct attribute_group tpdm_dsb_msr_grp = { .name = "dsb_msr", }; +static struct attribute_group tpdm_cmb_attr_grp = { + .attrs = tpdm_cmb_attrs, + .is_visible = tpdm_cmb_is_visible, +}; + static const struct attribute_group *tpdm_attr_grps[] = { &tpdm_attr_grp, &tpdm_dsb_attr_grp, @@ -881,6 +940,7 @@ static const struct attribute_group *tpdm_attr_grps[] = { &tpdm_dsb_trig_patt_grp, &tpdm_dsb_patt_grp, &tpdm_dsb_msr_grp, + &tpdm_cmb_attr_grp, NULL, }; diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index a442d9c6e4ac4..2af92c270ed12 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -14,6 +14,8 @@ /* Enable bit for CMB subunit */ #define TPDM_CMB_CR_ENA BIT(0) +/* Trace collection mode for CMB subunit */ +#define TPDM_CMB_CR_MODE BIT(1) /* DSB Subunit Registers */ #define TPDM_DSB_CR (0x780) @@ -181,6 +183,14 @@ struct dsb_dataset { bool trig_type; }; +/** + * struct cmb_dataset + * @trace_mode: Dataset collection mode + */ +struct cmb_dataset { + u32 trace_mode; +}; + /** * struct tpdm_drvdata - specifics associated to an TPDM component * @base: memory mapped base address for this component. @@ -190,6 +200,7 @@ struct dsb_dataset { * @enable: enable status of the component. * @datasets: The datasets types present of the TPDM. * @dsb Specifics associated to TPDM DSB. + * @cmb Specifics associated to TPDM CMB. * @dsb_msr_num Number of MSR supported by DSB TPDM */ @@ -201,6 +212,7 @@ struct tpdm_drvdata { bool enable; unsigned long datasets; struct dsb_dataset *dsb; + struct cmb_dataset *cmb; u32 dsb_msr_num; }; From 53d4a017a52458d835a1f9524df09c65c2208400 Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Sun, 4 Feb 2024 13:30:38 +0800 Subject: [PATCH 24/32] coresight-tpdm: Add pattern registers support for CMB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Timestamps are requested if the monitor’s CMB data set unit input data matches the value in the Monitor CMB timestamp pattern and mask registers (M_CMB_TPR and M_CMB_TPMR) when CMB timestamp enabled via the timestamp insertion enable register bit(CMB_TIER.PATT_TSENAB). The pattern match trigger output is achieved via setting values into the CMB trigger pattern and mask registers (CMB_XPR and CMB_XPMR). After configuring a pattern through these registers, the TPDM subunit will assert an output trigger every time it receives new input data that matches the configured pattern value. Values in a given bit number of the mask register correspond to the same bit number in the corresponding pattern register. Reviewed-by: James Clark Signed-off-by: Tao Zhang Signed-off-by: Jinlong Mao Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/1707024641-22460-8-git-send-email-quic_taozha@quicinc.com --- .../testing/sysfs-bus-coresight-devices-tpdm | 30 ++++++ drivers/hwtracing/coresight/coresight-tpdm.c | 96 ++++++++++++++++++- drivers/hwtracing/coresight/coresight-tpdm.h | 39 ++++++++ 3 files changed, 164 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm index 6dfb18d6d64ae..b6cf050861edf 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm @@ -184,3 +184,33 @@ Description: (Write) Set the data collection mode of CMB tpdm. Continuous Accepts only one of the 2 values - 0 or 1. 0 : Continuous CMB collection mode. 1 : Trace-on-change CMB collection mode. + +What: /sys/bus/coresight/devices//cmb_trig_patt/xpr[0:1] +Date: January 2024 +KernelVersion 6.9 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the value of the trigger pattern for the CMB + subunit TPDM. + +What: /sys/bus/coresight/devices//cmb_trig_patt/xpmr[0:1] +Date: January 2024 +KernelVersion 6.9 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the mask of the trigger pattern for the CMB + subunit TPDM. + +What: /sys/bus/coresight/devices//dsb_patt/tpr[0:1] +Date: January 2024 +KernelVersion 6.9 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the value of the pattern for the CMB subunit TPDM. + +What: /sys/bus/coresight/devices//dsb_patt/tpmr[0:1] +Date: January 2024 +KernelVersion 6.9 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the mask of the pattern for the CMB subunit TPDM. diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index b200714603754..07587287d9fac 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -66,6 +66,26 @@ static ssize_t tpdm_simple_dataset_show(struct device *dev, return -EINVAL; return sysfs_emit(buf, "0x%x\n", drvdata->dsb->msr[tpdm_attr->idx]); + case CMB_TRIG_PATT: + if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) + return -EINVAL; + return sysfs_emit(buf, "0x%x\n", + drvdata->cmb->trig_patt[tpdm_attr->idx]); + case CMB_TRIG_PATT_MASK: + if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) + return -EINVAL; + return sysfs_emit(buf, "0x%x\n", + drvdata->cmb->trig_patt_mask[tpdm_attr->idx]); + case CMB_PATT: + if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) + return -EINVAL; + return sysfs_emit(buf, "0x%x\n", + drvdata->cmb->patt_val[tpdm_attr->idx]); + case CMB_PATT_MASK: + if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) + return -EINVAL; + return sysfs_emit(buf, "0x%x\n", + drvdata->cmb->patt_mask[tpdm_attr->idx]); } return -EINVAL; } @@ -118,6 +138,30 @@ static ssize_t tpdm_simple_dataset_store(struct device *dev, ret = size; } break; + case CMB_TRIG_PATT: + if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) { + drvdata->cmb->trig_patt[tpdm_attr->idx] = val; + ret = size; + } + break; + case CMB_TRIG_PATT_MASK: + if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) { + drvdata->cmb->trig_patt_mask[tpdm_attr->idx] = val; + ret = size; + } + break; + case CMB_PATT: + if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) { + drvdata->cmb->patt_val[tpdm_attr->idx] = val; + ret = size; + } + break; + case CMB_PATT_MASK: + if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) { + drvdata->cmb->patt_mask[tpdm_attr->idx] = val; + ret = size; + } + break; default: break; } @@ -280,12 +324,32 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata) { - u32 val; + u32 val, i; if (!tpdm_has_cmb_dataset(drvdata)) return; + /* Configure pattern registers */ + for (i = 0; i < TPDM_CMB_MAX_PATT; i++) { + writel_relaxed(drvdata->cmb->patt_val[i], + drvdata->base + TPDM_CMB_TPR(i)); + writel_relaxed(drvdata->cmb->patt_mask[i], + drvdata->base + TPDM_CMB_TPMR(i)); + writel_relaxed(drvdata->cmb->trig_patt[i], + drvdata->base + TPDM_CMB_XPR(i)); + writel_relaxed(drvdata->cmb->trig_patt_mask[i], + drvdata->base + TPDM_CMB_XPMR(i)); + } + val = readl_relaxed(drvdata->base + TPDM_CMB_CR); + /* + * Set to 0 for continuous CMB collection mode, + * 1 for trace-on-change CMB collection mode. + */ + if (drvdata->cmb->trace_mode) + val |= TPDM_CMB_CR_MODE; + else + val &= ~TPDM_CMB_CR_MODE; /* Set the enable bit of CMB control register to 1 */ val |= TPDM_CMB_CR_ENA; writel_relaxed(val, drvdata->base + TPDM_CMB_CR); @@ -887,6 +951,22 @@ static struct attribute *tpdm_dsb_msr_attrs[] = { NULL, }; +static struct attribute *tpdm_cmb_trig_patt_attrs[] = { + CMB_TRIG_PATT_ATTR(0), + CMB_TRIG_PATT_ATTR(1), + CMB_TRIG_PATT_MASK_ATTR(0), + CMB_TRIG_PATT_MASK_ATTR(1), + NULL, +}; + +static struct attribute *tpdm_cmb_patt_attrs[] = { + CMB_PATT_ATTR(0), + CMB_PATT_ATTR(1), + CMB_PATT_MASK_ATTR(0), + CMB_PATT_MASK_ATTR(1), + NULL, +}; + static struct attribute *tpdm_dsb_attrs[] = { &dev_attr_dsb_mode.attr, &dev_attr_dsb_trig_ts.attr, @@ -933,6 +1013,18 @@ static struct attribute_group tpdm_cmb_attr_grp = { .is_visible = tpdm_cmb_is_visible, }; +static struct attribute_group tpdm_cmb_trig_patt_grp = { + .attrs = tpdm_cmb_trig_patt_attrs, + .is_visible = tpdm_cmb_is_visible, + .name = "cmb_trig_patt", +}; + +static struct attribute_group tpdm_cmb_patt_grp = { + .attrs = tpdm_cmb_patt_attrs, + .is_visible = tpdm_cmb_is_visible, + .name = "cmb_patt", +}; + static const struct attribute_group *tpdm_attr_grps[] = { &tpdm_attr_grp, &tpdm_dsb_attr_grp, @@ -941,6 +1033,8 @@ static const struct attribute_group *tpdm_attr_grps[] = { &tpdm_dsb_patt_grp, &tpdm_dsb_msr_grp, &tpdm_cmb_attr_grp, + &tpdm_cmb_trig_patt_grp, + &tpdm_cmb_patt_grp, NULL, }; diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index 2af92c270ed12..e5d4c22cd38c3 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -11,12 +11,23 @@ /* CMB Subunit Registers */ #define TPDM_CMB_CR (0xA00) +/* CMB subunit timestamp pattern registers */ +#define TPDM_CMB_TPR(n) (0xA08 + (n * 4)) +/* CMB subunit timestamp pattern mask registers */ +#define TPDM_CMB_TPMR(n) (0xA10 + (n * 4)) +/* CMB subunit trigger pattern registers */ +#define TPDM_CMB_XPR(n) (0xA18 + (n * 4)) +/* CMB subunit trigger pattern mask registers */ +#define TPDM_CMB_XPMR(n) (0xA20 + (n * 4)) /* Enable bit for CMB subunit */ #define TPDM_CMB_CR_ENA BIT(0) /* Trace collection mode for CMB subunit */ #define TPDM_CMB_CR_MODE BIT(1) +/* Patten register number */ +#define TPDM_CMB_MAX_PATT 2 + /* DSB Subunit Registers */ #define TPDM_DSB_CR (0x780) #define TPDM_DSB_TIER (0x784) @@ -151,6 +162,22 @@ tpdm_simple_dataset_rw(msr##nr, \ DSB_MSR, nr) +#define CMB_TRIG_PATT_ATTR(nr) \ + tpdm_simple_dataset_rw(xpr##nr, \ + CMB_TRIG_PATT, nr) + +#define CMB_TRIG_PATT_MASK_ATTR(nr) \ + tpdm_simple_dataset_rw(xpmr##nr, \ + CMB_TRIG_PATT_MASK, nr) + +#define CMB_PATT_ATTR(nr) \ + tpdm_simple_dataset_rw(tpr##nr, \ + CMB_PATT, nr) + +#define CMB_PATT_MASK_ATTR(nr) \ + tpdm_simple_dataset_rw(tpmr##nr, \ + CMB_PATT_MASK, nr) + /** * struct dsb_dataset - specifics associated to dsb dataset * @mode: DSB programming mode @@ -186,9 +213,17 @@ struct dsb_dataset { /** * struct cmb_dataset * @trace_mode: Dataset collection mode + * @patt_val: Save value for pattern + * @patt_mask: Save value for pattern mask + * @trig_patt: Save value for trigger pattern + * @trig_patt_mask: Save value for trigger pattern mask */ struct cmb_dataset { u32 trace_mode; + u32 patt_val[TPDM_CMB_MAX_PATT]; + u32 patt_mask[TPDM_CMB_MAX_PATT]; + u32 trig_patt[TPDM_CMB_MAX_PATT]; + u32 trig_patt_mask[TPDM_CMB_MAX_PATT]; }; /** @@ -225,6 +260,10 @@ enum dataset_mem { DSB_PATT, DSB_PATT_MASK, DSB_MSR, + CMB_TRIG_PATT, + CMB_TRIG_PATT_MASK, + CMB_PATT, + CMB_PATT_MASK }; /** From dc6ce57e2aa0b10b0b78517245ea0ba47eed75b1 Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Sun, 4 Feb 2024 13:30:39 +0800 Subject: [PATCH 25/32] coresight-tpdm: Add timestamp control register support for the CMB CMB_TIER register is CMB subunit timestamp insertion enable register. Bit 0 is PATT_TSENAB bit. Set this bit to 1 to request a timestamp following a CMB interface pattern match. Bit 1 is XTRIG_TSENAB bit. Set this bit to 1 to request a timestamp following a CMB CTI timestamp request. Bit 2 is TS_ALL bit. Set this bit to 1 to request timestamp for all packets. Reviewed-by: James Clark Signed-off-by: Tao Zhang Signed-off-by: Jinlong Mao Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/1707024641-22460-9-git-send-email-quic_taozha@quicinc.com --- .../testing/sysfs-bus-coresight-devices-tpdm | 35 +++++ drivers/hwtracing/coresight/coresight-tpdm.c | 121 +++++++++++++++++- drivers/hwtracing/coresight/coresight-tpdm.h | 31 +++++ 3 files changed, 180 insertions(+), 7 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm index b6cf050861edf..e8c76ce4dd155 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm @@ -214,3 +214,38 @@ KernelVersion 6.9 Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) Description: (RW) Set/Get the mask of the pattern for the CMB subunit TPDM. + +What: /sys/bus/coresight/devices//cmb_patt/enable_ts +Date: January 2024 +KernelVersion 6.9 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (Write) Set the pattern timestamp of CMB tpdm. Read + the pattern timestamp of CMB tpdm. + + Accepts only one of the 2 values - 0 or 1. + 0 : Disable CMB pattern timestamp. + 1 : Enable CMB pattern timestamp. + +What: /sys/bus/coresight/devices//cmb_trig_ts +Date: January 2024 +KernelVersion 6.9 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the trigger timestamp of the CMB for tpdm. + + Accepts only one of the 2 values - 0 or 1. + 0 : Set the CMB trigger type to false + 1 : Set the CMB trigger type to true + +What: /sys/bus/coresight/devices//cmb_ts_all +Date: January 2024 +KernelVersion 6.9 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Read or write the status of timestamp upon all interface. + Only value 0 and 1 can be written to this node. Set this node to 1 to requeset + timestamp to all trace packet. + Accepts only one of the 2 values - 0 or 1. + 0 : Disable the timestamp of all trace packets. + 1 : Enable the timestamp of all trace packets. diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 07587287d9fac..22966d541230a 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -322,6 +322,31 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) writel_relaxed(val, drvdata->base + TPDM_DSB_CR); } +static void set_cmb_tier(struct tpdm_drvdata *drvdata) +{ + u32 val; + + val = readl_relaxed(drvdata->base + TPDM_CMB_TIER); + + /* Clear all relevant fields */ + val &= ~(TPDM_CMB_TIER_PATT_TSENAB | TPDM_CMB_TIER_TS_ALL | + TPDM_CMB_TIER_XTRIG_TSENAB); + + /* Set pattern timestamp type and enablement */ + if (drvdata->cmb->patt_ts) + val |= TPDM_CMB_TIER_PATT_TSENAB; + + /* Set trigger timestamp */ + if (drvdata->cmb->trig_ts) + val |= TPDM_CMB_TIER_XTRIG_TSENAB; + + /* Set all timestamp enablement*/ + if (drvdata->cmb->ts_all) + val |= TPDM_CMB_TIER_TS_ALL; + + writel_relaxed(val, drvdata->base + TPDM_CMB_TIER); +} + static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata) { u32 val, i; @@ -341,6 +366,8 @@ static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata) drvdata->base + TPDM_CMB_XPMR(i)); } + set_cmb_tier(drvdata); + val = readl_relaxed(drvdata->base + TPDM_CMB_CR); /* * Set to 0 for continuous CMB collection mode, @@ -687,9 +714,18 @@ static ssize_t enable_ts_show(struct device *dev, char *buf) { struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct tpdm_dataset_attribute *tpdm_attr = + container_of(attr, struct tpdm_dataset_attribute, attr); + ssize_t size = -EINVAL; - return sysfs_emit(buf, "%u\n", - (unsigned int)drvdata->dsb->patt_ts); + if (tpdm_attr->mem == DSB_PATT) + size = sysfs_emit(buf, "%u\n", + (unsigned int)drvdata->dsb->patt_ts); + else if (tpdm_attr->mem == CMB_PATT) + size = sysfs_emit(buf, "%u\n", + (unsigned int)drvdata->cmb->patt_ts); + + return size; } /* @@ -701,17 +737,23 @@ static ssize_t enable_ts_store(struct device *dev, size_t size) { struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + struct tpdm_dataset_attribute *tpdm_attr = + container_of(attr, struct tpdm_dataset_attribute, attr); unsigned long val; if ((kstrtoul(buf, 0, &val)) || (val & ~1UL)) return -EINVAL; - spin_lock(&drvdata->spinlock); - drvdata->dsb->patt_ts = !!val; - spin_unlock(&drvdata->spinlock); + guard(spinlock)(&drvdata->spinlock); + if (tpdm_attr->mem == DSB_PATT) + drvdata->dsb->patt_ts = !!val; + else if (tpdm_attr->mem == CMB_PATT) + drvdata->cmb->patt_ts = !!val; + else + return -EINVAL; + return size; } -static DEVICE_ATTR_RW(enable_ts); static ssize_t set_type_show(struct device *dev, struct device_attribute *attr, @@ -842,6 +884,68 @@ static ssize_t cmb_mode_store(struct device *dev, } static DEVICE_ATTR_RW(cmb_mode); +static ssize_t cmb_ts_all_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return sysfs_emit(buf, "%u\n", + (unsigned int)drvdata->cmb->ts_all); +} + +static ssize_t cmb_ts_all_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if ((kstrtoul(buf, 0, &val)) || (val & ~1UL)) + return -EINVAL; + + guard(spinlock)(&drvdata->spinlock); + if (val) + drvdata->cmb->ts_all = true; + else + drvdata->cmb->ts_all = false; + + return size; +} +static DEVICE_ATTR_RW(cmb_ts_all); + +static ssize_t cmb_trig_ts_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return sysfs_emit(buf, "%u\n", + (unsigned int)drvdata->cmb->trig_ts); +} + +static ssize_t cmb_trig_ts_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if ((kstrtoul(buf, 0, &val)) || (val & ~1UL)) + return -EINVAL; + + guard(spinlock)(&drvdata->spinlock); + if (val) + drvdata->cmb->trig_ts = true; + else + drvdata->cmb->trig_ts = false; + + return size; +} +static DEVICE_ATTR_RW(cmb_trig_ts); + static struct attribute *tpdm_dsb_edge_attrs[] = { &dev_attr_ctrl_idx.attr, &dev_attr_ctrl_val.attr, @@ -910,7 +1014,7 @@ static struct attribute *tpdm_dsb_patt_attrs[] = { DSB_PATT_MASK_ATTR(5), DSB_PATT_MASK_ATTR(6), DSB_PATT_MASK_ATTR(7), - &dev_attr_enable_ts.attr, + DSB_PATT_ENABLE_TS, &dev_attr_set_type.attr, NULL, }; @@ -964,6 +1068,7 @@ static struct attribute *tpdm_cmb_patt_attrs[] = { CMB_PATT_ATTR(1), CMB_PATT_MASK_ATTR(0), CMB_PATT_MASK_ATTR(1), + CMB_PATT_ENABLE_TS, NULL, }; @@ -976,6 +1081,8 @@ static struct attribute *tpdm_dsb_attrs[] = { static struct attribute *tpdm_cmb_attrs[] = { &dev_attr_cmb_mode.attr, + &dev_attr_cmb_ts_all.attr, + &dev_attr_cmb_trig_ts.attr, NULL, }; diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index e5d4c22cd38c3..6d1fe4aed7d03 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -11,6 +11,8 @@ /* CMB Subunit Registers */ #define TPDM_CMB_CR (0xA00) +/* CMB subunit timestamp insertion enable register */ +#define TPDM_CMB_TIER (0xA04) /* CMB subunit timestamp pattern registers */ #define TPDM_CMB_TPR(n) (0xA08 + (n * 4)) /* CMB subunit timestamp pattern mask registers */ @@ -24,6 +26,12 @@ #define TPDM_CMB_CR_ENA BIT(0) /* Trace collection mode for CMB subunit */ #define TPDM_CMB_CR_MODE BIT(1) +/* Timestamp control for pattern match */ +#define TPDM_CMB_TIER_PATT_TSENAB BIT(0) +/* CMB CTI timestamp request */ +#define TPDM_CMB_TIER_XTRIG_TSENAB BIT(1) +/* For timestamp fo all trace */ +#define TPDM_CMB_TIER_TS_ALL BIT(2) /* Patten register number */ #define TPDM_CMB_MAX_PATT 2 @@ -134,6 +142,15 @@ } \ })[0].attr.attr) +#define tpdm_patt_enable_ts(name, mem) \ + (&((struct tpdm_dataset_attribute[]) { \ + { \ + __ATTR(name, 0644, enable_ts_show, \ + enable_ts_store), \ + mem, \ + } \ + })[0].attr.attr) + #define DSB_EDGE_CTRL_ATTR(nr) \ tpdm_simple_dataset_ro(edcr##nr, \ DSB_EDGE_CTRL, nr) @@ -158,6 +175,10 @@ tpdm_simple_dataset_rw(tpmr##nr, \ DSB_PATT_MASK, nr) +#define DSB_PATT_ENABLE_TS \ + tpdm_patt_enable_ts(enable_ts, \ + DSB_PATT) + #define DSB_MSR_ATTR(nr) \ tpdm_simple_dataset_rw(msr##nr, \ DSB_MSR, nr) @@ -178,6 +199,10 @@ tpdm_simple_dataset_rw(tpmr##nr, \ CMB_PATT_MASK, nr) +#define CMB_PATT_ENABLE_TS \ + tpdm_patt_enable_ts(enable_ts, \ + CMB_PATT) + /** * struct dsb_dataset - specifics associated to dsb dataset * @mode: DSB programming mode @@ -217,6 +242,9 @@ struct dsb_dataset { * @patt_mask: Save value for pattern mask * @trig_patt: Save value for trigger pattern * @trig_patt_mask: Save value for trigger pattern mask + * @patt_ts: Indicates if pattern match for timestamp is enabled. + * @trig_ts: Indicates if CTI trigger for timestamp is enabled. + * @ts_all: Indicates if timestamp is enabled for all packets. */ struct cmb_dataset { u32 trace_mode; @@ -224,6 +252,9 @@ struct cmb_dataset { u32 patt_mask[TPDM_CMB_MAX_PATT]; u32 trig_patt[TPDM_CMB_MAX_PATT]; u32 trig_patt_mask[TPDM_CMB_MAX_PATT]; + bool patt_ts; + bool trig_ts; + bool ts_all; }; /** From 19bfaff3845727f354079a140f092336d97e5c1e Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Sun, 4 Feb 2024 13:30:40 +0800 Subject: [PATCH 26/32] dt-bindings: arm: qcom,coresight-tpdm: Add support for TPDM CMB MSR register Add property "qcom,cmb_msr_num" to support CMB MSR(mux select register) for TPDM. It specifies the number of CMB MSR registers supported by the TDPM. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Tao Zhang Signed-off-by: Mao Jinlong Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/1707024641-22460-10-git-send-email-quic_taozha@quicinc.com --- .../devicetree/bindings/arm/qcom,coresight-tpdm.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml index 2320b54459006..d0647ffaed71e 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml @@ -69,6 +69,15 @@ properties: minimum: 0 maximum: 32 + qcom,cmb-msrs-num: + description: + Specifies the number of CMB MSR(mux select register) registers supported + by the monitor. If this property is not configured or set to 0, it means + this TPDM doesn't support CMB MSR. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 32 + clocks: maxItems: 1 @@ -123,6 +132,7 @@ examples: reg = <0x06c29000 0x1000>; qcom,cmb-element-bits = <64>; + qcom,cmb-msrs-num = <32>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; From 8e8804145a46e092c5207bb1258d29236a2cbcaa Mon Sep 17 00:00:00 2001 From: Tao Zhang Date: Sun, 4 Feb 2024 13:30:41 +0800 Subject: [PATCH 27/32] coresight-tpdm: Add msr register support for CMB Add the nodes for CMB subunit MSR(mux select register) support. CMB MSRs(mux select registers) is to separate mux, arbitration, interleaving,data packing control from stream filtering control. Reviewed-by: James Clark Signed-off-by: Tao Zhang Signed-off-by: Mao Jinlong Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/1707024641-22460-11-git-send-email-quic_taozha@quicinc.com --- .../testing/sysfs-bus-coresight-devices-tpdm | 8 ++ drivers/hwtracing/coresight/coresight-tpdm.c | 85 +++++++++++++++++++ drivers/hwtracing/coresight/coresight-tpdm.h | 16 +++- 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm index e8c76ce4dd155..b4d0fc8d319df 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm @@ -249,3 +249,11 @@ Description: Accepts only one of the 2 values - 0 or 1. 0 : Disable the timestamp of all trace packets. 1 : Enable the timestamp of all trace packets. + +What: /sys/bus/coresight/devices//cmb_msr/msr[0:31] +Date: January 2024 +KernelVersion 6.9 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the MSR(mux select register) for the CMB subunit + TPDM. diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 22966d541230a..a9708ab0d4886 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -86,6 +86,11 @@ static ssize_t tpdm_simple_dataset_show(struct device *dev, return -EINVAL; return sysfs_emit(buf, "0x%x\n", drvdata->cmb->patt_mask[tpdm_attr->idx]); + case CMB_MSR: + if (tpdm_attr->idx >= drvdata->cmb_msr_num) + return -EINVAL; + return sysfs_emit(buf, "0x%x\n", + drvdata->cmb->msr[tpdm_attr->idx]); } return -EINVAL; } @@ -162,6 +167,12 @@ static ssize_t tpdm_simple_dataset_store(struct device *dev, ret = size; } break; + case CMB_MSR: + if (tpdm_attr->idx < drvdata->cmb_msr_num) { + drvdata->cmb->msr[tpdm_attr->idx] = val; + ret = size; + } + break; default: break; } @@ -209,6 +220,23 @@ static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj, return 0; } +static umode_t tpdm_cmb_msr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + struct device_attribute *dev_attr = + container_of(attr, struct device_attribute, attr); + struct tpdm_dataset_attribute *tpdm_attr = + container_of(dev_attr, struct tpdm_dataset_attribute, attr); + + if (tpdm_attr->idx < drvdata->cmb_msr_num) + return attr->mode; + + return 0; +} + static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata) { if (tpdm_has_dsb_dataset(drvdata)) { @@ -347,6 +375,15 @@ static void set_cmb_tier(struct tpdm_drvdata *drvdata) writel_relaxed(val, drvdata->base + TPDM_CMB_TIER); } +static void set_cmb_msr(struct tpdm_drvdata *drvdata) +{ + int i; + + for (i = 0; i < drvdata->cmb_msr_num; i++) + writel_relaxed(drvdata->cmb->msr[i], + drvdata->base + TPDM_CMB_MSR(i)); +} + static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata) { u32 val, i; @@ -367,6 +404,7 @@ static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata) } set_cmb_tier(drvdata); + set_cmb_msr(drvdata); val = readl_relaxed(drvdata->base + TPDM_CMB_CR); /* @@ -1072,6 +1110,42 @@ static struct attribute *tpdm_cmb_patt_attrs[] = { NULL, }; +static struct attribute *tpdm_cmb_msr_attrs[] = { + CMB_MSR_ATTR(0), + CMB_MSR_ATTR(1), + CMB_MSR_ATTR(2), + CMB_MSR_ATTR(3), + CMB_MSR_ATTR(4), + CMB_MSR_ATTR(5), + CMB_MSR_ATTR(6), + CMB_MSR_ATTR(7), + CMB_MSR_ATTR(8), + CMB_MSR_ATTR(9), + CMB_MSR_ATTR(10), + CMB_MSR_ATTR(11), + CMB_MSR_ATTR(12), + CMB_MSR_ATTR(13), + CMB_MSR_ATTR(14), + CMB_MSR_ATTR(15), + CMB_MSR_ATTR(16), + CMB_MSR_ATTR(17), + CMB_MSR_ATTR(18), + CMB_MSR_ATTR(19), + CMB_MSR_ATTR(20), + CMB_MSR_ATTR(21), + CMB_MSR_ATTR(22), + CMB_MSR_ATTR(23), + CMB_MSR_ATTR(24), + CMB_MSR_ATTR(25), + CMB_MSR_ATTR(26), + CMB_MSR_ATTR(27), + CMB_MSR_ATTR(28), + CMB_MSR_ATTR(29), + CMB_MSR_ATTR(30), + CMB_MSR_ATTR(31), + NULL, +}; + static struct attribute *tpdm_dsb_attrs[] = { &dev_attr_dsb_mode.attr, &dev_attr_dsb_trig_ts.attr, @@ -1132,6 +1206,12 @@ static struct attribute_group tpdm_cmb_patt_grp = { .name = "cmb_patt", }; +static struct attribute_group tpdm_cmb_msr_grp = { + .attrs = tpdm_cmb_msr_attrs, + .is_visible = tpdm_cmb_msr_is_visible, + .name = "cmb_msr", +}; + static const struct attribute_group *tpdm_attr_grps[] = { &tpdm_attr_grp, &tpdm_dsb_attr_grp, @@ -1142,6 +1222,7 @@ static const struct attribute_group *tpdm_attr_grps[] = { &tpdm_cmb_attr_grp, &tpdm_cmb_trig_patt_grp, &tpdm_cmb_patt_grp, + &tpdm_cmb_msr_grp, NULL, }; @@ -1180,6 +1261,10 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) of_property_read_u32(drvdata->dev->of_node, "qcom,dsb-msrs-num", &drvdata->dsb_msr_num); + if (drvdata && tpdm_has_cmb_dataset(drvdata)) + of_property_read_u32(drvdata->dev->of_node, + "qcom,cmb-msrs-num", &drvdata->cmb_msr_num); + /* Set up coresight component description */ desc.name = coresight_alloc_device_name(&tpdm_devs, dev); if (!desc.name) diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index 6d1fe4aed7d03..f3a8f56d0fe76 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -21,6 +21,8 @@ #define TPDM_CMB_XPR(n) (0xA18 + (n * 4)) /* CMB subunit trigger pattern mask registers */ #define TPDM_CMB_XPMR(n) (0xA20 + (n * 4)) +/* CMB MSR register */ +#define TPDM_CMB_MSR(n) (0xA80 + (n * 4)) /* Enable bit for CMB subunit */ #define TPDM_CMB_CR_ENA BIT(0) @@ -36,6 +38,9 @@ /* Patten register number */ #define TPDM_CMB_MAX_PATT 2 +/* MAX number of DSB MSR */ +#define TPDM_CMB_MAX_MSR 32 + /* DSB Subunit Registers */ #define TPDM_DSB_CR (0x780) #define TPDM_DSB_TIER (0x784) @@ -203,6 +208,10 @@ tpdm_patt_enable_ts(enable_ts, \ CMB_PATT) +#define CMB_MSR_ATTR(nr) \ + tpdm_simple_dataset_rw(msr##nr, \ + CMB_MSR, nr) + /** * struct dsb_dataset - specifics associated to dsb dataset * @mode: DSB programming mode @@ -242,6 +251,7 @@ struct dsb_dataset { * @patt_mask: Save value for pattern mask * @trig_patt: Save value for trigger pattern * @trig_patt_mask: Save value for trigger pattern mask + * @msr Save value for MSR * @patt_ts: Indicates if pattern match for timestamp is enabled. * @trig_ts: Indicates if CTI trigger for timestamp is enabled. * @ts_all: Indicates if timestamp is enabled for all packets. @@ -252,6 +262,7 @@ struct cmb_dataset { u32 patt_mask[TPDM_CMB_MAX_PATT]; u32 trig_patt[TPDM_CMB_MAX_PATT]; u32 trig_patt_mask[TPDM_CMB_MAX_PATT]; + u32 msr[TPDM_CMB_MAX_MSR]; bool patt_ts; bool trig_ts; bool ts_all; @@ -268,6 +279,7 @@ struct cmb_dataset { * @dsb Specifics associated to TPDM DSB. * @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 */ struct tpdm_drvdata { @@ -280,6 +292,7 @@ struct tpdm_drvdata { struct dsb_dataset *dsb; struct cmb_dataset *cmb; u32 dsb_msr_num; + u32 cmb_msr_num; }; /* Enumerate members of various datasets */ @@ -294,7 +307,8 @@ enum dataset_mem { CMB_TRIG_PATT, CMB_TRIG_PATT_MASK, CMB_PATT, - CMB_PATT_MASK + CMB_PATT_MASK, + CMB_MSR }; /** From 1bbe0a247e5d72f723daeecf41596bfa99e199f1 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Wed, 31 Jan 2024 02:54:19 -0800 Subject: [PATCH 28/32] coresight: etm4x: Set skip_power_up in etm4_init_arch_data function skip_power_up is used in etm4_init_arch_data when set lpoverride. So need to set the value of it before calling using it. Fixes: 5214b563588e ("coresight: etm4x: Add support for sysreg only devices") Signed-off-by: Mao Jinlong Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240131105423.9519-1-quic_jinlmao@quicinc.com --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index f087bc8d1da6b..c2ca4a02dfce1 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1196,6 +1196,7 @@ static void etm4_init_arch_data(void *info) struct etm4_init_arg *init_arg = info; struct etmv4_drvdata *drvdata; struct csdev_access *csa; + struct device *dev = init_arg->dev; int i; drvdata = dev_get_drvdata(init_arg->dev); @@ -1209,6 +1210,10 @@ static void etm4_init_arch_data(void *info) if (!etm4_init_csdev_access(drvdata, csa)) return; + if (!csa->io_mem || + fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up")) + drvdata->skip_power_up = true; + /* Detect the support for OS Lock before we actually use it */ etm_detect_os_lock(drvdata, csa); @@ -2036,11 +2041,6 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg) if (!drvdata->arch) return -EINVAL; - /* TRCPDCR is not accessible with system instructions. */ - if (!desc.access.io_mem || - fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up")) - drvdata->skip_power_up = true; - major = ETM_ARCH_MAJOR_VERSION(drvdata->arch); minor = ETM_ARCH_MINOR_VERSION(drvdata->arch); From c099fdd218a0fedfe87e0b88d2ba0667eab3b3c8 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Tue, 13 Feb 2024 10:12:46 +0000 Subject: [PATCH 29/32] coresight: tpdm: Fix build break due to uninitialised field {CMB/DSB}_PATT_ENABLE_TS attributes do not use an "idx" field and never sets it. But, since have full blown warning enabled in coresight, it triggerst the warning on some of the newer compiler versions: drivers/hwtracing/coresight/coresight-tpdm.c:1055:2: error: missing field 'idx' initializer [-Werror,-Wmissing-field-initializers] 1055 | DSB_PATT_ENABLE_TS, | ^ drivers/hwtracing/coresight/coresight-tpdm.h:184:3: note: expanded from macro 'DSB_PATT_ENABLE_TS' 184 | tpdm_patt_enable_ts(enable_ts, \ | ^ drivers/hwtracing/coresight/coresight-tpdm.h:156:5: note: expanded from macro 'tpdm_patt_enable_ts' 156 | } \ | ^ drivers/hwtracing/coresight/coresight-tpdm.c:1109:2: error: missing field 'idx' initializer [-Werror,-Wmissing-field-initializers] 1109 | CMB_PATT_ENABLE_TS, | ^ drivers/hwtracing/coresight/coresight-tpdm.h:208:3: note: expanded from macro 'CMB_PATT_ENABLE_TS' 208 | tpdm_patt_enable_ts(enable_ts, \ | ^ drivers/hwtracing/coresight/coresight-tpdm.h:156:5: note: expanded from macro 'tpdm_patt_enable_ts' 156 | } \ | ^ Make sure we initialise this. Fixes: dc6ce57e2aa0 ("coresight-tpdm: Add timestamp control register support for the CMB") Acked-by: Arnd Bergmann Reported-by: Arnd Bergmann Cc: Tao Zhang Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-tpdm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h index f3a8f56d0fe76..e08d212642e35 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.h +++ b/drivers/hwtracing/coresight/coresight-tpdm.h @@ -153,6 +153,7 @@ __ATTR(name, 0644, enable_ts_show, \ enable_ts_store), \ mem, \ + 0, \ } \ })[0].attr.attr) From 06226d120a28f146abd3637799958a4dc4dbb7a1 Mon Sep 17 00:00:00 2001 From: Yang Jihong Date: Mon, 8 Jan 2024 12:19:06 +0000 Subject: [PATCH 30/32] hwtracing: hisi_ptt: Move type check to the beginning of hisi_ptt_pmu_event_init() When perf_init_event() calls perf_try_init_event() to init pmu driver, searches for the next pmu driver only when the return value is -ENOENT. Therefore, hisi_ptt_pmu_event_init() needs to check the type at the beginning of the function. Otherwise, in the case of perf-task mode, perf_try_init_event() returns -EOPNOTSUPP and skips subsequent pmu drivers, causes perf_init_event() to fail. Fixes: ff0de066b463 ("hwtracing: hisi_ptt: Add trace function support for HiSilicon PCIe Tune and Trace device") Signed-off-by: Yang Jihong Reviewed-by: Yicong Yang Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20240108121906.3514820-1-yangjihong1@huawei.com --- drivers/hwtracing/ptt/hisi_ptt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c index c1b5fd2b89741..4bf04a9778407 100644 --- a/drivers/hwtracing/ptt/hisi_ptt.c +++ b/drivers/hwtracing/ptt/hisi_ptt.c @@ -998,6 +998,9 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event) int ret; u32 val; + if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type) + return -ENOENT; + if (event->cpu < 0) { dev_dbg(event->pmu->dev, "Per-task mode not supported\n"); return -EOPNOTSUPP; @@ -1006,9 +1009,6 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event) if (event->attach_state & PERF_ATTACH_TASK) return -EOPNOTSUPP; - if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type) - return -ENOENT; - ret = hisi_ptt_trace_valid_filter(hisi_ptt, event->attr.config); if (ret < 0) return ret; From 7f6860e856062fc927127fa731288b909af797bc Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Sun, 18 Feb 2024 01:43:19 -0800 Subject: [PATCH 31/32] dt-bindings: arm: qcom,coresight-tpdm: Rename qcom,dsb-element-size The unit for TPDM DSB element size is bits. So rename the property: qcom,dsb-element-size => qcom,dsb-element-bits This also makes it consistent with the naming for the CMB element size property. There is no tpdm node in any DT as of now. Make this change before any tpdm node is added to DT. Fixes: 2a8d9b371566 ("dt-bindings: arm: Add support for DSB element size") Signed-off-by: Mao Jinlong Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240218094322.22470-2-quic_jinlmao@quicinc.com [ Reworded commit description to explain why we change this ] Signed-off-by: Suzuki K Poulose --- .../devicetree/bindings/arm/qcom,coresight-tpdm.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml index d0647ffaed71e..8eec07d9d4542 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml @@ -44,12 +44,11 @@ properties: minItems: 1 maxItems: 2 - qcom,dsb-element-size: + qcom,dsb-element-bits: description: Specifies the DSB(Discrete Single Bit) element size supported by the monitor. The associated aggregator will read this size before it is enabled. DSB element size currently only supports 32-bit and 64-bit. - $ref: /schemas/types.yaml#/definitions/uint8 enum: [32, 64] qcom,cmb-element-bits: @@ -111,7 +110,7 @@ examples: compatible = "qcom,coresight-tpdm", "arm,primecell"; reg = <0x0684c000 0x1000>; - qcom,dsb-element-size = /bits/ 8 <32>; + qcom,dsb-element-bits = <32>; qcom,dsb-msrs-num = <16>; clocks = <&aoss_qmp>; From a4f3057d19ffe1f5a7b9320303471a6725f11379 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Sun, 18 Feb 2024 01:43:20 -0800 Subject: [PATCH 32/32] coresight-tpda: Change qcom,dsb-element-size to qcom,dsb-elem-bits Change qcom,dsb-element-size to qcom,dsb-elem-bits as the unit is bit. When use "-bits" suffix, the type of the property is u32 from property-units.yaml, so use fwnode_property_read_u32 to read the property. Fixes: 57e7235aa1d1 ("coresight-tpda: Add DSB dataset support") Signed-off-by: Mao Jinlong Link: https://lore.kernel.org/r/20240218094322.22470-3-quic_jinlmao@quicinc.com Signed-off-by: Suzuki K Poulose --- drivers/hwtracing/coresight/coresight-tpda.c | 4 ++-- drivers/hwtracing/coresight/coresight-tpda.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index 6863afe7ca940..7739bc7adc449 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -69,8 +69,8 @@ static int tpdm_read_element_size(struct tpda_drvdata *drvdata, struct tpdm_drvdata *tpdm_data = dev_get_drvdata(csdev->dev.parent); if (tpdm_has_dsb_dataset(tpdm_data)) { - rc = fwnode_property_read_u8(dev_fwnode(csdev->dev.parent), - "qcom,dsb-element-size", &drvdata->dsb_esize); + rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent), + "qcom,dsb-element-bits", &drvdata->dsb_esize); } if (tpdm_has_cmb_dataset(tpdm_data)) { rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent), diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h index 19af64120fcfb..c6af3d2da3efe 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.h +++ b/drivers/hwtracing/coresight/coresight-tpda.h @@ -36,7 +36,7 @@ struct tpda_drvdata { struct coresight_device *csdev; spinlock_t spinlock; u8 atid; - u8 dsb_esize; + u32 dsb_esize; u32 cmb_esize; };