[PATCH v2 4/6] coresight: samples: Add an example config writer for configfs load
Mathieu Poirier
mathieu.poirier at linaro.org
Thu Jan 13 09:56:36 PST 2022
Good morning Mike,
On Tue, Nov 30, 2021 at 10:00:58PM +0000, 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.
>
Despite trying quite hard I haven't found a single bug in this patchset, which
is a feat for user space code.
Please see comments below...
> Signed-off-by: Mike Leach <mike.leach at linaro.org>
> ---
> samples/coresight/Makefile | 7 +
> samples/coresight/coresight-cfg-bufw.c | 302 ++++++++++++++++++++++
> samples/coresight/coresight-cfg-bufw.h | 24 ++
> samples/coresight/coresight-cfg-filegen.c | 89 +++++++
> 4 files changed, 422 insertions(+)
> create mode 100644 samples/coresight/coresight-cfg-bufw.c
> create mode 100644 samples/coresight/coresight-cfg-bufw.h
> create mode 100644 samples/coresight/coresight-cfg-filegen.c
>
> diff --git a/samples/coresight/Makefile b/samples/coresight/Makefile
> index b3fce4af2347..07bfd99d7a68 100644
> --- a/samples/coresight/Makefile
> +++ b/samples/coresight/Makefile
> @@ -1,4 +1,11 @@
> # SPDX-License-Identifier: GPL-2.0-only
>
> +# coresight config - loadable module configuration.
> obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG) += coresight-cfg-sample.o
> ccflags-y += -I$(srctree)/drivers/hwtracing/coresight
> +
> +# coresight config - configfs loadable binary config generator
> +userprogs-always-y += coresight-cfg-filegen
> +
> +coresight-cfg-filegen-objs := coresight-cfg-filegen.o coresight-cfg-bufw.o
> +userccflags += -I$(srctree)/drivers/hwtracing/coresight
> diff --git a/samples/coresight/coresight-cfg-bufw.c b/samples/coresight/coresight-cfg-bufw.c
> new file mode 100644
> index 000000000000..8c32a8509eef
> --- /dev/null
> +++ b/samples/coresight/coresight-cfg-bufw.c
> @@ -0,0 +1,302 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2020 Linaro Limited, All rights reserved.
Are you sure you want to keep this to 2020? Here and in all other files.
> + * Author: Mike Leach <mike.leach at linaro.org>
> + */
> +
> +#include <string.h>
> +
> +#include "coresight-cfg-bufw.h"
> +
> +/*
> + * Set of macros to make writing the buffer code easier.
> + *.
Extra '.'
> + * 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;
> +}
> +
> +
Extra newline
> +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
> + *
> + *
Extra newlines
> + */
> +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/samples/coresight/coresight-cfg-bufw.h b/samples/coresight/coresight-cfg-bufw.h
> new file mode 100644
> index 000000000000..00b16c583cad
> --- /dev/null
> +++ b/samples/coresight/coresight-cfg-bufw.h
> @@ -0,0 +1,24 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2020 Linaro Limited, All rights reserved.
> + * Author: Mike Leach <mike.leach at linaro.org>
> + */
> +
> +#ifndef _CORESIGHT_CFG_BUFW_H
> +#define _CORESIGHT_CFG_BUFW_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/samples/coresight/coresight-cfg-filegen.c b/samples/coresight/coresight-cfg-filegen.c
> new file mode 100644
> index 000000000000..c8be18ee97b6
> --- /dev/null
> +++ b/samples/coresight/coresight-cfg-filegen.c
> @@ -0,0 +1,89 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2020 Linaro Limited, All rights reserved.
> + * Author: Mike Leach <mike.leach at linaro.org>
> + */
> +
> +#include <linux/types.h>
> +#include <linux/unistd.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +
> +#include "coresight-cfg-bufw.h"
> +
> +/*
> + * generate example binary coresight configuration files for loading
> + * into the coresight subsystem via configfs
> + */
> +
> +/* create a similar configuration example as the coresight-cfg-sample.c file. */
> +
> +/* we will provide 4 sets of preset parameter values */
> +#define AFDO2_NR_PRESETS 4
> +/* the total number of parameters in used features - strobing has 2 */
> +#define AFDO2_NR_PARAM_SUM 2
> +
> +static const char *afdo2_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 afdo2_presets[AFDO2_NR_PRESETS][AFDO2_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(afdo2_ref_names),
> + .feat_ref_names = afdo2_ref_names,
> + .nr_presets = AFDO2_NR_PRESETS,
> + .nr_total_params = AFDO2_NR_PARAM_SUM,
> + .presets = &afdo2_presets[0][0],
> +};
> +
> +static struct cscfg_feature_desc *sample_feats[] = {
> + NULL
> +};
For completeness there would be value in providing an example that requires
features.
> +
> +static struct cscfg_config_desc *sample_cfgs[] = {
> + &afdo3,
> + NULL
> +};
Any reason to declare sample_cfgs[] when there can only be one configuration?
Lastly I get the following [1] when compiling this set - I have not investigated
further.
Thanks,
Mathieu
[1]. https://pastebin.com/Nw2DTqTC
> +
> +
> +#define CSCFG_BIN_FILENAME "example1.cscfg"
> +
> +int main(int argc, char **argv)
> +{
> + u8 buffer[CSCFG_FILE_MAXSIZE];
> + int used;
> + FILE *fp;
> +
> + printf("Coresight Configuration file Generator\n\n");
> +
> + used = cscfg_file_write_buffer(buffer, CSCFG_FILE_MAXSIZE,
> + sample_cfgs[0], sample_feats);
> +
> + if (used < 0) {
> + printf("Error %d writing configuration %s into buffer\n",
> + used, sample_cfgs[0]->name);
> + return used;
> + }
> +
> + fp = fopen(CSCFG_BIN_FILENAME, "wb");
> + if (fp == NULL) {
> + printf("Error opening file %s\n", CSCFG_BIN_FILENAME);
> + return -1;
> + }
> + fwrite(buffer, used, sizeof(u8), fp);
> + fclose(fp);
> + return 0;
> +}
> --
> 2.17.1
>
More information about the linux-arm-kernel
mailing list