18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright(C) 2015-2018 Linaro Limited.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: Tor Jeremiassen <tor@ti.com>
68c2ecf20Sopenharmony_ci * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/bitops.h>
108c2ecf20Sopenharmony_ci#include <linux/err.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/log2.h>
138c2ecf20Sopenharmony_ci#include <linux/types.h>
148c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <opencsd/ocsd_if_types.h>
178c2ecf20Sopenharmony_ci#include <stdlib.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "auxtrace.h"
208c2ecf20Sopenharmony_ci#include "color.h"
218c2ecf20Sopenharmony_ci#include "cs-etm.h"
228c2ecf20Sopenharmony_ci#include "cs-etm-decoder/cs-etm-decoder.h"
238c2ecf20Sopenharmony_ci#include "debug.h"
248c2ecf20Sopenharmony_ci#include "dso.h"
258c2ecf20Sopenharmony_ci#include "evlist.h"
268c2ecf20Sopenharmony_ci#include "intlist.h"
278c2ecf20Sopenharmony_ci#include "machine.h"
288c2ecf20Sopenharmony_ci#include "map.h"
298c2ecf20Sopenharmony_ci#include "perf.h"
308c2ecf20Sopenharmony_ci#include "session.h"
318c2ecf20Sopenharmony_ci#include "map_symbol.h"
328c2ecf20Sopenharmony_ci#include "branch.h"
338c2ecf20Sopenharmony_ci#include "symbol.h"
348c2ecf20Sopenharmony_ci#include "tool.h"
358c2ecf20Sopenharmony_ci#include "thread.h"
368c2ecf20Sopenharmony_ci#include "thread-stack.h"
378c2ecf20Sopenharmony_ci#include <tools/libc_compat.h>
388c2ecf20Sopenharmony_ci#include "util/synthetic-events.h"
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define MAX_TIMESTAMP (~0ULL)
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct cs_etm_auxtrace {
438c2ecf20Sopenharmony_ci	struct auxtrace auxtrace;
448c2ecf20Sopenharmony_ci	struct auxtrace_queues queues;
458c2ecf20Sopenharmony_ci	struct auxtrace_heap heap;
468c2ecf20Sopenharmony_ci	struct itrace_synth_opts synth_opts;
478c2ecf20Sopenharmony_ci	struct perf_session *session;
488c2ecf20Sopenharmony_ci	struct machine *machine;
498c2ecf20Sopenharmony_ci	struct thread *unknown_thread;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	u8 timeless_decoding;
528c2ecf20Sopenharmony_ci	u8 snapshot_mode;
538c2ecf20Sopenharmony_ci	u8 data_queued;
548c2ecf20Sopenharmony_ci	u8 sample_branches;
558c2ecf20Sopenharmony_ci	u8 sample_instructions;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	int num_cpu;
588c2ecf20Sopenharmony_ci	u32 auxtrace_type;
598c2ecf20Sopenharmony_ci	u64 branches_sample_type;
608c2ecf20Sopenharmony_ci	u64 branches_id;
618c2ecf20Sopenharmony_ci	u64 instructions_sample_type;
628c2ecf20Sopenharmony_ci	u64 instructions_sample_period;
638c2ecf20Sopenharmony_ci	u64 instructions_id;
648c2ecf20Sopenharmony_ci	u64 **metadata;
658c2ecf20Sopenharmony_ci	u64 kernel_start;
668c2ecf20Sopenharmony_ci	unsigned int pmu_type;
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistruct cs_etm_traceid_queue {
708c2ecf20Sopenharmony_ci	u8 trace_chan_id;
718c2ecf20Sopenharmony_ci	pid_t pid, tid;
728c2ecf20Sopenharmony_ci	u64 period_instructions;
738c2ecf20Sopenharmony_ci	size_t last_branch_pos;
748c2ecf20Sopenharmony_ci	union perf_event *event_buf;
758c2ecf20Sopenharmony_ci	struct thread *thread;
768c2ecf20Sopenharmony_ci	struct branch_stack *last_branch;
778c2ecf20Sopenharmony_ci	struct branch_stack *last_branch_rb;
788c2ecf20Sopenharmony_ci	struct cs_etm_packet *prev_packet;
798c2ecf20Sopenharmony_ci	struct cs_etm_packet *packet;
808c2ecf20Sopenharmony_ci	struct cs_etm_packet_queue packet_queue;
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistruct cs_etm_queue {
848c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *etm;
858c2ecf20Sopenharmony_ci	struct cs_etm_decoder *decoder;
868c2ecf20Sopenharmony_ci	struct auxtrace_buffer *buffer;
878c2ecf20Sopenharmony_ci	unsigned int queue_nr;
888c2ecf20Sopenharmony_ci	u8 pending_timestamp;
898c2ecf20Sopenharmony_ci	u64 offset;
908c2ecf20Sopenharmony_ci	const unsigned char *buf;
918c2ecf20Sopenharmony_ci	size_t buf_len, buf_used;
928c2ecf20Sopenharmony_ci	/* Conversion between traceID and index in traceid_queues array */
938c2ecf20Sopenharmony_ci	struct intlist *traceid_queues_list;
948c2ecf20Sopenharmony_ci	struct cs_etm_traceid_queue **traceid_queues;
958c2ecf20Sopenharmony_ci};
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/* RB tree for quick conversion between traceID and metadata pointers */
988c2ecf20Sopenharmony_cistatic struct intlist *traceid_list;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic int cs_etm__update_queues(struct cs_etm_auxtrace *etm);
1018c2ecf20Sopenharmony_cistatic int cs_etm__process_queues(struct cs_etm_auxtrace *etm);
1028c2ecf20Sopenharmony_cistatic int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm,
1038c2ecf20Sopenharmony_ci					   pid_t tid);
1048c2ecf20Sopenharmony_cistatic int cs_etm__get_data_block(struct cs_etm_queue *etmq);
1058c2ecf20Sopenharmony_cistatic int cs_etm__decode_data_block(struct cs_etm_queue *etmq);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci/* PTMs ETMIDR [11:8] set to b0011 */
1088c2ecf20Sopenharmony_ci#define ETMIDR_PTM_VERSION 0x00000300
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci/*
1118c2ecf20Sopenharmony_ci * A struct auxtrace_heap_item only has a queue_nr and a timestamp to
1128c2ecf20Sopenharmony_ci * work with.  One option is to modify to auxtrace_heap_XYZ() API or simply
1138c2ecf20Sopenharmony_ci * encode the etm queue number as the upper 16 bit and the channel as
1148c2ecf20Sopenharmony_ci * the lower 16 bit.
1158c2ecf20Sopenharmony_ci */
1168c2ecf20Sopenharmony_ci#define TO_CS_QUEUE_NR(queue_nr, trace_chan_id)	\
1178c2ecf20Sopenharmony_ci		      (queue_nr << 16 | trace_chan_id)
1188c2ecf20Sopenharmony_ci#define TO_QUEUE_NR(cs_queue_nr) (cs_queue_nr >> 16)
1198c2ecf20Sopenharmony_ci#define TO_TRACE_CHAN_ID(cs_queue_nr) (cs_queue_nr & 0x0000ffff)
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic u32 cs_etm__get_v7_protocol_version(u32 etmidr)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	etmidr &= ETMIDR_PTM_VERSION;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (etmidr == ETMIDR_PTM_VERSION)
1268c2ecf20Sopenharmony_ci		return CS_ETM_PROTO_PTM;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return CS_ETM_PROTO_ETMV3;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic int cs_etm__get_magic(u8 trace_chan_id, u64 *magic)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct int_node *inode;
1348c2ecf20Sopenharmony_ci	u64 *metadata;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	inode = intlist__find(traceid_list, trace_chan_id);
1378c2ecf20Sopenharmony_ci	if (!inode)
1388c2ecf20Sopenharmony_ci		return -EINVAL;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	metadata = inode->priv;
1418c2ecf20Sopenharmony_ci	*magic = metadata[CS_ETM_MAGIC];
1428c2ecf20Sopenharmony_ci	return 0;
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ciint cs_etm__get_cpu(u8 trace_chan_id, int *cpu)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct int_node *inode;
1488c2ecf20Sopenharmony_ci	u64 *metadata;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	inode = intlist__find(traceid_list, trace_chan_id);
1518c2ecf20Sopenharmony_ci	if (!inode)
1528c2ecf20Sopenharmony_ci		return -EINVAL;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	metadata = inode->priv;
1558c2ecf20Sopenharmony_ci	*cpu = (int)metadata[CS_ETM_CPU];
1568c2ecf20Sopenharmony_ci	return 0;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_civoid cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq,
1608c2ecf20Sopenharmony_ci					      u8 trace_chan_id)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	/*
1638c2ecf20Sopenharmony_ci	 * Wnen a timestamp packet is encountered the backend code
1648c2ecf20Sopenharmony_ci	 * is stopped so that the front end has time to process packets
1658c2ecf20Sopenharmony_ci	 * that were accumulated in the traceID queue.  Since there can
1668c2ecf20Sopenharmony_ci	 * be more than one channel per cs_etm_queue, we need to specify
1678c2ecf20Sopenharmony_ci	 * what traceID queue needs servicing.
1688c2ecf20Sopenharmony_ci	 */
1698c2ecf20Sopenharmony_ci	etmq->pending_timestamp = trace_chan_id;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic u64 cs_etm__etmq_get_timestamp(struct cs_etm_queue *etmq,
1738c2ecf20Sopenharmony_ci				      u8 *trace_chan_id)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	struct cs_etm_packet_queue *packet_queue;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (!etmq->pending_timestamp)
1788c2ecf20Sopenharmony_ci		return 0;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	if (trace_chan_id)
1818c2ecf20Sopenharmony_ci		*trace_chan_id = etmq->pending_timestamp;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	packet_queue = cs_etm__etmq_get_packet_queue(etmq,
1848c2ecf20Sopenharmony_ci						     etmq->pending_timestamp);
1858c2ecf20Sopenharmony_ci	if (!packet_queue)
1868c2ecf20Sopenharmony_ci		return 0;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	/* Acknowledge pending status */
1898c2ecf20Sopenharmony_ci	etmq->pending_timestamp = 0;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	/* See function cs_etm_decoder__do_{hard|soft}_timestamp() */
1928c2ecf20Sopenharmony_ci	return packet_queue->timestamp;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic void cs_etm__clear_packet_queue(struct cs_etm_packet_queue *queue)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	int i;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	queue->head = 0;
2008c2ecf20Sopenharmony_ci	queue->tail = 0;
2018c2ecf20Sopenharmony_ci	queue->packet_count = 0;
2028c2ecf20Sopenharmony_ci	for (i = 0; i < CS_ETM_PACKET_MAX_BUFFER; i++) {
2038c2ecf20Sopenharmony_ci		queue->packet_buffer[i].isa = CS_ETM_ISA_UNKNOWN;
2048c2ecf20Sopenharmony_ci		queue->packet_buffer[i].start_addr = CS_ETM_INVAL_ADDR;
2058c2ecf20Sopenharmony_ci		queue->packet_buffer[i].end_addr = CS_ETM_INVAL_ADDR;
2068c2ecf20Sopenharmony_ci		queue->packet_buffer[i].instr_count = 0;
2078c2ecf20Sopenharmony_ci		queue->packet_buffer[i].last_instr_taken_branch = false;
2088c2ecf20Sopenharmony_ci		queue->packet_buffer[i].last_instr_size = 0;
2098c2ecf20Sopenharmony_ci		queue->packet_buffer[i].last_instr_type = 0;
2108c2ecf20Sopenharmony_ci		queue->packet_buffer[i].last_instr_subtype = 0;
2118c2ecf20Sopenharmony_ci		queue->packet_buffer[i].last_instr_cond = 0;
2128c2ecf20Sopenharmony_ci		queue->packet_buffer[i].flags = 0;
2138c2ecf20Sopenharmony_ci		queue->packet_buffer[i].exception_number = UINT32_MAX;
2148c2ecf20Sopenharmony_ci		queue->packet_buffer[i].trace_chan_id = UINT8_MAX;
2158c2ecf20Sopenharmony_ci		queue->packet_buffer[i].cpu = INT_MIN;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic void cs_etm__clear_all_packet_queues(struct cs_etm_queue *etmq)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	int idx;
2228c2ecf20Sopenharmony_ci	struct int_node *inode;
2238c2ecf20Sopenharmony_ci	struct cs_etm_traceid_queue *tidq;
2248c2ecf20Sopenharmony_ci	struct intlist *traceid_queues_list = etmq->traceid_queues_list;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	intlist__for_each_entry(inode, traceid_queues_list) {
2278c2ecf20Sopenharmony_ci		idx = (int)(intptr_t)inode->priv;
2288c2ecf20Sopenharmony_ci		tidq = etmq->traceid_queues[idx];
2298c2ecf20Sopenharmony_ci		cs_etm__clear_packet_queue(&tidq->packet_queue);
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
2348c2ecf20Sopenharmony_ci				      struct cs_etm_traceid_queue *tidq,
2358c2ecf20Sopenharmony_ci				      u8 trace_chan_id)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	int rc = -ENOMEM;
2388c2ecf20Sopenharmony_ci	struct auxtrace_queue *queue;
2398c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *etm = etmq->etm;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	cs_etm__clear_packet_queue(&tidq->packet_queue);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	queue = &etmq->etm->queues.queue_array[etmq->queue_nr];
2448c2ecf20Sopenharmony_ci	tidq->tid = queue->tid;
2458c2ecf20Sopenharmony_ci	tidq->pid = -1;
2468c2ecf20Sopenharmony_ci	tidq->trace_chan_id = trace_chan_id;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	tidq->packet = zalloc(sizeof(struct cs_etm_packet));
2498c2ecf20Sopenharmony_ci	if (!tidq->packet)
2508c2ecf20Sopenharmony_ci		goto out;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	tidq->prev_packet = zalloc(sizeof(struct cs_etm_packet));
2538c2ecf20Sopenharmony_ci	if (!tidq->prev_packet)
2548c2ecf20Sopenharmony_ci		goto out_free;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (etm->synth_opts.last_branch) {
2578c2ecf20Sopenharmony_ci		size_t sz = sizeof(struct branch_stack);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci		sz += etm->synth_opts.last_branch_sz *
2608c2ecf20Sopenharmony_ci		      sizeof(struct branch_entry);
2618c2ecf20Sopenharmony_ci		tidq->last_branch = zalloc(sz);
2628c2ecf20Sopenharmony_ci		if (!tidq->last_branch)
2638c2ecf20Sopenharmony_ci			goto out_free;
2648c2ecf20Sopenharmony_ci		tidq->last_branch_rb = zalloc(sz);
2658c2ecf20Sopenharmony_ci		if (!tidq->last_branch_rb)
2668c2ecf20Sopenharmony_ci			goto out_free;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	tidq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE);
2708c2ecf20Sopenharmony_ci	if (!tidq->event_buf)
2718c2ecf20Sopenharmony_ci		goto out_free;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	return 0;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ciout_free:
2768c2ecf20Sopenharmony_ci	zfree(&tidq->last_branch_rb);
2778c2ecf20Sopenharmony_ci	zfree(&tidq->last_branch);
2788c2ecf20Sopenharmony_ci	zfree(&tidq->prev_packet);
2798c2ecf20Sopenharmony_ci	zfree(&tidq->packet);
2808c2ecf20Sopenharmony_ciout:
2818c2ecf20Sopenharmony_ci	return rc;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic struct cs_etm_traceid_queue
2858c2ecf20Sopenharmony_ci*cs_etm__etmq_get_traceid_queue(struct cs_etm_queue *etmq, u8 trace_chan_id)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	int idx;
2888c2ecf20Sopenharmony_ci	struct int_node *inode;
2898c2ecf20Sopenharmony_ci	struct intlist *traceid_queues_list;
2908c2ecf20Sopenharmony_ci	struct cs_etm_traceid_queue *tidq, **traceid_queues;
2918c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *etm = etmq->etm;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (etm->timeless_decoding)
2948c2ecf20Sopenharmony_ci		trace_chan_id = CS_ETM_PER_THREAD_TRACEID;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	traceid_queues_list = etmq->traceid_queues_list;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	/*
2998c2ecf20Sopenharmony_ci	 * Check if the traceid_queue exist for this traceID by looking
3008c2ecf20Sopenharmony_ci	 * in the queue list.
3018c2ecf20Sopenharmony_ci	 */
3028c2ecf20Sopenharmony_ci	inode = intlist__find(traceid_queues_list, trace_chan_id);
3038c2ecf20Sopenharmony_ci	if (inode) {
3048c2ecf20Sopenharmony_ci		idx = (int)(intptr_t)inode->priv;
3058c2ecf20Sopenharmony_ci		return etmq->traceid_queues[idx];
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	/* We couldn't find a traceid_queue for this traceID, allocate one */
3098c2ecf20Sopenharmony_ci	tidq = malloc(sizeof(*tidq));
3108c2ecf20Sopenharmony_ci	if (!tidq)
3118c2ecf20Sopenharmony_ci		return NULL;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	memset(tidq, 0, sizeof(*tidq));
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	/* Get a valid index for the new traceid_queue */
3168c2ecf20Sopenharmony_ci	idx = intlist__nr_entries(traceid_queues_list);
3178c2ecf20Sopenharmony_ci	/* Memory for the inode is free'ed in cs_etm_free_traceid_queues () */
3188c2ecf20Sopenharmony_ci	inode = intlist__findnew(traceid_queues_list, trace_chan_id);
3198c2ecf20Sopenharmony_ci	if (!inode)
3208c2ecf20Sopenharmony_ci		goto out_free;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/* Associate this traceID with this index */
3238c2ecf20Sopenharmony_ci	inode->priv = (void *)(intptr_t)idx;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	if (cs_etm__init_traceid_queue(etmq, tidq, trace_chan_id))
3268c2ecf20Sopenharmony_ci		goto out_free;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/* Grow the traceid_queues array by one unit */
3298c2ecf20Sopenharmony_ci	traceid_queues = etmq->traceid_queues;
3308c2ecf20Sopenharmony_ci	traceid_queues = reallocarray(traceid_queues,
3318c2ecf20Sopenharmony_ci				      idx + 1,
3328c2ecf20Sopenharmony_ci				      sizeof(*traceid_queues));
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	/*
3358c2ecf20Sopenharmony_ci	 * On failure reallocarray() returns NULL and the original block of
3368c2ecf20Sopenharmony_ci	 * memory is left untouched.
3378c2ecf20Sopenharmony_ci	 */
3388c2ecf20Sopenharmony_ci	if (!traceid_queues)
3398c2ecf20Sopenharmony_ci		goto out_free;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	traceid_queues[idx] = tidq;
3428c2ecf20Sopenharmony_ci	etmq->traceid_queues = traceid_queues;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	return etmq->traceid_queues[idx];
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ciout_free:
3478c2ecf20Sopenharmony_ci	/*
3488c2ecf20Sopenharmony_ci	 * Function intlist__remove() removes the inode from the list
3498c2ecf20Sopenharmony_ci	 * and delete the memory associated to it.
3508c2ecf20Sopenharmony_ci	 */
3518c2ecf20Sopenharmony_ci	intlist__remove(traceid_queues_list, inode);
3528c2ecf20Sopenharmony_ci	free(tidq);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	return NULL;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistruct cs_etm_packet_queue
3588c2ecf20Sopenharmony_ci*cs_etm__etmq_get_packet_queue(struct cs_etm_queue *etmq, u8 trace_chan_id)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	struct cs_etm_traceid_queue *tidq;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
3638c2ecf20Sopenharmony_ci	if (tidq)
3648c2ecf20Sopenharmony_ci		return &tidq->packet_queue;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	return NULL;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic void cs_etm__packet_swap(struct cs_etm_auxtrace *etm,
3708c2ecf20Sopenharmony_ci				struct cs_etm_traceid_queue *tidq)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	struct cs_etm_packet *tmp;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	if (etm->sample_branches || etm->synth_opts.last_branch ||
3758c2ecf20Sopenharmony_ci	    etm->sample_instructions) {
3768c2ecf20Sopenharmony_ci		/*
3778c2ecf20Sopenharmony_ci		 * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
3788c2ecf20Sopenharmony_ci		 * the next incoming packet.
3798c2ecf20Sopenharmony_ci		 */
3808c2ecf20Sopenharmony_ci		tmp = tidq->packet;
3818c2ecf20Sopenharmony_ci		tidq->packet = tidq->prev_packet;
3828c2ecf20Sopenharmony_ci		tidq->prev_packet = tmp;
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic void cs_etm__packet_dump(const char *pkt_string)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	const char *color = PERF_COLOR_BLUE;
3898c2ecf20Sopenharmony_ci	int len = strlen(pkt_string);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	if (len && (pkt_string[len-1] == '\n'))
3928c2ecf20Sopenharmony_ci		color_fprintf(stdout, color, "	%s", pkt_string);
3938c2ecf20Sopenharmony_ci	else
3948c2ecf20Sopenharmony_ci		color_fprintf(stdout, color, "	%s\n", pkt_string);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	fflush(stdout);
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic void cs_etm__set_trace_param_etmv3(struct cs_etm_trace_params *t_params,
4008c2ecf20Sopenharmony_ci					  struct cs_etm_auxtrace *etm, int idx,
4018c2ecf20Sopenharmony_ci					  u32 etmidr)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	u64 **metadata = etm->metadata;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	t_params[idx].protocol = cs_etm__get_v7_protocol_version(etmidr);
4068c2ecf20Sopenharmony_ci	t_params[idx].etmv3.reg_ctrl = metadata[idx][CS_ETM_ETMCR];
4078c2ecf20Sopenharmony_ci	t_params[idx].etmv3.reg_trc_id = metadata[idx][CS_ETM_ETMTRACEIDR];
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cistatic void cs_etm__set_trace_param_etmv4(struct cs_etm_trace_params *t_params,
4118c2ecf20Sopenharmony_ci					  struct cs_etm_auxtrace *etm, int idx)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	u64 **metadata = etm->metadata;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	t_params[idx].protocol = CS_ETM_PROTO_ETMV4i;
4168c2ecf20Sopenharmony_ci	t_params[idx].etmv4.reg_idr0 = metadata[idx][CS_ETMV4_TRCIDR0];
4178c2ecf20Sopenharmony_ci	t_params[idx].etmv4.reg_idr1 = metadata[idx][CS_ETMV4_TRCIDR1];
4188c2ecf20Sopenharmony_ci	t_params[idx].etmv4.reg_idr2 = metadata[idx][CS_ETMV4_TRCIDR2];
4198c2ecf20Sopenharmony_ci	t_params[idx].etmv4.reg_idr8 = metadata[idx][CS_ETMV4_TRCIDR8];
4208c2ecf20Sopenharmony_ci	t_params[idx].etmv4.reg_configr = metadata[idx][CS_ETMV4_TRCCONFIGR];
4218c2ecf20Sopenharmony_ci	t_params[idx].etmv4.reg_traceidr = metadata[idx][CS_ETMV4_TRCTRACEIDR];
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic int cs_etm__init_trace_params(struct cs_etm_trace_params *t_params,
4258c2ecf20Sopenharmony_ci				     struct cs_etm_auxtrace *etm)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	int i;
4288c2ecf20Sopenharmony_ci	u32 etmidr;
4298c2ecf20Sopenharmony_ci	u64 architecture;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	for (i = 0; i < etm->num_cpu; i++) {
4328c2ecf20Sopenharmony_ci		architecture = etm->metadata[i][CS_ETM_MAGIC];
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci		switch (architecture) {
4358c2ecf20Sopenharmony_ci		case __perf_cs_etmv3_magic:
4368c2ecf20Sopenharmony_ci			etmidr = etm->metadata[i][CS_ETM_ETMIDR];
4378c2ecf20Sopenharmony_ci			cs_etm__set_trace_param_etmv3(t_params, etm, i, etmidr);
4388c2ecf20Sopenharmony_ci			break;
4398c2ecf20Sopenharmony_ci		case __perf_cs_etmv4_magic:
4408c2ecf20Sopenharmony_ci			cs_etm__set_trace_param_etmv4(t_params, etm, i);
4418c2ecf20Sopenharmony_ci			break;
4428c2ecf20Sopenharmony_ci		default:
4438c2ecf20Sopenharmony_ci			return -EINVAL;
4448c2ecf20Sopenharmony_ci		}
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	return 0;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic int cs_etm__init_decoder_params(struct cs_etm_decoder_params *d_params,
4518c2ecf20Sopenharmony_ci				       struct cs_etm_queue *etmq,
4528c2ecf20Sopenharmony_ci				       enum cs_etm_decoder_operation mode)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	int ret = -EINVAL;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	if (!(mode < CS_ETM_OPERATION_MAX))
4578c2ecf20Sopenharmony_ci		goto out;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	d_params->packet_printer = cs_etm__packet_dump;
4608c2ecf20Sopenharmony_ci	d_params->operation = mode;
4618c2ecf20Sopenharmony_ci	d_params->data = etmq;
4628c2ecf20Sopenharmony_ci	d_params->formatted = true;
4638c2ecf20Sopenharmony_ci	d_params->fsyncs = false;
4648c2ecf20Sopenharmony_ci	d_params->hsyncs = false;
4658c2ecf20Sopenharmony_ci	d_params->frame_aligned = true;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	ret = 0;
4688c2ecf20Sopenharmony_ciout:
4698c2ecf20Sopenharmony_ci	return ret;
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cistatic void cs_etm__dump_event(struct cs_etm_auxtrace *etm,
4738c2ecf20Sopenharmony_ci			       struct auxtrace_buffer *buffer)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	int ret;
4768c2ecf20Sopenharmony_ci	const char *color = PERF_COLOR_BLUE;
4778c2ecf20Sopenharmony_ci	struct cs_etm_decoder_params d_params;
4788c2ecf20Sopenharmony_ci	struct cs_etm_trace_params *t_params;
4798c2ecf20Sopenharmony_ci	struct cs_etm_decoder *decoder;
4808c2ecf20Sopenharmony_ci	size_t buffer_used = 0;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	fprintf(stdout, "\n");
4838c2ecf20Sopenharmony_ci	color_fprintf(stdout, color,
4848c2ecf20Sopenharmony_ci		     ". ... CoreSight ETM Trace data: size %zu bytes\n",
4858c2ecf20Sopenharmony_ci		     buffer->size);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	/* Use metadata to fill in trace parameters for trace decoder */
4888c2ecf20Sopenharmony_ci	t_params = zalloc(sizeof(*t_params) * etm->num_cpu);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (!t_params)
4918c2ecf20Sopenharmony_ci		return;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	if (cs_etm__init_trace_params(t_params, etm))
4948c2ecf20Sopenharmony_ci		goto out_free;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	/* Set decoder parameters to simply print the trace packets */
4978c2ecf20Sopenharmony_ci	if (cs_etm__init_decoder_params(&d_params, NULL,
4988c2ecf20Sopenharmony_ci					CS_ETM_OPERATION_PRINT))
4998c2ecf20Sopenharmony_ci		goto out_free;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	decoder = cs_etm_decoder__new(etm->num_cpu, &d_params, t_params);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if (!decoder)
5048c2ecf20Sopenharmony_ci		goto out_free;
5058c2ecf20Sopenharmony_ci	do {
5068c2ecf20Sopenharmony_ci		size_t consumed;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci		ret = cs_etm_decoder__process_data_block(
5098c2ecf20Sopenharmony_ci				decoder, buffer->offset,
5108c2ecf20Sopenharmony_ci				&((u8 *)buffer->data)[buffer_used],
5118c2ecf20Sopenharmony_ci				buffer->size - buffer_used, &consumed);
5128c2ecf20Sopenharmony_ci		if (ret)
5138c2ecf20Sopenharmony_ci			break;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci		buffer_used += consumed;
5168c2ecf20Sopenharmony_ci	} while (buffer_used < buffer->size);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	cs_etm_decoder__free(decoder);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ciout_free:
5218c2ecf20Sopenharmony_ci	zfree(&t_params);
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic int cs_etm__flush_events(struct perf_session *session,
5258c2ecf20Sopenharmony_ci				struct perf_tool *tool)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	int ret;
5288c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *etm = container_of(session->auxtrace,
5298c2ecf20Sopenharmony_ci						   struct cs_etm_auxtrace,
5308c2ecf20Sopenharmony_ci						   auxtrace);
5318c2ecf20Sopenharmony_ci	if (dump_trace)
5328c2ecf20Sopenharmony_ci		return 0;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	if (!tool->ordered_events)
5358c2ecf20Sopenharmony_ci		return -EINVAL;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	ret = cs_etm__update_queues(etm);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	if (ret < 0)
5408c2ecf20Sopenharmony_ci		return ret;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	if (etm->timeless_decoding)
5438c2ecf20Sopenharmony_ci		return cs_etm__process_timeless_queues(etm, -1);
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	return cs_etm__process_queues(etm);
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	int idx;
5518c2ecf20Sopenharmony_ci	uintptr_t priv;
5528c2ecf20Sopenharmony_ci	struct int_node *inode, *tmp;
5538c2ecf20Sopenharmony_ci	struct cs_etm_traceid_queue *tidq;
5548c2ecf20Sopenharmony_ci	struct intlist *traceid_queues_list = etmq->traceid_queues_list;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	intlist__for_each_entry_safe(inode, tmp, traceid_queues_list) {
5578c2ecf20Sopenharmony_ci		priv = (uintptr_t)inode->priv;
5588c2ecf20Sopenharmony_ci		idx = priv;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci		/* Free this traceid_queue from the array */
5618c2ecf20Sopenharmony_ci		tidq = etmq->traceid_queues[idx];
5628c2ecf20Sopenharmony_ci		thread__zput(tidq->thread);
5638c2ecf20Sopenharmony_ci		zfree(&tidq->event_buf);
5648c2ecf20Sopenharmony_ci		zfree(&tidq->last_branch);
5658c2ecf20Sopenharmony_ci		zfree(&tidq->last_branch_rb);
5668c2ecf20Sopenharmony_ci		zfree(&tidq->prev_packet);
5678c2ecf20Sopenharmony_ci		zfree(&tidq->packet);
5688c2ecf20Sopenharmony_ci		zfree(&tidq);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		/*
5718c2ecf20Sopenharmony_ci		 * Function intlist__remove() removes the inode from the list
5728c2ecf20Sopenharmony_ci		 * and delete the memory associated to it.
5738c2ecf20Sopenharmony_ci		 */
5748c2ecf20Sopenharmony_ci		intlist__remove(traceid_queues_list, inode);
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	/* Then the RB tree itself */
5788c2ecf20Sopenharmony_ci	intlist__delete(traceid_queues_list);
5798c2ecf20Sopenharmony_ci	etmq->traceid_queues_list = NULL;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	/* finally free the traceid_queues array */
5828c2ecf20Sopenharmony_ci	zfree(&etmq->traceid_queues);
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_cistatic void cs_etm__free_queue(void *priv)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	struct cs_etm_queue *etmq = priv;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	if (!etmq)
5908c2ecf20Sopenharmony_ci		return;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	cs_etm_decoder__free(etmq->decoder);
5938c2ecf20Sopenharmony_ci	cs_etm__free_traceid_queues(etmq);
5948c2ecf20Sopenharmony_ci	free(etmq);
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic void cs_etm__free_events(struct perf_session *session)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	unsigned int i;
6008c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
6018c2ecf20Sopenharmony_ci						   struct cs_etm_auxtrace,
6028c2ecf20Sopenharmony_ci						   auxtrace);
6038c2ecf20Sopenharmony_ci	struct auxtrace_queues *queues = &aux->queues;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	for (i = 0; i < queues->nr_queues; i++) {
6068c2ecf20Sopenharmony_ci		cs_etm__free_queue(queues->queue_array[i].priv);
6078c2ecf20Sopenharmony_ci		queues->queue_array[i].priv = NULL;
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	auxtrace_queues__free(queues);
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic void cs_etm__free(struct perf_session *session)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	int i;
6168c2ecf20Sopenharmony_ci	struct int_node *inode, *tmp;
6178c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
6188c2ecf20Sopenharmony_ci						   struct cs_etm_auxtrace,
6198c2ecf20Sopenharmony_ci						   auxtrace);
6208c2ecf20Sopenharmony_ci	cs_etm__free_events(session);
6218c2ecf20Sopenharmony_ci	session->auxtrace = NULL;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	/* First remove all traceID/metadata nodes for the RB tree */
6248c2ecf20Sopenharmony_ci	intlist__for_each_entry_safe(inode, tmp, traceid_list)
6258c2ecf20Sopenharmony_ci		intlist__remove(traceid_list, inode);
6268c2ecf20Sopenharmony_ci	/* Then the RB tree itself */
6278c2ecf20Sopenharmony_ci	intlist__delete(traceid_list);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	for (i = 0; i < aux->num_cpu; i++)
6308c2ecf20Sopenharmony_ci		zfree(&aux->metadata[i]);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	thread__zput(aux->unknown_thread);
6338c2ecf20Sopenharmony_ci	zfree(&aux->metadata);
6348c2ecf20Sopenharmony_ci	zfree(&aux);
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cistatic bool cs_etm__evsel_is_auxtrace(struct perf_session *session,
6388c2ecf20Sopenharmony_ci				      struct evsel *evsel)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
6418c2ecf20Sopenharmony_ci						   struct cs_etm_auxtrace,
6428c2ecf20Sopenharmony_ci						   auxtrace);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	return evsel->core.attr.type == aux->pmu_type;
6458c2ecf20Sopenharmony_ci}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_cistatic u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address)
6488c2ecf20Sopenharmony_ci{
6498c2ecf20Sopenharmony_ci	struct machine *machine;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	machine = etmq->etm->machine;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if (address >= etmq->etm->kernel_start) {
6548c2ecf20Sopenharmony_ci		if (machine__is_host(machine))
6558c2ecf20Sopenharmony_ci			return PERF_RECORD_MISC_KERNEL;
6568c2ecf20Sopenharmony_ci		else
6578c2ecf20Sopenharmony_ci			return PERF_RECORD_MISC_GUEST_KERNEL;
6588c2ecf20Sopenharmony_ci	} else {
6598c2ecf20Sopenharmony_ci		if (machine__is_host(machine))
6608c2ecf20Sopenharmony_ci			return PERF_RECORD_MISC_USER;
6618c2ecf20Sopenharmony_ci		else if (perf_guest)
6628c2ecf20Sopenharmony_ci			return PERF_RECORD_MISC_GUEST_USER;
6638c2ecf20Sopenharmony_ci		else
6648c2ecf20Sopenharmony_ci			return PERF_RECORD_MISC_HYPERVISOR;
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
6698c2ecf20Sopenharmony_ci			      u64 address, size_t size, u8 *buffer)
6708c2ecf20Sopenharmony_ci{
6718c2ecf20Sopenharmony_ci	u8  cpumode;
6728c2ecf20Sopenharmony_ci	u64 offset;
6738c2ecf20Sopenharmony_ci	int len;
6748c2ecf20Sopenharmony_ci	struct thread *thread;
6758c2ecf20Sopenharmony_ci	struct machine *machine;
6768c2ecf20Sopenharmony_ci	struct addr_location al;
6778c2ecf20Sopenharmony_ci	struct cs_etm_traceid_queue *tidq;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	if (!etmq)
6808c2ecf20Sopenharmony_ci		return 0;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	machine = etmq->etm->machine;
6838c2ecf20Sopenharmony_ci	cpumode = cs_etm__cpu_mode(etmq, address);
6848c2ecf20Sopenharmony_ci	tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
6858c2ecf20Sopenharmony_ci	if (!tidq)
6868c2ecf20Sopenharmony_ci		return 0;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	thread = tidq->thread;
6898c2ecf20Sopenharmony_ci	if (!thread) {
6908c2ecf20Sopenharmony_ci		if (cpumode != PERF_RECORD_MISC_KERNEL)
6918c2ecf20Sopenharmony_ci			return 0;
6928c2ecf20Sopenharmony_ci		thread = etmq->etm->unknown_thread;
6938c2ecf20Sopenharmony_ci	}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	if (!thread__find_map(thread, cpumode, address, &al) || !al.map->dso)
6968c2ecf20Sopenharmony_ci		return 0;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR &&
6998c2ecf20Sopenharmony_ci	    dso__data_status_seen(al.map->dso, DSO_DATA_STATUS_SEEN_ITRACE))
7008c2ecf20Sopenharmony_ci		return 0;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	offset = al.map->map_ip(al.map, address);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	map__load(al.map);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	len = dso__data_read_offset(al.map->dso, machine, offset, buffer, size);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	if (len <= 0)
7098c2ecf20Sopenharmony_ci		return 0;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	return len;
7128c2ecf20Sopenharmony_ci}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_cistatic struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	struct cs_etm_decoder_params d_params;
7178c2ecf20Sopenharmony_ci	struct cs_etm_trace_params  *t_params = NULL;
7188c2ecf20Sopenharmony_ci	struct cs_etm_queue *etmq;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	etmq = zalloc(sizeof(*etmq));
7218c2ecf20Sopenharmony_ci	if (!etmq)
7228c2ecf20Sopenharmony_ci		return NULL;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	etmq->traceid_queues_list = intlist__new(NULL);
7258c2ecf20Sopenharmony_ci	if (!etmq->traceid_queues_list)
7268c2ecf20Sopenharmony_ci		goto out_free;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	/* Use metadata to fill in trace parameters for trace decoder */
7298c2ecf20Sopenharmony_ci	t_params = zalloc(sizeof(*t_params) * etm->num_cpu);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	if (!t_params)
7328c2ecf20Sopenharmony_ci		goto out_free;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	if (cs_etm__init_trace_params(t_params, etm))
7358c2ecf20Sopenharmony_ci		goto out_free;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	/* Set decoder parameters to decode trace packets */
7388c2ecf20Sopenharmony_ci	if (cs_etm__init_decoder_params(&d_params, etmq,
7398c2ecf20Sopenharmony_ci					CS_ETM_OPERATION_DECODE))
7408c2ecf20Sopenharmony_ci		goto out_free;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	etmq->decoder = cs_etm_decoder__new(etm->num_cpu, &d_params, t_params);
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	if (!etmq->decoder)
7458c2ecf20Sopenharmony_ci		goto out_free;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	/*
7488c2ecf20Sopenharmony_ci	 * Register a function to handle all memory accesses required by
7498c2ecf20Sopenharmony_ci	 * the trace decoder library.
7508c2ecf20Sopenharmony_ci	 */
7518c2ecf20Sopenharmony_ci	if (cs_etm_decoder__add_mem_access_cb(etmq->decoder,
7528c2ecf20Sopenharmony_ci					      0x0L, ((u64) -1L),
7538c2ecf20Sopenharmony_ci					      cs_etm__mem_access))
7548c2ecf20Sopenharmony_ci		goto out_free_decoder;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	zfree(&t_params);
7578c2ecf20Sopenharmony_ci	return etmq;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ciout_free_decoder:
7608c2ecf20Sopenharmony_ci	cs_etm_decoder__free(etmq->decoder);
7618c2ecf20Sopenharmony_ciout_free:
7628c2ecf20Sopenharmony_ci	intlist__delete(etmq->traceid_queues_list);
7638c2ecf20Sopenharmony_ci	free(etmq);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	return NULL;
7668c2ecf20Sopenharmony_ci}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_cistatic int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
7698c2ecf20Sopenharmony_ci			       struct auxtrace_queue *queue,
7708c2ecf20Sopenharmony_ci			       unsigned int queue_nr)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	int ret = 0;
7738c2ecf20Sopenharmony_ci	unsigned int cs_queue_nr;
7748c2ecf20Sopenharmony_ci	u8 trace_chan_id;
7758c2ecf20Sopenharmony_ci	u64 timestamp;
7768c2ecf20Sopenharmony_ci	struct cs_etm_queue *etmq = queue->priv;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	if (list_empty(&queue->head) || etmq)
7798c2ecf20Sopenharmony_ci		goto out;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	etmq = cs_etm__alloc_queue(etm);
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	if (!etmq) {
7848c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7858c2ecf20Sopenharmony_ci		goto out;
7868c2ecf20Sopenharmony_ci	}
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	queue->priv = etmq;
7898c2ecf20Sopenharmony_ci	etmq->etm = etm;
7908c2ecf20Sopenharmony_ci	etmq->queue_nr = queue_nr;
7918c2ecf20Sopenharmony_ci	etmq->offset = 0;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	if (etm->timeless_decoding)
7948c2ecf20Sopenharmony_ci		goto out;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	/*
7978c2ecf20Sopenharmony_ci	 * We are under a CPU-wide trace scenario.  As such we need to know
7988c2ecf20Sopenharmony_ci	 * when the code that generated the traces started to execute so that
7998c2ecf20Sopenharmony_ci	 * it can be correlated with execution on other CPUs.  So we get a
8008c2ecf20Sopenharmony_ci	 * handle on the beginning of traces and decode until we find a
8018c2ecf20Sopenharmony_ci	 * timestamp.  The timestamp is then added to the auxtrace min heap
8028c2ecf20Sopenharmony_ci	 * in order to know what nibble (of all the etmqs) to decode first.
8038c2ecf20Sopenharmony_ci	 */
8048c2ecf20Sopenharmony_ci	while (1) {
8058c2ecf20Sopenharmony_ci		/*
8068c2ecf20Sopenharmony_ci		 * Fetch an aux_buffer from this etmq.  Bail if no more
8078c2ecf20Sopenharmony_ci		 * blocks or an error has been encountered.
8088c2ecf20Sopenharmony_ci		 */
8098c2ecf20Sopenharmony_ci		ret = cs_etm__get_data_block(etmq);
8108c2ecf20Sopenharmony_ci		if (ret <= 0)
8118c2ecf20Sopenharmony_ci			goto out;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci		/*
8148c2ecf20Sopenharmony_ci		 * Run decoder on the trace block.  The decoder will stop when
8158c2ecf20Sopenharmony_ci		 * encountering a timestamp, a full packet queue or the end of
8168c2ecf20Sopenharmony_ci		 * trace for that block.
8178c2ecf20Sopenharmony_ci		 */
8188c2ecf20Sopenharmony_ci		ret = cs_etm__decode_data_block(etmq);
8198c2ecf20Sopenharmony_ci		if (ret)
8208c2ecf20Sopenharmony_ci			goto out;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci		/*
8238c2ecf20Sopenharmony_ci		 * Function cs_etm_decoder__do_{hard|soft}_timestamp() does all
8248c2ecf20Sopenharmony_ci		 * the timestamp calculation for us.
8258c2ecf20Sopenharmony_ci		 */
8268c2ecf20Sopenharmony_ci		timestamp = cs_etm__etmq_get_timestamp(etmq, &trace_chan_id);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci		/* We found a timestamp, no need to continue. */
8298c2ecf20Sopenharmony_ci		if (timestamp)
8308c2ecf20Sopenharmony_ci			break;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci		/*
8338c2ecf20Sopenharmony_ci		 * We didn't find a timestamp so empty all the traceid packet
8348c2ecf20Sopenharmony_ci		 * queues before looking for another timestamp packet, either
8358c2ecf20Sopenharmony_ci		 * in the current data block or a new one.  Packets that were
8368c2ecf20Sopenharmony_ci		 * just decoded are useless since no timestamp has been
8378c2ecf20Sopenharmony_ci		 * associated with them.  As such simply discard them.
8388c2ecf20Sopenharmony_ci		 */
8398c2ecf20Sopenharmony_ci		cs_etm__clear_all_packet_queues(etmq);
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	/*
8438c2ecf20Sopenharmony_ci	 * We have a timestamp.  Add it to the min heap to reflect when
8448c2ecf20Sopenharmony_ci	 * instructions conveyed by the range packets of this traceID queue
8458c2ecf20Sopenharmony_ci	 * started to execute.  Once the same has been done for all the traceID
8468c2ecf20Sopenharmony_ci	 * queues of each etmq, redenring and decoding can start in
8478c2ecf20Sopenharmony_ci	 * chronological order.
8488c2ecf20Sopenharmony_ci	 *
8498c2ecf20Sopenharmony_ci	 * Note that packets decoded above are still in the traceID's packet
8508c2ecf20Sopenharmony_ci	 * queue and will be processed in cs_etm__process_queues().
8518c2ecf20Sopenharmony_ci	 */
8528c2ecf20Sopenharmony_ci	cs_queue_nr = TO_CS_QUEUE_NR(queue_nr, trace_chan_id);
8538c2ecf20Sopenharmony_ci	ret = auxtrace_heap__add(&etm->heap, cs_queue_nr, timestamp);
8548c2ecf20Sopenharmony_ciout:
8558c2ecf20Sopenharmony_ci	return ret;
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cistatic int cs_etm__setup_queues(struct cs_etm_auxtrace *etm)
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	unsigned int i;
8618c2ecf20Sopenharmony_ci	int ret;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	if (!etm->kernel_start)
8648c2ecf20Sopenharmony_ci		etm->kernel_start = machine__kernel_start(etm->machine);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	for (i = 0; i < etm->queues.nr_queues; i++) {
8678c2ecf20Sopenharmony_ci		ret = cs_etm__setup_queue(etm, &etm->queues.queue_array[i], i);
8688c2ecf20Sopenharmony_ci		if (ret)
8698c2ecf20Sopenharmony_ci			return ret;
8708c2ecf20Sopenharmony_ci	}
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	return 0;
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cistatic int cs_etm__update_queues(struct cs_etm_auxtrace *etm)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	if (etm->queues.new_data) {
8788c2ecf20Sopenharmony_ci		etm->queues.new_data = false;
8798c2ecf20Sopenharmony_ci		return cs_etm__setup_queues(etm);
8808c2ecf20Sopenharmony_ci	}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	return 0;
8838c2ecf20Sopenharmony_ci}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_cistatic inline
8868c2ecf20Sopenharmony_civoid cs_etm__copy_last_branch_rb(struct cs_etm_queue *etmq,
8878c2ecf20Sopenharmony_ci				 struct cs_etm_traceid_queue *tidq)
8888c2ecf20Sopenharmony_ci{
8898c2ecf20Sopenharmony_ci	struct branch_stack *bs_src = tidq->last_branch_rb;
8908c2ecf20Sopenharmony_ci	struct branch_stack *bs_dst = tidq->last_branch;
8918c2ecf20Sopenharmony_ci	size_t nr = 0;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	/*
8948c2ecf20Sopenharmony_ci	 * Set the number of records before early exit: ->nr is used to
8958c2ecf20Sopenharmony_ci	 * determine how many branches to copy from ->entries.
8968c2ecf20Sopenharmony_ci	 */
8978c2ecf20Sopenharmony_ci	bs_dst->nr = bs_src->nr;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	/*
9008c2ecf20Sopenharmony_ci	 * Early exit when there is nothing to copy.
9018c2ecf20Sopenharmony_ci	 */
9028c2ecf20Sopenharmony_ci	if (!bs_src->nr)
9038c2ecf20Sopenharmony_ci		return;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	/*
9068c2ecf20Sopenharmony_ci	 * As bs_src->entries is a circular buffer, we need to copy from it in
9078c2ecf20Sopenharmony_ci	 * two steps.  First, copy the branches from the most recently inserted
9088c2ecf20Sopenharmony_ci	 * branch ->last_branch_pos until the end of bs_src->entries buffer.
9098c2ecf20Sopenharmony_ci	 */
9108c2ecf20Sopenharmony_ci	nr = etmq->etm->synth_opts.last_branch_sz - tidq->last_branch_pos;
9118c2ecf20Sopenharmony_ci	memcpy(&bs_dst->entries[0],
9128c2ecf20Sopenharmony_ci	       &bs_src->entries[tidq->last_branch_pos],
9138c2ecf20Sopenharmony_ci	       sizeof(struct branch_entry) * nr);
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	/*
9168c2ecf20Sopenharmony_ci	 * If we wrapped around at least once, the branches from the beginning
9178c2ecf20Sopenharmony_ci	 * of the bs_src->entries buffer and until the ->last_branch_pos element
9188c2ecf20Sopenharmony_ci	 * are older valid branches: copy them over.  The total number of
9198c2ecf20Sopenharmony_ci	 * branches copied over will be equal to the number of branches asked by
9208c2ecf20Sopenharmony_ci	 * the user in last_branch_sz.
9218c2ecf20Sopenharmony_ci	 */
9228c2ecf20Sopenharmony_ci	if (bs_src->nr >= etmq->etm->synth_opts.last_branch_sz) {
9238c2ecf20Sopenharmony_ci		memcpy(&bs_dst->entries[nr],
9248c2ecf20Sopenharmony_ci		       &bs_src->entries[0],
9258c2ecf20Sopenharmony_ci		       sizeof(struct branch_entry) * tidq->last_branch_pos);
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_cistatic inline
9308c2ecf20Sopenharmony_civoid cs_etm__reset_last_branch_rb(struct cs_etm_traceid_queue *tidq)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	tidq->last_branch_pos = 0;
9338c2ecf20Sopenharmony_ci	tidq->last_branch_rb->nr = 0;
9348c2ecf20Sopenharmony_ci}
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_cistatic inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq,
9378c2ecf20Sopenharmony_ci					 u8 trace_chan_id, u64 addr)
9388c2ecf20Sopenharmony_ci{
9398c2ecf20Sopenharmony_ci	u8 instrBytes[2];
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	cs_etm__mem_access(etmq, trace_chan_id, addr,
9428c2ecf20Sopenharmony_ci			   ARRAY_SIZE(instrBytes), instrBytes);
9438c2ecf20Sopenharmony_ci	/*
9448c2ecf20Sopenharmony_ci	 * T32 instruction size is indicated by bits[15:11] of the first
9458c2ecf20Sopenharmony_ci	 * 16-bit word of the instruction: 0b11101, 0b11110 and 0b11111
9468c2ecf20Sopenharmony_ci	 * denote a 32-bit instruction.
9478c2ecf20Sopenharmony_ci	 */
9488c2ecf20Sopenharmony_ci	return ((instrBytes[1] & 0xF8) >= 0xE8) ? 4 : 2;
9498c2ecf20Sopenharmony_ci}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_cistatic inline u64 cs_etm__first_executed_instr(struct cs_etm_packet *packet)
9528c2ecf20Sopenharmony_ci{
9538c2ecf20Sopenharmony_ci	/* Returns 0 for the CS_ETM_DISCONTINUITY packet */
9548c2ecf20Sopenharmony_ci	if (packet->sample_type == CS_ETM_DISCONTINUITY)
9558c2ecf20Sopenharmony_ci		return 0;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	return packet->start_addr;
9588c2ecf20Sopenharmony_ci}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_cistatic inline
9618c2ecf20Sopenharmony_ciu64 cs_etm__last_executed_instr(const struct cs_etm_packet *packet)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	/* Returns 0 for the CS_ETM_DISCONTINUITY packet */
9648c2ecf20Sopenharmony_ci	if (packet->sample_type == CS_ETM_DISCONTINUITY)
9658c2ecf20Sopenharmony_ci		return 0;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	return packet->end_addr - packet->last_instr_size;
9688c2ecf20Sopenharmony_ci}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_cistatic inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq,
9718c2ecf20Sopenharmony_ci				     u64 trace_chan_id,
9728c2ecf20Sopenharmony_ci				     const struct cs_etm_packet *packet,
9738c2ecf20Sopenharmony_ci				     u64 offset)
9748c2ecf20Sopenharmony_ci{
9758c2ecf20Sopenharmony_ci	if (packet->isa == CS_ETM_ISA_T32) {
9768c2ecf20Sopenharmony_ci		u64 addr = packet->start_addr;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci		while (offset) {
9798c2ecf20Sopenharmony_ci			addr += cs_etm__t32_instr_size(etmq,
9808c2ecf20Sopenharmony_ci						       trace_chan_id, addr);
9818c2ecf20Sopenharmony_ci			offset--;
9828c2ecf20Sopenharmony_ci		}
9838c2ecf20Sopenharmony_ci		return addr;
9848c2ecf20Sopenharmony_ci	}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	/* Assume a 4 byte instruction size (A32/A64) */
9878c2ecf20Sopenharmony_ci	return packet->start_addr + offset * 4;
9888c2ecf20Sopenharmony_ci}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_cistatic void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq,
9918c2ecf20Sopenharmony_ci					  struct cs_etm_traceid_queue *tidq)
9928c2ecf20Sopenharmony_ci{
9938c2ecf20Sopenharmony_ci	struct branch_stack *bs = tidq->last_branch_rb;
9948c2ecf20Sopenharmony_ci	struct branch_entry *be;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	/*
9978c2ecf20Sopenharmony_ci	 * The branches are recorded in a circular buffer in reverse
9988c2ecf20Sopenharmony_ci	 * chronological order: we start recording from the last element of the
9998c2ecf20Sopenharmony_ci	 * buffer down.  After writing the first element of the stack, move the
10008c2ecf20Sopenharmony_ci	 * insert position back to the end of the buffer.
10018c2ecf20Sopenharmony_ci	 */
10028c2ecf20Sopenharmony_ci	if (!tidq->last_branch_pos)
10038c2ecf20Sopenharmony_ci		tidq->last_branch_pos = etmq->etm->synth_opts.last_branch_sz;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	tidq->last_branch_pos -= 1;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	be       = &bs->entries[tidq->last_branch_pos];
10088c2ecf20Sopenharmony_ci	be->from = cs_etm__last_executed_instr(tidq->prev_packet);
10098c2ecf20Sopenharmony_ci	be->to	 = cs_etm__first_executed_instr(tidq->packet);
10108c2ecf20Sopenharmony_ci	/* No support for mispredict */
10118c2ecf20Sopenharmony_ci	be->flags.mispred = 0;
10128c2ecf20Sopenharmony_ci	be->flags.predicted = 1;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	/*
10158c2ecf20Sopenharmony_ci	 * Increment bs->nr until reaching the number of last branches asked by
10168c2ecf20Sopenharmony_ci	 * the user on the command line.
10178c2ecf20Sopenharmony_ci	 */
10188c2ecf20Sopenharmony_ci	if (bs->nr < etmq->etm->synth_opts.last_branch_sz)
10198c2ecf20Sopenharmony_ci		bs->nr += 1;
10208c2ecf20Sopenharmony_ci}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_cistatic int cs_etm__inject_event(union perf_event *event,
10238c2ecf20Sopenharmony_ci			       struct perf_sample *sample, u64 type)
10248c2ecf20Sopenharmony_ci{
10258c2ecf20Sopenharmony_ci	event->header.size = perf_event__sample_event_size(sample, type, 0);
10268c2ecf20Sopenharmony_ci	return perf_event__synthesize_sample(event, type, 0, sample);
10278c2ecf20Sopenharmony_ci}
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_cistatic int
10318c2ecf20Sopenharmony_cics_etm__get_trace(struct cs_etm_queue *etmq)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	struct auxtrace_buffer *aux_buffer = etmq->buffer;
10348c2ecf20Sopenharmony_ci	struct auxtrace_buffer *old_buffer = aux_buffer;
10358c2ecf20Sopenharmony_ci	struct auxtrace_queue *queue;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	queue = &etmq->etm->queues.queue_array[etmq->queue_nr];
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	aux_buffer = auxtrace_buffer__next(queue, aux_buffer);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	/* If no more data, drop the previous auxtrace_buffer and return */
10428c2ecf20Sopenharmony_ci	if (!aux_buffer) {
10438c2ecf20Sopenharmony_ci		if (old_buffer)
10448c2ecf20Sopenharmony_ci			auxtrace_buffer__drop_data(old_buffer);
10458c2ecf20Sopenharmony_ci		etmq->buf_len = 0;
10468c2ecf20Sopenharmony_ci		return 0;
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	etmq->buffer = aux_buffer;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	/* If the aux_buffer doesn't have data associated, try to load it */
10528c2ecf20Sopenharmony_ci	if (!aux_buffer->data) {
10538c2ecf20Sopenharmony_ci		/* get the file desc associated with the perf data file */
10548c2ecf20Sopenharmony_ci		int fd = perf_data__fd(etmq->etm->session->data);
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci		aux_buffer->data = auxtrace_buffer__get_data(aux_buffer, fd);
10578c2ecf20Sopenharmony_ci		if (!aux_buffer->data)
10588c2ecf20Sopenharmony_ci			return -ENOMEM;
10598c2ecf20Sopenharmony_ci	}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	/* If valid, drop the previous buffer */
10628c2ecf20Sopenharmony_ci	if (old_buffer)
10638c2ecf20Sopenharmony_ci		auxtrace_buffer__drop_data(old_buffer);
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	etmq->buf_used = 0;
10668c2ecf20Sopenharmony_ci	etmq->buf_len = aux_buffer->size;
10678c2ecf20Sopenharmony_ci	etmq->buf = aux_buffer->data;
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	return etmq->buf_len;
10708c2ecf20Sopenharmony_ci}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_cistatic void cs_etm__set_pid_tid_cpu(struct cs_etm_auxtrace *etm,
10738c2ecf20Sopenharmony_ci				    struct cs_etm_traceid_queue *tidq)
10748c2ecf20Sopenharmony_ci{
10758c2ecf20Sopenharmony_ci	if ((!tidq->thread) && (tidq->tid != -1))
10768c2ecf20Sopenharmony_ci		tidq->thread = machine__find_thread(etm->machine, -1,
10778c2ecf20Sopenharmony_ci						    tidq->tid);
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	if (tidq->thread)
10808c2ecf20Sopenharmony_ci		tidq->pid = tidq->thread->pid_;
10818c2ecf20Sopenharmony_ci}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ciint cs_etm__etmq_set_tid(struct cs_etm_queue *etmq,
10848c2ecf20Sopenharmony_ci			 pid_t tid, u8 trace_chan_id)
10858c2ecf20Sopenharmony_ci{
10868c2ecf20Sopenharmony_ci	int cpu, err = -EINVAL;
10878c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *etm = etmq->etm;
10888c2ecf20Sopenharmony_ci	struct cs_etm_traceid_queue *tidq;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
10918c2ecf20Sopenharmony_ci	if (!tidq)
10928c2ecf20Sopenharmony_ci		return err;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	if (cs_etm__get_cpu(trace_chan_id, &cpu) < 0)
10958c2ecf20Sopenharmony_ci		return err;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	err = machine__set_current_tid(etm->machine, cpu, tid, tid);
10988c2ecf20Sopenharmony_ci	if (err)
10998c2ecf20Sopenharmony_ci		return err;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	tidq->tid = tid;
11028c2ecf20Sopenharmony_ci	thread__zput(tidq->thread);
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	cs_etm__set_pid_tid_cpu(etm, tidq);
11058c2ecf20Sopenharmony_ci	return 0;
11068c2ecf20Sopenharmony_ci}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_cibool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq)
11098c2ecf20Sopenharmony_ci{
11108c2ecf20Sopenharmony_ci	return !!etmq->etm->timeless_decoding;
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_cistatic void cs_etm__copy_insn(struct cs_etm_queue *etmq,
11148c2ecf20Sopenharmony_ci			      u64 trace_chan_id,
11158c2ecf20Sopenharmony_ci			      const struct cs_etm_packet *packet,
11168c2ecf20Sopenharmony_ci			      struct perf_sample *sample)
11178c2ecf20Sopenharmony_ci{
11188c2ecf20Sopenharmony_ci	/*
11198c2ecf20Sopenharmony_ci	 * It's pointless to read instructions for the CS_ETM_DISCONTINUITY
11208c2ecf20Sopenharmony_ci	 * packet, so directly bail out with 'insn_len' = 0.
11218c2ecf20Sopenharmony_ci	 */
11228c2ecf20Sopenharmony_ci	if (packet->sample_type == CS_ETM_DISCONTINUITY) {
11238c2ecf20Sopenharmony_ci		sample->insn_len = 0;
11248c2ecf20Sopenharmony_ci		return;
11258c2ecf20Sopenharmony_ci	}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	/*
11288c2ecf20Sopenharmony_ci	 * T32 instruction size might be 32-bit or 16-bit, decide by calling
11298c2ecf20Sopenharmony_ci	 * cs_etm__t32_instr_size().
11308c2ecf20Sopenharmony_ci	 */
11318c2ecf20Sopenharmony_ci	if (packet->isa == CS_ETM_ISA_T32)
11328c2ecf20Sopenharmony_ci		sample->insn_len = cs_etm__t32_instr_size(etmq, trace_chan_id,
11338c2ecf20Sopenharmony_ci							  sample->ip);
11348c2ecf20Sopenharmony_ci	/* Otherwise, A64 and A32 instruction size are always 32-bit. */
11358c2ecf20Sopenharmony_ci	else
11368c2ecf20Sopenharmony_ci		sample->insn_len = 4;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	cs_etm__mem_access(etmq, trace_chan_id, sample->ip,
11398c2ecf20Sopenharmony_ci			   sample->insn_len, (void *)sample->insn);
11408c2ecf20Sopenharmony_ci}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_cistatic int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
11438c2ecf20Sopenharmony_ci					    struct cs_etm_traceid_queue *tidq,
11448c2ecf20Sopenharmony_ci					    u64 addr, u64 period)
11458c2ecf20Sopenharmony_ci{
11468c2ecf20Sopenharmony_ci	int ret = 0;
11478c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *etm = etmq->etm;
11488c2ecf20Sopenharmony_ci	union perf_event *event = tidq->event_buf;
11498c2ecf20Sopenharmony_ci	struct perf_sample sample = {.ip = 0,};
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	event->sample.header.type = PERF_RECORD_SAMPLE;
11528c2ecf20Sopenharmony_ci	event->sample.header.misc = cs_etm__cpu_mode(etmq, addr);
11538c2ecf20Sopenharmony_ci	event->sample.header.size = sizeof(struct perf_event_header);
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	sample.ip = addr;
11568c2ecf20Sopenharmony_ci	sample.pid = tidq->pid;
11578c2ecf20Sopenharmony_ci	sample.tid = tidq->tid;
11588c2ecf20Sopenharmony_ci	sample.id = etmq->etm->instructions_id;
11598c2ecf20Sopenharmony_ci	sample.stream_id = etmq->etm->instructions_id;
11608c2ecf20Sopenharmony_ci	sample.period = period;
11618c2ecf20Sopenharmony_ci	sample.cpu = tidq->packet->cpu;
11628c2ecf20Sopenharmony_ci	sample.flags = tidq->prev_packet->flags;
11638c2ecf20Sopenharmony_ci	sample.cpumode = event->sample.header.misc;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->packet, &sample);
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	if (etm->synth_opts.last_branch)
11688c2ecf20Sopenharmony_ci		sample.branch_stack = tidq->last_branch;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	if (etm->synth_opts.inject) {
11718c2ecf20Sopenharmony_ci		ret = cs_etm__inject_event(event, &sample,
11728c2ecf20Sopenharmony_ci					   etm->instructions_sample_type);
11738c2ecf20Sopenharmony_ci		if (ret)
11748c2ecf20Sopenharmony_ci			return ret;
11758c2ecf20Sopenharmony_ci	}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	ret = perf_session__deliver_synth_event(etm->session, event, &sample);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	if (ret)
11808c2ecf20Sopenharmony_ci		pr_err(
11818c2ecf20Sopenharmony_ci			"CS ETM Trace: failed to deliver instruction event, error %d\n",
11828c2ecf20Sopenharmony_ci			ret);
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	return ret;
11858c2ecf20Sopenharmony_ci}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci/*
11888c2ecf20Sopenharmony_ci * The cs etm packet encodes an instruction range between a branch target
11898c2ecf20Sopenharmony_ci * and the next taken branch. Generate sample accordingly.
11908c2ecf20Sopenharmony_ci */
11918c2ecf20Sopenharmony_cistatic int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
11928c2ecf20Sopenharmony_ci				       struct cs_etm_traceid_queue *tidq)
11938c2ecf20Sopenharmony_ci{
11948c2ecf20Sopenharmony_ci	int ret = 0;
11958c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *etm = etmq->etm;
11968c2ecf20Sopenharmony_ci	struct perf_sample sample = {.ip = 0,};
11978c2ecf20Sopenharmony_ci	union perf_event *event = tidq->event_buf;
11988c2ecf20Sopenharmony_ci	struct dummy_branch_stack {
11998c2ecf20Sopenharmony_ci		u64			nr;
12008c2ecf20Sopenharmony_ci		u64			hw_idx;
12018c2ecf20Sopenharmony_ci		struct branch_entry	entries;
12028c2ecf20Sopenharmony_ci	} dummy_bs;
12038c2ecf20Sopenharmony_ci	u64 ip;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	ip = cs_etm__last_executed_instr(tidq->prev_packet);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	event->sample.header.type = PERF_RECORD_SAMPLE;
12088c2ecf20Sopenharmony_ci	event->sample.header.misc = cs_etm__cpu_mode(etmq, ip);
12098c2ecf20Sopenharmony_ci	event->sample.header.size = sizeof(struct perf_event_header);
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	sample.ip = ip;
12128c2ecf20Sopenharmony_ci	sample.pid = tidq->pid;
12138c2ecf20Sopenharmony_ci	sample.tid = tidq->tid;
12148c2ecf20Sopenharmony_ci	sample.addr = cs_etm__first_executed_instr(tidq->packet);
12158c2ecf20Sopenharmony_ci	sample.id = etmq->etm->branches_id;
12168c2ecf20Sopenharmony_ci	sample.stream_id = etmq->etm->branches_id;
12178c2ecf20Sopenharmony_ci	sample.period = 1;
12188c2ecf20Sopenharmony_ci	sample.cpu = tidq->packet->cpu;
12198c2ecf20Sopenharmony_ci	sample.flags = tidq->prev_packet->flags;
12208c2ecf20Sopenharmony_ci	sample.cpumode = event->sample.header.misc;
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->prev_packet,
12238c2ecf20Sopenharmony_ci			  &sample);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	/*
12268c2ecf20Sopenharmony_ci	 * perf report cannot handle events without a branch stack
12278c2ecf20Sopenharmony_ci	 */
12288c2ecf20Sopenharmony_ci	if (etm->synth_opts.last_branch) {
12298c2ecf20Sopenharmony_ci		dummy_bs = (struct dummy_branch_stack){
12308c2ecf20Sopenharmony_ci			.nr = 1,
12318c2ecf20Sopenharmony_ci			.hw_idx = -1ULL,
12328c2ecf20Sopenharmony_ci			.entries = {
12338c2ecf20Sopenharmony_ci				.from = sample.ip,
12348c2ecf20Sopenharmony_ci				.to = sample.addr,
12358c2ecf20Sopenharmony_ci			},
12368c2ecf20Sopenharmony_ci		};
12378c2ecf20Sopenharmony_ci		sample.branch_stack = (struct branch_stack *)&dummy_bs;
12388c2ecf20Sopenharmony_ci	}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	if (etm->synth_opts.inject) {
12418c2ecf20Sopenharmony_ci		ret = cs_etm__inject_event(event, &sample,
12428c2ecf20Sopenharmony_ci					   etm->branches_sample_type);
12438c2ecf20Sopenharmony_ci		if (ret)
12448c2ecf20Sopenharmony_ci			return ret;
12458c2ecf20Sopenharmony_ci	}
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	ret = perf_session__deliver_synth_event(etm->session, event, &sample);
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	if (ret)
12508c2ecf20Sopenharmony_ci		pr_err(
12518c2ecf20Sopenharmony_ci		"CS ETM Trace: failed to deliver instruction event, error %d\n",
12528c2ecf20Sopenharmony_ci		ret);
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	return ret;
12558c2ecf20Sopenharmony_ci}
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_cistruct cs_etm_synth {
12588c2ecf20Sopenharmony_ci	struct perf_tool dummy_tool;
12598c2ecf20Sopenharmony_ci	struct perf_session *session;
12608c2ecf20Sopenharmony_ci};
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_cistatic int cs_etm__event_synth(struct perf_tool *tool,
12638c2ecf20Sopenharmony_ci			       union perf_event *event,
12648c2ecf20Sopenharmony_ci			       struct perf_sample *sample __maybe_unused,
12658c2ecf20Sopenharmony_ci			       struct machine *machine __maybe_unused)
12668c2ecf20Sopenharmony_ci{
12678c2ecf20Sopenharmony_ci	struct cs_etm_synth *cs_etm_synth =
12688c2ecf20Sopenharmony_ci		      container_of(tool, struct cs_etm_synth, dummy_tool);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	return perf_session__deliver_synth_event(cs_etm_synth->session,
12718c2ecf20Sopenharmony_ci						 event, NULL);
12728c2ecf20Sopenharmony_ci}
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_cistatic int cs_etm__synth_event(struct perf_session *session,
12758c2ecf20Sopenharmony_ci			       struct perf_event_attr *attr, u64 id)
12768c2ecf20Sopenharmony_ci{
12778c2ecf20Sopenharmony_ci	struct cs_etm_synth cs_etm_synth;
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	memset(&cs_etm_synth, 0, sizeof(struct cs_etm_synth));
12808c2ecf20Sopenharmony_ci	cs_etm_synth.session = session;
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	return perf_event__synthesize_attr(&cs_etm_synth.dummy_tool, attr, 1,
12838c2ecf20Sopenharmony_ci					   &id, cs_etm__event_synth);
12848c2ecf20Sopenharmony_ci}
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_cistatic int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
12878c2ecf20Sopenharmony_ci				struct perf_session *session)
12888c2ecf20Sopenharmony_ci{
12898c2ecf20Sopenharmony_ci	struct evlist *evlist = session->evlist;
12908c2ecf20Sopenharmony_ci	struct evsel *evsel;
12918c2ecf20Sopenharmony_ci	struct perf_event_attr attr;
12928c2ecf20Sopenharmony_ci	bool found = false;
12938c2ecf20Sopenharmony_ci	u64 id;
12948c2ecf20Sopenharmony_ci	int err;
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
12978c2ecf20Sopenharmony_ci		if (evsel->core.attr.type == etm->pmu_type) {
12988c2ecf20Sopenharmony_ci			found = true;
12998c2ecf20Sopenharmony_ci			break;
13008c2ecf20Sopenharmony_ci		}
13018c2ecf20Sopenharmony_ci	}
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	if (!found) {
13048c2ecf20Sopenharmony_ci		pr_debug("No selected events with CoreSight Trace data\n");
13058c2ecf20Sopenharmony_ci		return 0;
13068c2ecf20Sopenharmony_ci	}
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	memset(&attr, 0, sizeof(struct perf_event_attr));
13098c2ecf20Sopenharmony_ci	attr.size = sizeof(struct perf_event_attr);
13108c2ecf20Sopenharmony_ci	attr.type = PERF_TYPE_HARDWARE;
13118c2ecf20Sopenharmony_ci	attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK;
13128c2ecf20Sopenharmony_ci	attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID |
13138c2ecf20Sopenharmony_ci			    PERF_SAMPLE_PERIOD;
13148c2ecf20Sopenharmony_ci	if (etm->timeless_decoding)
13158c2ecf20Sopenharmony_ci		attr.sample_type &= ~(u64)PERF_SAMPLE_TIME;
13168c2ecf20Sopenharmony_ci	else
13178c2ecf20Sopenharmony_ci		attr.sample_type |= PERF_SAMPLE_TIME;
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	attr.exclude_user = evsel->core.attr.exclude_user;
13208c2ecf20Sopenharmony_ci	attr.exclude_kernel = evsel->core.attr.exclude_kernel;
13218c2ecf20Sopenharmony_ci	attr.exclude_hv = evsel->core.attr.exclude_hv;
13228c2ecf20Sopenharmony_ci	attr.exclude_host = evsel->core.attr.exclude_host;
13238c2ecf20Sopenharmony_ci	attr.exclude_guest = evsel->core.attr.exclude_guest;
13248c2ecf20Sopenharmony_ci	attr.sample_id_all = evsel->core.attr.sample_id_all;
13258c2ecf20Sopenharmony_ci	attr.read_format = evsel->core.attr.read_format;
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	/* create new id val to be a fixed offset from evsel id */
13288c2ecf20Sopenharmony_ci	id = evsel->core.id[0] + 1000000000;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	if (!id)
13318c2ecf20Sopenharmony_ci		id = 1;
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	if (etm->synth_opts.branches) {
13348c2ecf20Sopenharmony_ci		attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
13358c2ecf20Sopenharmony_ci		attr.sample_period = 1;
13368c2ecf20Sopenharmony_ci		attr.sample_type |= PERF_SAMPLE_ADDR;
13378c2ecf20Sopenharmony_ci		err = cs_etm__synth_event(session, &attr, id);
13388c2ecf20Sopenharmony_ci		if (err)
13398c2ecf20Sopenharmony_ci			return err;
13408c2ecf20Sopenharmony_ci		etm->sample_branches = true;
13418c2ecf20Sopenharmony_ci		etm->branches_sample_type = attr.sample_type;
13428c2ecf20Sopenharmony_ci		etm->branches_id = id;
13438c2ecf20Sopenharmony_ci		id += 1;
13448c2ecf20Sopenharmony_ci		attr.sample_type &= ~(u64)PERF_SAMPLE_ADDR;
13458c2ecf20Sopenharmony_ci	}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	if (etm->synth_opts.last_branch) {
13488c2ecf20Sopenharmony_ci		attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
13498c2ecf20Sopenharmony_ci		/*
13508c2ecf20Sopenharmony_ci		 * We don't use the hardware index, but the sample generation
13518c2ecf20Sopenharmony_ci		 * code uses the new format branch_stack with this field,
13528c2ecf20Sopenharmony_ci		 * so the event attributes must indicate that it's present.
13538c2ecf20Sopenharmony_ci		 */
13548c2ecf20Sopenharmony_ci		attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
13558c2ecf20Sopenharmony_ci	}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	if (etm->synth_opts.instructions) {
13588c2ecf20Sopenharmony_ci		attr.config = PERF_COUNT_HW_INSTRUCTIONS;
13598c2ecf20Sopenharmony_ci		attr.sample_period = etm->synth_opts.period;
13608c2ecf20Sopenharmony_ci		etm->instructions_sample_period = attr.sample_period;
13618c2ecf20Sopenharmony_ci		err = cs_etm__synth_event(session, &attr, id);
13628c2ecf20Sopenharmony_ci		if (err)
13638c2ecf20Sopenharmony_ci			return err;
13648c2ecf20Sopenharmony_ci		etm->sample_instructions = true;
13658c2ecf20Sopenharmony_ci		etm->instructions_sample_type = attr.sample_type;
13668c2ecf20Sopenharmony_ci		etm->instructions_id = id;
13678c2ecf20Sopenharmony_ci		id += 1;
13688c2ecf20Sopenharmony_ci	}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	return 0;
13718c2ecf20Sopenharmony_ci}
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_cistatic int cs_etm__sample(struct cs_etm_queue *etmq,
13748c2ecf20Sopenharmony_ci			  struct cs_etm_traceid_queue *tidq)
13758c2ecf20Sopenharmony_ci{
13768c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *etm = etmq->etm;
13778c2ecf20Sopenharmony_ci	int ret;
13788c2ecf20Sopenharmony_ci	u8 trace_chan_id = tidq->trace_chan_id;
13798c2ecf20Sopenharmony_ci	u64 instrs_prev;
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	/* Get instructions remainder from previous packet */
13828c2ecf20Sopenharmony_ci	instrs_prev = tidq->period_instructions;
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	tidq->period_instructions += tidq->packet->instr_count;
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	/*
13878c2ecf20Sopenharmony_ci	 * Record a branch when the last instruction in
13888c2ecf20Sopenharmony_ci	 * PREV_PACKET is a branch.
13898c2ecf20Sopenharmony_ci	 */
13908c2ecf20Sopenharmony_ci	if (etm->synth_opts.last_branch &&
13918c2ecf20Sopenharmony_ci	    tidq->prev_packet->sample_type == CS_ETM_RANGE &&
13928c2ecf20Sopenharmony_ci	    tidq->prev_packet->last_instr_taken_branch)
13938c2ecf20Sopenharmony_ci		cs_etm__update_last_branch_rb(etmq, tidq);
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	if (etm->sample_instructions &&
13968c2ecf20Sopenharmony_ci	    tidq->period_instructions >= etm->instructions_sample_period) {
13978c2ecf20Sopenharmony_ci		/*
13988c2ecf20Sopenharmony_ci		 * Emit instruction sample periodically
13998c2ecf20Sopenharmony_ci		 * TODO: allow period to be defined in cycles and clock time
14008c2ecf20Sopenharmony_ci		 */
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci		/*
14038c2ecf20Sopenharmony_ci		 * Below diagram demonstrates the instruction samples
14048c2ecf20Sopenharmony_ci		 * generation flows:
14058c2ecf20Sopenharmony_ci		 *
14068c2ecf20Sopenharmony_ci		 *    Instrs     Instrs       Instrs       Instrs
14078c2ecf20Sopenharmony_ci		 *   Sample(n)  Sample(n+1)  Sample(n+2)  Sample(n+3)
14088c2ecf20Sopenharmony_ci		 *    |            |            |            |
14098c2ecf20Sopenharmony_ci		 *    V            V            V            V
14108c2ecf20Sopenharmony_ci		 *   --------------------------------------------------
14118c2ecf20Sopenharmony_ci		 *            ^                                  ^
14128c2ecf20Sopenharmony_ci		 *            |                                  |
14138c2ecf20Sopenharmony_ci		 *         Period                             Period
14148c2ecf20Sopenharmony_ci		 *    instructions(Pi)                   instructions(Pi')
14158c2ecf20Sopenharmony_ci		 *
14168c2ecf20Sopenharmony_ci		 *            |                                  |
14178c2ecf20Sopenharmony_ci		 *            \---------------- -----------------/
14188c2ecf20Sopenharmony_ci		 *                             V
14198c2ecf20Sopenharmony_ci		 *                 tidq->packet->instr_count
14208c2ecf20Sopenharmony_ci		 *
14218c2ecf20Sopenharmony_ci		 * Instrs Sample(n...) are the synthesised samples occurring
14228c2ecf20Sopenharmony_ci		 * every etm->instructions_sample_period instructions - as
14238c2ecf20Sopenharmony_ci		 * defined on the perf command line.  Sample(n) is being the
14248c2ecf20Sopenharmony_ci		 * last sample before the current etm packet, n+1 to n+3
14258c2ecf20Sopenharmony_ci		 * samples are generated from the current etm packet.
14268c2ecf20Sopenharmony_ci		 *
14278c2ecf20Sopenharmony_ci		 * tidq->packet->instr_count represents the number of
14288c2ecf20Sopenharmony_ci		 * instructions in the current etm packet.
14298c2ecf20Sopenharmony_ci		 *
14308c2ecf20Sopenharmony_ci		 * Period instructions (Pi) contains the the number of
14318c2ecf20Sopenharmony_ci		 * instructions executed after the sample point(n) from the
14328c2ecf20Sopenharmony_ci		 * previous etm packet.  This will always be less than
14338c2ecf20Sopenharmony_ci		 * etm->instructions_sample_period.
14348c2ecf20Sopenharmony_ci		 *
14358c2ecf20Sopenharmony_ci		 * When generate new samples, it combines with two parts
14368c2ecf20Sopenharmony_ci		 * instructions, one is the tail of the old packet and another
14378c2ecf20Sopenharmony_ci		 * is the head of the new coming packet, to generate
14388c2ecf20Sopenharmony_ci		 * sample(n+1); sample(n+2) and sample(n+3) consume the
14398c2ecf20Sopenharmony_ci		 * instructions with sample period.  After sample(n+3), the rest
14408c2ecf20Sopenharmony_ci		 * instructions will be used by later packet and it is assigned
14418c2ecf20Sopenharmony_ci		 * to tidq->period_instructions for next round calculation.
14428c2ecf20Sopenharmony_ci		 */
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci		/*
14458c2ecf20Sopenharmony_ci		 * Get the initial offset into the current packet instructions;
14468c2ecf20Sopenharmony_ci		 * entry conditions ensure that instrs_prev is less than
14478c2ecf20Sopenharmony_ci		 * etm->instructions_sample_period.
14488c2ecf20Sopenharmony_ci		 */
14498c2ecf20Sopenharmony_ci		u64 offset = etm->instructions_sample_period - instrs_prev;
14508c2ecf20Sopenharmony_ci		u64 addr;
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci		/* Prepare last branches for instruction sample */
14538c2ecf20Sopenharmony_ci		if (etm->synth_opts.last_branch)
14548c2ecf20Sopenharmony_ci			cs_etm__copy_last_branch_rb(etmq, tidq);
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci		while (tidq->period_instructions >=
14578c2ecf20Sopenharmony_ci				etm->instructions_sample_period) {
14588c2ecf20Sopenharmony_ci			/*
14598c2ecf20Sopenharmony_ci			 * Calculate the address of the sampled instruction (-1
14608c2ecf20Sopenharmony_ci			 * as sample is reported as though instruction has just
14618c2ecf20Sopenharmony_ci			 * been executed, but PC has not advanced to next
14628c2ecf20Sopenharmony_ci			 * instruction)
14638c2ecf20Sopenharmony_ci			 */
14648c2ecf20Sopenharmony_ci			addr = cs_etm__instr_addr(etmq, trace_chan_id,
14658c2ecf20Sopenharmony_ci						  tidq->packet, offset - 1);
14668c2ecf20Sopenharmony_ci			ret = cs_etm__synth_instruction_sample(
14678c2ecf20Sopenharmony_ci				etmq, tidq, addr,
14688c2ecf20Sopenharmony_ci				etm->instructions_sample_period);
14698c2ecf20Sopenharmony_ci			if (ret)
14708c2ecf20Sopenharmony_ci				return ret;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci			offset += etm->instructions_sample_period;
14738c2ecf20Sopenharmony_ci			tidq->period_instructions -=
14748c2ecf20Sopenharmony_ci				etm->instructions_sample_period;
14758c2ecf20Sopenharmony_ci		}
14768c2ecf20Sopenharmony_ci	}
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	if (etm->sample_branches) {
14798c2ecf20Sopenharmony_ci		bool generate_sample = false;
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci		/* Generate sample for tracing on packet */
14828c2ecf20Sopenharmony_ci		if (tidq->prev_packet->sample_type == CS_ETM_DISCONTINUITY)
14838c2ecf20Sopenharmony_ci			generate_sample = true;
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci		/* Generate sample for branch taken packet */
14868c2ecf20Sopenharmony_ci		if (tidq->prev_packet->sample_type == CS_ETM_RANGE &&
14878c2ecf20Sopenharmony_ci		    tidq->prev_packet->last_instr_taken_branch)
14888c2ecf20Sopenharmony_ci			generate_sample = true;
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci		if (generate_sample) {
14918c2ecf20Sopenharmony_ci			ret = cs_etm__synth_branch_sample(etmq, tidq);
14928c2ecf20Sopenharmony_ci			if (ret)
14938c2ecf20Sopenharmony_ci				return ret;
14948c2ecf20Sopenharmony_ci		}
14958c2ecf20Sopenharmony_ci	}
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	cs_etm__packet_swap(etm, tidq);
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	return 0;
15008c2ecf20Sopenharmony_ci}
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_cistatic int cs_etm__exception(struct cs_etm_traceid_queue *tidq)
15038c2ecf20Sopenharmony_ci{
15048c2ecf20Sopenharmony_ci	/*
15058c2ecf20Sopenharmony_ci	 * When the exception packet is inserted, whether the last instruction
15068c2ecf20Sopenharmony_ci	 * in previous range packet is taken branch or not, we need to force
15078c2ecf20Sopenharmony_ci	 * to set 'prev_packet->last_instr_taken_branch' to true.  This ensures
15088c2ecf20Sopenharmony_ci	 * to generate branch sample for the instruction range before the
15098c2ecf20Sopenharmony_ci	 * exception is trapped to kernel or before the exception returning.
15108c2ecf20Sopenharmony_ci	 *
15118c2ecf20Sopenharmony_ci	 * The exception packet includes the dummy address values, so don't
15128c2ecf20Sopenharmony_ci	 * swap PACKET with PREV_PACKET.  This keeps PREV_PACKET to be useful
15138c2ecf20Sopenharmony_ci	 * for generating instruction and branch samples.
15148c2ecf20Sopenharmony_ci	 */
15158c2ecf20Sopenharmony_ci	if (tidq->prev_packet->sample_type == CS_ETM_RANGE)
15168c2ecf20Sopenharmony_ci		tidq->prev_packet->last_instr_taken_branch = true;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	return 0;
15198c2ecf20Sopenharmony_ci}
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_cistatic int cs_etm__flush(struct cs_etm_queue *etmq,
15228c2ecf20Sopenharmony_ci			 struct cs_etm_traceid_queue *tidq)
15238c2ecf20Sopenharmony_ci{
15248c2ecf20Sopenharmony_ci	int err = 0;
15258c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *etm = etmq->etm;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	/* Handle start tracing packet */
15288c2ecf20Sopenharmony_ci	if (tidq->prev_packet->sample_type == CS_ETM_EMPTY)
15298c2ecf20Sopenharmony_ci		goto swap_packet;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	if (etmq->etm->synth_opts.last_branch &&
15328c2ecf20Sopenharmony_ci	    tidq->prev_packet->sample_type == CS_ETM_RANGE) {
15338c2ecf20Sopenharmony_ci		u64 addr;
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci		/* Prepare last branches for instruction sample */
15368c2ecf20Sopenharmony_ci		cs_etm__copy_last_branch_rb(etmq, tidq);
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci		/*
15398c2ecf20Sopenharmony_ci		 * Generate a last branch event for the branches left in the
15408c2ecf20Sopenharmony_ci		 * circular buffer at the end of the trace.
15418c2ecf20Sopenharmony_ci		 *
15428c2ecf20Sopenharmony_ci		 * Use the address of the end of the last reported execution
15438c2ecf20Sopenharmony_ci		 * range
15448c2ecf20Sopenharmony_ci		 */
15458c2ecf20Sopenharmony_ci		addr = cs_etm__last_executed_instr(tidq->prev_packet);
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci		err = cs_etm__synth_instruction_sample(
15488c2ecf20Sopenharmony_ci			etmq, tidq, addr,
15498c2ecf20Sopenharmony_ci			tidq->period_instructions);
15508c2ecf20Sopenharmony_ci		if (err)
15518c2ecf20Sopenharmony_ci			return err;
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci		tidq->period_instructions = 0;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	}
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	if (etm->sample_branches &&
15588c2ecf20Sopenharmony_ci	    tidq->prev_packet->sample_type == CS_ETM_RANGE) {
15598c2ecf20Sopenharmony_ci		err = cs_etm__synth_branch_sample(etmq, tidq);
15608c2ecf20Sopenharmony_ci		if (err)
15618c2ecf20Sopenharmony_ci			return err;
15628c2ecf20Sopenharmony_ci	}
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ciswap_packet:
15658c2ecf20Sopenharmony_ci	cs_etm__packet_swap(etm, tidq);
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	/* Reset last branches after flush the trace */
15688c2ecf20Sopenharmony_ci	if (etm->synth_opts.last_branch)
15698c2ecf20Sopenharmony_ci		cs_etm__reset_last_branch_rb(tidq);
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	return err;
15728c2ecf20Sopenharmony_ci}
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_cistatic int cs_etm__end_block(struct cs_etm_queue *etmq,
15758c2ecf20Sopenharmony_ci			     struct cs_etm_traceid_queue *tidq)
15768c2ecf20Sopenharmony_ci{
15778c2ecf20Sopenharmony_ci	int err;
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	/*
15808c2ecf20Sopenharmony_ci	 * It has no new packet coming and 'etmq->packet' contains the stale
15818c2ecf20Sopenharmony_ci	 * packet which was set at the previous time with packets swapping;
15828c2ecf20Sopenharmony_ci	 * so skip to generate branch sample to avoid stale packet.
15838c2ecf20Sopenharmony_ci	 *
15848c2ecf20Sopenharmony_ci	 * For this case only flush branch stack and generate a last branch
15858c2ecf20Sopenharmony_ci	 * event for the branches left in the circular buffer at the end of
15868c2ecf20Sopenharmony_ci	 * the trace.
15878c2ecf20Sopenharmony_ci	 */
15888c2ecf20Sopenharmony_ci	if (etmq->etm->synth_opts.last_branch &&
15898c2ecf20Sopenharmony_ci	    tidq->prev_packet->sample_type == CS_ETM_RANGE) {
15908c2ecf20Sopenharmony_ci		u64 addr;
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci		/* Prepare last branches for instruction sample */
15938c2ecf20Sopenharmony_ci		cs_etm__copy_last_branch_rb(etmq, tidq);
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci		/*
15968c2ecf20Sopenharmony_ci		 * Use the address of the end of the last reported execution
15978c2ecf20Sopenharmony_ci		 * range.
15988c2ecf20Sopenharmony_ci		 */
15998c2ecf20Sopenharmony_ci		addr = cs_etm__last_executed_instr(tidq->prev_packet);
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci		err = cs_etm__synth_instruction_sample(
16028c2ecf20Sopenharmony_ci			etmq, tidq, addr,
16038c2ecf20Sopenharmony_ci			tidq->period_instructions);
16048c2ecf20Sopenharmony_ci		if (err)
16058c2ecf20Sopenharmony_ci			return err;
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci		tidq->period_instructions = 0;
16088c2ecf20Sopenharmony_ci	}
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	return 0;
16118c2ecf20Sopenharmony_ci}
16128c2ecf20Sopenharmony_ci/*
16138c2ecf20Sopenharmony_ci * cs_etm__get_data_block: Fetch a block from the auxtrace_buffer queue
16148c2ecf20Sopenharmony_ci *			   if need be.
16158c2ecf20Sopenharmony_ci * Returns:	< 0	if error
16168c2ecf20Sopenharmony_ci *		= 0	if no more auxtrace_buffer to read
16178c2ecf20Sopenharmony_ci *		> 0	if the current buffer isn't empty yet
16188c2ecf20Sopenharmony_ci */
16198c2ecf20Sopenharmony_cistatic int cs_etm__get_data_block(struct cs_etm_queue *etmq)
16208c2ecf20Sopenharmony_ci{
16218c2ecf20Sopenharmony_ci	int ret;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	if (!etmq->buf_len) {
16248c2ecf20Sopenharmony_ci		ret = cs_etm__get_trace(etmq);
16258c2ecf20Sopenharmony_ci		if (ret <= 0)
16268c2ecf20Sopenharmony_ci			return ret;
16278c2ecf20Sopenharmony_ci		/*
16288c2ecf20Sopenharmony_ci		 * We cannot assume consecutive blocks in the data file
16298c2ecf20Sopenharmony_ci		 * are contiguous, reset the decoder to force re-sync.
16308c2ecf20Sopenharmony_ci		 */
16318c2ecf20Sopenharmony_ci		ret = cs_etm_decoder__reset(etmq->decoder);
16328c2ecf20Sopenharmony_ci		if (ret)
16338c2ecf20Sopenharmony_ci			return ret;
16348c2ecf20Sopenharmony_ci	}
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	return etmq->buf_len;
16378c2ecf20Sopenharmony_ci}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_cistatic bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
16408c2ecf20Sopenharmony_ci				 struct cs_etm_packet *packet,
16418c2ecf20Sopenharmony_ci				 u64 end_addr)
16428c2ecf20Sopenharmony_ci{
16438c2ecf20Sopenharmony_ci	/* Initialise to keep compiler happy */
16448c2ecf20Sopenharmony_ci	u16 instr16 = 0;
16458c2ecf20Sopenharmony_ci	u32 instr32 = 0;
16468c2ecf20Sopenharmony_ci	u64 addr;
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	switch (packet->isa) {
16498c2ecf20Sopenharmony_ci	case CS_ETM_ISA_T32:
16508c2ecf20Sopenharmony_ci		/*
16518c2ecf20Sopenharmony_ci		 * The SVC of T32 is defined in ARM DDI 0487D.a, F5.1.247:
16528c2ecf20Sopenharmony_ci		 *
16538c2ecf20Sopenharmony_ci		 *  b'15         b'8
16548c2ecf20Sopenharmony_ci		 * +-----------------+--------+
16558c2ecf20Sopenharmony_ci		 * | 1 1 0 1 1 1 1 1 |  imm8  |
16568c2ecf20Sopenharmony_ci		 * +-----------------+--------+
16578c2ecf20Sopenharmony_ci		 *
16588c2ecf20Sopenharmony_ci		 * According to the specifiction, it only defines SVC for T32
16598c2ecf20Sopenharmony_ci		 * with 16 bits instruction and has no definition for 32bits;
16608c2ecf20Sopenharmony_ci		 * so below only read 2 bytes as instruction size for T32.
16618c2ecf20Sopenharmony_ci		 */
16628c2ecf20Sopenharmony_ci		addr = end_addr - 2;
16638c2ecf20Sopenharmony_ci		cs_etm__mem_access(etmq, trace_chan_id, addr,
16648c2ecf20Sopenharmony_ci				   sizeof(instr16), (u8 *)&instr16);
16658c2ecf20Sopenharmony_ci		if ((instr16 & 0xFF00) == 0xDF00)
16668c2ecf20Sopenharmony_ci			return true;
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci		break;
16698c2ecf20Sopenharmony_ci	case CS_ETM_ISA_A32:
16708c2ecf20Sopenharmony_ci		/*
16718c2ecf20Sopenharmony_ci		 * The SVC of A32 is defined in ARM DDI 0487D.a, F5.1.247:
16728c2ecf20Sopenharmony_ci		 *
16738c2ecf20Sopenharmony_ci		 *  b'31 b'28 b'27 b'24
16748c2ecf20Sopenharmony_ci		 * +---------+---------+-------------------------+
16758c2ecf20Sopenharmony_ci		 * |  !1111  | 1 1 1 1 |        imm24            |
16768c2ecf20Sopenharmony_ci		 * +---------+---------+-------------------------+
16778c2ecf20Sopenharmony_ci		 */
16788c2ecf20Sopenharmony_ci		addr = end_addr - 4;
16798c2ecf20Sopenharmony_ci		cs_etm__mem_access(etmq, trace_chan_id, addr,
16808c2ecf20Sopenharmony_ci				   sizeof(instr32), (u8 *)&instr32);
16818c2ecf20Sopenharmony_ci		if ((instr32 & 0x0F000000) == 0x0F000000 &&
16828c2ecf20Sopenharmony_ci		    (instr32 & 0xF0000000) != 0xF0000000)
16838c2ecf20Sopenharmony_ci			return true;
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci		break;
16868c2ecf20Sopenharmony_ci	case CS_ETM_ISA_A64:
16878c2ecf20Sopenharmony_ci		/*
16888c2ecf20Sopenharmony_ci		 * The SVC of A64 is defined in ARM DDI 0487D.a, C6.2.294:
16898c2ecf20Sopenharmony_ci		 *
16908c2ecf20Sopenharmony_ci		 *  b'31               b'21           b'4     b'0
16918c2ecf20Sopenharmony_ci		 * +-----------------------+---------+-----------+
16928c2ecf20Sopenharmony_ci		 * | 1 1 0 1 0 1 0 0 0 0 0 |  imm16  | 0 0 0 0 1 |
16938c2ecf20Sopenharmony_ci		 * +-----------------------+---------+-----------+
16948c2ecf20Sopenharmony_ci		 */
16958c2ecf20Sopenharmony_ci		addr = end_addr - 4;
16968c2ecf20Sopenharmony_ci		cs_etm__mem_access(etmq, trace_chan_id, addr,
16978c2ecf20Sopenharmony_ci				   sizeof(instr32), (u8 *)&instr32);
16988c2ecf20Sopenharmony_ci		if ((instr32 & 0xFFE0001F) == 0xd4000001)
16998c2ecf20Sopenharmony_ci			return true;
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci		break;
17028c2ecf20Sopenharmony_ci	case CS_ETM_ISA_UNKNOWN:
17038c2ecf20Sopenharmony_ci	default:
17048c2ecf20Sopenharmony_ci		break;
17058c2ecf20Sopenharmony_ci	}
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci	return false;
17088c2ecf20Sopenharmony_ci}
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_cistatic bool cs_etm__is_syscall(struct cs_etm_queue *etmq,
17118c2ecf20Sopenharmony_ci			       struct cs_etm_traceid_queue *tidq, u64 magic)
17128c2ecf20Sopenharmony_ci{
17138c2ecf20Sopenharmony_ci	u8 trace_chan_id = tidq->trace_chan_id;
17148c2ecf20Sopenharmony_ci	struct cs_etm_packet *packet = tidq->packet;
17158c2ecf20Sopenharmony_ci	struct cs_etm_packet *prev_packet = tidq->prev_packet;
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	if (magic == __perf_cs_etmv3_magic)
17188c2ecf20Sopenharmony_ci		if (packet->exception_number == CS_ETMV3_EXC_SVC)
17198c2ecf20Sopenharmony_ci			return true;
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	/*
17228c2ecf20Sopenharmony_ci	 * ETMv4 exception type CS_ETMV4_EXC_CALL covers SVC, SMC and
17238c2ecf20Sopenharmony_ci	 * HVC cases; need to check if it's SVC instruction based on
17248c2ecf20Sopenharmony_ci	 * packet address.
17258c2ecf20Sopenharmony_ci	 */
17268c2ecf20Sopenharmony_ci	if (magic == __perf_cs_etmv4_magic) {
17278c2ecf20Sopenharmony_ci		if (packet->exception_number == CS_ETMV4_EXC_CALL &&
17288c2ecf20Sopenharmony_ci		    cs_etm__is_svc_instr(etmq, trace_chan_id, prev_packet,
17298c2ecf20Sopenharmony_ci					 prev_packet->end_addr))
17308c2ecf20Sopenharmony_ci			return true;
17318c2ecf20Sopenharmony_ci	}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	return false;
17348c2ecf20Sopenharmony_ci}
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_cistatic bool cs_etm__is_async_exception(struct cs_etm_traceid_queue *tidq,
17378c2ecf20Sopenharmony_ci				       u64 magic)
17388c2ecf20Sopenharmony_ci{
17398c2ecf20Sopenharmony_ci	struct cs_etm_packet *packet = tidq->packet;
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	if (magic == __perf_cs_etmv3_magic)
17428c2ecf20Sopenharmony_ci		if (packet->exception_number == CS_ETMV3_EXC_DEBUG_HALT ||
17438c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV3_EXC_ASYNC_DATA_ABORT ||
17448c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV3_EXC_PE_RESET ||
17458c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV3_EXC_IRQ ||
17468c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV3_EXC_FIQ)
17478c2ecf20Sopenharmony_ci			return true;
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	if (magic == __perf_cs_etmv4_magic)
17508c2ecf20Sopenharmony_ci		if (packet->exception_number == CS_ETMV4_EXC_RESET ||
17518c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV4_EXC_DEBUG_HALT ||
17528c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV4_EXC_SYSTEM_ERROR ||
17538c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV4_EXC_INST_DEBUG ||
17548c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV4_EXC_DATA_DEBUG ||
17558c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV4_EXC_IRQ ||
17568c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV4_EXC_FIQ)
17578c2ecf20Sopenharmony_ci			return true;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	return false;
17608c2ecf20Sopenharmony_ci}
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_cistatic bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq,
17638c2ecf20Sopenharmony_ci				      struct cs_etm_traceid_queue *tidq,
17648c2ecf20Sopenharmony_ci				      u64 magic)
17658c2ecf20Sopenharmony_ci{
17668c2ecf20Sopenharmony_ci	u8 trace_chan_id = tidq->trace_chan_id;
17678c2ecf20Sopenharmony_ci	struct cs_etm_packet *packet = tidq->packet;
17688c2ecf20Sopenharmony_ci	struct cs_etm_packet *prev_packet = tidq->prev_packet;
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	if (magic == __perf_cs_etmv3_magic)
17718c2ecf20Sopenharmony_ci		if (packet->exception_number == CS_ETMV3_EXC_SMC ||
17728c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV3_EXC_HYP ||
17738c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV3_EXC_JAZELLE_THUMBEE ||
17748c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV3_EXC_UNDEFINED_INSTR ||
17758c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV3_EXC_PREFETCH_ABORT ||
17768c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV3_EXC_DATA_FAULT ||
17778c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV3_EXC_GENERIC)
17788c2ecf20Sopenharmony_ci			return true;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	if (magic == __perf_cs_etmv4_magic) {
17818c2ecf20Sopenharmony_ci		if (packet->exception_number == CS_ETMV4_EXC_TRAP ||
17828c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV4_EXC_ALIGNMENT ||
17838c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV4_EXC_INST_FAULT ||
17848c2ecf20Sopenharmony_ci		    packet->exception_number == CS_ETMV4_EXC_DATA_FAULT)
17858c2ecf20Sopenharmony_ci			return true;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci		/*
17888c2ecf20Sopenharmony_ci		 * For CS_ETMV4_EXC_CALL, except SVC other instructions
17898c2ecf20Sopenharmony_ci		 * (SMC, HVC) are taken as sync exceptions.
17908c2ecf20Sopenharmony_ci		 */
17918c2ecf20Sopenharmony_ci		if (packet->exception_number == CS_ETMV4_EXC_CALL &&
17928c2ecf20Sopenharmony_ci		    !cs_etm__is_svc_instr(etmq, trace_chan_id, prev_packet,
17938c2ecf20Sopenharmony_ci					  prev_packet->end_addr))
17948c2ecf20Sopenharmony_ci			return true;
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci		/*
17978c2ecf20Sopenharmony_ci		 * ETMv4 has 5 bits for exception number; if the numbers
17988c2ecf20Sopenharmony_ci		 * are in the range ( CS_ETMV4_EXC_FIQ, CS_ETMV4_EXC_END ]
17998c2ecf20Sopenharmony_ci		 * they are implementation defined exceptions.
18008c2ecf20Sopenharmony_ci		 *
18018c2ecf20Sopenharmony_ci		 * For this case, simply take it as sync exception.
18028c2ecf20Sopenharmony_ci		 */
18038c2ecf20Sopenharmony_ci		if (packet->exception_number > CS_ETMV4_EXC_FIQ &&
18048c2ecf20Sopenharmony_ci		    packet->exception_number <= CS_ETMV4_EXC_END)
18058c2ecf20Sopenharmony_ci			return true;
18068c2ecf20Sopenharmony_ci	}
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	return false;
18098c2ecf20Sopenharmony_ci}
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_cistatic int cs_etm__set_sample_flags(struct cs_etm_queue *etmq,
18128c2ecf20Sopenharmony_ci				    struct cs_etm_traceid_queue *tidq)
18138c2ecf20Sopenharmony_ci{
18148c2ecf20Sopenharmony_ci	struct cs_etm_packet *packet = tidq->packet;
18158c2ecf20Sopenharmony_ci	struct cs_etm_packet *prev_packet = tidq->prev_packet;
18168c2ecf20Sopenharmony_ci	u8 trace_chan_id = tidq->trace_chan_id;
18178c2ecf20Sopenharmony_ci	u64 magic;
18188c2ecf20Sopenharmony_ci	int ret;
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci	switch (packet->sample_type) {
18218c2ecf20Sopenharmony_ci	case CS_ETM_RANGE:
18228c2ecf20Sopenharmony_ci		/*
18238c2ecf20Sopenharmony_ci		 * Immediate branch instruction without neither link nor
18248c2ecf20Sopenharmony_ci		 * return flag, it's normal branch instruction within
18258c2ecf20Sopenharmony_ci		 * the function.
18268c2ecf20Sopenharmony_ci		 */
18278c2ecf20Sopenharmony_ci		if (packet->last_instr_type == OCSD_INSTR_BR &&
18288c2ecf20Sopenharmony_ci		    packet->last_instr_subtype == OCSD_S_INSTR_NONE) {
18298c2ecf20Sopenharmony_ci			packet->flags = PERF_IP_FLAG_BRANCH;
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci			if (packet->last_instr_cond)
18328c2ecf20Sopenharmony_ci				packet->flags |= PERF_IP_FLAG_CONDITIONAL;
18338c2ecf20Sopenharmony_ci		}
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci		/*
18368c2ecf20Sopenharmony_ci		 * Immediate branch instruction with link (e.g. BL), this is
18378c2ecf20Sopenharmony_ci		 * branch instruction for function call.
18388c2ecf20Sopenharmony_ci		 */
18398c2ecf20Sopenharmony_ci		if (packet->last_instr_type == OCSD_INSTR_BR &&
18408c2ecf20Sopenharmony_ci		    packet->last_instr_subtype == OCSD_S_INSTR_BR_LINK)
18418c2ecf20Sopenharmony_ci			packet->flags = PERF_IP_FLAG_BRANCH |
18428c2ecf20Sopenharmony_ci					PERF_IP_FLAG_CALL;
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci		/*
18458c2ecf20Sopenharmony_ci		 * Indirect branch instruction with link (e.g. BLR), this is
18468c2ecf20Sopenharmony_ci		 * branch instruction for function call.
18478c2ecf20Sopenharmony_ci		 */
18488c2ecf20Sopenharmony_ci		if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
18498c2ecf20Sopenharmony_ci		    packet->last_instr_subtype == OCSD_S_INSTR_BR_LINK)
18508c2ecf20Sopenharmony_ci			packet->flags = PERF_IP_FLAG_BRANCH |
18518c2ecf20Sopenharmony_ci					PERF_IP_FLAG_CALL;
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci		/*
18548c2ecf20Sopenharmony_ci		 * Indirect branch instruction with subtype of
18558c2ecf20Sopenharmony_ci		 * OCSD_S_INSTR_V7_IMPLIED_RET, this is explicit hint for
18568c2ecf20Sopenharmony_ci		 * function return for A32/T32.
18578c2ecf20Sopenharmony_ci		 */
18588c2ecf20Sopenharmony_ci		if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
18598c2ecf20Sopenharmony_ci		    packet->last_instr_subtype == OCSD_S_INSTR_V7_IMPLIED_RET)
18608c2ecf20Sopenharmony_ci			packet->flags = PERF_IP_FLAG_BRANCH |
18618c2ecf20Sopenharmony_ci					PERF_IP_FLAG_RETURN;
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci		/*
18648c2ecf20Sopenharmony_ci		 * Indirect branch instruction without link (e.g. BR), usually
18658c2ecf20Sopenharmony_ci		 * this is used for function return, especially for functions
18668c2ecf20Sopenharmony_ci		 * within dynamic link lib.
18678c2ecf20Sopenharmony_ci		 */
18688c2ecf20Sopenharmony_ci		if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
18698c2ecf20Sopenharmony_ci		    packet->last_instr_subtype == OCSD_S_INSTR_NONE)
18708c2ecf20Sopenharmony_ci			packet->flags = PERF_IP_FLAG_BRANCH |
18718c2ecf20Sopenharmony_ci					PERF_IP_FLAG_RETURN;
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci		/* Return instruction for function return. */
18748c2ecf20Sopenharmony_ci		if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
18758c2ecf20Sopenharmony_ci		    packet->last_instr_subtype == OCSD_S_INSTR_V8_RET)
18768c2ecf20Sopenharmony_ci			packet->flags = PERF_IP_FLAG_BRANCH |
18778c2ecf20Sopenharmony_ci					PERF_IP_FLAG_RETURN;
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci		/*
18808c2ecf20Sopenharmony_ci		 * Decoder might insert a discontinuity in the middle of
18818c2ecf20Sopenharmony_ci		 * instruction packets, fixup prev_packet with flag
18828c2ecf20Sopenharmony_ci		 * PERF_IP_FLAG_TRACE_BEGIN to indicate restarting trace.
18838c2ecf20Sopenharmony_ci		 */
18848c2ecf20Sopenharmony_ci		if (prev_packet->sample_type == CS_ETM_DISCONTINUITY)
18858c2ecf20Sopenharmony_ci			prev_packet->flags |= PERF_IP_FLAG_BRANCH |
18868c2ecf20Sopenharmony_ci					      PERF_IP_FLAG_TRACE_BEGIN;
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci		/*
18898c2ecf20Sopenharmony_ci		 * If the previous packet is an exception return packet
18908c2ecf20Sopenharmony_ci		 * and the return address just follows SVC instuction,
18918c2ecf20Sopenharmony_ci		 * it needs to calibrate the previous packet sample flags
18928c2ecf20Sopenharmony_ci		 * as PERF_IP_FLAG_SYSCALLRET.
18938c2ecf20Sopenharmony_ci		 */
18948c2ecf20Sopenharmony_ci		if (prev_packet->flags == (PERF_IP_FLAG_BRANCH |
18958c2ecf20Sopenharmony_ci					   PERF_IP_FLAG_RETURN |
18968c2ecf20Sopenharmony_ci					   PERF_IP_FLAG_INTERRUPT) &&
18978c2ecf20Sopenharmony_ci		    cs_etm__is_svc_instr(etmq, trace_chan_id,
18988c2ecf20Sopenharmony_ci					 packet, packet->start_addr))
18998c2ecf20Sopenharmony_ci			prev_packet->flags = PERF_IP_FLAG_BRANCH |
19008c2ecf20Sopenharmony_ci					     PERF_IP_FLAG_RETURN |
19018c2ecf20Sopenharmony_ci					     PERF_IP_FLAG_SYSCALLRET;
19028c2ecf20Sopenharmony_ci		break;
19038c2ecf20Sopenharmony_ci	case CS_ETM_DISCONTINUITY:
19048c2ecf20Sopenharmony_ci		/*
19058c2ecf20Sopenharmony_ci		 * The trace is discontinuous, if the previous packet is
19068c2ecf20Sopenharmony_ci		 * instruction packet, set flag PERF_IP_FLAG_TRACE_END
19078c2ecf20Sopenharmony_ci		 * for previous packet.
19088c2ecf20Sopenharmony_ci		 */
19098c2ecf20Sopenharmony_ci		if (prev_packet->sample_type == CS_ETM_RANGE)
19108c2ecf20Sopenharmony_ci			prev_packet->flags |= PERF_IP_FLAG_BRANCH |
19118c2ecf20Sopenharmony_ci					      PERF_IP_FLAG_TRACE_END;
19128c2ecf20Sopenharmony_ci		break;
19138c2ecf20Sopenharmony_ci	case CS_ETM_EXCEPTION:
19148c2ecf20Sopenharmony_ci		ret = cs_etm__get_magic(packet->trace_chan_id, &magic);
19158c2ecf20Sopenharmony_ci		if (ret)
19168c2ecf20Sopenharmony_ci			return ret;
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci		/* The exception is for system call. */
19198c2ecf20Sopenharmony_ci		if (cs_etm__is_syscall(etmq, tidq, magic))
19208c2ecf20Sopenharmony_ci			packet->flags = PERF_IP_FLAG_BRANCH |
19218c2ecf20Sopenharmony_ci					PERF_IP_FLAG_CALL |
19228c2ecf20Sopenharmony_ci					PERF_IP_FLAG_SYSCALLRET;
19238c2ecf20Sopenharmony_ci		/*
19248c2ecf20Sopenharmony_ci		 * The exceptions are triggered by external signals from bus,
19258c2ecf20Sopenharmony_ci		 * interrupt controller, debug module, PE reset or halt.
19268c2ecf20Sopenharmony_ci		 */
19278c2ecf20Sopenharmony_ci		else if (cs_etm__is_async_exception(tidq, magic))
19288c2ecf20Sopenharmony_ci			packet->flags = PERF_IP_FLAG_BRANCH |
19298c2ecf20Sopenharmony_ci					PERF_IP_FLAG_CALL |
19308c2ecf20Sopenharmony_ci					PERF_IP_FLAG_ASYNC |
19318c2ecf20Sopenharmony_ci					PERF_IP_FLAG_INTERRUPT;
19328c2ecf20Sopenharmony_ci		/*
19338c2ecf20Sopenharmony_ci		 * Otherwise, exception is caused by trap, instruction &
19348c2ecf20Sopenharmony_ci		 * data fault, or alignment errors.
19358c2ecf20Sopenharmony_ci		 */
19368c2ecf20Sopenharmony_ci		else if (cs_etm__is_sync_exception(etmq, tidq, magic))
19378c2ecf20Sopenharmony_ci			packet->flags = PERF_IP_FLAG_BRANCH |
19388c2ecf20Sopenharmony_ci					PERF_IP_FLAG_CALL |
19398c2ecf20Sopenharmony_ci					PERF_IP_FLAG_INTERRUPT;
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci		/*
19428c2ecf20Sopenharmony_ci		 * When the exception packet is inserted, since exception
19438c2ecf20Sopenharmony_ci		 * packet is not used standalone for generating samples
19448c2ecf20Sopenharmony_ci		 * and it's affiliation to the previous instruction range
19458c2ecf20Sopenharmony_ci		 * packet; so set previous range packet flags to tell perf
19468c2ecf20Sopenharmony_ci		 * it is an exception taken branch.
19478c2ecf20Sopenharmony_ci		 */
19488c2ecf20Sopenharmony_ci		if (prev_packet->sample_type == CS_ETM_RANGE)
19498c2ecf20Sopenharmony_ci			prev_packet->flags = packet->flags;
19508c2ecf20Sopenharmony_ci		break;
19518c2ecf20Sopenharmony_ci	case CS_ETM_EXCEPTION_RET:
19528c2ecf20Sopenharmony_ci		/*
19538c2ecf20Sopenharmony_ci		 * When the exception return packet is inserted, since
19548c2ecf20Sopenharmony_ci		 * exception return packet is not used standalone for
19558c2ecf20Sopenharmony_ci		 * generating samples and it's affiliation to the previous
19568c2ecf20Sopenharmony_ci		 * instruction range packet; so set previous range packet
19578c2ecf20Sopenharmony_ci		 * flags to tell perf it is an exception return branch.
19588c2ecf20Sopenharmony_ci		 *
19598c2ecf20Sopenharmony_ci		 * The exception return can be for either system call or
19608c2ecf20Sopenharmony_ci		 * other exception types; unfortunately the packet doesn't
19618c2ecf20Sopenharmony_ci		 * contain exception type related info so we cannot decide
19628c2ecf20Sopenharmony_ci		 * the exception type purely based on exception return packet.
19638c2ecf20Sopenharmony_ci		 * If we record the exception number from exception packet and
19648c2ecf20Sopenharmony_ci		 * reuse it for excpetion return packet, this is not reliable
19658c2ecf20Sopenharmony_ci		 * due the trace can be discontinuity or the interrupt can
19668c2ecf20Sopenharmony_ci		 * be nested, thus the recorded exception number cannot be
19678c2ecf20Sopenharmony_ci		 * used for exception return packet for these two cases.
19688c2ecf20Sopenharmony_ci		 *
19698c2ecf20Sopenharmony_ci		 * For exception return packet, we only need to distinguish the
19708c2ecf20Sopenharmony_ci		 * packet is for system call or for other types.  Thus the
19718c2ecf20Sopenharmony_ci		 * decision can be deferred when receive the next packet which
19728c2ecf20Sopenharmony_ci		 * contains the return address, based on the return address we
19738c2ecf20Sopenharmony_ci		 * can read out the previous instruction and check if it's a
19748c2ecf20Sopenharmony_ci		 * system call instruction and then calibrate the sample flag
19758c2ecf20Sopenharmony_ci		 * as needed.
19768c2ecf20Sopenharmony_ci		 */
19778c2ecf20Sopenharmony_ci		if (prev_packet->sample_type == CS_ETM_RANGE)
19788c2ecf20Sopenharmony_ci			prev_packet->flags = PERF_IP_FLAG_BRANCH |
19798c2ecf20Sopenharmony_ci					     PERF_IP_FLAG_RETURN |
19808c2ecf20Sopenharmony_ci					     PERF_IP_FLAG_INTERRUPT;
19818c2ecf20Sopenharmony_ci		break;
19828c2ecf20Sopenharmony_ci	case CS_ETM_EMPTY:
19838c2ecf20Sopenharmony_ci	default:
19848c2ecf20Sopenharmony_ci		break;
19858c2ecf20Sopenharmony_ci	}
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	return 0;
19888c2ecf20Sopenharmony_ci}
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_cistatic int cs_etm__decode_data_block(struct cs_etm_queue *etmq)
19918c2ecf20Sopenharmony_ci{
19928c2ecf20Sopenharmony_ci	int ret = 0;
19938c2ecf20Sopenharmony_ci	size_t processed = 0;
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	/*
19968c2ecf20Sopenharmony_ci	 * Packets are decoded and added to the decoder's packet queue
19978c2ecf20Sopenharmony_ci	 * until the decoder packet processing callback has requested that
19988c2ecf20Sopenharmony_ci	 * processing stops or there is nothing left in the buffer.  Normal
19998c2ecf20Sopenharmony_ci	 * operations that stop processing are a timestamp packet or a full
20008c2ecf20Sopenharmony_ci	 * decoder buffer queue.
20018c2ecf20Sopenharmony_ci	 */
20028c2ecf20Sopenharmony_ci	ret = cs_etm_decoder__process_data_block(etmq->decoder,
20038c2ecf20Sopenharmony_ci						 etmq->offset,
20048c2ecf20Sopenharmony_ci						 &etmq->buf[etmq->buf_used],
20058c2ecf20Sopenharmony_ci						 etmq->buf_len,
20068c2ecf20Sopenharmony_ci						 &processed);
20078c2ecf20Sopenharmony_ci	if (ret)
20088c2ecf20Sopenharmony_ci		goto out;
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci	etmq->offset += processed;
20118c2ecf20Sopenharmony_ci	etmq->buf_used += processed;
20128c2ecf20Sopenharmony_ci	etmq->buf_len -= processed;
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ciout:
20158c2ecf20Sopenharmony_ci	return ret;
20168c2ecf20Sopenharmony_ci}
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_cistatic int cs_etm__process_traceid_queue(struct cs_etm_queue *etmq,
20198c2ecf20Sopenharmony_ci					 struct cs_etm_traceid_queue *tidq)
20208c2ecf20Sopenharmony_ci{
20218c2ecf20Sopenharmony_ci	int ret;
20228c2ecf20Sopenharmony_ci	struct cs_etm_packet_queue *packet_queue;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	packet_queue = &tidq->packet_queue;
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci	/* Process each packet in this chunk */
20278c2ecf20Sopenharmony_ci	while (1) {
20288c2ecf20Sopenharmony_ci		ret = cs_etm_decoder__get_packet(packet_queue,
20298c2ecf20Sopenharmony_ci						 tidq->packet);
20308c2ecf20Sopenharmony_ci		if (ret <= 0)
20318c2ecf20Sopenharmony_ci			/*
20328c2ecf20Sopenharmony_ci			 * Stop processing this chunk on
20338c2ecf20Sopenharmony_ci			 * end of data or error
20348c2ecf20Sopenharmony_ci			 */
20358c2ecf20Sopenharmony_ci			break;
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci		/*
20388c2ecf20Sopenharmony_ci		 * Since packet addresses are swapped in packet
20398c2ecf20Sopenharmony_ci		 * handling within below switch() statements,
20408c2ecf20Sopenharmony_ci		 * thus setting sample flags must be called
20418c2ecf20Sopenharmony_ci		 * prior to switch() statement to use address
20428c2ecf20Sopenharmony_ci		 * information before packets swapping.
20438c2ecf20Sopenharmony_ci		 */
20448c2ecf20Sopenharmony_ci		ret = cs_etm__set_sample_flags(etmq, tidq);
20458c2ecf20Sopenharmony_ci		if (ret < 0)
20468c2ecf20Sopenharmony_ci			break;
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci		switch (tidq->packet->sample_type) {
20498c2ecf20Sopenharmony_ci		case CS_ETM_RANGE:
20508c2ecf20Sopenharmony_ci			/*
20518c2ecf20Sopenharmony_ci			 * If the packet contains an instruction
20528c2ecf20Sopenharmony_ci			 * range, generate instruction sequence
20538c2ecf20Sopenharmony_ci			 * events.
20548c2ecf20Sopenharmony_ci			 */
20558c2ecf20Sopenharmony_ci			cs_etm__sample(etmq, tidq);
20568c2ecf20Sopenharmony_ci			break;
20578c2ecf20Sopenharmony_ci		case CS_ETM_EXCEPTION:
20588c2ecf20Sopenharmony_ci		case CS_ETM_EXCEPTION_RET:
20598c2ecf20Sopenharmony_ci			/*
20608c2ecf20Sopenharmony_ci			 * If the exception packet is coming,
20618c2ecf20Sopenharmony_ci			 * make sure the previous instruction
20628c2ecf20Sopenharmony_ci			 * range packet to be handled properly.
20638c2ecf20Sopenharmony_ci			 */
20648c2ecf20Sopenharmony_ci			cs_etm__exception(tidq);
20658c2ecf20Sopenharmony_ci			break;
20668c2ecf20Sopenharmony_ci		case CS_ETM_DISCONTINUITY:
20678c2ecf20Sopenharmony_ci			/*
20688c2ecf20Sopenharmony_ci			 * Discontinuity in trace, flush
20698c2ecf20Sopenharmony_ci			 * previous branch stack
20708c2ecf20Sopenharmony_ci			 */
20718c2ecf20Sopenharmony_ci			cs_etm__flush(etmq, tidq);
20728c2ecf20Sopenharmony_ci			break;
20738c2ecf20Sopenharmony_ci		case CS_ETM_EMPTY:
20748c2ecf20Sopenharmony_ci			/*
20758c2ecf20Sopenharmony_ci			 * Should not receive empty packet,
20768c2ecf20Sopenharmony_ci			 * report error.
20778c2ecf20Sopenharmony_ci			 */
20788c2ecf20Sopenharmony_ci			pr_err("CS ETM Trace: empty packet\n");
20798c2ecf20Sopenharmony_ci			return -EINVAL;
20808c2ecf20Sopenharmony_ci		default:
20818c2ecf20Sopenharmony_ci			break;
20828c2ecf20Sopenharmony_ci		}
20838c2ecf20Sopenharmony_ci	}
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci	return ret;
20868c2ecf20Sopenharmony_ci}
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_cistatic void cs_etm__clear_all_traceid_queues(struct cs_etm_queue *etmq)
20898c2ecf20Sopenharmony_ci{
20908c2ecf20Sopenharmony_ci	int idx;
20918c2ecf20Sopenharmony_ci	struct int_node *inode;
20928c2ecf20Sopenharmony_ci	struct cs_etm_traceid_queue *tidq;
20938c2ecf20Sopenharmony_ci	struct intlist *traceid_queues_list = etmq->traceid_queues_list;
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_ci	intlist__for_each_entry(inode, traceid_queues_list) {
20968c2ecf20Sopenharmony_ci		idx = (int)(intptr_t)inode->priv;
20978c2ecf20Sopenharmony_ci		tidq = etmq->traceid_queues[idx];
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci		/* Ignore return value */
21008c2ecf20Sopenharmony_ci		cs_etm__process_traceid_queue(etmq, tidq);
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci		/*
21038c2ecf20Sopenharmony_ci		 * Generate an instruction sample with the remaining
21048c2ecf20Sopenharmony_ci		 * branchstack entries.
21058c2ecf20Sopenharmony_ci		 */
21068c2ecf20Sopenharmony_ci		cs_etm__flush(etmq, tidq);
21078c2ecf20Sopenharmony_ci	}
21088c2ecf20Sopenharmony_ci}
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_cistatic int cs_etm__run_decoder(struct cs_etm_queue *etmq)
21118c2ecf20Sopenharmony_ci{
21128c2ecf20Sopenharmony_ci	int err = 0;
21138c2ecf20Sopenharmony_ci	struct cs_etm_traceid_queue *tidq;
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	tidq = cs_etm__etmq_get_traceid_queue(etmq, CS_ETM_PER_THREAD_TRACEID);
21168c2ecf20Sopenharmony_ci	if (!tidq)
21178c2ecf20Sopenharmony_ci		return -EINVAL;
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci	/* Go through each buffer in the queue and decode them one by one */
21208c2ecf20Sopenharmony_ci	while (1) {
21218c2ecf20Sopenharmony_ci		err = cs_etm__get_data_block(etmq);
21228c2ecf20Sopenharmony_ci		if (err <= 0)
21238c2ecf20Sopenharmony_ci			return err;
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci		/* Run trace decoder until buffer consumed or end of trace */
21268c2ecf20Sopenharmony_ci		do {
21278c2ecf20Sopenharmony_ci			err = cs_etm__decode_data_block(etmq);
21288c2ecf20Sopenharmony_ci			if (err)
21298c2ecf20Sopenharmony_ci				return err;
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci			/*
21328c2ecf20Sopenharmony_ci			 * Process each packet in this chunk, nothing to do if
21338c2ecf20Sopenharmony_ci			 * an error occurs other than hoping the next one will
21348c2ecf20Sopenharmony_ci			 * be better.
21358c2ecf20Sopenharmony_ci			 */
21368c2ecf20Sopenharmony_ci			err = cs_etm__process_traceid_queue(etmq, tidq);
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci		} while (etmq->buf_len);
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci		if (err == 0)
21418c2ecf20Sopenharmony_ci			/* Flush any remaining branch stack entries */
21428c2ecf20Sopenharmony_ci			err = cs_etm__end_block(etmq, tidq);
21438c2ecf20Sopenharmony_ci	}
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci	return err;
21468c2ecf20Sopenharmony_ci}
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_cistatic int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm,
21498c2ecf20Sopenharmony_ci					   pid_t tid)
21508c2ecf20Sopenharmony_ci{
21518c2ecf20Sopenharmony_ci	unsigned int i;
21528c2ecf20Sopenharmony_ci	struct auxtrace_queues *queues = &etm->queues;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	for (i = 0; i < queues->nr_queues; i++) {
21558c2ecf20Sopenharmony_ci		struct auxtrace_queue *queue = &etm->queues.queue_array[i];
21568c2ecf20Sopenharmony_ci		struct cs_etm_queue *etmq = queue->priv;
21578c2ecf20Sopenharmony_ci		struct cs_etm_traceid_queue *tidq;
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci		if (!etmq)
21608c2ecf20Sopenharmony_ci			continue;
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci		tidq = cs_etm__etmq_get_traceid_queue(etmq,
21638c2ecf20Sopenharmony_ci						CS_ETM_PER_THREAD_TRACEID);
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ci		if (!tidq)
21668c2ecf20Sopenharmony_ci			continue;
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci		if ((tid == -1) || (tidq->tid == tid)) {
21698c2ecf20Sopenharmony_ci			cs_etm__set_pid_tid_cpu(etm, tidq);
21708c2ecf20Sopenharmony_ci			cs_etm__run_decoder(etmq);
21718c2ecf20Sopenharmony_ci		}
21728c2ecf20Sopenharmony_ci	}
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	return 0;
21758c2ecf20Sopenharmony_ci}
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_cistatic int cs_etm__process_queues(struct cs_etm_auxtrace *etm)
21788c2ecf20Sopenharmony_ci{
21798c2ecf20Sopenharmony_ci	int ret = 0;
21808c2ecf20Sopenharmony_ci	unsigned int cs_queue_nr, queue_nr;
21818c2ecf20Sopenharmony_ci	u8 trace_chan_id;
21828c2ecf20Sopenharmony_ci	u64 timestamp;
21838c2ecf20Sopenharmony_ci	struct auxtrace_queue *queue;
21848c2ecf20Sopenharmony_ci	struct cs_etm_queue *etmq;
21858c2ecf20Sopenharmony_ci	struct cs_etm_traceid_queue *tidq;
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci	while (1) {
21888c2ecf20Sopenharmony_ci		if (!etm->heap.heap_cnt)
21898c2ecf20Sopenharmony_ci			goto out;
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci		/* Take the entry at the top of the min heap */
21928c2ecf20Sopenharmony_ci		cs_queue_nr = etm->heap.heap_array[0].queue_nr;
21938c2ecf20Sopenharmony_ci		queue_nr = TO_QUEUE_NR(cs_queue_nr);
21948c2ecf20Sopenharmony_ci		trace_chan_id = TO_TRACE_CHAN_ID(cs_queue_nr);
21958c2ecf20Sopenharmony_ci		queue = &etm->queues.queue_array[queue_nr];
21968c2ecf20Sopenharmony_ci		etmq = queue->priv;
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci		/*
21998c2ecf20Sopenharmony_ci		 * Remove the top entry from the heap since we are about
22008c2ecf20Sopenharmony_ci		 * to process it.
22018c2ecf20Sopenharmony_ci		 */
22028c2ecf20Sopenharmony_ci		auxtrace_heap__pop(&etm->heap);
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci		tidq  = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
22058c2ecf20Sopenharmony_ci		if (!tidq) {
22068c2ecf20Sopenharmony_ci			/*
22078c2ecf20Sopenharmony_ci			 * No traceID queue has been allocated for this traceID,
22088c2ecf20Sopenharmony_ci			 * which means something somewhere went very wrong.  No
22098c2ecf20Sopenharmony_ci			 * other choice than simply exit.
22108c2ecf20Sopenharmony_ci			 */
22118c2ecf20Sopenharmony_ci			ret = -EINVAL;
22128c2ecf20Sopenharmony_ci			goto out;
22138c2ecf20Sopenharmony_ci		}
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci		/*
22168c2ecf20Sopenharmony_ci		 * Packets associated with this timestamp are already in
22178c2ecf20Sopenharmony_ci		 * the etmq's traceID queue, so process them.
22188c2ecf20Sopenharmony_ci		 */
22198c2ecf20Sopenharmony_ci		ret = cs_etm__process_traceid_queue(etmq, tidq);
22208c2ecf20Sopenharmony_ci		if (ret < 0)
22218c2ecf20Sopenharmony_ci			goto out;
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci		/*
22248c2ecf20Sopenharmony_ci		 * Packets for this timestamp have been processed, time to
22258c2ecf20Sopenharmony_ci		 * move on to the next timestamp, fetching a new auxtrace_buffer
22268c2ecf20Sopenharmony_ci		 * if need be.
22278c2ecf20Sopenharmony_ci		 */
22288c2ecf20Sopenharmony_cirefetch:
22298c2ecf20Sopenharmony_ci		ret = cs_etm__get_data_block(etmq);
22308c2ecf20Sopenharmony_ci		if (ret < 0)
22318c2ecf20Sopenharmony_ci			goto out;
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci		/*
22348c2ecf20Sopenharmony_ci		 * No more auxtrace_buffers to process in this etmq, simply
22358c2ecf20Sopenharmony_ci		 * move on to another entry in the auxtrace_heap.
22368c2ecf20Sopenharmony_ci		 */
22378c2ecf20Sopenharmony_ci		if (!ret)
22388c2ecf20Sopenharmony_ci			continue;
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_ci		ret = cs_etm__decode_data_block(etmq);
22418c2ecf20Sopenharmony_ci		if (ret)
22428c2ecf20Sopenharmony_ci			goto out;
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci		timestamp = cs_etm__etmq_get_timestamp(etmq, &trace_chan_id);
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci		if (!timestamp) {
22478c2ecf20Sopenharmony_ci			/*
22488c2ecf20Sopenharmony_ci			 * Function cs_etm__decode_data_block() returns when
22498c2ecf20Sopenharmony_ci			 * there is no more traces to decode in the current
22508c2ecf20Sopenharmony_ci			 * auxtrace_buffer OR when a timestamp has been
22518c2ecf20Sopenharmony_ci			 * encountered on any of the traceID queues.  Since we
22528c2ecf20Sopenharmony_ci			 * did not get a timestamp, there is no more traces to
22538c2ecf20Sopenharmony_ci			 * process in this auxtrace_buffer.  As such empty and
22548c2ecf20Sopenharmony_ci			 * flush all traceID queues.
22558c2ecf20Sopenharmony_ci			 */
22568c2ecf20Sopenharmony_ci			cs_etm__clear_all_traceid_queues(etmq);
22578c2ecf20Sopenharmony_ci
22588c2ecf20Sopenharmony_ci			/* Fetch another auxtrace_buffer for this etmq */
22598c2ecf20Sopenharmony_ci			goto refetch;
22608c2ecf20Sopenharmony_ci		}
22618c2ecf20Sopenharmony_ci
22628c2ecf20Sopenharmony_ci		/*
22638c2ecf20Sopenharmony_ci		 * Add to the min heap the timestamp for packets that have
22648c2ecf20Sopenharmony_ci		 * just been decoded.  They will be processed and synthesized
22658c2ecf20Sopenharmony_ci		 * during the next call to cs_etm__process_traceid_queue() for
22668c2ecf20Sopenharmony_ci		 * this queue/traceID.
22678c2ecf20Sopenharmony_ci		 */
22688c2ecf20Sopenharmony_ci		cs_queue_nr = TO_CS_QUEUE_NR(queue_nr, trace_chan_id);
22698c2ecf20Sopenharmony_ci		ret = auxtrace_heap__add(&etm->heap, cs_queue_nr, timestamp);
22708c2ecf20Sopenharmony_ci	}
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_ciout:
22738c2ecf20Sopenharmony_ci	return ret;
22748c2ecf20Sopenharmony_ci}
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_cistatic int cs_etm__process_itrace_start(struct cs_etm_auxtrace *etm,
22778c2ecf20Sopenharmony_ci					union perf_event *event)
22788c2ecf20Sopenharmony_ci{
22798c2ecf20Sopenharmony_ci	struct thread *th;
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci	if (etm->timeless_decoding)
22828c2ecf20Sopenharmony_ci		return 0;
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci	/*
22858c2ecf20Sopenharmony_ci	 * Add the tid/pid to the log so that we can get a match when
22868c2ecf20Sopenharmony_ci	 * we get a contextID from the decoder.
22878c2ecf20Sopenharmony_ci	 */
22888c2ecf20Sopenharmony_ci	th = machine__findnew_thread(etm->machine,
22898c2ecf20Sopenharmony_ci				     event->itrace_start.pid,
22908c2ecf20Sopenharmony_ci				     event->itrace_start.tid);
22918c2ecf20Sopenharmony_ci	if (!th)
22928c2ecf20Sopenharmony_ci		return -ENOMEM;
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	thread__put(th);
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci	return 0;
22978c2ecf20Sopenharmony_ci}
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_cistatic int cs_etm__process_switch_cpu_wide(struct cs_etm_auxtrace *etm,
23008c2ecf20Sopenharmony_ci					   union perf_event *event)
23018c2ecf20Sopenharmony_ci{
23028c2ecf20Sopenharmony_ci	struct thread *th;
23038c2ecf20Sopenharmony_ci	bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_ci	/*
23068c2ecf20Sopenharmony_ci	 * Context switch in per-thread mode are irrelevant since perf
23078c2ecf20Sopenharmony_ci	 * will start/stop tracing as the process is scheduled.
23088c2ecf20Sopenharmony_ci	 */
23098c2ecf20Sopenharmony_ci	if (etm->timeless_decoding)
23108c2ecf20Sopenharmony_ci		return 0;
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci	/*
23138c2ecf20Sopenharmony_ci	 * SWITCH_IN events carry the next process to be switched out while
23148c2ecf20Sopenharmony_ci	 * SWITCH_OUT events carry the process to be switched in.  As such
23158c2ecf20Sopenharmony_ci	 * we don't care about IN events.
23168c2ecf20Sopenharmony_ci	 */
23178c2ecf20Sopenharmony_ci	if (!out)
23188c2ecf20Sopenharmony_ci		return 0;
23198c2ecf20Sopenharmony_ci
23208c2ecf20Sopenharmony_ci	/*
23218c2ecf20Sopenharmony_ci	 * Add the tid/pid to the log so that we can get a match when
23228c2ecf20Sopenharmony_ci	 * we get a contextID from the decoder.
23238c2ecf20Sopenharmony_ci	 */
23248c2ecf20Sopenharmony_ci	th = machine__findnew_thread(etm->machine,
23258c2ecf20Sopenharmony_ci				     event->context_switch.next_prev_pid,
23268c2ecf20Sopenharmony_ci				     event->context_switch.next_prev_tid);
23278c2ecf20Sopenharmony_ci	if (!th)
23288c2ecf20Sopenharmony_ci		return -ENOMEM;
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	thread__put(th);
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	return 0;
23338c2ecf20Sopenharmony_ci}
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_cistatic int cs_etm__process_event(struct perf_session *session,
23368c2ecf20Sopenharmony_ci				 union perf_event *event,
23378c2ecf20Sopenharmony_ci				 struct perf_sample *sample,
23388c2ecf20Sopenharmony_ci				 struct perf_tool *tool)
23398c2ecf20Sopenharmony_ci{
23408c2ecf20Sopenharmony_ci	int err = 0;
23418c2ecf20Sopenharmony_ci	u64 timestamp;
23428c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *etm = container_of(session->auxtrace,
23438c2ecf20Sopenharmony_ci						   struct cs_etm_auxtrace,
23448c2ecf20Sopenharmony_ci						   auxtrace);
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	if (dump_trace)
23478c2ecf20Sopenharmony_ci		return 0;
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	if (!tool->ordered_events) {
23508c2ecf20Sopenharmony_ci		pr_err("CoreSight ETM Trace requires ordered events\n");
23518c2ecf20Sopenharmony_ci		return -EINVAL;
23528c2ecf20Sopenharmony_ci	}
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_ci	if (sample->time && (sample->time != (u64) -1))
23558c2ecf20Sopenharmony_ci		timestamp = sample->time;
23568c2ecf20Sopenharmony_ci	else
23578c2ecf20Sopenharmony_ci		timestamp = 0;
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_ci	if (timestamp || etm->timeless_decoding) {
23608c2ecf20Sopenharmony_ci		err = cs_etm__update_queues(etm);
23618c2ecf20Sopenharmony_ci		if (err)
23628c2ecf20Sopenharmony_ci			return err;
23638c2ecf20Sopenharmony_ci	}
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci	if (etm->timeless_decoding &&
23668c2ecf20Sopenharmony_ci	    event->header.type == PERF_RECORD_EXIT)
23678c2ecf20Sopenharmony_ci		return cs_etm__process_timeless_queues(etm,
23688c2ecf20Sopenharmony_ci						       event->fork.tid);
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_ci	if (event->header.type == PERF_RECORD_ITRACE_START)
23718c2ecf20Sopenharmony_ci		return cs_etm__process_itrace_start(etm, event);
23728c2ecf20Sopenharmony_ci	else if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)
23738c2ecf20Sopenharmony_ci		return cs_etm__process_switch_cpu_wide(etm, event);
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci	if (!etm->timeless_decoding &&
23768c2ecf20Sopenharmony_ci	    event->header.type == PERF_RECORD_AUX)
23778c2ecf20Sopenharmony_ci		return cs_etm__process_queues(etm);
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci	return 0;
23808c2ecf20Sopenharmony_ci}
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_cistatic int cs_etm__process_auxtrace_event(struct perf_session *session,
23838c2ecf20Sopenharmony_ci					  union perf_event *event,
23848c2ecf20Sopenharmony_ci					  struct perf_tool *tool __maybe_unused)
23858c2ecf20Sopenharmony_ci{
23868c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *etm = container_of(session->auxtrace,
23878c2ecf20Sopenharmony_ci						   struct cs_etm_auxtrace,
23888c2ecf20Sopenharmony_ci						   auxtrace);
23898c2ecf20Sopenharmony_ci	if (!etm->data_queued) {
23908c2ecf20Sopenharmony_ci		struct auxtrace_buffer *buffer;
23918c2ecf20Sopenharmony_ci		off_t  data_offset;
23928c2ecf20Sopenharmony_ci		int fd = perf_data__fd(session->data);
23938c2ecf20Sopenharmony_ci		bool is_pipe = perf_data__is_pipe(session->data);
23948c2ecf20Sopenharmony_ci		int err;
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci		if (is_pipe)
23978c2ecf20Sopenharmony_ci			data_offset = 0;
23988c2ecf20Sopenharmony_ci		else {
23998c2ecf20Sopenharmony_ci			data_offset = lseek(fd, 0, SEEK_CUR);
24008c2ecf20Sopenharmony_ci			if (data_offset == -1)
24018c2ecf20Sopenharmony_ci				return -errno;
24028c2ecf20Sopenharmony_ci		}
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci		err = auxtrace_queues__add_event(&etm->queues, session,
24058c2ecf20Sopenharmony_ci						 event, data_offset, &buffer);
24068c2ecf20Sopenharmony_ci		if (err)
24078c2ecf20Sopenharmony_ci			return err;
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci		if (dump_trace)
24108c2ecf20Sopenharmony_ci			if (auxtrace_buffer__get_data(buffer, fd)) {
24118c2ecf20Sopenharmony_ci				cs_etm__dump_event(etm, buffer);
24128c2ecf20Sopenharmony_ci				auxtrace_buffer__put_data(buffer);
24138c2ecf20Sopenharmony_ci			}
24148c2ecf20Sopenharmony_ci	}
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ci	return 0;
24178c2ecf20Sopenharmony_ci}
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_cistatic bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm)
24208c2ecf20Sopenharmony_ci{
24218c2ecf20Sopenharmony_ci	struct evsel *evsel;
24228c2ecf20Sopenharmony_ci	struct evlist *evlist = etm->session->evlist;
24238c2ecf20Sopenharmony_ci	bool timeless_decoding = true;
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	/*
24268c2ecf20Sopenharmony_ci	 * Circle through the list of event and complain if we find one
24278c2ecf20Sopenharmony_ci	 * with the time bit set.
24288c2ecf20Sopenharmony_ci	 */
24298c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
24308c2ecf20Sopenharmony_ci		if ((evsel->core.attr.sample_type & PERF_SAMPLE_TIME))
24318c2ecf20Sopenharmony_ci			timeless_decoding = false;
24328c2ecf20Sopenharmony_ci	}
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	return timeless_decoding;
24358c2ecf20Sopenharmony_ci}
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_cistatic const char * const cs_etm_global_header_fmts[] = {
24388c2ecf20Sopenharmony_ci	[CS_HEADER_VERSION_0]	= "	Header version		       %llx\n",
24398c2ecf20Sopenharmony_ci	[CS_PMU_TYPE_CPUS]	= "	PMU type/num cpus	       %llx\n",
24408c2ecf20Sopenharmony_ci	[CS_ETM_SNAPSHOT]	= "	Snapshot		       %llx\n",
24418c2ecf20Sopenharmony_ci};
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_cistatic const char * const cs_etm_priv_fmts[] = {
24448c2ecf20Sopenharmony_ci	[CS_ETM_MAGIC]		= "	Magic number		       %llx\n",
24458c2ecf20Sopenharmony_ci	[CS_ETM_CPU]		= "	CPU			       %lld\n",
24468c2ecf20Sopenharmony_ci	[CS_ETM_ETMCR]		= "	ETMCR			       %llx\n",
24478c2ecf20Sopenharmony_ci	[CS_ETM_ETMTRACEIDR]	= "	ETMTRACEIDR		       %llx\n",
24488c2ecf20Sopenharmony_ci	[CS_ETM_ETMCCER]	= "	ETMCCER			       %llx\n",
24498c2ecf20Sopenharmony_ci	[CS_ETM_ETMIDR]		= "	ETMIDR			       %llx\n",
24508c2ecf20Sopenharmony_ci};
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_cistatic const char * const cs_etmv4_priv_fmts[] = {
24538c2ecf20Sopenharmony_ci	[CS_ETM_MAGIC]		= "	Magic number		       %llx\n",
24548c2ecf20Sopenharmony_ci	[CS_ETM_CPU]		= "	CPU			       %lld\n",
24558c2ecf20Sopenharmony_ci	[CS_ETMV4_TRCCONFIGR]	= "	TRCCONFIGR		       %llx\n",
24568c2ecf20Sopenharmony_ci	[CS_ETMV4_TRCTRACEIDR]	= "	TRCTRACEIDR		       %llx\n",
24578c2ecf20Sopenharmony_ci	[CS_ETMV4_TRCIDR0]	= "	TRCIDR0			       %llx\n",
24588c2ecf20Sopenharmony_ci	[CS_ETMV4_TRCIDR1]	= "	TRCIDR1			       %llx\n",
24598c2ecf20Sopenharmony_ci	[CS_ETMV4_TRCIDR2]	= "	TRCIDR2			       %llx\n",
24608c2ecf20Sopenharmony_ci	[CS_ETMV4_TRCIDR8]	= "	TRCIDR8			       %llx\n",
24618c2ecf20Sopenharmony_ci	[CS_ETMV4_TRCAUTHSTATUS] = "	TRCAUTHSTATUS		       %llx\n",
24628c2ecf20Sopenharmony_ci};
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_cistatic void cs_etm__print_auxtrace_info(__u64 *val, int num)
24658c2ecf20Sopenharmony_ci{
24668c2ecf20Sopenharmony_ci	int i, j, cpu = 0;
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci	for (i = 0; i < CS_HEADER_VERSION_0_MAX; i++)
24698c2ecf20Sopenharmony_ci		fprintf(stdout, cs_etm_global_header_fmts[i], val[i]);
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	for (i = CS_HEADER_VERSION_0_MAX; cpu < num; cpu++) {
24728c2ecf20Sopenharmony_ci		if (val[i] == __perf_cs_etmv3_magic)
24738c2ecf20Sopenharmony_ci			for (j = 0; j < CS_ETM_PRIV_MAX; j++, i++)
24748c2ecf20Sopenharmony_ci				fprintf(stdout, cs_etm_priv_fmts[j], val[i]);
24758c2ecf20Sopenharmony_ci		else if (val[i] == __perf_cs_etmv4_magic)
24768c2ecf20Sopenharmony_ci			for (j = 0; j < CS_ETMV4_PRIV_MAX; j++, i++)
24778c2ecf20Sopenharmony_ci				fprintf(stdout, cs_etmv4_priv_fmts[j], val[i]);
24788c2ecf20Sopenharmony_ci		else
24798c2ecf20Sopenharmony_ci			/* failure.. return */
24808c2ecf20Sopenharmony_ci			return;
24818c2ecf20Sopenharmony_ci	}
24828c2ecf20Sopenharmony_ci}
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ciint cs_etm__process_auxtrace_info(union perf_event *event,
24858c2ecf20Sopenharmony_ci				  struct perf_session *session)
24868c2ecf20Sopenharmony_ci{
24878c2ecf20Sopenharmony_ci	struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
24888c2ecf20Sopenharmony_ci	struct cs_etm_auxtrace *etm = NULL;
24898c2ecf20Sopenharmony_ci	struct int_node *inode;
24908c2ecf20Sopenharmony_ci	unsigned int pmu_type;
24918c2ecf20Sopenharmony_ci	int event_header_size = sizeof(struct perf_event_header);
24928c2ecf20Sopenharmony_ci	int info_header_size;
24938c2ecf20Sopenharmony_ci	int total_size = auxtrace_info->header.size;
24948c2ecf20Sopenharmony_ci	int priv_size = 0;
24958c2ecf20Sopenharmony_ci	int num_cpu;
24968c2ecf20Sopenharmony_ci	int err = 0, idx = -1;
24978c2ecf20Sopenharmony_ci	int i, j, k;
24988c2ecf20Sopenharmony_ci	u64 *ptr, *hdr = NULL;
24998c2ecf20Sopenharmony_ci	u64 **metadata = NULL;
25008c2ecf20Sopenharmony_ci
25018c2ecf20Sopenharmony_ci	/*
25028c2ecf20Sopenharmony_ci	 * sizeof(auxtrace_info_event::type) +
25038c2ecf20Sopenharmony_ci	 * sizeof(auxtrace_info_event::reserved) == 8
25048c2ecf20Sopenharmony_ci	 */
25058c2ecf20Sopenharmony_ci	info_header_size = 8;
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_ci	if (total_size < (event_header_size + info_header_size))
25088c2ecf20Sopenharmony_ci		return -EINVAL;
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci	priv_size = total_size - event_header_size - info_header_size;
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci	/* First the global part */
25138c2ecf20Sopenharmony_ci	ptr = (u64 *) auxtrace_info->priv;
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	/* Look for version '0' of the header */
25168c2ecf20Sopenharmony_ci	if (ptr[0] != 0)
25178c2ecf20Sopenharmony_ci		return -EINVAL;
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci	hdr = zalloc(sizeof(*hdr) * CS_HEADER_VERSION_0_MAX);
25208c2ecf20Sopenharmony_ci	if (!hdr)
25218c2ecf20Sopenharmony_ci		return -ENOMEM;
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci	/* Extract header information - see cs-etm.h for format */
25248c2ecf20Sopenharmony_ci	for (i = 0; i < CS_HEADER_VERSION_0_MAX; i++)
25258c2ecf20Sopenharmony_ci		hdr[i] = ptr[i];
25268c2ecf20Sopenharmony_ci	num_cpu = hdr[CS_PMU_TYPE_CPUS] & 0xffffffff;
25278c2ecf20Sopenharmony_ci	pmu_type = (unsigned int) ((hdr[CS_PMU_TYPE_CPUS] >> 32) &
25288c2ecf20Sopenharmony_ci				    0xffffffff);
25298c2ecf20Sopenharmony_ci
25308c2ecf20Sopenharmony_ci	/*
25318c2ecf20Sopenharmony_ci	 * Create an RB tree for traceID-metadata tuple.  Since the conversion
25328c2ecf20Sopenharmony_ci	 * has to be made for each packet that gets decoded, optimizing access
25338c2ecf20Sopenharmony_ci	 * in anything other than a sequential array is worth doing.
25348c2ecf20Sopenharmony_ci	 */
25358c2ecf20Sopenharmony_ci	traceid_list = intlist__new(NULL);
25368c2ecf20Sopenharmony_ci	if (!traceid_list) {
25378c2ecf20Sopenharmony_ci		err = -ENOMEM;
25388c2ecf20Sopenharmony_ci		goto err_free_hdr;
25398c2ecf20Sopenharmony_ci	}
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci	metadata = zalloc(sizeof(*metadata) * num_cpu);
25428c2ecf20Sopenharmony_ci	if (!metadata) {
25438c2ecf20Sopenharmony_ci		err = -ENOMEM;
25448c2ecf20Sopenharmony_ci		goto err_free_traceid_list;
25458c2ecf20Sopenharmony_ci	}
25468c2ecf20Sopenharmony_ci
25478c2ecf20Sopenharmony_ci	/*
25488c2ecf20Sopenharmony_ci	 * The metadata is stored in the auxtrace_info section and encodes
25498c2ecf20Sopenharmony_ci	 * the configuration of the ARM embedded trace macrocell which is
25508c2ecf20Sopenharmony_ci	 * required by the trace decoder to properly decode the trace due
25518c2ecf20Sopenharmony_ci	 * to its highly compressed nature.
25528c2ecf20Sopenharmony_ci	 */
25538c2ecf20Sopenharmony_ci	for (j = 0; j < num_cpu; j++) {
25548c2ecf20Sopenharmony_ci		if (ptr[i] == __perf_cs_etmv3_magic) {
25558c2ecf20Sopenharmony_ci			metadata[j] = zalloc(sizeof(*metadata[j]) *
25568c2ecf20Sopenharmony_ci					     CS_ETM_PRIV_MAX);
25578c2ecf20Sopenharmony_ci			if (!metadata[j]) {
25588c2ecf20Sopenharmony_ci				err = -ENOMEM;
25598c2ecf20Sopenharmony_ci				goto err_free_metadata;
25608c2ecf20Sopenharmony_ci			}
25618c2ecf20Sopenharmony_ci			for (k = 0; k < CS_ETM_PRIV_MAX; k++)
25628c2ecf20Sopenharmony_ci				metadata[j][k] = ptr[i + k];
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci			/* The traceID is our handle */
25658c2ecf20Sopenharmony_ci			idx = metadata[j][CS_ETM_ETMTRACEIDR];
25668c2ecf20Sopenharmony_ci			i += CS_ETM_PRIV_MAX;
25678c2ecf20Sopenharmony_ci		} else if (ptr[i] == __perf_cs_etmv4_magic) {
25688c2ecf20Sopenharmony_ci			metadata[j] = zalloc(sizeof(*metadata[j]) *
25698c2ecf20Sopenharmony_ci					     CS_ETMV4_PRIV_MAX);
25708c2ecf20Sopenharmony_ci			if (!metadata[j]) {
25718c2ecf20Sopenharmony_ci				err = -ENOMEM;
25728c2ecf20Sopenharmony_ci				goto err_free_metadata;
25738c2ecf20Sopenharmony_ci			}
25748c2ecf20Sopenharmony_ci			for (k = 0; k < CS_ETMV4_PRIV_MAX; k++)
25758c2ecf20Sopenharmony_ci				metadata[j][k] = ptr[i + k];
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci			/* The traceID is our handle */
25788c2ecf20Sopenharmony_ci			idx = metadata[j][CS_ETMV4_TRCTRACEIDR];
25798c2ecf20Sopenharmony_ci			i += CS_ETMV4_PRIV_MAX;
25808c2ecf20Sopenharmony_ci		}
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci		/* Get an RB node for this CPU */
25838c2ecf20Sopenharmony_ci		inode = intlist__findnew(traceid_list, idx);
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci		/* Something went wrong, no need to continue */
25868c2ecf20Sopenharmony_ci		if (!inode) {
25878c2ecf20Sopenharmony_ci			err = -ENOMEM;
25888c2ecf20Sopenharmony_ci			goto err_free_metadata;
25898c2ecf20Sopenharmony_ci		}
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci		/*
25928c2ecf20Sopenharmony_ci		 * The node for that CPU should not be taken.
25938c2ecf20Sopenharmony_ci		 * Back out if that's the case.
25948c2ecf20Sopenharmony_ci		 */
25958c2ecf20Sopenharmony_ci		if (inode->priv) {
25968c2ecf20Sopenharmony_ci			err = -EINVAL;
25978c2ecf20Sopenharmony_ci			goto err_free_metadata;
25988c2ecf20Sopenharmony_ci		}
25998c2ecf20Sopenharmony_ci		/* All good, associate the traceID with the metadata pointer */
26008c2ecf20Sopenharmony_ci		inode->priv = metadata[j];
26018c2ecf20Sopenharmony_ci	}
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_ci	/*
26048c2ecf20Sopenharmony_ci	 * Each of CS_HEADER_VERSION_0_MAX, CS_ETM_PRIV_MAX and
26058c2ecf20Sopenharmony_ci	 * CS_ETMV4_PRIV_MAX mark how many double words are in the
26068c2ecf20Sopenharmony_ci	 * global metadata, and each cpu's metadata respectively.
26078c2ecf20Sopenharmony_ci	 * The following tests if the correct number of double words was
26088c2ecf20Sopenharmony_ci	 * present in the auxtrace info section.
26098c2ecf20Sopenharmony_ci	 */
26108c2ecf20Sopenharmony_ci	if (i * 8 != priv_size) {
26118c2ecf20Sopenharmony_ci		err = -EINVAL;
26128c2ecf20Sopenharmony_ci		goto err_free_metadata;
26138c2ecf20Sopenharmony_ci	}
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci	etm = zalloc(sizeof(*etm));
26168c2ecf20Sopenharmony_ci
26178c2ecf20Sopenharmony_ci	if (!etm) {
26188c2ecf20Sopenharmony_ci		err = -ENOMEM;
26198c2ecf20Sopenharmony_ci		goto err_free_metadata;
26208c2ecf20Sopenharmony_ci	}
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci	err = auxtrace_queues__init(&etm->queues);
26238c2ecf20Sopenharmony_ci	if (err)
26248c2ecf20Sopenharmony_ci		goto err_free_etm;
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_ci	etm->session = session;
26278c2ecf20Sopenharmony_ci	etm->machine = &session->machines.host;
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_ci	etm->num_cpu = num_cpu;
26308c2ecf20Sopenharmony_ci	etm->pmu_type = pmu_type;
26318c2ecf20Sopenharmony_ci	etm->snapshot_mode = (hdr[CS_ETM_SNAPSHOT] != 0);
26328c2ecf20Sopenharmony_ci	etm->metadata = metadata;
26338c2ecf20Sopenharmony_ci	etm->auxtrace_type = auxtrace_info->type;
26348c2ecf20Sopenharmony_ci	etm->timeless_decoding = cs_etm__is_timeless_decoding(etm);
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ci	etm->auxtrace.process_event = cs_etm__process_event;
26378c2ecf20Sopenharmony_ci	etm->auxtrace.process_auxtrace_event = cs_etm__process_auxtrace_event;
26388c2ecf20Sopenharmony_ci	etm->auxtrace.flush_events = cs_etm__flush_events;
26398c2ecf20Sopenharmony_ci	etm->auxtrace.free_events = cs_etm__free_events;
26408c2ecf20Sopenharmony_ci	etm->auxtrace.free = cs_etm__free;
26418c2ecf20Sopenharmony_ci	etm->auxtrace.evsel_is_auxtrace = cs_etm__evsel_is_auxtrace;
26428c2ecf20Sopenharmony_ci	session->auxtrace = &etm->auxtrace;
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci	etm->unknown_thread = thread__new(999999999, 999999999);
26458c2ecf20Sopenharmony_ci	if (!etm->unknown_thread) {
26468c2ecf20Sopenharmony_ci		err = -ENOMEM;
26478c2ecf20Sopenharmony_ci		goto err_free_queues;
26488c2ecf20Sopenharmony_ci	}
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci	/*
26518c2ecf20Sopenharmony_ci	 * Initialize list node so that at thread__zput() we can avoid
26528c2ecf20Sopenharmony_ci	 * segmentation fault at list_del_init().
26538c2ecf20Sopenharmony_ci	 */
26548c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&etm->unknown_thread->node);
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	err = thread__set_comm(etm->unknown_thread, "unknown", 0);
26578c2ecf20Sopenharmony_ci	if (err)
26588c2ecf20Sopenharmony_ci		goto err_delete_thread;
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci	if (thread__init_maps(etm->unknown_thread, etm->machine)) {
26618c2ecf20Sopenharmony_ci		err = -ENOMEM;
26628c2ecf20Sopenharmony_ci		goto err_delete_thread;
26638c2ecf20Sopenharmony_ci	}
26648c2ecf20Sopenharmony_ci
26658c2ecf20Sopenharmony_ci	if (dump_trace) {
26668c2ecf20Sopenharmony_ci		cs_etm__print_auxtrace_info(auxtrace_info->priv, num_cpu);
26678c2ecf20Sopenharmony_ci		return 0;
26688c2ecf20Sopenharmony_ci	}
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ci	if (session->itrace_synth_opts->set) {
26718c2ecf20Sopenharmony_ci		etm->synth_opts = *session->itrace_synth_opts;
26728c2ecf20Sopenharmony_ci	} else {
26738c2ecf20Sopenharmony_ci		itrace_synth_opts__set_default(&etm->synth_opts,
26748c2ecf20Sopenharmony_ci				session->itrace_synth_opts->default_no_sample);
26758c2ecf20Sopenharmony_ci		etm->synth_opts.callchain = false;
26768c2ecf20Sopenharmony_ci	}
26778c2ecf20Sopenharmony_ci
26788c2ecf20Sopenharmony_ci	err = cs_etm__synth_events(etm, session);
26798c2ecf20Sopenharmony_ci	if (err)
26808c2ecf20Sopenharmony_ci		goto err_delete_thread;
26818c2ecf20Sopenharmony_ci
26828c2ecf20Sopenharmony_ci	err = auxtrace_queues__process_index(&etm->queues, session);
26838c2ecf20Sopenharmony_ci	if (err)
26848c2ecf20Sopenharmony_ci		goto err_delete_thread;
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_ci	etm->data_queued = etm->queues.populated;
26878c2ecf20Sopenharmony_ci
26888c2ecf20Sopenharmony_ci	return 0;
26898c2ecf20Sopenharmony_ci
26908c2ecf20Sopenharmony_cierr_delete_thread:
26918c2ecf20Sopenharmony_ci	thread__zput(etm->unknown_thread);
26928c2ecf20Sopenharmony_cierr_free_queues:
26938c2ecf20Sopenharmony_ci	auxtrace_queues__free(&etm->queues);
26948c2ecf20Sopenharmony_ci	session->auxtrace = NULL;
26958c2ecf20Sopenharmony_cierr_free_etm:
26968c2ecf20Sopenharmony_ci	zfree(&etm);
26978c2ecf20Sopenharmony_cierr_free_metadata:
26988c2ecf20Sopenharmony_ci	/* No need to check @metadata[j], free(NULL) is supported */
26998c2ecf20Sopenharmony_ci	for (j = 0; j < num_cpu; j++)
27008c2ecf20Sopenharmony_ci		zfree(&metadata[j]);
27018c2ecf20Sopenharmony_ci	zfree(&metadata);
27028c2ecf20Sopenharmony_cierr_free_traceid_list:
27038c2ecf20Sopenharmony_ci	intlist__delete(traceid_list);
27048c2ecf20Sopenharmony_cierr_free_hdr:
27058c2ecf20Sopenharmony_ci	zfree(&hdr);
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci	return err;
27088c2ecf20Sopenharmony_ci}
2709