Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9a01a11 authored by Mathieu Poirier's avatar Mathieu Poirier Committed by Arnaldo Carvalho de Melo
Browse files

perf tools: Add support for decoding CoreSight trace data



Adding functionality to create a CoreSight trace decoder capable
of decoding trace data pushed by a client application.

Co-authored-by: default avatarTor Jeremiassen <tor@ti.com>
Signed-off-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
Acked-by: default avatarJiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Kim Phillips <kim.phillips@arm.com>
Cc: Mike Leach <mike.leach@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: linux-arm-kernel@lists.infradead.org
Link: http://lkml.kernel.org/r/1516211539-5166-6-git-send-email-mathieu.poirier@linaro.org


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 68ffe390
Loading
Loading
Loading
Loading
+119 −0
Original line number Diff line number Diff line
@@ -200,6 +200,121 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
	}
}

static ocsd_datapath_resp_t
cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
			      const ocsd_generic_trace_elem *elem,
			      const u8 trace_chan_id,
			      enum cs_etm_sample_type sample_type)
{
	u32 et = 0;
	struct int_node *inode = NULL;

	if (decoder->packet_count >= MAX_BUFFER - 1)
		return OCSD_RESP_FATAL_SYS_ERR;

	/* Search the RB tree for the cpu associated with this traceID */
	inode = intlist__find(traceid_list, trace_chan_id);
	if (!inode)
		return OCSD_RESP_FATAL_SYS_ERR;

	et = decoder->tail;
	decoder->packet_buffer[et].sample_type = sample_type;
	decoder->packet_buffer[et].start_addr = elem->st_addr;
	decoder->packet_buffer[et].end_addr = elem->en_addr;
	decoder->packet_buffer[et].exc = false;
	decoder->packet_buffer[et].exc_ret = false;
	decoder->packet_buffer[et].cpu = *((int *)inode->priv);

	/* Wrap around if need be */
	et = (et + 1) & (MAX_BUFFER - 1);

	decoder->tail = et;
	decoder->packet_count++;

	if (decoder->packet_count == MAX_BUFFER - 1)
		return OCSD_RESP_WAIT;

	return OCSD_RESP_CONT;
}

static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
				const void *context,
				const ocsd_trc_index_t indx __maybe_unused,
				const u8 trace_chan_id __maybe_unused,
				const ocsd_generic_trace_elem *elem)
{
	ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
	struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context;

	switch (elem->elem_type) {
	case OCSD_GEN_TRC_ELEM_UNKNOWN:
		break;
	case OCSD_GEN_TRC_ELEM_NO_SYNC:
		decoder->trace_on = false;
		break;
	case OCSD_GEN_TRC_ELEM_TRACE_ON:
		decoder->trace_on = true;
		break;
	case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
		resp = cs_etm_decoder__buffer_packet(decoder, elem,
						     trace_chan_id,
						     CS_ETM_RANGE);
		break;
	case OCSD_GEN_TRC_ELEM_EXCEPTION:
		decoder->packet_buffer[decoder->tail].exc = true;
		break;
	case OCSD_GEN_TRC_ELEM_EXCEPTION_RET:
		decoder->packet_buffer[decoder->tail].exc_ret = true;
		break;
	case OCSD_GEN_TRC_ELEM_PE_CONTEXT:
	case OCSD_GEN_TRC_ELEM_EO_TRACE:
	case OCSD_GEN_TRC_ELEM_ADDR_NACC:
	case OCSD_GEN_TRC_ELEM_TIMESTAMP:
	case OCSD_GEN_TRC_ELEM_CYCLE_COUNT:
	case OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN:
	case OCSD_GEN_TRC_ELEM_EVENT:
	case OCSD_GEN_TRC_ELEM_SWTRACE:
	case OCSD_GEN_TRC_ELEM_CUSTOM:
	default:
		break;
	}

	return resp;
}

static int cs_etm_decoder__create_etm_packet_decoder(
					struct cs_etm_trace_params *t_params,
					struct cs_etm_decoder *decoder)
{
	const char *decoder_name;
	ocsd_etmv4_cfg trace_config_etmv4;
	void *trace_config;
	u8 csid;

	switch (t_params->protocol) {
	case CS_ETM_PROTO_ETMV4i:
		cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4);
		decoder_name = OCSD_BUILTIN_DCD_ETMV4I;
		trace_config = &trace_config_etmv4;
		break;
	default:
		return -1;
	}

	if (ocsd_dt_create_decoder(decoder->dcd_tree,
				     decoder_name,
				     OCSD_CREATE_FLG_FULL_DECODER,
				     trace_config, &csid))
		return -1;

	if (ocsd_dt_set_gen_elem_outfn(decoder->dcd_tree,
				       cs_etm_decoder__gen_trace_elem_printer,
				       decoder))
		return -1;

	return 0;
}

static int
cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params,
				   struct cs_etm_trace_params *t_params,
@@ -208,6 +323,10 @@ cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params,
	if (d_params->operation == CS_ETM_OPERATION_PRINT)
		return cs_etm_decoder__create_etm_packet_printer(t_params,
								 decoder);
	else if (d_params->operation == CS_ETM_OPERATION_DECODE)
		return cs_etm_decoder__create_etm_packet_decoder(t_params,
								 decoder);

	return -1;
}