2 * Hypervisor supplied "gpci" ("get performance counter info") performance
5 * Author: Cody P Schafer <cody@linux.vnet.ibm.com>
6 * Copyright 2014 IBM Corporation.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
14 #define pr_fmt(fmt) "hv-gpci: " fmt
16 #include <linux/init.h>
17 #include <linux/perf_event.h>
18 #include <asm/firmware.h>
19 #include <asm/hvcall.h>
23 #include "hv-common.h"
27 * perf stat -e 'hv_gpci/counter_info_version=3,offset=0,length=8,
28 * secondary_index=0,starting_index=0xffffffff,request=0x10/' ...
32 EVENT_DEFINE_RANGE_FORMAT(request
, config
, 0, 31);
35 * Note that starting_index, phys_processor_idx, sibling_part_id,
36 * hw_chip_id, partition_id all refer to the same bit range. They
37 * are basically aliases for the starting_index. The specific alias
38 * used depends on the event. See REQUEST_IDX_KIND in hv-gpci-requests.h
40 EVENT_DEFINE_RANGE_FORMAT(starting_index
, config
, 32, 63);
41 EVENT_DEFINE_RANGE_FORMAT_LITE(phys_processor_idx
, config
, 32, 63);
42 EVENT_DEFINE_RANGE_FORMAT_LITE(sibling_part_id
, config
, 32, 63);
43 EVENT_DEFINE_RANGE_FORMAT_LITE(hw_chip_id
, config
, 32, 63);
44 EVENT_DEFINE_RANGE_FORMAT_LITE(partition_id
, config
, 32, 63);
47 EVENT_DEFINE_RANGE_FORMAT(secondary_index
, config1
, 0, 15);
49 EVENT_DEFINE_RANGE_FORMAT(counter_info_version
, config1
, 16, 23);
50 /* u8, bytes of data (1-8) */
51 EVENT_DEFINE_RANGE_FORMAT(length
, config1
, 24, 31);
52 /* u32, byte offset */
53 EVENT_DEFINE_RANGE_FORMAT(offset
, config1
, 32, 63);
55 static struct attribute
*format_attrs
[] = {
56 &format_attr_request
.attr
,
57 &format_attr_starting_index
.attr
,
58 &format_attr_phys_processor_idx
.attr
,
59 &format_attr_sibling_part_id
.attr
,
60 &format_attr_hw_chip_id
.attr
,
61 &format_attr_partition_id
.attr
,
62 &format_attr_secondary_index
.attr
,
63 &format_attr_counter_info_version
.attr
,
65 &format_attr_offset
.attr
,
66 &format_attr_length
.attr
,
70 static struct attribute_group format_group
= {
72 .attrs
= format_attrs
,
75 static struct attribute_group event_group
= {
77 .attrs
= hv_gpci_event_attrs
,
80 #define HV_CAPS_ATTR(_name, _format) \
81 static ssize_t _name##_show(struct device *dev, \
82 struct device_attribute *attr, \
85 struct hv_perf_caps caps; \
86 unsigned long hret = hv_perf_caps_get(&caps); \
90 return sprintf(page, _format, caps._name); \
92 static struct device_attribute hv_caps_attr_##_name = __ATTR_RO(_name)
94 static ssize_t
kernel_version_show(struct device
*dev
,
95 struct device_attribute
*attr
,
98 return sprintf(page
, "0x%x\n", COUNTER_INFO_VERSION_CURRENT
);
101 static DEVICE_ATTR_RO(kernel_version
);
102 HV_CAPS_ATTR(version
, "0x%x\n");
103 HV_CAPS_ATTR(ga
, "%d\n");
104 HV_CAPS_ATTR(expanded
, "%d\n");
105 HV_CAPS_ATTR(lab
, "%d\n");
106 HV_CAPS_ATTR(collect_privileged
, "%d\n");
108 static struct attribute
*interface_attrs
[] = {
109 &dev_attr_kernel_version
.attr
,
110 &hv_caps_attr_version
.attr
,
111 &hv_caps_attr_ga
.attr
,
112 &hv_caps_attr_expanded
.attr
,
113 &hv_caps_attr_lab
.attr
,
114 &hv_caps_attr_collect_privileged
.attr
,
118 static struct attribute_group interface_group
= {
120 .attrs
= interface_attrs
,
123 static const struct attribute_group
*attr_groups
[] = {
130 #define GPCI_MAX_DATA_BYTES \
131 (1024 - sizeof(struct hv_get_perf_counter_info_params))
133 static unsigned long single_gpci_request(u32 req
, u32 starting_index
,
134 u16 secondary_index
, u8 version_in
, u32 offset
, u8 length
,
142 struct hv_get_perf_counter_info_params params
;
143 uint8_t bytes
[GPCI_MAX_DATA_BYTES
];
144 } __packed
__aligned(sizeof(uint64_t)) arg
= {
146 .counter_request
= cpu_to_be32(req
),
147 .starting_index
= cpu_to_be32(starting_index
),
148 .secondary_index
= cpu_to_be16(secondary_index
),
149 .counter_info_version_in
= version_in
,
153 ret
= plpar_hcall_norets(H_GET_PERF_COUNTER_INFO
,
154 virt_to_phys(&arg
), sizeof(arg
));
156 pr_devel("hcall failed: 0x%lx\n", ret
);
161 * we verify offset and length are within the zeroed buffer at event
165 for (i
= offset
; i
< offset
+ length
; i
++)
166 count
|= arg
.bytes
[i
] << (i
- offset
);
172 static u64
h_gpci_get_value(struct perf_event
*event
)
175 unsigned long ret
= single_gpci_request(event_get_request(event
),
176 event_get_starting_index(event
),
177 event_get_secondary_index(event
),
178 event_get_counter_info_version(event
),
179 event_get_offset(event
),
180 event_get_length(event
),
187 static void h_gpci_event_update(struct perf_event
*event
)
190 u64 now
= h_gpci_get_value(event
);
191 prev
= local64_xchg(&event
->hw
.prev_count
, now
);
192 local64_add(now
- prev
, &event
->count
);
195 static void h_gpci_event_start(struct perf_event
*event
, int flags
)
197 local64_set(&event
->hw
.prev_count
, h_gpci_get_value(event
));
200 static void h_gpci_event_stop(struct perf_event
*event
, int flags
)
202 h_gpci_event_update(event
);
205 static int h_gpci_event_add(struct perf_event
*event
, int flags
)
207 if (flags
& PERF_EF_START
)
208 h_gpci_event_start(event
, flags
);
213 static int h_gpci_event_init(struct perf_event
*event
)
219 if (event
->attr
.type
!= event
->pmu
->type
)
222 /* config2 is unused */
223 if (event
->attr
.config2
) {
224 pr_devel("config2 set when reserved\n");
228 /* unsupported modes and filters */
229 if (event
->attr
.exclude_user
||
230 event
->attr
.exclude_kernel
||
231 event
->attr
.exclude_hv
||
232 event
->attr
.exclude_idle
||
233 event
->attr
.exclude_host
||
234 event
->attr
.exclude_guest
)
237 /* no branch sampling */
238 if (has_branch_stack(event
))
241 length
= event_get_length(event
);
242 if (length
< 1 || length
> 8) {
243 pr_devel("length invalid\n");
247 /* last byte within the buffer? */
248 if ((event_get_offset(event
) + length
) > GPCI_MAX_DATA_BYTES
) {
249 pr_devel("request outside of buffer: %zu > %zu\n",
250 (size_t)event_get_offset(event
) + length
,
251 GPCI_MAX_DATA_BYTES
);
255 /* check if the request works... */
256 if (single_gpci_request(event_get_request(event
),
257 event_get_starting_index(event
),
258 event_get_secondary_index(event
),
259 event_get_counter_info_version(event
),
260 event_get_offset(event
),
263 pr_devel("gpci hcall failed\n");
270 static struct pmu h_gpci_pmu
= {
271 .task_ctx_nr
= perf_invalid_context
,
274 .attr_groups
= attr_groups
,
275 .event_init
= h_gpci_event_init
,
276 .add
= h_gpci_event_add
,
277 .del
= h_gpci_event_stop
,
278 .start
= h_gpci_event_start
,
279 .stop
= h_gpci_event_stop
,
280 .read
= h_gpci_event_update
,
283 static int hv_gpci_init(void)
287 struct hv_perf_caps caps
;
289 hv_gpci_assert_offsets_correct();
291 if (!firmware_has_feature(FW_FEATURE_LPAR
)) {
292 pr_debug("not a virtualized system, not enabling\n");
296 hret
= hv_perf_caps_get(&caps
);
298 pr_debug("could not obtain capabilities, not enabling, rc=%ld\n",
303 /* sampling not supported */
304 h_gpci_pmu
.capabilities
|= PERF_PMU_CAP_NO_INTERRUPT
;
306 r
= perf_pmu_register(&h_gpci_pmu
, h_gpci_pmu
.name
, -1);
313 device_initcall(hv_gpci_init
);