diff mbox series

[v3,4/5] coresight: tools: Add config file write and reader tools

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

Commit Message

Mike Leach April 14, 2022, 6:44 a.m. UTC
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

Comments

Mathieu Poirier May 26, 2022, 5:46 p.m. UTC | #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;		   \
> +	}
> +

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 = &regs_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
>
Mathieu Poirier May 27, 2022, 4:25 p.m. UTC | #2
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 = &regs_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
>
Mike Leach June 1, 2022, 10:56 a.m. UTC | #3
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 = &regs_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
> >
Mathieu Poirier June 1, 2022, 4:10 p.m. UTC | #4
[...]

> > > 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 mbox series

Patch

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 = &regs_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 */