@@ -2301,6 +2301,7 @@ F: include/dt-bindings/arm/coresight-cti-dt.h
F: include/linux/coresight*
F: include/uapi/linux/coresight*
F: samples/coresight/*
+F: tools/coresight/*
F: tools/perf/Documentation/arm-coresight.txt
F: tools/perf/arch/arm/util/auxtrace.c
F: tools/perf/arch/arm/util/cs-etm.c
@@ -9,7 +9,12 @@
#include <linux/sizes.h>
+#ifdef __KERNEL__
#include "coresight-config.h"
+#else
+#include "coresight-config-uapi.h"
+#endif
+
/*
* Configurations and features can be dynamically loaded at runtime
new file mode 100644
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: GPL-2.0-only
+include ../scripts/Makefile.include
+include ../scripts/Makefile.arch
+
+# Makefile to build the coresight configuration table file reader and generator tools
+
+this-makefile := $(lastword $(MAKEFILE_LIST))
+tools-src := $(realpath $(dir $(this-makefile)))
+srctree := $(realpath $(dir $(tools-src)/../../.))
+
+# ensure we use all as the default - skip anything in included Makefile
+.DEFAULT_GOAL = all
+# MAKECMDGOALS isn't set if there's no explicit goal in the
+# command line, so set the default.
+MAKECMDGOALS ?= $(.DEFAULT_GOAL)
+
+# cs tools includes
+CS_TOOLS_INCLUDE = -I$(srctree)/drivers/hwtracing/coresight -I$(srctree)/tools/include/ \
+ -I$(srctree)/tools/include/uapi -I$(srctree)/tools/coresight
+
+# compile flags
+CFLAGS += $(CPPFLAGS) -c -Wall -DLINUX -Wno-switch -Wlogical-op -fPIC $(CS_TOOLS_INCLUDE)
+
+# object files
+coresight-cfg-file-gen-objs := coresight-cfg-file-gen.o coresight-cfg-bufw.o \
+ coresight-cfg-example1.o coresight-cfg-example2.o
+coresight-cfg-file-read-objs := coresight-cfg-file-read.o coresight-config-table.o
+
+# debug variant
+ifdef DEBUG
+CFLAGS += -g -O0 -DDEBUG
+else
+CFLAGS += -O2 -DNDEBUG
+endif
+
+.PHONY: all
+all: coresight-cfg-file-gen coresight-cfg-file-read
+
+coresight-config-table.o: src_copy
+ $(CC) $(CFLAGS) coresight-config-table.c -o coresight-config-table.o
+
+.PHONY: src_copy
+src_copy:
+ @cp $(srctree)/drivers/hwtracing/coresight/coresight-config-table.c $(srctree)/tools/coresight/.
+
+coresight-cfg-file-gen: $(coresight-cfg-file-gen-objs)
+ $(CC) $(LDFLAGS) $(coresight-cfg-file-gen-objs) -o coresight-cfg-file-gen
+
+coresight-cfg-file-read: $(coresight-cfg-file-read-objs)
+ $(CC) $(LDFLAGS) $(coresight-cfg-file-read-objs) -o coresight-cfg-file-read
+
+clean:
+ rm -f coresight-cfg-file-gen coresight-cfg-file-read
+ rm -f *.o
+ rm -f coresight-config-table.c
+ rm -f *.cscfg
new file mode 100644
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020-2022 Linaro Limited, All rights reserved.
+ * Author: Mike Leach <mike.leach@linaro.org>
+ */
+
+#include <string.h>
+
+#include "coresight-cfg-bufw.h"
+#include "coresight-config-uapi.h"
+
+/*
+ * Set of macros to make writing the buffer code easier.
+ *.
+ * Uses naming convention as 'buffer' for the buffer pointer and
+ * 'used' as the current bytes used by the encosing function.
+ */
+#define cscfg_write_u64(val64) { \
+ *(u64 *)(buffer + used) = val64; \
+ used += sizeof(u64); \
+ }
+
+#define cscfg_write_u32(val32) { \
+ *(u32 *)(buffer + used) = val32; \
+ used += sizeof(u32); \
+ }
+
+#define cscfg_write_u16(val16) { \
+ *(u16 *)(buffer + used) = val16; \
+ used += sizeof(u16); \
+ }
+
+#define cscfg_write_u8(val8) { \
+ *(buffer + used) = val8; \
+ used++; \
+ }
+
+/* write the header at the start of the buffer */
+static int cscfg_table_write_fhdr(u8 *buffer, const int buflen,
+ const struct cscfg_table_header *fhdr)
+{
+ int used = 0;
+
+ cscfg_write_u32(fhdr->magic_version);
+ cscfg_write_u16(fhdr->length);
+ cscfg_write_u16(fhdr->nr_configs);
+ cscfg_write_u16(fhdr->nr_features);
+ return used;
+}
+
+static int cscfg_table_write_string(u8 *buffer, const int buflen, const char *string)
+{
+ int len, used = 0;
+
+ len = strlen(string);
+ if (len > CSCFG_TABLE_STR_MAXSIZE)
+ return -EINVAL;
+
+ if (buflen < (len + 1 + sizeof(u16)))
+ return -EINVAL;
+
+ cscfg_write_u16((u16)(len + 1));
+ strncpy((char *)(buffer + used), string, len + 1);
+ used += (len + 1);
+
+ return used;
+}
+
+static int cscfg_table_write_elem_hdr(u8 *buffer, const int buflen,
+ struct cscfg_table_elem_header *ehdr)
+{
+ int used = 0;
+
+ if (buflen < (sizeof(u16) + sizeof(u8)))
+ return -EINVAL;
+
+ cscfg_write_u16(ehdr->elem_length);
+ cscfg_write_u8(ehdr->elem_type);
+
+ return used;
+}
+
+static int cscfg_table_write_config(u8 *buffer, const int buflen,
+ struct cscfg_config_desc *config_desc)
+{
+ int used = 0, bytes_w, space_req, preset_bytes, i;
+ struct cscfg_table_elem_header ehdr;
+
+ ehdr.elem_length = 0;
+ ehdr.elem_type = CSCFG_TABLE_ELEM_TYPE_CFG;
+
+ /* write element header at current buffer location */
+ bytes_w = cscfg_table_write_elem_hdr(buffer, buflen, &ehdr);
+ if (bytes_w < 0)
+ return bytes_w;
+ used += bytes_w;
+
+ /* write out the configuration name */
+ bytes_w = cscfg_table_write_string(buffer + used, buflen - used,
+ config_desc->name);
+ if (bytes_w < 0)
+ return bytes_w;
+ used += bytes_w;
+
+ /* write out the description string */
+ bytes_w = cscfg_table_write_string(buffer + used, buflen - used,
+ config_desc->description);
+ if (bytes_w < 0)
+ return bytes_w;
+ used += bytes_w;
+
+ /*
+ * calculate the space needed for variables + presets
+ * [u16 value - nr_presets]
+ * [u32 value - nr_total_params]
+ * [u16 value - nr_feat_refs]
+ * [u64 values] * (nr_presets * nr_total_params)
+ */
+ preset_bytes = sizeof(u64) * config_desc->nr_presets * config_desc->nr_total_params;
+ space_req = (sizeof(u16) * 2) + sizeof(u32) + preset_bytes;
+
+ if ((buflen - used) < space_req)
+ return -EINVAL;
+
+ cscfg_write_u16((u16)config_desc->nr_presets);
+ cscfg_write_u32((u32)config_desc->nr_total_params);
+ cscfg_write_u16((u16)config_desc->nr_feat_refs);
+ if (preset_bytes) {
+ memcpy(buffer + used, (u8 *)config_desc->presets, preset_bytes);
+ used += preset_bytes;
+ }
+
+ /* now write the feature ref names */
+ for (i = 0; i < config_desc->nr_feat_refs; i++) {
+ bytes_w = cscfg_table_write_string(buffer + used, buflen - used,
+ config_desc->feat_ref_names[i]);
+ if (bytes_w < 0)
+ return bytes_w;
+ used += bytes_w;
+ }
+
+ /* rewrite the element header with the correct length */
+ ehdr.elem_length = used;
+ bytes_w = cscfg_table_write_elem_hdr(buffer, buflen, &ehdr);
+ /* used must not be updated here */
+ if (bytes_w < 0)
+ return bytes_w;
+
+ return used;
+}
+
+/*
+ * write a parameter structure into the buffer in following format:
+ * [cscfg_table_elem_str] - parameter name.
+ * [u64 value: param_value] - initial value.
+ */
+static int cscfg_table_write_param(u8 *buffer, const int buflen,
+ struct cscfg_parameter_desc *param_desc)
+{
+ int used = 0, bytes_w;
+
+ bytes_w = cscfg_table_write_string(buffer + used, buflen - used,
+ param_desc->name);
+ if (bytes_w < 0)
+ return bytes_w;
+ used += bytes_w;
+
+ if ((buflen - used) < sizeof(u64))
+ return -EINVAL;
+
+ cscfg_write_u64(param_desc->value);
+ return used;
+}
+
+/*
+ * Write a feature element from cscfg_feature_desc in following format:
+ *
+ * [cscfg_table_elem_header] - header length is total bytes to end of param structures.
+ * [cscfg_table_elem_str] - feature name.
+ * [cscfg_table_elem_str] - feature description.
+ * [u32 value: match_flags]
+ * [u16 value: nr_regs] - number of registers.
+ * [u16 value: nr_params] - number of parameters.
+ * [cscfg_regval_desc struct] * nr_regs
+ * [PARAM_ELEM] * nr_params
+ */
+static int cscfg_table_write_feat(u8 *buffer, const int buflen,
+ struct cscfg_feature_desc *feat_desc)
+{
+ struct cscfg_table_elem_header ehdr;
+ struct cscfg_regval_desc *p_reg_desc;
+ int used = 0, bytes_w, i, space_req;
+ u32 val32;
+
+ ehdr.elem_length = 0;
+ ehdr.elem_type = CSCFG_TABLE_ELEM_TYPE_FEAT;
+
+ /* write element header at current buffer location */
+ bytes_w = cscfg_table_write_elem_hdr(buffer, buflen, &ehdr);
+ if (bytes_w < 0)
+ return bytes_w;
+ used += bytes_w;
+
+ /* write out the name string */
+ bytes_w = cscfg_table_write_string(buffer + used, buflen - used,
+ feat_desc->name);
+ if (bytes_w < 0)
+ return bytes_w;
+ used += bytes_w;
+
+ /* write out the description string */
+ bytes_w = cscfg_table_write_string(buffer + used, buflen - used,
+ feat_desc->description);
+ if (bytes_w < 0)
+ return bytes_w;
+ used += bytes_w;
+
+ /* check for space for variables and register structures */
+ space_req = (sizeof(u16) * 2) + sizeof(u32) +
+ (sizeof(struct cscfg_regval_desc) * feat_desc->nr_regs);
+ if ((buflen - used) < space_req)
+ return -EINVAL;
+
+ /* write the variables */
+ cscfg_write_u32((u32)feat_desc->match_flags);
+ cscfg_write_u16((u16)feat_desc->nr_regs);
+ cscfg_write_u16((u16)feat_desc->nr_params);
+
+ /*write the registers */
+ for (i = 0; i < feat_desc->nr_regs; i++) {
+ p_reg_desc = (struct cscfg_regval_desc *)&feat_desc->regs_desc[i];
+ CSCFG_TABLE_REG_DESC_INFO_TO_U32(val32, p_reg_desc);
+ cscfg_write_u32(val32);
+ cscfg_write_u64(feat_desc->regs_desc[i].val64);
+ }
+
+ /* write any parameters */
+ for (i = 0; i < feat_desc->nr_params; i++) {
+ bytes_w = cscfg_table_write_param(buffer + used, buflen - used,
+ &feat_desc->params_desc[i]);
+ if (bytes_w < 0)
+ return bytes_w;
+ used += bytes_w;
+
+ }
+
+ /*
+ * rewrite the element header at the start of the buffer block
+ * with the correct length
+ */
+ ehdr.elem_length = used;
+ bytes_w = cscfg_table_write_elem_hdr(buffer, buflen, &ehdr);
+ /* used must not be updated here */
+ if (bytes_w < 0)
+ return bytes_w;
+
+ return used;
+}
+
+/*
+ * write a buffer from the configuration and feature
+ * descriptors to write into a file for configfs.
+ *
+ * Will only write one config, and/or a number of features,
+ * per the file standard.
+ */
+int cscfg_table_write_buffer(u8 *buffer, const int buflen,
+ struct cscfg_config_desc **config_descs,
+ struct cscfg_feature_desc **feat_descs)
+{
+ struct cscfg_table_header fhdr;
+ int used = 0, bytes_w, i;
+
+ /* init the file header */
+ fhdr.magic_version = CSCFG_TABLE_MAGIC_VERSION;
+ fhdr.length = 0;
+ fhdr.nr_configs = 0;
+ fhdr.nr_features = 0;
+
+ /* count the configs */
+ if (config_descs) {
+ while (config_descs[fhdr.nr_configs])
+ fhdr.nr_configs++;
+ }
+
+ /* count the features */
+ if (feat_descs) {
+ while (feat_descs[fhdr.nr_features])
+ fhdr.nr_features++;
+ }
+
+ /* need a buffer and at least one config or feature */
+ if ((!fhdr.nr_configs && !fhdr.nr_features) ||
+ !buffer || (buflen > CSCFG_TABLE_MAXSIZE))
+ return -EINVAL;
+
+ /* write a header at the start to get the length of the header */
+ bytes_w = cscfg_table_write_fhdr(buffer, buflen, &fhdr);
+ if (bytes_w < 0)
+ return bytes_w;
+ used += bytes_w;
+
+ /* write configs */
+ for (i = 0; i < fhdr.nr_configs; i++) {
+ bytes_w = cscfg_table_write_config(buffer + used, buflen - used,
+ config_descs[i]);
+ if (bytes_w < 0)
+ return bytes_w;
+ used += bytes_w;
+ }
+
+ /* write any features */
+ for (i = 0; i < fhdr.nr_features; i++) {
+ bytes_w = cscfg_table_write_feat(buffer + used, buflen - used,
+ feat_descs[i]);
+ if (bytes_w < 0)
+ return bytes_w;
+ used += bytes_w;
+ }
+
+ /* finally re-write the header at the buffer start with the correct length */
+ fhdr.length = (u16)used;
+ bytes_w = cscfg_table_write_fhdr(buffer, buflen, &fhdr);
+ /* used must not be updated here */
+ if (bytes_w < 0)
+ return bytes_w;
+ return used;
+}
new file mode 100644
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020-2022 Linaro Limited, All rights reserved.
+ * Author: Mike Leach <mike.leach@linaro.org>
+ */
+
+#ifndef _CORESIGHT_CFG_BUFW_H
+#define _CORESIGHT_CFG_BUFW_H
+
+#include <linux/types.h>
+
+#include "coresight-config-table.h"
+
+/*
+ * Function to take coresight configurations and features and
+ * write them into a supplied memory buffer for serialisation
+ * into a file.
+ *
+ * Resulting file can then be loaded into the coresight
+ * infrastructure via configfs.
+ */
+int cscfg_table_write_buffer(u8 *buffer, const int buflen,
+ struct cscfg_config_desc **config_descs,
+ struct cscfg_feature_desc **feat_descs);
+
+#endif /* _CORESIGHT_CFG_BUFW_H */
new file mode 100644
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020-2022 Linaro Limited, All rights reserved.
+ * Author: Mike Leach <mike.leach@linaro.org>
+ */
+#include <linux/types.h>
+#include <linux/unistd.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "coresight-cfg-examples.h"
+
+/*
+ * create a configuration only example using the strobing feature
+ */
+
+/* we will provide 4 sets of preset parameter values */
+#define AFDO3_NR_PRESETS 4
+/* the total number of parameters in used features - strobing has 2 */
+#define AFDO3_NR_PARAM_SUM 2
+
+static const char *afdo3_ref_names[] = {
+ "strobing",
+};
+
+/*
+ * set of presets leaves strobing window constant while varying period to allow
+ * experimentation with mark / space ratios for various workloads
+ */
+static u64 afdo3_presets[AFDO3_NR_PRESETS][AFDO3_NR_PARAM_SUM] = {
+ { 2000, 100 },
+ { 2000, 1000 },
+ { 2000, 5000 },
+ { 2000, 10000 },
+};
+
+struct cscfg_config_desc afdo3 = {
+ .name = "autofdo3",
+ .description = "Setup ETMs with strobing for autofdo\n"
+ "Supplied presets allow experimentation with mark-space ratio for various loads\n",
+ .nr_feat_refs = ARRAY_SIZE(afdo3_ref_names),
+ .feat_ref_names = afdo3_ref_names,
+ .nr_presets = AFDO3_NR_PRESETS,
+ .nr_total_params = AFDO3_NR_PARAM_SUM,
+ .presets = &afdo3_presets[0][0],
+};
+
+static struct cscfg_feature_desc *sample_feats[] = {
+ NULL
+};
+
+static struct cscfg_config_desc *sample_cfgs[] = {
+ &afdo3,
+ NULL
+};
+
+struct cscfg_file_eg_info file_info_eg1 = {
+ .example_name = "example1",
+ .filename = "example1.cscfg",
+ .config_descs = sample_cfgs,
+ .feat_descs = sample_feats,
+};
new file mode 100644
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020-2022 Linaro Limited, All rights reserved.
+ * Author: Mike Leach <mike.leach@linaro.org>
+ */
+#include <linux/types.h>
+#include <linux/unistd.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "coresight-cfg-examples.h"
+
+/*
+ * create a dual configuration only example using the strobing feature
+ */
+
+/* we will provide 10 sets of preset parameter values */
+#define AFDO_NR_PRESETS 10
+/* the total number of parameters in used features - strobing has 2 */
+#define AFDO_NR_PARAM_SUM 2
+
+static const char *afdo_ref_names[] = {
+ "strobing",
+};
+
+/*
+ * sets of presets leaves strobing window constant while varying period to allow
+ * experimentation with mark / space ratios for various workloads
+ */
+static u64 afdo_set_a_presets[AFDO_NR_PRESETS][AFDO_NR_PARAM_SUM] = {
+ { 2000, 100 },
+ { 2000, 1000 },
+ { 2000, 5000 },
+ { 2000, 10000 },
+ { 4000, 100 },
+ { 4000, 1000 },
+ { 4000, 5000 },
+ { 4000, 10000 },
+ { 6000, 100 },
+ { 6000, 1000 },
+};
+
+
+static u64 afdo_set_b_presets[AFDO_NR_PRESETS][AFDO_NR_PARAM_SUM] = {
+ { 6000, 5000 },
+ { 6000, 10000 },
+ { 8000, 100 },
+ { 8000, 1000 },
+ { 8000, 5000 },
+ { 8000, 10000 },
+ { 12000, 100 },
+ { 12000, 1000 },
+ { 12000, 5000 },
+ { 12000, 10000 },
+};
+/* two configurations with differing preset tables */
+struct cscfg_config_desc afdo_seta = {
+ .name = "autofdo_set_a",
+ .description = "Setup ETMs with strobing for autofdo\n"
+ "Supplied presets allow experimentation with mark-space ratio for various loads\n",
+ .nr_feat_refs = ARRAY_SIZE(afdo_ref_names),
+ .feat_ref_names = afdo_ref_names,
+ .nr_presets = AFDO_NR_PRESETS,
+ .nr_total_params = AFDO_NR_PARAM_SUM,
+ .presets = &afdo_set_a_presets[0][0],
+};
+
+struct cscfg_config_desc afdo_setb = {
+ .name = "autofdo_set_b",
+ .description = "Setup ETMs with strobing for autofdo\n"
+ "Supplied presets allow experimentation with mark-space ratio for various loads\n",
+ .nr_feat_refs = ARRAY_SIZE(afdo_ref_names),
+ .feat_ref_names = afdo_ref_names,
+ .nr_presets = AFDO_NR_PRESETS,
+ .nr_total_params = AFDO_NR_PARAM_SUM,
+ .presets = &afdo_set_b_presets[0][0],
+};
+
+
+static struct cscfg_feature_desc *sample_feats[] = {
+ NULL
+};
+
+static struct cscfg_config_desc *sample_cfgs[] = {
+ &afdo_seta,
+ &afdo_setb,
+ NULL
+};
+
+struct cscfg_file_eg_info file_info_eg2 = {
+ .example_name = "example2",
+ .filename = "example2.cscfg",
+ .config_descs = sample_cfgs,
+ .feat_descs = sample_feats,
+};
new file mode 100644
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020-2022 Linaro Limited, All rights reserved.
+ * Author: Mike Leach <mike.leach@linaro.org>
+ */
+
+#ifndef _CORESIGHT_CFG_EXAMPLES_H
+#define _CORESIGHT_CFG_EXAMPLES_H
+
+#include <linux/kernel.h>
+
+#include "coresight-config-uapi.h"
+
+/*
+ * structure to pass C configuration structure information to
+ * configuration table file generator program
+ */
+struct cscfg_file_eg_info {
+ const char *example_name;
+ const char *filename;
+ struct cscfg_config_desc **config_descs;
+ struct cscfg_feature_desc **feat_descs;
+};
+
+#endif /* _CORESIGHT_CFG_EXAMPLES_H */
new file mode 100644
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020-2022 Linaro Limited, All rights reserved.
+ * Author: Mike Leach <mike.leach@linaro.org>
+ */
+
+#include <linux/types.h>
+#include <linux/unistd.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "coresight-cfg-bufw.h"
+#include "coresight-cfg-examples.h"
+#include "coresight-cfg-file-gen.h"
+
+/* array of example table files to generate */
+struct cscfg_file_eg_info *info_ptrs[] = {
+ &file_info_eg1,
+ &file_info_eg2,
+ NULL,
+};
+
+int main(int argc, char **argv)
+{
+ struct cscfg_config_desc **config_descs;
+ struct cscfg_feature_desc **feat_descs;
+ u8 buffer[CSCFG_TABLE_MAXSIZE];
+ int used, idx = 0;
+ FILE *fp;
+ const char *filename;
+
+ printf("Coresight Configuration table file Generator\n\n");
+
+ while (info_ptrs[idx]) {
+ printf("Generating %s example\n", info_ptrs[idx]->example_name);
+ config_descs = info_ptrs[idx]->config_descs;
+ feat_descs = info_ptrs[idx]->feat_descs;
+ filename = info_ptrs[idx]->filename;
+ used = cscfg_table_write_buffer(buffer, CSCFG_TABLE_MAXSIZE,
+ config_descs, feat_descs);
+
+ if (used < 0) {
+ printf("Error %d writing configuration %s into buffer\n",
+ used, info_ptrs[idx]->example_name);
+ return used;
+ }
+
+ fp = fopen(filename, "wb");
+ if (fp == NULL) {
+ printf("Error opening file %s\n", filename);
+ return -1;
+ }
+ fwrite(buffer, used, sizeof(u8), fp);
+ fclose(fp);
+ idx++;
+ }
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020-2022 Linaro Limited, All rights reserved.
+ * Author: Mike Leach <mike.leach@linaro.org>
+ */
+
+#ifndef _CORESIGHT_CFG_FILE_GEN_H
+#define _CORESIGHT_CFG_FILE_GEN_H
+
+/*
+ * references to the configuration and feature example
+ * structures in example source files
+ */
+extern struct cscfg_file_eg_info file_info_eg1;
+extern struct cscfg_file_eg_info file_info_eg2;
+
+#endif /* _CORESIGHT_CFG_FILE_GEN_H */
new file mode 100644
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020-2022 Linaro Limited, All rights reserved.
+ * Author: Mike Leach <mike.leach@linaro.org>
+ */
+
+#include <linux/types.h>
+#include <linux/unistd.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "coresight-config-table.h"
+#include "coresight-config-uapi.h"
+
+/*
+ * tool to read and print a generated configuration
+ * re-uses the read code source from the driver.
+ */
+
+static void validate_config_name(const char *name)
+{
+ int i, len = strlen(name);
+
+ for (i = 0; i < len; i++) {
+ if (!isalnum(name[i]) && !(name[i] == '_')) {
+ printf("\n************************************************\n");
+ printf("ERROR: Configuration name %s invalid character(s)\n", name);
+ printf(" : must contain only alphanumeric and _ only\n");
+ printf("************************************************\n");
+ }
+ }
+}
+
+static void print_configs(struct cscfg_table_load_descs *load_descs, int *nr_configs)
+{
+ struct cscfg_config_desc *config_desc;
+ int i, j, p, cfg_idx = 0;
+
+ *nr_configs = 0;
+ config_desc = load_descs->config_descs[cfg_idx];
+ if (!config_desc) {
+ printf("File contains no configurations.\n\n");
+ return;
+ }
+
+ while (config_desc) {
+ printf("Configuration %d\nName:- %s\n", cfg_idx + 1, config_desc->name);
+ validate_config_name(config_desc->name);
+ printf("Description:-\n%s\n", config_desc->description);
+ printf("Uses %d features:-\n", config_desc->nr_feat_refs);
+ for (i = 0; i < config_desc->nr_feat_refs; i++)
+ printf("Feature-%d: %s\n", i + 1, config_desc->feat_ref_names[i]);
+
+ printf("\nProvides %d sets of preset values, %d presets per set\n",
+ config_desc->nr_presets, config_desc->nr_total_params);
+ if (config_desc->nr_presets) {
+ for (i = 0; i < config_desc->nr_presets; i++) {
+ printf("set[%d]: ", i);
+ for (j = 0; j < config_desc->nr_total_params; j++) {
+ p = (i * config_desc->nr_total_params) + j;
+ printf("0x%lx, ", config_desc->presets[p]);
+ }
+ printf("\n");
+ }
+ }
+ printf("\n============================================\n");
+ cfg_idx++;
+ config_desc = load_descs->config_descs[cfg_idx];
+ (*nr_configs)++;
+ }
+}
+
+static void print_reg_type_info(u8 type)
+{
+ if (type & CS_CFG_REG_TYPE_STD)
+ printf("std_reg ");
+ if (type & CS_CFG_REG_TYPE_RESOURCE)
+ printf("resource ");
+ if (type & CS_CFG_REG_TYPE_VAL_PARAM)
+ printf("param_index ");
+ if (type & CS_CFG_REG_TYPE_VAL_64BIT)
+ printf("64_bit ");
+ else
+ printf("32_bit ");
+ if (type & CS_CFG_REG_TYPE_VAL_MASK)
+ printf("masked ");
+ if (type & CS_CFG_REG_TYPE_VAL_SAVE)
+ printf("save_on_disable ");
+
+}
+
+static void print_regs(int nr, struct cscfg_regval_desc *regs_desc_array)
+{
+ int i;
+ struct cscfg_regval_desc *reg_desc;
+ u8 type;
+ u16 offset;
+ u16 info;
+
+ for (i = 0; i < nr; i++) {
+ reg_desc = ®s_desc_array[i];
+ type = (u8)reg_desc->type;
+ offset = (u16)reg_desc->offset;
+ info = (u16)reg_desc->hw_info;
+
+ printf("Reg(%d): Type 0x%x: ", i, type);
+ print_reg_type_info(type);
+ printf("\nOffset: 0x%03x; HW Info: 0x%03x\n", offset, info);
+ printf("Value: ");
+ if (type & CS_CFG_REG_TYPE_VAL_64BIT)
+ printf("0x%lx\n", reg_desc->val64);
+ else if (type & CS_CFG_REG_TYPE_VAL_PARAM) {
+ printf("param(%d) ", reg_desc->param_idx);
+ if (type & (CS_CFG_REG_TYPE_VAL_MASK))
+ printf(" mask: 0x%x", reg_desc->mask32);
+ printf("\n");
+ } else {
+ printf("0x%x ", reg_desc->val32);
+ if (type & (CS_CFG_REG_TYPE_VAL_MASK))
+ printf(" mask: 0x%x", reg_desc->mask32);
+ printf("\n");
+ }
+ }
+}
+
+static void print_params(int nr, struct cscfg_parameter_desc *params_desc)
+{
+ int i;
+
+ for (i = 0; i < nr; i++)
+ printf("Param(%d) : %s; Init value 0x%lx\n", i,
+ params_desc[i].name, params_desc[i].value);
+}
+
+static void print_features(struct cscfg_table_load_descs *load_descs, int *nr_feats)
+{
+ struct cscfg_feature_desc *feat_desc = 0;
+ int idx = 0;
+
+ *nr_feats = 0;
+ feat_desc = load_descs->feat_descs[idx];
+ if (!feat_desc) {
+ printf("File contains no features\n\n");
+ return;
+ }
+
+ while (feat_desc) {
+ printf("Feature %d\nName:- %s\n\n", idx + 1, feat_desc->name);
+ printf("Description:- %s\n", feat_desc->description);
+ printf("Match flags: 0x%x\n", feat_desc->match_flags);
+ printf("\nNumber of Paraneters: %d\n", feat_desc->nr_params);
+ if (feat_desc->nr_params)
+ print_params(feat_desc->nr_params, feat_desc->params_desc);
+ printf("\nNumber of Registers: %d\n", feat_desc->nr_regs);
+ if (feat_desc->nr_regs)
+ print_regs(feat_desc->nr_regs, feat_desc->regs_desc);
+ printf("\n============================================\n");
+
+ /* next feature */
+ idx++;
+ feat_desc = load_descs->feat_descs[idx];
+ (*nr_feats)++;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ FILE *fp;
+ struct cscfg_table_load_descs *load_descs;
+ int err, fsize, nr_configs = 0, nr_feats = 0;
+ u8 buffer[CSCFG_TABLE_MAXSIZE];
+
+ printf("\n\n============================================\n");
+ printf("CoreSight Configuration table file reader");
+ printf("\n============================================\n\n");
+
+ /* need a filename */
+ if (argc <= 1) {
+ printf("Please provide filename on command line\n");
+ return -EINVAL;
+ }
+
+ /* open file and read into the buffer. */
+ fp = fopen(argv[1], "rb");
+ if (fp == NULL) {
+ printf("Error opening file %s\n", argv[1]);
+ return -EINVAL;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ fsize = ftell(fp);
+ rewind(fp);
+ if (fsize > CSCFG_TABLE_MAXSIZE) {
+ printf("Error: Input file too large.");
+ fclose(fp);
+ return -EINVAL;
+ }
+ err = fread(buffer, sizeof(u8), fsize, fp);
+ fclose(fp);
+
+ if (err < fsize) {
+ printf("Error reading file %s\n", argv[1]);
+ return -EINVAL;
+ }
+
+ /* allocate the descriptor structures to be populated by read operation */
+ load_descs = calloc(1, sizeof(struct cscfg_table_load_descs));
+ if (!load_descs) {
+ printf("Error allocating load descs structure.\n");
+ return -ENOMEM;
+ }
+
+ /* read the buffer and create the configuration and feature structures */
+ err = cscfg_table_read_buffer(buffer, fsize, load_descs);
+ if (err) {
+ printf("Error reading configuration file\n");
+ goto exit_free_mem;
+ }
+
+ /* print the contents of the structures */
+ print_configs(load_descs, &nr_configs);
+ print_features(load_descs, &nr_feats);
+
+ printf("\n\n======= Summary ============================\n");
+ printf(" Config File Name: : %s\n", argv[1]);
+ printf(" Number of Configurations: %d\n", nr_configs);
+ printf(" Number of Features : %d\n", nr_feats);
+ printf(" Load name : %s\n", load_descs->load_name);
+ printf("============================================\n\n");
+
+
+exit_free_mem:
+ cscfg_table_free_load_descs(load_descs);
+ free(load_descs);
+ return err;
+}
new file mode 100644
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 Linaro Limited, All rights reserved.
+ * Author: Mike Leach <mike.leach@linaro.org>
+ */
+
+#ifndef _CORESIGHT_CORESIGHT_CONFIG_UAPI_H
+#define _CORESIGHT_CORESIGHT_CONFIG_UAPI_H
+
+#include <linux/types.h>
+#include <asm-generic/errno-base.h>
+
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "coresight-config-desc.h"
+
+/*
+ * Userspace versions of the configuration and feature descriptors.
+ * Used in the tools/coresight programs.
+ *
+ * Compatible with structures in coresight-config.h for use in
+ * coresight-config-file.c common reader source file.
+ */
+
+/**
+ * Device feature descriptor - combination of registers and parameters to
+ * program a device to implement a specific complex function.
+ *
+ * UAPI version - removed kernel constructs.
+ *
+ * @name: feature name.
+ * @description: brief description of the feature.
+ * @match_flags: matching information if loading into a device
+ * @nr_params: number of parameters used.
+ * @params_desc: array of parameters used.
+ * @nr_regs: number of registers used.
+ * @regs_desc: array of registers used.
+ */
+struct cscfg_feature_desc {
+ const char *name;
+ const char *description;
+ u32 match_flags;
+ int nr_params;
+ struct cscfg_parameter_desc *params_desc;
+ int nr_regs;
+ struct cscfg_regval_desc *regs_desc;
+};
+
+/**
+ * Configuration descriptor - describes selectable system configuration.
+ *
+ * A configuration describes device features in use, and may provide preset
+ * values for the parameters in those features.
+ *
+ * A single set of presets is the sum of the parameters declared by
+ * all the features in use - this value is @nr_total_params.
+ *
+ * UAPI version - removed kernel constructs.
+ *
+ * @name: name of the configuration - used for selection.
+ * @description: description of the purpose of the configuration.
+ * @nr_feat_refs: Number of features used in this configuration.
+ * @feat_ref_names: references to features used in this configuration.
+ * @nr_presets: Number of sets of presets supplied by this configuration.
+ * @nr_total_params: Sum of all parameters declared by used features
+ * @presets: Array of preset values.
+ */
+struct cscfg_config_desc {
+ const char *name;
+ const char *description;
+ int nr_feat_refs;
+ const char **feat_ref_names;
+ int nr_presets;
+ int nr_total_params;
+ const u64 *presets; /* nr_presets * nr_total_params */
+};
+
+/* UAPI allocators for descriptors in common config file buffer read code */
+static inline void *cscfg_calloc(size_t num, size_t size)
+{
+ return calloc(num, size);
+}
+
+static inline char *cscfg_strdup(const char *str)
+{
+ return strdup(str);
+}
+
+static inline void *cscfg_zalloc(size_t size)
+{
+ void *ptr = malloc(size);
+
+ if (ptr)
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+static inline void cscfg_free(void *mem)
+{
+ free(mem);
+}
+
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_UAPI_H */
Add an example config table generator to test loading configuration tables. Provides a table buffer writer function that can be re-used in other userspace programs. Table write format matches that expected by the corresponding reader in the configfs driver code. Generates tables and outputs in form of binary files. Add a config table file reader and printer. Takes in config table files and prints the contents. Uses table reader source from kernel driver. Signed-off-by: Mike Leach <mike.leach@linaro.org> --- MAINTAINERS | 1 + .../coresight/coresight-config-table.h | 5 + tools/coresight/Makefile | 56 +++ tools/coresight/coresight-cfg-bufw.c | 328 ++++++++++++++++++ tools/coresight/coresight-cfg-bufw.h | 26 ++ tools/coresight/coresight-cfg-example1.c | 62 ++++ tools/coresight/coresight-cfg-example2.c | 95 +++++ tools/coresight/coresight-cfg-examples.h | 25 ++ tools/coresight/coresight-cfg-file-gen.c | 58 ++++ tools/coresight/coresight-cfg-file-gen.h | 17 + tools/coresight/coresight-cfg-file-read.c | 239 +++++++++++++ tools/coresight/coresight-config-uapi.h | 105 ++++++ 12 files changed, 1017 insertions(+) create mode 100644 tools/coresight/Makefile create mode 100644 tools/coresight/coresight-cfg-bufw.c create mode 100644 tools/coresight/coresight-cfg-bufw.h create mode 100644 tools/coresight/coresight-cfg-example1.c create mode 100644 tools/coresight/coresight-cfg-example2.c create mode 100644 tools/coresight/coresight-cfg-examples.h create mode 100644 tools/coresight/coresight-cfg-file-gen.c create mode 100644 tools/coresight/coresight-cfg-file-gen.h create mode 100644 tools/coresight/coresight-cfg-file-read.c create mode 100644 tools/coresight/coresight-config-uapi.h