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