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/err.h>
108c2ecf20Sopenharmony_ci#include <linux/list.h>
118c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
128c2ecf20Sopenharmony_ci#include <stdlib.h>
138c2ecf20Sopenharmony_ci#include <opencsd/c_api/opencsd_c_api.h>
148c2ecf20Sopenharmony_ci#include <opencsd/etmv4/trc_pkt_types_etmv4.h>
158c2ecf20Sopenharmony_ci#include <opencsd/ocsd_if_types.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "cs-etm.h"
188c2ecf20Sopenharmony_ci#include "cs-etm-decoder.h"
198c2ecf20Sopenharmony_ci#include "intlist.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* use raw logging */
228c2ecf20Sopenharmony_ci#ifdef CS_DEBUG_RAW
238c2ecf20Sopenharmony_ci#define CS_LOG_RAW_FRAMES
248c2ecf20Sopenharmony_ci#ifdef CS_RAW_PACKED
258c2ecf20Sopenharmony_ci#define CS_RAW_DEBUG_FLAGS (OCSD_DFRMTR_UNPACKED_RAW_OUT | \
268c2ecf20Sopenharmony_ci			    OCSD_DFRMTR_PACKED_RAW_OUT)
278c2ecf20Sopenharmony_ci#else
288c2ecf20Sopenharmony_ci#define CS_RAW_DEBUG_FLAGS (OCSD_DFRMTR_UNPACKED_RAW_OUT)
298c2ecf20Sopenharmony_ci#endif
308c2ecf20Sopenharmony_ci#endif
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistruct cs_etm_decoder {
338c2ecf20Sopenharmony_ci	void *data;
348c2ecf20Sopenharmony_ci	void (*packet_printer)(const char *msg);
358c2ecf20Sopenharmony_ci	dcd_tree_handle_t dcd_tree;
368c2ecf20Sopenharmony_ci	cs_etm_mem_cb_type mem_access;
378c2ecf20Sopenharmony_ci	ocsd_datapath_resp_t prev_return;
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic u32
418c2ecf20Sopenharmony_cics_etm_decoder__mem_access(const void *context,
428c2ecf20Sopenharmony_ci			   const ocsd_vaddr_t address,
438c2ecf20Sopenharmony_ci			   const ocsd_mem_space_acc_t mem_space __maybe_unused,
448c2ecf20Sopenharmony_ci			   const u8 trace_chan_id,
458c2ecf20Sopenharmony_ci			   const u32 req_size,
468c2ecf20Sopenharmony_ci			   u8 *buffer)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	return decoder->mem_access(decoder->data, trace_chan_id,
518c2ecf20Sopenharmony_ci				   address, req_size, buffer);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ciint cs_etm_decoder__add_mem_access_cb(struct cs_etm_decoder *decoder,
558c2ecf20Sopenharmony_ci				      u64 start, u64 end,
568c2ecf20Sopenharmony_ci				      cs_etm_mem_cb_type cb_func)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	decoder->mem_access = cb_func;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (ocsd_dt_add_callback_trcid_mem_acc(decoder->dcd_tree, start, end,
618c2ecf20Sopenharmony_ci					       OCSD_MEM_SPACE_ANY,
628c2ecf20Sopenharmony_ci					       cs_etm_decoder__mem_access,
638c2ecf20Sopenharmony_ci					       decoder))
648c2ecf20Sopenharmony_ci		return -1;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	return 0;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ciint cs_etm_decoder__reset(struct cs_etm_decoder *decoder)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	ocsd_datapath_resp_t dp_ret;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	decoder->prev_return = OCSD_RESP_CONT;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	dp_ret = ocsd_dt_process_data(decoder->dcd_tree, OCSD_OP_RESET,
768c2ecf20Sopenharmony_ci				      0, 0, NULL, NULL);
778c2ecf20Sopenharmony_ci	if (OCSD_DATA_RESP_IS_FATAL(dp_ret))
788c2ecf20Sopenharmony_ci		return -1;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return 0;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ciint cs_etm_decoder__get_packet(struct cs_etm_packet_queue *packet_queue,
848c2ecf20Sopenharmony_ci			       struct cs_etm_packet *packet)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	if (!packet_queue || !packet)
878c2ecf20Sopenharmony_ci		return -EINVAL;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* Nothing to do, might as well just return */
908c2ecf20Sopenharmony_ci	if (packet_queue->packet_count == 0)
918c2ecf20Sopenharmony_ci		return 0;
928c2ecf20Sopenharmony_ci	/*
938c2ecf20Sopenharmony_ci	 * The queueing process in function cs_etm_decoder__buffer_packet()
948c2ecf20Sopenharmony_ci	 * increments the tail *before* using it.  This is somewhat counter
958c2ecf20Sopenharmony_ci	 * intuitive but it has the advantage of centralizing tail management
968c2ecf20Sopenharmony_ci	 * at a single location.  Because of that we need to follow the same
978c2ecf20Sopenharmony_ci	 * heuristic with the head, i.e we increment it before using its
988c2ecf20Sopenharmony_ci	 * value.  Otherwise the first element of the packet queue is not
998c2ecf20Sopenharmony_ci	 * used.
1008c2ecf20Sopenharmony_ci	 */
1018c2ecf20Sopenharmony_ci	packet_queue->head = (packet_queue->head + 1) &
1028c2ecf20Sopenharmony_ci			     (CS_ETM_PACKET_MAX_BUFFER - 1);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	*packet = packet_queue->packet_buffer[packet_queue->head];
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	packet_queue->packet_count--;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	return 1;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic int cs_etm_decoder__gen_etmv3_config(struct cs_etm_trace_params *params,
1128c2ecf20Sopenharmony_ci					    ocsd_etmv3_cfg *config)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	config->reg_idr = params->etmv3.reg_idr;
1158c2ecf20Sopenharmony_ci	config->reg_ctrl = params->etmv3.reg_ctrl;
1168c2ecf20Sopenharmony_ci	config->reg_ccer = params->etmv3.reg_ccer;
1178c2ecf20Sopenharmony_ci	config->reg_trc_id = params->etmv3.reg_trc_id;
1188c2ecf20Sopenharmony_ci	config->arch_ver = ARCH_V7;
1198c2ecf20Sopenharmony_ci	config->core_prof = profile_CortexA;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return 0;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic void cs_etm_decoder__gen_etmv4_config(struct cs_etm_trace_params *params,
1258c2ecf20Sopenharmony_ci					     ocsd_etmv4_cfg *config)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	config->reg_configr = params->etmv4.reg_configr;
1288c2ecf20Sopenharmony_ci	config->reg_traceidr = params->etmv4.reg_traceidr;
1298c2ecf20Sopenharmony_ci	config->reg_idr0 = params->etmv4.reg_idr0;
1308c2ecf20Sopenharmony_ci	config->reg_idr1 = params->etmv4.reg_idr1;
1318c2ecf20Sopenharmony_ci	config->reg_idr2 = params->etmv4.reg_idr2;
1328c2ecf20Sopenharmony_ci	config->reg_idr8 = params->etmv4.reg_idr8;
1338c2ecf20Sopenharmony_ci	config->reg_idr9 = 0;
1348c2ecf20Sopenharmony_ci	config->reg_idr10 = 0;
1358c2ecf20Sopenharmony_ci	config->reg_idr11 = 0;
1368c2ecf20Sopenharmony_ci	config->reg_idr12 = 0;
1378c2ecf20Sopenharmony_ci	config->reg_idr13 = 0;
1388c2ecf20Sopenharmony_ci	config->arch_ver = ARCH_V8;
1398c2ecf20Sopenharmony_ci	config->core_prof = profile_CortexA;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic void cs_etm_decoder__print_str_cb(const void *p_context,
1438c2ecf20Sopenharmony_ci					 const char *msg,
1448c2ecf20Sopenharmony_ci					 const int str_len)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	if (p_context && str_len)
1478c2ecf20Sopenharmony_ci		((struct cs_etm_decoder *)p_context)->packet_printer(msg);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic int
1518c2ecf20Sopenharmony_cics_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params,
1528c2ecf20Sopenharmony_ci					 struct cs_etm_decoder *decoder)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	int ret = 0;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (d_params->packet_printer == NULL)
1578c2ecf20Sopenharmony_ci		return -1;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	decoder->packet_printer = d_params->packet_printer;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/*
1628c2ecf20Sopenharmony_ci	 * Set up a library default logger to process any printers
1638c2ecf20Sopenharmony_ci	 * (packet/raw frame) we add later.
1648c2ecf20Sopenharmony_ci	 */
1658c2ecf20Sopenharmony_ci	ret = ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1);
1668c2ecf20Sopenharmony_ci	if (ret != 0)
1678c2ecf20Sopenharmony_ci		return -1;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/* no stdout / err / file output */
1708c2ecf20Sopenharmony_ci	ret = ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL);
1718c2ecf20Sopenharmony_ci	if (ret != 0)
1728c2ecf20Sopenharmony_ci		return -1;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	/*
1758c2ecf20Sopenharmony_ci	 * Set the string CB for the default logger, passes strings to
1768c2ecf20Sopenharmony_ci	 * perf print logger.
1778c2ecf20Sopenharmony_ci	 */
1788c2ecf20Sopenharmony_ci	ret = ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree,
1798c2ecf20Sopenharmony_ci					      (void *)decoder,
1808c2ecf20Sopenharmony_ci					      cs_etm_decoder__print_str_cb);
1818c2ecf20Sopenharmony_ci	if (ret != 0)
1828c2ecf20Sopenharmony_ci		ret = -1;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	return 0;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci#ifdef CS_LOG_RAW_FRAMES
1888c2ecf20Sopenharmony_cistatic void
1898c2ecf20Sopenharmony_cics_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params,
1908c2ecf20Sopenharmony_ci				       struct cs_etm_decoder *decoder)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	/* Only log these during a --dump operation */
1938c2ecf20Sopenharmony_ci	if (d_params->operation == CS_ETM_OPERATION_PRINT) {
1948c2ecf20Sopenharmony_ci		/* set up a library default logger to process the
1958c2ecf20Sopenharmony_ci		 *  raw frame printer we add later
1968c2ecf20Sopenharmony_ci		 */
1978c2ecf20Sopenharmony_ci		ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci		/* no stdout / err / file output */
2008c2ecf20Sopenharmony_ci		ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		/* set the string CB for the default logger,
2038c2ecf20Sopenharmony_ci		 * passes strings to perf print logger.
2048c2ecf20Sopenharmony_ci		 */
2058c2ecf20Sopenharmony_ci		ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree,
2068c2ecf20Sopenharmony_ci						(void *)decoder,
2078c2ecf20Sopenharmony_ci						cs_etm_decoder__print_str_cb);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		/* use the built in library printer for the raw frames */
2108c2ecf20Sopenharmony_ci		ocsd_dt_set_raw_frame_printer(decoder->dcd_tree,
2118c2ecf20Sopenharmony_ci					      CS_RAW_DEBUG_FLAGS);
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci#else
2158c2ecf20Sopenharmony_cistatic void
2168c2ecf20Sopenharmony_cics_etm_decoder__init_raw_frame_logging(
2178c2ecf20Sopenharmony_ci		struct cs_etm_decoder_params *d_params __maybe_unused,
2188c2ecf20Sopenharmony_ci		struct cs_etm_decoder *decoder __maybe_unused)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci#endif
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic int cs_etm_decoder__create_packet_printer(struct cs_etm_decoder *decoder,
2248c2ecf20Sopenharmony_ci						 const char *decoder_name,
2258c2ecf20Sopenharmony_ci						 void *trace_config)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	u8 csid;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	if (ocsd_dt_create_decoder(decoder->dcd_tree, decoder_name,
2308c2ecf20Sopenharmony_ci				   OCSD_CREATE_FLG_PACKET_PROC,
2318c2ecf20Sopenharmony_ci				   trace_config, &csid))
2328c2ecf20Sopenharmony_ci		return -1;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (ocsd_dt_set_pkt_protocol_printer(decoder->dcd_tree, csid, 0))
2358c2ecf20Sopenharmony_ci		return -1;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return 0;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic int
2418c2ecf20Sopenharmony_cics_etm_decoder__create_etm_packet_printer(struct cs_etm_trace_params *t_params,
2428c2ecf20Sopenharmony_ci					  struct cs_etm_decoder *decoder)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	const char *decoder_name;
2458c2ecf20Sopenharmony_ci	ocsd_etmv3_cfg config_etmv3;
2468c2ecf20Sopenharmony_ci	ocsd_etmv4_cfg trace_config_etmv4;
2478c2ecf20Sopenharmony_ci	void *trace_config;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	switch (t_params->protocol) {
2508c2ecf20Sopenharmony_ci	case CS_ETM_PROTO_ETMV3:
2518c2ecf20Sopenharmony_ci	case CS_ETM_PROTO_PTM:
2528c2ecf20Sopenharmony_ci		cs_etm_decoder__gen_etmv3_config(t_params, &config_etmv3);
2538c2ecf20Sopenharmony_ci		decoder_name = (t_params->protocol == CS_ETM_PROTO_ETMV3) ?
2548c2ecf20Sopenharmony_ci							OCSD_BUILTIN_DCD_ETMV3 :
2558c2ecf20Sopenharmony_ci							OCSD_BUILTIN_DCD_PTM;
2568c2ecf20Sopenharmony_ci		trace_config = &config_etmv3;
2578c2ecf20Sopenharmony_ci		break;
2588c2ecf20Sopenharmony_ci	case CS_ETM_PROTO_ETMV4i:
2598c2ecf20Sopenharmony_ci		cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4);
2608c2ecf20Sopenharmony_ci		decoder_name = OCSD_BUILTIN_DCD_ETMV4I;
2618c2ecf20Sopenharmony_ci		trace_config = &trace_config_etmv4;
2628c2ecf20Sopenharmony_ci		break;
2638c2ecf20Sopenharmony_ci	default:
2648c2ecf20Sopenharmony_ci		return -1;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	return cs_etm_decoder__create_packet_printer(decoder,
2688c2ecf20Sopenharmony_ci						     decoder_name,
2698c2ecf20Sopenharmony_ci						     trace_config);
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic ocsd_datapath_resp_t
2738c2ecf20Sopenharmony_cics_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq,
2748c2ecf20Sopenharmony_ci				  struct cs_etm_packet_queue *packet_queue,
2758c2ecf20Sopenharmony_ci				  const uint8_t trace_chan_id)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	/* No timestamp packet has been received, nothing to do */
2788c2ecf20Sopenharmony_ci	if (!packet_queue->timestamp)
2798c2ecf20Sopenharmony_ci		return OCSD_RESP_CONT;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	packet_queue->timestamp = packet_queue->next_timestamp;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	/* Estimate the timestamp for the next range packet */
2848c2ecf20Sopenharmony_ci	packet_queue->next_timestamp += packet_queue->instr_count;
2858c2ecf20Sopenharmony_ci	packet_queue->instr_count = 0;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	/* Tell the front end which traceid_queue needs attention */
2888c2ecf20Sopenharmony_ci	cs_etm__etmq_set_traceid_queue_timestamp(etmq, trace_chan_id);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	return OCSD_RESP_WAIT;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic ocsd_datapath_resp_t
2948c2ecf20Sopenharmony_cics_etm_decoder__do_hard_timestamp(struct cs_etm_queue *etmq,
2958c2ecf20Sopenharmony_ci				  const ocsd_generic_trace_elem *elem,
2968c2ecf20Sopenharmony_ci				  const uint8_t trace_chan_id)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	struct cs_etm_packet_queue *packet_queue;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	/* First get the packet queue for this traceID */
3018c2ecf20Sopenharmony_ci	packet_queue = cs_etm__etmq_get_packet_queue(etmq, trace_chan_id);
3028c2ecf20Sopenharmony_ci	if (!packet_queue)
3038c2ecf20Sopenharmony_ci		return OCSD_RESP_FATAL_SYS_ERR;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/*
3068c2ecf20Sopenharmony_ci	 * We've seen a timestamp packet before - simply record the new value.
3078c2ecf20Sopenharmony_ci	 * Function do_soft_timestamp() will report the value to the front end,
3088c2ecf20Sopenharmony_ci	 * hence asking the decoder to keep decoding rather than stopping.
3098c2ecf20Sopenharmony_ci	 */
3108c2ecf20Sopenharmony_ci	if (packet_queue->timestamp) {
3118c2ecf20Sopenharmony_ci		packet_queue->next_timestamp = elem->timestamp;
3128c2ecf20Sopenharmony_ci		return OCSD_RESP_CONT;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	/*
3168c2ecf20Sopenharmony_ci	 * This is the first timestamp we've seen since the beginning of traces
3178c2ecf20Sopenharmony_ci	 * or a discontinuity.  Since timestamps packets are generated *after*
3188c2ecf20Sopenharmony_ci	 * range packets have been generated, we need to estimate the time at
3198c2ecf20Sopenharmony_ci	 * which instructions started by substracting the number of instructions
3208c2ecf20Sopenharmony_ci	 * executed to the timestamp.
3218c2ecf20Sopenharmony_ci	 */
3228c2ecf20Sopenharmony_ci	packet_queue->timestamp = elem->timestamp - packet_queue->instr_count;
3238c2ecf20Sopenharmony_ci	packet_queue->next_timestamp = elem->timestamp;
3248c2ecf20Sopenharmony_ci	packet_queue->instr_count = 0;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	/* Tell the front end which traceid_queue needs attention */
3278c2ecf20Sopenharmony_ci	cs_etm__etmq_set_traceid_queue_timestamp(etmq, trace_chan_id);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/* Halt processing until we are being told to proceed */
3308c2ecf20Sopenharmony_ci	return OCSD_RESP_WAIT;
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic void
3348c2ecf20Sopenharmony_cics_etm_decoder__reset_timestamp(struct cs_etm_packet_queue *packet_queue)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	packet_queue->timestamp = 0;
3378c2ecf20Sopenharmony_ci	packet_queue->next_timestamp = 0;
3388c2ecf20Sopenharmony_ci	packet_queue->instr_count = 0;
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic ocsd_datapath_resp_t
3428c2ecf20Sopenharmony_cics_etm_decoder__buffer_packet(struct cs_etm_packet_queue *packet_queue,
3438c2ecf20Sopenharmony_ci			      const u8 trace_chan_id,
3448c2ecf20Sopenharmony_ci			      enum cs_etm_sample_type sample_type)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	u32 et = 0;
3478c2ecf20Sopenharmony_ci	int cpu;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (packet_queue->packet_count >= CS_ETM_PACKET_MAX_BUFFER - 1)
3508c2ecf20Sopenharmony_ci		return OCSD_RESP_FATAL_SYS_ERR;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (cs_etm__get_cpu(trace_chan_id, &cpu) < 0)
3538c2ecf20Sopenharmony_ci		return OCSD_RESP_FATAL_SYS_ERR;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	et = packet_queue->tail;
3568c2ecf20Sopenharmony_ci	et = (et + 1) & (CS_ETM_PACKET_MAX_BUFFER - 1);
3578c2ecf20Sopenharmony_ci	packet_queue->tail = et;
3588c2ecf20Sopenharmony_ci	packet_queue->packet_count++;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].sample_type = sample_type;
3618c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].isa = CS_ETM_ISA_UNKNOWN;
3628c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].cpu = cpu;
3638c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].start_addr = CS_ETM_INVAL_ADDR;
3648c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].end_addr = CS_ETM_INVAL_ADDR;
3658c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].instr_count = 0;
3668c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].last_instr_taken_branch = false;
3678c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].last_instr_size = 0;
3688c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].last_instr_type = 0;
3698c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].last_instr_subtype = 0;
3708c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].last_instr_cond = 0;
3718c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].flags = 0;
3728c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].exception_number = UINT32_MAX;
3738c2ecf20Sopenharmony_ci	packet_queue->packet_buffer[et].trace_chan_id = trace_chan_id;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (packet_queue->packet_count == CS_ETM_PACKET_MAX_BUFFER - 1)
3768c2ecf20Sopenharmony_ci		return OCSD_RESP_WAIT;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	return OCSD_RESP_CONT;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic ocsd_datapath_resp_t
3828c2ecf20Sopenharmony_cics_etm_decoder__buffer_range(struct cs_etm_queue *etmq,
3838c2ecf20Sopenharmony_ci			     struct cs_etm_packet_queue *packet_queue,
3848c2ecf20Sopenharmony_ci			     const ocsd_generic_trace_elem *elem,
3858c2ecf20Sopenharmony_ci			     const uint8_t trace_chan_id)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	int ret = 0;
3888c2ecf20Sopenharmony_ci	struct cs_etm_packet *packet;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	ret = cs_etm_decoder__buffer_packet(packet_queue, trace_chan_id,
3918c2ecf20Sopenharmony_ci					    CS_ETM_RANGE);
3928c2ecf20Sopenharmony_ci	if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT)
3938c2ecf20Sopenharmony_ci		return ret;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	packet = &packet_queue->packet_buffer[packet_queue->tail];
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	switch (elem->isa) {
3988c2ecf20Sopenharmony_ci	case ocsd_isa_aarch64:
3998c2ecf20Sopenharmony_ci		packet->isa = CS_ETM_ISA_A64;
4008c2ecf20Sopenharmony_ci		break;
4018c2ecf20Sopenharmony_ci	case ocsd_isa_arm:
4028c2ecf20Sopenharmony_ci		packet->isa = CS_ETM_ISA_A32;
4038c2ecf20Sopenharmony_ci		break;
4048c2ecf20Sopenharmony_ci	case ocsd_isa_thumb2:
4058c2ecf20Sopenharmony_ci		packet->isa = CS_ETM_ISA_T32;
4068c2ecf20Sopenharmony_ci		break;
4078c2ecf20Sopenharmony_ci	case ocsd_isa_tee:
4088c2ecf20Sopenharmony_ci	case ocsd_isa_jazelle:
4098c2ecf20Sopenharmony_ci	case ocsd_isa_custom:
4108c2ecf20Sopenharmony_ci	case ocsd_isa_unknown:
4118c2ecf20Sopenharmony_ci	default:
4128c2ecf20Sopenharmony_ci		packet->isa = CS_ETM_ISA_UNKNOWN;
4138c2ecf20Sopenharmony_ci	}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	packet->start_addr = elem->st_addr;
4168c2ecf20Sopenharmony_ci	packet->end_addr = elem->en_addr;
4178c2ecf20Sopenharmony_ci	packet->instr_count = elem->num_instr_range;
4188c2ecf20Sopenharmony_ci	packet->last_instr_type = elem->last_i_type;
4198c2ecf20Sopenharmony_ci	packet->last_instr_subtype = elem->last_i_subtype;
4208c2ecf20Sopenharmony_ci	packet->last_instr_cond = elem->last_instr_cond;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	switch (elem->last_i_type) {
4238c2ecf20Sopenharmony_ci	case OCSD_INSTR_BR:
4248c2ecf20Sopenharmony_ci	case OCSD_INSTR_BR_INDIRECT:
4258c2ecf20Sopenharmony_ci		packet->last_instr_taken_branch = elem->last_instr_exec;
4268c2ecf20Sopenharmony_ci		break;
4278c2ecf20Sopenharmony_ci	case OCSD_INSTR_ISB:
4288c2ecf20Sopenharmony_ci	case OCSD_INSTR_DSB_DMB:
4298c2ecf20Sopenharmony_ci	case OCSD_INSTR_WFI_WFE:
4308c2ecf20Sopenharmony_ci	case OCSD_INSTR_OTHER:
4318c2ecf20Sopenharmony_ci	default:
4328c2ecf20Sopenharmony_ci		packet->last_instr_taken_branch = false;
4338c2ecf20Sopenharmony_ci		break;
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	packet->last_instr_size = elem->last_instr_sz;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	/* per-thread scenario, no need to generate a timestamp */
4398c2ecf20Sopenharmony_ci	if (cs_etm__etmq_is_timeless(etmq))
4408c2ecf20Sopenharmony_ci		goto out;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	/*
4438c2ecf20Sopenharmony_ci	 * The packet queue is full and we haven't seen a timestamp (had we
4448c2ecf20Sopenharmony_ci	 * seen one the packet queue wouldn't be full).  Let the front end
4458c2ecf20Sopenharmony_ci	 * deal with it.
4468c2ecf20Sopenharmony_ci	 */
4478c2ecf20Sopenharmony_ci	if (ret == OCSD_RESP_WAIT)
4488c2ecf20Sopenharmony_ci		goto out;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	packet_queue->instr_count += elem->num_instr_range;
4518c2ecf20Sopenharmony_ci	/* Tell the front end we have a new timestamp to process */
4528c2ecf20Sopenharmony_ci	ret = cs_etm_decoder__do_soft_timestamp(etmq, packet_queue,
4538c2ecf20Sopenharmony_ci						trace_chan_id);
4548c2ecf20Sopenharmony_ciout:
4558c2ecf20Sopenharmony_ci	return ret;
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic ocsd_datapath_resp_t
4598c2ecf20Sopenharmony_cics_etm_decoder__buffer_discontinuity(struct cs_etm_packet_queue *queue,
4608c2ecf20Sopenharmony_ci				     const uint8_t trace_chan_id)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	/*
4638c2ecf20Sopenharmony_ci	 * Something happened and who knows when we'll get new traces so
4648c2ecf20Sopenharmony_ci	 * reset time statistics.
4658c2ecf20Sopenharmony_ci	 */
4668c2ecf20Sopenharmony_ci	cs_etm_decoder__reset_timestamp(queue);
4678c2ecf20Sopenharmony_ci	return cs_etm_decoder__buffer_packet(queue, trace_chan_id,
4688c2ecf20Sopenharmony_ci					     CS_ETM_DISCONTINUITY);
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic ocsd_datapath_resp_t
4728c2ecf20Sopenharmony_cics_etm_decoder__buffer_exception(struct cs_etm_packet_queue *queue,
4738c2ecf20Sopenharmony_ci				 const ocsd_generic_trace_elem *elem,
4748c2ecf20Sopenharmony_ci				 const uint8_t trace_chan_id)
4758c2ecf20Sopenharmony_ci{	int ret = 0;
4768c2ecf20Sopenharmony_ci	struct cs_etm_packet *packet;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	ret = cs_etm_decoder__buffer_packet(queue, trace_chan_id,
4798c2ecf20Sopenharmony_ci					    CS_ETM_EXCEPTION);
4808c2ecf20Sopenharmony_ci	if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT)
4818c2ecf20Sopenharmony_ci		return ret;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	packet = &queue->packet_buffer[queue->tail];
4848c2ecf20Sopenharmony_ci	packet->exception_number = elem->exception_number;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	return ret;
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistatic ocsd_datapath_resp_t
4908c2ecf20Sopenharmony_cics_etm_decoder__buffer_exception_ret(struct cs_etm_packet_queue *queue,
4918c2ecf20Sopenharmony_ci				     const uint8_t trace_chan_id)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	return cs_etm_decoder__buffer_packet(queue, trace_chan_id,
4948c2ecf20Sopenharmony_ci					     CS_ETM_EXCEPTION_RET);
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistatic ocsd_datapath_resp_t
4988c2ecf20Sopenharmony_cics_etm_decoder__set_tid(struct cs_etm_queue *etmq,
4998c2ecf20Sopenharmony_ci			struct cs_etm_packet_queue *packet_queue,
5008c2ecf20Sopenharmony_ci			const ocsd_generic_trace_elem *elem,
5018c2ecf20Sopenharmony_ci			const uint8_t trace_chan_id)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	pid_t tid;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	/* Ignore PE_CONTEXT packets that don't have a valid contextID */
5068c2ecf20Sopenharmony_ci	if (!elem->context.ctxt_id_valid)
5078c2ecf20Sopenharmony_ci		return OCSD_RESP_CONT;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	tid =  elem->context.context_id;
5108c2ecf20Sopenharmony_ci	if (cs_etm__etmq_set_tid(etmq, tid, trace_chan_id))
5118c2ecf20Sopenharmony_ci		return OCSD_RESP_FATAL_SYS_ERR;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	/*
5148c2ecf20Sopenharmony_ci	 * A timestamp is generated after a PE_CONTEXT element so make sure
5158c2ecf20Sopenharmony_ci	 * to rely on that coming one.
5168c2ecf20Sopenharmony_ci	 */
5178c2ecf20Sopenharmony_ci	cs_etm_decoder__reset_timestamp(packet_queue);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	return OCSD_RESP_CONT;
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
5238c2ecf20Sopenharmony_ci				const void *context,
5248c2ecf20Sopenharmony_ci				const ocsd_trc_index_t indx __maybe_unused,
5258c2ecf20Sopenharmony_ci				const u8 trace_chan_id __maybe_unused,
5268c2ecf20Sopenharmony_ci				const ocsd_generic_trace_elem *elem)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
5298c2ecf20Sopenharmony_ci	struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context;
5308c2ecf20Sopenharmony_ci	struct cs_etm_queue *etmq = decoder->data;
5318c2ecf20Sopenharmony_ci	struct cs_etm_packet_queue *packet_queue;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	/* First get the packet queue for this traceID */
5348c2ecf20Sopenharmony_ci	packet_queue = cs_etm__etmq_get_packet_queue(etmq, trace_chan_id);
5358c2ecf20Sopenharmony_ci	if (!packet_queue)
5368c2ecf20Sopenharmony_ci		return OCSD_RESP_FATAL_SYS_ERR;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	switch (elem->elem_type) {
5398c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_UNKNOWN:
5408c2ecf20Sopenharmony_ci		break;
5418c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_EO_TRACE:
5428c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_NO_SYNC:
5438c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_TRACE_ON:
5448c2ecf20Sopenharmony_ci		resp = cs_etm_decoder__buffer_discontinuity(packet_queue,
5458c2ecf20Sopenharmony_ci							    trace_chan_id);
5468c2ecf20Sopenharmony_ci		break;
5478c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
5488c2ecf20Sopenharmony_ci		resp = cs_etm_decoder__buffer_range(etmq, packet_queue, elem,
5498c2ecf20Sopenharmony_ci						    trace_chan_id);
5508c2ecf20Sopenharmony_ci		break;
5518c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_EXCEPTION:
5528c2ecf20Sopenharmony_ci		resp = cs_etm_decoder__buffer_exception(packet_queue, elem,
5538c2ecf20Sopenharmony_ci							trace_chan_id);
5548c2ecf20Sopenharmony_ci		break;
5558c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_EXCEPTION_RET:
5568c2ecf20Sopenharmony_ci		resp = cs_etm_decoder__buffer_exception_ret(packet_queue,
5578c2ecf20Sopenharmony_ci							    trace_chan_id);
5588c2ecf20Sopenharmony_ci		break;
5598c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_TIMESTAMP:
5608c2ecf20Sopenharmony_ci		resp = cs_etm_decoder__do_hard_timestamp(etmq, elem,
5618c2ecf20Sopenharmony_ci							 trace_chan_id);
5628c2ecf20Sopenharmony_ci		break;
5638c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_PE_CONTEXT:
5648c2ecf20Sopenharmony_ci		resp = cs_etm_decoder__set_tid(etmq, packet_queue,
5658c2ecf20Sopenharmony_ci					       elem, trace_chan_id);
5668c2ecf20Sopenharmony_ci		break;
5678c2ecf20Sopenharmony_ci	/* Unused packet types */
5688c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_I_RANGE_NOPATH:
5698c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_ADDR_NACC:
5708c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_CYCLE_COUNT:
5718c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN:
5728c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_EVENT:
5738c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_SWTRACE:
5748c2ecf20Sopenharmony_ci	case OCSD_GEN_TRC_ELEM_CUSTOM:
5758c2ecf20Sopenharmony_ci	default:
5768c2ecf20Sopenharmony_ci		break;
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	return resp;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic int cs_etm_decoder__create_etm_packet_decoder(
5838c2ecf20Sopenharmony_ci					struct cs_etm_trace_params *t_params,
5848c2ecf20Sopenharmony_ci					struct cs_etm_decoder *decoder)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	const char *decoder_name;
5878c2ecf20Sopenharmony_ci	ocsd_etmv3_cfg config_etmv3;
5888c2ecf20Sopenharmony_ci	ocsd_etmv4_cfg trace_config_etmv4;
5898c2ecf20Sopenharmony_ci	void *trace_config;
5908c2ecf20Sopenharmony_ci	u8 csid;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	switch (t_params->protocol) {
5938c2ecf20Sopenharmony_ci	case CS_ETM_PROTO_ETMV3:
5948c2ecf20Sopenharmony_ci	case CS_ETM_PROTO_PTM:
5958c2ecf20Sopenharmony_ci		cs_etm_decoder__gen_etmv3_config(t_params, &config_etmv3);
5968c2ecf20Sopenharmony_ci		decoder_name = (t_params->protocol == CS_ETM_PROTO_ETMV3) ?
5978c2ecf20Sopenharmony_ci							OCSD_BUILTIN_DCD_ETMV3 :
5988c2ecf20Sopenharmony_ci							OCSD_BUILTIN_DCD_PTM;
5998c2ecf20Sopenharmony_ci		trace_config = &config_etmv3;
6008c2ecf20Sopenharmony_ci		break;
6018c2ecf20Sopenharmony_ci	case CS_ETM_PROTO_ETMV4i:
6028c2ecf20Sopenharmony_ci		cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4);
6038c2ecf20Sopenharmony_ci		decoder_name = OCSD_BUILTIN_DCD_ETMV4I;
6048c2ecf20Sopenharmony_ci		trace_config = &trace_config_etmv4;
6058c2ecf20Sopenharmony_ci		break;
6068c2ecf20Sopenharmony_ci	default:
6078c2ecf20Sopenharmony_ci		return -1;
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	if (ocsd_dt_create_decoder(decoder->dcd_tree,
6118c2ecf20Sopenharmony_ci				     decoder_name,
6128c2ecf20Sopenharmony_ci				     OCSD_CREATE_FLG_FULL_DECODER,
6138c2ecf20Sopenharmony_ci				     trace_config, &csid))
6148c2ecf20Sopenharmony_ci		return -1;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	if (ocsd_dt_set_gen_elem_outfn(decoder->dcd_tree,
6178c2ecf20Sopenharmony_ci				       cs_etm_decoder__gen_trace_elem_printer,
6188c2ecf20Sopenharmony_ci				       decoder))
6198c2ecf20Sopenharmony_ci		return -1;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	return 0;
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_cistatic int
6258c2ecf20Sopenharmony_cics_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params,
6268c2ecf20Sopenharmony_ci				   struct cs_etm_trace_params *t_params,
6278c2ecf20Sopenharmony_ci				   struct cs_etm_decoder *decoder)
6288c2ecf20Sopenharmony_ci{
6298c2ecf20Sopenharmony_ci	if (d_params->operation == CS_ETM_OPERATION_PRINT)
6308c2ecf20Sopenharmony_ci		return cs_etm_decoder__create_etm_packet_printer(t_params,
6318c2ecf20Sopenharmony_ci								 decoder);
6328c2ecf20Sopenharmony_ci	else if (d_params->operation == CS_ETM_OPERATION_DECODE)
6338c2ecf20Sopenharmony_ci		return cs_etm_decoder__create_etm_packet_decoder(t_params,
6348c2ecf20Sopenharmony_ci								 decoder);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	return -1;
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_cistruct cs_etm_decoder *
6408c2ecf20Sopenharmony_cics_etm_decoder__new(int num_cpu, struct cs_etm_decoder_params *d_params,
6418c2ecf20Sopenharmony_ci		    struct cs_etm_trace_params t_params[])
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	struct cs_etm_decoder *decoder;
6448c2ecf20Sopenharmony_ci	ocsd_dcd_tree_src_t format;
6458c2ecf20Sopenharmony_ci	u32 flags;
6468c2ecf20Sopenharmony_ci	int i, ret;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	if ((!t_params) || (!d_params))
6498c2ecf20Sopenharmony_ci		return NULL;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	decoder = zalloc(sizeof(*decoder));
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if (!decoder)
6548c2ecf20Sopenharmony_ci		return NULL;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	decoder->data = d_params->data;
6578c2ecf20Sopenharmony_ci	decoder->prev_return = OCSD_RESP_CONT;
6588c2ecf20Sopenharmony_ci	format = (d_params->formatted ? OCSD_TRC_SRC_FRAME_FORMATTED :
6598c2ecf20Sopenharmony_ci					 OCSD_TRC_SRC_SINGLE);
6608c2ecf20Sopenharmony_ci	flags = 0;
6618c2ecf20Sopenharmony_ci	flags |= (d_params->fsyncs ? OCSD_DFRMTR_HAS_FSYNCS : 0);
6628c2ecf20Sopenharmony_ci	flags |= (d_params->hsyncs ? OCSD_DFRMTR_HAS_HSYNCS : 0);
6638c2ecf20Sopenharmony_ci	flags |= (d_params->frame_aligned ? OCSD_DFRMTR_FRAME_MEM_ALIGN : 0);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	/*
6668c2ecf20Sopenharmony_ci	 * Drivers may add barrier frames when used with perf, set up to
6678c2ecf20Sopenharmony_ci	 * handle this. Barriers const of FSYNC packet repeated 4 times.
6688c2ecf20Sopenharmony_ci	 */
6698c2ecf20Sopenharmony_ci	flags |= OCSD_DFRMTR_RESET_ON_4X_FSYNC;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	/* Create decode tree for the data source */
6728c2ecf20Sopenharmony_ci	decoder->dcd_tree = ocsd_create_dcd_tree(format, flags);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	if (decoder->dcd_tree == 0)
6758c2ecf20Sopenharmony_ci		goto err_free_decoder;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	/* init library print logging support */
6788c2ecf20Sopenharmony_ci	ret = cs_etm_decoder__init_def_logger_printing(d_params, decoder);
6798c2ecf20Sopenharmony_ci	if (ret != 0)
6808c2ecf20Sopenharmony_ci		goto err_free_decoder;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	/* init raw frame logging if required */
6838c2ecf20Sopenharmony_ci	cs_etm_decoder__init_raw_frame_logging(d_params, decoder);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	for (i = 0; i < num_cpu; i++) {
6868c2ecf20Sopenharmony_ci		ret = cs_etm_decoder__create_etm_decoder(d_params,
6878c2ecf20Sopenharmony_ci							 &t_params[i],
6888c2ecf20Sopenharmony_ci							 decoder);
6898c2ecf20Sopenharmony_ci		if (ret != 0)
6908c2ecf20Sopenharmony_ci			goto err_free_decoder;
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	return decoder;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_cierr_free_decoder:
6968c2ecf20Sopenharmony_ci	cs_etm_decoder__free(decoder);
6978c2ecf20Sopenharmony_ci	return NULL;
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ciint cs_etm_decoder__process_data_block(struct cs_etm_decoder *decoder,
7018c2ecf20Sopenharmony_ci				       u64 indx, const u8 *buf,
7028c2ecf20Sopenharmony_ci				       size_t len, size_t *consumed)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	int ret = 0;
7058c2ecf20Sopenharmony_ci	ocsd_datapath_resp_t cur = OCSD_RESP_CONT;
7068c2ecf20Sopenharmony_ci	ocsd_datapath_resp_t prev_return = decoder->prev_return;
7078c2ecf20Sopenharmony_ci	size_t processed = 0;
7088c2ecf20Sopenharmony_ci	u32 count;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	while (processed < len) {
7118c2ecf20Sopenharmony_ci		if (OCSD_DATA_RESP_IS_WAIT(prev_return)) {
7128c2ecf20Sopenharmony_ci			cur = ocsd_dt_process_data(decoder->dcd_tree,
7138c2ecf20Sopenharmony_ci						   OCSD_OP_FLUSH,
7148c2ecf20Sopenharmony_ci						   0,
7158c2ecf20Sopenharmony_ci						   0,
7168c2ecf20Sopenharmony_ci						   NULL,
7178c2ecf20Sopenharmony_ci						   NULL);
7188c2ecf20Sopenharmony_ci		} else if (OCSD_DATA_RESP_IS_CONT(prev_return)) {
7198c2ecf20Sopenharmony_ci			cur = ocsd_dt_process_data(decoder->dcd_tree,
7208c2ecf20Sopenharmony_ci						   OCSD_OP_DATA,
7218c2ecf20Sopenharmony_ci						   indx + processed,
7228c2ecf20Sopenharmony_ci						   len - processed,
7238c2ecf20Sopenharmony_ci						   &buf[processed],
7248c2ecf20Sopenharmony_ci						   &count);
7258c2ecf20Sopenharmony_ci			processed += count;
7268c2ecf20Sopenharmony_ci		} else {
7278c2ecf20Sopenharmony_ci			ret = -EINVAL;
7288c2ecf20Sopenharmony_ci			break;
7298c2ecf20Sopenharmony_ci		}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci		/*
7328c2ecf20Sopenharmony_ci		 * Return to the input code if the packet buffer is full.
7338c2ecf20Sopenharmony_ci		 * Flushing will get done once the packet buffer has been
7348c2ecf20Sopenharmony_ci		 * processed.
7358c2ecf20Sopenharmony_ci		 */
7368c2ecf20Sopenharmony_ci		if (OCSD_DATA_RESP_IS_WAIT(cur))
7378c2ecf20Sopenharmony_ci			break;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci		prev_return = cur;
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	decoder->prev_return = cur;
7438c2ecf20Sopenharmony_ci	*consumed = processed;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	return ret;
7468c2ecf20Sopenharmony_ci}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_civoid cs_etm_decoder__free(struct cs_etm_decoder *decoder)
7498c2ecf20Sopenharmony_ci{
7508c2ecf20Sopenharmony_ci	if (!decoder)
7518c2ecf20Sopenharmony_ci		return;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	ocsd_destroy_dcd_tree(decoder->dcd_tree);
7548c2ecf20Sopenharmony_ci	decoder->dcd_tree = NULL;
7558c2ecf20Sopenharmony_ci	free(decoder);
7568c2ecf20Sopenharmony_ci}
757