This set extends the configfs support to allow loading and unloading of configurations as binary files via configfs.
Additional attributes - load, unload and last_load_status are provided to implement the load functionality.
Routines to generate binary configuration files are supplied in ./samples/coresight.
Example generator and reader applications are provided.
Additional Makefile.host supplied to build the generator and reader applications on the host system separate from a cross compiled kernel.
Documentation is updated to describe feature usage.
Applies and tested on latest coresight/next that includes the previous coresight configuration dynamic load patchset.
Changes since v1: 1) Rebased to coresight/next - 5.16-rc1 with previous coresight config set applied. 2) Makefile.host fixed to default to all target.
Mike Leach (6): coresight: configfs: Add in functionality for load via configfs coresight: configfs: Add in binary attributes to load files coresight: configfs: Modify config files to allow userspace use coresight: samples: Add an example config writer for configfs load coresight: samples: Add coresight file reader sample program Documentation: coresight: docs for config load via configfs
.../trace/coresight/coresight-config.rst | 151 +++++- drivers/hwtracing/coresight/Makefile | 2 +- .../coresight/coresight-config-file.c | 472 ++++++++++++++++++ .../coresight/coresight-config-file.h | 158 ++++++ .../hwtracing/coresight/coresight-config.h | 38 ++ .../coresight/coresight-syscfg-configfs.c | 148 +++++- .../coresight/coresight-syscfg-configfs.h | 8 + .../hwtracing/coresight/coresight-syscfg.c | 36 ++ .../hwtracing/coresight/coresight-syscfg.h | 2 + samples/coresight/Makefile | 23 + samples/coresight/Makefile.host | 47 ++ samples/coresight/coresight-cfg-bufw.c | 302 +++++++++++ samples/coresight/coresight-cfg-bufw.h | 24 + samples/coresight/coresight-cfg-file-read.c | 191 +++++++ samples/coresight/coresight-cfg-filegen.c | 89 ++++ 15 files changed, 1677 insertions(+), 14 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config-file.c create mode 100644 drivers/hwtracing/coresight/coresight-config-file.h create mode 100644 samples/coresight/Makefile.host 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-file-read.c create mode 100644 samples/coresight/coresight-cfg-filegen.c
Add in functionality to allow load via configfs.
define a binary file format and provide a reader for that format that will create and populate configuration and feature structures use by the driver infrastructure.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/Makefile | 2 +- .../coresight/coresight-config-file.c | 432 ++++++++++++++++++ .../coresight/coresight-config-file.h | 118 +++++ .../hwtracing/coresight/coresight-config.h | 17 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 569 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-config-file.c create mode 100644 drivers/hwtracing/coresight/coresight-config-file.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index b6c4a48140ec..5de2bb79f4ac 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ coresight-sysfs.o coresight-syscfg.o coresight-config.o \ coresight-cfg-preload.o coresight-cfg-afdo.o \ - coresight-syscfg-configfs.o + coresight-syscfg-configfs.o coresight-config-file.o obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c new file mode 100644 index 000000000000..3fd001938324 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -0,0 +1,432 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#include "coresight-config.h" +#include "coresight-config-file.h" +#include "coresight-syscfg.h" + +#define cscfg_extract_u64(val64) { \ + val64 = *(u64 *)(buffer + used); \ + used += sizeof(u64); \ + } + +#define cscfg_extract_u32(val32) { \ + val32 = *(u32 *)(buffer + used); \ + used += sizeof(u32); \ + } + +#define cscfg_extract_u16(val16) { \ + val16 = *(u16 *)(buffer + used); \ + used += sizeof(u16); \ + } + +#define cscfg_extract_u8(val8) { \ + val8 = *(buffer + used); \ + used++; \ + } + +static int cscfg_file_read_hdr(const u8 *buffer, const int buflen, int *buf_used, + struct cscfg_file_header *hdr) +{ + /* file header always at the start of the buffer */ + int used = 0; + + if (buflen < sizeof(struct cscfg_file_header)) + return -EINVAL; + + cscfg_extract_u32(hdr->magic_version); + if (hdr->magic_version != CSCFG_FILE_MAGIC_VERSION) + return -EINVAL; + + cscfg_extract_u16(hdr->length); + if (hdr->length > buflen) + return -EINVAL; + + cscfg_extract_u16(hdr->nr_features); + + *buf_used = used; + return 0; +} + +static int cscfg_file_read_elem_hdr(const u8 *buffer, const int buflen, int *buf_used, + struct cscfg_file_elem_header *elem_hdr) +{ + int used = *buf_used; + + if ((buflen - used) < (sizeof(u16) + sizeof(u8))) + return -EINVAL; + + /* read length and check enough buffer remains for this element */ + elem_hdr->elem_length = *(u16 *)(buffer + used); + if ((buflen - used) < elem_hdr->elem_length) + return -EINVAL; + /* don't use extract fn as we update used _after_ the comparison */ + used += sizeof(u16); + + /* read type and validate */ + cscfg_extract_u8(elem_hdr->elem_type); + if ((elem_hdr->elem_type < CSCFG_FILE_ELEM_TYPE_FEAT) || + (elem_hdr->elem_type > CSCFG_FILE_ELEM_TYPE_CFG)) + return -EINVAL; + + *buf_used = used; + return 0; +} + +static int cscfg_file_read_elem_str(const u8 *buffer, const int buflen, int *buf_used, + struct cscfg_file_elem_str *elem_str) +{ + int used = *buf_used; + + if ((buflen - used) < sizeof(u16)) + return -EINVAL; + + cscfg_extract_u16(elem_str->str_len); + + if ((buflen - used) < elem_str->str_len) + return -EINVAL; + + /* check for 0 termination */ + if (buffer[elem_str->str_len - 1] != 0) + return -EINVAL; + + elem_str->str = devm_kstrdup(cscfg_device(), (char *)buffer, GFP_KERNEL); + used += elem_str->str_len; + + *buf_used = used; + return 0; +} + +static int cscfg_file_alloc_desc_arrays(struct cscfg_fs_load_descs *desc_arrays, + int nr_features) +{ + /* arrays are 0 terminated - max of 1 config & nr_features features */ + desc_arrays->config_descs = devm_kcalloc(cscfg_device(), 2, + sizeof(struct cscfg_config_desc *), + GFP_KERNEL); + if (!desc_arrays->config_descs) + return -ENOMEM; + desc_arrays->feat_descs = devm_kcalloc(cscfg_device(), nr_features + 1, + sizeof(struct cscfg_feature_desc *), + GFP_KERNEL); + if (!desc_arrays->feat_descs) + return -ENOMEM; + return 0; +} + +static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int *buf_used, + struct cscfg_fs_load_descs *desc_arrays) +{ + struct cscfg_file_elem_header elem_hdr; + struct cscfg_file_elem_str elem_str; + struct cscfg_config_desc *config_desc; + int used = *buf_used, nr_preset_vals, nr_preset_bytes, i; + int err = 0; + u64 *presets; + + /* + * read the header - if not config, then don't update buf_used + * pointer on return + */ + err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr); + if (err) + return err; + if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_CFG) + return 0; + + /* we have a config - allocate the descriptor */ + config_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_config_desc), + GFP_KERNEL); + if (!config_desc) + return -ENOMEM; + + /* read the name string */ + err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str); + if (err) + return err; + config_desc->name = elem_str.str; + + /* read the description string */ + err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str); + if (err) + return err; + config_desc->description = elem_str.str; + + /* read in some values */ + if ((buflen - used) < sizeof(u64)) + return -EINVAL; + cscfg_extract_u16(config_desc->nr_presets); + cscfg_extract_u32(config_desc->nr_total_params); + cscfg_extract_u16(config_desc->nr_feat_refs); + + /* read the array of 64bit presets if present */ + nr_preset_vals = config_desc->nr_total_params * config_desc->nr_presets; + if (nr_preset_vals) { + presets = devm_kcalloc(cscfg_device(), nr_preset_vals, + sizeof(u64), GFP_KERNEL); + if (!presets) + return -ENOMEM; + + nr_preset_bytes = sizeof(u64) * nr_preset_vals; + if ((buflen - used) < nr_preset_bytes) + return -EINVAL; + + memcpy(presets, (buffer + used), nr_preset_bytes); + config_desc->presets = presets; + used += nr_preset_bytes; + } + + /* read the array of feature names referenced by the config */ + if (config_desc->nr_feat_refs) { + config_desc->feat_ref_names = devm_kcalloc(cscfg_device(), + config_desc->nr_feat_refs, + sizeof(char *), + GFP_KERNEL); + if (!config_desc->feat_ref_names) + return -ENOMEM; + + for (i = 0; i < config_desc->nr_feat_refs; i++) { + err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str); + if (err) + return err; + config_desc->feat_ref_names[i] = elem_str.str; + } + } + + desc_arrays->config_descs[0] = config_desc; + *buf_used = used; + return 0; +} + +/* just read the config name - if there is a config at this position */ +static int cscfg_file_read_elem_config_name(const u8 *buffer, const int buflen, int *buf_used, + struct cscfg_file_elem_str *elem_str) +{ + struct cscfg_file_elem_header elem_hdr; + int used = *buf_used; + int err; + + elem_str->str_len = 0; + /* + * read the header - if not config, then don't update buf_used + * pointer on return + */ + err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr); + if (err) + return err; + if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_CFG) + return 0; + + /* read the name string */ + err = cscfg_file_read_elem_str(buffer, buflen, &used, elem_str); + if (err) + return err; + *buf_used = used; + + return 0; +} + +static int cscfg_file_read_elem_param(const u8 *buffer, const int buflen, int *buf_used, + struct cscfg_parameter_desc *param_desc) +{ + struct cscfg_file_elem_str elem_str; + int err = 0, used = *buf_used; + + /* parameter name */ + err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str); + if (err) + return err; + param_desc->name = elem_str.str; + + /* parameter value */ + if ((buflen - used) < sizeof(u64)) + return -EINVAL; + cscfg_extract_u64(param_desc->value); + + *buf_used = used; + return err; +} + +static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int *buf_used, + struct cscfg_fs_load_descs *desc_arrays, + const int feat_idx) +{ + struct cscfg_file_elem_header elem_hdr; + struct cscfg_file_elem_str elem_str; + struct cscfg_feature_desc *feat_desc; + struct cscfg_regval_desc *p_reg_desc; + int used = *buf_used, err, i, nr_regs_bytes; + u32 val32; + + /* allocate the feature descriptor object */ + feat_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_feature_desc), + GFP_KERNEL); + if (!feat_desc) + return -ENOMEM; + + /* read and check the element header */ + err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr); + if (err) + return err; + + if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_FEAT) + return -EINVAL; + + /* read the feature name */ + err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str); + if (err) + return err; + feat_desc->name = elem_str.str; + + /* read the description string */ + err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str); + if (err) + return err; + feat_desc->description = elem_str.str; + + /* + * read in some values + * [u32 value: match_flags] + * [u16 value: nr_regs] - number of registers. + * [u16 value: nr_params] - number of parameters. + */ + cscfg_extract_u32(feat_desc->match_flags); + cscfg_extract_u16(feat_desc->nr_regs); + cscfg_extract_u16(feat_desc->nr_params); + + /* register descriptors - 32 bit + 64 bit value */ + if (feat_desc->nr_regs) { + nr_regs_bytes = ((sizeof(u32) + sizeof(u64)) * feat_desc->nr_regs); + if ((buflen - used) < nr_regs_bytes) + return -EINVAL; + feat_desc->regs_desc = devm_kcalloc(cscfg_device(), + feat_desc->nr_regs, + sizeof(struct cscfg_regval_desc), + GFP_KERNEL); + if (!feat_desc->regs_desc) + return -ENOMEM; + + for (i = 0; i < feat_desc->nr_regs; i++) { + cscfg_extract_u32(val32); + p_reg_desc = (struct cscfg_regval_desc *)&feat_desc->regs_desc[i]; + CSCFG_FILE_U32_TO_REG_DESC_INFO(val32, p_reg_desc); + cscfg_extract_u64(feat_desc->regs_desc[i].val64); + } + } + + /* parameter descriptors - string + 64 bit value */ + if (feat_desc->nr_params) { + feat_desc->params_desc = devm_kcalloc(cscfg_device(), + feat_desc->nr_params, + sizeof(struct cscfg_parameter_desc), + GFP_KERNEL); + if (!feat_desc->params_desc) + return -ENOMEM; + for (i = 0; i < feat_desc->nr_params; i++) { + err = cscfg_file_read_elem_param(buffer, buflen, &used, + &feat_desc->params_desc[i]); + if (err) + return err; + } + } + + desc_arrays->feat_descs[feat_idx] = feat_desc; + *buf_used = used; + return 0; +} + +/* just read the feature name - if there is a feature at this position */ +static int cscfg_file_read_elem_feat_name(const u8 *buffer, const int buflen, int *buf_used, + struct cscfg_file_elem_str *elem_str) +{ + struct cscfg_file_elem_header elem_hdr; + int used = *buf_used; + int err; + + elem_str->str_len = 0; + /* + * read the header - if not config, then don't update buf_used + * pointer on return + */ + err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr); + if (err) + return err; + if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_FEAT) + return -EINVAL; + + /* read the feature name */ + err = cscfg_file_read_elem_str(buffer, buflen, &used, elem_str); + if (err) + return err; + *buf_used = used; + + return 0; +} + +/* + * Read a buffer and create the configuration and feature + * descriptors to load into the cscfg system + */ +int cscfg_file_read_buffer(const u8 *buffer, const int buflen, + struct cscfg_fs_load_descs *desc_arrays) +{ + struct cscfg_file_header hdr; + int used = 0, err, i; + + /* read in the file header */ + err = cscfg_file_read_hdr(buffer, buflen, &used, &hdr); + if (err) + return err; + + /* allocate the memory for the descriptor pointer arrays */ + err = cscfg_file_alloc_desc_arrays(desc_arrays, hdr.nr_features); + if (err) + return err; + + /* read elements */ + + /* first element could be a config so check */ + err = cscfg_file_read_elem_config(buffer, buflen, &used, desc_arrays); + if (err) + return err; + + /* now read and populate all the feature descriptors */ + for (i = 0; i < hdr.nr_features; i++) { + err = cscfg_file_read_elem_feature(buffer, buflen, &used, desc_arrays, i); + if (err) + return err; + } + return used; +} + +int cscfg_file_read_buffer_first_name(const u8 *buffer, const int buflen, + const char **name) +{ + struct cscfg_file_header hdr; + struct cscfg_file_elem_str elem_str; + int used = 0, err = 0; + + *name = NULL; + + /* read in the file header */ + err = cscfg_file_read_hdr(buffer, buflen, &used, &hdr); + if (err) + return err; + + err = cscfg_file_read_elem_config_name(buffer, buflen, &used, &elem_str); + if (err) + return err; + + /* no config string - get first feature name */ + if (!elem_str.str_len) { + err = cscfg_file_read_elem_feat_name(buffer, buflen, &used, &elem_str); + if (err) + return err; + } + if (elem_str.str_len) + *name = elem_str.str; + return err; +} diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h new file mode 100644 index 000000000000..6c8c5af0a614 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -0,0 +1,118 @@ +/* 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_FILE_H +#define _CORESIGHT_CORESIGHT_CONFIG_FILE_H + +/* + * Structures to represent configuration descriptors in a memory buffer + * to serialise to and from files + * + * File structure - for loading a configuration + features + * from configfs. + * + * [cscfg_file_header] - mandatory + * [CONFIG_ELEM] - optional - only one permitted, + * [FEATURE_ELEM] * [cscfg_file_header.nr_features] + * - optional - file valid with config only. + * + * Invalid file if no config or features. + * + * + * File structure for [CONFIG_ELEM]: + * + * [cscfg_file_elem_header] - header length value to end of feature strings. + * [cscfg_file_elem_str] - name of the configuration + * [cscfg_file_elem_str] - description of configuration + * [u16 value - nr_presets] + * [u32 value - nr_total_params] + * [u16 value - nr_feat_refs] + * [u64 values] * (nr_presets * nr_total_params) + * [cscfg_file_elem_str] * nr_feat_refs + * + * Only one configuration per file. + * + * File structure for a [FEATURE_ELEM] + * + * [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 + * + * File structure for [PARAM_ELEM] + * + * [cscfg_file_elem_str] - parameter name. + * [u64 value: param_value] - initial value. + */ + +/* major element types - configurations and features */ + +#define CSCFG_FILE_ELEM_TYPE_FEAT 0x1 +#define CSCFG_FILE_ELEM_TYPE_CFG 0x2 + +#define CSCFG_FILE_MAGIC_VERSION 0xC5CF0001 + +#define CSCFG_FILE_U32_TO_REG_DESC_INFO(val32, p_desc) \ + { \ + p_desc->type = (val32 >> 24) & 0xFF; \ + p_desc->offset = (val32 >> 12) & 0xFFF; \ + p_desc->hw_info = val32 & 0xFFF; \ + } + +#define CSCFG_FILE_REG_DESC_INFO_TO_U32(val32, p_desc) \ + { \ + val32 = p_desc->hw_info & 0xFFF; \ + val32 |= ((p_desc->offset & 0xFFF) << 12); \ + val32 |= ((p_desc->type & 0xFF) << 24); \ + } + +/* binary attributes in configfs need a max size - declare a value for this. */ +#define CSCFG_FILE_MAXSIZE 16384 + +/* limit string sizes */ +#define CSCFG_FILE_STR_MAXSIZE 1024 + + +/** + * file header. + * + * @magic_version: magic number / version for file/buffer format. + * @length : total length of all data in the buffer. + * @nr_features : total number of features in the buffer. + */ +struct cscfg_file_header { + u32 magic_version; + u16 length; + u16 nr_features; +}; + +/** + * element header + * + * @elem_length: total length of this element + * @elem_type : type of this element - one of CSCFG_FILE_ELEM_TYPE.. defines. + */ +struct cscfg_file_elem_header { + u16 elem_length; + u8 elem_type; +}; + +/** + * string file element. + * + * @str_len: length of string buffer including 0 terminator + * @str : string buffer - 0 terminated. + */ +struct cscfg_file_elem_str { + u16 str_len; + char *str; +}; + +#endif /* _CORESIGHT_CORESIGHT_CONFIG_FILE_H */ diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 9bd44b940add..770986316bc2 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -150,6 +150,23 @@ struct cscfg_config_desc { struct config_group *fs_group; };
+/** + * Dynamically loaded descriptor arrays loaded via configfs. + * + * For builtin or module loaded configurations / features these are + * statically defined at compile time. For configfs we create the arrays + * dynamically so need a structure to handle this. + * + * @owner_info: associated owner info struct to add to load order list. + * @config_descs: array of config descriptor pointers. + * @feat_descs: array of feature descriptor pointers. + */ +struct cscfg_fs_load_descs { + void *owner_info; + struct cscfg_config_desc **config_descs; + struct cscfg_feature_desc **feat_descs; +}; + /** * config register instance - part of a loaded feature. * maps register values to csdev driver structures diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 9106ffab4833..6a6e33585be9 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -66,6 +66,7 @@ struct cscfg_registered_csdev { enum cscfg_load_owner_type { CSCFG_OWNER_PRELOAD, CSCFG_OWNER_MODULE, + CSCFG_OWNER_CONFIGFS, };
/**
Good morning Mike,
Please find below (and in upcoming emails) the rest or my comments for this set.
On Tue, Nov 30, 2021 at 10:00:55PM +0000, Mike Leach wrote:
Add in functionality to allow load via configfs.
define a binary file format and provide a reader for that format that will create and populate configuration and feature structures use by the driver infrastructure.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../coresight/coresight-config-file.c | 432 ++++++++++++++++++ .../coresight/coresight-config-file.h | 118 +++++ .../hwtracing/coresight/coresight-config.h | 17 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 569 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-config-file.c create mode 100644 drivers/hwtracing/coresight/coresight-config-file.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index b6c4a48140ec..5de2bb79f4ac 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ coresight-sysfs.o coresight-syscfg.o coresight-config.o \ coresight-cfg-preload.o coresight-cfg-afdo.o \
coresight-syscfg-configfs.o
coresight-syscfg-configfs.o coresight-config-file.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c new file mode 100644 index 000000000000..3fd001938324 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -0,0 +1,432 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include "coresight-config.h" +#include "coresight-config-file.h" +#include "coresight-syscfg.h"
+#define cscfg_extract_u64(val64) { \
- val64 = *(u64 *)(buffer + used); \
- used += sizeof(u64); \
- }
+#define cscfg_extract_u32(val32) { \
- val32 = *(u32 *)(buffer + used); \
- used += sizeof(u32); \
- }
+#define cscfg_extract_u16(val16) { \
- val16 = *(u16 *)(buffer + used); \
- used += sizeof(u16); \
- }
+#define cscfg_extract_u8(val8) { \
- val8 = *(buffer + used); \
- used++; \
- }
+static int cscfg_file_read_hdr(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_header *hdr)
+{
- /* file header always at the start of the buffer */
- int used = 0;
- if (buflen < sizeof(struct cscfg_file_header))
return -EINVAL;
- cscfg_extract_u32(hdr->magic_version);
- if (hdr->magic_version != CSCFG_FILE_MAGIC_VERSION)
return -EINVAL;
- cscfg_extract_u16(hdr->length);
- if (hdr->length > buflen)
return -EINVAL;
- cscfg_extract_u16(hdr->nr_features);
- *buf_used = used;
- return 0;
+}
+static int cscfg_file_read_elem_hdr(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_elem_header *elem_hdr)
+{
- int used = *buf_used;
- if ((buflen - used) < (sizeof(u16) + sizeof(u8)))
return -EINVAL;
- /* read length and check enough buffer remains for this element */
- elem_hdr->elem_length = *(u16 *)(buffer + used);
- if ((buflen - used) < elem_hdr->elem_length)
return -EINVAL;
- /* don't use extract fn as we update used _after_ the comparison */
- used += sizeof(u16);
- /* read type and validate */
- cscfg_extract_u8(elem_hdr->elem_type);
- if ((elem_hdr->elem_type < CSCFG_FILE_ELEM_TYPE_FEAT) ||
(elem_hdr->elem_type > CSCFG_FILE_ELEM_TYPE_CFG))
return -EINVAL;
- *buf_used = used;
- return 0;
+}
+static int cscfg_file_read_elem_str(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_elem_str *elem_str)
+{
- int used = *buf_used;
- if ((buflen - used) < sizeof(u16))
return -EINVAL;
- cscfg_extract_u16(elem_str->str_len);
- if ((buflen - used) < elem_str->str_len)
return -EINVAL;
- /* check for 0 termination */
- if (buffer[elem_str->str_len - 1] != 0)
return -EINVAL;
- elem_str->str = devm_kstrdup(cscfg_device(), (char *)buffer, GFP_KERNEL);
- used += elem_str->str_len;
- *buf_used = used;
- return 0;
+}
+static int cscfg_file_alloc_desc_arrays(struct cscfg_fs_load_descs *desc_arrays,
int nr_features)
+{
- /* arrays are 0 terminated - max of 1 config & nr_features features */
- desc_arrays->config_descs = devm_kcalloc(cscfg_device(), 2,
sizeof(struct cscfg_config_desc *),
GFP_KERNEL);
- if (!desc_arrays->config_descs)
return -ENOMEM;
- desc_arrays->feat_descs = devm_kcalloc(cscfg_device(), nr_features + 1,
sizeof(struct cscfg_feature_desc *),
GFP_KERNEL);
- if (!desc_arrays->feat_descs)
return -ENOMEM;
- return 0;
+}
+static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_fs_load_descs *desc_arrays)
+{
- struct cscfg_file_elem_header elem_hdr;
- struct cscfg_file_elem_str elem_str;
- struct cscfg_config_desc *config_desc;
- int used = *buf_used, nr_preset_vals, nr_preset_bytes, i;
- int err = 0;
- u64 *presets;
- /*
* read the header - if not config, then don't update buf_used
* pointer on return
*/
- err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr);
- if (err)
return err;
- if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_CFG)
return 0;
- /* we have a config - allocate the descriptor */
- config_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_config_desc),
GFP_KERNEL);
- if (!config_desc)
return -ENOMEM;
- /* read the name string */
- err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);
- if (err)
return err;
- config_desc->name = elem_str.str;
- /* read the description string */
- err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);
- if (err)
return err;
- config_desc->description = elem_str.str;
- /* read in some values */
- if ((buflen - used) < sizeof(u64))
return -EINVAL;
- cscfg_extract_u16(config_desc->nr_presets);
- cscfg_extract_u32(config_desc->nr_total_params);
- cscfg_extract_u16(config_desc->nr_feat_refs);
- /* read the array of 64bit presets if present */
- nr_preset_vals = config_desc->nr_total_params * config_desc->nr_presets;
- if (nr_preset_vals) {
presets = devm_kcalloc(cscfg_device(), nr_preset_vals,
sizeof(u64), GFP_KERNEL);
if (!presets)
return -ENOMEM;
nr_preset_bytes = sizeof(u64) * nr_preset_vals;
if ((buflen - used) < nr_preset_bytes)
return -EINVAL;
memcpy(presets, (buffer + used), nr_preset_bytes);
config_desc->presets = presets;
used += nr_preset_bytes;
- }
- /* read the array of feature names referenced by the config */
- if (config_desc->nr_feat_refs) {
config_desc->feat_ref_names = devm_kcalloc(cscfg_device(),
config_desc->nr_feat_refs,
sizeof(char *),
GFP_KERNEL);
if (!config_desc->feat_ref_names)
return -ENOMEM;
for (i = 0; i < config_desc->nr_feat_refs; i++) {
err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);
if (err)
return err;
config_desc->feat_ref_names[i] = elem_str.str;
}
- }
- desc_arrays->config_descs[0] = config_desc;
- *buf_used = used;
- return 0;
+}
+/* just read the config name - if there is a config at this position */ +static int cscfg_file_read_elem_config_name(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_elem_str *elem_str)
+{
- struct cscfg_file_elem_header elem_hdr;
- int used = *buf_used;
- int err;
- elem_str->str_len = 0;
- /*
* read the header - if not config, then don't update buf_used
* pointer on return
*/
- err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr);
- if (err)
return err;
- if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_CFG)
return 0;
- /* read the name string */
- err = cscfg_file_read_elem_str(buffer, buflen, &used, elem_str);
- if (err)
return err;
- *buf_used = used;
- return 0;
+}
+static int cscfg_file_read_elem_param(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_parameter_desc *param_desc)
+{
- struct cscfg_file_elem_str elem_str;
- int err = 0, used = *buf_used;
- /* parameter name */
- err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);
- if (err)
return err;
- param_desc->name = elem_str.str;
- /* parameter value */
- if ((buflen - used) < sizeof(u64))
return -EINVAL;
- cscfg_extract_u64(param_desc->value);
- *buf_used = used;
- return err;
+}
+static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_fs_load_descs *desc_arrays,
const int feat_idx)
+{
- struct cscfg_file_elem_header elem_hdr;
- struct cscfg_file_elem_str elem_str;
- struct cscfg_feature_desc *feat_desc;
- struct cscfg_regval_desc *p_reg_desc;
- int used = *buf_used, err, i, nr_regs_bytes;
- u32 val32;
- /* allocate the feature descriptor object */
- feat_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_feature_desc),
GFP_KERNEL);
- if (!feat_desc)
return -ENOMEM;
- /* read and check the element header */
- err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr);
- if (err)
return err;
- if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_FEAT)
return -EINVAL;
- /* read the feature name */
- err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);
- if (err)
return err;
- feat_desc->name = elem_str.str;
- /* read the description string */
- err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);
- if (err)
return err;
- feat_desc->description = elem_str.str;
- /*
* read in some values
* [u32 value: match_flags]
* [u16 value: nr_regs] - number of registers.
* [u16 value: nr_params] - number of parameters.
*/
- cscfg_extract_u32(feat_desc->match_flags);
- cscfg_extract_u16(feat_desc->nr_regs);
- cscfg_extract_u16(feat_desc->nr_params);
- /* register descriptors - 32 bit + 64 bit value */
- if (feat_desc->nr_regs) {
nr_regs_bytes = ((sizeof(u32) + sizeof(u64)) * feat_desc->nr_regs);
if ((buflen - used) < nr_regs_bytes)
return -EINVAL;
feat_desc->regs_desc = devm_kcalloc(cscfg_device(),
feat_desc->nr_regs,
sizeof(struct cscfg_regval_desc),
GFP_KERNEL);
if (!feat_desc->regs_desc)
return -ENOMEM;
for (i = 0; i < feat_desc->nr_regs; i++) {
cscfg_extract_u32(val32);
p_reg_desc = (struct cscfg_regval_desc *)&feat_desc->regs_desc[i];
CSCFG_FILE_U32_TO_REG_DESC_INFO(val32, p_reg_desc);
cscfg_extract_u64(feat_desc->regs_desc[i].val64);
}
- }
- /* parameter descriptors - string + 64 bit value */
- if (feat_desc->nr_params) {
feat_desc->params_desc = devm_kcalloc(cscfg_device(),
feat_desc->nr_params,
sizeof(struct cscfg_parameter_desc),
GFP_KERNEL);
if (!feat_desc->params_desc)
return -ENOMEM;
for (i = 0; i < feat_desc->nr_params; i++) {
err = cscfg_file_read_elem_param(buffer, buflen, &used,
&feat_desc->params_desc[i]);
if (err)
return err;
}
- }
- desc_arrays->feat_descs[feat_idx] = feat_desc;
- *buf_used = used;
- return 0;
+}
+/* just read the feature name - if there is a feature at this position */ +static int cscfg_file_read_elem_feat_name(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_elem_str *elem_str)
+{
- struct cscfg_file_elem_header elem_hdr;
- int used = *buf_used;
- int err;
- elem_str->str_len = 0;
- /*
* read the header - if not config, then don't update buf_used
* pointer on return
*/
- err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr);
- if (err)
return err;
- if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_FEAT)
return -EINVAL;
- /* read the feature name */
- err = cscfg_file_read_elem_str(buffer, buflen, &used, elem_str);
- if (err)
return err;
- *buf_used = used;
- return 0;
+}
+/*
- Read a buffer and create the configuration and feature
- descriptors to load into the cscfg system
- */
+int cscfg_file_read_buffer(const u8 *buffer, const int buflen,
struct cscfg_fs_load_descs *desc_arrays)
+{
- struct cscfg_file_header hdr;
- int used = 0, err, i;
- /* read in the file header */
- err = cscfg_file_read_hdr(buffer, buflen, &used, &hdr);
- if (err)
return err;
- /* allocate the memory for the descriptor pointer arrays */
- err = cscfg_file_alloc_desc_arrays(desc_arrays, hdr.nr_features);
- if (err)
return err;
- /* read elements */
- /* first element could be a config so check */
- err = cscfg_file_read_elem_config(buffer, buflen, &used, desc_arrays);
- if (err)
return err;
- /* now read and populate all the feature descriptors */
- for (i = 0; i < hdr.nr_features; i++) {
err = cscfg_file_read_elem_feature(buffer, buflen, &used, desc_arrays, i);
if (err)
return err;
- }
- return used;
+}
+int cscfg_file_read_buffer_first_name(const u8 *buffer, const int buflen,
const char **name)
+{
- struct cscfg_file_header hdr;
- struct cscfg_file_elem_str elem_str;
- int used = 0, err = 0;
- *name = NULL;
- /* read in the file header */
- err = cscfg_file_read_hdr(buffer, buflen, &used, &hdr);
- if (err)
return err;
- err = cscfg_file_read_elem_config_name(buffer, buflen, &used, &elem_str);
- if (err)
return err;
- /* no config string - get first feature name */
- if (!elem_str.str_len) {
err = cscfg_file_read_elem_feat_name(buffer, buflen, &used, &elem_str);
if (err)
return err;
- }
- if (elem_str.str_len)
*name = elem_str.str;
- return err;
+}
I haven't found a problem or a bug in the above.
diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h new file mode 100644 index 000000000000..6c8c5af0a614 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -0,0 +1,118 @@ +/* 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_FILE_H +#define _CORESIGHT_CORESIGHT_CONFIG_FILE_H
+/*
- Structures to represent configuration descriptors in a memory buffer
- to serialise to and from files
- File structure - for loading a configuration + features
- from configfs.
- [cscfg_file_header] - mandatory
- [CONFIG_ELEM] - optional - only one permitted,
- [FEATURE_ELEM] * [cscfg_file_header.nr_features]
- optional - file valid with config only.
- Invalid file if no config or features.
- File structure for [CONFIG_ELEM]:
- [cscfg_file_elem_header] - header length value to end of feature strings.
- [cscfg_file_elem_str] - name of the configuration
- [cscfg_file_elem_str] - description of configuration
- [u16 value - nr_presets]
- [u32 value - nr_total_params]
- [u16 value - nr_feat_refs]
- [u64 values] * (nr_presets * nr_total_params)
- [cscfg_file_elem_str] * nr_feat_refs
- Only one configuration per file.
- File structure for a [FEATURE_ELEM]
- [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
- File structure for [PARAM_ELEM]
- [cscfg_file_elem_str] - parameter name.
- [u64 value: param_value] - initial value.
- */
The above is really really dry, even for someone that is acquainted with the CS subsystem and the complex configuration feature. I doubt someone looking to start with the subsystem will be able to understand what is going on.
+/* major element types - configurations and features */
+#define CSCFG_FILE_ELEM_TYPE_FEAT 0x1 +#define CSCFG_FILE_ELEM_TYPE_CFG 0x2
+#define CSCFG_FILE_MAGIC_VERSION 0xC5CF0001
I like that magic number.
+#define CSCFG_FILE_U32_TO_REG_DESC_INFO(val32, p_desc) \
- { \
- p_desc->type = (val32 >> 24) & 0xFF; \
- p_desc->offset = (val32 >> 12) & 0xFFF; \
- p_desc->hw_info = val32 & 0xFFF; \
- }
+#define CSCFG_FILE_REG_DESC_INFO_TO_U32(val32, p_desc) \
- { \
- val32 = p_desc->hw_info & 0xFFF; \
- val32 |= ((p_desc->offset & 0xFFF) << 12); \
- val32 |= ((p_desc->type & 0xFF) << 24); \
- }
+/* binary attributes in configfs need a max size - declare a value for this. */ +#define CSCFG_FILE_MAXSIZE 16384
+/* limit string sizes */ +#define CSCFG_FILE_STR_MAXSIZE 1024
Extra newline.
+/**
- file header.
- @magic_version: magic number / version for file/buffer format.
- @length : total length of all data in the buffer.
- @nr_features : total number of features in the buffer.
- */
+struct cscfg_file_header {
- u32 magic_version;
- u16 length;
- u16 nr_features;
+};
+/**
- element header
- @elem_length: total length of this element
- @elem_type : type of this element - one of CSCFG_FILE_ELEM_TYPE.. defines.
- */
+struct cscfg_file_elem_header {
- u16 elem_length;
- u8 elem_type;
+};
+/**
- string file element.
- @str_len: length of string buffer including 0 terminator
- @str : string buffer - 0 terminated.
- */
+struct cscfg_file_elem_str {
- u16 str_len;
- char *str;
+};
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_FILE_H */ diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 9bd44b940add..770986316bc2 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -150,6 +150,23 @@ struct cscfg_config_desc { struct config_group *fs_group; }; +/**
- Dynamically loaded descriptor arrays loaded via configfs.
- For builtin or module loaded configurations / features these are
- statically defined at compile time. For configfs we create the arrays
- dynamically so need a structure to handle this.
- @owner_info: associated owner info struct to add to load order list.
- @config_descs: array of config descriptor pointers.
- @feat_descs: array of feature descriptor pointers.
- */
+struct cscfg_fs_load_descs {
- void *owner_info;
- struct cscfg_config_desc **config_descs;
- struct cscfg_feature_desc **feat_descs;
+};
/**
- config register instance - part of a loaded feature.
maps register values to csdev driver structures
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 9106ffab4833..6a6e33585be9 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -66,6 +66,7 @@ struct cscfg_registered_csdev { enum cscfg_load_owner_type { CSCFG_OWNER_PRELOAD, CSCFG_OWNER_MODULE,
- CSCFG_OWNER_CONFIGFS,
Other than the above comments this patch works.
}; /** -- 2.17.1
Hi Mathieu,
On Fri, 28 Jan 2022 at 18:08, Mathieu Poirier mathieu.poirier@linaro.org wrote:
Good morning Mike,
Please find below (and in upcoming emails) the rest or my comments for this set.
On Tue, Nov 30, 2021 at 10:00:55PM +0000, Mike Leach wrote:
Add in functionality to allow load via configfs.
define a binary file format and provide a reader for that format that will create and populate configuration and feature structures use by the driver infrastructure.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../coresight/coresight-config-file.c | 432 ++++++++++++++++++ .../coresight/coresight-config-file.h | 118 +++++ .../hwtracing/coresight/coresight-config.h | 17 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 569 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-config-file.c create mode 100644 drivers/hwtracing/coresight/coresight-config-file.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index b6c4a48140ec..5de2bb79f4ac 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ coresight-sysfs.o coresight-syscfg.o coresight-config.o \ coresight-cfg-preload.o coresight-cfg-afdo.o \
coresight-syscfg-configfs.o
coresight-syscfg-configfs.o coresight-config-file.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c new file mode 100644 index 000000000000..3fd001938324 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -0,0 +1,432 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include "coresight-config.h" +#include "coresight-config-file.h" +#include "coresight-syscfg.h"
+#define cscfg_extract_u64(val64) { \
val64 = *(u64 *)(buffer + used); \
used += sizeof(u64); \
}
+#define cscfg_extract_u32(val32) { \
val32 = *(u32 *)(buffer + used); \
used += sizeof(u32); \
}
+#define cscfg_extract_u16(val16) { \
val16 = *(u16 *)(buffer + used); \
used += sizeof(u16); \
}
+#define cscfg_extract_u8(val8) { \
val8 = *(buffer + used); \
used++; \
}
+static int cscfg_file_read_hdr(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_header *hdr)
+{
/* file header always at the start of the buffer */
int used = 0;
if (buflen < sizeof(struct cscfg_file_header))
return -EINVAL;
cscfg_extract_u32(hdr->magic_version);
if (hdr->magic_version != CSCFG_FILE_MAGIC_VERSION)
return -EINVAL;
cscfg_extract_u16(hdr->length);
if (hdr->length > buflen)
return -EINVAL;
cscfg_extract_u16(hdr->nr_features);
*buf_used = used;
return 0;
+}
+static int cscfg_file_read_elem_hdr(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_elem_header *elem_hdr)
+{
int used = *buf_used;
if ((buflen - used) < (sizeof(u16) + sizeof(u8)))
return -EINVAL;
/* read length and check enough buffer remains for this element */
elem_hdr->elem_length = *(u16 *)(buffer + used);
if ((buflen - used) < elem_hdr->elem_length)
return -EINVAL;
/* don't use extract fn as we update used _after_ the comparison */
used += sizeof(u16);
/* read type and validate */
cscfg_extract_u8(elem_hdr->elem_type);
if ((elem_hdr->elem_type < CSCFG_FILE_ELEM_TYPE_FEAT) ||
(elem_hdr->elem_type > CSCFG_FILE_ELEM_TYPE_CFG))
return -EINVAL;
*buf_used = used;
return 0;
+}
+static int cscfg_file_read_elem_str(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_elem_str *elem_str)
+{
int used = *buf_used;
if ((buflen - used) < sizeof(u16))
return -EINVAL;
cscfg_extract_u16(elem_str->str_len);
if ((buflen - used) < elem_str->str_len)
return -EINVAL;
/* check for 0 termination */
if (buffer[elem_str->str_len - 1] != 0)
return -EINVAL;
elem_str->str = devm_kstrdup(cscfg_device(), (char *)buffer, GFP_KERNEL);
used += elem_str->str_len;
*buf_used = used;
return 0;
+}
+static int cscfg_file_alloc_desc_arrays(struct cscfg_fs_load_descs *desc_arrays,
int nr_features)
+{
/* arrays are 0 terminated - max of 1 config & nr_features features */
desc_arrays->config_descs = devm_kcalloc(cscfg_device(), 2,
sizeof(struct cscfg_config_desc *),
GFP_KERNEL);
if (!desc_arrays->config_descs)
return -ENOMEM;
desc_arrays->feat_descs = devm_kcalloc(cscfg_device(), nr_features + 1,
sizeof(struct cscfg_feature_desc *),
GFP_KERNEL);
if (!desc_arrays->feat_descs)
return -ENOMEM;
return 0;
+}
+static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_fs_load_descs *desc_arrays)
+{
struct cscfg_file_elem_header elem_hdr;
struct cscfg_file_elem_str elem_str;
struct cscfg_config_desc *config_desc;
int used = *buf_used, nr_preset_vals, nr_preset_bytes, i;
int err = 0;
u64 *presets;
/*
* read the header - if not config, then don't update buf_used
* pointer on return
*/
err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr);
if (err)
return err;
if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_CFG)
return 0;
/* we have a config - allocate the descriptor */
config_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_config_desc),
GFP_KERNEL);
if (!config_desc)
return -ENOMEM;
/* read the name string */
err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);
if (err)
return err;
config_desc->name = elem_str.str;
/* read the description string */
err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);
if (err)
return err;
config_desc->description = elem_str.str;
/* read in some values */
if ((buflen - used) < sizeof(u64))
return -EINVAL;
cscfg_extract_u16(config_desc->nr_presets);
cscfg_extract_u32(config_desc->nr_total_params);
cscfg_extract_u16(config_desc->nr_feat_refs);
/* read the array of 64bit presets if present */
nr_preset_vals = config_desc->nr_total_params * config_desc->nr_presets;
if (nr_preset_vals) {
presets = devm_kcalloc(cscfg_device(), nr_preset_vals,
sizeof(u64), GFP_KERNEL);
if (!presets)
return -ENOMEM;
nr_preset_bytes = sizeof(u64) * nr_preset_vals;
if ((buflen - used) < nr_preset_bytes)
return -EINVAL;
memcpy(presets, (buffer + used), nr_preset_bytes);
config_desc->presets = presets;
used += nr_preset_bytes;
}
/* read the array of feature names referenced by the config */
if (config_desc->nr_feat_refs) {
config_desc->feat_ref_names = devm_kcalloc(cscfg_device(),
config_desc->nr_feat_refs,
sizeof(char *),
GFP_KERNEL);
if (!config_desc->feat_ref_names)
return -ENOMEM;
for (i = 0; i < config_desc->nr_feat_refs; i++) {
err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);
if (err)
return err;
config_desc->feat_ref_names[i] = elem_str.str;
}
}
desc_arrays->config_descs[0] = config_desc;
*buf_used = used;
return 0;
+}
+/* just read the config name - if there is a config at this position */ +static int cscfg_file_read_elem_config_name(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_elem_str *elem_str)
+{
struct cscfg_file_elem_header elem_hdr;
int used = *buf_used;
int err;
elem_str->str_len = 0;
/*
* read the header - if not config, then don't update buf_used
* pointer on return
*/
err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr);
if (err)
return err;
if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_CFG)
return 0;
/* read the name string */
err = cscfg_file_read_elem_str(buffer, buflen, &used, elem_str);
if (err)
return err;
*buf_used = used;
return 0;
+}
+static int cscfg_file_read_elem_param(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_parameter_desc *param_desc)
+{
struct cscfg_file_elem_str elem_str;
int err = 0, used = *buf_used;
/* parameter name */
err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);
if (err)
return err;
param_desc->name = elem_str.str;
/* parameter value */
if ((buflen - used) < sizeof(u64))
return -EINVAL;
cscfg_extract_u64(param_desc->value);
*buf_used = used;
return err;
+}
+static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_fs_load_descs *desc_arrays,
const int feat_idx)
+{
struct cscfg_file_elem_header elem_hdr;
struct cscfg_file_elem_str elem_str;
struct cscfg_feature_desc *feat_desc;
struct cscfg_regval_desc *p_reg_desc;
int used = *buf_used, err, i, nr_regs_bytes;
u32 val32;
/* allocate the feature descriptor object */
feat_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_feature_desc),
GFP_KERNEL);
if (!feat_desc)
return -ENOMEM;
/* read and check the element header */
err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr);
if (err)
return err;
if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_FEAT)
return -EINVAL;
/* read the feature name */
err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);
if (err)
return err;
feat_desc->name = elem_str.str;
/* read the description string */
err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);
if (err)
return err;
feat_desc->description = elem_str.str;
/*
* read in some values
* [u32 value: match_flags]
* [u16 value: nr_regs] - number of registers.
* [u16 value: nr_params] - number of parameters.
*/
cscfg_extract_u32(feat_desc->match_flags);
cscfg_extract_u16(feat_desc->nr_regs);
cscfg_extract_u16(feat_desc->nr_params);
/* register descriptors - 32 bit + 64 bit value */
if (feat_desc->nr_regs) {
nr_regs_bytes = ((sizeof(u32) + sizeof(u64)) * feat_desc->nr_regs);
if ((buflen - used) < nr_regs_bytes)
return -EINVAL;
feat_desc->regs_desc = devm_kcalloc(cscfg_device(),
feat_desc->nr_regs,
sizeof(struct cscfg_regval_desc),
GFP_KERNEL);
if (!feat_desc->regs_desc)
return -ENOMEM;
for (i = 0; i < feat_desc->nr_regs; i++) {
cscfg_extract_u32(val32);
p_reg_desc = (struct cscfg_regval_desc *)&feat_desc->regs_desc[i];
CSCFG_FILE_U32_TO_REG_DESC_INFO(val32, p_reg_desc);
cscfg_extract_u64(feat_desc->regs_desc[i].val64);
}
}
/* parameter descriptors - string + 64 bit value */
if (feat_desc->nr_params) {
feat_desc->params_desc = devm_kcalloc(cscfg_device(),
feat_desc->nr_params,
sizeof(struct cscfg_parameter_desc),
GFP_KERNEL);
if (!feat_desc->params_desc)
return -ENOMEM;
for (i = 0; i < feat_desc->nr_params; i++) {
err = cscfg_file_read_elem_param(buffer, buflen, &used,
&feat_desc->params_desc[i]);
if (err)
return err;
}
}
desc_arrays->feat_descs[feat_idx] = feat_desc;
*buf_used = used;
return 0;
+}
+/* just read the feature name - if there is a feature at this position */ +static int cscfg_file_read_elem_feat_name(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_elem_str *elem_str)
+{
struct cscfg_file_elem_header elem_hdr;
int used = *buf_used;
int err;
elem_str->str_len = 0;
/*
* read the header - if not config, then don't update buf_used
* pointer on return
*/
err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr);
if (err)
return err;
if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_FEAT)
return -EINVAL;
/* read the feature name */
err = cscfg_file_read_elem_str(buffer, buflen, &used, elem_str);
if (err)
return err;
*buf_used = used;
return 0;
+}
+/*
- Read a buffer and create the configuration and feature
- descriptors to load into the cscfg system
- */
+int cscfg_file_read_buffer(const u8 *buffer, const int buflen,
struct cscfg_fs_load_descs *desc_arrays)
+{
struct cscfg_file_header hdr;
int used = 0, err, i;
/* read in the file header */
err = cscfg_file_read_hdr(buffer, buflen, &used, &hdr);
if (err)
return err;
/* allocate the memory for the descriptor pointer arrays */
err = cscfg_file_alloc_desc_arrays(desc_arrays, hdr.nr_features);
if (err)
return err;
/* read elements */
/* first element could be a config so check */
err = cscfg_file_read_elem_config(buffer, buflen, &used, desc_arrays);
if (err)
return err;
/* now read and populate all the feature descriptors */
for (i = 0; i < hdr.nr_features; i++) {
err = cscfg_file_read_elem_feature(buffer, buflen, &used, desc_arrays, i);
if (err)
return err;
}
return used;
+}
+int cscfg_file_read_buffer_first_name(const u8 *buffer, const int buflen,
const char **name)
+{
struct cscfg_file_header hdr;
struct cscfg_file_elem_str elem_str;
int used = 0, err = 0;
*name = NULL;
/* read in the file header */
err = cscfg_file_read_hdr(buffer, buflen, &used, &hdr);
if (err)
return err;
err = cscfg_file_read_elem_config_name(buffer, buflen, &used, &elem_str);
if (err)
return err;
/* no config string - get first feature name */
if (!elem_str.str_len) {
err = cscfg_file_read_elem_feat_name(buffer, buflen, &used, &elem_str);
if (err)
return err;
}
if (elem_str.str_len)
*name = elem_str.str;
return err;
+}
I haven't found a problem or a bug in the above.
diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h new file mode 100644 index 000000000000..6c8c5af0a614 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -0,0 +1,118 @@ +/* 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_FILE_H +#define _CORESIGHT_CORESIGHT_CONFIG_FILE_H
+/*
- Structures to represent configuration descriptors in a memory buffer
- to serialise to and from files
- File structure - for loading a configuration + features
- from configfs.
- [cscfg_file_header] - mandatory
- [CONFIG_ELEM] - optional - only one permitted,
- [FEATURE_ELEM] * [cscfg_file_header.nr_features]
- optional - file valid with config only.
- Invalid file if no config or features.
- File structure for [CONFIG_ELEM]:
- [cscfg_file_elem_header] - header length value to end of feature strings.
- [cscfg_file_elem_str] - name of the configuration
- [cscfg_file_elem_str] - description of configuration
- [u16 value - nr_presets]
- [u32 value - nr_total_params]
- [u16 value - nr_feat_refs]
- [u64 values] * (nr_presets * nr_total_params)
- [cscfg_file_elem_str] * nr_feat_refs
- Only one configuration per file.
- File structure for a [FEATURE_ELEM]
- [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
- File structure for [PARAM_ELEM]
- [cscfg_file_elem_str] - parameter name.
- [u64 value: param_value] - initial value.
- */
The above is really really dry, even for someone that is acquainted with the CS subsystem and the complex configuration feature. I doubt someone looking to start with the subsystem will be able to understand what is going on.
I am hoping that the additional documentation in patch 6 should provide additional exaplanation, as the exaplantion appears alongside the details of how the coresight config system works.
+/* major element types - configurations and features */
+#define CSCFG_FILE_ELEM_TYPE_FEAT 0x1 +#define CSCFG_FILE_ELEM_TYPE_CFG 0x2
+#define CSCFG_FILE_MAGIC_VERSION 0xC5CF0001
I like that magic number.
+#define CSCFG_FILE_U32_TO_REG_DESC_INFO(val32, p_desc) \
{ \
p_desc->type = (val32 >> 24) & 0xFF; \
p_desc->offset = (val32 >> 12) & 0xFFF; \
p_desc->hw_info = val32 & 0xFFF; \
}
+#define CSCFG_FILE_REG_DESC_INFO_TO_U32(val32, p_desc) \
{ \
val32 = p_desc->hw_info & 0xFFF; \
val32 |= ((p_desc->offset & 0xFFF) << 12); \
val32 |= ((p_desc->type & 0xFF) << 24); \
}
+/* binary attributes in configfs need a max size - declare a value for this. */ +#define CSCFG_FILE_MAXSIZE 16384
+/* limit string sizes */ +#define CSCFG_FILE_STR_MAXSIZE 1024
Extra newline.
will fix
Thanks for the review.
Mike
+/**
- file header.
- @magic_version: magic number / version for file/buffer format.
- @length : total length of all data in the buffer.
- @nr_features : total number of features in the buffer.
- */
+struct cscfg_file_header {
u32 magic_version;
u16 length;
u16 nr_features;
+};
+/**
- element header
- @elem_length: total length of this element
- @elem_type : type of this element - one of CSCFG_FILE_ELEM_TYPE.. defines.
- */
+struct cscfg_file_elem_header {
u16 elem_length;
u8 elem_type;
+};
+/**
- string file element.
- @str_len: length of string buffer including 0 terminator
- @str : string buffer - 0 terminated.
- */
+struct cscfg_file_elem_str {
u16 str_len;
char *str;
+};
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_FILE_H */ diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 9bd44b940add..770986316bc2 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -150,6 +150,23 @@ struct cscfg_config_desc { struct config_group *fs_group; };
+/**
- Dynamically loaded descriptor arrays loaded via configfs.
- For builtin or module loaded configurations / features these are
- statically defined at compile time. For configfs we create the arrays
- dynamically so need a structure to handle this.
- @owner_info: associated owner info struct to add to load order list.
- @config_descs: array of config descriptor pointers.
- @feat_descs: array of feature descriptor pointers.
- */
+struct cscfg_fs_load_descs {
void *owner_info;
struct cscfg_config_desc **config_descs;
struct cscfg_feature_desc **feat_descs;
+};
/**
- config register instance - part of a loaded feature.
maps register values to csdev driver structures
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 9106ffab4833..6a6e33585be9 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -66,6 +66,7 @@ struct cscfg_registered_csdev { enum cscfg_load_owner_type { CSCFG_OWNER_PRELOAD, CSCFG_OWNER_MODULE,
CSCFG_OWNER_CONFIGFS,
Other than the above comments this patch works.
};
/**
2.17.1
Add in functionality and binary attribute to load configurations as binary data.
Reads the incoming attribute, which must be formatted correctly as defined in the file reader code - and will create a configuration and/or features and load them into the system.
These will then appear in configfs ready for use.
Unload functionality is also provided.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../coresight/coresight-config-file.h | 7 + .../coresight/coresight-syscfg-configfs.c | 148 +++++++++++++++++- .../coresight/coresight-syscfg-configfs.h | 8 + .../hwtracing/coresight/coresight-syscfg.c | 36 +++++ .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 193 insertions(+), 7 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h index 6c8c5af0a614..03899f7d94c9 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.h +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -115,4 +115,11 @@ struct cscfg_file_elem_str { char *str; };
+/* kernel configfs needs to read the incoming file buffers to load. */ +int cscfg_file_read_buffer(const u8 *buffer, const int buflen, + struct cscfg_fs_load_descs *desc_arrays); +/* to unload we just need the first name - config or first feature */ +int cscfg_file_read_buffer_first_name(const u8 *buffer, const int buflen, + const char **name); + #endif /* _CORESIGHT_CORESIGHT_CONFIG_FILE_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c index 433ede94dd63..50abdb5aa6b6 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -7,6 +7,7 @@ #include <linux/configfs.h>
#include "coresight-config.h" +#include "coresight-config-file.h" #include "coresight-syscfg-configfs.h"
/* create a default ci_type. */ @@ -380,14 +381,147 @@ static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc return &feat_view->group; }
+/* Attributes in configfs that allow load and unload of configuration binary files */ + +/* load "buffer" as a configuration binary file */ +static ssize_t cscfg_cfg_load_write(struct config_item *item, const void *buffer, size_t size) +{ + struct cscfg_fs_configs_grp *configs_grp; + struct cscfg_fs_load_descs *load_descs = 0; + struct cscfg_load_owner_info *owner_info = 0; + int err = 0; + const char *name; + + configs_grp = container_of(to_config_group(item), struct cscfg_fs_configs_grp, group); + if (size > CSCFG_FILE_MAXSIZE) { + scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN, + "Load error: Input file too large.\n"); + return -EINVAL; + } + + load_descs = kzalloc(sizeof(struct cscfg_fs_load_descs), GFP_KERNEL); + owner_info = kzalloc(sizeof(struct cscfg_load_owner_info), GFP_KERNEL); + if (!load_descs || !owner_info) { + err = -ENOMEM; + goto exit_memfree; + } + + load_descs->owner_info = owner_info; + owner_info->owner_handle = load_descs; + owner_info->type = CSCFG_OWNER_CONFIGFS; + + err = cscfg_file_read_buffer(buffer, size, load_descs); + if (err) { + scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN, + "Load error: Failed to read input file.\n"); + goto exit_memfree; + } + + err = cscfg_load_config_sets(load_descs->config_descs, load_descs->feat_descs, owner_info); + if (err) { + scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN, + "Load error: Failed to load configuaration file.\n"); + goto exit_memfree; + } + + /* name of config if there is one, otherwise first feature */ + if (load_descs->config_descs[0]) + name = load_descs->config_descs[0]->name; + else + name = load_descs->feat_descs[0]->name; + scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN, + "OK: configuration file loaded (%s).\n", name); + + return size; + +exit_memfree: + kfree(load_descs); + kfree(owner_info); + return err; +} +CONFIGFS_BIN_ATTR_WO(cscfg_cfg_, load, NULL, CSCFG_FILE_MAXSIZE); + +/* read "buffer" and unload configuration */ +static ssize_t cscfg_cfg_unload_write(struct config_item *item, const void *buffer, size_t size) +{ + struct cscfg_fs_configs_grp *configs_grp; + struct cscfg_fs_load_descs *load_descs; + const char *name; + int err; + + configs_grp = container_of(to_config_group(item), struct cscfg_fs_configs_grp, group); + if (size > CSCFG_FILE_MAXSIZE) { + scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN, + "Unload error: Input file too large\n"); + return -EINVAL; + } + + err = cscfg_file_read_buffer_first_name(buffer, size, &name); + if (err) { + scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN, + "Unload error: Failed to read input file\n"); + return err; + } + + load_descs = cscfg_find_fs_owned_cfg_by_name(name); + if (!load_descs) { + scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN, + "Unload error: Failed to find configuration %s from input file\n", + name); + return err; + } + err = cscfg_unload_config_sets(load_descs->owner_info); + if (err) { + scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN, + "Unload error: Cannot unload configuration %s\n", + name); + return err; + } + + scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN, + "OK: configuration file unloaded (%s).\n", name); + + kfree((struct cscfg_load_owner_info *)load_descs->owner_info); + kfree(load_descs); + return size; +} +CONFIGFS_BIN_ATTR_WO(cscfg_cfg_, unload, NULL, CSCFG_FILE_MAXSIZE); + +/* show the status of the last load / unload operation */ +static ssize_t cscfg_cfg_last_load_status_show(struct config_item *item, char *page) +{ + struct cscfg_fs_configs_grp *configs_grp; + + configs_grp = container_of(to_config_group(item), struct cscfg_fs_configs_grp, group); + + return scnprintf(page, PAGE_SIZE, "%s\n", configs_grp->status); +} +CONFIGFS_ATTR_RO(cscfg_cfg_, last_load_status); + +static struct configfs_attribute *cscfg_config_configs_attrs[] = { + &cscfg_cfg_attr_last_load_status, + NULL, +}; + +static struct configfs_bin_attribute *cscfg_config_configfs_bin_attrs[] = { + &cscfg_cfg_attr_load, + &cscfg_cfg_attr_unload, + NULL, +}; + static struct config_item_type cscfg_configs_type = { .ct_owner = THIS_MODULE, + .ct_bin_attrs = cscfg_config_configfs_bin_attrs, + .ct_attrs = cscfg_config_configs_attrs, };
-static struct config_group cscfg_configs_grp = { - .cg_item = { - .ci_namebuf = "configurations", - .ci_type = &cscfg_configs_type, +/* group for configurations dir, with load, unload and status attribs */ +static struct cscfg_fs_configs_grp cscfg_configs_grp = { + .group = { + .cg_item = { + .ci_namebuf = "configurations", + .ci_type = &cscfg_configs_type, + }, }, };
@@ -400,7 +534,7 @@ int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc) new_group = cscfg_create_config_group(config_desc); if (IS_ERR(new_group)) return PTR_ERR(new_group); - err = configfs_register_group(&cscfg_configs_grp, new_group); + err = configfs_register_group(&cscfg_configs_grp.group, new_group); if (!err) config_desc->fs_group = new_group; return err; @@ -468,8 +602,8 @@ int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr) mutex_init(&subsys->su_mutex);
/* Add default groups to subsystem */ - config_group_init(&cscfg_configs_grp); - configfs_add_default_group(&cscfg_configs_grp, &subsys->su_group); + config_group_init(&cscfg_configs_grp.group); + configfs_add_default_group(&cscfg_configs_grp.group, &subsys->su_group);
config_group_init(&cscfg_features_grp); configfs_add_default_group(&cscfg_features_grp, &subsys->su_group); diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h index 373d84d43268..8d6900e8c1ea 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h @@ -11,6 +11,14 @@
#define CSCFG_FS_SUBSYS_NAME "cs-syscfg"
+#define CSCFG_FS_STATUS_STRLEN 256 + +/* container for configs group */ +struct cscfg_fs_configs_grp { + struct config_group group; + char status[CSCFG_FS_STATUS_STRLEN]; +}; + /* container for configuration view */ struct cscfg_fs_config { struct cscfg_config_desc *config_desc; diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 098fc34c4829..b5804cc2af9c 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -587,6 +587,42 @@ int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info) } EXPORT_SYMBOL_GPL(cscfg_unload_config_sets);
+/* find a configuration owned by configfs by name of config / first feature */ +struct cscfg_fs_load_descs *cscfg_find_fs_owned_cfg_by_name(const char *name) +{ + struct cscfg_load_owner_info *owner_info; + struct cscfg_fs_load_descs *fs_load_cfg = NULL; + struct cscfg_config_desc *config_desc; + struct cscfg_feature_desc *feat_desc; + + mutex_lock(&cscfg_mutex); + + /* search the load_owner list for CONFIGFS loaded types */ + list_for_each_entry(owner_info, &cscfg_mgr->load_order_list, item) { + /* if this is a config fs owned item, then try to match */ + if (owner_info->type == CSCFG_OWNER_CONFIGFS) { + fs_load_cfg = owner_info->owner_handle; + /* first try to match the name against the config if it exists */ + if (fs_load_cfg->config_descs[0]) { + config_desc = fs_load_cfg->config_descs[0]; + if (!strcmp(config_desc->name, name)) + goto exit_unlock; + /* no config - match against first feature name */ + } else { + feat_desc = fs_load_cfg->feat_descs[0]; + if (!strcmp(feat_desc->name, name)) + goto exit_unlock; + } + /* no match - move on */ + fs_load_cfg = NULL; + } + } + +exit_unlock: + mutex_unlock(&cscfg_mutex); + return fs_load_cfg; +} + /* Handle coresight device registration and add configs and features to devices */
/* iterate through config lists and load matching configs to device */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 6a6e33585be9..6bc29abe0650 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -95,6 +95,7 @@ int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc, int param_idx, u64 value); int cscfg_config_sysfs_activate(struct cscfg_config_desc *cfg_desc, bool activate); void cscfg_config_sysfs_set_preset(int preset); +struct cscfg_fs_load_descs *cscfg_find_fs_owned_cfg_by_name(const char *name);
/* syscfg manager external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
On Tue, Nov 30, 2021 at 10:00:56PM +0000, Mike Leach wrote:
Add in functionality and binary attribute to load configurations as binary data.
Reads the incoming attribute, which must be formatted correctly as defined in the file reader code - and will create a configuration and/or features and load them into the system.
These will then appear in configfs ready for use.
Unload functionality is also provided.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../coresight/coresight-config-file.h | 7 + .../coresight/coresight-syscfg-configfs.c | 148 +++++++++++++++++- .../coresight/coresight-syscfg-configfs.h | 8 + .../hwtracing/coresight/coresight-syscfg.c | 36 +++++ .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 193 insertions(+), 7 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h index 6c8c5af0a614..03899f7d94c9 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.h +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -115,4 +115,11 @@ struct cscfg_file_elem_str { char *str; }; +/* kernel configfs needs to read the incoming file buffers to load. */ +int cscfg_file_read_buffer(const u8 *buffer, const int buflen,
struct cscfg_fs_load_descs *desc_arrays);
+/* to unload we just need the first name - config or first feature */ +int cscfg_file_read_buffer_first_name(const u8 *buffer, const int buflen,
const char **name);
#endif /* _CORESIGHT_CORESIGHT_CONFIG_FILE_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c index 433ede94dd63..50abdb5aa6b6 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -7,6 +7,7 @@ #include <linux/configfs.h> #include "coresight-config.h" +#include "coresight-config-file.h" #include "coresight-syscfg-configfs.h" /* create a default ci_type. */ @@ -380,14 +381,147 @@ static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc return &feat_view->group; } +/* Attributes in configfs that allow load and unload of configuration binary files */
+/* load "buffer" as a configuration binary file */ +static ssize_t cscfg_cfg_load_write(struct config_item *item, const void *buffer, size_t size) +{
- struct cscfg_fs_configs_grp *configs_grp;
- struct cscfg_fs_load_descs *load_descs = 0;
- struct cscfg_load_owner_info *owner_info = 0;
- int err = 0;
- const char *name;
- configs_grp = container_of(to_config_group(item), struct cscfg_fs_configs_grp, group);
- if (size > CSCFG_FILE_MAXSIZE) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Load error: Input file too large.\n");
return -EINVAL;
- }
- load_descs = kzalloc(sizeof(struct cscfg_fs_load_descs), GFP_KERNEL);
- owner_info = kzalloc(sizeof(struct cscfg_load_owner_info), GFP_KERNEL);
- if (!load_descs || !owner_info) {
err = -ENOMEM;
goto exit_memfree;
- }
- load_descs->owner_info = owner_info;
- owner_info->owner_handle = load_descs;
- owner_info->type = CSCFG_OWNER_CONFIGFS;
- err = cscfg_file_read_buffer(buffer, size, load_descs);
- if (err) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Load error: Failed to read input file.\n");
goto exit_memfree;
- }
- err = cscfg_load_config_sets(load_descs->config_descs, load_descs->feat_descs, owner_info);
- if (err) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Load error: Failed to load configuaration file.\n");
goto exit_memfree;
- }
- /* name of config if there is one, otherwise first feature */
- if (load_descs->config_descs[0])
name = load_descs->config_descs[0]->name;
- else
name = load_descs->feat_descs[0]->name;
- scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"OK: configuration file loaded (%s).\n", name);
- return size;
+exit_memfree:
- kfree(load_descs);
- kfree(owner_info);
- return err;
+} +CONFIGFS_BIN_ATTR_WO(cscfg_cfg_, load, NULL, CSCFG_FILE_MAXSIZE);
+/* read "buffer" and unload configuration */ +static ssize_t cscfg_cfg_unload_write(struct config_item *item, const void *buffer, size_t size) +{
- struct cscfg_fs_configs_grp *configs_grp;
- struct cscfg_fs_load_descs *load_descs;
- const char *name;
- int err;
- configs_grp = container_of(to_config_group(item), struct cscfg_fs_configs_grp, group);
- if (size > CSCFG_FILE_MAXSIZE) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Unload error: Input file too large\n");
return -EINVAL;
- }
- err = cscfg_file_read_buffer_first_name(buffer, size, &name);
- if (err) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Unload error: Failed to read input file\n");
return err;
- }
- load_descs = cscfg_find_fs_owned_cfg_by_name(name);
- if (!load_descs) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Unload error: Failed to find configuration %s from input file\n",
name);
return err;
- }
- err = cscfg_unload_config_sets(load_descs->owner_info);
- if (err) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Unload error: Cannot unload configuration %s\n",
name);
return err;
- }
- scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"OK: configuration file unloaded (%s).\n", name);
- kfree((struct cscfg_load_owner_info *)load_descs->owner_info);
- kfree(load_descs);
- return size;
+} +CONFIGFS_BIN_ATTR_WO(cscfg_cfg_, unload, NULL, CSCFG_FILE_MAXSIZE);
+/* show the status of the last load / unload operation */ +static ssize_t cscfg_cfg_last_load_status_show(struct config_item *item, char *page) +{
- struct cscfg_fs_configs_grp *configs_grp;
- configs_grp = container_of(to_config_group(item), struct cscfg_fs_configs_grp, group);
- return scnprintf(page, PAGE_SIZE, "%s\n", configs_grp->status);
I am still very ambivalent about this status thing... Especially since it only reports on the last item that was loaded/unloaded.
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, last_load_status);
+static struct configfs_attribute *cscfg_config_configs_attrs[] = {
- &cscfg_cfg_attr_last_load_status,
- NULL,
+};
+static struct configfs_bin_attribute *cscfg_config_configfs_bin_attrs[] = {
- &cscfg_cfg_attr_load,
- &cscfg_cfg_attr_unload,
- NULL,
+};
static struct config_item_type cscfg_configs_type = { .ct_owner = THIS_MODULE,
- .ct_bin_attrs = cscfg_config_configfs_bin_attrs,
- .ct_attrs = cscfg_config_configs_attrs,
}; -static struct config_group cscfg_configs_grp = {
- .cg_item = {
.ci_namebuf = "configurations",
.ci_type = &cscfg_configs_type,
+/* group for configurations dir, with load, unload and status attribs */ +static struct cscfg_fs_configs_grp cscfg_configs_grp = {
- .group = {
.cg_item = {
.ci_namebuf = "configurations",
.ci_type = &cscfg_configs_type,
},},
}; @@ -400,7 +534,7 @@ int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc) new_group = cscfg_create_config_group(config_desc); if (IS_ERR(new_group)) return PTR_ERR(new_group);
- err = configfs_register_group(&cscfg_configs_grp, new_group);
- err = configfs_register_group(&cscfg_configs_grp.group, new_group); if (!err) config_desc->fs_group = new_group; return err;
@@ -468,8 +602,8 @@ int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr) mutex_init(&subsys->su_mutex); /* Add default groups to subsystem */
- config_group_init(&cscfg_configs_grp);
- configfs_add_default_group(&cscfg_configs_grp, &subsys->su_group);
- config_group_init(&cscfg_configs_grp.group);
- configfs_add_default_group(&cscfg_configs_grp.group, &subsys->su_group);
config_group_init(&cscfg_features_grp); configfs_add_default_group(&cscfg_features_grp, &subsys->su_group); diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h index 373d84d43268..8d6900e8c1ea 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h @@ -11,6 +11,14 @@ #define CSCFG_FS_SUBSYS_NAME "cs-syscfg" +#define CSCFG_FS_STATUS_STRLEN 256
+/* container for configs group */ +struct cscfg_fs_configs_grp {
- struct config_group group;
- char status[CSCFG_FS_STATUS_STRLEN];
+};
/* container for configuration view */ struct cscfg_fs_config { struct cscfg_config_desc *config_desc; diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 098fc34c4829..b5804cc2af9c 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -587,6 +587,42 @@ int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info) } EXPORT_SYMBOL_GPL(cscfg_unload_config_sets); +/* find a configuration owned by configfs by name of config / first feature */ +struct cscfg_fs_load_descs *cscfg_find_fs_owned_cfg_by_name(const char *name) +{
- struct cscfg_load_owner_info *owner_info;
- struct cscfg_fs_load_descs *fs_load_cfg = NULL;
- struct cscfg_config_desc *config_desc;
- struct cscfg_feature_desc *feat_desc;
- mutex_lock(&cscfg_mutex);
- /* search the load_owner list for CONFIGFS loaded types */
- list_for_each_entry(owner_info, &cscfg_mgr->load_order_list, item) {
/* if this is a config fs owned item, then try to match */
if (owner_info->type == CSCFG_OWNER_CONFIGFS) {
fs_load_cfg = owner_info->owner_handle;
/* first try to match the name against the config if it exists */
if (fs_load_cfg->config_descs[0]) {
config_desc = fs_load_cfg->config_descs[0];
if (!strcmp(config_desc->name, name))
goto exit_unlock;
/* no config - match against first feature name */
} else {
feat_desc = fs_load_cfg->feat_descs[0];
if (!strcmp(feat_desc->name, name))
goto exit_unlock;
}
/* no match - move on */
fs_load_cfg = NULL;
}
- }
+exit_unlock:
- mutex_unlock(&cscfg_mutex);
- return fs_load_cfg;
+}
/* Handle coresight device registration and add configs and features to devices */ /* iterate through config lists and load matching configs to device */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 6a6e33585be9..6bc29abe0650 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -95,6 +95,7 @@ int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc, int param_idx, u64 value); int cscfg_config_sysfs_activate(struct cscfg_config_desc *cfg_desc, bool activate); void cscfg_config_sysfs_set_preset(int preset); +struct cscfg_fs_load_descs *cscfg_find_fs_owned_cfg_by_name(const char *name); /* syscfg manager external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, -- 2.17.1
Hi Mathieu,
On Fri, 28 Jan 2022 at 18:17, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Tue, Nov 30, 2021 at 10:00:56PM +0000, Mike Leach wrote:
Add in functionality and binary attribute to load configurations as binary data.
Reads the incoming attribute, which must be formatted correctly as defined in the file reader code - and will create a configuration and/or features and load them into the system.
These will then appear in configfs ready for use.
Unload functionality is also provided.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../coresight/coresight-config-file.h | 7 + .../coresight/coresight-syscfg-configfs.c | 148 +++++++++++++++++- .../coresight/coresight-syscfg-configfs.h | 8 + .../hwtracing/coresight/coresight-syscfg.c | 36 +++++ .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 193 insertions(+), 7 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h index 6c8c5af0a614..03899f7d94c9 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.h +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -115,4 +115,11 @@ struct cscfg_file_elem_str { char *str; };
+/* kernel configfs needs to read the incoming file buffers to load. */ +int cscfg_file_read_buffer(const u8 *buffer, const int buflen,
struct cscfg_fs_load_descs *desc_arrays);
+/* to unload we just need the first name - config or first feature */ +int cscfg_file_read_buffer_first_name(const u8 *buffer, const int buflen,
const char **name);
#endif /* _CORESIGHT_CORESIGHT_CONFIG_FILE_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c index 433ede94dd63..50abdb5aa6b6 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -7,6 +7,7 @@ #include <linux/configfs.h>
#include "coresight-config.h" +#include "coresight-config-file.h" #include "coresight-syscfg-configfs.h"
/* create a default ci_type. */ @@ -380,14 +381,147 @@ static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc return &feat_view->group; }
+/* Attributes in configfs that allow load and unload of configuration binary files */
+/* load "buffer" as a configuration binary file */ +static ssize_t cscfg_cfg_load_write(struct config_item *item, const void *buffer, size_t size) +{
struct cscfg_fs_configs_grp *configs_grp;
struct cscfg_fs_load_descs *load_descs = 0;
struct cscfg_load_owner_info *owner_info = 0;
int err = 0;
const char *name;
configs_grp = container_of(to_config_group(item), struct cscfg_fs_configs_grp, group);
if (size > CSCFG_FILE_MAXSIZE) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Load error: Input file too large.\n");
return -EINVAL;
}
load_descs = kzalloc(sizeof(struct cscfg_fs_load_descs), GFP_KERNEL);
owner_info = kzalloc(sizeof(struct cscfg_load_owner_info), GFP_KERNEL);
if (!load_descs || !owner_info) {
err = -ENOMEM;
goto exit_memfree;
}
load_descs->owner_info = owner_info;
owner_info->owner_handle = load_descs;
owner_info->type = CSCFG_OWNER_CONFIGFS;
err = cscfg_file_read_buffer(buffer, size, load_descs);
if (err) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Load error: Failed to read input file.\n");
goto exit_memfree;
}
err = cscfg_load_config_sets(load_descs->config_descs, load_descs->feat_descs, owner_info);
if (err) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Load error: Failed to load configuaration file.\n");
goto exit_memfree;
}
/* name of config if there is one, otherwise first feature */
if (load_descs->config_descs[0])
name = load_descs->config_descs[0]->name;
else
name = load_descs->feat_descs[0]->name;
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"OK: configuration file loaded (%s).\n", name);
return size;
+exit_memfree:
kfree(load_descs);
kfree(owner_info);
return err;
+} +CONFIGFS_BIN_ATTR_WO(cscfg_cfg_, load, NULL, CSCFG_FILE_MAXSIZE);
+/* read "buffer" and unload configuration */ +static ssize_t cscfg_cfg_unload_write(struct config_item *item, const void *buffer, size_t size) +{
struct cscfg_fs_configs_grp *configs_grp;
struct cscfg_fs_load_descs *load_descs;
const char *name;
int err;
configs_grp = container_of(to_config_group(item), struct cscfg_fs_configs_grp, group);
if (size > CSCFG_FILE_MAXSIZE) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Unload error: Input file too large\n");
return -EINVAL;
}
err = cscfg_file_read_buffer_first_name(buffer, size, &name);
if (err) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Unload error: Failed to read input file\n");
return err;
}
load_descs = cscfg_find_fs_owned_cfg_by_name(name);
if (!load_descs) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Unload error: Failed to find configuration %s from input file\n",
name);
return err;
}
err = cscfg_unload_config_sets(load_descs->owner_info);
if (err) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Unload error: Cannot unload configuration %s\n",
name);
return err;
}
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"OK: configuration file unloaded (%s).\n", name);
kfree((struct cscfg_load_owner_info *)load_descs->owner_info);
kfree(load_descs);
return size;
+} +CONFIGFS_BIN_ATTR_WO(cscfg_cfg_, unload, NULL, CSCFG_FILE_MAXSIZE);
+/* show the status of the last load / unload operation */ +static ssize_t cscfg_cfg_last_load_status_show(struct config_item *item, char *page) +{
struct cscfg_fs_configs_grp *configs_grp;
configs_grp = container_of(to_config_group(item), struct cscfg_fs_configs_grp, group);
return scnprintf(page, PAGE_SIZE, "%s\n", configs_grp->status);
I am still very ambivalent about this status thing... Especially since it only reports on the last item that was loaded/unloaded.
I guess the priciple use is to give feedback to the user if a load error occurs. An alternative could be pr_err at point of error. What I am trying to avoid is the case where someone attempts to load a configuration and it fails but there is no feedback. (Once the resource management patchset set for ETM is used, tnen loading can fail if the resources required do not match those avaialble - this is important given that amount of ETM resource is a hardware design implementation detail).
Regards
Mike
+} +CONFIGFS_ATTR_RO(cscfg_cfg_, last_load_status);
+static struct configfs_attribute *cscfg_config_configs_attrs[] = {
&cscfg_cfg_attr_last_load_status,
NULL,
+};
+static struct configfs_bin_attribute *cscfg_config_configfs_bin_attrs[] = {
&cscfg_cfg_attr_load,
&cscfg_cfg_attr_unload,
NULL,
+};
static struct config_item_type cscfg_configs_type = { .ct_owner = THIS_MODULE,
.ct_bin_attrs = cscfg_config_configfs_bin_attrs,
.ct_attrs = cscfg_config_configs_attrs,
};
-static struct config_group cscfg_configs_grp = {
.cg_item = {
.ci_namebuf = "configurations",
.ci_type = &cscfg_configs_type,
+/* group for configurations dir, with load, unload and status attribs */ +static struct cscfg_fs_configs_grp cscfg_configs_grp = {
.group = {
.cg_item = {
.ci_namebuf = "configurations",
.ci_type = &cscfg_configs_type,
}, },
};
@@ -400,7 +534,7 @@ int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc) new_group = cscfg_create_config_group(config_desc); if (IS_ERR(new_group)) return PTR_ERR(new_group);
err = configfs_register_group(&cscfg_configs_grp, new_group);
err = configfs_register_group(&cscfg_configs_grp.group, new_group); if (!err) config_desc->fs_group = new_group; return err;
@@ -468,8 +602,8 @@ int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr) mutex_init(&subsys->su_mutex);
/* Add default groups to subsystem */
config_group_init(&cscfg_configs_grp);
configfs_add_default_group(&cscfg_configs_grp, &subsys->su_group);
config_group_init(&cscfg_configs_grp.group);
configfs_add_default_group(&cscfg_configs_grp.group, &subsys->su_group); config_group_init(&cscfg_features_grp); configfs_add_default_group(&cscfg_features_grp, &subsys->su_group);
diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h index 373d84d43268..8d6900e8c1ea 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h @@ -11,6 +11,14 @@
#define CSCFG_FS_SUBSYS_NAME "cs-syscfg"
+#define CSCFG_FS_STATUS_STRLEN 256
+/* container for configs group */ +struct cscfg_fs_configs_grp {
struct config_group group;
char status[CSCFG_FS_STATUS_STRLEN];
+};
/* container for configuration view */ struct cscfg_fs_config { struct cscfg_config_desc *config_desc; diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 098fc34c4829..b5804cc2af9c 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -587,6 +587,42 @@ int cscfg_unload_config_sets(struct cscfg_load_owner_info *owner_info) } EXPORT_SYMBOL_GPL(cscfg_unload_config_sets);
+/* find a configuration owned by configfs by name of config / first feature */ +struct cscfg_fs_load_descs *cscfg_find_fs_owned_cfg_by_name(const char *name) +{
struct cscfg_load_owner_info *owner_info;
struct cscfg_fs_load_descs *fs_load_cfg = NULL;
struct cscfg_config_desc *config_desc;
struct cscfg_feature_desc *feat_desc;
mutex_lock(&cscfg_mutex);
/* search the load_owner list for CONFIGFS loaded types */
list_for_each_entry(owner_info, &cscfg_mgr->load_order_list, item) {
/* if this is a config fs owned item, then try to match */
if (owner_info->type == CSCFG_OWNER_CONFIGFS) {
fs_load_cfg = owner_info->owner_handle;
/* first try to match the name against the config if it exists */
if (fs_load_cfg->config_descs[0]) {
config_desc = fs_load_cfg->config_descs[0];
if (!strcmp(config_desc->name, name))
goto exit_unlock;
/* no config - match against first feature name */
} else {
feat_desc = fs_load_cfg->feat_descs[0];
if (!strcmp(feat_desc->name, name))
goto exit_unlock;
}
/* no match - move on */
fs_load_cfg = NULL;
}
}
+exit_unlock:
mutex_unlock(&cscfg_mutex);
return fs_load_cfg;
+}
/* Handle coresight device registration and add configs and features to devices */
/* iterate through config lists and load matching configs to device */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 6a6e33585be9..6bc29abe0650 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -95,6 +95,7 @@ int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc, int param_idx, u64 value); int cscfg_config_sysfs_activate(struct cscfg_config_desc *cfg_desc, bool activate); void cscfg_config_sysfs_set_preset(int preset); +struct cscfg_fs_load_descs *cscfg_find_fs_owned_cfg_by_name(const char *name);
/* syscfg manager external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, -- 2.17.1
[...]
+/* read "buffer" and unload configuration */ +static ssize_t cscfg_cfg_unload_write(struct config_item *item, const void *buffer, size_t size) +{
struct cscfg_fs_configs_grp *configs_grp;
struct cscfg_fs_load_descs *load_descs;
const char *name;
int err;
configs_grp = container_of(to_config_group(item), struct cscfg_fs_configs_grp, group);
if (size > CSCFG_FILE_MAXSIZE) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Unload error: Input file too large\n");
return -EINVAL;
}
err = cscfg_file_read_buffer_first_name(buffer, size, &name);
if (err) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Unload error: Failed to read input file\n");
return err;
}
load_descs = cscfg_find_fs_owned_cfg_by_name(name);
if (!load_descs) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Unload error: Failed to find configuration %s from input file\n",
name);
return err;
}
err = cscfg_unload_config_sets(load_descs->owner_info);
if (err) {
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"Unload error: Cannot unload configuration %s\n",
name);
return err;
}
scnprintf(configs_grp->status, CSCFG_FS_STATUS_STRLEN,
"OK: configuration file unloaded (%s).\n", name);
kfree((struct cscfg_load_owner_info *)load_descs->owner_info);
kfree(load_descs);
return size;
+} +CONFIGFS_BIN_ATTR_WO(cscfg_cfg_, unload, NULL, CSCFG_FILE_MAXSIZE);
+/* show the status of the last load / unload operation */ +static ssize_t cscfg_cfg_last_load_status_show(struct config_item *item, char *page) +{
struct cscfg_fs_configs_grp *configs_grp;
configs_grp = container_of(to_config_group(item), struct cscfg_fs_configs_grp, group);
return scnprintf(page, PAGE_SIZE, "%s\n", configs_grp->status);
I am still very ambivalent about this status thing... Especially since it only reports on the last item that was loaded/unloaded.
I guess the priciple use is to give feedback to the user if a load error occurs. An alternative could be pr_err at point of error.
I'd be fine with a pr_err().
Thanks, Mathieu
Update coresight-config.h and the coresight-config-file.c & .h to allow use in userspace programs.
Use __KERNEL__ defines to filter out driver only structures and elements so that user space programs can use the descriptor structures.
Abstract memory allocation in coresight-config-file.c to allow read file functions to be run in userspace and kernel drivers.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../coresight/coresight-config-file.c | 96 +++++++++++++------ .../coresight/coresight-config-file.h | 33 +++++++ .../hwtracing/coresight/coresight-config.h | 21 ++++ 3 files changed, 122 insertions(+), 28 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c index 3fd001938324..77a64b54280d 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.c +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -4,10 +4,58 @@ * Author: Mike Leach mike.leach@linaro.org */
-#include "coresight-config.h" #include "coresight-config-file.h" + +/* + * To allow reuse of this source in tools, define memory allocation fns according + * to build environment. + */ + +#ifdef __KERNEL__ #include "coresight-syscfg.h"
+static void *cscfg_calloc(size_t num, size_t size) +{ + return devm_kcalloc(cscfg_device(), num, size, GFP_KERNEL); +} + +static char *cscfg_strdup(const char *str) +{ + return devm_kstrdup(cscfg_device(), str, GFP_KERNEL); +} + +static void *cscfg_zalloc(size_t size) +{ + return devm_kzalloc(cscfg_device(), size, GFP_KERNEL); +} + +#else + +#include <stddef.h> +#include <string.h> +#include <stdlib.h> + +static void *cscfg_calloc(size_t num, size_t size) +{ + return calloc(num, size); +} + +static char *cscfg_strdup(const char *str) +{ + return strdup(str); +} + +static void *cscfg_zalloc(size_t size) +{ + void *ptr = malloc(size); + + if (ptr) + memset(ptr, 0, size); + return ptr; +} + +#endif + #define cscfg_extract_u64(val64) { \ val64 = *(u64 *)(buffer + used); \ used += sizeof(u64); \ @@ -80,6 +128,7 @@ static int cscfg_file_read_elem_str(const u8 *buffer, const int buflen, int *buf struct cscfg_file_elem_str *elem_str) { int used = *buf_used; + const u8 *str;
if ((buflen - used) < sizeof(u16)) return -EINVAL; @@ -89,11 +138,13 @@ static int cscfg_file_read_elem_str(const u8 *buffer, const int buflen, int *buf if ((buflen - used) < elem_str->str_len) return -EINVAL;
+ str = buffer + used; + /* check for 0 termination */ - if (buffer[elem_str->str_len - 1] != 0) + if (str[elem_str->str_len - 1] != 0) return -EINVAL;
- elem_str->str = devm_kstrdup(cscfg_device(), (char *)buffer, GFP_KERNEL); + elem_str->str = cscfg_strdup((char *)str); used += elem_str->str_len;
*buf_used = used; @@ -104,14 +155,12 @@ static int cscfg_file_alloc_desc_arrays(struct cscfg_fs_load_descs *desc_arrays, int nr_features) { /* arrays are 0 terminated - max of 1 config & nr_features features */ - desc_arrays->config_descs = devm_kcalloc(cscfg_device(), 2, - sizeof(struct cscfg_config_desc *), - GFP_KERNEL); + desc_arrays->config_descs = cscfg_calloc(2, sizeof(struct cscfg_config_desc *)); if (!desc_arrays->config_descs) return -ENOMEM; - desc_arrays->feat_descs = devm_kcalloc(cscfg_device(), nr_features + 1, - sizeof(struct cscfg_feature_desc *), - GFP_KERNEL); + + desc_arrays->feat_descs = cscfg_calloc(nr_features + 1, + sizeof(struct cscfg_feature_desc *)); if (!desc_arrays->feat_descs) return -ENOMEM; return 0; @@ -138,8 +187,7 @@ static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int * return 0;
/* we have a config - allocate the descriptor */ - config_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_config_desc), - GFP_KERNEL); + config_desc = cscfg_zalloc(sizeof(struct cscfg_config_desc)); if (!config_desc) return -ENOMEM;
@@ -165,8 +213,7 @@ static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int * /* read the array of 64bit presets if present */ nr_preset_vals = config_desc->nr_total_params * config_desc->nr_presets; if (nr_preset_vals) { - presets = devm_kcalloc(cscfg_device(), nr_preset_vals, - sizeof(u64), GFP_KERNEL); + presets = cscfg_calloc(nr_preset_vals, sizeof(u64)); if (!presets) return -ENOMEM;
@@ -181,10 +228,8 @@ static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int *
/* read the array of feature names referenced by the config */ if (config_desc->nr_feat_refs) { - config_desc->feat_ref_names = devm_kcalloc(cscfg_device(), - config_desc->nr_feat_refs, - sizeof(char *), - GFP_KERNEL); + config_desc->feat_ref_names = cscfg_calloc(config_desc->nr_feat_refs, + sizeof(char *)); if (!config_desc->feat_ref_names) return -ENOMEM;
@@ -262,8 +307,7 @@ static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int u32 val32;
/* allocate the feature descriptor object */ - feat_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_feature_desc), - GFP_KERNEL); + feat_desc = cscfg_zalloc(sizeof(struct cscfg_feature_desc)); if (!feat_desc) return -ENOMEM;
@@ -302,10 +346,8 @@ static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int nr_regs_bytes = ((sizeof(u32) + sizeof(u64)) * feat_desc->nr_regs); if ((buflen - used) < nr_regs_bytes) return -EINVAL; - feat_desc->regs_desc = devm_kcalloc(cscfg_device(), - feat_desc->nr_regs, - sizeof(struct cscfg_regval_desc), - GFP_KERNEL); + feat_desc->regs_desc = cscfg_calloc(feat_desc->nr_regs, + sizeof(struct cscfg_regval_desc)); if (!feat_desc->regs_desc) return -ENOMEM;
@@ -319,10 +361,8 @@ static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int
/* parameter descriptors - string + 64 bit value */ if (feat_desc->nr_params) { - feat_desc->params_desc = devm_kcalloc(cscfg_device(), - feat_desc->nr_params, - sizeof(struct cscfg_parameter_desc), - GFP_KERNEL); + feat_desc->params_desc = cscfg_calloc(feat_desc->nr_params, + sizeof(struct cscfg_parameter_desc)); if (!feat_desc->params_desc) return -ENOMEM; for (i = 0; i < feat_desc->nr_params; i++) { @@ -399,7 +439,7 @@ int cscfg_file_read_buffer(const u8 *buffer, const int buflen, if (err) return err; } - return used; + return 0; }
int cscfg_file_read_buffer_first_name(const u8 *buffer, const int buflen, diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h index 03899f7d94c9..04c365e5109b 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.h +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -7,6 +7,39 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_FILE_H #define _CORESIGHT_CORESIGHT_CONFIG_FILE_H
+#include <linux/types.h> + +#ifndef __KERNEL__ +/* + * allow the user space programs to include the coresight config headers + * to use the _desc structures, and reuse the read code + */ +#ifndef u8 +typedef __u8 u8; +typedef __u16 u16; +typedef __u32 u32; +typedef __u64 u64; +#endif + +/* ARRAY SIZE is useful too */ +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +/* define EINVAL for user space */ +#ifndef EINVAL +#define EINVAL 22 +#endif + +#ifndef ENOMEM +#define ENOMEM 12 +#endif + +#endif + +#include "coresight-config.h" + + /* * Structures to represent configuration descriptors in a memory buffer * to serialise to and from files diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 770986316bc2..2136393df710 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -7,7 +7,14 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_H #define _CORESIGHT_CORESIGHT_CONFIG_H
+/* + * Filter out kernel only portions of the file to allow user space programs + * to use the descriptor definitions. + */ +#ifdef __KERNEL__ #include <linux/coresight.h> +#endif + #include <linux/types.h>
/* CoreSight Configuration Management - component and system wide configuration */ @@ -103,14 +110,18 @@ struct cscfg_regval_desc { struct cscfg_feature_desc { const char *name; const char *description; +#ifdef __KERNEL__ struct list_head item; +#endif u32 match_flags; int nr_params; struct cscfg_parameter_desc *params_desc; int nr_regs; struct cscfg_regval_desc *regs_desc; +#ifdef __KERNEL__ void *load_owner; struct config_group *fs_group; +#endif };
/** @@ -138,16 +149,20 @@ struct cscfg_feature_desc { struct cscfg_config_desc { const char *name; const char *description; +#ifdef __KERNEL__ struct list_head item; +#endif int nr_feat_refs; const char **feat_ref_names; int nr_presets; int nr_total_params; const u64 *presets; /* nr_presets * nr_total_params */ +#ifdef __KERNEL__ struct dev_ext_attribute *event_ea; atomic_t active_cnt; void *load_owner; struct config_group *fs_group; +#endif };
/** @@ -162,11 +177,16 @@ struct cscfg_config_desc { * @feat_descs: array of feature descriptor pointers. */ struct cscfg_fs_load_descs { +#ifdef __KERNEL__ void *owner_info; +#endif struct cscfg_config_desc **config_descs; struct cscfg_feature_desc **feat_descs; };
+/* remainder of header is used by the kernel drivers only */ +#ifdef __KERNEL__ + /** * config register instance - part of a loaded feature. * maps register values to csdev driver structures @@ -274,4 +294,5 @@ void cscfg_csdev_disable_config(struct cscfg_config_csdev *config_csdev); /* reset a feature to default values */ void cscfg_reset_feat(struct cscfg_feature_csdev *feat_csdev);
+#endif /* __KERNEL__ */ #endif /* _CORESIGHT_CORESIGHT_CONFIG_H */
On Tue, Nov 30, 2021 at 10:00:57PM +0000, Mike Leach wrote:
Update coresight-config.h and the coresight-config-file.c & .h to allow use in userspace programs.
Use __KERNEL__ defines to filter out driver only structures and elements so that user space programs can use the descriptor structures.
Abstract memory allocation in coresight-config-file.c to allow read file functions to be run in userspace and kernel drivers.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../coresight/coresight-config-file.c | 96 +++++++++++++------ .../coresight/coresight-config-file.h | 33 +++++++ .../hwtracing/coresight/coresight-config.h | 21 ++++ 3 files changed, 122 insertions(+), 28 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c index 3fd001938324..77a64b54280d 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.c +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -4,10 +4,58 @@
- Author: Mike Leach mike.leach@linaro.org
*/ -#include "coresight-config.h" #include "coresight-config-file.h"
+/*
- To allow reuse of this source in tools, define memory allocation fns according
- to build environment.
- */
+#ifdef __KERNEL__ #include "coresight-syscfg.h" +static void *cscfg_calloc(size_t num, size_t size) +{
- return devm_kcalloc(cscfg_device(), num, size, GFP_KERNEL);
+}
+static char *cscfg_strdup(const char *str) +{
- return devm_kstrdup(cscfg_device(), str, GFP_KERNEL);
+}
+static void *cscfg_zalloc(size_t size) +{
- return devm_kzalloc(cscfg_device(), size, GFP_KERNEL);
+}
+#else
+#include <stddef.h> +#include <string.h> +#include <stdlib.h>
+static void *cscfg_calloc(size_t num, size_t size) +{
- return calloc(num, size);
+}
+static char *cscfg_strdup(const char *str) +{
- return strdup(str);
+}
+static void *cscfg_zalloc(size_t size) +{
- void *ptr = malloc(size);
- if (ptr)
memset(ptr, 0, size);
- return ptr;
+}
+#endif
#define cscfg_extract_u64(val64) { \ val64 = *(u64 *)(buffer + used); \ used += sizeof(u64); \ @@ -80,6 +128,7 @@ static int cscfg_file_read_elem_str(const u8 *buffer, const int buflen, int *buf struct cscfg_file_elem_str *elem_str) { int used = *buf_used;
- const u8 *str;
if ((buflen - used) < sizeof(u16)) return -EINVAL; @@ -89,11 +138,13 @@ static int cscfg_file_read_elem_str(const u8 *buffer, const int buflen, int *buf if ((buflen - used) < elem_str->str_len) return -EINVAL;
- str = buffer + used;
- /* check for 0 termination */
- if (buffer[elem_str->str_len - 1] != 0)
- if (str[elem_str->str_len - 1] != 0) return -EINVAL;
- elem_str->str = devm_kstrdup(cscfg_device(), (char *)buffer, GFP_KERNEL);
- elem_str->str = cscfg_strdup((char *)str); used += elem_str->str_len;
*buf_used = used; @@ -104,14 +155,12 @@ static int cscfg_file_alloc_desc_arrays(struct cscfg_fs_load_descs *desc_arrays, int nr_features) { /* arrays are 0 terminated - max of 1 config & nr_features features */
- desc_arrays->config_descs = devm_kcalloc(cscfg_device(), 2,
sizeof(struct cscfg_config_desc *),
GFP_KERNEL);
- desc_arrays->config_descs = cscfg_calloc(2, sizeof(struct cscfg_config_desc *)); if (!desc_arrays->config_descs) return -ENOMEM;
- desc_arrays->feat_descs = devm_kcalloc(cscfg_device(), nr_features + 1,
sizeof(struct cscfg_feature_desc *),
GFP_KERNEL);
- desc_arrays->feat_descs = cscfg_calloc(nr_features + 1,
if (!desc_arrays->feat_descs) return -ENOMEM; return 0;sizeof(struct cscfg_feature_desc *));
@@ -138,8 +187,7 @@ static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int * return 0; /* we have a config - allocate the descriptor */
- config_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_config_desc),
GFP_KERNEL);
- config_desc = cscfg_zalloc(sizeof(struct cscfg_config_desc)); if (!config_desc) return -ENOMEM;
@@ -165,8 +213,7 @@ static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int * /* read the array of 64bit presets if present */ nr_preset_vals = config_desc->nr_total_params * config_desc->nr_presets; if (nr_preset_vals) {
presets = devm_kcalloc(cscfg_device(), nr_preset_vals,
sizeof(u64), GFP_KERNEL);
if (!presets) return -ENOMEM;presets = cscfg_calloc(nr_preset_vals, sizeof(u64));
@@ -181,10 +228,8 @@ static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int * /* read the array of feature names referenced by the config */ if (config_desc->nr_feat_refs) {
config_desc->feat_ref_names = devm_kcalloc(cscfg_device(),
config_desc->nr_feat_refs,
sizeof(char *),
GFP_KERNEL);
config_desc->feat_ref_names = cscfg_calloc(config_desc->nr_feat_refs,
if (!config_desc->feat_ref_names) return -ENOMEM;sizeof(char *));
@@ -262,8 +307,7 @@ static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int u32 val32; /* allocate the feature descriptor object */
- feat_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_feature_desc),
GFP_KERNEL);
- feat_desc = cscfg_zalloc(sizeof(struct cscfg_feature_desc)); if (!feat_desc) return -ENOMEM;
@@ -302,10 +346,8 @@ static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int nr_regs_bytes = ((sizeof(u32) + sizeof(u64)) * feat_desc->nr_regs); if ((buflen - used) < nr_regs_bytes) return -EINVAL;
feat_desc->regs_desc = devm_kcalloc(cscfg_device(),
feat_desc->nr_regs,
sizeof(struct cscfg_regval_desc),
GFP_KERNEL);
feat_desc->regs_desc = cscfg_calloc(feat_desc->nr_regs,
if (!feat_desc->regs_desc) return -ENOMEM;sizeof(struct cscfg_regval_desc));
@@ -319,10 +361,8 @@ static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int /* parameter descriptors - string + 64 bit value */ if (feat_desc->nr_params) {
feat_desc->params_desc = devm_kcalloc(cscfg_device(),
feat_desc->nr_params,
sizeof(struct cscfg_parameter_desc),
GFP_KERNEL);
feat_desc->params_desc = cscfg_calloc(feat_desc->nr_params,
if (!feat_desc->params_desc) return -ENOMEM; for (i = 0; i < feat_desc->nr_params; i++) {sizeof(struct cscfg_parameter_desc));
@@ -399,7 +439,7 @@ int cscfg_file_read_buffer(const u8 *buffer, const int buflen, if (err) return err; }
- return used;
- return 0;
} int cscfg_file_read_buffer_first_name(const u8 *buffer, const int buflen, diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h index 03899f7d94c9..04c365e5109b 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.h +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -7,6 +7,39 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_FILE_H #define _CORESIGHT_CORESIGHT_CONFIG_FILE_H +#include <linux/types.h>
+#ifndef __KERNEL__ +/*
- allow the user space programs to include the coresight config headers
- to use the _desc structures, and reuse the read code
- */
+#ifndef u8 +typedef __u8 u8; +typedef __u16 u16; +typedef __u32 u32; +typedef __u64 u64; +#endif
+/* ARRAY SIZE is useful too */ +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif
+/* define EINVAL for user space */ +#ifndef EINVAL +#define EINVAL 22 +#endif
+#ifndef ENOMEM +#define ENOMEM 12 +#endif
+#endif
+#include "coresight-config.h"
/*
- Structures to represent configuration descriptors in a memory buffer
- to serialise to and from files
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 770986316bc2..2136393df710 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -7,7 +7,14 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_H #define _CORESIGHT_CORESIGHT_CONFIG_H +/*
- Filter out kernel only portions of the file to allow user space programs
- to use the descriptor definitions.
- */
+#ifdef __KERNEL__ #include <linux/coresight.h> +#endif
#include <linux/types.h> /* CoreSight Configuration Management - component and system wide configuration */ @@ -103,14 +110,18 @@ struct cscfg_regval_desc { struct cscfg_feature_desc { const char *name; const char *description; +#ifdef __KERNEL__ struct list_head item; +#endif u32 match_flags; int nr_params; struct cscfg_parameter_desc *params_desc; int nr_regs; struct cscfg_regval_desc *regs_desc; +#ifdef __KERNEL__ void *load_owner; struct config_group *fs_group; +#endif };
That will quickly become a maintenance nightmare. I suggest the following:
struct cscfg_feature_desc { struct list_head item; void *load_owner; struct config_group *fs_group; struct cscfg_feature_udesc *udesc; };
struct cscfg_feature_udesc { u32 version; 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; };
Structure cscfg_feature_udesc should likely be under include/uapi/linux/coresight-config.h
/** @@ -138,16 +149,20 @@ struct cscfg_feature_desc { struct cscfg_config_desc { const char *name; const char *description; +#ifdef __KERNEL__ struct list_head item; +#endif int nr_feat_refs; const char **feat_ref_names; int nr_presets; int nr_total_params; const u64 *presets; /* nr_presets * nr_total_params */ +#ifdef __KERNEL__ struct dev_ext_attribute *event_ea; atomic_t active_cnt; void *load_owner; struct config_group *fs_group; +#endif }; /** @@ -162,11 +177,16 @@ struct cscfg_config_desc {
- @feat_descs: array of feature descriptor pointers.
*/ struct cscfg_fs_load_descs { +#ifdef __KERNEL__ void *owner_info; +#endif struct cscfg_config_desc **config_descs; struct cscfg_feature_desc **feat_descs; };
Same comment as above.
+/* remainder of header is used by the kernel drivers only */ +#ifdef __KERNEL__
/**
- config register instance - part of a loaded feature.
maps register values to csdev driver structures
@@ -274,4 +294,5 @@ void cscfg_csdev_disable_config(struct cscfg_config_csdev *config_csdev); /* reset a feature to default values */ void cscfg_reset_feat(struct cscfg_feature_csdev *feat_csdev); +#endif /* __KERNEL__ */
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */
2.17.1
Hi Mathieu,
On Fri, 28 Jan 2022 at 18:33, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Tue, Nov 30, 2021 at 10:00:57PM +0000, Mike Leach wrote:
Update coresight-config.h and the coresight-config-file.c & .h to allow use in userspace programs.
Use __KERNEL__ defines to filter out driver only structures and elements so that user space programs can use the descriptor structures.
Abstract memory allocation in coresight-config-file.c to allow read file functions to be run in userspace and kernel drivers.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../coresight/coresight-config-file.c | 96 +++++++++++++------ .../coresight/coresight-config-file.h | 33 +++++++ .../hwtracing/coresight/coresight-config.h | 21 ++++ 3 files changed, 122 insertions(+), 28 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c index 3fd001938324..77a64b54280d 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.c +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -4,10 +4,58 @@
- Author: Mike Leach mike.leach@linaro.org
*/
-#include "coresight-config.h" #include "coresight-config-file.h"
+/*
- To allow reuse of this source in tools, define memory allocation fns according
- to build environment.
- */
+#ifdef __KERNEL__ #include "coresight-syscfg.h"
+static void *cscfg_calloc(size_t num, size_t size) +{
return devm_kcalloc(cscfg_device(), num, size, GFP_KERNEL);
+}
+static char *cscfg_strdup(const char *str) +{
return devm_kstrdup(cscfg_device(), str, GFP_KERNEL);
+}
+static void *cscfg_zalloc(size_t size) +{
return devm_kzalloc(cscfg_device(), size, GFP_KERNEL);
+}
+#else
+#include <stddef.h> +#include <string.h> +#include <stdlib.h>
+static void *cscfg_calloc(size_t num, size_t size) +{
return calloc(num, size);
+}
+static char *cscfg_strdup(const char *str) +{
return strdup(str);
+}
+static void *cscfg_zalloc(size_t size) +{
void *ptr = malloc(size);
if (ptr)
memset(ptr, 0, size);
return ptr;
+}
+#endif
#define cscfg_extract_u64(val64) { \ val64 = *(u64 *)(buffer + used); \ used += sizeof(u64); \ @@ -80,6 +128,7 @@ static int cscfg_file_read_elem_str(const u8 *buffer, const int buflen, int *buf struct cscfg_file_elem_str *elem_str) { int used = *buf_used;
const u8 *str; if ((buflen - used) < sizeof(u16)) return -EINVAL;
@@ -89,11 +138,13 @@ static int cscfg_file_read_elem_str(const u8 *buffer, const int buflen, int *buf if ((buflen - used) < elem_str->str_len) return -EINVAL;
str = buffer + used;
/* check for 0 termination */
if (buffer[elem_str->str_len - 1] != 0)
if (str[elem_str->str_len - 1] != 0) return -EINVAL;
elem_str->str = devm_kstrdup(cscfg_device(), (char *)buffer, GFP_KERNEL);
elem_str->str = cscfg_strdup((char *)str); used += elem_str->str_len; *buf_used = used;
@@ -104,14 +155,12 @@ static int cscfg_file_alloc_desc_arrays(struct cscfg_fs_load_descs *desc_arrays, int nr_features) { /* arrays are 0 terminated - max of 1 config & nr_features features */
desc_arrays->config_descs = devm_kcalloc(cscfg_device(), 2,
sizeof(struct cscfg_config_desc *),
GFP_KERNEL);
desc_arrays->config_descs = cscfg_calloc(2, sizeof(struct cscfg_config_desc *)); if (!desc_arrays->config_descs) return -ENOMEM;
desc_arrays->feat_descs = devm_kcalloc(cscfg_device(), nr_features + 1,
sizeof(struct cscfg_feature_desc *),
GFP_KERNEL);
desc_arrays->feat_descs = cscfg_calloc(nr_features + 1,
sizeof(struct cscfg_feature_desc *)); if (!desc_arrays->feat_descs) return -ENOMEM; return 0;
@@ -138,8 +187,7 @@ static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int * return 0;
/* we have a config - allocate the descriptor */
config_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_config_desc),
GFP_KERNEL);
config_desc = cscfg_zalloc(sizeof(struct cscfg_config_desc)); if (!config_desc) return -ENOMEM;
@@ -165,8 +213,7 @@ static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int * /* read the array of 64bit presets if present */ nr_preset_vals = config_desc->nr_total_params * config_desc->nr_presets; if (nr_preset_vals) {
presets = devm_kcalloc(cscfg_device(), nr_preset_vals,
sizeof(u64), GFP_KERNEL);
presets = cscfg_calloc(nr_preset_vals, sizeof(u64)); if (!presets) return -ENOMEM;
@@ -181,10 +228,8 @@ static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int *
/* read the array of feature names referenced by the config */ if (config_desc->nr_feat_refs) {
config_desc->feat_ref_names = devm_kcalloc(cscfg_device(),
config_desc->nr_feat_refs,
sizeof(char *),
GFP_KERNEL);
config_desc->feat_ref_names = cscfg_calloc(config_desc->nr_feat_refs,
sizeof(char *)); if (!config_desc->feat_ref_names) return -ENOMEM;
@@ -262,8 +307,7 @@ static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int u32 val32;
/* allocate the feature descriptor object */
feat_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_feature_desc),
GFP_KERNEL);
feat_desc = cscfg_zalloc(sizeof(struct cscfg_feature_desc)); if (!feat_desc) return -ENOMEM;
@@ -302,10 +346,8 @@ static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int nr_regs_bytes = ((sizeof(u32) + sizeof(u64)) * feat_desc->nr_regs); if ((buflen - used) < nr_regs_bytes) return -EINVAL;
feat_desc->regs_desc = devm_kcalloc(cscfg_device(),
feat_desc->nr_regs,
sizeof(struct cscfg_regval_desc),
GFP_KERNEL);
feat_desc->regs_desc = cscfg_calloc(feat_desc->nr_regs,
sizeof(struct cscfg_regval_desc)); if (!feat_desc->regs_desc) return -ENOMEM;
@@ -319,10 +361,8 @@ static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int
/* parameter descriptors - string + 64 bit value */ if (feat_desc->nr_params) {
feat_desc->params_desc = devm_kcalloc(cscfg_device(),
feat_desc->nr_params,
sizeof(struct cscfg_parameter_desc),
GFP_KERNEL);
feat_desc->params_desc = cscfg_calloc(feat_desc->nr_params,
sizeof(struct cscfg_parameter_desc)); if (!feat_desc->params_desc) return -ENOMEM; for (i = 0; i < feat_desc->nr_params; i++) {
@@ -399,7 +439,7 @@ int cscfg_file_read_buffer(const u8 *buffer, const int buflen, if (err) return err; }
return used;
return 0;
}
int cscfg_file_read_buffer_first_name(const u8 *buffer, const int buflen, diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h index 03899f7d94c9..04c365e5109b 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.h +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -7,6 +7,39 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_FILE_H #define _CORESIGHT_CORESIGHT_CONFIG_FILE_H
+#include <linux/types.h>
+#ifndef __KERNEL__ +/*
- allow the user space programs to include the coresight config headers
- to use the _desc structures, and reuse the read code
- */
+#ifndef u8 +typedef __u8 u8; +typedef __u16 u16; +typedef __u32 u32; +typedef __u64 u64; +#endif
+/* ARRAY SIZE is useful too */ +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif
+/* define EINVAL for user space */ +#ifndef EINVAL +#define EINVAL 22 +#endif
+#ifndef ENOMEM +#define ENOMEM 12 +#endif
+#endif
+#include "coresight-config.h"
/*
- Structures to represent configuration descriptors in a memory buffer
- to serialise to and from files
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 770986316bc2..2136393df710 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -7,7 +7,14 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_H #define _CORESIGHT_CORESIGHT_CONFIG_H
+/*
- Filter out kernel only portions of the file to allow user space programs
- to use the descriptor definitions.
- */
+#ifdef __KERNEL__ #include <linux/coresight.h> +#endif
#include <linux/types.h>
/* CoreSight Configuration Management - component and system wide configuration */ @@ -103,14 +110,18 @@ struct cscfg_regval_desc { struct cscfg_feature_desc { const char *name; const char *description; +#ifdef __KERNEL__ struct list_head item; +#endif u32 match_flags; int nr_params; struct cscfg_parameter_desc *params_desc; int nr_regs; struct cscfg_regval_desc *regs_desc; +#ifdef __KERNEL__ void *load_owner; struct config_group *fs_group; +#endif };
That will quickly become a maintenance nightmare. I suggest the following:
I take your point. I was trying to avoid having a new structure, but allow the config buffer reader to use the same code in both kernel and userspace - good for testing and avoid maintaing two copies of the same code.
struct cscfg_feature_desc { struct list_head item; void *load_owner; struct config_group *fs_group; struct cscfg_feature_udesc *udesc; };
struct cscfg_feature_udesc { u32 version; 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; };
Structure cscfg_feature_udesc should likely be under include/uapi/linux/coresight-config.h
I don't mid addiing a udesc set of structures - but wanted to avoid changing the kernel structure. A change such as above would have huge ripple effects throughout all the existing kernel code.
It may be better to have separate user and kernel structures but try to get more abstraction into the reader algorithm.
I'll revisit this
Thanks
Mike
/** @@ -138,16 +149,20 @@ struct cscfg_feature_desc { struct cscfg_config_desc { const char *name; const char *description; +#ifdef __KERNEL__ struct list_head item; +#endif int nr_feat_refs; const char **feat_ref_names; int nr_presets; int nr_total_params; const u64 *presets; /* nr_presets * nr_total_params */ +#ifdef __KERNEL__ struct dev_ext_attribute *event_ea; atomic_t active_cnt; void *load_owner; struct config_group *fs_group; +#endif };
/** @@ -162,11 +177,16 @@ struct cscfg_config_desc {
- @feat_descs: array of feature descriptor pointers.
*/ struct cscfg_fs_load_descs { +#ifdef __KERNEL__ void *owner_info; +#endif struct cscfg_config_desc **config_descs; struct cscfg_feature_desc **feat_descs; };
Same comment as above.
+/* remainder of header is used by the kernel drivers only */ +#ifdef __KERNEL__
/**
- config register instance - part of a loaded feature.
maps register values to csdev driver structures
@@ -274,4 +294,5 @@ void cscfg_csdev_disable_config(struct cscfg_config_csdev *config_csdev); /* reset a feature to default values */ void cscfg_reset_feat(struct cscfg_feature_csdev *feat_csdev);
+#endif /* __KERNEL__ */
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */
2.17.1
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.
Signed-off-by: Mike Leach mike.leach@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. + * Author: Mike Leach mike.leach@linaro.org + */ + +#include <string.h> + +#include "coresight-cfg-bufw.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/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@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@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 +}; + +static struct cscfg_config_desc *sample_cfgs[] = { + &afdo3, + NULL +}; + + +#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; +}
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@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@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@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@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
HI Mathieu,
On Thu, 13 Jan 2022 at 17:56, Mathieu Poirier mathieu.poirier@linaro.org wrote:
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@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.
Given the lenght of legal copyright - not a major issue - but if respinning will address.
- Author: Mike Leach mike.leach@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
Will sort these.
- */
+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@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@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.
Agreed but given this patchset has been split into multiple ones this has dropped som eof the context between patches. The next set - which adds ETMv4 resource management also contains multiple additional examples showing features. These cannot appear here as they use the new resource IDs introduced in the next set.
+static struct cscfg_config_desc *sample_cfgs[] = {
&afdo3,
NULL
+};
Any reason to declare sample_cfgs[] when there can only be one configuration?
The API defined requires a NULL terminated list.
Lastly I get the following [1] when compiling this set - I have not investigated further.
Looks like there is a failure to copy the coresight_config_file.c source from the kernel into the sample working directory. This is compiled into the user space reader tool. Not sure why it would be copying in my environment and not yours.
It seems like we have been here before in a previous patchset that contained the samples - I think then it was something to do with directtory definitions - but I never really understood why the fix we found worked.
The sampel can be compiled natively (x86). In the samples directory run:- make -f Makefile.host This will do the same copy and build, but create x86 versions of the tools. Perhaps this will highlight the differences.
As an aside, the output files from coresight-cfg-filegen can be subsequently transferred across to the ARM base target and used.
Thanks
Mike
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
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.
The user space program to read and write configurations should go under tools/coresight rather than sample/coresight. Have a look at tools/perf and tools/bpf. There is a lot of examples in there that deals with code shared between kernel and user space. There is even a nifty scripts that checks for diverging files between kernel and tools when compiling the perf tools.
You should also find how to properly deal with error codes and standard types in a generic way rather than redefining them as in the previous patch.
I think this patchset is holding together but needs some refactoring to conform to what others have done when dealing with shared kernel/user space code.
I am done reviewing this set.
Thanks, Mathieu
Signed-off-by: Mike Leach mike.leach@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.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <string.h>
+#include "coresight-cfg-bufw.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/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@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@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
+};
+static struct cscfg_config_desc *sample_cfgs[] = {
- &afdo3,
- NULL
+};
+#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
Hi Mathieu,
On Fri, 28 Jan 2022 at 18:43, Mathieu Poirier mathieu.poirier@linaro.org wrote:
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.
The user space program to read and write configurations should go under tools/coresight rather than sample/coresight. Have a look at tools/perf and tools/bpf. There is a lot of examples in there that deals with code shared between kernel and user space. There is even a nifty scripts that checks for diverging files between kernel and tools when compiling the perf tools.
OK - hadn't thought of that but seems like a good idea,
You should also find how to properly deal with error codes and standard types in a generic way rather than redefining them as in the previous patch.
Agreed - having a quick look, there appears to be suitable headers in tools/include/uapi/...
I think this patchset is holding together but needs some refactoring to conform to what others have done when dealing with shared kernel/user space code.
Agreed.
Thanks
Mike
I am done reviewing this set.
Thanks, Mathieu
Signed-off-by: Mike Leach mike.leach@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.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <string.h>
+#include "coresight-cfg-bufw.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/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@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@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
+};
+static struct cscfg_config_desc *sample_cfgs[] = {
&afdo3,
NULL
+};
+#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
Add a userspace program to read and print a configuration generated for loading via the configfs attributes.
Signed-off-by: Mike Leach mike.leach@linaro.org --- samples/coresight/Makefile | 20 +- samples/coresight/Makefile.host | 47 +++++ samples/coresight/coresight-cfg-file-read.c | 191 ++++++++++++++++++++ 3 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 samples/coresight/Makefile.host create mode 100644 samples/coresight/coresight-cfg-file-read.c
diff --git a/samples/coresight/Makefile b/samples/coresight/Makefile index 07bfd99d7a68..ad8f29a77881 100644 --- a/samples/coresight/Makefile +++ b/samples/coresight/Makefile @@ -4,8 +4,24 @@ 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 config - configfs loadable binary config generator & reader +userprogs-always-y += coresight-cfg-filegen coresight-cfg-file-read
coresight-cfg-filegen-objs := coresight-cfg-filegen.o coresight-cfg-bufw.o +coresight-cfg-file-read-objs := coresight-cfg-file-read.o coresight-config-file.o + +# pull in the coresight headers userccflags += -I$(srctree)/drivers/hwtracing/coresight + +# need to copy over the reader source from the driver tree - to build separately +CORESIGHT_SRC_PATH := $(abspath $(srctree)/$(src)) + +$(src)/coresight-config-file.c: copy_coresight_source + +.PHONY: copy_coresight_source + +copy_coresight_source: + @cp $(CORESIGHT_SRC_PATH)/../../drivers/hwtracing/coresight/coresight-config-file.c $(CORESIGHT_SRC_PATH)/. + +# clean up the copy after use. +clean-files += coresight-config-file.c diff --git a/samples/coresight/Makefile.host b/samples/coresight/Makefile.host new file mode 100644 index 000000000000..fc01f33bc1ff --- /dev/null +++ b/samples/coresight/Makefile.host @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-only + +# Makefile to build just the example userspace programs on host m/c + +this-makefile := $(lastword $(MAKEFILE_LIST)) +sample-src := $(realpath $(dir $(this-makefile))) +srctree := $(realpath $(dir $(sample-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) + +# include the main Makefile to use some of the vars from it +include Makefile + +# compile flags +CFLAGS += $(CPPFLAGS) -c -Wall -DLINUX -Wno-switch -Wlogical-op -fPIC $(userccflags) + +# debug variant +ifdef DEBUG +CFLAGS += -g -O0 -DDEBUG +else +CFLAGS += -O2 -DNDEBUG +endif + +.PHONY: all +all: coresight-cfg-filegen 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 $(sample-src)/. + +coresight-cfg-filegen: $(coresight-cfg-filegen-objs) + $(CC) $(LDFLAGS) $(coresight-cfg-filegen-objs) -o coresight-cfg-filegen + +coresight-cfg-file-read: $(coresight-cfg-file-read-objs) + $(CC) $(LDFLAGS) $(coresight-cfg-file-read-objs) -o coresight-cfg-file-read + +clean: + rm -f $(userprogs-always-y) + rm -f *.o + rm -f $(clean-files) diff --git a/samples/coresight/coresight-cfg-file-read.c b/samples/coresight/coresight-cfg-file-read.c new file mode 100644 index 000000000000..4e0fd840428f --- /dev/null +++ b/samples/coresight/coresight-cfg-file-read.c @@ -0,0 +1,191 @@ +// 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" + +/* + * 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%llx, ", config_desc->presets[p]); + } + printf("\n"); + } + } + printf("\n\n"); +} + +static void print_reg_type_info(u8 type) +{ + if (type & CS_CFG_REG_TYPE_STD) + printf("std_reg "); + if (type & CS_CFG_REG_TYPE_RESOURCE) + printf("resource "); + if (type & CS_CFG_REG_TYPE_VAL_PARAM) + printf("param_index "); + if (type & CS_CFG_REG_TYPE_VAL_64BIT) + printf("64_bit "); + else + printf("32_bit "); + if (type & CS_CFG_REG_TYPE_VAL_MASK) + printf("masked "); + if (type & CS_CFG_REG_TYPE_VAL_SAVE) + printf("save_on_disable "); + +} + +static void print_regs(int nr, struct cscfg_regval_desc *regs_desc_array) +{ + int i; + struct cscfg_regval_desc *reg_desc; + u8 type; + u16 offset; + u16 info; + + for (i = 0; i < nr; i++) { + reg_desc = ®s_desc_array[i]; + type = (u8)reg_desc->type; + offset = (u16)reg_desc->offset; + info = (u16)reg_desc->hw_info; + + printf("Reg(%d): Type 0x%x: ", i, type); + print_reg_type_info(type); + printf("\nOffset: 0x%03x; HW Info: 0x%03x\n", offset, info); + printf("Value: "); + if (type & CS_CFG_REG_TYPE_VAL_64BIT) + printf("0x%llx\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%llx\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; + } + fread(buffer, sizeof(u8), fsize, fp); + fclose(fp); + + /* 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; +}
Add documentation covering the configfs updates that allow binary configuration files to be loaded and unloaded via configfs, along with the demonstration programs in samples.
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../trace/coresight/coresight-config.rst | 151 +++++++++++++++++- 1 file changed, 145 insertions(+), 6 deletions(-)
diff --git a/Documentation/trace/coresight/coresight-config.rst b/Documentation/trace/coresight/coresight-config.rst index 6d5ffa6f7347..f11def230fab 100644 --- a/Documentation/trace/coresight/coresight-config.rst +++ b/Documentation/trace/coresight/coresight-config.rst @@ -152,7 +152,7 @@ follows::
$ cd configurations/ $ ls - autofdo + autofdo last_load_status load unload $ cd autofdo/ $ ls description feature_refs preset1 preset3 preset5 preset7 preset9 @@ -278,9 +278,19 @@ Creating and Loading Custom Configurations ==========================================
Custom configurations and / or features can be dynamically loaded into the -system by using a loadable module. +system by using a loadable module, or by loading a binary configuration +file in configfs. + +Loaded configurations can use previously loaded features. The system will +ensure that it is not possible to unload a feature that is currently in +use, by enforcing the unload order as the strict reverse of the load order. + +An example of a custom configuration module, and generators for binary +configuration files are found in './samples/coresight'.
-An example of a custom configuration is found in ./samples/coresight. + +Using a Loadable Module +-----------------------
This creates a new configuration that uses the existing built in strobing feature, but provides a different set of presets. @@ -289,6 +299,135 @@ When the module is loaded, then the configuration appears in the configfs file system and is selectable in the same way as the built in configuration described above.
-Configurations can use previously loaded features. The system will ensure -that it is not possible to unload a feature that is currently in use, by -enforcing the unload order as the strict reverse of the load order. +The file 'coresight-cfg-sample.c' contains the configuration and module +initialisation code needed to create the loadable module. + +This will be built alongside the kernel modules if select in KConfig. + + +Using a Binary Configuration File +--------------------------------- + +Building the samples creates the 'coresight-cfg-filegen' program that will +generate a configuration binary 'example1.cscfg' that can be loaded into the +system using configfs. The configuration declared in the source file +'coresight-cfg-filegen.c' is named 'autofdo3' - the name that will be used +once loaded. + +The source files 'coresight-cfg-bufw.h' and 'coresight-cfg-bufw.c' provide a +standard function to convert a configuration declared in 'C' into the correct +binary buffer format. These files can be re-used to create new custom +configurations. + +The program 'coresight-cfg-file-read' can read back and print a configuration +binary. This is built using the reader from the driver code. + +There are additional attributes in the configurations directory - load, unload +and last_load_status that can be used to load and unload configuration +binary files. To load, 'cat' the binary config into the load attribute:: + + $ ls /config/cs-syscfg/configurations/ + autofdo last_load_status load unload + $ cat example1.cscfg > /config/cs-syscfg/configurations/load + $ ls /config/cs-syscfg/configurations/ + autofdo autofdo3 last_load_status load unload + $ cat /config/cs-syscfg/configurations/last_load_status + OK: configuration file loaded (autofdo3). + +To unload, use the same file in the unload attribute:: + + $ cat example1.cscfg > /config/cs-syscfg/configurations/unload + $ cat /config/cs-syscfg/configurations/last_load_status + OK: configuration file unloaded (autofdo3). + ls /config/cs-syscfg/configurations/ + autofdo last_load_status load unload + +The generator and reader programs can also be built directly, separately from +the kernel build by using the 'Makefile.host' file. This allows native binaries +to be created on the host machine rather than cross compiled version for the +target. + + +Binary Configuration File Format +-------------------------------- + +The file format is defined in the source file **coresight-config-file.h** + +The source reader and generator examples produce a binary of this format. + +This arrangement is reproduced below:- + +Overall File structure +~~~~~~~~~~~~~~~~~~~~~~ + +:: + + [cscfg_file_header] // Mandatory + [CONFIG_ELEM] // Optional - one per file, if present, first element in file. + [FEATURE_ELEM]* // Optional - multiple, defined by cscfg_file_header.nr_features + +File is invalid if both [CONFIG_ELEM] and [FEATURE_ELEM] are omitted. + +A file that contains only [FEATURE_ELEM] may be loaded, and the features used +by subsequently loaded files with [CONFIG_ELEM] elements. + +Where [CONFIG_ELEM] is present, then **cscfg_file_header.nr_features** and +**CONFIG_ELEM.nr_feat_refs** must have the same value. + +CONFIG_ELEM element +~~~~~~~~~~~~~~~~~~~ + +:: + + [cscfg_file_elem_header] // header length value to end of feature strings. + [cscfg_file_elem_str] // name of the configuration. + [cscfg_file_elem_str] // description of configuration. + [u16 value](nr_presets) // number of defined presets. + [u32 value](nr_total_params) // total parameters defined by all used features. + [u16 value](nr_feat_refs) // number of features referenced by the configuration + [u64 values] * (nr_presets * nr_total_params) // the preset values. + [cscfg_file_elem_str] * (nr_feat_refs) // the features used in the configurations. + +FEATURE_ELEM element +~~~~~~~~~~~~~~~~~~~~ + +:: + + [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) // flags to associate the feature with a device. + [u16 value](nr_regs) // number of registers. + [u16 value](nr_params) // number of parameters. + [cscfg_regval_desc struct] * (nr_regs) // register definitions + [PARAM_ELEM] * (nr_params) // parameters definitions + +PARAM_ELEM element +~~~~~~~~~~~~~~~~~~ + +:: + + [cscfg_file_elem_str] // parameter name. + [u64 value](param_value] // initial value. + +Additional definitions. +~~~~~~~~~~~~~~~~~~~~~~~ + +The following structures are defined in **coresight-config-file.h** + + * **struct cscfg_file_header** : This structure contains an initial magic number, the total + length of the file, and the number of features in the file. + * **struct cscfg_file_elem_header**: This defines the total length and type of a CONFIG_ELEM + or a FEATURE_ELEM. + * **struct cscfg_file_elem_str**: This defines a string and its length. + +The magic number in cscfg_file_header is defined as two bitfields:: + + [31:8] Fixed magic number to identify file type. + [7:0] Current file format version. + +The following defines determine the maximum overall file size and maximum individual +string size:: + + CSCFG_FILE_MAXSIZE // maximum overall file size. + CSCFG_FILE_STR_MAXSIZE // maximum individual string size.
Hi Mike,
On Tue, Nov 30, 2021 at 10:01:00PM +0000, Mike Leach wrote:
Add documentation covering the configfs updates that allow binary configuration files to be loaded and unloaded via configfs, along with the demonstration programs in samples.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../trace/coresight/coresight-config.rst | 151 +++++++++++++++++- 1 file changed, 145 insertions(+), 6 deletions(-)
diff --git a/Documentation/trace/coresight/coresight-config.rst b/Documentation/trace/coresight/coresight-config.rst index 6d5ffa6f7347..f11def230fab 100644 --- a/Documentation/trace/coresight/coresight-config.rst +++ b/Documentation/trace/coresight/coresight-config.rst @@ -152,7 +152,7 @@ follows:: $ cd configurations/ $ ls
- autofdo
- autofdo last_load_status load unload $ cd autofdo/ $ ls description feature_refs preset1 preset3 preset5 preset7 preset9
@@ -278,9 +278,19 @@ Creating and Loading Custom Configurations
Custom configurations and / or features can be dynamically loaded into the -system by using a loadable module. +system by using a loadable module, or by loading a binary configuration +file in configfs.
+Loaded configurations can use previously loaded features. The system will +ensure that it is not possible to unload a feature that is currently in +use, by enforcing the unload order as the strict reverse of the load order.
+An example of a custom configuration module, and generators for binary +configuration files are found in './samples/coresight'. -An example of a custom configuration is found in ./samples/coresight.
+Using a Loadable Module +----------------------- This creates a new configuration that uses the existing built in strobing feature, but provides a different set of presets. @@ -289,6 +299,135 @@ When the module is loaded, then the configuration appears in the configfs file system and is selectable in the same way as the built in configuration described above. -Configurations can use previously loaded features. The system will ensure -that it is not possible to unload a feature that is currently in use, by -enforcing the unload order as the strict reverse of the load order. +The file 'coresight-cfg-sample.c' contains the configuration and module +initialisation code needed to create the loadable module.
+This will be built alongside the kernel modules if select in KConfig.
+Using a Binary Configuration File +---------------------------------
+Building the samples creates the 'coresight-cfg-filegen' program that will +generate a configuration binary 'example1.cscfg' that can be loaded into the +system using configfs. The configuration declared in the source file +'coresight-cfg-filegen.c' is named 'autofdo3' - the name that will be used +once loaded.
+The source files 'coresight-cfg-bufw.h' and 'coresight-cfg-bufw.c' provide a +standard function to convert a configuration declared in 'C' into the correct +binary buffer format. These files can be re-used to create new custom +configurations.
+The program 'coresight-cfg-file-read' can read back and print a configuration +binary. This is built using the reader from the driver code.
+There are additional attributes in the configurations directory - load, unload +and last_load_status that can be used to load and unload configuration +binary files. To load, 'cat' the binary config into the load attribute::
- $ ls /config/cs-syscfg/configurations/
- autofdo last_load_status load unload
- $ cat example1.cscfg > /config/cs-syscfg/configurations/load
- $ ls /config/cs-syscfg/configurations/
- autofdo autofdo3 last_load_status load unload
- $ cat /config/cs-syscfg/configurations/last_load_status
- OK: configuration file loaded (autofdo3).
+To unload, use the same file in the unload attribute::
- $ cat example1.cscfg > /config/cs-syscfg/configurations/unload
- $ cat /config/cs-syscfg/configurations/last_load_status
- OK: configuration file unloaded (autofdo3).
- ls /config/cs-syscfg/configurations/
- autofdo last_load_status load unload
+The generator and reader programs can also be built directly, separately from +the kernel build by using the 'Makefile.host' file. This allows native binaries +to be created on the host machine rather than cross compiled version for the +target.
+Binary Configuration File Format +--------------------------------
+The file format is defined in the source file **coresight-config-file.h**
+The source reader and generator examples produce a binary of this format.
+This arrangement is reproduced below:-
+Overall File structure +~~~~~~~~~~~~~~~~~~~~~~
+::
- [cscfg_file_header] // Mandatory
- [CONFIG_ELEM] // Optional - one per file, if present, first element in file.
- [FEATURE_ELEM]* // Optional - multiple, defined by cscfg_file_header.nr_features
+File is invalid if both [CONFIG_ELEM] and [FEATURE_ELEM] are omitted.
+A file that contains only [FEATURE_ELEM] may be loaded, and the features used +by subsequently loaded files with [CONFIG_ELEM] elements.
+Where [CONFIG_ELEM] is present, then **cscfg_file_header.nr_features** and +**CONFIG_ELEM.nr_feat_refs** must have the same value.
+CONFIG_ELEM element +~~~~~~~~~~~~~~~~~~~
+::
- [cscfg_file_elem_header] // header length value to end of feature strings.
- [cscfg_file_elem_str] // name of the configuration.
- [cscfg_file_elem_str] // description of configuration.
- [u16 value](nr_presets) // number of defined presets.
- [u32 value](nr_total_params) // total parameters defined by all used features.
- [u16 value](nr_feat_refs) // number of features referenced by the configuration
- [u64 values] * (nr_presets * nr_total_params) // the preset values.
- [cscfg_file_elem_str] * (nr_feat_refs) // the features used in the configurations.
There seems to be a discrepency between the above format and the afdo3 structure definition in sample file coresight-cfg-filegen.c.
More comments to come...
Thanks, Mathieu
+FEATURE_ELEM element +~~~~~~~~~~~~~~~~~~~~
+::
- [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) // flags to associate the feature with a device.
- [u16 value](nr_regs) // number of registers.
- [u16 value](nr_params) // number of parameters.
- [cscfg_regval_desc struct] * (nr_regs) // register definitions
- [PARAM_ELEM] * (nr_params) // parameters definitions
+PARAM_ELEM element +~~~~~~~~~~~~~~~~~~
+::
- [cscfg_file_elem_str] // parameter name.
- [u64 value](param_value] // initial value.
+Additional definitions. +~~~~~~~~~~~~~~~~~~~~~~~
+The following structures are defined in **coresight-config-file.h**
- **struct cscfg_file_header** : This structure contains an initial magic number, the total
- length of the file, and the number of features in the file.
- **struct cscfg_file_elem_header**: This defines the total length and type of a CONFIG_ELEM
- or a FEATURE_ELEM.
- **struct cscfg_file_elem_str**: This defines a string and its length.
+The magic number in cscfg_file_header is defined as two bitfields::
- [31:8] Fixed magic number to identify file type.
- [7:0] Current file format version.
+The following defines determine the maximum overall file size and maximum individual +string size::
- CSCFG_FILE_MAXSIZE // maximum overall file size.
- CSCFG_FILE_STR_MAXSIZE // maximum individual string size.
-- 2.17.1
[...]
+CONFIG_ELEM element +~~~~~~~~~~~~~~~~~~~
+::
- [cscfg_file_elem_header] // header length value to end of feature strings.
- [cscfg_file_elem_str] // name of the configuration.
- [cscfg_file_elem_str] // description of configuration.
- [u16 value](nr_presets) // number of defined presets.
- [u32 value](nr_total_params) // total parameters defined by all used features.
- [u16 value](nr_feat_refs) // number of features referenced by the configuration
- [u64 values] * (nr_presets * nr_total_params) // the preset values.
- [cscfg_file_elem_str] * (nr_feat_refs) // the features used in the configurations.
There seems to be a discrepency between the above format and the afdo3 structure definition in sample file coresight-cfg-filegen.c.
Void that comment - the above and the struct cscfg_config_desc don't have a 1:1 mapping.
More comments to come...
Thanks, Mathieu
+FEATURE_ELEM element +~~~~~~~~~~~~~~~~~~~~
+::
- [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) // flags to associate the feature with a device.
- [u16 value](nr_regs) // number of registers.
- [u16 value](nr_params) // number of parameters.
- [cscfg_regval_desc struct] * (nr_regs) // register definitions
- [PARAM_ELEM] * (nr_params) // parameters definitions
+PARAM_ELEM element +~~~~~~~~~~~~~~~~~~
+::
- [cscfg_file_elem_str] // parameter name.
- [u64 value](param_value] // initial value.
+Additional definitions. +~~~~~~~~~~~~~~~~~~~~~~~
+The following structures are defined in **coresight-config-file.h**
- **struct cscfg_file_header** : This structure contains an initial magic number, the total
- length of the file, and the number of features in the file.
- **struct cscfg_file_elem_header**: This defines the total length and type of a CONFIG_ELEM
- or a FEATURE_ELEM.
- **struct cscfg_file_elem_str**: This defines a string and its length.
+The magic number in cscfg_file_header is defined as two bitfields::
- [31:8] Fixed magic number to identify file type.
- [7:0] Current file format version.
+The following defines determine the maximum overall file size and maximum individual +string size::
- CSCFG_FILE_MAXSIZE // maximum overall file size.
- CSCFG_FILE_STR_MAXSIZE // maximum individual string size.
-- 2.17.1
More comments...
On Tue, Nov 30, 2021 at 10:01:00PM +0000, Mike Leach wrote:
Add documentation covering the configfs updates that allow binary configuration files to be loaded and unloaded via configfs, along with the demonstration programs in samples.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../trace/coresight/coresight-config.rst | 151 +++++++++++++++++- 1 file changed, 145 insertions(+), 6 deletions(-)
diff --git a/Documentation/trace/coresight/coresight-config.rst b/Documentation/trace/coresight/coresight-config.rst index 6d5ffa6f7347..f11def230fab 100644 --- a/Documentation/trace/coresight/coresight-config.rst +++ b/Documentation/trace/coresight/coresight-config.rst @@ -152,7 +152,7 @@ follows:: $ cd configurations/ $ ls
- autofdo
- autofdo last_load_status load unload $ cd autofdo/ $ ls description feature_refs preset1 preset3 preset5 preset7 preset9
@@ -278,9 +278,19 @@ Creating and Loading Custom Configurations
Custom configurations and / or features can be dynamically loaded into the -system by using a loadable module. +system by using a loadable module, or by loading a binary configuration +file in configfs.
+Loaded configurations can use previously loaded features. The system will +ensure that it is not possible to unload a feature that is currently in +use, by enforcing the unload order as the strict reverse of the load order.
+An example of a custom configuration module, and generators for binary +configuration files are found in './samples/coresight'. -An example of a custom configuration is found in ./samples/coresight.
+Using a Loadable Module +----------------------- This creates a new configuration that uses the existing built in strobing feature, but provides a different set of presets. @@ -289,6 +299,135 @@ When the module is loaded, then the configuration appears in the configfs file system and is selectable in the same way as the built in configuration described above. -Configurations can use previously loaded features. The system will ensure -that it is not possible to unload a feature that is currently in use, by -enforcing the unload order as the strict reverse of the load order. +The file 'coresight-cfg-sample.c' contains the configuration and module +initialisation code needed to create the loadable module.
+This will be built alongside the kernel modules if select in KConfig.
+Using a Binary Configuration File +---------------------------------
+Building the samples creates the 'coresight-cfg-filegen' program that will +generate a configuration binary 'example1.cscfg' that can be loaded into the +system using configfs. The configuration declared in the source file +'coresight-cfg-filegen.c' is named 'autofdo3' - the name that will be used +once loaded.
+The source files 'coresight-cfg-bufw.h' and 'coresight-cfg-bufw.c' provide a +standard function to convert a configuration declared in 'C' into the correct +binary buffer format. These files can be re-used to create new custom +configurations.
+The program 'coresight-cfg-file-read' can read back and print a configuration +binary. This is built using the reader from the driver code.
+There are additional attributes in the configurations directory - load, unload +and last_load_status that can be used to load and unload configuration +binary files. To load, 'cat' the binary config into the load attribute::
- $ ls /config/cs-syscfg/configurations/
- autofdo last_load_status load unload
- $ cat example1.cscfg > /config/cs-syscfg/configurations/load
- $ ls /config/cs-syscfg/configurations/
- autofdo autofdo3 last_load_status load unload
- $ cat /config/cs-syscfg/configurations/last_load_status
- OK: configuration file loaded (autofdo3).
+To unload, use the same file in the unload attribute::
- $ cat example1.cscfg > /config/cs-syscfg/configurations/unload
- $ cat /config/cs-syscfg/configurations/last_load_status
- OK: configuration file unloaded (autofdo3).
- ls /config/cs-syscfg/configurations/
- autofdo last_load_status load unload
I'm not certain that "last_load_status" is needed. To me seeing the name of a newly added configuration should be enough to confirm a successful status. The same applies to unload.
Thanks, Mathieu
+The generator and reader programs can also be built directly, separately from +the kernel build by using the 'Makefile.host' file. This allows native binaries +to be created on the host machine rather than cross compiled version for the +target.
+Binary Configuration File Format +--------------------------------
+The file format is defined in the source file **coresight-config-file.h**
+The source reader and generator examples produce a binary of this format.
+This arrangement is reproduced below:-
+Overall File structure +~~~~~~~~~~~~~~~~~~~~~~
+::
- [cscfg_file_header] // Mandatory
- [CONFIG_ELEM] // Optional - one per file, if present, first element in file.
- [FEATURE_ELEM]* // Optional - multiple, defined by cscfg_file_header.nr_features
+File is invalid if both [CONFIG_ELEM] and [FEATURE_ELEM] are omitted.
+A file that contains only [FEATURE_ELEM] may be loaded, and the features used +by subsequently loaded files with [CONFIG_ELEM] elements.
+Where [CONFIG_ELEM] is present, then **cscfg_file_header.nr_features** and +**CONFIG_ELEM.nr_feat_refs** must have the same value.
+CONFIG_ELEM element +~~~~~~~~~~~~~~~~~~~
+::
- [cscfg_file_elem_header] // header length value to end of feature strings.
- [cscfg_file_elem_str] // name of the configuration.
- [cscfg_file_elem_str] // description of configuration.
- [u16 value](nr_presets) // number of defined presets.
- [u32 value](nr_total_params) // total parameters defined by all used features.
- [u16 value](nr_feat_refs) // number of features referenced by the configuration
- [u64 values] * (nr_presets * nr_total_params) // the preset values.
- [cscfg_file_elem_str] * (nr_feat_refs) // the features used in the configurations.
+FEATURE_ELEM element +~~~~~~~~~~~~~~~~~~~~
+::
- [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) // flags to associate the feature with a device.
- [u16 value](nr_regs) // number of registers.
- [u16 value](nr_params) // number of parameters.
- [cscfg_regval_desc struct] * (nr_regs) // register definitions
- [PARAM_ELEM] * (nr_params) // parameters definitions
+PARAM_ELEM element +~~~~~~~~~~~~~~~~~~
+::
- [cscfg_file_elem_str] // parameter name.
- [u64 value](param_value] // initial value.
+Additional definitions. +~~~~~~~~~~~~~~~~~~~~~~~
+The following structures are defined in **coresight-config-file.h**
- **struct cscfg_file_header** : This structure contains an initial magic number, the total
- length of the file, and the number of features in the file.
- **struct cscfg_file_elem_header**: This defines the total length and type of a CONFIG_ELEM
- or a FEATURE_ELEM.
- **struct cscfg_file_elem_str**: This defines a string and its length.
+The magic number in cscfg_file_header is defined as two bitfields::
- [31:8] Fixed magic number to identify file type.
- [7:0] Current file format version.
+The following defines determine the maximum overall file size and maximum individual +string size::
- CSCFG_FILE_MAXSIZE // maximum overall file size.
- CSCFG_FILE_STR_MAXSIZE // maximum individual string size.
-- 2.17.1
Hi Mathieu,
On Thu, 13 Jan 2022 at 18:16, Mathieu Poirier mathieu.poirier@linaro.org wrote:
More comments...
On Tue, Nov 30, 2021 at 10:01:00PM +0000, Mike Leach wrote:
Add documentation covering the configfs updates that allow binary configuration files to be loaded and unloaded via configfs, along with the demonstration programs in samples.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../trace/coresight/coresight-config.rst | 151 +++++++++++++++++- 1 file changed, 145 insertions(+), 6 deletions(-)
diff --git a/Documentation/trace/coresight/coresight-config.rst b/Documentation/trace/coresight/coresight-config.rst index 6d5ffa6f7347..f11def230fab 100644 --- a/Documentation/trace/coresight/coresight-config.rst +++ b/Documentation/trace/coresight/coresight-config.rst @@ -152,7 +152,7 @@ follows::
$ cd configurations/ $ ls
- autofdo
- autofdo last_load_status load unload $ cd autofdo/ $ ls description feature_refs preset1 preset3 preset5 preset7 preset9
@@ -278,9 +278,19 @@ Creating and Loading Custom Configurations
Custom configurations and / or features can be dynamically loaded into the -system by using a loadable module. +system by using a loadable module, or by loading a binary configuration +file in configfs.
+Loaded configurations can use previously loaded features. The system will +ensure that it is not possible to unload a feature that is currently in +use, by enforcing the unload order as the strict reverse of the load order.
+An example of a custom configuration module, and generators for binary +configuration files are found in './samples/coresight'.
-An example of a custom configuration is found in ./samples/coresight.
+Using a Loadable Module +-----------------------
This creates a new configuration that uses the existing built in strobing feature, but provides a different set of presets. @@ -289,6 +299,135 @@ When the module is loaded, then the configuration appears in the configfs file system and is selectable in the same way as the built in configuration described above.
-Configurations can use previously loaded features. The system will ensure -that it is not possible to unload a feature that is currently in use, by -enforcing the unload order as the strict reverse of the load order. +The file 'coresight-cfg-sample.c' contains the configuration and module +initialisation code needed to create the loadable module.
+This will be built alongside the kernel modules if select in KConfig.
+Using a Binary Configuration File +---------------------------------
+Building the samples creates the 'coresight-cfg-filegen' program that will +generate a configuration binary 'example1.cscfg' that can be loaded into the +system using configfs. The configuration declared in the source file +'coresight-cfg-filegen.c' is named 'autofdo3' - the name that will be used +once loaded.
+The source files 'coresight-cfg-bufw.h' and 'coresight-cfg-bufw.c' provide a +standard function to convert a configuration declared in 'C' into the correct +binary buffer format. These files can be re-used to create new custom +configurations.
+The program 'coresight-cfg-file-read' can read back and print a configuration +binary. This is built using the reader from the driver code.
+There are additional attributes in the configurations directory - load, unload +and last_load_status that can be used to load and unload configuration +binary files. To load, 'cat' the binary config into the load attribute::
- $ ls /config/cs-syscfg/configurations/
- autofdo last_load_status load unload
- $ cat example1.cscfg > /config/cs-syscfg/configurations/load
- $ ls /config/cs-syscfg/configurations/
- autofdo autofdo3 last_load_status load unload
- $ cat /config/cs-syscfg/configurations/last_load_status
- OK: configuration file loaded (autofdo3).
+To unload, use the same file in the unload attribute::
- $ cat example1.cscfg > /config/cs-syscfg/configurations/unload
- $ cat /config/cs-syscfg/configurations/last_load_status
- OK: configuration file unloaded (autofdo3).
- ls /config/cs-syscfg/configurations/
- autofdo last_load_status load unload
I'm not certain that "last_load_status" is needed. To me seeing the name of a newly added configuration should be enough to confirm a successful status. The same applies to unload.
Again - this makes more sense after the next ETM patchset that uses resource management - this status is more useful when features or configurations fail to load - as this can be due to insufficient resources on the system. When we have portable binary configuration files, loading via configfs, then this information is important to users.
Thanks
Mike
Thanks, Mathieu
+The generator and reader programs can also be built directly, separately from +the kernel build by using the 'Makefile.host' file. This allows native binaries +to be created on the host machine rather than cross compiled version for the +target.
+Binary Configuration File Format +--------------------------------
+The file format is defined in the source file **coresight-config-file.h**
+The source reader and generator examples produce a binary of this format.
+This arrangement is reproduced below:-
+Overall File structure +~~~~~~~~~~~~~~~~~~~~~~
+::
- [cscfg_file_header] // Mandatory
- [CONFIG_ELEM] // Optional - one per file, if present, first element in file.
- [FEATURE_ELEM]* // Optional - multiple, defined by cscfg_file_header.nr_features
+File is invalid if both [CONFIG_ELEM] and [FEATURE_ELEM] are omitted.
+A file that contains only [FEATURE_ELEM] may be loaded, and the features used +by subsequently loaded files with [CONFIG_ELEM] elements.
+Where [CONFIG_ELEM] is present, then **cscfg_file_header.nr_features** and +**CONFIG_ELEM.nr_feat_refs** must have the same value.
+CONFIG_ELEM element +~~~~~~~~~~~~~~~~~~~
+::
- [cscfg_file_elem_header] // header length value to end of feature strings.
- [cscfg_file_elem_str] // name of the configuration.
- [cscfg_file_elem_str] // description of configuration.
- [u16 value](nr_presets) // number of defined presets.
- [u32 value](nr_total_params) // total parameters defined by all used features.
- [u16 value](nr_feat_refs) // number of features referenced by the configuration
- [u64 values] * (nr_presets * nr_total_params) // the preset values.
- [cscfg_file_elem_str] * (nr_feat_refs) // the features used in the configurations.
+FEATURE_ELEM element +~~~~~~~~~~~~~~~~~~~~
+::
- [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) // flags to associate the feature with a device.
- [u16 value](nr_regs) // number of registers.
- [u16 value](nr_params) // number of parameters.
- [cscfg_regval_desc struct] * (nr_regs) // register definitions
- [PARAM_ELEM] * (nr_params) // parameters definitions
+PARAM_ELEM element +~~~~~~~~~~~~~~~~~~
+::
- [cscfg_file_elem_str] // parameter name.
- [u64 value](param_value] // initial value.
+Additional definitions. +~~~~~~~~~~~~~~~~~~~~~~~
+The following structures are defined in **coresight-config-file.h**
- **struct cscfg_file_header** : This structure contains an initial magic number, the total
- length of the file, and the number of features in the file.
- **struct cscfg_file_elem_header**: This defines the total length and type of a CONFIG_ELEM
- or a FEATURE_ELEM.
- **struct cscfg_file_elem_str**: This defines a string and its length.
+The magic number in cscfg_file_header is defined as two bitfields::
- [31:8] Fixed magic number to identify file type.
- [7:0] Current file format version.
+The following defines determine the maximum overall file size and maximum individual +string size::
- CSCFG_FILE_MAXSIZE // maximum overall file size.
- CSCFG_FILE_STR_MAXSIZE // maximum individual string size.
-- 2.17.1
Good morning Mike,
On Tue, Nov 30, 2021 at 10:00:54PM +0000, Mike Leach wrote:
This set extends the configfs support to allow loading and unloading of configurations as binary files via configfs.
Additional attributes - load, unload and last_load_status are provided to implement the load functionality.
Routines to generate binary configuration files are supplied in ./samples/coresight.
Example generator and reader applications are provided.
Additional Makefile.host supplied to build the generator and reader applications on the host system separate from a cross compiled kernel.
Documentation is updated to describe feature usage.
Applies and tested on latest coresight/next that includes the previous coresight configuration dynamic load patchset.
I have started to review this set.
Thanks, Mathieu
Changes since v1:
- Rebased to coresight/next - 5.16-rc1 with previous coresight config
set applied. 2) Makefile.host fixed to default to all target.
Mike Leach (6): coresight: configfs: Add in functionality for load via configfs coresight: configfs: Add in binary attributes to load files coresight: configfs: Modify config files to allow userspace use coresight: samples: Add an example config writer for configfs load coresight: samples: Add coresight file reader sample program Documentation: coresight: docs for config load via configfs
.../trace/coresight/coresight-config.rst | 151 +++++- drivers/hwtracing/coresight/Makefile | 2 +- .../coresight/coresight-config-file.c | 472 ++++++++++++++++++ .../coresight/coresight-config-file.h | 158 ++++++ .../hwtracing/coresight/coresight-config.h | 38 ++ .../coresight/coresight-syscfg-configfs.c | 148 +++++- .../coresight/coresight-syscfg-configfs.h | 8 + .../hwtracing/coresight/coresight-syscfg.c | 36 ++ .../hwtracing/coresight/coresight-syscfg.h | 2 + samples/coresight/Makefile | 23 + samples/coresight/Makefile.host | 47 ++ samples/coresight/coresight-cfg-bufw.c | 302 +++++++++++ samples/coresight/coresight-cfg-bufw.h | 24 + samples/coresight/coresight-cfg-file-read.c | 191 +++++++ samples/coresight/coresight-cfg-filegen.c | 89 ++++ 15 files changed, 1677 insertions(+), 14 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config-file.c create mode 100644 drivers/hwtracing/coresight/coresight-config-file.h create mode 100644 samples/coresight/Makefile.host 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-file-read.c create mode 100644 samples/coresight/coresight-cfg-filegen.c
-- 2.17.1