1 | /* SPDX-License-Identifier: GPL-2.0 |
2 | * |
3 | * ARM CoreSight Architecture PMU driver. |
4 | * Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. |
5 | * |
6 | */ |
7 | |
8 | #ifndef __ARM_CSPMU_H__ |
9 | #define __ARM_CSPMU_H__ |
10 | |
11 | #include <linux/bitfield.h> |
12 | #include <linux/cpumask.h> |
13 | #include <linux/device.h> |
14 | #include <linux/kernel.h> |
15 | #include <linux/module.h> |
16 | #include <linux/perf_event.h> |
17 | #include <linux/platform_device.h> |
18 | #include <linux/types.h> |
19 | |
20 | #define to_arm_cspmu(p) (container_of(p, struct arm_cspmu, pmu)) |
21 | |
22 | #define ARM_CSPMU_EXT_ATTR(_name, _func, _config) \ |
23 | (&((struct dev_ext_attribute[]){ \ |
24 | { \ |
25 | .attr = __ATTR(_name, 0444, _func, NULL), \ |
26 | .var = (void *)_config \ |
27 | } \ |
28 | })[0].attr.attr) |
29 | |
30 | #define ARM_CSPMU_FORMAT_ATTR(_name, _config) \ |
31 | ARM_CSPMU_EXT_ATTR(_name, arm_cspmu_sysfs_format_show, (char *)_config) |
32 | |
33 | #define ARM_CSPMU_EVENT_ATTR(_name, _config) \ |
34 | PMU_EVENT_ATTR_ID(_name, arm_cspmu_sysfs_event_show, _config) |
35 | |
36 | |
37 | /* Default event id mask */ |
38 | #define ARM_CSPMU_EVENT_MASK GENMASK_ULL(63, 0) |
39 | |
40 | /* Default filter value mask */ |
41 | #define ARM_CSPMU_FILTER_MASK GENMASK_ULL(63, 0) |
42 | |
43 | /* Default event format */ |
44 | #define ARM_CSPMU_FORMAT_EVENT_ATTR \ |
45 | ARM_CSPMU_FORMAT_ATTR(event, "config:0-32") |
46 | |
47 | /* Default filter format */ |
48 | #define ARM_CSPMU_FORMAT_FILTER_ATTR \ |
49 | ARM_CSPMU_FORMAT_ATTR(filter, "config1:0-31") |
50 | |
51 | /* |
52 | * This is the default event number for cycle count, if supported, since the |
53 | * ARM Coresight PMU specification does not define a standard event code |
54 | * for cycle count. |
55 | */ |
56 | #define ARM_CSPMU_EVT_CYCLES_DEFAULT (0x1ULL << 32) |
57 | |
58 | /* |
59 | * The ARM Coresight PMU supports up to 256 event counters. |
60 | * If the counters are larger-than 32-bits, then the PMU includes at |
61 | * most 128 counters. |
62 | */ |
63 | #define ARM_CSPMU_MAX_HW_CNTRS 256 |
64 | |
65 | /* The cycle counter, if implemented, is located at counter[31]. */ |
66 | #define ARM_CSPMU_CYCLE_CNTR_IDX 31 |
67 | |
68 | /* PMIIDR register field */ |
69 | #define ARM_CSPMU_PMIIDR_IMPLEMENTER GENMASK(11, 0) |
70 | #define ARM_CSPMU_PMIIDR_PRODUCTID GENMASK(31, 20) |
71 | |
72 | /* JEDEC-assigned JEP106 identification code */ |
73 | #define ARM_CSPMU_IMPL_ID_NVIDIA 0x36B |
74 | #define ARM_CSPMU_IMPL_ID_AMPERE 0xA16 |
75 | |
76 | struct arm_cspmu; |
77 | |
78 | /* This tracks the events assigned to each counter in the PMU. */ |
79 | struct arm_cspmu_hw_events { |
80 | /* The events that are active on the PMU for a given logical index. */ |
81 | struct perf_event **events; |
82 | |
83 | /* |
84 | * Each bit indicates a logical counter is being used (or not) for an |
85 | * event. If cycle counter is supported and there is a gap between |
86 | * regular and cycle counter, the last logical counter is mapped to |
87 | * cycle counter. Otherwise, logical and physical have 1-to-1 mapping. |
88 | */ |
89 | DECLARE_BITMAP(used_ctrs, ARM_CSPMU_MAX_HW_CNTRS); |
90 | }; |
91 | |
92 | /* Contains ops to query vendor/implementer specific attribute. */ |
93 | struct arm_cspmu_impl_ops { |
94 | /* Get event attributes */ |
95 | struct attribute **(*get_event_attrs)(const struct arm_cspmu *cspmu); |
96 | /* Get format attributes */ |
97 | struct attribute **(*get_format_attrs)(const struct arm_cspmu *cspmu); |
98 | /* Get string identifier */ |
99 | const char *(*get_identifier)(const struct arm_cspmu *cspmu); |
100 | /* Get PMU name to register to core perf */ |
101 | const char *(*get_name)(const struct arm_cspmu *cspmu); |
102 | /* Check if the event corresponds to cycle count event */ |
103 | bool (*is_cycle_counter_event)(const struct perf_event *event); |
104 | /* Decode event type/id from configs */ |
105 | u32 (*event_type)(const struct perf_event *event); |
106 | /* Decode filter value from configs */ |
107 | u32 (*event_filter)(const struct perf_event *event); |
108 | /* Set event filter */ |
109 | void (*set_ev_filter)(struct arm_cspmu *cspmu, |
110 | struct hw_perf_event *hwc, u32 filter); |
111 | /* Implementation specific event validation */ |
112 | int (*validate_event)(struct arm_cspmu *cspmu, |
113 | struct perf_event *event); |
114 | /* Hide/show unsupported events */ |
115 | umode_t (*event_attr_is_visible)(struct kobject *kobj, |
116 | struct attribute *attr, int unused); |
117 | }; |
118 | |
119 | /* Vendor/implementer registration parameter. */ |
120 | struct arm_cspmu_impl_match { |
121 | /* Backend module. */ |
122 | struct module *module; |
123 | const char *module_name; |
124 | /* PMIIDR value/mask. */ |
125 | u32 pmiidr_val; |
126 | u32 pmiidr_mask; |
127 | /* Callback to vendor backend to init arm_cspmu_impl::ops. */ |
128 | int (*impl_init_ops)(struct arm_cspmu *cspmu); |
129 | }; |
130 | |
131 | /* Vendor/implementer descriptor. */ |
132 | struct arm_cspmu_impl { |
133 | u32 pmiidr; |
134 | struct module *module; |
135 | struct arm_cspmu_impl_match *match; |
136 | struct arm_cspmu_impl_ops ops; |
137 | void *ctx; |
138 | }; |
139 | |
140 | /* Coresight PMU descriptor. */ |
141 | struct arm_cspmu { |
142 | struct pmu pmu; |
143 | struct device *dev; |
144 | const char *name; |
145 | const char *identifier; |
146 | void __iomem *base0; |
147 | void __iomem *base1; |
148 | cpumask_t associated_cpus; |
149 | cpumask_t active_cpu; |
150 | struct hlist_node cpuhp_node; |
151 | int irq; |
152 | |
153 | bool has_atomic_dword; |
154 | u32 pmcfgr; |
155 | u32 num_logical_ctrs; |
156 | u32 num_set_clr_reg; |
157 | int cycle_counter_logical_idx; |
158 | |
159 | struct arm_cspmu_hw_events hw_events; |
160 | const struct attribute_group *attr_groups[5]; |
161 | |
162 | struct arm_cspmu_impl impl; |
163 | }; |
164 | |
165 | /* Default function to show event attribute in sysfs. */ |
166 | ssize_t arm_cspmu_sysfs_event_show(struct device *dev, |
167 | struct device_attribute *attr, |
168 | char *buf); |
169 | |
170 | /* Default function to show format attribute in sysfs. */ |
171 | ssize_t arm_cspmu_sysfs_format_show(struct device *dev, |
172 | struct device_attribute *attr, |
173 | char *buf); |
174 | |
175 | /* Register vendor backend. */ |
176 | int arm_cspmu_impl_register(const struct arm_cspmu_impl_match *impl_match); |
177 | |
178 | /* Unregister vendor backend. */ |
179 | void arm_cspmu_impl_unregister(const struct arm_cspmu_impl_match *impl_match); |
180 | |
181 | #endif /* __ARM_CSPMU_H__ */ |
182 | |