162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Arm Statistical Profiling Extensions (SPE) support
462306a36Sopenharmony_ci * Copyright (c) 2017-2018, Arm Ltd.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <byteswap.h>
862306a36Sopenharmony_ci#include <endian.h>
962306a36Sopenharmony_ci#include <errno.h>
1062306a36Sopenharmony_ci#include <inttypes.h>
1162306a36Sopenharmony_ci#include <linux/bitops.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/log2.h>
1462306a36Sopenharmony_ci#include <linux/types.h>
1562306a36Sopenharmony_ci#include <linux/zalloc.h>
1662306a36Sopenharmony_ci#include <stdlib.h>
1762306a36Sopenharmony_ci#include <unistd.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "auxtrace.h"
2062306a36Sopenharmony_ci#include "color.h"
2162306a36Sopenharmony_ci#include "debug.h"
2262306a36Sopenharmony_ci#include "evlist.h"
2362306a36Sopenharmony_ci#include "evsel.h"
2462306a36Sopenharmony_ci#include "machine.h"
2562306a36Sopenharmony_ci#include "session.h"
2662306a36Sopenharmony_ci#include "symbol.h"
2762306a36Sopenharmony_ci#include "thread.h"
2862306a36Sopenharmony_ci#include "thread-stack.h"
2962306a36Sopenharmony_ci#include "tsc.h"
3062306a36Sopenharmony_ci#include "tool.h"
3162306a36Sopenharmony_ci#include "util/synthetic-events.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include "arm-spe.h"
3462306a36Sopenharmony_ci#include "arm-spe-decoder/arm-spe-decoder.h"
3562306a36Sopenharmony_ci#include "arm-spe-decoder/arm-spe-pkt-decoder.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include "../../arch/arm64/include/asm/cputype.h"
3862306a36Sopenharmony_ci#define MAX_TIMESTAMP (~0ULL)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistruct arm_spe {
4162306a36Sopenharmony_ci	struct auxtrace			auxtrace;
4262306a36Sopenharmony_ci	struct auxtrace_queues		queues;
4362306a36Sopenharmony_ci	struct auxtrace_heap		heap;
4462306a36Sopenharmony_ci	struct itrace_synth_opts        synth_opts;
4562306a36Sopenharmony_ci	u32				auxtrace_type;
4662306a36Sopenharmony_ci	struct perf_session		*session;
4762306a36Sopenharmony_ci	struct machine			*machine;
4862306a36Sopenharmony_ci	u32				pmu_type;
4962306a36Sopenharmony_ci	u64				midr;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	struct perf_tsc_conversion	tc;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	u8				timeless_decoding;
5462306a36Sopenharmony_ci	u8				data_queued;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	u64				sample_type;
5762306a36Sopenharmony_ci	u8				sample_flc;
5862306a36Sopenharmony_ci	u8				sample_llc;
5962306a36Sopenharmony_ci	u8				sample_tlb;
6062306a36Sopenharmony_ci	u8				sample_branch;
6162306a36Sopenharmony_ci	u8				sample_remote_access;
6262306a36Sopenharmony_ci	u8				sample_memory;
6362306a36Sopenharmony_ci	u8				sample_instructions;
6462306a36Sopenharmony_ci	u64				instructions_sample_period;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	u64				l1d_miss_id;
6762306a36Sopenharmony_ci	u64				l1d_access_id;
6862306a36Sopenharmony_ci	u64				llc_miss_id;
6962306a36Sopenharmony_ci	u64				llc_access_id;
7062306a36Sopenharmony_ci	u64				tlb_miss_id;
7162306a36Sopenharmony_ci	u64				tlb_access_id;
7262306a36Sopenharmony_ci	u64				branch_miss_id;
7362306a36Sopenharmony_ci	u64				remote_access_id;
7462306a36Sopenharmony_ci	u64				memory_id;
7562306a36Sopenharmony_ci	u64				instructions_id;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	u64				kernel_start;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	unsigned long			num_events;
8062306a36Sopenharmony_ci	u8				use_ctx_pkt_for_pid;
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct arm_spe_queue {
8462306a36Sopenharmony_ci	struct arm_spe			*spe;
8562306a36Sopenharmony_ci	unsigned int			queue_nr;
8662306a36Sopenharmony_ci	struct auxtrace_buffer		*buffer;
8762306a36Sopenharmony_ci	struct auxtrace_buffer		*old_buffer;
8862306a36Sopenharmony_ci	union perf_event		*event_buf;
8962306a36Sopenharmony_ci	bool				on_heap;
9062306a36Sopenharmony_ci	bool				done;
9162306a36Sopenharmony_ci	pid_t				pid;
9262306a36Sopenharmony_ci	pid_t				tid;
9362306a36Sopenharmony_ci	int				cpu;
9462306a36Sopenharmony_ci	struct arm_spe_decoder		*decoder;
9562306a36Sopenharmony_ci	u64				time;
9662306a36Sopenharmony_ci	u64				timestamp;
9762306a36Sopenharmony_ci	struct thread			*thread;
9862306a36Sopenharmony_ci	u64				period_instructions;
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic void arm_spe_dump(struct arm_spe *spe __maybe_unused,
10262306a36Sopenharmony_ci			 unsigned char *buf, size_t len)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	struct arm_spe_pkt packet;
10562306a36Sopenharmony_ci	size_t pos = 0;
10662306a36Sopenharmony_ci	int ret, pkt_len, i;
10762306a36Sopenharmony_ci	char desc[ARM_SPE_PKT_DESC_MAX];
10862306a36Sopenharmony_ci	const char *color = PERF_COLOR_BLUE;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	color_fprintf(stdout, color,
11162306a36Sopenharmony_ci		      ". ... ARM SPE data: size %#zx bytes\n",
11262306a36Sopenharmony_ci		      len);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	while (len) {
11562306a36Sopenharmony_ci		ret = arm_spe_get_packet(buf, len, &packet);
11662306a36Sopenharmony_ci		if (ret > 0)
11762306a36Sopenharmony_ci			pkt_len = ret;
11862306a36Sopenharmony_ci		else
11962306a36Sopenharmony_ci			pkt_len = 1;
12062306a36Sopenharmony_ci		printf(".");
12162306a36Sopenharmony_ci		color_fprintf(stdout, color, "  %08x: ", pos);
12262306a36Sopenharmony_ci		for (i = 0; i < pkt_len; i++)
12362306a36Sopenharmony_ci			color_fprintf(stdout, color, " %02x", buf[i]);
12462306a36Sopenharmony_ci		for (; i < 16; i++)
12562306a36Sopenharmony_ci			color_fprintf(stdout, color, "   ");
12662306a36Sopenharmony_ci		if (ret > 0) {
12762306a36Sopenharmony_ci			ret = arm_spe_pkt_desc(&packet, desc,
12862306a36Sopenharmony_ci					       ARM_SPE_PKT_DESC_MAX);
12962306a36Sopenharmony_ci			if (!ret)
13062306a36Sopenharmony_ci				color_fprintf(stdout, color, " %s\n", desc);
13162306a36Sopenharmony_ci		} else {
13262306a36Sopenharmony_ci			color_fprintf(stdout, color, " Bad packet!\n");
13362306a36Sopenharmony_ci		}
13462306a36Sopenharmony_ci		pos += pkt_len;
13562306a36Sopenharmony_ci		buf += pkt_len;
13662306a36Sopenharmony_ci		len -= pkt_len;
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic void arm_spe_dump_event(struct arm_spe *spe, unsigned char *buf,
14162306a36Sopenharmony_ci			       size_t len)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	printf(".\n");
14462306a36Sopenharmony_ci	arm_spe_dump(spe, buf, len);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic int arm_spe_get_trace(struct arm_spe_buffer *b, void *data)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	struct arm_spe_queue *speq = data;
15062306a36Sopenharmony_ci	struct auxtrace_buffer *buffer = speq->buffer;
15162306a36Sopenharmony_ci	struct auxtrace_buffer *old_buffer = speq->old_buffer;
15262306a36Sopenharmony_ci	struct auxtrace_queue *queue;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	queue = &speq->spe->queues.queue_array[speq->queue_nr];
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	buffer = auxtrace_buffer__next(queue, buffer);
15762306a36Sopenharmony_ci	/* If no more data, drop the previous auxtrace_buffer and return */
15862306a36Sopenharmony_ci	if (!buffer) {
15962306a36Sopenharmony_ci		if (old_buffer)
16062306a36Sopenharmony_ci			auxtrace_buffer__drop_data(old_buffer);
16162306a36Sopenharmony_ci		b->len = 0;
16262306a36Sopenharmony_ci		return 0;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	speq->buffer = buffer;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* If the aux_buffer doesn't have data associated, try to load it */
16862306a36Sopenharmony_ci	if (!buffer->data) {
16962306a36Sopenharmony_ci		/* get the file desc associated with the perf data file */
17062306a36Sopenharmony_ci		int fd = perf_data__fd(speq->spe->session->data);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci		buffer->data = auxtrace_buffer__get_data(buffer, fd);
17362306a36Sopenharmony_ci		if (!buffer->data)
17462306a36Sopenharmony_ci			return -ENOMEM;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	b->len = buffer->size;
17862306a36Sopenharmony_ci	b->buf = buffer->data;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	if (b->len) {
18162306a36Sopenharmony_ci		if (old_buffer)
18262306a36Sopenharmony_ci			auxtrace_buffer__drop_data(old_buffer);
18362306a36Sopenharmony_ci		speq->old_buffer = buffer;
18462306a36Sopenharmony_ci	} else {
18562306a36Sopenharmony_ci		auxtrace_buffer__drop_data(buffer);
18662306a36Sopenharmony_ci		return arm_spe_get_trace(b, data);
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return 0;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic struct arm_spe_queue *arm_spe__alloc_queue(struct arm_spe *spe,
19362306a36Sopenharmony_ci		unsigned int queue_nr)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	struct arm_spe_params params = { .get_trace = 0, };
19662306a36Sopenharmony_ci	struct arm_spe_queue *speq;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	speq = zalloc(sizeof(*speq));
19962306a36Sopenharmony_ci	if (!speq)
20062306a36Sopenharmony_ci		return NULL;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	speq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE);
20362306a36Sopenharmony_ci	if (!speq->event_buf)
20462306a36Sopenharmony_ci		goto out_free;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	speq->spe = spe;
20762306a36Sopenharmony_ci	speq->queue_nr = queue_nr;
20862306a36Sopenharmony_ci	speq->pid = -1;
20962306a36Sopenharmony_ci	speq->tid = -1;
21062306a36Sopenharmony_ci	speq->cpu = -1;
21162306a36Sopenharmony_ci	speq->period_instructions = 0;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* params set */
21462306a36Sopenharmony_ci	params.get_trace = arm_spe_get_trace;
21562306a36Sopenharmony_ci	params.data = speq;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	/* create new decoder */
21862306a36Sopenharmony_ci	speq->decoder = arm_spe_decoder_new(&params);
21962306a36Sopenharmony_ci	if (!speq->decoder)
22062306a36Sopenharmony_ci		goto out_free;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	return speq;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ciout_free:
22562306a36Sopenharmony_ci	zfree(&speq->event_buf);
22662306a36Sopenharmony_ci	free(speq);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	return NULL;
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic inline u8 arm_spe_cpumode(struct arm_spe *spe, u64 ip)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	return ip >= spe->kernel_start ?
23462306a36Sopenharmony_ci		PERF_RECORD_MISC_KERNEL :
23562306a36Sopenharmony_ci		PERF_RECORD_MISC_USER;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic void arm_spe_set_pid_tid_cpu(struct arm_spe *spe,
23962306a36Sopenharmony_ci				    struct auxtrace_queue *queue)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct arm_spe_queue *speq = queue->priv;
24262306a36Sopenharmony_ci	pid_t tid;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	tid = machine__get_current_tid(spe->machine, speq->cpu);
24562306a36Sopenharmony_ci	if (tid != -1) {
24662306a36Sopenharmony_ci		speq->tid = tid;
24762306a36Sopenharmony_ci		thread__zput(speq->thread);
24862306a36Sopenharmony_ci	} else
24962306a36Sopenharmony_ci		speq->tid = queue->tid;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if ((!speq->thread) && (speq->tid != -1)) {
25262306a36Sopenharmony_ci		speq->thread = machine__find_thread(spe->machine, -1,
25362306a36Sopenharmony_ci						    speq->tid);
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (speq->thread) {
25762306a36Sopenharmony_ci		speq->pid = thread__pid(speq->thread);
25862306a36Sopenharmony_ci		if (queue->cpu == -1)
25962306a36Sopenharmony_ci			speq->cpu = thread__cpu(speq->thread);
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic int arm_spe_set_tid(struct arm_spe_queue *speq, pid_t tid)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct arm_spe *spe = speq->spe;
26662306a36Sopenharmony_ci	int err = machine__set_current_tid(spe->machine, speq->cpu, -1, tid);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (err)
26962306a36Sopenharmony_ci		return err;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	arm_spe_set_pid_tid_cpu(spe, &spe->queues.queue_array[speq->queue_nr]);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return 0;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic struct simd_flags arm_spe__synth_simd_flags(const struct arm_spe_record *record)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	struct simd_flags simd_flags = {};
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if ((record->op & ARM_SPE_OP_LDST) && (record->op & ARM_SPE_OP_SVE_LDST))
28162306a36Sopenharmony_ci		simd_flags.arch |= SIMD_OP_FLAGS_ARCH_SVE;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	if ((record->op & ARM_SPE_OP_OTHER) && (record->op & ARM_SPE_OP_SVE_OTHER))
28462306a36Sopenharmony_ci		simd_flags.arch |= SIMD_OP_FLAGS_ARCH_SVE;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	if (record->type & ARM_SPE_SVE_PARTIAL_PRED)
28762306a36Sopenharmony_ci		simd_flags.pred |= SIMD_OP_FLAGS_PRED_PARTIAL;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (record->type & ARM_SPE_SVE_EMPTY_PRED)
29062306a36Sopenharmony_ci		simd_flags.pred |= SIMD_OP_FLAGS_PRED_EMPTY;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return simd_flags;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic void arm_spe_prep_sample(struct arm_spe *spe,
29662306a36Sopenharmony_ci				struct arm_spe_queue *speq,
29762306a36Sopenharmony_ci				union perf_event *event,
29862306a36Sopenharmony_ci				struct perf_sample *sample)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct arm_spe_record *record = &speq->decoder->record;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (!spe->timeless_decoding)
30362306a36Sopenharmony_ci		sample->time = tsc_to_perf_time(record->timestamp, &spe->tc);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	sample->ip = record->from_ip;
30662306a36Sopenharmony_ci	sample->cpumode = arm_spe_cpumode(spe, sample->ip);
30762306a36Sopenharmony_ci	sample->pid = speq->pid;
30862306a36Sopenharmony_ci	sample->tid = speq->tid;
30962306a36Sopenharmony_ci	sample->period = 1;
31062306a36Sopenharmony_ci	sample->cpu = speq->cpu;
31162306a36Sopenharmony_ci	sample->simd_flags = arm_spe__synth_simd_flags(record);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	event->sample.header.type = PERF_RECORD_SAMPLE;
31462306a36Sopenharmony_ci	event->sample.header.misc = sample->cpumode;
31562306a36Sopenharmony_ci	event->sample.header.size = sizeof(struct perf_event_header);
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic int arm_spe__inject_event(union perf_event *event, struct perf_sample *sample, u64 type)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	event->header.size = perf_event__sample_event_size(sample, type, 0);
32162306a36Sopenharmony_ci	return perf_event__synthesize_sample(event, type, 0, sample);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic inline int
32562306a36Sopenharmony_ciarm_spe_deliver_synth_event(struct arm_spe *spe,
32662306a36Sopenharmony_ci			    struct arm_spe_queue *speq __maybe_unused,
32762306a36Sopenharmony_ci			    union perf_event *event,
32862306a36Sopenharmony_ci			    struct perf_sample *sample)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	int ret;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (spe->synth_opts.inject) {
33362306a36Sopenharmony_ci		ret = arm_spe__inject_event(event, sample, spe->sample_type);
33462306a36Sopenharmony_ci		if (ret)
33562306a36Sopenharmony_ci			return ret;
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	ret = perf_session__deliver_synth_event(spe->session, event, sample);
33962306a36Sopenharmony_ci	if (ret)
34062306a36Sopenharmony_ci		pr_err("ARM SPE: failed to deliver event, error %d\n", ret);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	return ret;
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic int arm_spe__synth_mem_sample(struct arm_spe_queue *speq,
34662306a36Sopenharmony_ci				     u64 spe_events_id, u64 data_src)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct arm_spe *spe = speq->spe;
34962306a36Sopenharmony_ci	struct arm_spe_record *record = &speq->decoder->record;
35062306a36Sopenharmony_ci	union perf_event *event = speq->event_buf;
35162306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	arm_spe_prep_sample(spe, speq, event, &sample);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	sample.id = spe_events_id;
35662306a36Sopenharmony_ci	sample.stream_id = spe_events_id;
35762306a36Sopenharmony_ci	sample.addr = record->virt_addr;
35862306a36Sopenharmony_ci	sample.phys_addr = record->phys_addr;
35962306a36Sopenharmony_ci	sample.data_src = data_src;
36062306a36Sopenharmony_ci	sample.weight = record->latency;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	return arm_spe_deliver_synth_event(spe, speq, event, &sample);
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic int arm_spe__synth_branch_sample(struct arm_spe_queue *speq,
36662306a36Sopenharmony_ci					u64 spe_events_id)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct arm_spe *spe = speq->spe;
36962306a36Sopenharmony_ci	struct arm_spe_record *record = &speq->decoder->record;
37062306a36Sopenharmony_ci	union perf_event *event = speq->event_buf;
37162306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	arm_spe_prep_sample(spe, speq, event, &sample);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	sample.id = spe_events_id;
37662306a36Sopenharmony_ci	sample.stream_id = spe_events_id;
37762306a36Sopenharmony_ci	sample.addr = record->to_ip;
37862306a36Sopenharmony_ci	sample.weight = record->latency;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return arm_spe_deliver_synth_event(spe, speq, event, &sample);
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic int arm_spe__synth_instruction_sample(struct arm_spe_queue *speq,
38462306a36Sopenharmony_ci					     u64 spe_events_id, u64 data_src)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct arm_spe *spe = speq->spe;
38762306a36Sopenharmony_ci	struct arm_spe_record *record = &speq->decoder->record;
38862306a36Sopenharmony_ci	union perf_event *event = speq->event_buf;
38962306a36Sopenharmony_ci	struct perf_sample sample = { .ip = 0, };
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/*
39262306a36Sopenharmony_ci	 * Handles perf instruction sampling period.
39362306a36Sopenharmony_ci	 */
39462306a36Sopenharmony_ci	speq->period_instructions++;
39562306a36Sopenharmony_ci	if (speq->period_instructions < spe->instructions_sample_period)
39662306a36Sopenharmony_ci		return 0;
39762306a36Sopenharmony_ci	speq->period_instructions = 0;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	arm_spe_prep_sample(spe, speq, event, &sample);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	sample.id = spe_events_id;
40262306a36Sopenharmony_ci	sample.stream_id = spe_events_id;
40362306a36Sopenharmony_ci	sample.addr = record->virt_addr;
40462306a36Sopenharmony_ci	sample.phys_addr = record->phys_addr;
40562306a36Sopenharmony_ci	sample.data_src = data_src;
40662306a36Sopenharmony_ci	sample.period = spe->instructions_sample_period;
40762306a36Sopenharmony_ci	sample.weight = record->latency;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	return arm_spe_deliver_synth_event(spe, speq, event, &sample);
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic const struct midr_range neoverse_spe[] = {
41362306a36Sopenharmony_ci	MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1),
41462306a36Sopenharmony_ci	MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
41562306a36Sopenharmony_ci	MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1),
41662306a36Sopenharmony_ci	{},
41762306a36Sopenharmony_ci};
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic void arm_spe__synth_data_source_neoverse(const struct arm_spe_record *record,
42062306a36Sopenharmony_ci						union perf_mem_data_src *data_src)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	/*
42362306a36Sopenharmony_ci	 * Even though four levels of cache hierarchy are possible, no known
42462306a36Sopenharmony_ci	 * production Neoverse systems currently include more than three levels
42562306a36Sopenharmony_ci	 * so for the time being we assume three exist. If a production system
42662306a36Sopenharmony_ci	 * is built with four the this function would have to be changed to
42762306a36Sopenharmony_ci	 * detect the number of levels for reporting.
42862306a36Sopenharmony_ci	 */
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	/*
43162306a36Sopenharmony_ci	 * We have no data on the hit level or data source for stores in the
43262306a36Sopenharmony_ci	 * Neoverse SPE records.
43362306a36Sopenharmony_ci	 */
43462306a36Sopenharmony_ci	if (record->op & ARM_SPE_OP_ST) {
43562306a36Sopenharmony_ci		data_src->mem_lvl = PERF_MEM_LVL_NA;
43662306a36Sopenharmony_ci		data_src->mem_lvl_num = PERF_MEM_LVLNUM_NA;
43762306a36Sopenharmony_ci		data_src->mem_snoop = PERF_MEM_SNOOP_NA;
43862306a36Sopenharmony_ci		return;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	switch (record->source) {
44262306a36Sopenharmony_ci	case ARM_SPE_NV_L1D:
44362306a36Sopenharmony_ci		data_src->mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT;
44462306a36Sopenharmony_ci		data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1;
44562306a36Sopenharmony_ci		data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
44662306a36Sopenharmony_ci		break;
44762306a36Sopenharmony_ci	case ARM_SPE_NV_L2:
44862306a36Sopenharmony_ci		data_src->mem_lvl = PERF_MEM_LVL_L2 | PERF_MEM_LVL_HIT;
44962306a36Sopenharmony_ci		data_src->mem_lvl_num = PERF_MEM_LVLNUM_L2;
45062306a36Sopenharmony_ci		data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
45162306a36Sopenharmony_ci		break;
45262306a36Sopenharmony_ci	case ARM_SPE_NV_PEER_CORE:
45362306a36Sopenharmony_ci		data_src->mem_lvl = PERF_MEM_LVL_L2 | PERF_MEM_LVL_HIT;
45462306a36Sopenharmony_ci		data_src->mem_lvl_num = PERF_MEM_LVLNUM_L2;
45562306a36Sopenharmony_ci		data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER;
45662306a36Sopenharmony_ci		break;
45762306a36Sopenharmony_ci	/*
45862306a36Sopenharmony_ci	 * We don't know if this is L1, L2 but we do know it was a cache-2-cache
45962306a36Sopenharmony_ci	 * transfer, so set SNOOPX_PEER
46062306a36Sopenharmony_ci	 */
46162306a36Sopenharmony_ci	case ARM_SPE_NV_LOCAL_CLUSTER:
46262306a36Sopenharmony_ci	case ARM_SPE_NV_PEER_CLUSTER:
46362306a36Sopenharmony_ci		data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT;
46462306a36Sopenharmony_ci		data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3;
46562306a36Sopenharmony_ci		data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER;
46662306a36Sopenharmony_ci		break;
46762306a36Sopenharmony_ci	/*
46862306a36Sopenharmony_ci	 * System cache is assumed to be L3
46962306a36Sopenharmony_ci	 */
47062306a36Sopenharmony_ci	case ARM_SPE_NV_SYS_CACHE:
47162306a36Sopenharmony_ci		data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT;
47262306a36Sopenharmony_ci		data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3;
47362306a36Sopenharmony_ci		data_src->mem_snoop = PERF_MEM_SNOOP_HIT;
47462306a36Sopenharmony_ci		break;
47562306a36Sopenharmony_ci	/*
47662306a36Sopenharmony_ci	 * We don't know what level it hit in, except it came from the other
47762306a36Sopenharmony_ci	 * socket
47862306a36Sopenharmony_ci	 */
47962306a36Sopenharmony_ci	case ARM_SPE_NV_REMOTE:
48062306a36Sopenharmony_ci		data_src->mem_lvl = PERF_MEM_LVL_REM_CCE1;
48162306a36Sopenharmony_ci		data_src->mem_lvl_num = PERF_MEM_LVLNUM_ANY_CACHE;
48262306a36Sopenharmony_ci		data_src->mem_remote = PERF_MEM_REMOTE_REMOTE;
48362306a36Sopenharmony_ci		data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER;
48462306a36Sopenharmony_ci		break;
48562306a36Sopenharmony_ci	case ARM_SPE_NV_DRAM:
48662306a36Sopenharmony_ci		data_src->mem_lvl = PERF_MEM_LVL_LOC_RAM | PERF_MEM_LVL_HIT;
48762306a36Sopenharmony_ci		data_src->mem_lvl_num = PERF_MEM_LVLNUM_RAM;
48862306a36Sopenharmony_ci		data_src->mem_snoop = PERF_MEM_SNOOP_NONE;
48962306a36Sopenharmony_ci		break;
49062306a36Sopenharmony_ci	default:
49162306a36Sopenharmony_ci		break;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic void arm_spe__synth_data_source_generic(const struct arm_spe_record *record,
49662306a36Sopenharmony_ci					       union perf_mem_data_src *data_src)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	if (record->type & (ARM_SPE_LLC_ACCESS | ARM_SPE_LLC_MISS)) {
49962306a36Sopenharmony_ci		data_src->mem_lvl = PERF_MEM_LVL_L3;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci		if (record->type & ARM_SPE_LLC_MISS)
50262306a36Sopenharmony_ci			data_src->mem_lvl |= PERF_MEM_LVL_MISS;
50362306a36Sopenharmony_ci		else
50462306a36Sopenharmony_ci			data_src->mem_lvl |= PERF_MEM_LVL_HIT;
50562306a36Sopenharmony_ci	} else if (record->type & (ARM_SPE_L1D_ACCESS | ARM_SPE_L1D_MISS)) {
50662306a36Sopenharmony_ci		data_src->mem_lvl = PERF_MEM_LVL_L1;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci		if (record->type & ARM_SPE_L1D_MISS)
50962306a36Sopenharmony_ci			data_src->mem_lvl |= PERF_MEM_LVL_MISS;
51062306a36Sopenharmony_ci		else
51162306a36Sopenharmony_ci			data_src->mem_lvl |= PERF_MEM_LVL_HIT;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (record->type & ARM_SPE_REMOTE_ACCESS)
51562306a36Sopenharmony_ci		data_src->mem_lvl |= PERF_MEM_LVL_REM_CCE1;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic u64 arm_spe__synth_data_source(const struct arm_spe_record *record, u64 midr)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	union perf_mem_data_src	data_src = { .mem_op = PERF_MEM_OP_NA };
52162306a36Sopenharmony_ci	bool is_neoverse = is_midr_in_range_list(midr, neoverse_spe);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	if (record->op & ARM_SPE_OP_LD)
52462306a36Sopenharmony_ci		data_src.mem_op = PERF_MEM_OP_LOAD;
52562306a36Sopenharmony_ci	else if (record->op & ARM_SPE_OP_ST)
52662306a36Sopenharmony_ci		data_src.mem_op = PERF_MEM_OP_STORE;
52762306a36Sopenharmony_ci	else
52862306a36Sopenharmony_ci		return 0;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (is_neoverse)
53162306a36Sopenharmony_ci		arm_spe__synth_data_source_neoverse(record, &data_src);
53262306a36Sopenharmony_ci	else
53362306a36Sopenharmony_ci		arm_spe__synth_data_source_generic(record, &data_src);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (record->type & (ARM_SPE_TLB_ACCESS | ARM_SPE_TLB_MISS)) {
53662306a36Sopenharmony_ci		data_src.mem_dtlb = PERF_MEM_TLB_WK;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci		if (record->type & ARM_SPE_TLB_MISS)
53962306a36Sopenharmony_ci			data_src.mem_dtlb |= PERF_MEM_TLB_MISS;
54062306a36Sopenharmony_ci		else
54162306a36Sopenharmony_ci			data_src.mem_dtlb |= PERF_MEM_TLB_HIT;
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	return data_src.val;
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_cistatic int arm_spe_sample(struct arm_spe_queue *speq)
54862306a36Sopenharmony_ci{
54962306a36Sopenharmony_ci	const struct arm_spe_record *record = &speq->decoder->record;
55062306a36Sopenharmony_ci	struct arm_spe *spe = speq->spe;
55162306a36Sopenharmony_ci	u64 data_src;
55262306a36Sopenharmony_ci	int err;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	data_src = arm_spe__synth_data_source(record, spe->midr);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	if (spe->sample_flc) {
55762306a36Sopenharmony_ci		if (record->type & ARM_SPE_L1D_MISS) {
55862306a36Sopenharmony_ci			err = arm_spe__synth_mem_sample(speq, spe->l1d_miss_id,
55962306a36Sopenharmony_ci							data_src);
56062306a36Sopenharmony_ci			if (err)
56162306a36Sopenharmony_ci				return err;
56262306a36Sopenharmony_ci		}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci		if (record->type & ARM_SPE_L1D_ACCESS) {
56562306a36Sopenharmony_ci			err = arm_spe__synth_mem_sample(speq, spe->l1d_access_id,
56662306a36Sopenharmony_ci							data_src);
56762306a36Sopenharmony_ci			if (err)
56862306a36Sopenharmony_ci				return err;
56962306a36Sopenharmony_ci		}
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	if (spe->sample_llc) {
57362306a36Sopenharmony_ci		if (record->type & ARM_SPE_LLC_MISS) {
57462306a36Sopenharmony_ci			err = arm_spe__synth_mem_sample(speq, spe->llc_miss_id,
57562306a36Sopenharmony_ci							data_src);
57662306a36Sopenharmony_ci			if (err)
57762306a36Sopenharmony_ci				return err;
57862306a36Sopenharmony_ci		}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci		if (record->type & ARM_SPE_LLC_ACCESS) {
58162306a36Sopenharmony_ci			err = arm_spe__synth_mem_sample(speq, spe->llc_access_id,
58262306a36Sopenharmony_ci							data_src);
58362306a36Sopenharmony_ci			if (err)
58462306a36Sopenharmony_ci				return err;
58562306a36Sopenharmony_ci		}
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (spe->sample_tlb) {
58962306a36Sopenharmony_ci		if (record->type & ARM_SPE_TLB_MISS) {
59062306a36Sopenharmony_ci			err = arm_spe__synth_mem_sample(speq, spe->tlb_miss_id,
59162306a36Sopenharmony_ci							data_src);
59262306a36Sopenharmony_ci			if (err)
59362306a36Sopenharmony_ci				return err;
59462306a36Sopenharmony_ci		}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		if (record->type & ARM_SPE_TLB_ACCESS) {
59762306a36Sopenharmony_ci			err = arm_spe__synth_mem_sample(speq, spe->tlb_access_id,
59862306a36Sopenharmony_ci							data_src);
59962306a36Sopenharmony_ci			if (err)
60062306a36Sopenharmony_ci				return err;
60162306a36Sopenharmony_ci		}
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (spe->sample_branch && (record->type & ARM_SPE_BRANCH_MISS)) {
60562306a36Sopenharmony_ci		err = arm_spe__synth_branch_sample(speq, spe->branch_miss_id);
60662306a36Sopenharmony_ci		if (err)
60762306a36Sopenharmony_ci			return err;
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	if (spe->sample_remote_access &&
61162306a36Sopenharmony_ci	    (record->type & ARM_SPE_REMOTE_ACCESS)) {
61262306a36Sopenharmony_ci		err = arm_spe__synth_mem_sample(speq, spe->remote_access_id,
61362306a36Sopenharmony_ci						data_src);
61462306a36Sopenharmony_ci		if (err)
61562306a36Sopenharmony_ci			return err;
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/*
61962306a36Sopenharmony_ci	 * When data_src is zero it means the record is not a memory operation,
62062306a36Sopenharmony_ci	 * skip to synthesize memory sample for this case.
62162306a36Sopenharmony_ci	 */
62262306a36Sopenharmony_ci	if (spe->sample_memory && data_src) {
62362306a36Sopenharmony_ci		err = arm_spe__synth_mem_sample(speq, spe->memory_id, data_src);
62462306a36Sopenharmony_ci		if (err)
62562306a36Sopenharmony_ci			return err;
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (spe->sample_instructions) {
62962306a36Sopenharmony_ci		err = arm_spe__synth_instruction_sample(speq, spe->instructions_id, data_src);
63062306a36Sopenharmony_ci		if (err)
63162306a36Sopenharmony_ci			return err;
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	return 0;
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic int arm_spe_run_decoder(struct arm_spe_queue *speq, u64 *timestamp)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	struct arm_spe *spe = speq->spe;
64062306a36Sopenharmony_ci	struct arm_spe_record *record;
64162306a36Sopenharmony_ci	int ret;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (!spe->kernel_start)
64462306a36Sopenharmony_ci		spe->kernel_start = machine__kernel_start(spe->machine);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	while (1) {
64762306a36Sopenharmony_ci		/*
64862306a36Sopenharmony_ci		 * The usual logic is firstly to decode the packets, and then
64962306a36Sopenharmony_ci		 * based the record to synthesize sample; but here the flow is
65062306a36Sopenharmony_ci		 * reversed: it calls arm_spe_sample() for synthesizing samples
65162306a36Sopenharmony_ci		 * prior to arm_spe_decode().
65262306a36Sopenharmony_ci		 *
65362306a36Sopenharmony_ci		 * Two reasons for this code logic:
65462306a36Sopenharmony_ci		 * 1. Firstly, when setup queue in arm_spe__setup_queue(), it
65562306a36Sopenharmony_ci		 * has decoded trace data and generated a record, but the record
65662306a36Sopenharmony_ci		 * is left to generate sample until run to here, so it's correct
65762306a36Sopenharmony_ci		 * to synthesize sample for the left record.
65862306a36Sopenharmony_ci		 * 2. After decoding trace data, it needs to compare the record
65962306a36Sopenharmony_ci		 * timestamp with the coming perf event, if the record timestamp
66062306a36Sopenharmony_ci		 * is later than the perf event, it needs bail out and pushs the
66162306a36Sopenharmony_ci		 * record into auxtrace heap, thus the record can be deferred to
66262306a36Sopenharmony_ci		 * synthesize sample until run to here at the next time; so this
66362306a36Sopenharmony_ci		 * can correlate samples between Arm SPE trace data and other
66462306a36Sopenharmony_ci		 * perf events with correct time ordering.
66562306a36Sopenharmony_ci		 */
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		/*
66862306a36Sopenharmony_ci		 * Update pid/tid info.
66962306a36Sopenharmony_ci		 */
67062306a36Sopenharmony_ci		record = &speq->decoder->record;
67162306a36Sopenharmony_ci		if (!spe->timeless_decoding && record->context_id != (u64)-1) {
67262306a36Sopenharmony_ci			ret = arm_spe_set_tid(speq, record->context_id);
67362306a36Sopenharmony_ci			if (ret)
67462306a36Sopenharmony_ci				return ret;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci			spe->use_ctx_pkt_for_pid = true;
67762306a36Sopenharmony_ci		}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci		ret = arm_spe_sample(speq);
68062306a36Sopenharmony_ci		if (ret)
68162306a36Sopenharmony_ci			return ret;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci		ret = arm_spe_decode(speq->decoder);
68462306a36Sopenharmony_ci		if (!ret) {
68562306a36Sopenharmony_ci			pr_debug("No data or all data has been processed.\n");
68662306a36Sopenharmony_ci			return 1;
68762306a36Sopenharmony_ci		}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		/*
69062306a36Sopenharmony_ci		 * Error is detected when decode SPE trace data, continue to
69162306a36Sopenharmony_ci		 * the next trace data and find out more records.
69262306a36Sopenharmony_ci		 */
69362306a36Sopenharmony_ci		if (ret < 0)
69462306a36Sopenharmony_ci			continue;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci		record = &speq->decoder->record;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci		/* Update timestamp for the last record */
69962306a36Sopenharmony_ci		if (record->timestamp > speq->timestamp)
70062306a36Sopenharmony_ci			speq->timestamp = record->timestamp;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci		/*
70362306a36Sopenharmony_ci		 * If the timestamp of the queue is later than timestamp of the
70462306a36Sopenharmony_ci		 * coming perf event, bail out so can allow the perf event to
70562306a36Sopenharmony_ci		 * be processed ahead.
70662306a36Sopenharmony_ci		 */
70762306a36Sopenharmony_ci		if (!spe->timeless_decoding && speq->timestamp >= *timestamp) {
70862306a36Sopenharmony_ci			*timestamp = speq->timestamp;
70962306a36Sopenharmony_ci			return 0;
71062306a36Sopenharmony_ci		}
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	return 0;
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic int arm_spe__setup_queue(struct arm_spe *spe,
71762306a36Sopenharmony_ci			       struct auxtrace_queue *queue,
71862306a36Sopenharmony_ci			       unsigned int queue_nr)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct arm_spe_queue *speq = queue->priv;
72162306a36Sopenharmony_ci	struct arm_spe_record *record;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	if (list_empty(&queue->head) || speq)
72462306a36Sopenharmony_ci		return 0;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	speq = arm_spe__alloc_queue(spe, queue_nr);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (!speq)
72962306a36Sopenharmony_ci		return -ENOMEM;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	queue->priv = speq;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	if (queue->cpu != -1)
73462306a36Sopenharmony_ci		speq->cpu = queue->cpu;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (!speq->on_heap) {
73762306a36Sopenharmony_ci		int ret;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci		if (spe->timeless_decoding)
74062306a36Sopenharmony_ci			return 0;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ciretry:
74362306a36Sopenharmony_ci		ret = arm_spe_decode(speq->decoder);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci		if (!ret)
74662306a36Sopenharmony_ci			return 0;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci		if (ret < 0)
74962306a36Sopenharmony_ci			goto retry;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci		record = &speq->decoder->record;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci		speq->timestamp = record->timestamp;
75462306a36Sopenharmony_ci		ret = auxtrace_heap__add(&spe->heap, queue_nr, speq->timestamp);
75562306a36Sopenharmony_ci		if (ret)
75662306a36Sopenharmony_ci			return ret;
75762306a36Sopenharmony_ci		speq->on_heap = true;
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	return 0;
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_cistatic int arm_spe__setup_queues(struct arm_spe *spe)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	unsigned int i;
76662306a36Sopenharmony_ci	int ret;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	for (i = 0; i < spe->queues.nr_queues; i++) {
76962306a36Sopenharmony_ci		ret = arm_spe__setup_queue(spe, &spe->queues.queue_array[i], i);
77062306a36Sopenharmony_ci		if (ret)
77162306a36Sopenharmony_ci			return ret;
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	return 0;
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cistatic int arm_spe__update_queues(struct arm_spe *spe)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	if (spe->queues.new_data) {
78062306a36Sopenharmony_ci		spe->queues.new_data = false;
78162306a36Sopenharmony_ci		return arm_spe__setup_queues(spe);
78262306a36Sopenharmony_ci	}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	return 0;
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic bool arm_spe__is_timeless_decoding(struct arm_spe *spe)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	struct evsel *evsel;
79062306a36Sopenharmony_ci	struct evlist *evlist = spe->session->evlist;
79162306a36Sopenharmony_ci	bool timeless_decoding = true;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	/*
79462306a36Sopenharmony_ci	 * Circle through the list of event and complain if we find one
79562306a36Sopenharmony_ci	 * with the time bit set.
79662306a36Sopenharmony_ci	 */
79762306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
79862306a36Sopenharmony_ci		if ((evsel->core.attr.sample_type & PERF_SAMPLE_TIME))
79962306a36Sopenharmony_ci			timeless_decoding = false;
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	return timeless_decoding;
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cistatic int arm_spe_process_queues(struct arm_spe *spe, u64 timestamp)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	unsigned int queue_nr;
80862306a36Sopenharmony_ci	u64 ts;
80962306a36Sopenharmony_ci	int ret;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	while (1) {
81262306a36Sopenharmony_ci		struct auxtrace_queue *queue;
81362306a36Sopenharmony_ci		struct arm_spe_queue *speq;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci		if (!spe->heap.heap_cnt)
81662306a36Sopenharmony_ci			return 0;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci		if (spe->heap.heap_array[0].ordinal >= timestamp)
81962306a36Sopenharmony_ci			return 0;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci		queue_nr = spe->heap.heap_array[0].queue_nr;
82262306a36Sopenharmony_ci		queue = &spe->queues.queue_array[queue_nr];
82362306a36Sopenharmony_ci		speq = queue->priv;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci		auxtrace_heap__pop(&spe->heap);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci		if (spe->heap.heap_cnt) {
82862306a36Sopenharmony_ci			ts = spe->heap.heap_array[0].ordinal + 1;
82962306a36Sopenharmony_ci			if (ts > timestamp)
83062306a36Sopenharmony_ci				ts = timestamp;
83162306a36Sopenharmony_ci		} else {
83262306a36Sopenharmony_ci			ts = timestamp;
83362306a36Sopenharmony_ci		}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci		/*
83662306a36Sopenharmony_ci		 * A previous context-switch event has set pid/tid in the machine's context, so
83762306a36Sopenharmony_ci		 * here we need to update the pid/tid in the thread and SPE queue.
83862306a36Sopenharmony_ci		 */
83962306a36Sopenharmony_ci		if (!spe->use_ctx_pkt_for_pid)
84062306a36Sopenharmony_ci			arm_spe_set_pid_tid_cpu(spe, queue);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci		ret = arm_spe_run_decoder(speq, &ts);
84362306a36Sopenharmony_ci		if (ret < 0) {
84462306a36Sopenharmony_ci			auxtrace_heap__add(&spe->heap, queue_nr, ts);
84562306a36Sopenharmony_ci			return ret;
84662306a36Sopenharmony_ci		}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci		if (!ret) {
84962306a36Sopenharmony_ci			ret = auxtrace_heap__add(&spe->heap, queue_nr, ts);
85062306a36Sopenharmony_ci			if (ret < 0)
85162306a36Sopenharmony_ci				return ret;
85262306a36Sopenharmony_ci		} else {
85362306a36Sopenharmony_ci			speq->on_heap = false;
85462306a36Sopenharmony_ci		}
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	return 0;
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_cistatic int arm_spe_process_timeless_queues(struct arm_spe *spe, pid_t tid,
86162306a36Sopenharmony_ci					    u64 time_)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	struct auxtrace_queues *queues = &spe->queues;
86462306a36Sopenharmony_ci	unsigned int i;
86562306a36Sopenharmony_ci	u64 ts = 0;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	for (i = 0; i < queues->nr_queues; i++) {
86862306a36Sopenharmony_ci		struct auxtrace_queue *queue = &spe->queues.queue_array[i];
86962306a36Sopenharmony_ci		struct arm_spe_queue *speq = queue->priv;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci		if (speq && (tid == -1 || speq->tid == tid)) {
87262306a36Sopenharmony_ci			speq->time = time_;
87362306a36Sopenharmony_ci			arm_spe_set_pid_tid_cpu(spe, queue);
87462306a36Sopenharmony_ci			arm_spe_run_decoder(speq, &ts);
87562306a36Sopenharmony_ci		}
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci	return 0;
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic int arm_spe_context_switch(struct arm_spe *spe, union perf_event *event,
88162306a36Sopenharmony_ci				  struct perf_sample *sample)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	pid_t pid, tid;
88462306a36Sopenharmony_ci	int cpu;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	if (!(event->header.misc & PERF_RECORD_MISC_SWITCH_OUT))
88762306a36Sopenharmony_ci		return 0;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	pid = event->context_switch.next_prev_pid;
89062306a36Sopenharmony_ci	tid = event->context_switch.next_prev_tid;
89162306a36Sopenharmony_ci	cpu = sample->cpu;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	if (tid == -1)
89462306a36Sopenharmony_ci		pr_warning("context_switch event has no tid\n");
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	return machine__set_current_tid(spe->machine, cpu, pid, tid);
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_cistatic int arm_spe_process_event(struct perf_session *session,
90062306a36Sopenharmony_ci				 union perf_event *event,
90162306a36Sopenharmony_ci				 struct perf_sample *sample,
90262306a36Sopenharmony_ci				 struct perf_tool *tool)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	int err = 0;
90562306a36Sopenharmony_ci	u64 timestamp;
90662306a36Sopenharmony_ci	struct arm_spe *spe = container_of(session->auxtrace,
90762306a36Sopenharmony_ci			struct arm_spe, auxtrace);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	if (dump_trace)
91062306a36Sopenharmony_ci		return 0;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	if (!tool->ordered_events) {
91362306a36Sopenharmony_ci		pr_err("SPE trace requires ordered events\n");
91462306a36Sopenharmony_ci		return -EINVAL;
91562306a36Sopenharmony_ci	}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	if (sample->time && (sample->time != (u64) -1))
91862306a36Sopenharmony_ci		timestamp = perf_time_to_tsc(sample->time, &spe->tc);
91962306a36Sopenharmony_ci	else
92062306a36Sopenharmony_ci		timestamp = 0;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	if (timestamp || spe->timeless_decoding) {
92362306a36Sopenharmony_ci		err = arm_spe__update_queues(spe);
92462306a36Sopenharmony_ci		if (err)
92562306a36Sopenharmony_ci			return err;
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	if (spe->timeless_decoding) {
92962306a36Sopenharmony_ci		if (event->header.type == PERF_RECORD_EXIT) {
93062306a36Sopenharmony_ci			err = arm_spe_process_timeless_queues(spe,
93162306a36Sopenharmony_ci					event->fork.tid,
93262306a36Sopenharmony_ci					sample->time);
93362306a36Sopenharmony_ci		}
93462306a36Sopenharmony_ci	} else if (timestamp) {
93562306a36Sopenharmony_ci		err = arm_spe_process_queues(spe, timestamp);
93662306a36Sopenharmony_ci		if (err)
93762306a36Sopenharmony_ci			return err;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		if (!spe->use_ctx_pkt_for_pid &&
94062306a36Sopenharmony_ci		    (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE ||
94162306a36Sopenharmony_ci		    event->header.type == PERF_RECORD_SWITCH))
94262306a36Sopenharmony_ci			err = arm_spe_context_switch(spe, event, sample);
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	return err;
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_cistatic int arm_spe_process_auxtrace_event(struct perf_session *session,
94962306a36Sopenharmony_ci					  union perf_event *event,
95062306a36Sopenharmony_ci					  struct perf_tool *tool __maybe_unused)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
95362306a36Sopenharmony_ci					     auxtrace);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (!spe->data_queued) {
95662306a36Sopenharmony_ci		struct auxtrace_buffer *buffer;
95762306a36Sopenharmony_ci		off_t data_offset;
95862306a36Sopenharmony_ci		int fd = perf_data__fd(session->data);
95962306a36Sopenharmony_ci		int err;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci		if (perf_data__is_pipe(session->data)) {
96262306a36Sopenharmony_ci			data_offset = 0;
96362306a36Sopenharmony_ci		} else {
96462306a36Sopenharmony_ci			data_offset = lseek(fd, 0, SEEK_CUR);
96562306a36Sopenharmony_ci			if (data_offset == -1)
96662306a36Sopenharmony_ci				return -errno;
96762306a36Sopenharmony_ci		}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		err = auxtrace_queues__add_event(&spe->queues, session, event,
97062306a36Sopenharmony_ci				data_offset, &buffer);
97162306a36Sopenharmony_ci		if (err)
97262306a36Sopenharmony_ci			return err;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci		/* Dump here now we have copied a piped trace out of the pipe */
97562306a36Sopenharmony_ci		if (dump_trace) {
97662306a36Sopenharmony_ci			if (auxtrace_buffer__get_data(buffer, fd)) {
97762306a36Sopenharmony_ci				arm_spe_dump_event(spe, buffer->data,
97862306a36Sopenharmony_ci						buffer->size);
97962306a36Sopenharmony_ci				auxtrace_buffer__put_data(buffer);
98062306a36Sopenharmony_ci			}
98162306a36Sopenharmony_ci		}
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	return 0;
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic int arm_spe_flush(struct perf_session *session __maybe_unused,
98862306a36Sopenharmony_ci			 struct perf_tool *tool __maybe_unused)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
99162306a36Sopenharmony_ci			auxtrace);
99262306a36Sopenharmony_ci	int ret;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	if (dump_trace)
99562306a36Sopenharmony_ci		return 0;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	if (!tool->ordered_events)
99862306a36Sopenharmony_ci		return -EINVAL;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	ret = arm_spe__update_queues(spe);
100162306a36Sopenharmony_ci	if (ret < 0)
100262306a36Sopenharmony_ci		return ret;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	if (spe->timeless_decoding)
100562306a36Sopenharmony_ci		return arm_spe_process_timeless_queues(spe, -1,
100662306a36Sopenharmony_ci				MAX_TIMESTAMP - 1);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	ret = arm_spe_process_queues(spe, MAX_TIMESTAMP);
100962306a36Sopenharmony_ci	if (ret)
101062306a36Sopenharmony_ci		return ret;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	if (!spe->use_ctx_pkt_for_pid)
101362306a36Sopenharmony_ci		ui__warning("Arm SPE CONTEXT packets not found in the traces.\n"
101462306a36Sopenharmony_ci			    "Matching of TIDs to SPE events could be inaccurate.\n");
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	return 0;
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_cistatic void arm_spe_free_queue(void *priv)
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci	struct arm_spe_queue *speq = priv;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	if (!speq)
102462306a36Sopenharmony_ci		return;
102562306a36Sopenharmony_ci	thread__zput(speq->thread);
102662306a36Sopenharmony_ci	arm_spe_decoder_free(speq->decoder);
102762306a36Sopenharmony_ci	zfree(&speq->event_buf);
102862306a36Sopenharmony_ci	free(speq);
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic void arm_spe_free_events(struct perf_session *session)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
103462306a36Sopenharmony_ci					     auxtrace);
103562306a36Sopenharmony_ci	struct auxtrace_queues *queues = &spe->queues;
103662306a36Sopenharmony_ci	unsigned int i;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	for (i = 0; i < queues->nr_queues; i++) {
103962306a36Sopenharmony_ci		arm_spe_free_queue(queues->queue_array[i].priv);
104062306a36Sopenharmony_ci		queues->queue_array[i].priv = NULL;
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci	auxtrace_queues__free(queues);
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cistatic void arm_spe_free(struct perf_session *session)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
104862306a36Sopenharmony_ci					     auxtrace);
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	auxtrace_heap__free(&spe->heap);
105162306a36Sopenharmony_ci	arm_spe_free_events(session);
105262306a36Sopenharmony_ci	session->auxtrace = NULL;
105362306a36Sopenharmony_ci	free(spe);
105462306a36Sopenharmony_ci}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_cistatic bool arm_spe_evsel_is_auxtrace(struct perf_session *session,
105762306a36Sopenharmony_ci				      struct evsel *evsel)
105862306a36Sopenharmony_ci{
105962306a36Sopenharmony_ci	struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe, auxtrace);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	return evsel->core.attr.type == spe->pmu_type;
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic const char * const arm_spe_info_fmts[] = {
106562306a36Sopenharmony_ci	[ARM_SPE_PMU_TYPE]		= "  PMU Type           %"PRId64"\n",
106662306a36Sopenharmony_ci};
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_cistatic void arm_spe_print_info(__u64 *arr)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	if (!dump_trace)
107162306a36Sopenharmony_ci		return;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	fprintf(stdout, arm_spe_info_fmts[ARM_SPE_PMU_TYPE], arr[ARM_SPE_PMU_TYPE]);
107462306a36Sopenharmony_ci}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_cistruct arm_spe_synth {
107762306a36Sopenharmony_ci	struct perf_tool dummy_tool;
107862306a36Sopenharmony_ci	struct perf_session *session;
107962306a36Sopenharmony_ci};
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_cistatic int arm_spe_event_synth(struct perf_tool *tool,
108262306a36Sopenharmony_ci			       union perf_event *event,
108362306a36Sopenharmony_ci			       struct perf_sample *sample __maybe_unused,
108462306a36Sopenharmony_ci			       struct machine *machine __maybe_unused)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	struct arm_spe_synth *arm_spe_synth =
108762306a36Sopenharmony_ci		      container_of(tool, struct arm_spe_synth, dummy_tool);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	return perf_session__deliver_synth_event(arm_spe_synth->session,
109062306a36Sopenharmony_ci						 event, NULL);
109162306a36Sopenharmony_ci}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_cistatic int arm_spe_synth_event(struct perf_session *session,
109462306a36Sopenharmony_ci			       struct perf_event_attr *attr, u64 id)
109562306a36Sopenharmony_ci{
109662306a36Sopenharmony_ci	struct arm_spe_synth arm_spe_synth;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	memset(&arm_spe_synth, 0, sizeof(struct arm_spe_synth));
109962306a36Sopenharmony_ci	arm_spe_synth.session = session;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	return perf_event__synthesize_attr(&arm_spe_synth.dummy_tool, attr, 1,
110262306a36Sopenharmony_ci					   &id, arm_spe_event_synth);
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_cistatic void arm_spe_set_event_name(struct evlist *evlist, u64 id,
110662306a36Sopenharmony_ci				    const char *name)
110762306a36Sopenharmony_ci{
110862306a36Sopenharmony_ci	struct evsel *evsel;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
111162306a36Sopenharmony_ci		if (evsel->core.id && evsel->core.id[0] == id) {
111262306a36Sopenharmony_ci			if (evsel->name)
111362306a36Sopenharmony_ci				zfree(&evsel->name);
111462306a36Sopenharmony_ci			evsel->name = strdup(name);
111562306a36Sopenharmony_ci			break;
111662306a36Sopenharmony_ci		}
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_cistatic int
112162306a36Sopenharmony_ciarm_spe_synth_events(struct arm_spe *spe, struct perf_session *session)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	struct evlist *evlist = session->evlist;
112462306a36Sopenharmony_ci	struct evsel *evsel;
112562306a36Sopenharmony_ci	struct perf_event_attr attr;
112662306a36Sopenharmony_ci	bool found = false;
112762306a36Sopenharmony_ci	u64 id;
112862306a36Sopenharmony_ci	int err;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
113162306a36Sopenharmony_ci		if (evsel->core.attr.type == spe->pmu_type) {
113262306a36Sopenharmony_ci			found = true;
113362306a36Sopenharmony_ci			break;
113462306a36Sopenharmony_ci		}
113562306a36Sopenharmony_ci	}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	if (!found) {
113862306a36Sopenharmony_ci		pr_debug("No selected events with SPE trace data\n");
113962306a36Sopenharmony_ci		return 0;
114062306a36Sopenharmony_ci	}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	memset(&attr, 0, sizeof(struct perf_event_attr));
114362306a36Sopenharmony_ci	attr.size = sizeof(struct perf_event_attr);
114462306a36Sopenharmony_ci	attr.type = PERF_TYPE_HARDWARE;
114562306a36Sopenharmony_ci	attr.sample_type = evsel->core.attr.sample_type &
114662306a36Sopenharmony_ci				(PERF_SAMPLE_MASK | PERF_SAMPLE_PHYS_ADDR);
114762306a36Sopenharmony_ci	attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID |
114862306a36Sopenharmony_ci			    PERF_SAMPLE_PERIOD | PERF_SAMPLE_DATA_SRC |
114962306a36Sopenharmony_ci			    PERF_SAMPLE_WEIGHT | PERF_SAMPLE_ADDR;
115062306a36Sopenharmony_ci	if (spe->timeless_decoding)
115162306a36Sopenharmony_ci		attr.sample_type &= ~(u64)PERF_SAMPLE_TIME;
115262306a36Sopenharmony_ci	else
115362306a36Sopenharmony_ci		attr.sample_type |= PERF_SAMPLE_TIME;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	spe->sample_type = attr.sample_type;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	attr.exclude_user = evsel->core.attr.exclude_user;
115862306a36Sopenharmony_ci	attr.exclude_kernel = evsel->core.attr.exclude_kernel;
115962306a36Sopenharmony_ci	attr.exclude_hv = evsel->core.attr.exclude_hv;
116062306a36Sopenharmony_ci	attr.exclude_host = evsel->core.attr.exclude_host;
116162306a36Sopenharmony_ci	attr.exclude_guest = evsel->core.attr.exclude_guest;
116262306a36Sopenharmony_ci	attr.sample_id_all = evsel->core.attr.sample_id_all;
116362306a36Sopenharmony_ci	attr.read_format = evsel->core.attr.read_format;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	/* create new id val to be a fixed offset from evsel id */
116662306a36Sopenharmony_ci	id = evsel->core.id[0] + 1000000000;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	if (!id)
116962306a36Sopenharmony_ci		id = 1;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	if (spe->synth_opts.flc) {
117262306a36Sopenharmony_ci		spe->sample_flc = true;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci		/* Level 1 data cache miss */
117562306a36Sopenharmony_ci		err = arm_spe_synth_event(session, &attr, id);
117662306a36Sopenharmony_ci		if (err)
117762306a36Sopenharmony_ci			return err;
117862306a36Sopenharmony_ci		spe->l1d_miss_id = id;
117962306a36Sopenharmony_ci		arm_spe_set_event_name(evlist, id, "l1d-miss");
118062306a36Sopenharmony_ci		id += 1;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci		/* Level 1 data cache access */
118362306a36Sopenharmony_ci		err = arm_spe_synth_event(session, &attr, id);
118462306a36Sopenharmony_ci		if (err)
118562306a36Sopenharmony_ci			return err;
118662306a36Sopenharmony_ci		spe->l1d_access_id = id;
118762306a36Sopenharmony_ci		arm_spe_set_event_name(evlist, id, "l1d-access");
118862306a36Sopenharmony_ci		id += 1;
118962306a36Sopenharmony_ci	}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	if (spe->synth_opts.llc) {
119262306a36Sopenharmony_ci		spe->sample_llc = true;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci		/* Last level cache miss */
119562306a36Sopenharmony_ci		err = arm_spe_synth_event(session, &attr, id);
119662306a36Sopenharmony_ci		if (err)
119762306a36Sopenharmony_ci			return err;
119862306a36Sopenharmony_ci		spe->llc_miss_id = id;
119962306a36Sopenharmony_ci		arm_spe_set_event_name(evlist, id, "llc-miss");
120062306a36Sopenharmony_ci		id += 1;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci		/* Last level cache access */
120362306a36Sopenharmony_ci		err = arm_spe_synth_event(session, &attr, id);
120462306a36Sopenharmony_ci		if (err)
120562306a36Sopenharmony_ci			return err;
120662306a36Sopenharmony_ci		spe->llc_access_id = id;
120762306a36Sopenharmony_ci		arm_spe_set_event_name(evlist, id, "llc-access");
120862306a36Sopenharmony_ci		id += 1;
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	if (spe->synth_opts.tlb) {
121262306a36Sopenharmony_ci		spe->sample_tlb = true;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci		/* TLB miss */
121562306a36Sopenharmony_ci		err = arm_spe_synth_event(session, &attr, id);
121662306a36Sopenharmony_ci		if (err)
121762306a36Sopenharmony_ci			return err;
121862306a36Sopenharmony_ci		spe->tlb_miss_id = id;
121962306a36Sopenharmony_ci		arm_spe_set_event_name(evlist, id, "tlb-miss");
122062306a36Sopenharmony_ci		id += 1;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci		/* TLB access */
122362306a36Sopenharmony_ci		err = arm_spe_synth_event(session, &attr, id);
122462306a36Sopenharmony_ci		if (err)
122562306a36Sopenharmony_ci			return err;
122662306a36Sopenharmony_ci		spe->tlb_access_id = id;
122762306a36Sopenharmony_ci		arm_spe_set_event_name(evlist, id, "tlb-access");
122862306a36Sopenharmony_ci		id += 1;
122962306a36Sopenharmony_ci	}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	if (spe->synth_opts.branches) {
123262306a36Sopenharmony_ci		spe->sample_branch = true;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci		/* Branch miss */
123562306a36Sopenharmony_ci		err = arm_spe_synth_event(session, &attr, id);
123662306a36Sopenharmony_ci		if (err)
123762306a36Sopenharmony_ci			return err;
123862306a36Sopenharmony_ci		spe->branch_miss_id = id;
123962306a36Sopenharmony_ci		arm_spe_set_event_name(evlist, id, "branch-miss");
124062306a36Sopenharmony_ci		id += 1;
124162306a36Sopenharmony_ci	}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	if (spe->synth_opts.remote_access) {
124462306a36Sopenharmony_ci		spe->sample_remote_access = true;
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci		/* Remote access */
124762306a36Sopenharmony_ci		err = arm_spe_synth_event(session, &attr, id);
124862306a36Sopenharmony_ci		if (err)
124962306a36Sopenharmony_ci			return err;
125062306a36Sopenharmony_ci		spe->remote_access_id = id;
125162306a36Sopenharmony_ci		arm_spe_set_event_name(evlist, id, "remote-access");
125262306a36Sopenharmony_ci		id += 1;
125362306a36Sopenharmony_ci	}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	if (spe->synth_opts.mem) {
125662306a36Sopenharmony_ci		spe->sample_memory = true;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci		err = arm_spe_synth_event(session, &attr, id);
125962306a36Sopenharmony_ci		if (err)
126062306a36Sopenharmony_ci			return err;
126162306a36Sopenharmony_ci		spe->memory_id = id;
126262306a36Sopenharmony_ci		arm_spe_set_event_name(evlist, id, "memory");
126362306a36Sopenharmony_ci		id += 1;
126462306a36Sopenharmony_ci	}
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	if (spe->synth_opts.instructions) {
126762306a36Sopenharmony_ci		if (spe->synth_opts.period_type != PERF_ITRACE_PERIOD_INSTRUCTIONS) {
126862306a36Sopenharmony_ci			pr_warning("Only instruction-based sampling period is currently supported by Arm SPE.\n");
126962306a36Sopenharmony_ci			goto synth_instructions_out;
127062306a36Sopenharmony_ci		}
127162306a36Sopenharmony_ci		if (spe->synth_opts.period > 1)
127262306a36Sopenharmony_ci			pr_warning("Arm SPE has a hardware-based sample period.\n"
127362306a36Sopenharmony_ci				   "Additional instruction events will be discarded by --itrace\n");
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci		spe->sample_instructions = true;
127662306a36Sopenharmony_ci		attr.config = PERF_COUNT_HW_INSTRUCTIONS;
127762306a36Sopenharmony_ci		attr.sample_period = spe->synth_opts.period;
127862306a36Sopenharmony_ci		spe->instructions_sample_period = attr.sample_period;
127962306a36Sopenharmony_ci		err = arm_spe_synth_event(session, &attr, id);
128062306a36Sopenharmony_ci		if (err)
128162306a36Sopenharmony_ci			return err;
128262306a36Sopenharmony_ci		spe->instructions_id = id;
128362306a36Sopenharmony_ci		arm_spe_set_event_name(evlist, id, "instructions");
128462306a36Sopenharmony_ci	}
128562306a36Sopenharmony_cisynth_instructions_out:
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	return 0;
128862306a36Sopenharmony_ci}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ciint arm_spe_process_auxtrace_info(union perf_event *event,
129162306a36Sopenharmony_ci				  struct perf_session *session)
129262306a36Sopenharmony_ci{
129362306a36Sopenharmony_ci	struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
129462306a36Sopenharmony_ci	size_t min_sz = sizeof(u64) * ARM_SPE_AUXTRACE_PRIV_MAX;
129562306a36Sopenharmony_ci	struct perf_record_time_conv *tc = &session->time_conv;
129662306a36Sopenharmony_ci	const char *cpuid = perf_env__cpuid(session->evlist->env);
129762306a36Sopenharmony_ci	u64 midr = strtol(cpuid, NULL, 16);
129862306a36Sopenharmony_ci	struct arm_spe *spe;
129962306a36Sopenharmony_ci	int err;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) +
130262306a36Sopenharmony_ci					min_sz)
130362306a36Sopenharmony_ci		return -EINVAL;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	spe = zalloc(sizeof(struct arm_spe));
130662306a36Sopenharmony_ci	if (!spe)
130762306a36Sopenharmony_ci		return -ENOMEM;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	err = auxtrace_queues__init(&spe->queues);
131062306a36Sopenharmony_ci	if (err)
131162306a36Sopenharmony_ci		goto err_free;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	spe->session = session;
131462306a36Sopenharmony_ci	spe->machine = &session->machines.host; /* No kvm support */
131562306a36Sopenharmony_ci	spe->auxtrace_type = auxtrace_info->type;
131662306a36Sopenharmony_ci	spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE];
131762306a36Sopenharmony_ci	spe->midr = midr;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	spe->timeless_decoding = arm_spe__is_timeless_decoding(spe);
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	/*
132262306a36Sopenharmony_ci	 * The synthesized event PERF_RECORD_TIME_CONV has been handled ahead
132362306a36Sopenharmony_ci	 * and the parameters for hardware clock are stored in the session
132462306a36Sopenharmony_ci	 * context.  Passes these parameters to the struct perf_tsc_conversion
132562306a36Sopenharmony_ci	 * in "spe->tc", which is used for later conversion between clock
132662306a36Sopenharmony_ci	 * counter and timestamp.
132762306a36Sopenharmony_ci	 *
132862306a36Sopenharmony_ci	 * For backward compatibility, copies the fields starting from
132962306a36Sopenharmony_ci	 * "time_cycles" only if they are contained in the event.
133062306a36Sopenharmony_ci	 */
133162306a36Sopenharmony_ci	spe->tc.time_shift = tc->time_shift;
133262306a36Sopenharmony_ci	spe->tc.time_mult = tc->time_mult;
133362306a36Sopenharmony_ci	spe->tc.time_zero = tc->time_zero;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	if (event_contains(*tc, time_cycles)) {
133662306a36Sopenharmony_ci		spe->tc.time_cycles = tc->time_cycles;
133762306a36Sopenharmony_ci		spe->tc.time_mask = tc->time_mask;
133862306a36Sopenharmony_ci		spe->tc.cap_user_time_zero = tc->cap_user_time_zero;
133962306a36Sopenharmony_ci		spe->tc.cap_user_time_short = tc->cap_user_time_short;
134062306a36Sopenharmony_ci	}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	spe->auxtrace.process_event = arm_spe_process_event;
134362306a36Sopenharmony_ci	spe->auxtrace.process_auxtrace_event = arm_spe_process_auxtrace_event;
134462306a36Sopenharmony_ci	spe->auxtrace.flush_events = arm_spe_flush;
134562306a36Sopenharmony_ci	spe->auxtrace.free_events = arm_spe_free_events;
134662306a36Sopenharmony_ci	spe->auxtrace.free = arm_spe_free;
134762306a36Sopenharmony_ci	spe->auxtrace.evsel_is_auxtrace = arm_spe_evsel_is_auxtrace;
134862306a36Sopenharmony_ci	session->auxtrace = &spe->auxtrace;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	arm_spe_print_info(&auxtrace_info->priv[0]);
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	if (dump_trace)
135362306a36Sopenharmony_ci		return 0;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	if (session->itrace_synth_opts && session->itrace_synth_opts->set)
135662306a36Sopenharmony_ci		spe->synth_opts = *session->itrace_synth_opts;
135762306a36Sopenharmony_ci	else
135862306a36Sopenharmony_ci		itrace_synth_opts__set_default(&spe->synth_opts, false);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	err = arm_spe_synth_events(spe, session);
136162306a36Sopenharmony_ci	if (err)
136262306a36Sopenharmony_ci		goto err_free_queues;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	err = auxtrace_queues__process_index(&spe->queues, session);
136562306a36Sopenharmony_ci	if (err)
136662306a36Sopenharmony_ci		goto err_free_queues;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	if (spe->queues.populated)
136962306a36Sopenharmony_ci		spe->data_queued = true;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	return 0;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_cierr_free_queues:
137462306a36Sopenharmony_ci	auxtrace_queues__free(&spe->queues);
137562306a36Sopenharmony_ci	session->auxtrace = NULL;
137662306a36Sopenharmony_cierr_free:
137762306a36Sopenharmony_ci	free(spe);
137862306a36Sopenharmony_ci	return err;
137962306a36Sopenharmony_ci}
1380