1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Hypervisor supplied "gpci" ("get performance counter info") performance
6 * Author: Cody P Schafer <cody@linux.vnet.ibm.com>
7 * Copyright 2014 IBM Corporation.
10 #define pr_fmt(fmt) "hv-gpci: " fmt
12 #include <linux/init.h>
13 #include <linux/perf_event.h>
14 #include <asm/firmware.h>
15 #include <asm/hvcall.h>
19 #include "hv-common.h"
23 * perf stat -e 'hv_gpci/counter_info_version=3,offset=0,length=8,
24 * secondary_index=0,starting_index=0xffffffff,request=0x10/' ...
28 EVENT_DEFINE_RANGE_FORMAT(request
, config
, 0, 31);
31 * Note that starting_index, phys_processor_idx, sibling_part_id,
32 * hw_chip_id, partition_id all refer to the same bit range. They
33 * are basically aliases for the starting_index. The specific alias
34 * used depends on the event. See REQUEST_IDX_KIND in hv-gpci-requests.h
36 EVENT_DEFINE_RANGE_FORMAT(starting_index
, config
, 32, 63);
37 EVENT_DEFINE_RANGE_FORMAT_LITE(phys_processor_idx
, config
, 32, 63);
38 EVENT_DEFINE_RANGE_FORMAT_LITE(sibling_part_id
, config
, 32, 63);
39 EVENT_DEFINE_RANGE_FORMAT_LITE(hw_chip_id
, config
, 32, 63);
40 EVENT_DEFINE_RANGE_FORMAT_LITE(partition_id
, config
, 32, 63);
43 EVENT_DEFINE_RANGE_FORMAT(secondary_index
, config1
, 0, 15);
45 EVENT_DEFINE_RANGE_FORMAT(counter_info_version
, config1
, 16, 23);
46 /* u8, bytes of data (1-8) */
47 EVENT_DEFINE_RANGE_FORMAT(length
, config1
, 24, 31);
48 /* u32, byte offset */
49 EVENT_DEFINE_RANGE_FORMAT(offset
, config1
, 32, 63);
51 static cpumask_t hv_gpci_cpumask
;
53 static struct attribute
*format_attrs
[] = {
54 &format_attr_request
.attr
,
55 &format_attr_starting_index
.attr
,
56 &format_attr_phys_processor_idx
.attr
,
57 &format_attr_sibling_part_id
.attr
,
58 &format_attr_hw_chip_id
.attr
,
59 &format_attr_partition_id
.attr
,
60 &format_attr_secondary_index
.attr
,
61 &format_attr_counter_info_version
.attr
,
63 &format_attr_offset
.attr
,
64 &format_attr_length
.attr
,
68 static struct attribute_group format_group
= {
70 .attrs
= format_attrs
,
73 static struct attribute_group event_group
= {
75 .attrs
= hv_gpci_event_attrs
,
78 #define HV_CAPS_ATTR(_name, _format) \
79 static ssize_t _name##_show(struct device *dev, \
80 struct device_attribute *attr, \
83 struct hv_perf_caps caps; \
84 unsigned long hret = hv_perf_caps_get(&caps); \
88 return sprintf(page, _format, caps._name); \
90 static struct device_attribute hv_caps_attr_##_name = __ATTR_RO(_name)
92 static ssize_t
kernel_version_show(struct device
*dev
,
93 struct device_attribute
*attr
,
96 return sprintf(page
, "0x%x\n", COUNTER_INFO_VERSION_CURRENT
);
99 static ssize_t
cpumask_show(struct device
*dev
,
100 struct device_attribute
*attr
, char *buf
)
102 return cpumap_print_to_pagebuf(true, buf
, &hv_gpci_cpumask
);
105 static DEVICE_ATTR_RO(kernel_version
);
106 static DEVICE_ATTR_RO(cpumask
);
108 HV_CAPS_ATTR(version
, "0x%x\n");
109 HV_CAPS_ATTR(ga
, "%d\n");
110 HV_CAPS_ATTR(expanded
, "%d\n");
111 HV_CAPS_ATTR(lab
, "%d\n");
112 HV_CAPS_ATTR(collect_privileged
, "%d\n");
114 static struct attribute
*interface_attrs
[] = {
115 &dev_attr_kernel_version
.attr
,
116 &hv_caps_attr_version
.attr
,
117 &hv_caps_attr_ga
.attr
,
118 &hv_caps_attr_expanded
.attr
,
119 &hv_caps_attr_lab
.attr
,
120 &hv_caps_attr_collect_privileged
.attr
,
124 static struct attribute
*cpumask_attrs
[] = {
125 &dev_attr_cpumask
.attr
,
129 static struct attribute_group cpumask_attr_group
= {
130 .attrs
= cpumask_attrs
,
133 static struct attribute_group interface_group
= {
135 .attrs
= interface_attrs
,
138 static const struct attribute_group
*attr_groups
[] = {
146 static DEFINE_PER_CPU(char, hv_gpci_reqb
[HGPCI_REQ_BUFFER_SIZE
]) __aligned(sizeof(uint64_t));
148 static unsigned long single_gpci_request(u32 req
, u32 starting_index
,
149 u16 secondary_index
, u8 version_in
, u32 offset
, u8 length
,
155 struct hv_gpci_request_buffer
*arg
;
157 arg
= (void *)get_cpu_var(hv_gpci_reqb
);
158 memset(arg
, 0, HGPCI_REQ_BUFFER_SIZE
);
160 arg
->params
.counter_request
= cpu_to_be32(req
);
161 arg
->params
.starting_index
= cpu_to_be32(starting_index
);
162 arg
->params
.secondary_index
= cpu_to_be16(secondary_index
);
163 arg
->params
.counter_info_version_in
= version_in
;
165 ret
= plpar_hcall_norets(H_GET_PERF_COUNTER_INFO
,
166 virt_to_phys(arg
), HGPCI_REQ_BUFFER_SIZE
);
168 pr_devel("hcall failed: 0x%lx\n", ret
);
173 * we verify offset and length are within the zeroed buffer at event
177 for (i
= offset
; i
< offset
+ length
; i
++)
178 count
|= arg
->bytes
[i
] << (i
- offset
);
182 put_cpu_var(hv_gpci_reqb
);
186 static u64
h_gpci_get_value(struct perf_event
*event
)
189 unsigned long ret
= single_gpci_request(event_get_request(event
),
190 event_get_starting_index(event
),
191 event_get_secondary_index(event
),
192 event_get_counter_info_version(event
),
193 event_get_offset(event
),
194 event_get_length(event
),
201 static void h_gpci_event_update(struct perf_event
*event
)
204 u64 now
= h_gpci_get_value(event
);
205 prev
= local64_xchg(&event
->hw
.prev_count
, now
);
206 local64_add(now
- prev
, &event
->count
);
209 static void h_gpci_event_start(struct perf_event
*event
, int flags
)
211 local64_set(&event
->hw
.prev_count
, h_gpci_get_value(event
));
214 static void h_gpci_event_stop(struct perf_event
*event
, int flags
)
216 h_gpci_event_update(event
);
219 static int h_gpci_event_add(struct perf_event
*event
, int flags
)
221 if (flags
& PERF_EF_START
)
222 h_gpci_event_start(event
, flags
);
227 static int h_gpci_event_init(struct perf_event
*event
)
233 if (event
->attr
.type
!= event
->pmu
->type
)
236 /* config2 is unused */
237 if (event
->attr
.config2
) {
238 pr_devel("config2 set when reserved\n");
242 /* no branch sampling */
243 if (has_branch_stack(event
))
246 length
= event_get_length(event
);
247 if (length
< 1 || length
> 8) {
248 pr_devel("length invalid\n");
252 /* last byte within the buffer? */
253 if ((event_get_offset(event
) + length
) > HGPCI_MAX_DATA_BYTES
) {
254 pr_devel("request outside of buffer: %zu > %zu\n",
255 (size_t)event_get_offset(event
) + length
,
256 HGPCI_MAX_DATA_BYTES
);
260 /* check if the request works... */
261 if (single_gpci_request(event_get_request(event
),
262 event_get_starting_index(event
),
263 event_get_secondary_index(event
),
264 event_get_counter_info_version(event
),
265 event_get_offset(event
),
268 pr_devel("gpci hcall failed\n");
275 static struct pmu h_gpci_pmu
= {
276 .task_ctx_nr
= perf_invalid_context
,
279 .attr_groups
= attr_groups
,
280 .event_init
= h_gpci_event_init
,
281 .add
= h_gpci_event_add
,
282 .del
= h_gpci_event_stop
,
283 .start
= h_gpci_event_start
,
284 .stop
= h_gpci_event_stop
,
285 .read
= h_gpci_event_update
,
286 .capabilities
= PERF_PMU_CAP_NO_EXCLUDE
,
289 static int ppc_hv_gpci_cpu_online(unsigned int cpu
)
291 if (cpumask_empty(&hv_gpci_cpumask
))
292 cpumask_set_cpu(cpu
, &hv_gpci_cpumask
);
297 static int ppc_hv_gpci_cpu_offline(unsigned int cpu
)
301 /* Check if exiting cpu is used for collecting gpci events */
302 if (!cpumask_test_and_clear_cpu(cpu
, &hv_gpci_cpumask
))
305 /* Find a new cpu to collect gpci events */
306 target
= cpumask_last(cpu_active_mask
);
308 if (target
< 0 || target
>= nr_cpu_ids
) {
309 pr_err("hv_gpci: CPU hotplug init failed\n");
313 /* Migrate gpci events to the new target */
314 cpumask_set_cpu(target
, &hv_gpci_cpumask
);
315 perf_pmu_migrate_context(&h_gpci_pmu
, cpu
, target
);
320 static int hv_gpci_cpu_hotplug_init(void)
322 return cpuhp_setup_state(CPUHP_AP_PERF_POWERPC_HV_GPCI_ONLINE
,
323 "perf/powerpc/hv_gcpi:online",
324 ppc_hv_gpci_cpu_online
,
325 ppc_hv_gpci_cpu_offline
);
328 static int hv_gpci_init(void)
332 struct hv_perf_caps caps
;
334 hv_gpci_assert_offsets_correct();
336 if (!firmware_has_feature(FW_FEATURE_LPAR
)) {
337 pr_debug("not a virtualized system, not enabling\n");
341 hret
= hv_perf_caps_get(&caps
);
343 pr_debug("could not obtain capabilities, not enabling, rc=%ld\n",
348 /* init cpuhotplug */
349 r
= hv_gpci_cpu_hotplug_init();
353 /* sampling not supported */
354 h_gpci_pmu
.capabilities
|= PERF_PMU_CAP_NO_INTERRUPT
;
356 r
= perf_pmu_register(&h_gpci_pmu
, h_gpci_pmu
.name
, -1);
363 device_initcall(hv_gpci_init
);