Message ID | 20220414064457.12052-5-mike.leach@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | coresight: syscfg: Extend configfs for config load | expand |
On Thu, Apr 14, 2022 at 07:44:56AM +0100, Mike Leach wrote: > Add an example file generator to test loading configurations via a > binary attribute in configfs. > > Provides a file buffer writer function that can be re-used in other > userspace programs. > > Buffer write format matches that expected by the corresponding reader > in the configfs driver code. > > Add a config file reader and printer. Takes in config files and prints > the contents. Uses file reader source from kernel driver. > > Signed-off-by: Mike Leach <mike.leach@linaro.org> > --- > MAINTAINERS | 2 + > .../coresight/coresight-config-file.c | 2 + > tools/coresight/Makefile | 51 +++ > tools/coresight/coresight-cfg-bufw.c | 303 ++++++++++++++++++ > tools/coresight/coresight-cfg-bufw.h | 26 ++ > tools/coresight/coresight-cfg-example1.c | 65 ++++ > tools/coresight/coresight-cfg-examples.h | 27 ++ > tools/coresight/coresight-cfg-file-read.c | 197 ++++++++++++ > tools/coresight/coresight-cfg-filegen.c | 58 ++++ > tools/include/uapi/coresight-config-uapi.h | 76 +++++ > 10 files changed, 807 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-examples.h > create mode 100644 tools/coresight/coresight-cfg-file-read.c > create mode 100644 tools/coresight/coresight-cfg-filegen.c > create mode 100644 tools/include/uapi/coresight-config-uapi.h > > diff --git a/MAINTAINERS b/MAINTAINERS > index 61d9f114c37f..4e59486e75b5 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -1985,6 +1985,8 @@ F: drivers/hwtracing/coresight/* > F: include/dt-bindings/arm/coresight-cti-dt.h > F: include/linux/coresight* > F: samples/coresight/* > +F: tools/coresight/* > +F: tools/include/uapi/coresight-config-uapi.h > F: tools/perf/arch/arm/util/auxtrace.c > F: tools/perf/arch/arm/util/cs-etm.c > F: tools/perf/arch/arm/util/cs-etm.h > diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c > index 5b8f635ac50e..4a8b64405d84 100644 > --- a/drivers/hwtracing/coresight/coresight-config-file.c > +++ b/drivers/hwtracing/coresight/coresight-config-file.c > @@ -36,6 +36,8 @@ static void *cscfg_zalloc(size_t size) > #include <string.h> > #include <stdlib.h> > > +#include "uapi/coresight-config-uapi.h" > + > static void *cscfg_calloc(size_t num, size_t size) > { > return calloc(num, size); > diff --git a/tools/coresight/Makefile b/tools/coresight/Makefile > new file mode 100644 > index 000000000000..4004c315d65c > --- /dev/null > +++ b/tools/coresight/Makefile > @@ -0,0 +1,51 @@ > +# SPDX-License-Identifier: GPL-2.0-only > +include ../scripts/Makefile.include > +include ../scripts/Makefile.arch > + > +# Makefile to build the coresight configuration 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) > + > +# compile flags > +CFLAGS += $(CPPFLAGS) -c -Wall -DLINUX -Wno-switch -Wlogical-op -fPIC -I$(srctree)/drivers/hwtracing/coresight -I$(srctree)/tools/include/ -I$(srctree)/tools/include/uapi > + > +# object files > +coresight-cfg-file-gen-objs := coresight-cfg-filegen.o coresight-cfg-bufw.o coresight-cfg-example1.o > +coresight-cfg-file-read-objs := coresight-cfg-file-read.o coresight-config-file.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-file.o: src_copy > + $(CC) $(CFLAGS) coresight-config-file.c -o coresight-config-file.o > + > +.PHONY: src_copy > +src_copy: > + @cp $(srctree)/drivers/hwtracing/coresight/coresight-config-file.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-file.c > + rm -f *.cscfg > diff --git a/tools/coresight/coresight-cfg-bufw.c b/tools/coresight/coresight-cfg-bufw.c > new file mode 100644 > index 000000000000..73223de2b7e0 > --- /dev/null > +++ b/tools/coresight/coresight-cfg-bufw.c > @@ -0,0 +1,303 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 Linaro Limited, All rights reserved. > + * Author: Mike Leach <mike.leach@linaro.org> > + */ > + > +#include <string.h> > + > +#include "coresight-cfg-bufw.h" > +#include "uapi/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++; \ > + } > + > +#define CHECK_WRET(rval) { \ > + if (rval < 0) \ > + return rval; \ > + used += rval; \ > + } > + Either use a single space between the code and the '\' character or align them all on the same column. > +/* write the header at the start of the buffer */ > +static int cscfg_file_write_fhdr(u8 *buffer, const int buflen, > + const struct cscfg_file_header *fhdr) > +{ > + int used = 0; > + > + cscfg_write_u32(fhdr->magic_version); > + cscfg_write_u16(fhdr->length); > + cscfg_write_u16(fhdr->nr_features); > + return used; > +} > + > +static int cscfg_file_write_string(u8 *buffer, const int buflen, const char *string) > +{ > + int len, used = 0; > + > + len = strlen(string); > + if (len > CSCFG_FILE_STR_MAXSIZE) > + return -EINVAL; > + > + if (buflen < (len + 1 + sizeof(u16))) > + return -EINVAL; > + > + cscfg_write_u16((u16)(len + 1)); > + strcpy((char *)(buffer + used), string); > + used += (len + 1); > + > + return used; > +} > + > +static int cscfg_file_write_elem_hdr(u8 *buffer, const int buflen, > + struct cscfg_file_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; > +} > + > + Extra line. > +static int cscfg_file_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_file_elem_header ehdr; > + > + ehdr.elem_length = 0; > + ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_CFG; > + > + /* write element header at current buffer location */ > + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); > + CHECK_WRET(bytes_w); > + > + /* write out the configuration name */ > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > + config_desc->name); > + CHECK_WRET(bytes_w); > + > + /* write out the description string */ > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > + config_desc->description); > + CHECK_WRET(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_file_write_string(buffer + used, buflen - used, > + config_desc->feat_ref_names[i]); > + CHECK_WRET(bytes_w); > + } > + > + /* rewrite the element header with the correct length */ > + ehdr.elem_length = used; > + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); > + /* no CHECK_WRET as used must not be updated */ > + if (bytes_w < 0) > + return bytes_w; > + > + return used; > +} > + > +/* > + * write a parameter structure into the buffer in following format: > + * [cscfg_file_elem_str] - parameter name. > + * [u64 value: param_value] - initial value. > + */ > +static int cscfg_file_write_param(u8 *buffer, const int buflen, > + struct cscfg_parameter_desc *param_desc) > +{ > + int used = 0, bytes_w; > + > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > + param_desc->name); > + CHECK_WRET(bytes_w); > + > + if ((buflen - used) < sizeof(u64)) > + return -EINVAL; > + > + cscfg_write_u64(param_desc->value); > + return used; > +} Add an extra line. > +/* > + * Write a feature element from cscfg_feature_desc in following format: > + * > + * [cscfg_file_elem_header] - header length is total bytes to end of param structures. > + * [cscfg_file_elem_str] - feature name. > + * [cscfg_file_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 > + * > + * Two extra lines. > + */ > +static int cscfg_file_write_feat(u8 *buffer, const int buflen, > + struct cscfg_feature_desc *feat_desc) > +{ > + struct cscfg_file_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_FILE_ELEM_TYPE_FEAT; > + > + /* write element header at current buffer location */ > + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); > + CHECK_WRET(bytes_w); > + > + /* write out the name string */ > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > + feat_desc->name); > + CHECK_WRET(bytes_w) > + > + /* write out the description string */ > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > + feat_desc->description); > + CHECK_WRET(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_FILE_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_file_write_param(buffer + used, buflen - used, > + &feat_desc->params_desc[i]); > + CHECK_WRET(bytes_w); > + } > + > + /* > + * rewrite the element header at the start of the buffer block > + * with the correct length > + */ > + ehdr.elem_length = used; > + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); > + /* no CHECK_WRET as used must not be updated */ > + 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_file_write_buffer(u8 *buffer, const int buflen, > + struct cscfg_config_desc *config_desc, > + struct cscfg_feature_desc **feat_descs) > +{ > + struct cscfg_file_header fhdr; > + int used = 0, bytes_w, i; > + > + /* init the file header */ > + fhdr.magic_version = CSCFG_FILE_MAGIC_VERSION; > + fhdr.length = 0; > + fhdr.nr_features = 0; > + > + /* 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 ((!config_desc && !fhdr.nr_features) || > + !buffer || (buflen > CSCFG_FILE_MAXSIZE)) > + return -EINVAL; > + > + /* write a header at the start to get the length of the header */ > + bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr); > + CHECK_WRET(bytes_w); > + > + /* write a single config */ > + if (config_desc) { > + bytes_w = cscfg_file_write_config(buffer + used, buflen - used, > + config_desc); > + CHECK_WRET(bytes_w); > + } > + > + /* write any features */ > + for (i = 0; i < fhdr.nr_features; i++) { > + bytes_w = cscfg_file_write_feat(buffer + used, buflen - used, > + feat_descs[i]); > + CHECK_WRET(bytes_w); > + } > + > + /* finally re-write the header at the buffer start with the correct length */ > + fhdr.length = (u16)used; > + bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr); > + /* no CHECK_WRET as used must not be updated */ > + if (bytes_w < 0) > + return bytes_w; > + return used; > +} > diff --git a/tools/coresight/coresight-cfg-bufw.h b/tools/coresight/coresight-cfg-bufw.h > new file mode 100644 > index 000000000000..562df97599fc > --- /dev/null > +++ b/tools/coresight/coresight-cfg-bufw.h > @@ -0,0 +1,26 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (c) 2020 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-file.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_file_write_buffer(u8 *buffer, const int buflen, > + struct cscfg_config_desc *config_desc, > + struct cscfg_feature_desc **feat_descs); > + > +#endif /* _CORESIGHT_CFG_BUFW_H */ > diff --git a/tools/coresight/coresight-cfg-example1.c b/tools/coresight/coresight-cfg-example1.c > new file mode 100644 > index 000000000000..a71a6e43d7b3 > --- /dev/null > +++ b/tools/coresight/coresight-cfg-example1.c > @@ -0,0 +1,65 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 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" There is no need to include coresight-cfg-bufw.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 > +}; > + > +#define CSCFG_EG1_FILENAME "example1.cscfg" Not sure there is any value in specifying a define... I'd just hard code it the same way it was done for "example1". > + > +struct cscfg_file_eg_info buff_info_eg1 = { > + .example_name = "example1", > + .filename = CSCFG_EG1_FILENAME, > + .config_descs = sample_cfgs, > + .feat_descs = sample_feats, > +}; > diff --git a/tools/coresight/coresight-cfg-examples.h b/tools/coresight/coresight-cfg-examples.h > new file mode 100644 > index 000000000000..5c6908745201 > --- /dev/null > +++ b/tools/coresight/coresight-cfg-examples.h > @@ -0,0 +1,27 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (c) 2020 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 "uapi/coresight-config-uapi.h" > +#include "coresight-cfg-bufw.h" Same here. > + > +/* structure to pass configuraiton information to 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; > +}; > + > + > +/* references to the configuration and feature example structures */ > +extern struct cscfg_file_eg_info buff_info_eg1; I would put this in coresight-cfg-filegen.c. That way people only have to change a single file rather than two. More comments to follow on this file. I am not sure there is a need to read .cscfg files. > + > +#endif /* _CORESIGHT_CFG_EXAMPLES_H */ > diff --git a/tools/coresight/coresight-cfg-file-read.c b/tools/coresight/coresight-cfg-file-read.c > new file mode 100644 > index 000000000000..da7b831eb2df > --- /dev/null > +++ b/tools/coresight/coresight-cfg-file-read.c > @@ -0,0 +1,197 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 Linaro Limited, All rights reserved. > + * Author: Mike Leach <mike.leach@linaro.org> > + */ > + > +#include <linux/types.h> > +#include <linux/unistd.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <unistd.h> > + > +#include "coresight-config-file.h" > +#include "uapi/coresight-config-uapi.h" > + > +/* > + * tool to read and print a generated configuration > + * re-uses the read code source from the driver. > + */ > + > +static void print_configs(struct cscfg_fs_load_descs *load_descs) > +{ > + struct cscfg_config_desc *config_desc = load_descs->config_descs[0]; > + int i, j, p; > + > + if (!config_desc) { > + printf("File contains no configurations.\n\n"); > + return; > + } > + > + printf("Configuration name : %s\n", config_desc->name); > + 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"); > +} > + > +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("idx = %d\n", reg_desc->param_idx); > + 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_fs_load_descs *load_descs) > +{ > + struct cscfg_feature_desc *feat_desc = 0; > + int idx = 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 name : %s\n", idx+1, feat_desc->name); > + printf("Description: %s\n", feat_desc->description); > + printf("Match flags: 0x%x\n", feat_desc->match_flags); > + printf("Number of Paraneters: %d\n", feat_desc->nr_params); > + if (feat_desc->nr_params) > + print_params(feat_desc->nr_params, feat_desc->params_desc); > + printf("Number 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]; > + } > +} > + > +int main(int argc, char **argv) > +{ > + FILE *fp; > + struct cscfg_fs_load_descs *load_descs; > + int err, fsize; > + u8 buffer[CSCFG_FILE_MAXSIZE]; > + > + printf("CoreSight Configuration file reader\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_FILE_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 = malloc(sizeof(struct cscfg_fs_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_file_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); > + print_features(load_descs); > + > +exit_free_mem: > + free(load_descs); > + return err; > +} > diff --git a/tools/coresight/coresight-cfg-filegen.c b/tools/coresight/coresight-cfg-filegen.c > new file mode 100644 > index 000000000000..cd0589661d92 > --- /dev/null > +++ b/tools/coresight/coresight-cfg-filegen.c > @@ -0,0 +1,58 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 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 "uapi/coresight-config-uapi.h" > +#include "coresight-cfg-bufw.h" > +#include "coresight-cfg-examples.h" > + > + > +/* array of example files to generate */ > +struct cscfg_file_eg_info *info_ptrs[] = { > + &buff_info_eg1, > + NULL, > +}; > + > +int main(int argc, char **argv) > +{ > + struct cscfg_config_desc *config_desc; > + struct cscfg_feature_desc **feat_descs; > + u8 buffer[CSCFG_FILE_MAXSIZE]; > + int used, idx = 0; > + FILE *fp; > + const char *filename; > + > + printf("Coresight Configuration file Generator\n\n"); > + > + while (info_ptrs[idx]) { > + printf("Generating %s example\n", info_ptrs[idx]->example_name); > + config_desc = info_ptrs[idx]->config_descs[0]; > + feat_descs = info_ptrs[idx]->feat_descs; > + filename = info_ptrs[idx]->filename; > + used = cscfg_file_write_buffer(buffer, CSCFG_FILE_MAXSIZE, > + config_desc, 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; > +} > diff --git a/tools/include/uapi/coresight-config-uapi.h b/tools/include/uapi/coresight-config-uapi.h > new file mode 100644 > index 000000000000..d051c01ea982 > --- /dev/null > +++ b/tools/include/uapi/coresight-config-uapi.h > @@ -0,0 +1,76 @@ > +/* 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 "coresight-config.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 */ > +}; > + > +#endif /* _CORESIGHT_CORESIGHT_CONFIG_UAPI_H */ > -- > 2.17.1 >
On Thu, Apr 14, 2022 at 07:44:56AM +0100, Mike Leach wrote: > Add an example file generator to test loading configurations via a > binary attribute in configfs. > > Provides a file buffer writer function that can be re-used in other > userspace programs. > > Buffer write format matches that expected by the corresponding reader > in the configfs driver code. > > Add a config file reader and printer. Takes in config files and prints > the contents. Uses file reader source from kernel driver. > > Signed-off-by: Mike Leach <mike.leach@linaro.org> > --- > MAINTAINERS | 2 + > .../coresight/coresight-config-file.c | 2 + > tools/coresight/Makefile | 51 +++ > tools/coresight/coresight-cfg-bufw.c | 303 ++++++++++++++++++ > tools/coresight/coresight-cfg-bufw.h | 26 ++ > tools/coresight/coresight-cfg-example1.c | 65 ++++ > tools/coresight/coresight-cfg-examples.h | 27 ++ > tools/coresight/coresight-cfg-file-read.c | 197 ++++++++++++ > tools/coresight/coresight-cfg-filegen.c | 58 ++++ > tools/include/uapi/coresight-config-uapi.h | 76 +++++ > 10 files changed, 807 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-examples.h > create mode 100644 tools/coresight/coresight-cfg-file-read.c > create mode 100644 tools/coresight/coresight-cfg-filegen.c > create mode 100644 tools/include/uapi/coresight-config-uapi.h > > diff --git a/MAINTAINERS b/MAINTAINERS > index 61d9f114c37f..4e59486e75b5 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -1985,6 +1985,8 @@ F: drivers/hwtracing/coresight/* > F: include/dt-bindings/arm/coresight-cti-dt.h > F: include/linux/coresight* > F: samples/coresight/* > +F: tools/coresight/* > +F: tools/include/uapi/coresight-config-uapi.h > F: tools/perf/arch/arm/util/auxtrace.c > F: tools/perf/arch/arm/util/cs-etm.c > F: tools/perf/arch/arm/util/cs-etm.h > diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c > index 5b8f635ac50e..4a8b64405d84 100644 > --- a/drivers/hwtracing/coresight/coresight-config-file.c > +++ b/drivers/hwtracing/coresight/coresight-config-file.c > @@ -36,6 +36,8 @@ static void *cscfg_zalloc(size_t size) > #include <string.h> > #include <stdlib.h> > > +#include "uapi/coresight-config-uapi.h" > + > static void *cscfg_calloc(size_t num, size_t size) > { > return calloc(num, size); > diff --git a/tools/coresight/Makefile b/tools/coresight/Makefile > new file mode 100644 > index 000000000000..4004c315d65c > --- /dev/null > +++ b/tools/coresight/Makefile > @@ -0,0 +1,51 @@ > +# SPDX-License-Identifier: GPL-2.0-only > +include ../scripts/Makefile.include > +include ../scripts/Makefile.arch > + > +# Makefile to build the coresight configuration 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) > + > +# compile flags > +CFLAGS += $(CPPFLAGS) -c -Wall -DLINUX -Wno-switch -Wlogical-op -fPIC -I$(srctree)/drivers/hwtracing/coresight -I$(srctree)/tools/include/ -I$(srctree)/tools/include/uapi > + > +# object files > +coresight-cfg-file-gen-objs := coresight-cfg-filegen.o coresight-cfg-bufw.o coresight-cfg-example1.o > +coresight-cfg-file-read-objs := coresight-cfg-file-read.o coresight-config-file.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-file.o: src_copy > + $(CC) $(CFLAGS) coresight-config-file.c -o coresight-config-file.o > + > +.PHONY: src_copy > +src_copy: > + @cp $(srctree)/drivers/hwtracing/coresight/coresight-config-file.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-file.c > + rm -f *.cscfg > diff --git a/tools/coresight/coresight-cfg-bufw.c b/tools/coresight/coresight-cfg-bufw.c > new file mode 100644 > index 000000000000..73223de2b7e0 > --- /dev/null > +++ b/tools/coresight/coresight-cfg-bufw.c > @@ -0,0 +1,303 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 Linaro Limited, All rights reserved. > + * Author: Mike Leach <mike.leach@linaro.org> > + */ > + > +#include <string.h> > + > +#include "coresight-cfg-bufw.h" > +#include "uapi/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++; \ > + } > + > +#define CHECK_WRET(rval) { \ > + if (rval < 0) \ > + return rval; \ > + used += rval; \ > + } > + > +/* write the header at the start of the buffer */ > +static int cscfg_file_write_fhdr(u8 *buffer, const int buflen, > + const struct cscfg_file_header *fhdr) > +{ > + int used = 0; > + > + cscfg_write_u32(fhdr->magic_version); > + cscfg_write_u16(fhdr->length); > + cscfg_write_u16(fhdr->nr_features); > + return used; > +} > + > +static int cscfg_file_write_string(u8 *buffer, const int buflen, const char *string) > +{ > + int len, used = 0; > + > + len = strlen(string); > + if (len > CSCFG_FILE_STR_MAXSIZE) > + return -EINVAL; > + > + if (buflen < (len + 1 + sizeof(u16))) > + return -EINVAL; > + > + cscfg_write_u16((u16)(len + 1)); > + strcpy((char *)(buffer + used), string); > + used += (len + 1); > + > + return used; > +} > + > +static int cscfg_file_write_elem_hdr(u8 *buffer, const int buflen, > + struct cscfg_file_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_file_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_file_elem_header ehdr; > + > + ehdr.elem_length = 0; > + ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_CFG; > + > + /* write element header at current buffer location */ > + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); > + CHECK_WRET(bytes_w); > + > + /* write out the configuration name */ > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > + config_desc->name); > + CHECK_WRET(bytes_w); > + > + /* write out the description string */ > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > + config_desc->description); > + CHECK_WRET(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_file_write_string(buffer + used, buflen - used, > + config_desc->feat_ref_names[i]); > + CHECK_WRET(bytes_w); > + } > + > + /* rewrite the element header with the correct length */ > + ehdr.elem_length = used; > + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); > + /* no CHECK_WRET as used must not be updated */ > + if (bytes_w < 0) > + return bytes_w; > + > + return used; > +} > + > +/* > + * write a parameter structure into the buffer in following format: > + * [cscfg_file_elem_str] - parameter name. > + * [u64 value: param_value] - initial value. > + */ > +static int cscfg_file_write_param(u8 *buffer, const int buflen, > + struct cscfg_parameter_desc *param_desc) > +{ > + int used = 0, bytes_w; > + > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > + param_desc->name); > + CHECK_WRET(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_file_elem_header] - header length is total bytes to end of param structures. > + * [cscfg_file_elem_str] - feature name. > + * [cscfg_file_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_file_write_feat(u8 *buffer, const int buflen, > + struct cscfg_feature_desc *feat_desc) > +{ > + struct cscfg_file_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_FILE_ELEM_TYPE_FEAT; > + > + /* write element header at current buffer location */ > + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); > + CHECK_WRET(bytes_w); > + > + /* write out the name string */ > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > + feat_desc->name); > + CHECK_WRET(bytes_w) > + > + /* write out the description string */ > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > + feat_desc->description); > + CHECK_WRET(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_FILE_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_file_write_param(buffer + used, buflen - used, > + &feat_desc->params_desc[i]); > + CHECK_WRET(bytes_w); > + } > + > + /* > + * rewrite the element header at the start of the buffer block > + * with the correct length > + */ > + ehdr.elem_length = used; > + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); > + /* no CHECK_WRET as used must not be updated */ > + 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_file_write_buffer(u8 *buffer, const int buflen, > + struct cscfg_config_desc *config_desc, > + struct cscfg_feature_desc **feat_descs) > +{ > + struct cscfg_file_header fhdr; > + int used = 0, bytes_w, i; > + > + /* init the file header */ > + fhdr.magic_version = CSCFG_FILE_MAGIC_VERSION; > + fhdr.length = 0; > + fhdr.nr_features = 0; > + > + /* 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 ((!config_desc && !fhdr.nr_features) || > + !buffer || (buflen > CSCFG_FILE_MAXSIZE)) > + return -EINVAL; > + > + /* write a header at the start to get the length of the header */ > + bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr); > + CHECK_WRET(bytes_w); > + > + /* write a single config */ > + if (config_desc) { > + bytes_w = cscfg_file_write_config(buffer + used, buflen - used, > + config_desc); > + CHECK_WRET(bytes_w); > + } > + > + /* write any features */ > + for (i = 0; i < fhdr.nr_features; i++) { > + bytes_w = cscfg_file_write_feat(buffer + used, buflen - used, > + feat_descs[i]); > + CHECK_WRET(bytes_w); > + } > + > + /* finally re-write the header at the buffer start with the correct length */ > + fhdr.length = (u16)used; > + bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr); > + /* no CHECK_WRET as used must not be updated */ > + if (bytes_w < 0) > + return bytes_w; > + return used; > +} > diff --git a/tools/coresight/coresight-cfg-bufw.h b/tools/coresight/coresight-cfg-bufw.h > new file mode 100644 > index 000000000000..562df97599fc > --- /dev/null > +++ b/tools/coresight/coresight-cfg-bufw.h > @@ -0,0 +1,26 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (c) 2020 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-file.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_file_write_buffer(u8 *buffer, const int buflen, > + struct cscfg_config_desc *config_desc, > + struct cscfg_feature_desc **feat_descs); > + > +#endif /* _CORESIGHT_CFG_BUFW_H */ > diff --git a/tools/coresight/coresight-cfg-example1.c b/tools/coresight/coresight-cfg-example1.c > new file mode 100644 > index 000000000000..a71a6e43d7b3 > --- /dev/null > +++ b/tools/coresight/coresight-cfg-example1.c > @@ -0,0 +1,65 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 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" > + > +/* > + * 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 > +}; > + > +#define CSCFG_EG1_FILENAME "example1.cscfg" > + > +struct cscfg_file_eg_info buff_info_eg1 = { > + .example_name = "example1", > + .filename = CSCFG_EG1_FILENAME, > + .config_descs = sample_cfgs, > + .feat_descs = sample_feats, > +}; > diff --git a/tools/coresight/coresight-cfg-examples.h b/tools/coresight/coresight-cfg-examples.h > new file mode 100644 > index 000000000000..5c6908745201 > --- /dev/null > +++ b/tools/coresight/coresight-cfg-examples.h > @@ -0,0 +1,27 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (c) 2020 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 "uapi/coresight-config-uapi.h" > +#include "coresight-cfg-bufw.h" > + > +/* structure to pass configuraiton information to 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; > +}; > + > + > +/* references to the configuration and feature example structures */ > +extern struct cscfg_file_eg_info buff_info_eg1; > + > +#endif /* _CORESIGHT_CFG_EXAMPLES_H */ > diff --git a/tools/coresight/coresight-cfg-file-read.c b/tools/coresight/coresight-cfg-file-read.c > new file mode 100644 > index 000000000000..da7b831eb2df > --- /dev/null > +++ b/tools/coresight/coresight-cfg-file-read.c > @@ -0,0 +1,197 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 Linaro Limited, All rights reserved. > + * Author: Mike Leach <mike.leach@linaro.org> > + */ > + > +#include <linux/types.h> > +#include <linux/unistd.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <unistd.h> > + > +#include "coresight-config-file.h" > +#include "uapi/coresight-config-uapi.h" > + > +/* > + * tool to read and print a generated configuration > + * re-uses the read code source from the driver. > + */ > + > +static void print_configs(struct cscfg_fs_load_descs *load_descs) > +{ > + struct cscfg_config_desc *config_desc = load_descs->config_descs[0]; > + int i, j, p; > + > + if (!config_desc) { > + printf("File contains no configurations.\n\n"); > + return; > + } > + > + printf("Configuration name : %s\n", config_desc->name); > + 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"); > +} > + > +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("idx = %d\n", reg_desc->param_idx); > + 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_fs_load_descs *load_descs) > +{ > + struct cscfg_feature_desc *feat_desc = 0; > + int idx = 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 name : %s\n", idx+1, feat_desc->name); > + printf("Description: %s\n", feat_desc->description); > + printf("Match flags: 0x%x\n", feat_desc->match_flags); > + printf("Number of Paraneters: %d\n", feat_desc->nr_params); > + if (feat_desc->nr_params) > + print_params(feat_desc->nr_params, feat_desc->params_desc); > + printf("Number 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]; > + } > +} > + > +int main(int argc, char **argv) > +{ > + FILE *fp; > + struct cscfg_fs_load_descs *load_descs; > + int err, fsize; > + u8 buffer[CSCFG_FILE_MAXSIZE]; > + > + printf("CoreSight Configuration file reader\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_FILE_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 = malloc(sizeof(struct cscfg_fs_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_file_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); > + print_features(load_descs); > + > +exit_free_mem: > + free(load_descs); > + return err; > +} > diff --git a/tools/coresight/coresight-cfg-filegen.c b/tools/coresight/coresight-cfg-filegen.c > new file mode 100644 > index 000000000000..cd0589661d92 > --- /dev/null > +++ b/tools/coresight/coresight-cfg-filegen.c > @@ -0,0 +1,58 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 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 "uapi/coresight-config-uapi.h" > +#include "coresight-cfg-bufw.h" > +#include "coresight-cfg-examples.h" > + > + > +/* array of example files to generate */ > +struct cscfg_file_eg_info *info_ptrs[] = { > + &buff_info_eg1, > + NULL, > +}; > + > +int main(int argc, char **argv) > +{ > + struct cscfg_config_desc *config_desc; > + struct cscfg_feature_desc **feat_descs; > + u8 buffer[CSCFG_FILE_MAXSIZE]; > + int used, idx = 0; > + FILE *fp; > + const char *filename; > + > + printf("Coresight Configuration file Generator\n\n"); > + > + while (info_ptrs[idx]) { > + printf("Generating %s example\n", info_ptrs[idx]->example_name); > + config_desc = info_ptrs[idx]->config_descs[0]; > + feat_descs = info_ptrs[idx]->feat_descs; > + filename = info_ptrs[idx]->filename; > + used = cscfg_file_write_buffer(buffer, CSCFG_FILE_MAXSIZE, > + config_desc, 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; > +} > diff --git a/tools/include/uapi/coresight-config-uapi.h b/tools/include/uapi/coresight-config-uapi.h > new file mode 100644 > index 000000000000..d051c01ea982 > --- /dev/null > +++ b/tools/include/uapi/coresight-config-uapi.h > @@ -0,0 +1,76 @@ > +/* 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 "coresight-config.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 */ > +}; I would call the above cscfg_feature_fs_desc and cscfg_config_fs_desc to make sure they don't get confused with the kernel's internal structures of the same name. Moreover, I would keep this file private to tools/coresight/ and rename it coresight-config.h. > + > +#endif /* _CORESIGHT_CORESIGHT_CONFIG_UAPI_H */ > -- > 2.17.1 >
Hi Mathieu, I've fixed up the minor comments from your previous mail On Fri, 27 May 2022 at 17:25, Mathieu Poirier <mathieu.poirier@linaro.org> wrote: > > On Thu, Apr 14, 2022 at 07:44:56AM +0100, Mike Leach wrote: > > Add an example file generator to test loading configurations via a > > binary attribute in configfs. > > > > Provides a file buffer writer function that can be re-used in other > > userspace programs. > > > > Buffer write format matches that expected by the corresponding reader > > in the configfs driver code. > > > > Add a config file reader and printer. Takes in config files and prints > > the contents. Uses file reader source from kernel driver. > > > > Signed-off-by: Mike Leach <mike.leach@linaro.org> > > --- > > MAINTAINERS | 2 + > > .../coresight/coresight-config-file.c | 2 + > > tools/coresight/Makefile | 51 +++ > > tools/coresight/coresight-cfg-bufw.c | 303 ++++++++++++++++++ > > tools/coresight/coresight-cfg-bufw.h | 26 ++ > > tools/coresight/coresight-cfg-example1.c | 65 ++++ > > tools/coresight/coresight-cfg-examples.h | 27 ++ > > tools/coresight/coresight-cfg-file-read.c | 197 ++++++++++++ > > tools/coresight/coresight-cfg-filegen.c | 58 ++++ > > tools/include/uapi/coresight-config-uapi.h | 76 +++++ > > 10 files changed, 807 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-examples.h > > create mode 100644 tools/coresight/coresight-cfg-file-read.c > > create mode 100644 tools/coresight/coresight-cfg-filegen.c > > create mode 100644 tools/include/uapi/coresight-config-uapi.h > > > > diff --git a/MAINTAINERS b/MAINTAINERS > > index 61d9f114c37f..4e59486e75b5 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -1985,6 +1985,8 @@ F: drivers/hwtracing/coresight/* > > F: include/dt-bindings/arm/coresight-cti-dt.h > > F: include/linux/coresight* > > F: samples/coresight/* > > +F: tools/coresight/* > > +F: tools/include/uapi/coresight-config-uapi.h > > F: tools/perf/arch/arm/util/auxtrace.c > > F: tools/perf/arch/arm/util/cs-etm.c > > F: tools/perf/arch/arm/util/cs-etm.h > > diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c > > index 5b8f635ac50e..4a8b64405d84 100644 > > --- a/drivers/hwtracing/coresight/coresight-config-file.c > > +++ b/drivers/hwtracing/coresight/coresight-config-file.c > > @@ -36,6 +36,8 @@ static void *cscfg_zalloc(size_t size) > > #include <string.h> > > #include <stdlib.h> > > > > +#include "uapi/coresight-config-uapi.h" > > + > > static void *cscfg_calloc(size_t num, size_t size) > > { > > return calloc(num, size); > > diff --git a/tools/coresight/Makefile b/tools/coresight/Makefile > > new file mode 100644 > > index 000000000000..4004c315d65c > > --- /dev/null > > +++ b/tools/coresight/Makefile > > @@ -0,0 +1,51 @@ > > +# SPDX-License-Identifier: GPL-2.0-only > > +include ../scripts/Makefile.include > > +include ../scripts/Makefile.arch > > + > > +# Makefile to build the coresight configuration 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) > > + > > +# compile flags > > +CFLAGS += $(CPPFLAGS) -c -Wall -DLINUX -Wno-switch -Wlogical-op -fPIC -I$(srctree)/drivers/hwtracing/coresight -I$(srctree)/tools/include/ -I$(srctree)/tools/include/uapi > > + > > +# object files > > +coresight-cfg-file-gen-objs := coresight-cfg-filegen.o coresight-cfg-bufw.o coresight-cfg-example1.o > > +coresight-cfg-file-read-objs := coresight-cfg-file-read.o coresight-config-file.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-file.o: src_copy > > + $(CC) $(CFLAGS) coresight-config-file.c -o coresight-config-file.o > > + > > +.PHONY: src_copy > > +src_copy: > > + @cp $(srctree)/drivers/hwtracing/coresight/coresight-config-file.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-file.c > > + rm -f *.cscfg > > diff --git a/tools/coresight/coresight-cfg-bufw.c b/tools/coresight/coresight-cfg-bufw.c > > new file mode 100644 > > index 000000000000..73223de2b7e0 > > --- /dev/null > > +++ b/tools/coresight/coresight-cfg-bufw.c > > @@ -0,0 +1,303 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2020 Linaro Limited, All rights reserved. > > + * Author: Mike Leach <mike.leach@linaro.org> > > + */ > > + > > +#include <string.h> > > + > > +#include "coresight-cfg-bufw.h" > > +#include "uapi/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++; \ > > + } > > + > > +#define CHECK_WRET(rval) { \ > > + if (rval < 0) \ > > + return rval; \ > > + used += rval; \ > > + } > > + > > +/* write the header at the start of the buffer */ > > +static int cscfg_file_write_fhdr(u8 *buffer, const int buflen, > > + const struct cscfg_file_header *fhdr) > > +{ > > + int used = 0; > > + > > + cscfg_write_u32(fhdr->magic_version); > > + cscfg_write_u16(fhdr->length); > > + cscfg_write_u16(fhdr->nr_features); > > + return used; > > +} > > + > > +static int cscfg_file_write_string(u8 *buffer, const int buflen, const char *string) > > +{ > > + int len, used = 0; > > + > > + len = strlen(string); > > + if (len > CSCFG_FILE_STR_MAXSIZE) > > + return -EINVAL; > > + > > + if (buflen < (len + 1 + sizeof(u16))) > > + return -EINVAL; > > + > > + cscfg_write_u16((u16)(len + 1)); > > + strcpy((char *)(buffer + used), string); > > + used += (len + 1); > > + > > + return used; > > +} > > + > > +static int cscfg_file_write_elem_hdr(u8 *buffer, const int buflen, > > + struct cscfg_file_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_file_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_file_elem_header ehdr; > > + > > + ehdr.elem_length = 0; > > + ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_CFG; > > + > > + /* write element header at current buffer location */ > > + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); > > + CHECK_WRET(bytes_w); > > + > > + /* write out the configuration name */ > > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > > + config_desc->name); > > + CHECK_WRET(bytes_w); > > + > > + /* write out the description string */ > > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > > + config_desc->description); > > + CHECK_WRET(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_file_write_string(buffer + used, buflen - used, > > + config_desc->feat_ref_names[i]); > > + CHECK_WRET(bytes_w); > > + } > > + > > + /* rewrite the element header with the correct length */ > > + ehdr.elem_length = used; > > + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); > > + /* no CHECK_WRET as used must not be updated */ > > + if (bytes_w < 0) > > + return bytes_w; > > + > > + return used; > > +} > > + > > +/* > > + * write a parameter structure into the buffer in following format: > > + * [cscfg_file_elem_str] - parameter name. > > + * [u64 value: param_value] - initial value. > > + */ > > +static int cscfg_file_write_param(u8 *buffer, const int buflen, > > + struct cscfg_parameter_desc *param_desc) > > +{ > > + int used = 0, bytes_w; > > + > > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > > + param_desc->name); > > + CHECK_WRET(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_file_elem_header] - header length is total bytes to end of param structures. > > + * [cscfg_file_elem_str] - feature name. > > + * [cscfg_file_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_file_write_feat(u8 *buffer, const int buflen, > > + struct cscfg_feature_desc *feat_desc) > > +{ > > + struct cscfg_file_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_FILE_ELEM_TYPE_FEAT; > > + > > + /* write element header at current buffer location */ > > + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); > > + CHECK_WRET(bytes_w); > > + > > + /* write out the name string */ > > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > > + feat_desc->name); > > + CHECK_WRET(bytes_w) > > + > > + /* write out the description string */ > > + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, > > + feat_desc->description); > > + CHECK_WRET(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_FILE_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_file_write_param(buffer + used, buflen - used, > > + &feat_desc->params_desc[i]); > > + CHECK_WRET(bytes_w); > > + } > > + > > + /* > > + * rewrite the element header at the start of the buffer block > > + * with the correct length > > + */ > > + ehdr.elem_length = used; > > + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); > > + /* no CHECK_WRET as used must not be updated */ > > + 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_file_write_buffer(u8 *buffer, const int buflen, > > + struct cscfg_config_desc *config_desc, > > + struct cscfg_feature_desc **feat_descs) > > +{ > > + struct cscfg_file_header fhdr; > > + int used = 0, bytes_w, i; > > + > > + /* init the file header */ > > + fhdr.magic_version = CSCFG_FILE_MAGIC_VERSION; > > + fhdr.length = 0; > > + fhdr.nr_features = 0; > > + > > + /* 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 ((!config_desc && !fhdr.nr_features) || > > + !buffer || (buflen > CSCFG_FILE_MAXSIZE)) > > + return -EINVAL; > > + > > + /* write a header at the start to get the length of the header */ > > + bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr); > > + CHECK_WRET(bytes_w); > > + > > + /* write a single config */ > > + if (config_desc) { > > + bytes_w = cscfg_file_write_config(buffer + used, buflen - used, > > + config_desc); > > + CHECK_WRET(bytes_w); > > + } > > + > > + /* write any features */ > > + for (i = 0; i < fhdr.nr_features; i++) { > > + bytes_w = cscfg_file_write_feat(buffer + used, buflen - used, > > + feat_descs[i]); > > + CHECK_WRET(bytes_w); > > + } > > + > > + /* finally re-write the header at the buffer start with the correct length */ > > + fhdr.length = (u16)used; > > + bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr); > > + /* no CHECK_WRET as used must not be updated */ > > + if (bytes_w < 0) > > + return bytes_w; > > + return used; > > +} > > diff --git a/tools/coresight/coresight-cfg-bufw.h b/tools/coresight/coresight-cfg-bufw.h > > new file mode 100644 > > index 000000000000..562df97599fc > > --- /dev/null > > +++ b/tools/coresight/coresight-cfg-bufw.h > > @@ -0,0 +1,26 @@ > > +/* SPDX-License-Identifier: GPL-2.0 */ > > +/* > > + * Copyright (c) 2020 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-file.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_file_write_buffer(u8 *buffer, const int buflen, > > + struct cscfg_config_desc *config_desc, > > + struct cscfg_feature_desc **feat_descs); > > + > > +#endif /* _CORESIGHT_CFG_BUFW_H */ > > diff --git a/tools/coresight/coresight-cfg-example1.c b/tools/coresight/coresight-cfg-example1.c > > new file mode 100644 > > index 000000000000..a71a6e43d7b3 > > --- /dev/null > > +++ b/tools/coresight/coresight-cfg-example1.c > > @@ -0,0 +1,65 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2020 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" > > + > > +/* > > + * 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 > > +}; > > + > > +#define CSCFG_EG1_FILENAME "example1.cscfg" > > + > > +struct cscfg_file_eg_info buff_info_eg1 = { > > + .example_name = "example1", > > + .filename = CSCFG_EG1_FILENAME, > > + .config_descs = sample_cfgs, > > + .feat_descs = sample_feats, > > +}; > > diff --git a/tools/coresight/coresight-cfg-examples.h b/tools/coresight/coresight-cfg-examples.h > > new file mode 100644 > > index 000000000000..5c6908745201 > > --- /dev/null > > +++ b/tools/coresight/coresight-cfg-examples.h > > @@ -0,0 +1,27 @@ > > +/* SPDX-License-Identifier: GPL-2.0 */ > > +/* > > + * Copyright (c) 2020 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 "uapi/coresight-config-uapi.h" > > +#include "coresight-cfg-bufw.h" > > + > > +/* structure to pass configuraiton information to 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; > > +}; > > + > > + > > +/* references to the configuration and feature example structures */ > > +extern struct cscfg_file_eg_info buff_info_eg1; > > + > > +#endif /* _CORESIGHT_CFG_EXAMPLES_H */ > > diff --git a/tools/coresight/coresight-cfg-file-read.c b/tools/coresight/coresight-cfg-file-read.c > > new file mode 100644 > > index 000000000000..da7b831eb2df > > --- /dev/null > > +++ b/tools/coresight/coresight-cfg-file-read.c > > @@ -0,0 +1,197 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2020 Linaro Limited, All rights reserved. > > + * Author: Mike Leach <mike.leach@linaro.org> > > + */ > > + > > +#include <linux/types.h> > > +#include <linux/unistd.h> > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <unistd.h> > > + > > +#include "coresight-config-file.h" > > +#include "uapi/coresight-config-uapi.h" > > + > > +/* > > + * tool to read and print a generated configuration > > + * re-uses the read code source from the driver. > > + */ > > + > > +static void print_configs(struct cscfg_fs_load_descs *load_descs) > > +{ > > + struct cscfg_config_desc *config_desc = load_descs->config_descs[0]; > > + int i, j, p; > > + > > + if (!config_desc) { > > + printf("File contains no configurations.\n\n"); > > + return; > > + } > > + > > + printf("Configuration name : %s\n", config_desc->name); > > + 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"); > > +} > > + > > +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("idx = %d\n", reg_desc->param_idx); > > + 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_fs_load_descs *load_descs) > > +{ > > + struct cscfg_feature_desc *feat_desc = 0; > > + int idx = 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 name : %s\n", idx+1, feat_desc->name); > > + printf("Description: %s\n", feat_desc->description); > > + printf("Match flags: 0x%x\n", feat_desc->match_flags); > > + printf("Number of Paraneters: %d\n", feat_desc->nr_params); > > + if (feat_desc->nr_params) > > + print_params(feat_desc->nr_params, feat_desc->params_desc); > > + printf("Number 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]; > > + } > > +} > > + > > +int main(int argc, char **argv) > > +{ > > + FILE *fp; > > + struct cscfg_fs_load_descs *load_descs; > > + int err, fsize; > > + u8 buffer[CSCFG_FILE_MAXSIZE]; > > + > > + printf("CoreSight Configuration file reader\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_FILE_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 = malloc(sizeof(struct cscfg_fs_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_file_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); > > + print_features(load_descs); > > + > > +exit_free_mem: > > + free(load_descs); > > + return err; > > +} > > diff --git a/tools/coresight/coresight-cfg-filegen.c b/tools/coresight/coresight-cfg-filegen.c > > new file mode 100644 > > index 000000000000..cd0589661d92 > > --- /dev/null > > +++ b/tools/coresight/coresight-cfg-filegen.c > > @@ -0,0 +1,58 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2020 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 "uapi/coresight-config-uapi.h" > > +#include "coresight-cfg-bufw.h" > > +#include "coresight-cfg-examples.h" > > + > > + > > +/* array of example files to generate */ > > +struct cscfg_file_eg_info *info_ptrs[] = { > > + &buff_info_eg1, > > + NULL, > > +}; > > + > > +int main(int argc, char **argv) > > +{ > > + struct cscfg_config_desc *config_desc; > > + struct cscfg_feature_desc **feat_descs; > > + u8 buffer[CSCFG_FILE_MAXSIZE]; > > + int used, idx = 0; > > + FILE *fp; > > + const char *filename; > > + > > + printf("Coresight Configuration file Generator\n\n"); > > + > > + while (info_ptrs[idx]) { > > + printf("Generating %s example\n", info_ptrs[idx]->example_name); > > + config_desc = info_ptrs[idx]->config_descs[0]; > > + feat_descs = info_ptrs[idx]->feat_descs; > > + filename = info_ptrs[idx]->filename; > > + used = cscfg_file_write_buffer(buffer, CSCFG_FILE_MAXSIZE, > > + config_desc, 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; > > +} > > diff --git a/tools/include/uapi/coresight-config-uapi.h b/tools/include/uapi/coresight-config-uapi.h > > new file mode 100644 > > index 000000000000..d051c01ea982 > > --- /dev/null > > +++ b/tools/include/uapi/coresight-config-uapi.h > > @@ -0,0 +1,76 @@ > > +/* 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 "coresight-config.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 */ > > +}; > > I would call the above cscfg_feature_fs_desc and cscfg_config_fs_desc to make > sure they don't get confused with the kernel's internal structures of the same name. > The issue here is that the common reader code expects structs of these names. The alternative was to put multiple #if _KERNEL__ defines in the middle of the structures in the kernel headers to eliminate kernel only elements- which you pointed out in your comments to v2 of this set was a maintenence issue. This is a least worst alternative. We have common reader code, there are minimal changes to the kernel headers - some of the structures in coresight-config.h are backeted by a __KERNEL__ define but those without kernel specific elements are used in full. The cost is maintaining these two structures to be the same as the kernel versions - which I believe to be minimal as I do not expect the data format to change going forwards. > Moreover, I would keep this file private to tools/coresight/ and rename it > coresight-config.h. > I can and have moved it. Howver this file includes the kernel coresight-config.h, so renaming is a non-starter. Thanks and Regards Mike > > + > > +#endif /* _CORESIGHT_CORESIGHT_CONFIG_UAPI_H */ > > -- > > 2.17.1 > >
[...] > > > diff --git a/tools/include/uapi/coresight-config-uapi.h b/tools/include/uapi/coresight-config-uapi.h > > > new file mode 100644 > > > index 000000000000..d051c01ea982 > > > --- /dev/null > > > +++ b/tools/include/uapi/coresight-config-uapi.h > > > @@ -0,0 +1,76 @@ > > > +/* 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 "coresight-config.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 */ > > > +}; > > > > I would call the above cscfg_feature_fs_desc and cscfg_config_fs_desc to make > > sure they don't get confused with the kernel's internal structures of the same name. > > > > The issue here is that the common reader code expects structs of these names. > > The alternative was to put multiple #if _KERNEL__ defines in the > middle of the structures in the kernel headers to eliminate kernel > only elements- which you pointed out in your comments to v2 of this > set was a maintenence issue. > > This is a least worst alternative. We have common reader code, there > are minimal changes to the kernel headers - some of the structures in > coresight-config.h are backeted by a __KERNEL__ define but those > without kernel specific elements are used in full. > > The cost is maintaining these two structures to be the same as the > kernel versions - which I believe to be minimal as I do not expect the > data format to change going forwards. > I agree with you - the current implementation is the least intrusive and easiest to maintain. Unless someone finds an alternative it is better to keep the current solution. > > Moreover, I would keep this file private to tools/coresight/ and rename it > > coresight-config.h. > > > > I can and have moved it. > Howver this file includes the kernel coresight-config.h, so renaming > is a non-starter. > Yes, you are correct. > Thanks and Regards > > Mike > > > > + > > > +#endif /* _CORESIGHT_CORESIGHT_CONFIG_UAPI_H */ > > > -- > > > 2.17.1 > > > > > > > -- > Mike Leach > Principal Engineer, ARM Ltd. > Manchester Design Centre. UK
diff --git a/MAINTAINERS b/MAINTAINERS index 61d9f114c37f..4e59486e75b5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1985,6 +1985,8 @@ F: drivers/hwtracing/coresight/* F: include/dt-bindings/arm/coresight-cti-dt.h F: include/linux/coresight* F: samples/coresight/* +F: tools/coresight/* +F: tools/include/uapi/coresight-config-uapi.h F: tools/perf/arch/arm/util/auxtrace.c F: tools/perf/arch/arm/util/cs-etm.c F: tools/perf/arch/arm/util/cs-etm.h diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c index 5b8f635ac50e..4a8b64405d84 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.c +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -36,6 +36,8 @@ static void *cscfg_zalloc(size_t size) #include <string.h> #include <stdlib.h> +#include "uapi/coresight-config-uapi.h" + static void *cscfg_calloc(size_t num, size_t size) { return calloc(num, size); diff --git a/tools/coresight/Makefile b/tools/coresight/Makefile new file mode 100644 index 000000000000..4004c315d65c --- /dev/null +++ b/tools/coresight/Makefile @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only +include ../scripts/Makefile.include +include ../scripts/Makefile.arch + +# Makefile to build the coresight configuration 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) + +# compile flags +CFLAGS += $(CPPFLAGS) -c -Wall -DLINUX -Wno-switch -Wlogical-op -fPIC -I$(srctree)/drivers/hwtracing/coresight -I$(srctree)/tools/include/ -I$(srctree)/tools/include/uapi + +# object files +coresight-cfg-file-gen-objs := coresight-cfg-filegen.o coresight-cfg-bufw.o coresight-cfg-example1.o +coresight-cfg-file-read-objs := coresight-cfg-file-read.o coresight-config-file.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-file.o: src_copy + $(CC) $(CFLAGS) coresight-config-file.c -o coresight-config-file.o + +.PHONY: src_copy +src_copy: + @cp $(srctree)/drivers/hwtracing/coresight/coresight-config-file.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-file.c + rm -f *.cscfg diff --git a/tools/coresight/coresight-cfg-bufw.c b/tools/coresight/coresight-cfg-bufw.c new file mode 100644 index 000000000000..73223de2b7e0 --- /dev/null +++ b/tools/coresight/coresight-cfg-bufw.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach <mike.leach@linaro.org> + */ + +#include <string.h> + +#include "coresight-cfg-bufw.h" +#include "uapi/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++; \ + } + +#define CHECK_WRET(rval) { \ + if (rval < 0) \ + return rval; \ + used += rval; \ + } + +/* write the header at the start of the buffer */ +static int cscfg_file_write_fhdr(u8 *buffer, const int buflen, + const struct cscfg_file_header *fhdr) +{ + int used = 0; + + cscfg_write_u32(fhdr->magic_version); + cscfg_write_u16(fhdr->length); + cscfg_write_u16(fhdr->nr_features); + return used; +} + +static int cscfg_file_write_string(u8 *buffer, const int buflen, const char *string) +{ + int len, used = 0; + + len = strlen(string); + if (len > CSCFG_FILE_STR_MAXSIZE) + return -EINVAL; + + if (buflen < (len + 1 + sizeof(u16))) + return -EINVAL; + + cscfg_write_u16((u16)(len + 1)); + strcpy((char *)(buffer + used), string); + used += (len + 1); + + return used; +} + +static int cscfg_file_write_elem_hdr(u8 *buffer, const int buflen, + struct cscfg_file_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_file_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_file_elem_header ehdr; + + ehdr.elem_length = 0; + ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_CFG; + + /* write element header at current buffer location */ + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); + CHECK_WRET(bytes_w); + + /* write out the configuration name */ + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, + config_desc->name); + CHECK_WRET(bytes_w); + + /* write out the description string */ + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, + config_desc->description); + CHECK_WRET(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_file_write_string(buffer + used, buflen - used, + config_desc->feat_ref_names[i]); + CHECK_WRET(bytes_w); + } + + /* rewrite the element header with the correct length */ + ehdr.elem_length = used; + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); + /* no CHECK_WRET as used must not be updated */ + if (bytes_w < 0) + return bytes_w; + + return used; +} + +/* + * write a parameter structure into the buffer in following format: + * [cscfg_file_elem_str] - parameter name. + * [u64 value: param_value] - initial value. + */ +static int cscfg_file_write_param(u8 *buffer, const int buflen, + struct cscfg_parameter_desc *param_desc) +{ + int used = 0, bytes_w; + + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, + param_desc->name); + CHECK_WRET(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_file_elem_header] - header length is total bytes to end of param structures. + * [cscfg_file_elem_str] - feature name. + * [cscfg_file_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_file_write_feat(u8 *buffer, const int buflen, + struct cscfg_feature_desc *feat_desc) +{ + struct cscfg_file_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_FILE_ELEM_TYPE_FEAT; + + /* write element header at current buffer location */ + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); + CHECK_WRET(bytes_w); + + /* write out the name string */ + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, + feat_desc->name); + CHECK_WRET(bytes_w) + + /* write out the description string */ + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, + feat_desc->description); + CHECK_WRET(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_FILE_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_file_write_param(buffer + used, buflen - used, + &feat_desc->params_desc[i]); + CHECK_WRET(bytes_w); + } + + /* + * rewrite the element header at the start of the buffer block + * with the correct length + */ + ehdr.elem_length = used; + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); + /* no CHECK_WRET as used must not be updated */ + 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_file_write_buffer(u8 *buffer, const int buflen, + struct cscfg_config_desc *config_desc, + struct cscfg_feature_desc **feat_descs) +{ + struct cscfg_file_header fhdr; + int used = 0, bytes_w, i; + + /* init the file header */ + fhdr.magic_version = CSCFG_FILE_MAGIC_VERSION; + fhdr.length = 0; + fhdr.nr_features = 0; + + /* 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 ((!config_desc && !fhdr.nr_features) || + !buffer || (buflen > CSCFG_FILE_MAXSIZE)) + return -EINVAL; + + /* write a header at the start to get the length of the header */ + bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr); + CHECK_WRET(bytes_w); + + /* write a single config */ + if (config_desc) { + bytes_w = cscfg_file_write_config(buffer + used, buflen - used, + config_desc); + CHECK_WRET(bytes_w); + } + + /* write any features */ + for (i = 0; i < fhdr.nr_features; i++) { + bytes_w = cscfg_file_write_feat(buffer + used, buflen - used, + feat_descs[i]); + CHECK_WRET(bytes_w); + } + + /* finally re-write the header at the buffer start with the correct length */ + fhdr.length = (u16)used; + bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr); + /* no CHECK_WRET as used must not be updated */ + if (bytes_w < 0) + return bytes_w; + return used; +} diff --git a/tools/coresight/coresight-cfg-bufw.h b/tools/coresight/coresight-cfg-bufw.h new file mode 100644 index 000000000000..562df97599fc --- /dev/null +++ b/tools/coresight/coresight-cfg-bufw.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 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-file.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_file_write_buffer(u8 *buffer, const int buflen, + struct cscfg_config_desc *config_desc, + struct cscfg_feature_desc **feat_descs); + +#endif /* _CORESIGHT_CFG_BUFW_H */ diff --git a/tools/coresight/coresight-cfg-example1.c b/tools/coresight/coresight-cfg-example1.c new file mode 100644 index 000000000000..a71a6e43d7b3 --- /dev/null +++ b/tools/coresight/coresight-cfg-example1.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 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" + +/* + * 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 +}; + +#define CSCFG_EG1_FILENAME "example1.cscfg" + +struct cscfg_file_eg_info buff_info_eg1 = { + .example_name = "example1", + .filename = CSCFG_EG1_FILENAME, + .config_descs = sample_cfgs, + .feat_descs = sample_feats, +}; diff --git a/tools/coresight/coresight-cfg-examples.h b/tools/coresight/coresight-cfg-examples.h new file mode 100644 index 000000000000..5c6908745201 --- /dev/null +++ b/tools/coresight/coresight-cfg-examples.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 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 "uapi/coresight-config-uapi.h" +#include "coresight-cfg-bufw.h" + +/* structure to pass configuraiton information to 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; +}; + + +/* references to the configuration and feature example structures */ +extern struct cscfg_file_eg_info buff_info_eg1; + +#endif /* _CORESIGHT_CFG_EXAMPLES_H */ diff --git a/tools/coresight/coresight-cfg-file-read.c b/tools/coresight/coresight-cfg-file-read.c new file mode 100644 index 000000000000..da7b831eb2df --- /dev/null +++ b/tools/coresight/coresight-cfg-file-read.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach <mike.leach@linaro.org> + */ + +#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "coresight-config-file.h" +#include "uapi/coresight-config-uapi.h" + +/* + * tool to read and print a generated configuration + * re-uses the read code source from the driver. + */ + +static void print_configs(struct cscfg_fs_load_descs *load_descs) +{ + struct cscfg_config_desc *config_desc = load_descs->config_descs[0]; + int i, j, p; + + if (!config_desc) { + printf("File contains no configurations.\n\n"); + return; + } + + printf("Configuration name : %s\n", config_desc->name); + 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"); +} + +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("idx = %d\n", reg_desc->param_idx); + 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_fs_load_descs *load_descs) +{ + struct cscfg_feature_desc *feat_desc = 0; + int idx = 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 name : %s\n", idx+1, feat_desc->name); + printf("Description: %s\n", feat_desc->description); + printf("Match flags: 0x%x\n", feat_desc->match_flags); + printf("Number of Paraneters: %d\n", feat_desc->nr_params); + if (feat_desc->nr_params) + print_params(feat_desc->nr_params, feat_desc->params_desc); + printf("Number 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]; + } +} + +int main(int argc, char **argv) +{ + FILE *fp; + struct cscfg_fs_load_descs *load_descs; + int err, fsize; + u8 buffer[CSCFG_FILE_MAXSIZE]; + + printf("CoreSight Configuration file reader\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_FILE_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 = malloc(sizeof(struct cscfg_fs_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_file_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); + print_features(load_descs); + +exit_free_mem: + free(load_descs); + return err; +} diff --git a/tools/coresight/coresight-cfg-filegen.c b/tools/coresight/coresight-cfg-filegen.c new file mode 100644 index 000000000000..cd0589661d92 --- /dev/null +++ b/tools/coresight/coresight-cfg-filegen.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 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 "uapi/coresight-config-uapi.h" +#include "coresight-cfg-bufw.h" +#include "coresight-cfg-examples.h" + + +/* array of example files to generate */ +struct cscfg_file_eg_info *info_ptrs[] = { + &buff_info_eg1, + NULL, +}; + +int main(int argc, char **argv) +{ + struct cscfg_config_desc *config_desc; + struct cscfg_feature_desc **feat_descs; + u8 buffer[CSCFG_FILE_MAXSIZE]; + int used, idx = 0; + FILE *fp; + const char *filename; + + printf("Coresight Configuration file Generator\n\n"); + + while (info_ptrs[idx]) { + printf("Generating %s example\n", info_ptrs[idx]->example_name); + config_desc = info_ptrs[idx]->config_descs[0]; + feat_descs = info_ptrs[idx]->feat_descs; + filename = info_ptrs[idx]->filename; + used = cscfg_file_write_buffer(buffer, CSCFG_FILE_MAXSIZE, + config_desc, 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; +} diff --git a/tools/include/uapi/coresight-config-uapi.h b/tools/include/uapi/coresight-config-uapi.h new file mode 100644 index 000000000000..d051c01ea982 --- /dev/null +++ b/tools/include/uapi/coresight-config-uapi.h @@ -0,0 +1,76 @@ +/* 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 "coresight-config.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 */ +}; + +#endif /* _CORESIGHT_CORESIGHT_CONFIG_UAPI_H */
Add an example file generator to test loading configurations via a binary attribute in configfs. Provides a file buffer writer function that can be re-used in other userspace programs. Buffer write format matches that expected by the corresponding reader in the configfs driver code. Add a config file reader and printer. Takes in config files and prints the contents. Uses file reader source from kernel driver. Signed-off-by: Mike Leach <mike.leach@linaro.org> --- MAINTAINERS | 2 + .../coresight/coresight-config-file.c | 2 + tools/coresight/Makefile | 51 +++ tools/coresight/coresight-cfg-bufw.c | 303 ++++++++++++++++++ tools/coresight/coresight-cfg-bufw.h | 26 ++ tools/coresight/coresight-cfg-example1.c | 65 ++++ tools/coresight/coresight-cfg-examples.h | 27 ++ tools/coresight/coresight-cfg-file-read.c | 197 ++++++++++++ tools/coresight/coresight-cfg-filegen.c | 58 ++++ tools/include/uapi/coresight-config-uapi.h | 76 +++++ 10 files changed, 807 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-examples.h create mode 100644 tools/coresight/coresight-cfg-file-read.c create mode 100644 tools/coresight/coresight-cfg-filegen.c create mode 100644 tools/include/uapi/coresight-config-uapi.h