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