162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * intel-bts.c: Intel Processor Trace support
462306a36Sopenharmony_ci * Copyright (c) 2013-2015, Intel Corporation.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <endian.h>
862306a36Sopenharmony_ci#include <errno.h>
962306a36Sopenharmony_ci#include <byteswap.h>
1062306a36Sopenharmony_ci#include <inttypes.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/types.h>
1362306a36Sopenharmony_ci#include <linux/bitops.h>
1462306a36Sopenharmony_ci#include <linux/log2.h>
1562306a36Sopenharmony_ci#include <linux/zalloc.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "color.h"
1862306a36Sopenharmony_ci#include "evsel.h"
1962306a36Sopenharmony_ci#include "evlist.h"
2062306a36Sopenharmony_ci#include "machine.h"
2162306a36Sopenharmony_ci#include "symbol.h"
2262306a36Sopenharmony_ci#include "session.h"
2362306a36Sopenharmony_ci#include "tool.h"
2462306a36Sopenharmony_ci#include "thread.h"
2562306a36Sopenharmony_ci#include "thread-stack.h"
2662306a36Sopenharmony_ci#include "debug.h"
2762306a36Sopenharmony_ci#include "tsc.h"
2862306a36Sopenharmony_ci#include "auxtrace.h"
2962306a36Sopenharmony_ci#include "intel-pt-decoder/intel-pt-insn-decoder.h"
3062306a36Sopenharmony_ci#include "intel-bts.h"
3162306a36Sopenharmony_ci#include "util/synthetic-events.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define MAX_TIMESTAMP (~0ULL)
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define INTEL_BTS_ERR_NOINSN  5
3662306a36Sopenharmony_ci#define INTEL_BTS_ERR_LOST    9
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
3962306a36Sopenharmony_ci#define le64_to_cpu bswap_64
4062306a36Sopenharmony_ci#else
4162306a36Sopenharmony_ci#define le64_to_cpu
4262306a36Sopenharmony_ci#endif
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistruct intel_bts {
4562306a36Sopenharmony_ci	struct auxtrace			auxtrace;
4662306a36Sopenharmony_ci	struct auxtrace_queues		queues;
4762306a36Sopenharmony_ci	struct auxtrace_heap		heap;
4862306a36Sopenharmony_ci	u32				auxtrace_type;
4962306a36Sopenharmony_ci	struct perf_session		*session;
5062306a36Sopenharmony_ci	struct machine			*machine;
5162306a36Sopenharmony_ci	bool				sampling_mode;
5262306a36Sopenharmony_ci	bool				snapshot_mode;
5362306a36Sopenharmony_ci	bool				data_queued;
5462306a36Sopenharmony_ci	u32				pmu_type;
5562306a36Sopenharmony_ci	struct perf_tsc_conversion	tc;
5662306a36Sopenharmony_ci	bool				cap_user_time_zero;
5762306a36Sopenharmony_ci	struct itrace_synth_opts	synth_opts;
5862306a36Sopenharmony_ci	bool				sample_branches;
5962306a36Sopenharmony_ci	u32				branches_filter;
6062306a36Sopenharmony_ci	u64				branches_sample_type;
6162306a36Sopenharmony_ci	u64				branches_id;
6262306a36Sopenharmony_ci	size_t				branches_event_size;
6362306a36Sopenharmony_ci	unsigned long			num_events;
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistruct intel_bts_queue {
6762306a36Sopenharmony_ci	struct intel_bts	*bts;
6862306a36Sopenharmony_ci	unsigned int		queue_nr;
6962306a36Sopenharmony_ci	struct auxtrace_buffer	*buffer;
7062306a36Sopenharmony_ci	bool			on_heap;
7162306a36Sopenharmony_ci	bool			done;
7262306a36Sopenharmony_ci	pid_t			pid;
7362306a36Sopenharmony_ci	pid_t			tid;
7462306a36Sopenharmony_ci	int			cpu;
7562306a36Sopenharmony_ci	u64			time;
7662306a36Sopenharmony_ci	struct intel_pt_insn	intel_pt_insn;
7762306a36Sopenharmony_ci	u32			sample_flags;
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistruct branch {
8162306a36Sopenharmony_ci	u64 from;
8262306a36Sopenharmony_ci	u64 to;
8362306a36Sopenharmony_ci	u64 misc;
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic void intel_bts_dump(struct intel_bts *bts __maybe_unused,
8762306a36Sopenharmony_ci			   unsigned char *buf, size_t len)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	struct branch *branch;
9062306a36Sopenharmony_ci	size_t i, pos = 0, br_sz = sizeof(struct branch), sz;
9162306a36Sopenharmony_ci	const char *color = PERF_COLOR_BLUE;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	color_fprintf(stdout, color,
9462306a36Sopenharmony_ci		      ". ... Intel BTS data: size %zu bytes\n",
9562306a36Sopenharmony_ci		      len);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	while (len) {
9862306a36Sopenharmony_ci		if (len >= br_sz)
9962306a36Sopenharmony_ci			sz = br_sz;
10062306a36Sopenharmony_ci		else
10162306a36Sopenharmony_ci			sz = len;
10262306a36Sopenharmony_ci		printf(".");
10362306a36Sopenharmony_ci		color_fprintf(stdout, color, "  %08x: ", pos);
10462306a36Sopenharmony_ci		for (i = 0; i < sz; i++)
10562306a36Sopenharmony_ci			color_fprintf(stdout, color, " %02x", buf[i]);
10662306a36Sopenharmony_ci		for (; i < br_sz; i++)
10762306a36Sopenharmony_ci			color_fprintf(stdout, color, "   ");
10862306a36Sopenharmony_ci		if (len >= br_sz) {
10962306a36Sopenharmony_ci			branch = (struct branch *)buf;
11062306a36Sopenharmony_ci			color_fprintf(stdout, color, " %"PRIx64" -> %"PRIx64" %s\n",
11162306a36Sopenharmony_ci				      le64_to_cpu(branch->from),
11262306a36Sopenharmony_ci				      le64_to_cpu(branch->to),
11362306a36Sopenharmony_ci				      le64_to_cpu(branch->misc) & 0x10 ?
11462306a36Sopenharmony_ci							"pred" : "miss");
11562306a36Sopenharmony_ci		} else {
11662306a36Sopenharmony_ci			color_fprintf(stdout, color, " Bad record!\n");
11762306a36Sopenharmony_ci		}
11862306a36Sopenharmony_ci		pos += sz;
11962306a36Sopenharmony_ci		buf += sz;
12062306a36Sopenharmony_ci		len -= sz;
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic void intel_bts_dump_event(struct intel_bts *bts, unsigned char *buf,
12562306a36Sopenharmony_ci				 size_t len)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	printf(".\n");
12862306a36Sopenharmony_ci	intel_bts_dump(bts, buf, len);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic int intel_bts_lost(struct intel_bts *bts, struct perf_sample *sample)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	union perf_event event;
13462306a36Sopenharmony_ci	int err;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE,
13762306a36Sopenharmony_ci			     INTEL_BTS_ERR_LOST, sample->cpu, sample->pid,
13862306a36Sopenharmony_ci			     sample->tid, 0, "Lost trace data", sample->time);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	err = perf_session__deliver_synth_event(bts->session, &event, NULL);
14162306a36Sopenharmony_ci	if (err)
14262306a36Sopenharmony_ci		pr_err("Intel BTS: failed to deliver error event, error %d\n",
14362306a36Sopenharmony_ci		       err);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return err;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic struct intel_bts_queue *intel_bts_alloc_queue(struct intel_bts *bts,
14962306a36Sopenharmony_ci						     unsigned int queue_nr)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct intel_bts_queue *btsq;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	btsq = zalloc(sizeof(struct intel_bts_queue));
15462306a36Sopenharmony_ci	if (!btsq)
15562306a36Sopenharmony_ci		return NULL;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	btsq->bts = bts;
15862306a36Sopenharmony_ci	btsq->queue_nr = queue_nr;
15962306a36Sopenharmony_ci	btsq->pid = -1;
16062306a36Sopenharmony_ci	btsq->tid = -1;
16162306a36Sopenharmony_ci	btsq->cpu = -1;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	return btsq;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic int intel_bts_setup_queue(struct intel_bts *bts,
16762306a36Sopenharmony_ci				 struct auxtrace_queue *queue,
16862306a36Sopenharmony_ci				 unsigned int queue_nr)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct intel_bts_queue *btsq = queue->priv;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (list_empty(&queue->head))
17362306a36Sopenharmony_ci		return 0;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (!btsq) {
17662306a36Sopenharmony_ci		btsq = intel_bts_alloc_queue(bts, queue_nr);
17762306a36Sopenharmony_ci		if (!btsq)
17862306a36Sopenharmony_ci			return -ENOMEM;
17962306a36Sopenharmony_ci		queue->priv = btsq;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci		if (queue->cpu != -1)
18262306a36Sopenharmony_ci			btsq->cpu = queue->cpu;
18362306a36Sopenharmony_ci		btsq->tid = queue->tid;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (bts->sampling_mode)
18762306a36Sopenharmony_ci		return 0;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if (!btsq->on_heap && !btsq->buffer) {
19062306a36Sopenharmony_ci		int ret;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		btsq->buffer = auxtrace_buffer__next(queue, NULL);
19362306a36Sopenharmony_ci		if (!btsq->buffer)
19462306a36Sopenharmony_ci			return 0;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		ret = auxtrace_heap__add(&bts->heap, queue_nr,
19762306a36Sopenharmony_ci					 btsq->buffer->reference);
19862306a36Sopenharmony_ci		if (ret)
19962306a36Sopenharmony_ci			return ret;
20062306a36Sopenharmony_ci		btsq->on_heap = true;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return 0;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic int intel_bts_setup_queues(struct intel_bts *bts)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	unsigned int i;
20962306a36Sopenharmony_ci	int ret;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	for (i = 0; i < bts->queues.nr_queues; i++) {
21262306a36Sopenharmony_ci		ret = intel_bts_setup_queue(bts, &bts->queues.queue_array[i],
21362306a36Sopenharmony_ci					    i);
21462306a36Sopenharmony_ci		if (ret)
21562306a36Sopenharmony_ci			return ret;
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci	return 0;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic inline int intel_bts_update_queues(struct intel_bts *bts)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	if (bts->queues.new_data) {
22362306a36Sopenharmony_ci		bts->queues.new_data = false;
22462306a36Sopenharmony_ci		return intel_bts_setup_queues(bts);
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci	return 0;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic unsigned char *intel_bts_find_overlap(unsigned char *buf_a, size_t len_a,
23062306a36Sopenharmony_ci					     unsigned char *buf_b, size_t len_b)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	size_t offs, len;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (len_a > len_b)
23562306a36Sopenharmony_ci		offs = len_a - len_b;
23662306a36Sopenharmony_ci	else
23762306a36Sopenharmony_ci		offs = 0;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	for (; offs < len_a; offs += sizeof(struct branch)) {
24062306a36Sopenharmony_ci		len = len_a - offs;
24162306a36Sopenharmony_ci		if (!memcmp(buf_a + offs, buf_b, len))
24262306a36Sopenharmony_ci			return buf_b + len;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return buf_b;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int intel_bts_do_fix_overlap(struct auxtrace_queue *queue,
24962306a36Sopenharmony_ci				    struct auxtrace_buffer *b)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct auxtrace_buffer *a;
25262306a36Sopenharmony_ci	void *start;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (b->list.prev == &queue->head)
25562306a36Sopenharmony_ci		return 0;
25662306a36Sopenharmony_ci	a = list_entry(b->list.prev, struct auxtrace_buffer, list);
25762306a36Sopenharmony_ci	start = intel_bts_find_overlap(a->data, a->size, b->data, b->size);
25862306a36Sopenharmony_ci	if (!start)
25962306a36Sopenharmony_ci		return -EINVAL;
26062306a36Sopenharmony_ci	b->use_size = b->data + b->size - start;
26162306a36Sopenharmony_ci	b->use_data = start;
26262306a36Sopenharmony_ci	return 0;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic inline u8 intel_bts_cpumode(struct intel_bts *bts, uint64_t ip)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	return machine__kernel_ip(bts->machine, ip) ?
26862306a36Sopenharmony_ci	       PERF_RECORD_MISC_KERNEL :
26962306a36Sopenharmony_ci	       PERF_RECORD_MISC_USER;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq,
27362306a36Sopenharmony_ci					 struct branch *branch)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	int ret;
27662306a36Sopenharmony_ci	struct intel_bts *bts = btsq->bts;
27762306a36Sopenharmony_ci	union perf_event event;
27862306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if (bts->synth_opts.initial_skip &&
28162306a36Sopenharmony_ci	    bts->num_events++ <= bts->synth_opts.initial_skip)
28262306a36Sopenharmony_ci		return 0;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	sample.ip = le64_to_cpu(branch->from);
28562306a36Sopenharmony_ci	sample.cpumode = intel_bts_cpumode(bts, sample.ip);
28662306a36Sopenharmony_ci	sample.pid = btsq->pid;
28762306a36Sopenharmony_ci	sample.tid = btsq->tid;
28862306a36Sopenharmony_ci	sample.addr = le64_to_cpu(branch->to);
28962306a36Sopenharmony_ci	sample.id = btsq->bts->branches_id;
29062306a36Sopenharmony_ci	sample.stream_id = btsq->bts->branches_id;
29162306a36Sopenharmony_ci	sample.period = 1;
29262306a36Sopenharmony_ci	sample.cpu = btsq->cpu;
29362306a36Sopenharmony_ci	sample.flags = btsq->sample_flags;
29462306a36Sopenharmony_ci	sample.insn_len = btsq->intel_pt_insn.length;
29562306a36Sopenharmony_ci	memcpy(sample.insn, btsq->intel_pt_insn.buf, INTEL_PT_INSN_BUF_SZ);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	event.sample.header.type = PERF_RECORD_SAMPLE;
29862306a36Sopenharmony_ci	event.sample.header.misc = sample.cpumode;
29962306a36Sopenharmony_ci	event.sample.header.size = sizeof(struct perf_event_header);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (bts->synth_opts.inject) {
30262306a36Sopenharmony_ci		event.sample.header.size = bts->branches_event_size;
30362306a36Sopenharmony_ci		ret = perf_event__synthesize_sample(&event,
30462306a36Sopenharmony_ci						    bts->branches_sample_type,
30562306a36Sopenharmony_ci						    0, &sample);
30662306a36Sopenharmony_ci		if (ret)
30762306a36Sopenharmony_ci			return ret;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	ret = perf_session__deliver_synth_event(bts->session, &event, &sample);
31162306a36Sopenharmony_ci	if (ret)
31262306a36Sopenharmony_ci		pr_err("Intel BTS: failed to deliver branch event, error %d\n",
31362306a36Sopenharmony_ci		       ret);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return ret;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct machine *machine = btsq->bts->machine;
32162306a36Sopenharmony_ci	struct thread *thread;
32262306a36Sopenharmony_ci	unsigned char buf[INTEL_PT_INSN_BUF_SZ];
32362306a36Sopenharmony_ci	ssize_t len;
32462306a36Sopenharmony_ci	bool x86_64;
32562306a36Sopenharmony_ci	int err = -1;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	thread = machine__find_thread(machine, -1, btsq->tid);
32862306a36Sopenharmony_ci	if (!thread)
32962306a36Sopenharmony_ci		return -1;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	len = thread__memcpy(thread, machine, buf, ip, INTEL_PT_INSN_BUF_SZ, &x86_64);
33262306a36Sopenharmony_ci	if (len <= 0)
33362306a36Sopenharmony_ci		goto out_put;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (intel_pt_get_insn(buf, len, x86_64, &btsq->intel_pt_insn))
33662306a36Sopenharmony_ci		goto out_put;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	err = 0;
33962306a36Sopenharmony_ciout_put:
34062306a36Sopenharmony_ci	thread__put(thread);
34162306a36Sopenharmony_ci	return err;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic int intel_bts_synth_error(struct intel_bts *bts, int cpu, pid_t pid,
34562306a36Sopenharmony_ci				 pid_t tid, u64 ip)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	union perf_event event;
34862306a36Sopenharmony_ci	int err;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE,
35162306a36Sopenharmony_ci			     INTEL_BTS_ERR_NOINSN, cpu, pid, tid, ip,
35262306a36Sopenharmony_ci			     "Failed to get instruction", 0);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	err = perf_session__deliver_synth_event(bts->session, &event, NULL);
35562306a36Sopenharmony_ci	if (err)
35662306a36Sopenharmony_ci		pr_err("Intel BTS: failed to deliver error event, error %d\n",
35762306a36Sopenharmony_ci		       err);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return err;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic int intel_bts_get_branch_type(struct intel_bts_queue *btsq,
36362306a36Sopenharmony_ci				     struct branch *branch)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	int err;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (!branch->from) {
36862306a36Sopenharmony_ci		if (branch->to)
36962306a36Sopenharmony_ci			btsq->sample_flags = PERF_IP_FLAG_BRANCH |
37062306a36Sopenharmony_ci					     PERF_IP_FLAG_TRACE_BEGIN;
37162306a36Sopenharmony_ci		else
37262306a36Sopenharmony_ci			btsq->sample_flags = 0;
37362306a36Sopenharmony_ci		btsq->intel_pt_insn.length = 0;
37462306a36Sopenharmony_ci	} else if (!branch->to) {
37562306a36Sopenharmony_ci		btsq->sample_flags = PERF_IP_FLAG_BRANCH |
37662306a36Sopenharmony_ci				     PERF_IP_FLAG_TRACE_END;
37762306a36Sopenharmony_ci		btsq->intel_pt_insn.length = 0;
37862306a36Sopenharmony_ci	} else {
37962306a36Sopenharmony_ci		err = intel_bts_get_next_insn(btsq, branch->from);
38062306a36Sopenharmony_ci		if (err) {
38162306a36Sopenharmony_ci			btsq->sample_flags = 0;
38262306a36Sopenharmony_ci			btsq->intel_pt_insn.length = 0;
38362306a36Sopenharmony_ci			if (!btsq->bts->synth_opts.errors)
38462306a36Sopenharmony_ci				return 0;
38562306a36Sopenharmony_ci			err = intel_bts_synth_error(btsq->bts, btsq->cpu,
38662306a36Sopenharmony_ci						    btsq->pid, btsq->tid,
38762306a36Sopenharmony_ci						    branch->from);
38862306a36Sopenharmony_ci			return err;
38962306a36Sopenharmony_ci		}
39062306a36Sopenharmony_ci		btsq->sample_flags = intel_pt_insn_type(btsq->intel_pt_insn.op);
39162306a36Sopenharmony_ci		/* Check for an async branch into the kernel */
39262306a36Sopenharmony_ci		if (!machine__kernel_ip(btsq->bts->machine, branch->from) &&
39362306a36Sopenharmony_ci		    machine__kernel_ip(btsq->bts->machine, branch->to) &&
39462306a36Sopenharmony_ci		    btsq->sample_flags != (PERF_IP_FLAG_BRANCH |
39562306a36Sopenharmony_ci					   PERF_IP_FLAG_CALL |
39662306a36Sopenharmony_ci					   PERF_IP_FLAG_SYSCALLRET))
39762306a36Sopenharmony_ci			btsq->sample_flags = PERF_IP_FLAG_BRANCH |
39862306a36Sopenharmony_ci					     PERF_IP_FLAG_CALL |
39962306a36Sopenharmony_ci					     PERF_IP_FLAG_ASYNC |
40062306a36Sopenharmony_ci					     PERF_IP_FLAG_INTERRUPT;
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	return 0;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic int intel_bts_process_buffer(struct intel_bts_queue *btsq,
40762306a36Sopenharmony_ci				    struct auxtrace_buffer *buffer,
40862306a36Sopenharmony_ci				    struct thread *thread)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	struct branch *branch;
41162306a36Sopenharmony_ci	size_t sz, bsz = sizeof(struct branch);
41262306a36Sopenharmony_ci	u32 filter = btsq->bts->branches_filter;
41362306a36Sopenharmony_ci	int err = 0;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (buffer->use_data) {
41662306a36Sopenharmony_ci		sz = buffer->use_size;
41762306a36Sopenharmony_ci		branch = buffer->use_data;
41862306a36Sopenharmony_ci	} else {
41962306a36Sopenharmony_ci		sz = buffer->size;
42062306a36Sopenharmony_ci		branch = buffer->data;
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (!btsq->bts->sample_branches)
42462306a36Sopenharmony_ci		return 0;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	for (; sz > bsz; branch += 1, sz -= bsz) {
42762306a36Sopenharmony_ci		if (!branch->from && !branch->to)
42862306a36Sopenharmony_ci			continue;
42962306a36Sopenharmony_ci		intel_bts_get_branch_type(btsq, branch);
43062306a36Sopenharmony_ci		if (btsq->bts->synth_opts.thread_stack)
43162306a36Sopenharmony_ci			thread_stack__event(thread, btsq->cpu, btsq->sample_flags,
43262306a36Sopenharmony_ci					    le64_to_cpu(branch->from),
43362306a36Sopenharmony_ci					    le64_to_cpu(branch->to),
43462306a36Sopenharmony_ci					    btsq->intel_pt_insn.length,
43562306a36Sopenharmony_ci					    buffer->buffer_nr + 1, true, 0, 0);
43662306a36Sopenharmony_ci		if (filter && !(filter & btsq->sample_flags))
43762306a36Sopenharmony_ci			continue;
43862306a36Sopenharmony_ci		err = intel_bts_synth_branch_sample(btsq, branch);
43962306a36Sopenharmony_ci		if (err)
44062306a36Sopenharmony_ci			break;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	return err;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic int intel_bts_process_queue(struct intel_bts_queue *btsq, u64 *timestamp)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	struct auxtrace_buffer *buffer = btsq->buffer, *old_buffer = buffer;
44862306a36Sopenharmony_ci	struct auxtrace_queue *queue;
44962306a36Sopenharmony_ci	struct thread *thread;
45062306a36Sopenharmony_ci	int err;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (btsq->done)
45362306a36Sopenharmony_ci		return 1;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (btsq->pid == -1) {
45662306a36Sopenharmony_ci		thread = machine__find_thread(btsq->bts->machine, -1,
45762306a36Sopenharmony_ci					      btsq->tid);
45862306a36Sopenharmony_ci		if (thread)
45962306a36Sopenharmony_ci			btsq->pid = thread__pid(thread);
46062306a36Sopenharmony_ci	} else {
46162306a36Sopenharmony_ci		thread = machine__findnew_thread(btsq->bts->machine, btsq->pid,
46262306a36Sopenharmony_ci						 btsq->tid);
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	queue = &btsq->bts->queues.queue_array[btsq->queue_nr];
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (!buffer)
46862306a36Sopenharmony_ci		buffer = auxtrace_buffer__next(queue, NULL);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	if (!buffer) {
47162306a36Sopenharmony_ci		if (!btsq->bts->sampling_mode)
47262306a36Sopenharmony_ci			btsq->done = 1;
47362306a36Sopenharmony_ci		err = 1;
47462306a36Sopenharmony_ci		goto out_put;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* Currently there is no support for split buffers */
47862306a36Sopenharmony_ci	if (buffer->consecutive) {
47962306a36Sopenharmony_ci		err = -EINVAL;
48062306a36Sopenharmony_ci		goto out_put;
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (!buffer->data) {
48462306a36Sopenharmony_ci		int fd = perf_data__fd(btsq->bts->session->data);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		buffer->data = auxtrace_buffer__get_data(buffer, fd);
48762306a36Sopenharmony_ci		if (!buffer->data) {
48862306a36Sopenharmony_ci			err = -ENOMEM;
48962306a36Sopenharmony_ci			goto out_put;
49062306a36Sopenharmony_ci		}
49162306a36Sopenharmony_ci	}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if (btsq->bts->snapshot_mode && !buffer->consecutive &&
49462306a36Sopenharmony_ci	    intel_bts_do_fix_overlap(queue, buffer)) {
49562306a36Sopenharmony_ci		err = -ENOMEM;
49662306a36Sopenharmony_ci		goto out_put;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if (!btsq->bts->synth_opts.callchain &&
50062306a36Sopenharmony_ci	    !btsq->bts->synth_opts.thread_stack && thread &&
50162306a36Sopenharmony_ci	    (!old_buffer || btsq->bts->sampling_mode ||
50262306a36Sopenharmony_ci	     (btsq->bts->snapshot_mode && !buffer->consecutive)))
50362306a36Sopenharmony_ci		thread_stack__set_trace_nr(thread, btsq->cpu, buffer->buffer_nr + 1);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	err = intel_bts_process_buffer(btsq, buffer, thread);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	auxtrace_buffer__drop_data(buffer);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	btsq->buffer = auxtrace_buffer__next(queue, buffer);
51062306a36Sopenharmony_ci	if (btsq->buffer) {
51162306a36Sopenharmony_ci		if (timestamp)
51262306a36Sopenharmony_ci			*timestamp = btsq->buffer->reference;
51362306a36Sopenharmony_ci	} else {
51462306a36Sopenharmony_ci		if (!btsq->bts->sampling_mode)
51562306a36Sopenharmony_ci			btsq->done = 1;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ciout_put:
51862306a36Sopenharmony_ci	thread__put(thread);
51962306a36Sopenharmony_ci	return err;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic int intel_bts_flush_queue(struct intel_bts_queue *btsq)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	u64 ts = 0;
52562306a36Sopenharmony_ci	int ret;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	while (1) {
52862306a36Sopenharmony_ci		ret = intel_bts_process_queue(btsq, &ts);
52962306a36Sopenharmony_ci		if (ret < 0)
53062306a36Sopenharmony_ci			return ret;
53162306a36Sopenharmony_ci		if (ret)
53262306a36Sopenharmony_ci			break;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci	return 0;
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic int intel_bts_process_tid_exit(struct intel_bts *bts, pid_t tid)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	struct auxtrace_queues *queues = &bts->queues;
54062306a36Sopenharmony_ci	unsigned int i;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	for (i = 0; i < queues->nr_queues; i++) {
54362306a36Sopenharmony_ci		struct auxtrace_queue *queue = &bts->queues.queue_array[i];
54462306a36Sopenharmony_ci		struct intel_bts_queue *btsq = queue->priv;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		if (btsq && btsq->tid == tid)
54762306a36Sopenharmony_ci			return intel_bts_flush_queue(btsq);
54862306a36Sopenharmony_ci	}
54962306a36Sopenharmony_ci	return 0;
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic int intel_bts_process_queues(struct intel_bts *bts, u64 timestamp)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	while (1) {
55562306a36Sopenharmony_ci		unsigned int queue_nr;
55662306a36Sopenharmony_ci		struct auxtrace_queue *queue;
55762306a36Sopenharmony_ci		struct intel_bts_queue *btsq;
55862306a36Sopenharmony_ci		u64 ts = 0;
55962306a36Sopenharmony_ci		int ret;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci		if (!bts->heap.heap_cnt)
56262306a36Sopenharmony_ci			return 0;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci		if (bts->heap.heap_array[0].ordinal > timestamp)
56562306a36Sopenharmony_ci			return 0;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci		queue_nr = bts->heap.heap_array[0].queue_nr;
56862306a36Sopenharmony_ci		queue = &bts->queues.queue_array[queue_nr];
56962306a36Sopenharmony_ci		btsq = queue->priv;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		auxtrace_heap__pop(&bts->heap);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci		ret = intel_bts_process_queue(btsq, &ts);
57462306a36Sopenharmony_ci		if (ret < 0) {
57562306a36Sopenharmony_ci			auxtrace_heap__add(&bts->heap, queue_nr, ts);
57662306a36Sopenharmony_ci			return ret;
57762306a36Sopenharmony_ci		}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		if (!ret) {
58062306a36Sopenharmony_ci			ret = auxtrace_heap__add(&bts->heap, queue_nr, ts);
58162306a36Sopenharmony_ci			if (ret < 0)
58262306a36Sopenharmony_ci				return ret;
58362306a36Sopenharmony_ci		} else {
58462306a36Sopenharmony_ci			btsq->on_heap = false;
58562306a36Sopenharmony_ci		}
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	return 0;
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic int intel_bts_process_event(struct perf_session *session,
59262306a36Sopenharmony_ci				   union perf_event *event,
59362306a36Sopenharmony_ci				   struct perf_sample *sample,
59462306a36Sopenharmony_ci				   struct perf_tool *tool)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
59762306a36Sopenharmony_ci					     auxtrace);
59862306a36Sopenharmony_ci	u64 timestamp;
59962306a36Sopenharmony_ci	int err;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if (dump_trace)
60262306a36Sopenharmony_ci		return 0;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (!tool->ordered_events) {
60562306a36Sopenharmony_ci		pr_err("Intel BTS requires ordered events\n");
60662306a36Sopenharmony_ci		return -EINVAL;
60762306a36Sopenharmony_ci	}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (sample->time && sample->time != (u64)-1)
61062306a36Sopenharmony_ci		timestamp = perf_time_to_tsc(sample->time, &bts->tc);
61162306a36Sopenharmony_ci	else
61262306a36Sopenharmony_ci		timestamp = 0;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	err = intel_bts_update_queues(bts);
61562306a36Sopenharmony_ci	if (err)
61662306a36Sopenharmony_ci		return err;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	err = intel_bts_process_queues(bts, timestamp);
61962306a36Sopenharmony_ci	if (err)
62062306a36Sopenharmony_ci		return err;
62162306a36Sopenharmony_ci	if (event->header.type == PERF_RECORD_EXIT) {
62262306a36Sopenharmony_ci		err = intel_bts_process_tid_exit(bts, event->fork.tid);
62362306a36Sopenharmony_ci		if (err)
62462306a36Sopenharmony_ci			return err;
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	if (event->header.type == PERF_RECORD_AUX &&
62862306a36Sopenharmony_ci	    (event->aux.flags & PERF_AUX_FLAG_TRUNCATED) &&
62962306a36Sopenharmony_ci	    bts->synth_opts.errors)
63062306a36Sopenharmony_ci		err = intel_bts_lost(bts, sample);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	return err;
63362306a36Sopenharmony_ci}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic int intel_bts_process_auxtrace_event(struct perf_session *session,
63662306a36Sopenharmony_ci					    union perf_event *event,
63762306a36Sopenharmony_ci					    struct perf_tool *tool __maybe_unused)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
64062306a36Sopenharmony_ci					     auxtrace);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (bts->sampling_mode)
64362306a36Sopenharmony_ci		return 0;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (!bts->data_queued) {
64662306a36Sopenharmony_ci		struct auxtrace_buffer *buffer;
64762306a36Sopenharmony_ci		off_t data_offset;
64862306a36Sopenharmony_ci		int fd = perf_data__fd(session->data);
64962306a36Sopenharmony_ci		int err;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		if (perf_data__is_pipe(session->data)) {
65262306a36Sopenharmony_ci			data_offset = 0;
65362306a36Sopenharmony_ci		} else {
65462306a36Sopenharmony_ci			data_offset = lseek(fd, 0, SEEK_CUR);
65562306a36Sopenharmony_ci			if (data_offset == -1)
65662306a36Sopenharmony_ci				return -errno;
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci		err = auxtrace_queues__add_event(&bts->queues, session, event,
66062306a36Sopenharmony_ci						 data_offset, &buffer);
66162306a36Sopenharmony_ci		if (err)
66262306a36Sopenharmony_ci			return err;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		/* Dump here now we have copied a piped trace out of the pipe */
66562306a36Sopenharmony_ci		if (dump_trace) {
66662306a36Sopenharmony_ci			if (auxtrace_buffer__get_data(buffer, fd)) {
66762306a36Sopenharmony_ci				intel_bts_dump_event(bts, buffer->data,
66862306a36Sopenharmony_ci						     buffer->size);
66962306a36Sopenharmony_ci				auxtrace_buffer__put_data(buffer);
67062306a36Sopenharmony_ci			}
67162306a36Sopenharmony_ci		}
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	return 0;
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic int intel_bts_flush(struct perf_session *session,
67862306a36Sopenharmony_ci			   struct perf_tool *tool __maybe_unused)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
68162306a36Sopenharmony_ci					     auxtrace);
68262306a36Sopenharmony_ci	int ret;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	if (dump_trace || bts->sampling_mode)
68562306a36Sopenharmony_ci		return 0;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	if (!tool->ordered_events)
68862306a36Sopenharmony_ci		return -EINVAL;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	ret = intel_bts_update_queues(bts);
69162306a36Sopenharmony_ci	if (ret < 0)
69262306a36Sopenharmony_ci		return ret;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	return intel_bts_process_queues(bts, MAX_TIMESTAMP);
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_cistatic void intel_bts_free_queue(void *priv)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct intel_bts_queue *btsq = priv;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	if (!btsq)
70262306a36Sopenharmony_ci		return;
70362306a36Sopenharmony_ci	free(btsq);
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic void intel_bts_free_events(struct perf_session *session)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
70962306a36Sopenharmony_ci					     auxtrace);
71062306a36Sopenharmony_ci	struct auxtrace_queues *queues = &bts->queues;
71162306a36Sopenharmony_ci	unsigned int i;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	for (i = 0; i < queues->nr_queues; i++) {
71462306a36Sopenharmony_ci		intel_bts_free_queue(queues->queue_array[i].priv);
71562306a36Sopenharmony_ci		queues->queue_array[i].priv = NULL;
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci	auxtrace_queues__free(queues);
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic void intel_bts_free(struct perf_session *session)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
72362306a36Sopenharmony_ci					     auxtrace);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	auxtrace_heap__free(&bts->heap);
72662306a36Sopenharmony_ci	intel_bts_free_events(session);
72762306a36Sopenharmony_ci	session->auxtrace = NULL;
72862306a36Sopenharmony_ci	free(bts);
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic bool intel_bts_evsel_is_auxtrace(struct perf_session *session,
73262306a36Sopenharmony_ci					struct evsel *evsel)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
73562306a36Sopenharmony_ci					     auxtrace);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	return evsel->core.attr.type == bts->pmu_type;
73862306a36Sopenharmony_ci}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_cistruct intel_bts_synth {
74162306a36Sopenharmony_ci	struct perf_tool dummy_tool;
74262306a36Sopenharmony_ci	struct perf_session *session;
74362306a36Sopenharmony_ci};
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic int intel_bts_event_synth(struct perf_tool *tool,
74662306a36Sopenharmony_ci				 union perf_event *event,
74762306a36Sopenharmony_ci				 struct perf_sample *sample __maybe_unused,
74862306a36Sopenharmony_ci				 struct machine *machine __maybe_unused)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	struct intel_bts_synth *intel_bts_synth =
75162306a36Sopenharmony_ci			container_of(tool, struct intel_bts_synth, dummy_tool);
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	return perf_session__deliver_synth_event(intel_bts_synth->session,
75462306a36Sopenharmony_ci						 event, NULL);
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cistatic int intel_bts_synth_event(struct perf_session *session,
75862306a36Sopenharmony_ci				 struct perf_event_attr *attr, u64 id)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	struct intel_bts_synth intel_bts_synth;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	memset(&intel_bts_synth, 0, sizeof(struct intel_bts_synth));
76362306a36Sopenharmony_ci	intel_bts_synth.session = session;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	return perf_event__synthesize_attr(&intel_bts_synth.dummy_tool, attr, 1,
76662306a36Sopenharmony_ci					   &id, intel_bts_event_synth);
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic int intel_bts_synth_events(struct intel_bts *bts,
77062306a36Sopenharmony_ci				  struct perf_session *session)
77162306a36Sopenharmony_ci{
77262306a36Sopenharmony_ci	struct evlist *evlist = session->evlist;
77362306a36Sopenharmony_ci	struct evsel *evsel;
77462306a36Sopenharmony_ci	struct perf_event_attr attr;
77562306a36Sopenharmony_ci	bool found = false;
77662306a36Sopenharmony_ci	u64 id;
77762306a36Sopenharmony_ci	int err;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
78062306a36Sopenharmony_ci		if (evsel->core.attr.type == bts->pmu_type && evsel->core.ids) {
78162306a36Sopenharmony_ci			found = true;
78262306a36Sopenharmony_ci			break;
78362306a36Sopenharmony_ci		}
78462306a36Sopenharmony_ci	}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	if (!found) {
78762306a36Sopenharmony_ci		pr_debug("There are no selected events with Intel BTS data\n");
78862306a36Sopenharmony_ci		return 0;
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	memset(&attr, 0, sizeof(struct perf_event_attr));
79262306a36Sopenharmony_ci	attr.size = sizeof(struct perf_event_attr);
79362306a36Sopenharmony_ci	attr.type = PERF_TYPE_HARDWARE;
79462306a36Sopenharmony_ci	attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK;
79562306a36Sopenharmony_ci	attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID |
79662306a36Sopenharmony_ci			    PERF_SAMPLE_PERIOD;
79762306a36Sopenharmony_ci	attr.sample_type &= ~(u64)PERF_SAMPLE_TIME;
79862306a36Sopenharmony_ci	attr.sample_type &= ~(u64)PERF_SAMPLE_CPU;
79962306a36Sopenharmony_ci	attr.exclude_user = evsel->core.attr.exclude_user;
80062306a36Sopenharmony_ci	attr.exclude_kernel = evsel->core.attr.exclude_kernel;
80162306a36Sopenharmony_ci	attr.exclude_hv = evsel->core.attr.exclude_hv;
80262306a36Sopenharmony_ci	attr.exclude_host = evsel->core.attr.exclude_host;
80362306a36Sopenharmony_ci	attr.exclude_guest = evsel->core.attr.exclude_guest;
80462306a36Sopenharmony_ci	attr.sample_id_all = evsel->core.attr.sample_id_all;
80562306a36Sopenharmony_ci	attr.read_format = evsel->core.attr.read_format;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	id = evsel->core.id[0] + 1000000000;
80862306a36Sopenharmony_ci	if (!id)
80962306a36Sopenharmony_ci		id = 1;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	if (bts->synth_opts.branches) {
81262306a36Sopenharmony_ci		attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
81362306a36Sopenharmony_ci		attr.sample_period = 1;
81462306a36Sopenharmony_ci		attr.sample_type |= PERF_SAMPLE_ADDR;
81562306a36Sopenharmony_ci		pr_debug("Synthesizing 'branches' event with id %" PRIu64 " sample type %#" PRIx64 "\n",
81662306a36Sopenharmony_ci			 id, (u64)attr.sample_type);
81762306a36Sopenharmony_ci		err = intel_bts_synth_event(session, &attr, id);
81862306a36Sopenharmony_ci		if (err) {
81962306a36Sopenharmony_ci			pr_err("%s: failed to synthesize 'branches' event type\n",
82062306a36Sopenharmony_ci			       __func__);
82162306a36Sopenharmony_ci			return err;
82262306a36Sopenharmony_ci		}
82362306a36Sopenharmony_ci		bts->sample_branches = true;
82462306a36Sopenharmony_ci		bts->branches_sample_type = attr.sample_type;
82562306a36Sopenharmony_ci		bts->branches_id = id;
82662306a36Sopenharmony_ci		/*
82762306a36Sopenharmony_ci		 * We only use sample types from PERF_SAMPLE_MASK so we can use
82862306a36Sopenharmony_ci		 * __evsel__sample_size() here.
82962306a36Sopenharmony_ci		 */
83062306a36Sopenharmony_ci		bts->branches_event_size = sizeof(struct perf_record_sample) +
83162306a36Sopenharmony_ci					   __evsel__sample_size(attr.sample_type);
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	return 0;
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cistatic const char * const intel_bts_info_fmts[] = {
83862306a36Sopenharmony_ci	[INTEL_BTS_PMU_TYPE]		= "  PMU Type           %"PRId64"\n",
83962306a36Sopenharmony_ci	[INTEL_BTS_TIME_SHIFT]		= "  Time Shift         %"PRIu64"\n",
84062306a36Sopenharmony_ci	[INTEL_BTS_TIME_MULT]		= "  Time Muliplier     %"PRIu64"\n",
84162306a36Sopenharmony_ci	[INTEL_BTS_TIME_ZERO]		= "  Time Zero          %"PRIu64"\n",
84262306a36Sopenharmony_ci	[INTEL_BTS_CAP_USER_TIME_ZERO]	= "  Cap Time Zero      %"PRId64"\n",
84362306a36Sopenharmony_ci	[INTEL_BTS_SNAPSHOT_MODE]	= "  Snapshot mode      %"PRId64"\n",
84462306a36Sopenharmony_ci};
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_cistatic void intel_bts_print_info(__u64 *arr, int start, int finish)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	int i;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	if (!dump_trace)
85162306a36Sopenharmony_ci		return;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	for (i = start; i <= finish; i++)
85462306a36Sopenharmony_ci		fprintf(stdout, intel_bts_info_fmts[i], arr[i]);
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ciint intel_bts_process_auxtrace_info(union perf_event *event,
85862306a36Sopenharmony_ci				    struct perf_session *session)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
86162306a36Sopenharmony_ci	size_t min_sz = sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE;
86262306a36Sopenharmony_ci	struct intel_bts *bts;
86362306a36Sopenharmony_ci	int err;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) +
86662306a36Sopenharmony_ci					min_sz)
86762306a36Sopenharmony_ci		return -EINVAL;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	bts = zalloc(sizeof(struct intel_bts));
87062306a36Sopenharmony_ci	if (!bts)
87162306a36Sopenharmony_ci		return -ENOMEM;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	err = auxtrace_queues__init(&bts->queues);
87462306a36Sopenharmony_ci	if (err)
87562306a36Sopenharmony_ci		goto err_free;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	bts->session = session;
87862306a36Sopenharmony_ci	bts->machine = &session->machines.host; /* No kvm support */
87962306a36Sopenharmony_ci	bts->auxtrace_type = auxtrace_info->type;
88062306a36Sopenharmony_ci	bts->pmu_type = auxtrace_info->priv[INTEL_BTS_PMU_TYPE];
88162306a36Sopenharmony_ci	bts->tc.time_shift = auxtrace_info->priv[INTEL_BTS_TIME_SHIFT];
88262306a36Sopenharmony_ci	bts->tc.time_mult = auxtrace_info->priv[INTEL_BTS_TIME_MULT];
88362306a36Sopenharmony_ci	bts->tc.time_zero = auxtrace_info->priv[INTEL_BTS_TIME_ZERO];
88462306a36Sopenharmony_ci	bts->cap_user_time_zero =
88562306a36Sopenharmony_ci			auxtrace_info->priv[INTEL_BTS_CAP_USER_TIME_ZERO];
88662306a36Sopenharmony_ci	bts->snapshot_mode = auxtrace_info->priv[INTEL_BTS_SNAPSHOT_MODE];
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	bts->sampling_mode = false;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	bts->auxtrace.process_event = intel_bts_process_event;
89162306a36Sopenharmony_ci	bts->auxtrace.process_auxtrace_event = intel_bts_process_auxtrace_event;
89262306a36Sopenharmony_ci	bts->auxtrace.flush_events = intel_bts_flush;
89362306a36Sopenharmony_ci	bts->auxtrace.free_events = intel_bts_free_events;
89462306a36Sopenharmony_ci	bts->auxtrace.free = intel_bts_free;
89562306a36Sopenharmony_ci	bts->auxtrace.evsel_is_auxtrace = intel_bts_evsel_is_auxtrace;
89662306a36Sopenharmony_ci	session->auxtrace = &bts->auxtrace;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	intel_bts_print_info(&auxtrace_info->priv[0], INTEL_BTS_PMU_TYPE,
89962306a36Sopenharmony_ci			     INTEL_BTS_SNAPSHOT_MODE);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (dump_trace)
90262306a36Sopenharmony_ci		return 0;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	if (session->itrace_synth_opts->set) {
90562306a36Sopenharmony_ci		bts->synth_opts = *session->itrace_synth_opts;
90662306a36Sopenharmony_ci	} else {
90762306a36Sopenharmony_ci		itrace_synth_opts__set_default(&bts->synth_opts,
90862306a36Sopenharmony_ci				session->itrace_synth_opts->default_no_sample);
90962306a36Sopenharmony_ci		bts->synth_opts.thread_stack =
91062306a36Sopenharmony_ci				session->itrace_synth_opts->thread_stack;
91162306a36Sopenharmony_ci	}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	if (bts->synth_opts.calls)
91462306a36Sopenharmony_ci		bts->branches_filter |= PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
91562306a36Sopenharmony_ci					PERF_IP_FLAG_TRACE_END;
91662306a36Sopenharmony_ci	if (bts->synth_opts.returns)
91762306a36Sopenharmony_ci		bts->branches_filter |= PERF_IP_FLAG_RETURN |
91862306a36Sopenharmony_ci					PERF_IP_FLAG_TRACE_BEGIN;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	err = intel_bts_synth_events(bts, session);
92162306a36Sopenharmony_ci	if (err)
92262306a36Sopenharmony_ci		goto err_free_queues;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	err = auxtrace_queues__process_index(&bts->queues, session);
92562306a36Sopenharmony_ci	if (err)
92662306a36Sopenharmony_ci		goto err_free_queues;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	if (bts->queues.populated)
92962306a36Sopenharmony_ci		bts->data_queued = true;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	return 0;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_cierr_free_queues:
93462306a36Sopenharmony_ci	auxtrace_queues__free(&bts->queues);
93562306a36Sopenharmony_ci	session->auxtrace = NULL;
93662306a36Sopenharmony_cierr_free:
93762306a36Sopenharmony_ci	free(bts);
93862306a36Sopenharmony_ci	return err;
93962306a36Sopenharmony_ci}
940