powerpc/hv_gpci: Add sysfs file inside hv_gpci device to show affinity domain via...
[linux-block.git] / arch / powerpc / perf / hv-gpci.c
CommitLineData
2874c5fd 1// SPDX-License-Identifier: GPL-2.0-or-later
220a0c60
CS
2/*
3 * Hypervisor supplied "gpci" ("get performance counter info") performance
4 * counter support
5 *
6 * Author: Cody P Schafer <cody@linux.vnet.ibm.com>
7 * Copyright 2014 IBM Corporation.
220a0c60
CS
8 */
9
10#define pr_fmt(fmt) "hv-gpci: " fmt
11
12#include <linux/init.h>
13#include <linux/perf_event.h>
14#include <asm/firmware.h>
15#include <asm/hvcall.h>
16#include <asm/io.h>
17
18#include "hv-gpci.h"
19#include "hv-common.h"
20
21/*
22 * Example usage:
23 * perf stat -e 'hv_gpci/counter_info_version=3,offset=0,length=8,
24 * secondary_index=0,starting_index=0xffffffff,request=0x10/' ...
25 */
26
27/* u32 */
28EVENT_DEFINE_RANGE_FORMAT(request, config, 0, 31);
29/* u32 */
9e9f6010
CS
30/*
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
35 */
220a0c60 36EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 32, 63);
9e9f6010
CS
37EVENT_DEFINE_RANGE_FORMAT_LITE(phys_processor_idx, config, 32, 63);
38EVENT_DEFINE_RANGE_FORMAT_LITE(sibling_part_id, config, 32, 63);
39EVENT_DEFINE_RANGE_FORMAT_LITE(hw_chip_id, config, 32, 63);
40EVENT_DEFINE_RANGE_FORMAT_LITE(partition_id, config, 32, 63);
41
220a0c60
CS
42/* u16 */
43EVENT_DEFINE_RANGE_FORMAT(secondary_index, config1, 0, 15);
44/* u8 */
45EVENT_DEFINE_RANGE_FORMAT(counter_info_version, config1, 16, 23);
46/* u8, bytes of data (1-8) */
47EVENT_DEFINE_RANGE_FORMAT(length, config1, 24, 31);
48/* u32, byte offset */
49EVENT_DEFINE_RANGE_FORMAT(offset, config1, 32, 63);
50
dcb5cdf6
KJ
51static cpumask_t hv_gpci_cpumask;
52
220a0c60
CS
53static struct attribute *format_attrs[] = {
54 &format_attr_request.attr,
55 &format_attr_starting_index.attr,
9e9f6010
CS
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,
220a0c60
CS
60 &format_attr_secondary_index.attr,
61 &format_attr_counter_info_version.attr,
62
63 &format_attr_offset.attr,
64 &format_attr_length.attr,
65 NULL,
66};
67
6b3a3e12 68static const struct attribute_group format_group = {
220a0c60
CS
69 .name = "format",
70 .attrs = format_attrs,
71};
72
03f7c1d2 73static struct attribute_group event_group = {
9e9f6010 74 .name = "events",
03f7c1d2 75 /* .attrs is set in init */
9e9f6010
CS
76};
77
220a0c60
CS
78#define HV_CAPS_ATTR(_name, _format) \
79static ssize_t _name##_show(struct device *dev, \
80 struct device_attribute *attr, \
81 char *page) \
82{ \
83 struct hv_perf_caps caps; \
84 unsigned long hret = hv_perf_caps_get(&caps); \
85 if (hret) \
86 return -EIO; \
87 \
88 return sprintf(page, _format, caps._name); \
89} \
90static struct device_attribute hv_caps_attr_##_name = __ATTR_RO(_name)
91
92static ssize_t kernel_version_show(struct device *dev,
93 struct device_attribute *attr,
94 char *page)
95{
96 return sprintf(page, "0x%x\n", COUNTER_INFO_VERSION_CURRENT);
97}
98
09b791d9
KJ
99static ssize_t cpumask_show(struct device *dev,
100 struct device_attribute *attr, char *buf)
101{
102 return cpumap_print_to_pagebuf(true, buf, &hv_gpci_cpumask);
103}
104
71f1c396
KJ
105/* Interface attribute array index to store system information */
106#define INTERFACE_PROCESSOR_BUS_TOPOLOGY_ATTR 6
1a160c2a 107#define INTERFACE_PROCESSOR_CONFIG_ATTR 7
71a7ccb4 108#define INTERFACE_AFFINITY_DOMAIN_VIA_VP_ATTR 8
a69a57ca
KJ
109#define INTERFACE_AFFINITY_DOMAIN_VIA_DOM_ATTR 9
110#define INTERFACE_NULL_ATTR 10
1a160c2a
KJ
111
112/* Counter request value to retrieve system information */
113enum {
114 PROCESSOR_BUS_TOPOLOGY,
71a7ccb4
KJ
115 PROCESSOR_CONFIG,
116 AFFINITY_DOMAIN_VIA_VP, /* affinity domain via virtual processor */
a69a57ca 117 AFFINITY_DOMAIN_VIA_DOM, /* affinity domain via domain */
1a160c2a
KJ
118};
119
120static int sysinfo_counter_request[] = {
121 [PROCESSOR_BUS_TOPOLOGY] = 0xD0,
122 [PROCESSOR_CONFIG] = 0x90,
71a7ccb4 123 [AFFINITY_DOMAIN_VIA_VP] = 0xA0,
a69a57ca 124 [AFFINITY_DOMAIN_VIA_DOM] = 0xB0,
1a160c2a 125};
71f1c396
KJ
126
127static DEFINE_PER_CPU(char, hv_gpci_reqb[HGPCI_REQ_BUFFER_SIZE]) __aligned(sizeof(uint64_t));
128
129static unsigned long systeminfo_gpci_request(u32 req, u32 starting_index,
130 u16 secondary_index, char *buf,
131 size_t *n, struct hv_gpci_request_buffer *arg)
132{
133 unsigned long ret;
134 size_t i, j;
135
136 arg->params.counter_request = cpu_to_be32(req);
137 arg->params.starting_index = cpu_to_be32(starting_index);
138 arg->params.secondary_index = cpu_to_be16(secondary_index);
139
140 ret = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO,
141 virt_to_phys(arg), HGPCI_REQ_BUFFER_SIZE);
142
143 /*
144 * ret value as 'H_PARAMETER' corresponds to 'GEN_BUF_TOO_SMALL',
145 * which means that the current buffer size cannot accommodate
146 * all the information and a partial buffer returned.
147 * hcall fails incase of ret value other than H_SUCCESS or H_PARAMETER.
148 *
149 * ret value as H_AUTHORITY implies that partition is not permitted to retrieve
150 * performance information, and required to set
151 * "Enable Performance Information Collection" option.
152 */
153 if (ret == H_AUTHORITY)
154 return -EPERM;
155
156 /*
157 * hcall can fail with other possible ret value like H_PRIVILEGE/H_HARDWARE
158 * because of invalid buffer-length/address or due to some hardware
159 * error.
160 */
161 if (ret && (ret != H_PARAMETER))
162 return -EIO;
163
164 /*
165 * hcall H_GET_PERF_COUNTER_INFO populates the 'returned_values'
166 * to show the total number of counter_value array elements
167 * returned via hcall.
168 * hcall also populates 'cv_element_size' corresponds to individual
169 * counter_value array element size. Below loop go through all
170 * counter_value array elements as per their size and add it to
171 * the output buffer.
172 */
173 for (i = 0; i < be16_to_cpu(arg->params.returned_values); i++) {
174 j = i * be16_to_cpu(arg->params.cv_element_size);
175
176 for (; j < (i + 1) * be16_to_cpu(arg->params.cv_element_size); j++)
177 *n += sprintf(buf + *n, "%02x", (u8)arg->bytes[j]);
178 *n += sprintf(buf + *n, "\n");
179 }
180
181 if (*n >= PAGE_SIZE) {
182 pr_info("System information exceeds PAGE_SIZE\n");
183 return -EFBIG;
184 }
185
186 return ret;
187}
188
189static ssize_t processor_bus_topology_show(struct device *dev, struct device_attribute *attr,
190 char *buf)
191{
192 struct hv_gpci_request_buffer *arg;
193 unsigned long ret;
194 size_t n = 0;
195
196 arg = (void *)get_cpu_var(hv_gpci_reqb);
197 memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
198
199 /*
200 * Pass the counter request value 0xD0 corresponds to request
201 * type 'Processor_bus_topology', to retrieve
202 * the system topology information.
203 * starting_index value implies the starting hardware
204 * chip id.
205 */
1a160c2a
KJ
206 ret = systeminfo_gpci_request(sysinfo_counter_request[PROCESSOR_BUS_TOPOLOGY],
207 0, 0, buf, &n, arg);
71f1c396
KJ
208
209 if (!ret)
210 return n;
211
212 if (ret != H_PARAMETER)
213 goto out;
214
215 /*
216 * ret value as 'H_PARAMETER' corresponds to 'GEN_BUF_TOO_SMALL', which
217 * implies that buffer can't accommodate all information, and a partial buffer
218 * returned. To handle that, we need to make subsequent requests
219 * with next starting index to retrieve additional (missing) data.
220 * Below loop do subsequent hcalls with next starting index and add it
221 * to buffer util we get all the information.
222 */
223 while (ret == H_PARAMETER) {
224 int returned_values = be16_to_cpu(arg->params.returned_values);
225 int elementsize = be16_to_cpu(arg->params.cv_element_size);
226 int last_element = (returned_values - 1) * elementsize;
227
228 /*
229 * Since the starting index value is part of counter_value
230 * buffer elements, use the starting index value in the last
231 * element and add 1 to make subsequent hcalls.
232 */
233 u32 starting_index = arg->bytes[last_element + 3] +
234 (arg->bytes[last_element + 2] << 8) +
235 (arg->bytes[last_element + 1] << 16) +
236 (arg->bytes[last_element] << 24) + 1;
237
238 memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
239
1a160c2a
KJ
240 ret = systeminfo_gpci_request(sysinfo_counter_request[PROCESSOR_BUS_TOPOLOGY],
241 starting_index, 0, buf, &n, arg);
242
243 if (!ret)
244 return n;
245
246 if (ret != H_PARAMETER)
247 goto out;
248 }
249
250 return n;
251
252out:
253 put_cpu_var(hv_gpci_reqb);
254 return ret;
255}
256
257static ssize_t processor_config_show(struct device *dev, struct device_attribute *attr,
258 char *buf)
259{
260 struct hv_gpci_request_buffer *arg;
261 unsigned long ret;
262 size_t n = 0;
263
264 arg = (void *)get_cpu_var(hv_gpci_reqb);
265 memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
266
267 /*
268 * Pass the counter request value 0x90 corresponds to request
269 * type 'Processor_config', to retrieve
270 * the system processor information.
271 * starting_index value implies the starting hardware
272 * processor index.
273 */
274 ret = systeminfo_gpci_request(sysinfo_counter_request[PROCESSOR_CONFIG],
275 0, 0, buf, &n, arg);
276
277 if (!ret)
278 return n;
279
280 if (ret != H_PARAMETER)
281 goto out;
282
283 /*
284 * ret value as 'H_PARAMETER' corresponds to 'GEN_BUF_TOO_SMALL', which
285 * implies that buffer can't accommodate all information, and a partial buffer
286 * returned. To handle that, we need to take subsequent requests
287 * with next starting index to retrieve additional (missing) data.
288 * Below loop do subsequent hcalls with next starting index and add it
289 * to buffer util we get all the information.
290 */
291 while (ret == H_PARAMETER) {
292 int returned_values = be16_to_cpu(arg->params.returned_values);
293 int elementsize = be16_to_cpu(arg->params.cv_element_size);
294 int last_element = (returned_values - 1) * elementsize;
295
296 /*
297 * Since the starting index is part of counter_value
298 * buffer elements, use the starting index value in the last
299 * element and add 1 to subsequent hcalls.
300 */
301 u32 starting_index = arg->bytes[last_element + 3] +
302 (arg->bytes[last_element + 2] << 8) +
303 (arg->bytes[last_element + 1] << 16) +
304 (arg->bytes[last_element] << 24) + 1;
305
306 memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
307
308 ret = systeminfo_gpci_request(sysinfo_counter_request[PROCESSOR_CONFIG],
309 starting_index, 0, buf, &n, arg);
71f1c396
KJ
310
311 if (!ret)
312 return n;
313
314 if (ret != H_PARAMETER)
315 goto out;
316 }
317
318 return n;
319
320out:
321 put_cpu_var(hv_gpci_reqb);
322 return ret;
323}
324
71a7ccb4
KJ
325static ssize_t affinity_domain_via_virtual_processor_show(struct device *dev,
326 struct device_attribute *attr, char *buf)
327{
328 struct hv_gpci_request_buffer *arg;
329 unsigned long ret;
330 size_t n = 0;
331
332 arg = (void *)get_cpu_var(hv_gpci_reqb);
333 memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
334
335 /*
336 * Pass the counter request 0xA0 corresponds to request
337 * type 'Affinity_domain_information_by_virutal_processor',
338 * to retrieve the system affinity domain information.
339 * starting_index value refers to the starting hardware
340 * processor index.
341 */
342 ret = systeminfo_gpci_request(sysinfo_counter_request[AFFINITY_DOMAIN_VIA_VP],
343 0, 0, buf, &n, arg);
344
345 if (!ret)
346 return n;
347
348 if (ret != H_PARAMETER)
349 goto out;
350
351 /*
352 * ret value as 'H_PARAMETER' corresponds to 'GEN_BUF_TOO_SMALL', which
353 * implies that buffer can't accommodate all information, and a partial buffer
354 * returned. To handle that, we need to take subsequent requests
355 * with next secondary index to retrieve additional (missing) data.
356 * Below loop do subsequent hcalls with next secondary index and add it
357 * to buffer util we get all the information.
358 */
359 while (ret == H_PARAMETER) {
360 int returned_values = be16_to_cpu(arg->params.returned_values);
361 int elementsize = be16_to_cpu(arg->params.cv_element_size);
362 int last_element = (returned_values - 1) * elementsize;
363
364 /*
365 * Since the starting index and secondary index type is part of the
366 * counter_value buffer elements, use the starting index value in the
367 * last array element as subsequent starting index, and use secondary index
368 * value in the last array element plus 1 as subsequent secondary index.
369 * For counter request '0xA0', starting index points to partition id
370 * and secondary index points to corresponding virtual processor index.
371 */
372 u32 starting_index = arg->bytes[last_element + 1] + (arg->bytes[last_element] << 8);
373 u16 secondary_index = arg->bytes[last_element + 3] +
374 (arg->bytes[last_element + 2] << 8) + 1;
375
376 memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
377
378 ret = systeminfo_gpci_request(sysinfo_counter_request[AFFINITY_DOMAIN_VIA_VP],
379 starting_index, secondary_index, buf, &n, arg);
380
381 if (!ret)
382 return n;
383
384 if (ret != H_PARAMETER)
385 goto out;
386 }
387
388 return n;
389
390out:
391 put_cpu_var(hv_gpci_reqb);
392 return ret;
393}
394
a69a57ca
KJ
395static ssize_t affinity_domain_via_domain_show(struct device *dev, struct device_attribute *attr,
396 char *buf)
397{
398 struct hv_gpci_request_buffer *arg;
399 unsigned long ret;
400 size_t n = 0;
401
402 arg = (void *)get_cpu_var(hv_gpci_reqb);
403 memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
404
405 /*
406 * Pass the counter request 0xB0 corresponds to request
407 * type 'Affinity_domain_information_by_domain',
408 * to retrieve the system affinity domain information.
409 * starting_index value refers to the starting hardware
410 * processor index.
411 */
412 ret = systeminfo_gpci_request(sysinfo_counter_request[AFFINITY_DOMAIN_VIA_DOM],
413 0, 0, buf, &n, arg);
414
415 if (!ret)
416 return n;
417
418 if (ret != H_PARAMETER)
419 goto out;
420
421 /*
422 * ret value as 'H_PARAMETER' corresponds to 'GEN_BUF_TOO_SMALL', which
423 * implies that buffer can't accommodate all information, and a partial buffer
424 * returned. To handle that, we need to take subsequent requests
425 * with next starting index to retrieve additional (missing) data.
426 * Below loop do subsequent hcalls with next starting index and add it
427 * to buffer util we get all the information.
428 */
429 while (ret == H_PARAMETER) {
430 int returned_values = be16_to_cpu(arg->params.returned_values);
431 int elementsize = be16_to_cpu(arg->params.cv_element_size);
432 int last_element = (returned_values - 1) * elementsize;
433
434 /*
435 * Since the starting index value is part of counter_value
436 * buffer elements, use the starting index value in the last
437 * element and add 1 to make subsequent hcalls.
438 */
439 u32 starting_index = arg->bytes[last_element + 1] +
440 (arg->bytes[last_element] << 8) + 1;
441
442 memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
443
444 ret = systeminfo_gpci_request(sysinfo_counter_request[AFFINITY_DOMAIN_VIA_DOM],
445 starting_index, 0, buf, &n, arg);
446
447 if (!ret)
448 return n;
449
450 if (ret != H_PARAMETER)
451 goto out;
452 }
453
454 return n;
455
456out:
457 put_cpu_var(hv_gpci_reqb);
458 return ret;
459}
460
58a685c2 461static DEVICE_ATTR_RO(kernel_version);
09b791d9
KJ
462static DEVICE_ATTR_RO(cpumask);
463
220a0c60
CS
464HV_CAPS_ATTR(version, "0x%x\n");
465HV_CAPS_ATTR(ga, "%d\n");
466HV_CAPS_ATTR(expanded, "%d\n");
467HV_CAPS_ATTR(lab, "%d\n");
468HV_CAPS_ATTR(collect_privileged, "%d\n");
469
470static struct attribute *interface_attrs[] = {
471 &dev_attr_kernel_version.attr,
472 &hv_caps_attr_version.attr,
473 &hv_caps_attr_ga.attr,
474 &hv_caps_attr_expanded.attr,
475 &hv_caps_attr_lab.attr,
476 &hv_caps_attr_collect_privileged.attr,
71f1c396
KJ
477 /*
478 * This NULL is a placeholder for the processor_bus_topology
479 * attribute, set in init function if applicable.
480 */
481 NULL,
1a160c2a
KJ
482 /*
483 * This NULL is a placeholder for the processor_config
484 * attribute, set in init function if applicable.
485 */
486 NULL,
71a7ccb4
KJ
487 /*
488 * This NULL is a placeholder for the affinity_domain_via_virtual_processor
489 * attribute, set in init function if applicable.
490 */
491 NULL,
a69a57ca
KJ
492 /*
493 * This NULL is a placeholder for the affinity_domain_via_domain
494 * attribute, set in init function if applicable.
495 */
496 NULL,
220a0c60
CS
497 NULL,
498};
499
09b791d9
KJ
500static struct attribute *cpumask_attrs[] = {
501 &dev_attr_cpumask.attr,
502 NULL,
503};
504
6b3a3e12 505static const struct attribute_group cpumask_attr_group = {
09b791d9
KJ
506 .attrs = cpumask_attrs,
507};
508
6b3a3e12 509static const struct attribute_group interface_group = {
220a0c60
CS
510 .name = "interface",
511 .attrs = interface_attrs,
512};
513
514static const struct attribute_group *attr_groups[] = {
515 &format_group,
9e9f6010 516 &event_group,
220a0c60 517 &interface_group,
09b791d9 518 &cpumask_attr_group,
220a0c60
CS
519 NULL,
520};
521
220a0c60
CS
522static unsigned long single_gpci_request(u32 req, u32 starting_index,
523 u16 secondary_index, u8 version_in, u32 offset, u8 length,
524 u64 *value)
525{
526 unsigned long ret;
527 size_t i;
528 u64 count;
e4f226b1
SB
529 struct hv_gpci_request_buffer *arg;
530
531 arg = (void *)get_cpu_var(hv_gpci_reqb);
532 memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
220a0c60 533
e4f226b1
SB
534 arg->params.counter_request = cpu_to_be32(req);
535 arg->params.starting_index = cpu_to_be32(starting_index);
536 arg->params.secondary_index = cpu_to_be16(secondary_index);
537 arg->params.counter_info_version_in = version_in;
220a0c60
CS
538
539 ret = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO,
e4f226b1 540 virt_to_phys(arg), HGPCI_REQ_BUFFER_SIZE);
220a0c60
CS
541 if (ret) {
542 pr_devel("hcall failed: 0x%lx\n", ret);
e4f226b1 543 goto out;
220a0c60
CS
544 }
545
546 /*
547 * we verify offset and length are within the zeroed buffer at event
548 * init.
549 */
550 count = 0;
551 for (i = offset; i < offset + length; i++)
f9addd85 552 count |= (u64)(arg->bytes[i]) << ((length - 1 - (i - offset)) * 8);
220a0c60
CS
553
554 *value = count;
e4f226b1
SB
555out:
556 put_cpu_var(hv_gpci_reqb);
220a0c60
CS
557 return ret;
558}
559
560static u64 h_gpci_get_value(struct perf_event *event)
561{
562 u64 count;
563 unsigned long ret = single_gpci_request(event_get_request(event),
564 event_get_starting_index(event),
565 event_get_secondary_index(event),
566 event_get_counter_info_version(event),
567 event_get_offset(event),
568 event_get_length(event),
569 &count);
570 if (ret)
571 return 0;
572 return count;
573}
574
575static void h_gpci_event_update(struct perf_event *event)
576{
577 s64 prev;
578 u64 now = h_gpci_get_value(event);
579 prev = local64_xchg(&event->hw.prev_count, now);
580 local64_add(now - prev, &event->count);
581}
582
583static void h_gpci_event_start(struct perf_event *event, int flags)
584{
585 local64_set(&event->hw.prev_count, h_gpci_get_value(event));
586}
587
588static void h_gpci_event_stop(struct perf_event *event, int flags)
589{
590 h_gpci_event_update(event);
591}
592
593static int h_gpci_event_add(struct perf_event *event, int flags)
594{
595 if (flags & PERF_EF_START)
596 h_gpci_event_start(event, flags);
597
598 return 0;
599}
600
601static int h_gpci_event_init(struct perf_event *event)
602{
603 u64 count;
604 u8 length;
605
606 /* Not our event */
607 if (event->attr.type != event->pmu->type)
608 return -ENOENT;
609
610 /* config2 is unused */
611 if (event->attr.config2) {
612 pr_devel("config2 set when reserved\n");
613 return -EINVAL;
614 }
615
220a0c60
CS
616 /* no branch sampling */
617 if (has_branch_stack(event))
618 return -EOPNOTSUPP;
619
620 length = event_get_length(event);
621 if (length < 1 || length > 8) {
622 pr_devel("length invalid\n");
623 return -EINVAL;
624 }
625
626 /* last byte within the buffer? */
e4f226b1 627 if ((event_get_offset(event) + length) > HGPCI_MAX_DATA_BYTES) {
220a0c60
CS
628 pr_devel("request outside of buffer: %zu > %zu\n",
629 (size_t)event_get_offset(event) + length,
e4f226b1 630 HGPCI_MAX_DATA_BYTES);
220a0c60
CS
631 return -EINVAL;
632 }
633
634 /* check if the request works... */
635 if (single_gpci_request(event_get_request(event),
636 event_get_starting_index(event),
637 event_get_secondary_index(event),
638 event_get_counter_info_version(event),
639 event_get_offset(event),
640 length,
641 &count)) {
642 pr_devel("gpci hcall failed\n");
643 return -EINVAL;
644 }
645
646 return 0;
647}
648
220a0c60
CS
649static struct pmu h_gpci_pmu = {
650 .task_ctx_nr = perf_invalid_context,
651
652 .name = "hv_gpci",
653 .attr_groups = attr_groups,
654 .event_init = h_gpci_event_init,
655 .add = h_gpci_event_add,
656 .del = h_gpci_event_stop,
657 .start = h_gpci_event_start,
658 .stop = h_gpci_event_stop,
659 .read = h_gpci_event_update,
c2c9091d 660 .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
220a0c60
CS
661};
662
dcb5cdf6
KJ
663static int ppc_hv_gpci_cpu_online(unsigned int cpu)
664{
665 if (cpumask_empty(&hv_gpci_cpumask))
666 cpumask_set_cpu(cpu, &hv_gpci_cpumask);
667
668 return 0;
669}
670
671static int ppc_hv_gpci_cpu_offline(unsigned int cpu)
672{
673 int target;
674
675 /* Check if exiting cpu is used for collecting gpci events */
676 if (!cpumask_test_and_clear_cpu(cpu, &hv_gpci_cpumask))
677 return 0;
678
679 /* Find a new cpu to collect gpci events */
680 target = cpumask_last(cpu_active_mask);
681
682 if (target < 0 || target >= nr_cpu_ids) {
683 pr_err("hv_gpci: CPU hotplug init failed\n");
684 return -1;
685 }
686
687 /* Migrate gpci events to the new target */
688 cpumask_set_cpu(target, &hv_gpci_cpumask);
689 perf_pmu_migrate_context(&h_gpci_pmu, cpu, target);
690
691 return 0;
692}
693
694static int hv_gpci_cpu_hotplug_init(void)
695{
696 return cpuhp_setup_state(CPUHP_AP_PERF_POWERPC_HV_GPCI_ONLINE,
697 "perf/powerpc/hv_gcpi:online",
698 ppc_hv_gpci_cpu_online,
699 ppc_hv_gpci_cpu_offline);
700}
701
1a160c2a
KJ
702static struct device_attribute *sysinfo_device_attr_create(int
703 sysinfo_interface_group_index, u32 req)
71f1c396
KJ
704{
705 struct device_attribute *attr = NULL;
706 unsigned long ret;
707 struct hv_gpci_request_buffer *arg;
708
1a160c2a
KJ
709 if (sysinfo_interface_group_index < INTERFACE_PROCESSOR_BUS_TOPOLOGY_ATTR ||
710 sysinfo_interface_group_index >= INTERFACE_NULL_ATTR) {
711 pr_info("Wrong interface group index for system information\n");
712 return NULL;
713 }
714
715 /* Check for given counter request value support */
71f1c396
KJ
716 arg = (void *)get_cpu_var(hv_gpci_reqb);
717 memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
718
1a160c2a 719 arg->params.counter_request = cpu_to_be32(req);
71f1c396
KJ
720
721 ret = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO,
722 virt_to_phys(arg), HGPCI_REQ_BUFFER_SIZE);
723
724 put_cpu_var(hv_gpci_reqb);
725
726 /*
1a160c2a 727 * Add given counter request value attribute in the interface_attrs
71f1c396
KJ
728 * attribute array, only for valid return types.
729 */
730 if (!ret || ret == H_AUTHORITY || ret == H_PARAMETER) {
731 attr = kzalloc(sizeof(*attr), GFP_KERNEL);
732 if (!attr)
1a160c2a 733 return NULL;
71f1c396
KJ
734
735 sysfs_attr_init(&attr->attr);
71f1c396 736 attr->attr.mode = 0444;
1a160c2a
KJ
737
738 switch (sysinfo_interface_group_index) {
739 case INTERFACE_PROCESSOR_BUS_TOPOLOGY_ATTR:
740 attr->attr.name = "processor_bus_topology";
741 attr->show = processor_bus_topology_show;
742 break;
743 case INTERFACE_PROCESSOR_CONFIG_ATTR:
744 attr->attr.name = "processor_config";
745 attr->show = processor_config_show;
746 break;
71a7ccb4
KJ
747 case INTERFACE_AFFINITY_DOMAIN_VIA_VP_ATTR:
748 attr->attr.name = "affinity_domain_via_virtual_processor";
749 attr->show = affinity_domain_via_virtual_processor_show;
750 break;
a69a57ca
KJ
751 case INTERFACE_AFFINITY_DOMAIN_VIA_DOM_ATTR:
752 attr->attr.name = "affinity_domain_via_domain";
753 attr->show = affinity_domain_via_domain_show;
754 break;
1a160c2a 755 }
71f1c396
KJ
756 } else
757 pr_devel("hcall failed, with error: 0x%lx\n", ret);
1a160c2a
KJ
758
759 return attr;
760}
761
762static void add_sysinfo_interface_files(void)
763{
764 int sysfs_count;
765 struct device_attribute *attr[INTERFACE_NULL_ATTR - INTERFACE_PROCESSOR_BUS_TOPOLOGY_ATTR];
766 int i;
767
768 sysfs_count = INTERFACE_NULL_ATTR - INTERFACE_PROCESSOR_BUS_TOPOLOGY_ATTR;
769
770 /* Get device attribute for a given counter request value */
771 for (i = 0; i < sysfs_count; i++) {
772 attr[i] = sysinfo_device_attr_create(i + INTERFACE_PROCESSOR_BUS_TOPOLOGY_ATTR,
773 sysinfo_counter_request[i]);
774
775 if (!attr[i])
776 goto out;
777 }
778
779 /* Add sysinfo interface attributes in the interface_attrs attribute array */
780 for (i = 0; i < sysfs_count; i++)
781 interface_attrs[i + INTERFACE_PROCESSOR_BUS_TOPOLOGY_ATTR] = &attr[i]->attr;
782
783 return;
784
785out:
786 /*
787 * The sysinfo interface attributes will be added, only if hcall passed for
788 * all the counter request values. Free the device attribute array incase
789 * of any hcall failure.
790 */
791 if (i > 0) {
792 while (i >= 0) {
793 kfree(attr[i]);
794 i--;
795 }
796 }
71f1c396
KJ
797}
798
220a0c60
CS
799static int hv_gpci_init(void)
800{
801 int r;
802 unsigned long hret;
803 struct hv_perf_caps caps;
03f7c1d2 804 struct hv_gpci_request_buffer *arg;
220a0c60 805
9e9f6010
CS
806 hv_gpci_assert_offsets_correct();
807
220a0c60 808 if (!firmware_has_feature(FW_FEATURE_LPAR)) {
0a8cf9e2 809 pr_debug("not a virtualized system, not enabling\n");
220a0c60
CS
810 return -ENODEV;
811 }
812
813 hret = hv_perf_caps_get(&caps);
814 if (hret) {
0a8cf9e2 815 pr_debug("could not obtain capabilities, not enabling, rc=%ld\n",
220a0c60
CS
816 hret);
817 return -ENODEV;
818 }
819
dcb5cdf6
KJ
820 /* init cpuhotplug */
821 r = hv_gpci_cpu_hotplug_init();
822 if (r)
823 return r;
824
cc56d673
VW
825 /* sampling not supported */
826 h_gpci_pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
827
03f7c1d2
KJ
828 arg = (void *)get_cpu_var(hv_gpci_reqb);
829 memset(arg, 0, HGPCI_REQ_BUFFER_SIZE);
830
831 /*
832 * hcall H_GET_PERF_COUNTER_INFO populates the output
833 * counter_info_version value based on the system hypervisor.
834 * Pass the counter request 0x10 corresponds to request type
835 * 'Dispatch_timebase_by_processor', to get the supported
836 * counter_info_version.
837 */
838 arg->params.counter_request = cpu_to_be32(0x10);
839
840 r = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO,
841 virt_to_phys(arg), HGPCI_REQ_BUFFER_SIZE);
842 if (r) {
843 pr_devel("hcall failed, can't get supported counter_info_version: 0x%x\n", r);
844 arg->params.counter_info_version_out = 0x8;
845 }
846
847 /*
848 * Use counter_info_version_out value to assign
849 * required hv-gpci event list.
850 */
851 if (arg->params.counter_info_version_out >= 0x8)
852 event_group.attrs = hv_gpci_event_attrs;
853 else
854 event_group.attrs = hv_gpci_event_attrs_v6;
855
856 put_cpu_var(hv_gpci_reqb);
857
220a0c60
CS
858 r = perf_pmu_register(&h_gpci_pmu, h_gpci_pmu.name, -1);
859 if (r)
860 return r;
861
71f1c396
KJ
862 /* sysinfo interface files are only available for power10 and above platforms */
863 if (PVR_VER(mfspr(SPRN_PVR)) >= PVR_POWER10)
864 add_sysinfo_interface_files();
865
220a0c60
CS
866 return 0;
867}
868
869device_initcall(hv_gpci_init);