perf/arm_cspmu: Add devicetree support
Subsystems (2)
cover perf/arm_cspmu: Add devicetree support
Hi all,
This series does a bit more cleanup and adds devicetree support for CoreSight PMUs. The thing for which I originally wrote this has turned out not to warrant upstream support, but others have also expressed an interest so here it is.
Thanks,
Robin.
Robin Murphy (5):
perf/arm_cspmu: Simplify initialisation
perf/arm_cspmu: Simplify attribute groups
perf/arm_cspmu: Simplify counter reset
dt-bindings/perf: Add Arm CoreSight PMU
perf/arm_cspmu: Add devicetree support
.../bindings/perf/arm,coresight-pmu.yaml | 39 +++++ drivers/perf/arm_cspmu/arm_cspmu.c | 155 ++++++++++-------- drivers/perf/arm_cspmu/arm_cspmu.h | 1 + drivers/perf/arm_cspmu/nvidia_cspmu.c | 6 - 4 files changed, 126 insertions(+), 75 deletions(-) create mode 100644 Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
PATCH 1/5 perf/arm_cspmu: Simplify initialisation
It's far simpler for implementations to literally override whichever default ops they want to, by initialising to the default ops first. This saves all the bother of checking what the impl_init_ops call has or hasn't touched. Make the same clear distinction for the PMIIDR override as well, in case we gain more sources for overriding that in future.
--- drivers/perf/arm_cspmu/arm_cspmu.c | 55 +++++++++++---------------- drivers/perf/arm_cspmu/nvidia_cspmu.c | 6 --- 2 files changed, 22 insertions(+), 39 deletions(-)
drivers/perf/arm_cspmu/arm_cspmu.c +22 -33
@@ -100,13 +100,6 @@#define ARM_CSPMU_ACTIVE_CPU_MASK 0x0#define ARM_CSPMU_ASSOCIATED_CPU_MASK 0x1 -/* Check and use default if implementer doesn't provide attribute callback */ -#define CHECK_DEFAULT_IMPL_OPS (ops, callback) \ - do { \ - if (!ops->callback) \ - ops->callback = arm_cspmu_ ## callback; \ - } while (0) -/* * Maximum poll count for reading counter value using high-low-high sequence. */
@@ -408,21 +401,32 @@ static struct arm_cspmu_impl_match *arm_cspmu_impl_match_get(u32 pmiidr)return NULL ; } +#define DEFAULT_IMPL_OP (name) .name = arm_cspmu_##name +static int arm_cspmu_init_impl_ops (struct arm_cspmu *cspmu) {int ret =0 ; -struct arm_cspmu_impl_ops *impl_ops = &cspmu->impl.ops;struct acpi_apmt_node *apmt_node =arm_cspmu_apmt_node (cspmu->dev);struct arm_cspmu_impl_match *match; -/* -* Get PMU implementer and product id from APMT node. -* If APMT node doesn't have implementer/product id, try get it -* from PMIIDR. -*/ - cspmu->impl.pmiidr = - (apmt_node->impl_id) ? apmt_node->impl_id : -readl (cspmu->base0 +PMIIDR ); +/* Start with a default PMU implementation */ + cspmu->impl.module =THIS_MODULE ; + cspmu->impl.pmiidr =readl (cspmu->base0 +PMIIDR ); + cspmu->impl.ops = (struct arm_cspmu_impl_ops ) { +DEFAULT_IMPL_OP (get_event_attrs), +DEFAULT_IMPL_OP (get_format_attrs), +DEFAULT_IMPL_OP (get_identifier), +DEFAULT_IMPL_OP (get_name), +DEFAULT_IMPL_OP (is_cycle_counter_event), +DEFAULT_IMPL_OP (event_type), +DEFAULT_IMPL_OP (event_filter), +DEFAULT_IMPL_OP (set_ev_filter), +DEFAULT_IMPL_OP (event_attr_is_visible), + }; + +/* Firmware may override implementer/product ID from PMIIDR */ +if (apmt_node->impl_id) + cspmu->impl.pmiidr = apmt_node->impl_id;/* Find implementer specific attribute ops. */ match =arm_cspmu_impl_match_get (cspmu->impl.pmiidr);
@@ -450,24 +454,9 @@ static int arm_cspmu_init_impl_ops(struct arm_cspmu *cspmu) }mutex_unlock (&arm_cspmu_lock); + } -if (ret) -return ret; - }else - cspmu->impl.module =THIS_MODULE ; - -/* Use default callbacks if implementer doesn't provide one. */ -CHECK_DEFAULT_IMPL_OPS (impl_ops, get_event_attrs); -CHECK_DEFAULT_IMPL_OPS (impl_ops, get_format_attrs); -CHECK_DEFAULT_IMPL_OPS (impl_ops, get_identifier); -CHECK_DEFAULT_IMPL_OPS (impl_ops, get_name); -CHECK_DEFAULT_IMPL_OPS (impl_ops, is_cycle_counter_event); -CHECK_DEFAULT_IMPL_OPS (impl_ops, event_type); -CHECK_DEFAULT_IMPL_OPS (impl_ops, event_filter); -CHECK_DEFAULT_IMPL_OPS (impl_ops, event_attr_is_visible); -CHECK_DEFAULT_IMPL_OPS (impl_ops, set_ev_filter); - -return 0 ; +return ret; } static struct attribute_group *
drivers/perf/arm_cspmu/nvidia_cspmu.c +0 -6
@@ -388,12 +388,6 @@ static int nv_cspmu_init_ops(struct arm_cspmu *cspmu) impl_ops->get_format_attrs = nv_cspmu_get_format_attrs; impl_ops->get_name = nv_cspmu_get_name; -/* Set others to NULL to use default callback. */ - impl_ops->event_type =NULL ; - impl_ops->event_attr_is_visible =NULL ; - impl_ops->get_identifier =NULL ; - impl_ops->is_cycle_counter_event =NULL ; -return 0 ; }
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Re: [PATCH 1/5] perf/arm_cspmu: Simplify initialisation
Quoted 7 lines · Robin Murphy
It's far simpler for implementations to literally override whichever default ops they want to, by initialising to the default ops first. This saves all the bother of checking what the
impl_init_opscall has or hasn't touched. Make the same clear distinction for the PMIIDR override as well, in case we gain more sources for overriding that in future.Signed-off-by Robin Murphy <[email protected]>
Cheers, Ilkka
Quoted 113 lines
---
drivers/perf/arm_cspmu/arm_cspmu.c| 55 +++++++++++----------------drivers/perf/arm_cspmu/nvidia_cspmu.c| 6 ---2 files changed, 22 insertions(+), 39 deletions(-)drivers/perf/arm_cspmu/arm_cspmu.c +22
-33@@ -100,13 +100,6 @@#define ARM_CSPMU_ACTIVE_CPU_MASK 0x0#define ARM_CSPMU_ASSOCIATED_CPU_MASK 0x1 -/* Check and use default if implementer doesn't provide attribute callback */ -#define CHECK_DEFAULT_IMPL_OPS (ops, callback) \ - do { \ - if (!ops->callback) \ - ops->callback = arm_cspmu_ ## callback; \ - } while (0) -/* * Maximum poll count for reading counter value using high-low-high sequence. */ @@ -408,21 +401,32 @@ static struct arm_cspmu_impl_match *arm_cspmu_impl_match_get(u32 pmiidr)return NULL ; } +#define DEFAULT_IMPL_OP (name) .name = arm_cspmu_##name +static int arm_cspmu_init_impl_ops (struct arm_cspmu *cspmu) {int ret =0 ; -struct arm_cspmu_impl_ops *impl_ops = &cspmu->impl.ops;struct acpi_apmt_node *apmt_node =arm_cspmu_apmt_node (cspmu->dev);struct arm_cspmu_impl_match *match; -/* -* Get PMU implementer and product id from APMT node. -* If APMT node doesn't have implementer/product id, try get it -* from PMIIDR. -*/ - cspmu->impl.pmiidr = - (apmt_node->impl_id) ? apmt_node->impl_id : -readl (cspmu->base0 +PMIIDR ); +/* Start with a default PMU implementation */ + cspmu->impl.module =THIS_MODULE ; + cspmu->impl.pmiidr =readl (cspmu->base0 +PMIIDR ); + cspmu->impl.ops = (struct arm_cspmu_impl_ops ) { +DEFAULT_IMPL_OP (get_event_attrs), +DEFAULT_IMPL_OP (get_format_attrs), +DEFAULT_IMPL_OP (get_identifier), +DEFAULT_IMPL_OP (get_name), +DEFAULT_IMPL_OP (is_cycle_counter_event), +DEFAULT_IMPL_OP (event_type), +DEFAULT_IMPL_OP (event_filter), +DEFAULT_IMPL_OP (set_ev_filter), +DEFAULT_IMPL_OP (event_attr_is_visible), + }; + +/* Firmware may override implementer/product ID from PMIIDR */ +if (apmt_node->impl_id) + cspmu->impl.pmiidr = apmt_node->impl_id;/* Find implementer specific attribute ops. */ match =arm_cspmu_impl_match_get (cspmu->impl.pmiidr);@@ -450,24 +454,9 @@ static int arm_cspmu_init_impl_ops(struct arm_cspmu *cspmu) }mutex_unlock (&arm_cspmu_lock); + } -if (ret) -return ret; - }else - cspmu->impl.module =THIS_MODULE ; - -/* Use default callbacks if implementer doesn't provide one. */ -CHECK_DEFAULT_IMPL_OPS (impl_ops, get_event_attrs); -CHECK_DEFAULT_IMPL_OPS (impl_ops, get_format_attrs); -CHECK_DEFAULT_IMPL_OPS (impl_ops, get_identifier); -CHECK_DEFAULT_IMPL_OPS (impl_ops, get_name); -CHECK_DEFAULT_IMPL_OPS (impl_ops, is_cycle_counter_event); -CHECK_DEFAULT_IMPL_OPS (impl_ops, event_type); -CHECK_DEFAULT_IMPL_OPS (impl_ops, event_filter); -CHECK_DEFAULT_IMPL_OPS (impl_ops, event_attr_is_visible); -CHECK_DEFAULT_IMPL_OPS (impl_ops, set_ev_filter); - -return 0 ; +return ret; }static struct
attribute_group*drivers/perf/arm_cspmu/nvidia_cspmu.c +0
-6@@ -388,12 +388,6 @@ static int nv_cspmu_init_ops(struct arm_cspmu *cspmu) impl_ops->get_format_attrs = nv_cspmu_get_format_attrs; impl_ops->get_name = nv_cspmu_get_name; -/* Set others to NULL to use default callback. */ - impl_ops->event_type =NULL ; - impl_ops->event_attr_is_visible =NULL ; - impl_ops->get_identifier =NULL ; - impl_ops->is_cycle_counter_event =NULL ; -return 0 ; }Signature · 1 line
2.39.2.101.g768bb238c484.dirty
PATCH 2/5 perf/arm_cspmu: Simplify attribute groups
In reply to Robin MurphyThe attribute group array itself is always the same, so there's no need to allocate it separately. Storing it directly in our instance data saves memory and gives us one less point of failure.
--- drivers/perf/arm_cspmu/arm_cspmu.c | 26 +++++++++----------------- drivers/perf/arm_cspmu/arm_cspmu.h | 1 + 2 files changed, 10 insertions(+), 17 deletions(-)
drivers/perf/arm_cspmu/arm_cspmu.c +9 -17
@@ -501,23 +501,16 @@ arm_cspmu_alloc_format_attr_group(struct arm_cspmu *cspmu)return format_group; } -static struct attribute_group ** -arm_cspmu_alloc_attr_group (struct arm_cspmu *cspmu) +static int arm_cspmu_alloc_attr_groups (struct arm_cspmu *cspmu) { -struct attribute_group **attr_groups =NULL ; -struct device *dev = cspmu->dev; +const struct attribute_group **attr_groups = cspmu->attr_groups;const struct arm_cspmu_impl_ops *impl_ops = &cspmu->impl.ops; cspmu->identifier = impl_ops->get_identifier (cspmu); cspmu->name = impl_ops->get_name (cspmu);if (!cspmu->identifier || !cspmu->name) -return NULL ; - - attr_groups =devm_kcalloc (dev,5 ,sizeof (struct attribute_group *), -GFP_KERNEL ); -if (!attr_groups) -return NULL ; +return -ENOMEM ; attr_groups[0 ] =arm_cspmu_alloc_event_attr_group (cspmu); attr_groups[1 ] =arm_cspmu_alloc_format_attr_group (cspmu);
@@ -525,9 +518,9 @@ arm_cspmu_alloc_attr_group(struct arm_cspmu *cspmu) attr_groups[3 ] = &arm_cspmu_cpumask_attr_group;if (!attr_groups[0 ] || !attr_groups[1 ]) -return NULL ; +return -ENOMEM ; -return attr_groups; +return 0 ; }static inline void arm_cspmu_reset_counters (struct arm_cspmu *cspmu)
@@ -1166,11 +1159,10 @@ static int arm_cspmu_get_cpus(struct arm_cspmu *cspmu)static int arm_cspmu_register_pmu (struct arm_cspmu *cspmu) {int ret, capabilities; -struct attribute_group **attr_groups; - attr_groups =arm_cspmu_alloc_attr_group (cspmu); -if (!attr_groups) -return -ENOMEM ; + ret =arm_cspmu_alloc_attr_groups (cspmu); +if (ret) +return ret; ret =cpuhp_state_add_instance (arm_cspmu_cpuhp_state, &cspmu->cpuhp_node);
@@ -1192,7 +1184,7 @@ static int arm_cspmu_register_pmu(struct arm_cspmu *cspmu) .start = arm_cspmu_start, .stop = arm_cspmu_stop, .read = arm_cspmu_read, - .attr_groups = (const struct attribute_group **)attr_groups, + .attr_groups = cspmu->attr_groups, .capabilities = capabilities, };
drivers/perf/arm_cspmu/arm_cspmu.h +1 -0
@@ -157,6 +157,7 @@ struct arm_cspmu {int cycle_counter_logical_idx;struct arm_cspmu_hw_events hw_events; +const struct attribute_group *attr_groups[5 ];struct arm_cspmu_impl impl; };
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Re: [PATCH 2/5] perf/arm_cspmu: Simplify attribute groups
Quoted 5 lines · Robin Murphy
The attribute group array itself is always the same, so there's no need to allocate it separately. Storing it directly in our instance data saves memory and gives us one less point of failure.
Signed-off-by Robin Murphy <[email protected]>
Cheers, Ilkka
Quoted 88 lines
---
drivers/perf/arm_cspmu/arm_cspmu.c| 26 +++++++++-----------------drivers/perf/arm_cspmu/arm_cspmu.h| 1 +2 files changed, 10 insertions(+), 17 deletions(-)drivers/perf/arm_cspmu/arm_cspmu.c +9
-17@@ -501,23 +501,16 @@ arm_cspmu_alloc_format_attr_group(struct arm_cspmu *cspmu)return format_group; } -static struct attribute_group ** -arm_cspmu_alloc_attr_group (struct arm_cspmu *cspmu) +static int arm_cspmu_alloc_attr_groups (struct arm_cspmu *cspmu) { -struct attribute_group **attr_groups =NULL ; -struct device *dev = cspmu->dev; +const struct attribute_group **attr_groups = cspmu->attr_groups;const struct arm_cspmu_impl_ops *impl_ops = &cspmu->impl.ops; cspmu->identifier = impl_ops->get_identifier (cspmu); cspmu->name = impl_ops->get_name (cspmu);if (!cspmu->identifier || !cspmu->name) -return NULL ; - - attr_groups =devm_kcalloc (dev,5 ,sizeof (struct attribute_group *), -GFP_KERNEL ); -if (!attr_groups) -return NULL ; +return -ENOMEM ; attr_groups[0 ] =arm_cspmu_alloc_event_attr_group (cspmu); attr_groups[1 ] =arm_cspmu_alloc_format_attr_group (cspmu);@@ -525,9 +518,9 @@ arm_cspmu_alloc_attr_group(struct arm_cspmu *cspmu) attr_groups[3 ] = &arm_cspmu_cpumask_attr_group;if (!attr_groups[0 ] || !attr_groups[1 ]) -return NULL ; +return -ENOMEM ; -return attr_groups; +return 0 ; }static inline void arm_cspmu_reset_counters (struct arm_cspmu *cspmu)@@ -1166,11 +1159,10 @@ static int arm_cspmu_get_cpus(struct arm_cspmu *cspmu)static int arm_cspmu_register_pmu (struct arm_cspmu *cspmu) {int ret, capabilities; -struct attribute_group **attr_groups; - attr_groups =arm_cspmu_alloc_attr_group (cspmu); -if (!attr_groups) -return -ENOMEM ; + ret =arm_cspmu_alloc_attr_groups (cspmu); +if (ret) +return ret; ret =cpuhp_state_add_instance (arm_cspmu_cpuhp_state, &cspmu->cpuhp_node);@@ -1192,7 +1184,7 @@ static int arm_cspmu_register_pmu(struct arm_cspmu *cspmu) .start = arm_cspmu_start, .stop = arm_cspmu_stop, .read = arm_cspmu_read, - .attr_groups = (const struct attribute_group **)attr_groups, + .attr_groups = cspmu->attr_groups, .capabilities = capabilities, };drivers/perf/arm_cspmu/arm_cspmu.h +1
-0@@ -157,6 +157,7 @@ struct arm_cspmu {int cycle_counter_logical_idx;struct arm_cspmu_hw_events hw_events; +const struct attribute_group *attr_groups[5 ];struct arm_cspmu_impl impl; };Signature · 1 line
2.39.2.101.g768bb238c484.dirty
PATCH 3/5 perf/arm_cspmu: Simplify counter reset
In reply to Robin Murphyarm_cspmu_reset_counters() inherently also stops them since it is writing 0 to PMCR.E, so there should be no need to do that twice. Also tidy up the reset routine itself for consistency with the start and stop routines, and to be clear at first glance that it is simply writing a constant value.
--- drivers/perf/arm_cspmu/arm_cspmu.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
drivers/perf/arm_cspmu/arm_cspmu.c +1 -6
@@ -525,11 +525,7 @@ static int arm_cspmu_alloc_attr_groups(struct arm_cspmu *cspmu)static inline void arm_cspmu_reset_counters (struct arm_cspmu *cspmu) { -u32 pmcr =0 ; - - pmcr |=PMCR_P ; - pmcr |=PMCR_C ; -writel (pmcr, cspmu->base0 +PMCR ); +writel (PMCR_C |PMCR_P , cspmu->base0 +PMCR ); }static inline void arm_cspmu_start_counters (struct arm_cspmu *cspmu)
@@ -1189,7 +1185,6 @@ static int arm_cspmu_register_pmu(struct arm_cspmu *cspmu) };/* Hardware counter init */ -arm_cspmu_stop_counters (cspmu);arm_cspmu_reset_counters (cspmu); ret =perf_pmu_register (&cspmu->pmu, cspmu->name,-1 );
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Re: [PATCH 3/5] perf/arm_cspmu: Simplify counter reset
Quoted 7 lines · Robin Murphy
arm_cspmu_reset_counters()inherently also stops them since it is writing 0 to PMCR.E, so there should be no need to do that twice. Also tidy up the reset routine itself for consistency with the start and stop routines, and to be clear at first glance that it is simply writing a constant value.Signed-off-by Robin Murphy <[email protected]>
Cheers, Ilkka
Quoted 33 lines
---
drivers/perf/arm_cspmu/arm_cspmu.c| 7 +------1 file changed, 1 insertion(+), 6 deletions(-)drivers/perf/arm_cspmu/arm_cspmu.c +1
-6@@ -525,11 +525,7 @@ static int arm_cspmu_alloc_attr_groups(struct arm_cspmu *cspmu)static inline void arm_cspmu_reset_counters (struct arm_cspmu *cspmu) { -u32 pmcr =0 ; - - pmcr |=PMCR_P ; - pmcr |=PMCR_C ; -writel (pmcr, cspmu->base0 +PMCR ); +writel (PMCR_C |PMCR_P , cspmu->base0 +PMCR ); }static inline void arm_cspmu_start_counters (struct arm_cspmu *cspmu)@@ -1189,7 +1185,6 @@ static int arm_cspmu_register_pmu(struct arm_cspmu *cspmu) };/* Hardware counter init */ -arm_cspmu_stop_counters (cspmu);arm_cspmu_reset_counters (cspmu); ret =perf_pmu_register (&cspmu->pmu, cspmu->name,-1 );Signature · 1 line
2.39.2.101.g768bb238c484.dirty
PATCH 4/5 dt-bindings/perf: Add Arm CoreSight PMU
In reply to Robin MurphyAdd a binding for implementations of the Arm CoreSight Performance Monitoring Unit Architecture. Not to be confused with CoreSight debug and trace, the PMU architecture defines a standard MMIO interface for event counters similar to the CPU PMU architecture, where the implementation and most of its features are discoverable through ID registers.
--- .../bindings/perf/arm,coresight-pmu.yaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml new file +39 -0
@@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/perf/arm,coresight-pmu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Arm Coresight Performance Monitoring Unit Architecture + +maintainers: + - Robin Murphy <[email protected]> + +properties: + compatible: + const: arm,coresight-pmu + + reg: + items: + - description: Register page 0 + - description: Register page 1 (if dual-page extension implemented) + minItems: 1 + + interrupts: + items: + - description: Overflow interrupt + + cpus: + $ref: /schemas/types.yaml#/definitions/phandle-array + minItems: 1 + description: List of CPUs with which the PMU is associated, if applicable + + arm,64-bit-atomic: + type: boolean + description: Register accesses are single-copy atomic at doubleword granularity + +required: + - compatible + - reg + +additionalProperties: false
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Rob Herring
maintainerRe: [PATCH 4/5] dt-bindings/perf: Add Arm CoreSight PMU
Quoted 6 lines · Robin Murphy
Add a binding for implementations of the Arm CoreSight Performance Monitoring Unit Architecture. Not to be confused with CoreSight debug and trace, the PMU architecture defines a standard MMIO interface for event counters similar to the CPU PMU architecture, where the implementation and most of its features are discoverable through ID registers.
The implementation is separate from the CPU PMU rather than an MMIO view of it. Not really clear in my quick read of the spec.
Quoted 32 lines
CC Rob Herring <[email protected]>CC Krzysztof Kozlowski <[email protected]>CC Conor Dooley <[email protected]>Signed-off-by Robin Murphy <[email protected]>--- .../bindings/perf/arm,coresight-pmu.yaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/perf/arm,coresight-pmu.yamlDocumentation/devicetree/bindings/perf/arm,coresight-pmu.yaml new file +17
-0@@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/perf/arm,coresight-pmu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Arm Coresight Performance Monitoring Unit Architecture + +maintainers: + - Robin Murphy <[email protected]> + +properties: + compatible: + const: arm,coresight-pmu + + reg: + items:
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml line 27
Quoted 10 lines
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml new file +10
-0+ - description: Register page 0 + - description: Register page 1 (if dual-page extension implemented) + minItems: 1 + + interrupts: + items: + - description: Overflow interrupt + + cpus: + $ref: /schemas/types.yaml#/definitions/phandle-array
Don't need a type. Already defined.
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml line 28
Quoted 1 line
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml new file +1
-0+ minItems: 1
1 is always the minimum.
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml line 29
Quoted 1 line
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml new file +1
-0+ description: List of CPUs with which the PMU is associated, if applicable
When is it applicable? Presumably when it is associated with only a subset of CPUs?
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml line 33
Quoted 4 lines
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml new file +4
-0+ + arm,64-bit-atomic: + type: boolean + description: Register accesses are single-copy atomic at doubleword granularity
As this is recommended, shouldn't the property be the inverse.
Maybe the standard 'reg-io-width = <4>' would be sufficient here?
Rob
Re: [PATCH 4/5] dt-bindings/perf: Add Arm CoreSight PMU
Quoted 10 lines · Rob Herring
Quoted 6 lines · Robin Murphy
Add a binding for implementations of the Arm CoreSight Performance Monitoring Unit Architecture. Not to be confused with CoreSight debug and trace, the PMU architecture defines a standard MMIO interface for event counters similar to the CPU PMU architecture, where the implementation and most of its features are discoverable through ID registers.
The implementation is separate from the CPU PMU rather than an MMIO view of it. Not really clear in my quick read of the spec.
Yeah, the architecture seems to have aspirations of being able to describe the CPU PMU, but the main intent of this binding is to accommodate all of the arbitrary MMIO non-CPU things. However that's not to say it *couldn't* ever be used for the memory-mapped view of a CPU's PMU via its external debug interface, if it is suitably compatible. I concur that I'm rather light on description here, but that's mostly because the architecture itself isn't prescriptive - it really is pretty much just an interface to whatever PMU functionality can be made to fit it (and with plenty of imp-def leeway).
Quoted 36 lines
Quoted 36 lines
CC Rob Herring <[email protected]>CC Krzysztof Kozlowski <[email protected]>CC Conor Dooley <[email protected]>Signed-off-by Robin Murphy <[email protected]>--- .../bindings/perf/arm,coresight-pmu.yaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+)create mode 100644
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yamlDocumentation/devicetree/bindings/perf/arm,coresight-pmu.yaml new file +21
-0@@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/perf/arm,coresight-pmu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Arm Coresight Performance Monitoring Unit Architecture + +maintainers: + - Robin Murphy <[email protected]> + +properties: + compatible: + const: arm,coresight-pmu + + reg: + items: + - description: Register page 0 + - description: Register page 1 (if dual-page extension implemented) + minItems: 1 +
Quoted 8 lines
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml line 27
Quoted 6 lines
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml new file +6
-0+ interrupts: + items: + - description: Overflow interrupt + + cpus: + $ref: /schemas/types.yaml#/definitions/phandle-arrayDon't need a type. Already defined.
Ah, I hadn't noticed this was a common property now. Good to know, thanks.
Quoted 8 lines
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml line 28
Quoted 1 line
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml new file +1
-0+ minItems: 11 is always the minimum.
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml line 29
Quoted 1 line
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml new file +1
-0+ description: List of CPUs with which the PMU is associated, if applicableWhen is it applicable? Presumably when it is associated with only a subset of CPUs?
Affinity to one CPU or some subset, for things like tightly coupled accelerators or cluster-level things like DSU, would want explicitly describing, but for interconnects, memory controllers and random other standalone devices usually no meaningful association will exist (either they can be considered affine to no CPUs, or to all of them in an implicit manner).
Quoted 6 lines
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml line 33
Quoted 4 lines
Documentation/devicetree/bindings/perf/arm,coresight-pmu.yaml new file +4
-0+ + arm,64-bit-atomic: + type: boolean + description: Register accesses are single-copy atomic at doubleword granularityAs this is recommended, shouldn't the property be the inverse.
It may be recommended, but in practice I'm convinced it's going to remain the exception. It's mandatory (and thus assumable) for the 64-bit programmers model extension, and effectively moot if only 32-bit or smaller counters are implemented, so it's really only relevant to the in-between case of the standard "32-bit" programmers model with 64-bit (or at least >32-bit) counters, but even then I'd bet most folks are still going to implement those behind an APB interface that ends up with larger accesses split into 32-bit bursts if they're even accepted at all. I'm aware of 3 implementations so far; one I'm not sure how wide the counters are, while the other two have proven to be 64-bit *without* atomic access ;)
Quoted 1 line
Maybe the standard 'reg-io-width = <4>' would be sufficient here?
Oh, indeed I'd forgotten that was a thing - IIRC in common cases like UARTs it's used to represent a *minimum* access size, whereas here it would represent a maximum, but I imagine that ambiguity may well already exist via other bindings, so as long as that's OK I'm happy to go with it. As above I would still be inclined to make it default to 4 if absent, but permit either 4 or 8 to be specified.
Thanks,
Robin.
PATCH 5/5 perf/arm_cspmu: Add devicetree support
In reply to Robin MurphyHook up devicetree probing support. For now let's hope that people implement PMIIDR properly and we don't need an override mechanism.
--- drivers/perf/arm_cspmu/arm_cspmu.c | 71 +++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 15 deletions(-)
drivers/perf/arm_cspmu/arm_cspmu.c +56 -15
@@ -27,6 +27,7 @@#include <linux/io-64-nonatomic-lo-hi.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/of.h> #include <linux/perf_event.h> #include <linux/platform_device.h>
@@ -309,6 +310,10 @@ static const char *arm_cspmu_get_name(const struct arm_cspmu *cspmu)static atomic_t pmu_idx[ACPI_APMT_NODE_TYPE_COUNT ] = {0 }; dev = cspmu->dev; +if (!has_acpi_companion (dev)) +return devm_kasprintf (dev,GFP_KERNEL ,PMUNAME "_%u" , +atomic_fetch_inc (&pmu_idx[0 ])); + apmt_node =arm_cspmu_apmt_node (dev); pmu_type = apmt_node->type;
@@ -406,7 +411,6 @@ static struct arm_cspmu_impl_match *arm_cspmu_impl_match_get(u32 pmiidr)static int arm_cspmu_init_impl_ops (struct arm_cspmu *cspmu) {int ret =0 ; -struct acpi_apmt_node *apmt_node =arm_cspmu_apmt_node (cspmu->dev);struct arm_cspmu_impl_match *match;/* Start with a default PMU implementation */
@@ -425,8 +429,12 @@ static int arm_cspmu_init_impl_ops(struct arm_cspmu *cspmu) };/* Firmware may override implementer/product ID from PMIIDR */ -if (apmt_node->impl_id) - cspmu->impl.pmiidr = apmt_node->impl_id; +if (has_acpi_companion (cspmu->dev)) { +struct acpi_apmt_node *apmt_node =arm_cspmu_apmt_node (cspmu->dev); + +if (apmt_node->impl_id) + cspmu->impl.pmiidr = apmt_node->impl_id; + }/* Find implementer specific attribute ops. */ match =arm_cspmu_impl_match_get (cspmu->impl.pmiidr);
@@ -928,7 +936,6 @@ static void arm_cspmu_read(struct perf_event *event)static struct arm_cspmu *arm_cspmu_alloc (struct platform_device *pdev) { -struct acpi_apmt_node *apmt_node;struct arm_cspmu *cspmu;struct device *dev = &pdev->dev;
@@ -939,8 +946,13 @@ static struct arm_cspmu *arm_cspmu_alloc(struct platform_device *pdev) cspmu->dev = dev;platform_set_drvdata (pdev, cspmu); - apmt_node =arm_cspmu_apmt_node (dev); - cspmu->has_atomic_dword = apmt_node->flags &ACPI_APMT_FLAGS_ATOMIC ; +if (has_acpi_companion (dev)) { +struct acpi_apmt_node *apmt_node =arm_cspmu_apmt_node (dev); + + cspmu->has_atomic_dword = apmt_node->flags &ACPI_APMT_FLAGS_ATOMIC ; + }else { + cspmu->has_atomic_dword =device_property_read_bool (dev,"arm,64-bit-atomic" ); + }return cspmu; }
@@ -1133,11 +1145,6 @@ static int arm_cspmu_acpi_get_cpus(struct arm_cspmu *cspmu) } } -if (cpumask_empty (&cspmu->associated_cpus)) { -dev_dbg (cspmu->dev,"No cpu associated with the PMU\n" ); -return -ENODEV ; - } -return 0 ; }#else
@@ -1147,9 +1154,36 @@ static int arm_cspmu_acpi_get_cpus(struct arm_cspmu *cspmu) }#endif +static int arm_cspmu_of_get_cpus (struct arm_cspmu *cspmu) +{ +struct of_phandle_iterator it; +int ret, cpu; + +of_for_each_phandle (&it, ret, cspmu->dev->of_node,"cpus" ,NULL ,0 ) { + cpu =of_cpu_node_to_id (it.node); +if (cpu <0 ) +continue ; +cpumask_set_cpu (cpu, &cspmu->associated_cpus); + } +return ret; +} +static int arm_cspmu_get_cpus (struct arm_cspmu *cspmu) { -return arm_cspmu_acpi_get_cpus (cspmu); +int ret =0 ; + +if (has_acpi_companion (cspmu->dev)) + ret =arm_cspmu_acpi_get_cpus (cspmu); +else if (of_property_present (cspmu->dev->of_node,"cpus" )) + ret =arm_cspmu_of_get_cpus (cspmu); +else +cpumask_copy (&cspmu->associated_cpus, cpu_possible_mask); + +if (!ret &&cpumask_empty (&cspmu->associated_cpus)) { +dev_dbg (cspmu->dev,"No cpu associated with the PMU\n" ); + ret = -ENODEV ; + } +return ret; }static int arm_cspmu_register_pmu (struct arm_cspmu *cspmu)
@@ -1246,11 +1280,18 @@ static const struct platform_device_id arm_cspmu_id[] = { };MODULE_DEVICE_TABLE (platform, arm_cspmu_id); +static const struct of_device_id arm_cspmu_of_match[] = { + { .compatible ="arm,coresight-pmu" }, + {} +}; +MODULE_DEVICE_TABLE (of, arm_cspmu_of_match); +static struct platform_driver arm_cspmu_driver = { .driver = { - .name =DRVNAME , - .suppress_bind_attrs = true, - }, + .name =DRVNAME , + .of_match_table = arm_cspmu_of_match, + .suppress_bind_attrs = true, + }, .probe = arm_cspmu_device_probe, .remove = arm_cspmu_device_remove, .id_table = arm_cspmu_id,
Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Hi Robin,
Quoted 21 lines · Robin Murphy
Hook up devicetree probing support. For now let's hope that people implement PMIIDR properly and we don't need an override mechanism.
Signed-off-by Robin Murphy <[email protected]>---
drivers/perf/arm_cspmu/arm_cspmu.c| 71 +++++++++++++++++++++++-------1 file changed, 56 insertions(+), 15 deletions(-)drivers/perf/arm_cspmu/arm_cspmu.c +1
-0@@ -27,6 +27,7 @@#include <linux/io-64-nonatomic-lo-hi.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/of.h> #include <linux/perf_event.h> #include <linux/platform_device.h>
drivers/perf/arm_cspmu/arm_cspmu.c static const char *arm_cspmu_get_name(const struct arm_cspmu *cspmu) · line 313
Quoted 4 lines
drivers/perf/arm_cspmu/arm_cspmu.c +1
-0@@ -309,6 +310,10 @@ static const char *arm_cspmu_get_name(const struct arm_cspmu *cspmu)static atomic_t pmu_idx[ACPI_APMT_NODE_TYPE_COUNT ] = {0 }; dev = cspmu->dev; +if (!has_acpi_companion (dev))
Am I missing something since this doesn't work on top of v6.7-rc4?
The problem I see is that has_acpi_companion() calls is_acpi_device_node(), which compares whether
fwnode->ops == &acpi_device_fwnode_ops;
However, the acpi/apmt code allocates fwnode by calling acpi_alloc_fwnode_static(), which assigns &acpi_static_fwnode_ops to ops.
I wonder though, if is_acpi_device_node() should check the static variant too? :/
Cheers, Ilkka
Quoted 129 lines
drivers/perf/arm_cspmu/arm_cspmu.c +54
-15+return devm_kasprintf (dev,GFP_KERNEL ,PMUNAME "_%u" , +atomic_fetch_inc (&pmu_idx[0 ])); + apmt_node =arm_cspmu_apmt_node (dev); pmu_type = apmt_node->type;@@ -406,7 +411,6 @@ static struct arm_cspmu_impl_match *arm_cspmu_impl_match_get(u32 pmiidr)static int arm_cspmu_init_impl_ops (struct arm_cspmu *cspmu) {int ret =0 ; -struct acpi_apmt_node *apmt_node =arm_cspmu_apmt_node (cspmu->dev);struct arm_cspmu_impl_match *match;/* Start with a default PMU implementation */ @@ -425,8 +429,12 @@ static int arm_cspmu_init_impl_ops(struct arm_cspmu *cspmu) };/* Firmware may override implementer/product ID from PMIIDR */ -if (apmt_node->impl_id) - cspmu->impl.pmiidr = apmt_node->impl_id; +if (has_acpi_companion (cspmu->dev)) { +struct acpi_apmt_node *apmt_node =arm_cspmu_apmt_node (cspmu->dev); + +if (apmt_node->impl_id) + cspmu->impl.pmiidr = apmt_node->impl_id; + }/* Find implementer specific attribute ops. */ match =arm_cspmu_impl_match_get (cspmu->impl.pmiidr);@@ -928,7 +936,6 @@ static void arm_cspmu_read(struct perf_event *event)static struct arm_cspmu *arm_cspmu_alloc (struct platform_device *pdev) { -struct acpi_apmt_node *apmt_node;struct arm_cspmu *cspmu;struct device *dev = &pdev->dev;@@ -939,8 +946,13 @@ static struct arm_cspmu *arm_cspmu_alloc(struct platform_device *pdev) cspmu->dev = dev;platform_set_drvdata (pdev, cspmu); - apmt_node =arm_cspmu_apmt_node (dev); - cspmu->has_atomic_dword = apmt_node->flags &ACPI_APMT_FLAGS_ATOMIC ; +if (has_acpi_companion (dev)) { +struct acpi_apmt_node *apmt_node =arm_cspmu_apmt_node (dev); + + cspmu->has_atomic_dword = apmt_node->flags &ACPI_APMT_FLAGS_ATOMIC ; + }else { + cspmu->has_atomic_dword =device_property_read_bool (dev,"arm,64-bit-atomic" ); + }return cspmu; }@@ -1133,11 +1145,6 @@ static int arm_cspmu_acpi_get_cpus(struct arm_cspmu *cspmu) } } -if (cpumask_empty (&cspmu->associated_cpus)) { -dev_dbg (cspmu->dev,"No cpu associated with the PMU\n" ); -return -ENODEV ; - } -return 0 ; }#else @@ -1147,9 +1154,36 @@ static int arm_cspmu_acpi_get_cpus(struct arm_cspmu *cspmu) }#endif +static int arm_cspmu_of_get_cpus (struct arm_cspmu *cspmu) +{ +struct of_phandle_iterator it; +int ret, cpu; + +of_for_each_phandle (&it, ret, cspmu->dev->of_node,"cpus" ,NULL ,0 ) { + cpu =of_cpu_node_to_id (it.node); +if (cpu <0 ) +continue ; +cpumask_set_cpu (cpu, &cspmu->associated_cpus); + } +return ret; +} +static int arm_cspmu_get_cpus (struct arm_cspmu *cspmu) { -return arm_cspmu_acpi_get_cpus (cspmu); +int ret =0 ; + +if (has_acpi_companion (cspmu->dev)) + ret =arm_cspmu_acpi_get_cpus (cspmu); +else if (of_property_present (cspmu->dev->of_node,"cpus" )) + ret =arm_cspmu_of_get_cpus (cspmu); +else +cpumask_copy (&cspmu->associated_cpus, cpu_possible_mask); + +if (!ret &&cpumask_empty (&cspmu->associated_cpus)) { +dev_dbg (cspmu->dev,"No cpu associated with the PMU\n" ); + ret = -ENODEV ; + } +return ret; }static int arm_cspmu_register_pmu (struct arm_cspmu *cspmu)@@ -1246,11 +1280,18 @@ static const struct platform_device_id arm_cspmu_id[] = { };MODULE_DEVICE_TABLE (platform, arm_cspmu_id); +static const struct of_device_id arm_cspmu_of_match[] = { + { .compatible ="arm,coresight-pmu" }, + {} +}; +MODULE_DEVICE_TABLE (of, arm_cspmu_of_match); +static struct platform_driver arm_cspmu_driver = { .driver = { - .name =DRVNAME , - .suppress_bind_attrs = true, - }, + .name =DRVNAME , + .of_match_table = arm_cspmu_of_match, + .suppress_bind_attrs = true, + }, .probe = arm_cspmu_device_probe, .remove = arm_cspmu_device_remove, .id_table = arm_cspmu_id,Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Quoted 34 lines · Ilkka Koskinen
Hi Robin,
Quoted 21 lines · Robin Murphy
Hook up devicetree probing support. For now let's hope that people implement PMIIDR properly and we don't need an override mechanism.
Signed-off-by Robin Murphy <[email protected]>---
drivers/perf/arm_cspmu/arm_cspmu.c| 71 +++++++++++++++++++++++-------1 file changed, 56 insertions(+), 15 deletions(-)drivers/perf/arm_cspmu/arm_cspmu.c +1
-0@@ -27,6 +27,7 @@#include <linux/io-64-nonatomic-lo-hi.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/of.h> #include <linux/perf_event.h> #include <linux/platform_device.h> drivers/perf/arm_cspmu/arm_cspmu.c static const char *arm_cspmu_get_name(const · line 314
Quoted 5 lines
drivers/perf/arm_cspmu/arm_cspmu.c +1
-0@@ -309,6 +310,10 @@ static const char *arm_cspmu_get_name(const struct arm_cspmu *cspmu) static atomic_t pmu_idx[ACPI_APMT_NODE_TYPE_COUNT] = { 0 }; dev = cspmu->dev; + if (!has_acpi_companion(dev))Am I missing something since this doesn't work on top of v6.7-rc4?
The problem I see is thathas_acpi_companion()callsis_acpi_device_node(), which compares whether
Quoted 5 lines
fwnode->ops ==
&acpi_device_fwnode_ops;However, the acpi/apmt code allocates fwnode by calling
acpi_alloc_fwnode_static(), which assigns&acpi_static_fwnode_opsto ops.
Ah, I hadn't got as far as considering that has_acpi_companion() might only work for namespace devices, but it makes sense now that you point it out. I should have clarified that I don't have any suitable ACPI system to test this on, and have only been able to verify basic DT probing on an FPGA.
Quoted 1 line
I wonder though, if
is_acpi_device_node()should check the static variant too? :/
Thanks for the tip, I'll look into that and try to come up with something that works for a v2 (at worst there's always the traditional assumption that !dev->of_node implies ACPI)
Cheers,
Robin.
Quoted 142 lines
Cheers, Ilkka
Quoted 139 lines
drivers/perf/arm_cspmu/arm_cspmu.c +3
-1+ return devm_kasprintf(dev, GFP_KERNEL, PMUNAME "_%u", + atomic_fetch_inc(&pmu_idx[0])); + apmt_node = arm_cspmu_apmt_node(dev); pmu_type = apmt_node->type;@@ -406,7 +411,6 @@ static struct arm_cspmu_impl_match *arm_cspmu_impl_match_get(u32 pmiidr)static int arm_cspmu_init_impl_ops (struct arm_cspmu *cspmu) { int ret = 0; - struct acpi_apmt_node *apmt_node = arm_cspmu_apmt_node(cspmu->dev); struct arm_cspmu_impl_match *match;/* Start with a default PMU implementation */
drivers/perf/arm_cspmu/arm_cspmu.c +6
-2@@ -425,8 +429,12 @@ static int arm_cspmu_init_impl_ops(struct arm_cspmu *cspmu) }; /* Firmware may override implementer/product ID from PMIIDR */ - if (apmt_node->impl_id) - cspmu->impl.pmiidr = apmt_node->impl_id; + if (has_acpi_companion(cspmu->dev)) { + struct acpi_apmt_node *apmt_node =arm_cspmu_apmt_node (cspmu->dev); + + if (apmt_node->impl_id) + cspmu->impl.pmiidr = apmt_node->impl_id; + }/* Find implementer specific attribute ops. */ match =
arm_cspmu_impl_match_get(cspmu->impl.pmiidr);drivers/perf/arm_cspmu/arm_cspmu.c +7
-3@@ -928,7 +936,6 @@ static void arm_cspmu_read(struct perf_event *event)static struct arm_cspmu *arm_cspmu_alloc (struct platform_device *pdev) { - struct acpi_apmt_node *apmt_node; struct arm_cspmu *cspmu; struct device *dev = &pdev->dev;@@ -939,8 +946,13 @@ static struct arm_cspmu *arm_cspmu_alloc(struct platform_device *pdev) cspmu->dev = dev; platform_set_drvdata(pdev, cspmu); - apmt_node = arm_cspmu_apmt_node(dev); - cspmu->has_atomic_dword = apmt_node->flags & ACPI_APMT_FLAGS_ATOMIC; + if (has_acpi_companion(dev)) { + struct acpi_apmt_node *apmt_node = arm_cspmu_apmt_node(dev); + + cspmu->has_atomic_dword = apmt_node->flags &ACPI_APMT_FLAGS_ATOMIC ; + } else { + cspmu->has_atomic_dword = device_property_read_bool(dev,"arm,64-bit-atomic" ); + }return cspmu;
}drivers/perf/arm_cspmu/arm_cspmu.c +0
-5@@ -1133,11 +1145,6 @@ static int arm_cspmu_acpi_get_cpus(struct arm_cspmu *cspmu) } } - if (cpumask_empty(&cspmu->associated_cpus)) { - dev_dbg(cspmu->dev, "No cpu associated with the PMU\n"); - return -ENODEV; - } - return 0; }#else
drivers/perf/arm_cspmu/arm_cspmu.c +28
-1@@ -1147,9 +1154,36 @@ static int arm_cspmu_acpi_get_cpus(struct arm_cspmu *cspmu) }#endif +static int arm_cspmu_of_get_cpus (struct arm_cspmu *cspmu) +{ + struct of_phandle_iterator it; + int ret, cpu; + + of_for_each_phandle(&it, ret, cspmu->dev->of_node, "cpus", NULL, 0) { + cpu = of_cpu_node_to_id(it.node); + if (cpu < 0) + continue; + cpumask_set_cpu(cpu, &cspmu->associated_cpus); + } + return ret; +} +static int arm_cspmu_get_cpus (struct arm_cspmu *cspmu) { - return arm_cspmu_acpi_get_cpus(cspmu); + int ret = 0; + + if (has_acpi_companion(cspmu->dev)) + ret = arm_cspmu_acpi_get_cpus(cspmu); + else if (of_property_present(cspmu->dev->of_node, "cpus")) + ret = arm_cspmu_of_get_cpus(cspmu); + else + cpumask_copy(&cspmu->associated_cpus, cpu_possible_mask); + + if (!ret && cpumask_empty(&cspmu->associated_cpus)) { + dev_dbg(cspmu->dev, "No cpu associated with the PMU\n"); + ret = -ENODEV; + } + return ret; }static int
arm_cspmu_register_pmu(struct arm_cspmu *cspmu)drivers/perf/arm_cspmu/arm_cspmu.c +10
-3@@ -1246,11 +1280,18 @@ static const struct platform_device_id arm_cspmu_id[] = { };MODULE_DEVICE_TABLE (platform, arm_cspmu_id); +static const struct of_device_id arm_cspmu_of_match[] = { + { .compatible = "arm,coresight-pmu" }, + {} +}; +MODULE_DEVICE_TABLE (of, arm_cspmu_of_match); +static struct platform_driver arm_cspmu_driver = { .driver = { - .name = DRVNAME, - .suppress_bind_attrs = true, - }, + .name = DRVNAME, + .of_match_table = arm_cspmu_of_match, + .suppress_bind_attrs = true, + }, .probe = arm_cspmu_device_probe, .remove = arm_cspmu_device_remove,.id_table =
arm_cspmu_id,Signature · 1 line
2.39.2.101.g768bb238c484.dirty
Quoted 35 lines · Robin Murphy
Quoted 34 lines · Ilkka Koskinen
Hi Robin,
Quoted 21 lines · Robin Murphy
Hook up devicetree probing support. For now let's hope that people implement PMIIDR properly and we don't need an override mechanism.
Signed-off-by Robin Murphy <[email protected]>---
drivers/perf/arm_cspmu/arm_cspmu.c| 71 +++++++++++++++++++++++-------1 file changed, 56 insertions(+), 15 deletions(-)drivers/perf/arm_cspmu/arm_cspmu.c +1
-0@@ -27,6 +27,7 @@#include <linux/io-64-nonatomic-lo-hi.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/of.h> #include <linux/perf_event.h> #include <linux/platform_device.h> drivers/perf/arm_cspmu/arm_cspmu.c static const char *arm_cspmu_get_name(const struct · line 314
Quoted 5 lines
drivers/perf/arm_cspmu/arm_cspmu.c +1
-0@@ -309,6 +310,10 @@ static const char *arm_cspmu_get_name(const struct arm_cspmu *cspmu) static atomic_t pmu_idx[ACPI_APMT_NODE_TYPE_COUNT] = { 0 }; dev = cspmu->dev; + if (!has_acpi_companion(dev))Am I missing something since this doesn't work on top of v6.7-rc4?
The problem I see is thathas_acpi_companion()callsis_acpi_device_node(), which compares whether
Quoted 7 lines
Quoted 5 lines
fwnode->ops ==
&acpi_device_fwnode_ops;However, the acpi/apmt code allocates fwnode by calling
acpi_alloc_fwnode_static(), which assigns&acpi_static_fwnode_opsto ops.Ah, I hadn't got as far as considering that
has_acpi_companion()might only work for namespace devices, but it makes sense now that you point it out. I should have clarified that I don't have any suitable ACPI system to test this on, and have only been able to verify basic DT probing on an FPGA.
Ok, no problem. I'm always happy to give them a spin as soon as I find a little time.
Cheers, Ilkka
Quoted 150 lines
Quoted 2 lines
I wonder though, if
is_acpi_device_node()should check the static variant too? :/Thanks for the tip, I'll look into that and try to come up with something that works for a v2 (at worst there's always the traditional assumption that !dev->of_node implies ACPI)
Cheers,
Robin.Quoted 141 lines
Cheers, Ilkka
Quoted 138 lines
drivers/perf/arm_cspmu/arm_cspmu.c +3
-1+ return devm_kasprintf(dev, GFP_KERNEL, PMUNAME "_%u", + atomic_fetch_inc(&pmu_idx[0])); + apmt_node = arm_cspmu_apmt_node(dev); pmu_type = apmt_node->type;@@ -406,7 +411,6 @@ static struct arm_cspmu_impl_match *arm_cspmu_impl_match_get(u32 pmiidr)static int arm_cspmu_init_impl_ops (struct arm_cspmu *cspmu) { int ret = 0; - struct acpi_apmt_node *apmt_node = arm_cspmu_apmt_node(cspmu->dev); struct arm_cspmu_impl_match *match;/* Start with a default PMU implementation */
drivers/perf/arm_cspmu/arm_cspmu.c +6
-2@@ -425,8 +429,12 @@ static int arm_cspmu_init_impl_ops(struct arm_cspmu *cspmu) }; /* Firmware may override implementer/product ID from PMIIDR */ - if (apmt_node->impl_id) - cspmu->impl.pmiidr = apmt_node->impl_id; + if (has_acpi_companion(cspmu->dev)) { + struct acpi_apmt_node *apmt_node =arm_cspmu_apmt_node (cspmu->dev); + + if (apmt_node->impl_id) + cspmu->impl.pmiidr = apmt_node->impl_id; + }/* Find implementer specific attribute ops. */ match =
arm_cspmu_impl_match_get(cspmu->impl.pmiidr);drivers/perf/arm_cspmu/arm_cspmu.c +7
-3@@ -928,7 +936,6 @@ static void arm_cspmu_read(struct perf_event *event)static struct arm_cspmu *arm_cspmu_alloc (struct platform_device *pdev) { - struct acpi_apmt_node *apmt_node; struct arm_cspmu *cspmu; struct device *dev = &pdev->dev;@@ -939,8 +946,13 @@ static struct arm_cspmu *arm_cspmu_alloc(struct platform_device *pdev) cspmu->dev = dev; platform_set_drvdata(pdev, cspmu); - apmt_node = arm_cspmu_apmt_node(dev); - cspmu->has_atomic_dword = apmt_node->flags & ACPI_APMT_FLAGS_ATOMIC; + if (has_acpi_companion(dev)) { + struct acpi_apmt_node *apmt_node = arm_cspmu_apmt_node(dev); + + cspmu->has_atomic_dword = apmt_node->flags &ACPI_APMT_FLAGS_ATOMIC ; + } else { + cspmu->has_atomic_dword = device_property_read_bool(dev,"arm,64-bit-atomic" ); + }return cspmu;
}drivers/perf/arm_cspmu/arm_cspmu.c +0
-5@@ -1133,11 +1145,6 @@ static int arm_cspmu_acpi_get_cpus(struct arm_cspmu *cspmu) } } - if (cpumask_empty(&cspmu->associated_cpus)) { - dev_dbg(cspmu->dev, "No cpu associated with the PMU\n"); - return -ENODEV; - } - return 0; }#else
drivers/perf/arm_cspmu/arm_cspmu.c +28
-1@@ -1147,9 +1154,36 @@ static int arm_cspmu_acpi_get_cpus(struct arm_cspmu *cspmu) }#endif +static int arm_cspmu_of_get_cpus (struct arm_cspmu *cspmu) +{ + struct of_phandle_iterator it; + int ret, cpu; + + of_for_each_phandle(&it, ret, cspmu->dev->of_node, "cpus", NULL, 0) { + cpu = of_cpu_node_to_id(it.node); + if (cpu < 0) + continue; + cpumask_set_cpu(cpu, &cspmu->associated_cpus); + } + return ret; +} +static int arm_cspmu_get_cpus (struct arm_cspmu *cspmu) { - return arm_cspmu_acpi_get_cpus(cspmu); + int ret = 0; + + if (has_acpi_companion(cspmu->dev)) + ret = arm_cspmu_acpi_get_cpus(cspmu); + else if (of_property_present(cspmu->dev->of_node, "cpus")) + ret = arm_cspmu_of_get_cpus(cspmu); + else + cpumask_copy(&cspmu->associated_cpus, cpu_possible_mask); + + if (!ret && cpumask_empty(&cspmu->associated_cpus)) { + dev_dbg(cspmu->dev, "No cpu associated with the PMU\n"); + ret = -ENODEV; + } + return ret; }static int
arm_cspmu_register_pmu(struct arm_cspmu *cspmu)drivers/perf/arm_cspmu/arm_cspmu.c +10
-3@@ -1246,11 +1280,18 @@ static const struct platform_device_id arm_cspmu_id[] = { };MODULE_DEVICE_TABLE (platform, arm_cspmu_id); +static const struct of_device_id arm_cspmu_of_match[] = { + { .compatible = "arm,coresight-pmu" }, + {} +}; +MODULE_DEVICE_TABLE (of, arm_cspmu_of_match); +static struct platform_driver arm_cspmu_driver = { .driver = { - .name = DRVNAME, - .suppress_bind_attrs = true, - }, + .name = DRVNAME, + .of_match_table = arm_cspmu_of_match, + .suppress_bind_attrs = true, + }, .probe = arm_cspmu_device_probe, .remove = arm_cspmu_device_remove,.id_table =
arm_cspmu_id,Signature · 1 line
2.39.2.101.g768bb238c484.dirty