1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * VPA DTL PMU support
4 */
5
6 #include <linux/string.h>
7 #include <linux/zalloc.h>
8 #include <errno.h>
9 #include <inttypes.h>
10 #include "color.h"
11 #include "evlist.h"
12 #include "session.h"
13 #include "auxtrace.h"
14 #include "data.h"
15 #include "machine.h"
16 #include "debug.h"
17 #include "powerpc-vpadtl.h"
18 #include "sample.h"
19 #include "tool.h"
20
21 /*
22 * Structure to save the auxtrace queue
23 */
24 struct powerpc_vpadtl {
25 struct auxtrace auxtrace;
26 struct auxtrace_queues queues;
27 struct auxtrace_heap heap;
28 u32 auxtrace_type;
29 struct perf_session *session;
30 struct machine *machine;
31 u32 pmu_type;
32 u64 sample_id;
33 };
34
35 struct boottb_freq {
36 u64 boot_tb;
37 u64 tb_freq;
38 u64 timebase;
39 u64 padded[3];
40 };
41
42 struct powerpc_vpadtl_queue {
43 struct powerpc_vpadtl *vpa;
44 unsigned int queue_nr;
45 struct auxtrace_buffer *buffer;
46 struct thread *thread;
47 bool on_heap;
48 struct powerpc_vpadtl_entry *dtl;
49 u64 timestamp;
50 unsigned long pkt_len;
51 unsigned long buf_len;
52 u64 boot_tb;
53 u64 tb_freq;
54 unsigned int tb_buffer;
55 unsigned int size;
56 bool done;
57 pid_t pid;
58 pid_t tid;
59 int cpu;
60 };
61
62 const char *dispatch_reasons[11] = {
63 "external_interrupt",
64 "firmware_internal_event",
65 "H_PROD",
66 "decrementer_interrupt",
67 "system_reset",
68 "firmware_internal_event",
69 "conferred_cycles",
70 "time_slice",
71 "virtual_memory_page_fault",
72 "expropriated_adjunct",
73 "priv_doorbell"};
74
75 const char *preempt_reasons[10] = {
76 "unused",
77 "firmware_internal_event",
78 "H_CEDE",
79 "H_CONFER",
80 "time_slice",
81 "migration_hibernation_page_fault",
82 "virtual_memory_page_fault",
83 "H_CONFER_ADJUNCT",
84 "hcall_adjunct",
85 "HDEC_adjunct"};
86
87 #define dtl_entry_size sizeof(struct powerpc_vpadtl_entry)
88
89 /*
90 * Function to dump the dispatch trace data when perf report
91 * is invoked with -D
92 */
powerpc_vpadtl_dump(struct powerpc_vpadtl * vpa __maybe_unused,unsigned char * buf,size_t len)93 static void powerpc_vpadtl_dump(struct powerpc_vpadtl *vpa __maybe_unused,
94 unsigned char *buf, size_t len)
95 {
96 struct powerpc_vpadtl_entry *dtl;
97 int pkt_len, pos = 0;
98 const char *color = PERF_COLOR_BLUE;
99
100 color_fprintf(stdout, color,
101 ". ... VPA DTL PMU data: size %zu bytes, entries is %zu\n",
102 len, len/dtl_entry_size);
103
104 if (len % dtl_entry_size)
105 len = len - (len % dtl_entry_size);
106
107 while (len) {
108 pkt_len = dtl_entry_size;
109 printf(".");
110 color_fprintf(stdout, color, " %08x: ", pos);
111 dtl = (struct powerpc_vpadtl_entry *)buf;
112 if (dtl->timebase != 0) {
113 printf("dispatch_reason:%s, preempt_reason:%s, "
114 "enqueue_to_dispatch_time:%d, ready_to_enqueue_time:%d, "
115 "waiting_to_ready_time:%d\n",
116 dispatch_reasons[dtl->dispatch_reason],
117 preempt_reasons[dtl->preempt_reason],
118 be32_to_cpu(dtl->enqueue_to_dispatch_time),
119 be32_to_cpu(dtl->ready_to_enqueue_time),
120 be32_to_cpu(dtl->waiting_to_ready_time));
121 } else {
122 struct boottb_freq *boot_tb = (struct boottb_freq *)buf;
123
124 printf("boot_tb: %" PRIu64 ", tb_freq: %" PRIu64 "\n",
125 boot_tb->boot_tb, boot_tb->tb_freq);
126 }
127
128 pos += pkt_len;
129 buf += pkt_len;
130 len -= pkt_len;
131 }
132 }
133
powerpc_vpadtl_timestamp(struct powerpc_vpadtl_queue * vpaq)134 static unsigned long long powerpc_vpadtl_timestamp(struct powerpc_vpadtl_queue *vpaq)
135 {
136 struct powerpc_vpadtl_entry *record = vpaq->dtl;
137 unsigned long long timestamp = 0;
138 unsigned long long boot_tb;
139 unsigned long long diff;
140 double result, div;
141 double boot_freq;
142 /*
143 * Formula used to get timestamp that can be co-related with
144 * other perf events:
145 * ((timbase from DTL entry - boot time) / frequency) * 1000000000
146 */
147 if (record->timebase) {
148 boot_tb = vpaq->boot_tb;
149 boot_freq = vpaq->tb_freq;
150 diff = be64_to_cpu(record->timebase) - boot_tb;
151 div = diff / boot_freq;
152 result = div;
153 result = result * 1000000000;
154 timestamp = result;
155 }
156
157 return timestamp;
158 }
159
session_to_vpa(struct perf_session * session)160 static struct powerpc_vpadtl *session_to_vpa(struct perf_session *session)
161 {
162 return container_of(session->auxtrace, struct powerpc_vpadtl, auxtrace);
163 }
164
powerpc_vpadtl_dump_event(struct powerpc_vpadtl * vpa,unsigned char * buf,size_t len)165 static void powerpc_vpadtl_dump_event(struct powerpc_vpadtl *vpa, unsigned char *buf,
166 size_t len)
167 {
168 printf(".\n");
169 powerpc_vpadtl_dump(vpa, buf, len);
170 }
171
172 /*
173 * Generate perf sample for each entry in the dispatch trace log.
174 * - sample ip is picked from srr0 field of powerpc_vpadtl_entry
175 * - sample cpu is logical cpu.
176 * - cpumode is set to PERF_RECORD_MISC_KERNEL
177 * - Additionally save the details in raw_data of sample. This
178 * is to print the relevant fields in perf_sample__fprintf_synth()
179 * when called from builtin-script
180 */
powerpc_vpadtl_sample(struct powerpc_vpadtl_entry * record,struct powerpc_vpadtl * vpa,u64 save,int cpu)181 static int powerpc_vpadtl_sample(struct powerpc_vpadtl_entry *record,
182 struct powerpc_vpadtl *vpa, u64 save, int cpu)
183 {
184 struct perf_sample sample;
185 union perf_event event;
186 int ret;
187
188 perf_sample__init(&sample, /*all=*/true);
189 sample.ip = be64_to_cpu(record->srr0);
190 sample.period = 1;
191 sample.cpu = cpu;
192 sample.id = vpa->sample_id;
193 sample.callchain = NULL;
194 sample.branch_stack = NULL;
195 memset(&event, 0, sizeof(event));
196 sample.cpumode = PERF_RECORD_MISC_KERNEL;
197 sample.time = save;
198 sample.raw_data = record;
199 sample.raw_size = sizeof(*record);
200 event.sample.header.type = PERF_RECORD_SAMPLE;
201 event.sample.header.misc = sample.cpumode;
202 event.sample.header.size = sizeof(struct perf_event_header);
203
204 ret = perf_session__deliver_synth_event(vpa->session, &event, &sample);
205 if (ret)
206 pr_debug("Failed to create sample for dtl entry\n");
207
208 perf_sample__exit(&sample);
209 return ret;
210 }
211
powerpc_vpadtl_get_buffer(struct powerpc_vpadtl_queue * vpaq)212 static int powerpc_vpadtl_get_buffer(struct powerpc_vpadtl_queue *vpaq)
213 {
214 struct auxtrace_buffer *buffer = vpaq->buffer;
215 struct auxtrace_queues *queues = &vpaq->vpa->queues;
216 struct auxtrace_queue *queue;
217
218 queue = &queues->queue_array[vpaq->queue_nr];
219 buffer = auxtrace_buffer__next(queue, buffer);
220
221 if (!buffer)
222 return 0;
223
224 vpaq->buffer = buffer;
225 vpaq->size = buffer->size;
226
227 /* If the aux_buffer doesn't have data associated, try to load it */
228 if (!buffer->data) {
229 /* get the file desc associated with the perf data file */
230 int fd = perf_data__fd(vpaq->vpa->session->data);
231
232 buffer->data = auxtrace_buffer__get_data(buffer, fd);
233 if (!buffer->data)
234 return -ENOMEM;
235 }
236
237 vpaq->buf_len = buffer->size;
238
239 if (buffer->size % dtl_entry_size)
240 vpaq->buf_len = buffer->size - (buffer->size % dtl_entry_size);
241
242 if (vpaq->tb_buffer != buffer->buffer_nr) {
243 vpaq->pkt_len = 0;
244 vpaq->tb_buffer = 0;
245 }
246
247 return 1;
248 }
249
250 /*
251 * The first entry in the queue for VPA DTL PMU has the boot timebase,
252 * frequency details which are needed to get timestamp which is required to
253 * correlate with other events. Save the boot_tb and tb_freq as part of
254 * powerpc_vpadtl_queue. The very next entry is the actual trace data to
255 * be returned.
256 */
powerpc_vpadtl_decode(struct powerpc_vpadtl_queue * vpaq)257 static int powerpc_vpadtl_decode(struct powerpc_vpadtl_queue *vpaq)
258 {
259 int ret;
260 char *buf;
261 struct boottb_freq *boottb;
262
263 ret = powerpc_vpadtl_get_buffer(vpaq);
264 if (ret <= 0)
265 return ret;
266
267 boottb = (struct boottb_freq *)vpaq->buffer->data;
268 if (boottb->timebase == 0) {
269 vpaq->boot_tb = boottb->boot_tb;
270 vpaq->tb_freq = boottb->tb_freq;
271 vpaq->pkt_len += dtl_entry_size;
272 }
273
274 buf = vpaq->buffer->data;
275 buf += vpaq->pkt_len;
276 vpaq->dtl = (struct powerpc_vpadtl_entry *)buf;
277
278 vpaq->tb_buffer = vpaq->buffer->buffer_nr;
279 vpaq->buffer = NULL;
280 vpaq->buf_len = 0;
281
282 return 1;
283 }
284
powerpc_vpadtl_decode_all(struct powerpc_vpadtl_queue * vpaq)285 static int powerpc_vpadtl_decode_all(struct powerpc_vpadtl_queue *vpaq)
286 {
287 int ret;
288 unsigned char *buf;
289
290 if (!vpaq->buf_len || vpaq->pkt_len == vpaq->size) {
291 ret = powerpc_vpadtl_get_buffer(vpaq);
292 if (ret <= 0)
293 return ret;
294 }
295
296 if (vpaq->buffer) {
297 buf = vpaq->buffer->data;
298 buf += vpaq->pkt_len;
299 vpaq->dtl = (struct powerpc_vpadtl_entry *)buf;
300 if ((long long)be64_to_cpu(vpaq->dtl->timebase) <= 0) {
301 if (vpaq->pkt_len != dtl_entry_size && vpaq->buf_len) {
302 vpaq->pkt_len += dtl_entry_size;
303 vpaq->buf_len -= dtl_entry_size;
304 }
305 return -1;
306 }
307 vpaq->pkt_len += dtl_entry_size;
308 vpaq->buf_len -= dtl_entry_size;
309 } else {
310 return 0;
311 }
312
313 return 1;
314 }
315
powerpc_vpadtl_run_decoder(struct powerpc_vpadtl_queue * vpaq,u64 * timestamp)316 static int powerpc_vpadtl_run_decoder(struct powerpc_vpadtl_queue *vpaq, u64 *timestamp)
317 {
318 struct powerpc_vpadtl *vpa = vpaq->vpa;
319 struct powerpc_vpadtl_entry *record;
320 int ret;
321 unsigned long long vpaq_timestamp;
322
323 while (1) {
324 ret = powerpc_vpadtl_decode_all(vpaq);
325 if (!ret) {
326 pr_debug("All data in the queue has been processed.\n");
327 return 1;
328 }
329
330 /*
331 * Error is detected when decoding VPA PMU trace. Continue to
332 * the next trace data and find out more dtl entries.
333 */
334 if (ret < 0)
335 continue;
336
337 record = vpaq->dtl;
338
339 vpaq_timestamp = powerpc_vpadtl_timestamp(vpaq);
340
341 /* Update timestamp for the last record */
342 if (vpaq_timestamp > vpaq->timestamp)
343 vpaq->timestamp = vpaq_timestamp;
344
345 /*
346 * If the timestamp of the queue is later than timestamp of the
347 * coming perf event, bail out so can allow the perf event to
348 * be processed ahead.
349 */
350 if (vpaq->timestamp >= *timestamp) {
351 *timestamp = vpaq->timestamp;
352 vpaq->pkt_len -= dtl_entry_size;
353 vpaq->buf_len += dtl_entry_size;
354 return 0;
355 }
356
357 ret = powerpc_vpadtl_sample(record, vpa, vpaq_timestamp, vpaq->cpu);
358 if (ret)
359 continue;
360 }
361 return 0;
362 }
363
364 /*
365 * For each of the PERF_RECORD_XX record, compare the timestamp
366 * of perf record with timestamp of top element in the auxtrace heap.
367 * Process the auxtrace queue if the timestamp of element from heap is
368 * lower than timestamp from entry in perf record.
369 *
370 * Update the timestamp of the auxtrace heap with the timestamp
371 * of last processed entry from the auxtrace buffer.
372 */
powerpc_vpadtl_process_queues(struct powerpc_vpadtl * vpa,u64 timestamp)373 static int powerpc_vpadtl_process_queues(struct powerpc_vpadtl *vpa, u64 timestamp)
374 {
375 unsigned int queue_nr;
376 u64 ts;
377 int ret;
378
379 while (1) {
380 struct auxtrace_queue *queue;
381 struct powerpc_vpadtl_queue *vpaq;
382
383 if (!vpa->heap.heap_cnt)
384 return 0;
385
386 if (vpa->heap.heap_array[0].ordinal >= timestamp)
387 return 0;
388
389 queue_nr = vpa->heap.heap_array[0].queue_nr;
390 queue = &vpa->queues.queue_array[queue_nr];
391 vpaq = queue->priv;
392
393 auxtrace_heap__pop(&vpa->heap);
394
395 if (vpa->heap.heap_cnt) {
396 ts = vpa->heap.heap_array[0].ordinal + 1;
397 if (ts > timestamp)
398 ts = timestamp;
399 } else {
400 ts = timestamp;
401 }
402
403 ret = powerpc_vpadtl_run_decoder(vpaq, &ts);
404 if (ret < 0) {
405 auxtrace_heap__add(&vpa->heap, queue_nr, ts);
406 return ret;
407 }
408
409 if (!ret) {
410 ret = auxtrace_heap__add(&vpa->heap, queue_nr, ts);
411 if (ret < 0)
412 return ret;
413 } else {
414 vpaq->on_heap = false;
415 }
416 }
417 return 0;
418 }
419
powerpc_vpadtl__alloc_queue(struct powerpc_vpadtl * vpa,unsigned int queue_nr)420 static struct powerpc_vpadtl_queue *powerpc_vpadtl__alloc_queue(struct powerpc_vpadtl *vpa,
421 unsigned int queue_nr)
422 {
423 struct powerpc_vpadtl_queue *vpaq;
424
425 vpaq = zalloc(sizeof(*vpaq));
426 if (!vpaq)
427 return NULL;
428
429 vpaq->vpa = vpa;
430 vpaq->queue_nr = queue_nr;
431
432 return vpaq;
433 }
434
435 /*
436 * When the Dispatch Trace Log data is collected along with other events
437 * like sched tracepoint events, it needs to be correlated and present
438 * interleaved along with these events. Perf events can be collected
439 * parallely across the CPUs.
440 *
441 * An auxtrace_queue is created for each CPU. Data within each queue is in
442 * increasing order of timestamp. Allocate and setup auxtrace queues here.
443 * All auxtrace queues is maintained in auxtrace heap in the increasing order
444 * of timestamp. So always the lowest timestamp (entries to be processed first)
445 * is on top of the heap.
446 *
447 * To add to auxtrace heap, fetch the timestamp from first DTL entry
448 * for each of the queue.
449 */
powerpc_vpadtl__setup_queue(struct powerpc_vpadtl * vpa,struct auxtrace_queue * queue,unsigned int queue_nr)450 static int powerpc_vpadtl__setup_queue(struct powerpc_vpadtl *vpa,
451 struct auxtrace_queue *queue,
452 unsigned int queue_nr)
453 {
454 struct powerpc_vpadtl_queue *vpaq = queue->priv;
455
456 if (list_empty(&queue->head) || vpaq)
457 return 0;
458
459 vpaq = powerpc_vpadtl__alloc_queue(vpa, queue_nr);
460 if (!vpaq)
461 return -ENOMEM;
462
463 queue->priv = vpaq;
464
465 if (queue->cpu != -1)
466 vpaq->cpu = queue->cpu;
467
468 if (!vpaq->on_heap) {
469 int ret;
470 retry:
471 ret = powerpc_vpadtl_decode(vpaq);
472 if (!ret)
473 return 0;
474
475 if (ret < 0)
476 goto retry;
477
478 vpaq->timestamp = powerpc_vpadtl_timestamp(vpaq);
479
480 ret = auxtrace_heap__add(&vpa->heap, queue_nr, vpaq->timestamp);
481 if (ret)
482 return ret;
483 vpaq->on_heap = true;
484 }
485
486 return 0;
487 }
488
powerpc_vpadtl__setup_queues(struct powerpc_vpadtl * vpa)489 static int powerpc_vpadtl__setup_queues(struct powerpc_vpadtl *vpa)
490 {
491 unsigned int i;
492 int ret;
493
494 for (i = 0; i < vpa->queues.nr_queues; i++) {
495 ret = powerpc_vpadtl__setup_queue(vpa, &vpa->queues.queue_array[i], i);
496 if (ret)
497 return ret;
498 }
499
500 return 0;
501 }
502
powerpc_vpadtl__update_queues(struct powerpc_vpadtl * vpa)503 static int powerpc_vpadtl__update_queues(struct powerpc_vpadtl *vpa)
504 {
505 if (vpa->queues.new_data) {
506 vpa->queues.new_data = false;
507 return powerpc_vpadtl__setup_queues(vpa);
508 }
509
510 return 0;
511 }
512
powerpc_vpadtl_process_event(struct perf_session * session,union perf_event * event __maybe_unused,struct perf_sample * sample,const struct perf_tool * tool)513 static int powerpc_vpadtl_process_event(struct perf_session *session,
514 union perf_event *event __maybe_unused,
515 struct perf_sample *sample,
516 const struct perf_tool *tool)
517 {
518 struct powerpc_vpadtl *vpa = session_to_vpa(session);
519 int err = 0;
520
521 if (dump_trace)
522 return 0;
523
524 if (!tool->ordered_events) {
525 pr_err("VPA requires ordered events\n");
526 return -EINVAL;
527 }
528
529 if (sample->time) {
530 err = powerpc_vpadtl__update_queues(vpa);
531 if (err)
532 return err;
533
534 err = powerpc_vpadtl_process_queues(vpa, sample->time);
535 }
536
537 return err;
538 }
539
540 /*
541 * Process PERF_RECORD_AUXTRACE records
542 */
powerpc_vpadtl_process_auxtrace_event(struct perf_session * session,union perf_event * event,const struct perf_tool * tool __maybe_unused)543 static int powerpc_vpadtl_process_auxtrace_event(struct perf_session *session,
544 union perf_event *event,
545 const struct perf_tool *tool __maybe_unused)
546 {
547 struct powerpc_vpadtl *vpa = session_to_vpa(session);
548 struct auxtrace_buffer *buffer;
549 int fd = perf_data__fd(session->data);
550 off_t data_offset;
551 int err;
552
553 if (!dump_trace)
554 return 0;
555
556 if (perf_data__is_pipe(session->data)) {
557 data_offset = 0;
558 } else {
559 data_offset = lseek(fd, 0, SEEK_CUR);
560 if (data_offset == -1)
561 return -errno;
562 }
563
564 err = auxtrace_queues__add_event(&vpa->queues, session, event,
565 data_offset, &buffer);
566
567 if (err)
568 return err;
569
570 /* Dump here now we have copied a piped trace out of the pipe */
571 if (auxtrace_buffer__get_data(buffer, fd)) {
572 powerpc_vpadtl_dump_event(vpa, buffer->data, buffer->size);
573 auxtrace_buffer__put_data(buffer);
574 }
575
576 return 0;
577 }
578
powerpc_vpadtl_flush(struct perf_session * session __maybe_unused,const struct perf_tool * tool __maybe_unused)579 static int powerpc_vpadtl_flush(struct perf_session *session __maybe_unused,
580 const struct perf_tool *tool __maybe_unused)
581 {
582 return 0;
583 }
584
powerpc_vpadtl_free_events(struct perf_session * session)585 static void powerpc_vpadtl_free_events(struct perf_session *session)
586 {
587 struct powerpc_vpadtl *vpa = session_to_vpa(session);
588 struct auxtrace_queues *queues = &vpa->queues;
589
590 for (unsigned int i = 0; i < queues->nr_queues; i++)
591 zfree(&queues->queue_array[i].priv);
592
593 auxtrace_queues__free(queues);
594 }
595
powerpc_vpadtl_free(struct perf_session * session)596 static void powerpc_vpadtl_free(struct perf_session *session)
597 {
598 struct powerpc_vpadtl *vpa = session_to_vpa(session);
599
600 auxtrace_heap__free(&vpa->heap);
601 powerpc_vpadtl_free_events(session);
602 session->auxtrace = NULL;
603 free(vpa);
604 }
605
606 static const char * const powerpc_vpadtl_info_fmts[] = {
607 [POWERPC_VPADTL_TYPE] = " PMU Type %"PRId64"\n",
608 };
609
powerpc_vpadtl_print_info(__u64 * arr)610 static void powerpc_vpadtl_print_info(__u64 *arr)
611 {
612 if (!dump_trace)
613 return;
614
615 fprintf(stdout, powerpc_vpadtl_info_fmts[POWERPC_VPADTL_TYPE], arr[POWERPC_VPADTL_TYPE]);
616 }
617
set_event_name(struct evlist * evlist,u64 id,const char * name)618 static void set_event_name(struct evlist *evlist, u64 id,
619 const char *name)
620 {
621 struct evsel *evsel;
622
623 evlist__for_each_entry(evlist, evsel) {
624 if (evsel->core.id && evsel->core.id[0] == id) {
625 if (evsel->name)
626 zfree(&evsel->name);
627 evsel->name = strdup(name);
628 break;
629 }
630 }
631 }
632
633 static int
powerpc_vpadtl_synth_events(struct powerpc_vpadtl * vpa,struct perf_session * session)634 powerpc_vpadtl_synth_events(struct powerpc_vpadtl *vpa, struct perf_session *session)
635 {
636 struct evlist *evlist = session->evlist;
637 struct evsel *evsel;
638 struct perf_event_attr attr;
639 bool found = false;
640 u64 id;
641 int err;
642
643 evlist__for_each_entry(evlist, evsel) {
644 if (strstarts(evsel->name, "vpa_dtl")) {
645 found = true;
646 break;
647 }
648 }
649
650 if (!found) {
651 pr_debug("No selected events with VPA trace data\n");
652 return 0;
653 }
654
655 memset(&attr, 0, sizeof(struct perf_event_attr));
656 attr.size = sizeof(struct perf_event_attr);
657 attr.sample_type = evsel->core.attr.sample_type;
658 attr.sample_id_all = evsel->core.attr.sample_id_all;
659 attr.type = PERF_TYPE_SYNTH;
660 attr.config = PERF_SYNTH_POWERPC_VPA_DTL;
661
662 /* create new id val to be a fixed offset from evsel id */
663 id = auxtrace_synth_id_range_start(evsel);
664
665 err = perf_session__deliver_synth_attr_event(session, &attr, id);
666 if (err)
667 return err;
668
669 vpa->sample_id = id;
670 set_event_name(evlist, id, "vpa-dtl");
671
672 return 0;
673 }
674
675 /*
676 * Process the PERF_RECORD_AUXTRACE_INFO records and setup
677 * the infrastructure to process auxtrace events. PERF_RECORD_AUXTRACE_INFO
678 * is processed first since it is of type perf_user_event_type.
679 * Initialise the aux buffer queues using auxtrace_queues__init().
680 * auxtrace_queue is created for each CPU.
681 */
powerpc_vpadtl_process_auxtrace_info(union perf_event * event,struct perf_session * session)682 int powerpc_vpadtl_process_auxtrace_info(union perf_event *event,
683 struct perf_session *session)
684 {
685 struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
686 size_t min_sz = sizeof(u64) * POWERPC_VPADTL_TYPE;
687 struct powerpc_vpadtl *vpa;
688 int err;
689
690 if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) +
691 min_sz)
692 return -EINVAL;
693
694 vpa = zalloc(sizeof(struct powerpc_vpadtl));
695 if (!vpa)
696 return -ENOMEM;
697
698 err = auxtrace_queues__init(&vpa->queues);
699 if (err)
700 goto err_free;
701
702 vpa->session = session;
703 vpa->machine = &session->machines.host; /* No kvm support */
704 vpa->auxtrace_type = auxtrace_info->type;
705 vpa->pmu_type = auxtrace_info->priv[POWERPC_VPADTL_TYPE];
706
707 vpa->auxtrace.process_event = powerpc_vpadtl_process_event;
708 vpa->auxtrace.process_auxtrace_event = powerpc_vpadtl_process_auxtrace_event;
709 vpa->auxtrace.flush_events = powerpc_vpadtl_flush;
710 vpa->auxtrace.free_events = powerpc_vpadtl_free_events;
711 vpa->auxtrace.free = powerpc_vpadtl_free;
712 session->auxtrace = &vpa->auxtrace;
713
714 powerpc_vpadtl_print_info(&auxtrace_info->priv[0]);
715
716 if (dump_trace)
717 return 0;
718
719 err = powerpc_vpadtl_synth_events(vpa, session);
720 if (err)
721 goto err_free_queues;
722
723 err = auxtrace_queues__process_index(&vpa->queues, session);
724 if (err)
725 goto err_free_queues;
726
727 return 0;
728
729 err_free_queues:
730 auxtrace_queues__free(&vpa->queues);
731 session->auxtrace = NULL;
732
733 err_free:
734 free(vpa);
735 return err;
736 }
737