Commit 09277295 authored by Mike Leach's avatar Mike Leach Committed by Arnaldo Carvalho de Melo
Browse files

perf cs-etm: Move mapping of Trace ID and cpu into helper function



The information to associate Trace ID and CPU will be changing.

Drivers will start outputting this as a hardware ID packet in the data
file which if present will be used in preference to the AUXINFO values.

To prepare for this we provide a helper functions to do the individual ID
mapping, and one to extract the IDs from the completed metadata blocks.

Reviewed-by: default avatarJames Clark <james.clark@arm.com>
Signed-off-by: default avatarMike Leach <mike.leach@linaro.org>
Acked-by: default avatarSuzuki Poulouse <suzuki.poulose@arm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Darren Hart <darren@os.amperecomputing.com>
Cc: Ganapatrao Kulkarni <gankulkarni@os.amperecomputing.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will@kernel.org>
Cc: coresight@lists.linaro.org
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20230331055645.26918-2-mike.leach@linaro.org


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 84c3a2bb
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -7,9 +7,14 @@
#ifndef _LINUX_CORESIGHT_PMU_H
#define _LINUX_CORESIGHT_PMU_H

#include <linux/bits.h>

#define CORESIGHT_ETM_PMU_NAME "cs_etm"
#define CORESIGHT_ETM_PMU_SEED  0x10

/* CoreSight trace ID is currently the bottom 7 bits of the value */
#define CORESIGHT_TRACE_ID_VAL_MASK	GENMASK(6, 0)

/*
 * Below are the definition of bit offsets for perf option, and works as
 * arbitrary values for all ETM versions.
+2 −1
Original line number Diff line number Diff line
@@ -148,7 +148,8 @@ static void cs_etm__print_auxtrace_info(u64 *val, int num)
	for (i = CS_HEADER_VERSION_MAX; cpu < num; cpu++) {
		if (version == 0)
			err = cs_etm__print_cpu_metadata_v0(val, &i);
		else if (version == 1)
		/* printing same for both, but value bit flags added on v2 */
		else if ((version == 1) || (version == 2))
			err = cs_etm__print_cpu_metadata_v1(val, &i);
		if (err)
			return;
+60 −32
Original line number Diff line number Diff line
@@ -196,6 +196,30 @@ int cs_etm__get_pid_fmt(u8 trace_chan_id, u64 *pid_fmt)
	return 0;
}

static int cs_etm__map_trace_id(u8 trace_chan_id, u64 *cpu_metadata)
{
	struct int_node *inode;

	/* Get an RB node for this CPU */
	inode = intlist__findnew(traceid_list, trace_chan_id);

	/* Something went wrong, no need to continue */
	if (!inode)
		return -ENOMEM;

	/*
	 * The node for that CPU should not be taken.
	 * Back out if that's the case.
	 */
	if (inode->priv)
		return -EINVAL;

	/* All good, associate the traceID with the metadata pointer */
	inode->priv = cpu_metadata;

	return 0;
}

void cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq,
					      u8 trace_chan_id)
{
@@ -2804,17 +2828,46 @@ static bool cs_etm__has_virtual_ts(u64 **metadata, int num_cpu)
	return true;
}

/* map trace ids to correct metadata block, from information in metadata */
static int cs_etm__map_trace_ids_metadata(int num_cpu, u64 **metadata)
{
	u64 cs_etm_magic;
	u8 trace_chan_id;
	int i, err;

	for (i = 0; i < num_cpu; i++) {
		cs_etm_magic = metadata[i][CS_ETM_MAGIC];
		switch (cs_etm_magic) {
		case __perf_cs_etmv3_magic:
			trace_chan_id = (u8)((metadata[i][CS_ETM_ETMTRACEIDR]) &
					     CORESIGHT_TRACE_ID_VAL_MASK);
			break;
		case __perf_cs_etmv4_magic:
		case __perf_cs_ete_magic:
			trace_chan_id = (u8)((metadata[i][CS_ETMV4_TRCTRACEIDR]) &
					      CORESIGHT_TRACE_ID_VAL_MASK);
			break;
		default:
			/* unknown magic number */
			return -EINVAL;
		}
		err = cs_etm__map_trace_id(trace_chan_id, metadata[i]);
		if (err)
			return err;
	}
	return 0;
}

int cs_etm__process_auxtrace_info_full(union perf_event *event,
				       struct perf_session *session)
{
	struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
	struct cs_etm_auxtrace *etm = NULL;
	struct int_node *inode;
	struct perf_record_time_conv *tc = &session->time_conv;
	int event_header_size = sizeof(struct perf_event_header);
	int total_size = auxtrace_info->header.size;
	int priv_size = 0;
	int num_cpu, trcidr_idx;
	int num_cpu;
	int err = 0;
	int i, j;
	u64 *ptr = NULL;
@@ -2853,23 +2906,13 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
				cs_etm__create_meta_blk(ptr, &i,
							CS_ETM_PRIV_MAX,
							CS_ETM_NR_TRC_PARAMS_V0);

			/* The traceID is our handle */
			trcidr_idx = CS_ETM_ETMTRACEIDR;

		} else if (ptr[i] == __perf_cs_etmv4_magic) {
			metadata[j] =
				cs_etm__create_meta_blk(ptr, &i,
							CS_ETMV4_PRIV_MAX,
							CS_ETMV4_NR_TRC_PARAMS_V0);

			/* The traceID is our handle */
			trcidr_idx = CS_ETMV4_TRCTRACEIDR;
		} else if (ptr[i] == __perf_cs_ete_magic) {
			metadata[j] = cs_etm__create_meta_blk(ptr, &i, CS_ETE_PRIV_MAX, -1);

			/* ETE shares first part of metadata with ETMv4 */
			trcidr_idx = CS_ETMV4_TRCTRACEIDR;
		} else {
			ui__error("CS ETM Trace: Unrecognised magic number %#"PRIx64". File could be from a newer version of perf.\n",
				  ptr[i]);
@@ -2881,26 +2924,6 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
			err = -ENOMEM;
			goto err_free_metadata;
		}

		/* Get an RB node for this CPU */
		inode = intlist__findnew(traceid_list, metadata[j][trcidr_idx]);

		/* Something went wrong, no need to continue */
		if (!inode) {
			err = -ENOMEM;
			goto err_free_metadata;
		}

		/*
		 * The node for that CPU should not be taken.
		 * Back out if that's the case.
		 */
		if (inode->priv) {
			err = -EINVAL;
			goto err_free_metadata;
		}
		/* All good, associate the traceID with the metadata pointer */
		inode->priv = metadata[j];
	}

	/*
@@ -2994,6 +3017,11 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
	if (err)
		goto err_delete_thread;

	/* before aux records are queued, need to map metadata to trace IDs */
	err = cs_etm__map_trace_ids_metadata(num_cpu, metadata);
	if (err)
		goto err_delete_thread;

	err = cs_etm__queue_aux_records(session);
	if (err)
		goto err_delete_thread;
+12 −2
Original line number Diff line number Diff line
@@ -29,13 +29,17 @@ enum {
/*
 * Update the version for new format.
 *
 * New version 1 format adds a param count to the per cpu metadata.
 * Version 1: format adds a param count to the per cpu metadata.
 * This allows easy adding of new metadata parameters.
 * Requires that new params always added after current ones.
 * Also allows client reader to handle file versions that are different by
 * checking the number of params in the file vs the number expected.
 *
 * Version 2: Drivers will use PERF_RECORD_AUX_OUTPUT_HW_ID to output
 * CoreSight Trace ID. ...TRACEIDR metadata will be set to legacy values
 * but with addition flags.
 */
#define CS_HEADER_CURRENT_VERSION 1
#define CS_HEADER_CURRENT_VERSION	2

/* Beginning of header common to both ETMv3 and V4 */
enum {
@@ -97,6 +101,12 @@ enum {
	CS_ETE_PRIV_MAX
};

/*
 * Check for valid CoreSight trace ID. If an invalid value is present in the metadata,
 * then IDs are present in the hardware ID packet in the data file.
 */
#define CS_IS_VALID_TRACE_ID(id) ((id > 0) && (id < 0x70))

/*
 * ETMv3 exception encoding number:
 * See Embedded Trace Macrocell specification (ARM IHI 0014Q)