This set extends the configfs support to allow loading and unloading of configurations as binary files via configfs.
Additional attributes - load and unload are provided to in the configurations group to implement the load functionality.
Routines to generate binary configuration files are supplied in ./tools/coresight.
Example generator and reader applications are provided.
Tools may be cross compiled or built for use on host system.
Documentation is updated to describe feature usage.
Changes since v2: 1) Rebased & tested oo coresight/next - 5.18-rc2 2) Moved coresight config generator and reader programs from samples to tools/coresight. Docs updated to match. (suggested by Mathieu) 3) userspace builds now use userspace headers from tools/... 4) Other minor fixes from Mathieu's review.
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 (5): 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: tools: Add config file write and reader tools Documentation: coresight: docs for config load via configfs
.../trace/coresight/coresight-config.rst | 166 +++++- MAINTAINERS | 2 + drivers/hwtracing/coresight/Makefile | 2 +- .../coresight/coresight-config-file.c | 475 ++++++++++++++++++ .../coresight/coresight-config-file.h | 126 +++++ .../hwtracing/coresight/coresight-config.h | 27 + .../coresight/coresight-syscfg-configfs.c | 91 ++++ .../hwtracing/coresight/coresight-syscfg.c | 37 ++ .../hwtracing/coresight/coresight-syscfg.h | 2 + tools/coresight/Makefile | 51 ++ tools/coresight/coresight-cfg-bufw.c | 303 +++++++++++ tools/coresight/coresight-cfg-bufw.h | 26 + tools/coresight/coresight-cfg-example1.c | 65 +++ tools/coresight/coresight-cfg-examples.h | 27 + tools/coresight/coresight-cfg-file-read.c | 197 ++++++++ tools/coresight/coresight-cfg-filegen.c | 58 +++ tools/include/uapi/coresight-config-uapi.h | 76 +++ 17 files changed, 1724 insertions(+), 7 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config-file.c create mode 100644 drivers/hwtracing/coresight/coresight-config-file.h create mode 100644 tools/coresight/Makefile create mode 100644 tools/coresight/coresight-cfg-bufw.c create mode 100644 tools/coresight/coresight-cfg-bufw.h create mode 100644 tools/coresight/coresight-cfg-example1.c create mode 100644 tools/coresight/coresight-cfg-examples.h create mode 100644 tools/coresight/coresight-cfg-file-read.c create mode 100644 tools/coresight/coresight-cfg-filegen.c create mode 100644 tools/include/uapi/coresight-config-uapi.h
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 | 117 +++++ .../hwtracing/coresight/coresight-config.h | 15 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 566 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..591f4c2c4be9 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -0,0 +1,117 @@ +/* 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 2e1670523461..9cd3c26ce023 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -85,6 +85,21 @@ struct cscfg_regval_desc { }; };
+/** + * 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. + * + * @config_descs: array of config descriptor pointers. + * @feat_descs: array of feature descriptor pointers. + */ +struct cscfg_fs_load_descs { + struct cscfg_config_desc **config_descs; + struct cscfg_feature_desc **feat_descs; +}; + /** * Device feature descriptor - combination of registers and parameters to * program a device to implement a specific complex function. 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 day,
On Thu, Apr 14, 2022 at 07:44:53AM +0100, 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 | 117 +++++ .../hwtracing/coresight/coresight-config.h | 15 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 566 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)
As far as I can see @buffer is never incremented, and @elem_str->str_len is the length of the upcoming series of characters in the buffer. As such either this will always reference the start of @buffer and it is a bug or I am missing something very subtle. In the latter case please add a comment to underline what is happening.
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 */
Please add a description of the return behavior. Here I have to correlate with the code in cscfg_file_read_buffer_first_name() that it is not an error to find something else than a CSCFG_FILE_ELEM_TYPE_CFG type.
More comments coming tomorrow.
Thanks, Mathieu
+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..591f4c2c4be9 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -0,0 +1,117 @@ +/* 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 2e1670523461..9cd3c26ce023 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -85,6 +85,21 @@ struct cscfg_regval_desc { }; }; +/**
- 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.
- @config_descs: array of config descriptor pointers.
- @feat_descs: array of feature descriptor pointers.
- */
+struct cscfg_fs_load_descs {
- struct cscfg_config_desc **config_descs;
- struct cscfg_feature_desc **feat_descs;
+};
/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
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,
}; /** -- 2.17.1
Hi Mathieu,
On Wed, 11 May 2022 at 18:58, Mathieu Poirier mathieu.poirier@linaro.org wrote:
Good day,
On Thu, Apr 14, 2022 at 07:44:53AM +0100, 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 | 117 +++++ .../hwtracing/coresight/coresight-config.h | 15 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 566 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)
As far as I can see @buffer is never incremented, and @elem_str->str_len is the length of the upcoming series of characters in the buffer. As such either this will always reference the start of @buffer and it is a bug or I am missing something very subtle. In the latter case please add a comment to underline what is happening.
in the buffer a string consists of u16:len, followed by u8:*len characters - zero terminated. The buffer[len-1] points at what should be the zero terminating character, Must be zero terminated to allow kstrdup to work correctly.
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 */
Please add a description of the return behavior. Here I have to correlate with the code in cscfg_file_read_buffer_first_name() that it is not an error to find something else than a CSCFG_FILE_ELEM_TYPE_CFG type.
Will do.
Thanks
Mike
More comments coming tomorrow.
Thanks, Mathieu
+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..591f4c2c4be9 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -0,0 +1,117 @@ +/* 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 2e1670523461..9cd3c26ce023 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -85,6 +85,21 @@ struct cscfg_regval_desc { }; };
+/**
- 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.
- @config_descs: array of config descriptor pointers.
- @feat_descs: array of feature descriptor pointers.
- */
+struct cscfg_fs_load_descs {
struct cscfg_config_desc **config_descs;
struct cscfg_feature_desc **feat_descs;
+};
/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
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,
};
/**
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
On Thu, Apr 14, 2022 at 07:44:53AM +0100, 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 | 117 +++++ .../hwtracing/coresight/coresight-config.h | 15 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 566 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.
*/
I expected the same kind of check found in cscfg_file_read_elem_config().
I am done with patch, moving on with the rest in the coming days.
Thanks, Mathieu
- 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..591f4c2c4be9 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -0,0 +1,117 @@ +/* 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 2e1670523461..9cd3c26ce023 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -85,6 +85,21 @@ struct cscfg_regval_desc { }; }; +/**
- 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.
- @config_descs: array of config descriptor pointers.
- @feat_descs: array of feature descriptor pointers.
- */
+struct cscfg_fs_load_descs {
- struct cscfg_config_desc **config_descs;
- struct cscfg_feature_desc **feat_descs;
+};
/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
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,
}; /** -- 2.17.1
Good day,
I have resumed working on this patchset. More comments below as I went back while looking at other patches...
On Thu, Apr 14, 2022 at 07:44:53AM +0100, 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 | 117 +++++ .../hwtracing/coresight/coresight-config.h | 15 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 566 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.
I can't remember if I commented on that before but this should likely be 2022, and for all the other files introduced by this patchset.
- 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..591f4c2c4be9 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -0,0 +1,117 @@ +/* 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
s/16384/SZ_16K
Also, please enhance the comment to explain the 16K limit.
+/* limit string sizes */ +#define CSCFG_FILE_STR_MAXSIZE 1024
s/1024/SZ_1K
Thanks, Mathieu
+/**
- 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 2e1670523461..9cd3c26ce023 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -85,6 +85,21 @@ struct cscfg_regval_desc { }; }; +/**
- 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.
- @config_descs: array of config descriptor pointers.
- @feat_descs: array of feature descriptor pointers.
- */
+struct cscfg_fs_load_descs {
- struct cscfg_config_desc **config_descs;
- struct cscfg_feature_desc **feat_descs;
+};
/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
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,
}; /** -- 2.17.1
Hi,
On Wed, 25 May 2022 at 18:38, Mathieu Poirier mathieu.poirier@linaro.org wrote:
Good day,
I have resumed working on this patchset. More comments below as I went back while looking at other patches...
On Thu, Apr 14, 2022 at 07:44:53AM +0100, 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 | 117 +++++ .../hwtracing/coresight/coresight-config.h | 15 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 566 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.
I can't remember if I commented on that before but this should likely be 2022, and for all the other files introduced by this patchset.
- 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..591f4c2c4be9 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -0,0 +1,117 @@ +/* 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
s/16384/SZ_16K
Also, please enhance the comment to explain the 16K limit.
+/* limit string sizes */ +#define CSCFG_FILE_STR_MAXSIZE 1024
s/1024/SZ_1K
Thanks, Mathieu
Done all the above.
Thanks
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 2e1670523461..9cd3c26ce023 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -85,6 +85,21 @@ struct cscfg_regval_desc { }; };
+/**
- 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.
- @config_descs: array of config descriptor pointers.
- @feat_descs: array of feature descriptor pointers.
- */
+struct cscfg_fs_load_descs {
struct cscfg_config_desc **config_descs;
struct cscfg_feature_desc **feat_descs;
+};
/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
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,
};
/**
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
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 | 9 ++ .../coresight/coresight-syscfg-configfs.c | 91 +++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.c | 37 ++++++++ .../hwtracing/coresight/coresight-syscfg.h | 1 + 4 files changed, 138 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h index 591f4c2c4be9..f85cf1aabf56 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.h +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -7,6 +7,8 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_FILE_H #define _CORESIGHT_CORESIGHT_CONFIG_FILE_H
+#include "coresight-config.h" + /* * Structures to represent configuration descriptors in a memory buffer * to serialise to and from files @@ -114,4 +116,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..d1ddcba10ad8 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,10 +381,100 @@ 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_load_descs *load_descs = 0; + struct cscfg_load_owner_info *owner_info = 0; + int err = 0; + + if (size > CSCFG_FILE_MAXSIZE) { + pr_err("cscfg: 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; + } + + owner_info->owner_handle = load_descs; + owner_info->type = CSCFG_OWNER_CONFIGFS; + + err = cscfg_file_read_buffer(buffer, size, load_descs); + if (err) { + pr_err("cscfg: 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) { + pr_err("cscfg: Load error - Failed to load configuaration file.\n"); + goto exit_memfree; + } + + 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_load_owner_info *owner_info = 0; + const char *name; + int err; + + if (size > CSCFG_FILE_MAXSIZE) { + pr_err("cscfg: Unload error - Input file too large\n"); + return -EINVAL; + } + + err = cscfg_file_read_buffer_first_name(buffer, size, &name); + if (err) { + pr_err("cscfg: Unload error - Failed to read input file\n"); + return err; + } + + owner_info = cscfg_find_fs_owned_cfg_by_name(name); + if (!owner_info) { + pr_err("cscfg: Unload error: Failed to find configuration %s from input file\n", + name); + return err; + } + err = cscfg_unload_config_sets(owner_info); + if (err) { + pr_err("cscfg: Unload error: Cannot unload configuration %s\n", + name); + return err; + } + + kfree(owner_info); + kfree((struct cscfg_fs_load_descs *)(owner_info->owner_handle)); + return size; +} +CONFIGFS_BIN_ATTR_WO(cscfg_cfg_, unload, NULL, CSCFG_FILE_MAXSIZE); + +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, };
+/* group for configurations dir, with load and unload attribs */ static struct config_group cscfg_configs_grp = { .cg_item = { .ci_namebuf = "configurations", diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 11850fd8c3b5..2e478b3e8c8d 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -587,6 +587,43 @@ 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_load_owner_info *cscfg_find_fs_owned_cfg_by_name(const char *name) +{ + struct cscfg_load_owner_info *owner_info = NULL; + struct cscfg_fs_load_descs *fs_load_cfg; + 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; + } + } + } + + /* not found */ + owner_info = NULL; + +exit_unlock: + mutex_unlock(&cscfg_mutex); + return owner_info; +} + /* 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..487d872d931a 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_load_owner_info *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 Thu, Apr 14, 2022 at 07:44:54AM +0100, 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 | 9 ++ .../coresight/coresight-syscfg-configfs.c | 91 +++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.c | 37 ++++++++ .../hwtracing/coresight/coresight-syscfg.h | 1 + 4 files changed, 138 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h index 591f4c2c4be9..f85cf1aabf56 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.h +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -7,6 +7,8 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_FILE_H #define _CORESIGHT_CORESIGHT_CONFIG_FILE_H +#include "coresight-config.h"
/*
- Structures to represent configuration descriptors in a memory buffer
- to serialise to and from files
@@ -114,4 +116,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..d1ddcba10ad8 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,10 +381,100 @@ 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_load_descs *load_descs = 0;
- struct cscfg_load_owner_info *owner_info = 0;
- int err = 0;
- if (size > CSCFG_FILE_MAXSIZE) {
pr_err("cscfg: 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;
- }
- owner_info->owner_handle = load_descs;
- owner_info->type = CSCFG_OWNER_CONFIGFS;
- err = cscfg_file_read_buffer(buffer, size, load_descs);
- if (err) {
pr_err("cscfg: 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) {
pr_err("cscfg: Load error - Failed to load configuaration file.\n");
goto exit_memfree;
- }
- 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_load_owner_info *owner_info = 0;
- const char *name;
- int err;
- if (size > CSCFG_FILE_MAXSIZE) {
pr_err("cscfg: Unload error - Input file too large\n");
return -EINVAL;
- }
- err = cscfg_file_read_buffer_first_name(buffer, size, &name);
- if (err) {
pr_err("cscfg: Unload error - Failed to read input file\n");
return err;
- }
- owner_info = cscfg_find_fs_owned_cfg_by_name(name);
- if (!owner_info) {
pr_err("cscfg: Unload error: Failed to find configuration %s from input file\n",
name);
return err;
Since cscfg_find_fs_owned_cfg_by_name() reads a configuration of feature name, I think the error message should be:
pr_err("cscfg: Unload error: Failed to find %s from input file\n", name);
- }
- err = cscfg_unload_config_sets(owner_info);
- if (err) {
pr_err("cscfg: Unload error: Cannot unload configuration %s\n",
name);
return err;
- }
- kfree(owner_info);
- kfree((struct cscfg_fs_load_descs *)(owner_info->owner_handle));
I think the internal memory for the arrays contained in the cscfg_fs_load_descs structure should be freed explicitly here, especially if they can be up to 16K.
More comments to come later or tomorrow.
Thanks, Mathieu
- return size;
+} +CONFIGFS_BIN_ATTR_WO(cscfg_cfg_, unload, NULL, CSCFG_FILE_MAXSIZE);
+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,
}; +/* group for configurations dir, with load and unload attribs */ static struct config_group cscfg_configs_grp = { .cg_item = { .ci_namebuf = "configurations", diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 11850fd8c3b5..2e478b3e8c8d 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -587,6 +587,43 @@ 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_load_owner_info *cscfg_find_fs_owned_cfg_by_name(const char *name) +{
- struct cscfg_load_owner_info *owner_info = NULL;
- struct cscfg_fs_load_descs *fs_load_cfg;
- 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;
}
}
- }
- /* not found */
- owner_info = NULL;
+exit_unlock:
- mutex_unlock(&cscfg_mutex);
- return owner_info;
+}
/* 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..487d872d931a 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_load_owner_info *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
On Thu, Apr 14, 2022 at 07:44:54AM +0100, 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 | 9 ++ .../coresight/coresight-syscfg-configfs.c | 91 +++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.c | 37 ++++++++ .../hwtracing/coresight/coresight-syscfg.h | 1 + 4 files changed, 138 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h index 591f4c2c4be9..f85cf1aabf56 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.h +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -7,6 +7,8 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_FILE_H #define _CORESIGHT_CORESIGHT_CONFIG_FILE_H +#include "coresight-config.h"
/*
- Structures to represent configuration descriptors in a memory buffer
- to serialise to and from files
@@ -114,4 +116,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..d1ddcba10ad8 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,10 +381,100 @@ 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_load_descs *load_descs = 0;
- struct cscfg_load_owner_info *owner_info = 0;
- int err = 0;
- if (size > CSCFG_FILE_MAXSIZE) {
pr_err("cscfg: 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;
- }
- owner_info->owner_handle = load_descs;
- owner_info->type = CSCFG_OWNER_CONFIGFS;
- err = cscfg_file_read_buffer(buffer, size, load_descs);
- if (err) {
pr_err("cscfg: 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) {
pr_err("cscfg: Load error - Failed to load configuaration file.\n");
goto exit_memfree;
- }
- 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_load_owner_info *owner_info = 0;
- const char *name;
- int err;
- if (size > CSCFG_FILE_MAXSIZE) {
pr_err("cscfg: Unload error - Input file too large\n");
return -EINVAL;
- }
- err = cscfg_file_read_buffer_first_name(buffer, size, &name);
- if (err) {
pr_err("cscfg: Unload error - Failed to read input file\n");
return err;
- }
- owner_info = cscfg_find_fs_owned_cfg_by_name(name);
- if (!owner_info) {
pr_err("cscfg: Unload error: Failed to find configuration %s from input file\n",
name);
return err;
- }
- err = cscfg_unload_config_sets(owner_info);
- if (err) {
pr_err("cscfg: Unload error: Cannot unload configuration %s\n",
name);
return err;
- }
- kfree(owner_info);
- kfree((struct cscfg_fs_load_descs *)(owner_info->owner_handle));
- return size;
+} +CONFIGFS_BIN_ATTR_WO(cscfg_cfg_, unload, NULL, CSCFG_FILE_MAXSIZE);
+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,
I was thinking... Because it is possible to have a configuration file that only has features, wouldn't it make more sense to add the load and unload entries under cs-syscfg rather than cs-syscfg/configuration?
}; +/* group for configurations dir, with load and unload attribs */ static struct config_group cscfg_configs_grp = { .cg_item = { .ci_namebuf = "configurations", diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 11850fd8c3b5..2e478b3e8c8d 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -587,6 +587,43 @@ 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_load_owner_info *cscfg_find_fs_owned_cfg_by_name(const char *name) +{
- struct cscfg_load_owner_info *owner_info = NULL;
- struct cscfg_fs_load_descs *fs_load_cfg;
- 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;
}
}
- }
- /* not found */
- owner_info = NULL;
+exit_unlock:
- mutex_unlock(&cscfg_mutex);
- return owner_info;
+}
/* 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..487d872d931a 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_load_owner_info *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,
previous comments re: freeing up memory actioned.
On Wed, 25 May 2022 at 20:30, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Apr 14, 2022 at 07:44:54AM +0100, 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 | 9 ++ .../coresight/coresight-syscfg-configfs.c | 91 +++++++++++++++++++ .../hwtracing/coresight/coresight-syscfg.c | 37 ++++++++ .../hwtracing/coresight/coresight-syscfg.h | 1 + 4 files changed, 138 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h index 591f4c2c4be9..f85cf1aabf56 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.h +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -7,6 +7,8 @@ #ifndef _CORESIGHT_CORESIGHT_CONFIG_FILE_H #define _CORESIGHT_CORESIGHT_CONFIG_FILE_H
+#include "coresight-config.h"
/*
- Structures to represent configuration descriptors in a memory buffer
- to serialise to and from files
@@ -114,4 +116,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..d1ddcba10ad8 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,10 +381,100 @@ 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_load_descs *load_descs = 0;
struct cscfg_load_owner_info *owner_info = 0;
int err = 0;
if (size > CSCFG_FILE_MAXSIZE) {
pr_err("cscfg: 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;
}
owner_info->owner_handle = load_descs;
owner_info->type = CSCFG_OWNER_CONFIGFS;
err = cscfg_file_read_buffer(buffer, size, load_descs);
if (err) {
pr_err("cscfg: 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) {
pr_err("cscfg: Load error - Failed to load configuaration file.\n");
goto exit_memfree;
}
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_load_owner_info *owner_info = 0;
const char *name;
int err;
if (size > CSCFG_FILE_MAXSIZE) {
pr_err("cscfg: Unload error - Input file too large\n");
return -EINVAL;
}
err = cscfg_file_read_buffer_first_name(buffer, size, &name);
if (err) {
pr_err("cscfg: Unload error - Failed to read input file\n");
return err;
}
owner_info = cscfg_find_fs_owned_cfg_by_name(name);
if (!owner_info) {
pr_err("cscfg: Unload error: Failed to find configuration %s from input file\n",
name);
return err;
}
err = cscfg_unload_config_sets(owner_info);
if (err) {
pr_err("cscfg: Unload error: Cannot unload configuration %s\n",
name);
return err;
}
kfree(owner_info);
kfree((struct cscfg_fs_load_descs *)(owner_info->owner_handle));
return size;
+} +CONFIGFS_BIN_ATTR_WO(cscfg_cfg_, unload, NULL, CSCFG_FILE_MAXSIZE);
+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,
I was thinking... Because it is possible to have a configuration file that only has features, wouldn't it make more sense to add the load and unload entries under cs-syscfg rather than cs-syscfg/configuration?
That is a possibility - though the docs refer to "configuration files" irrespective of what they actually contain, so I think having these in configurations is not too bad.
cs-syscfg is regarded as our subsystem root so treated slightly differently in terms of registration etc in the configfs API. We know we can hang groups (directories) off it, so presumably attributes (files) would be fine too.
Shouldn't be too difficult to try out, and I can easily back out if issues arise.
Thanks
Mike
};
+/* group for configurations dir, with load and unload attribs */ static struct config_group cscfg_configs_grp = { .cg_item = { .ci_namebuf = "configurations", diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 11850fd8c3b5..2e478b3e8c8d 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -587,6 +587,43 @@ 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_load_owner_info *cscfg_find_fs_owned_cfg_by_name(const char *name) +{
struct cscfg_load_owner_info *owner_info = NULL;
struct cscfg_fs_load_descs *fs_load_cfg;
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;
}
}
}
/* not found */
owner_info = NULL;
+exit_unlock:
mutex_unlock(&cscfg_mutex);
return owner_info;
+}
/* 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..487d872d931a 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_load_owner_info *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
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
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 | 95 +++++++++++++------ .../hwtracing/coresight/coresight-config.h | 12 +++ 2 files changed, 80 insertions(+), 27 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c index 3fd001938324..5b8f635ac50e 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.c +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -6,8 +6,57 @@
#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 +129,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 +139,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 +156,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 +188,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 +214,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 +229,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 +308,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 +347,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 +362,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 +440,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.h b/drivers/hwtracing/coresight/coresight-config.h index 9cd3c26ce023..fce74e2fbd0c 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 */ @@ -100,6 +107,10 @@ struct cscfg_fs_load_descs { struct cscfg_feature_desc **feat_descs; };
+ +/* remainder of header is used by the kernel drivers only */ +#ifdef __KERNEL__ + /** * Device feature descriptor - combination of registers and parameters to * program a device to implement a specific complex function. @@ -272,4 +283,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 Thu, Apr 14, 2022 at 07:44:55AM +0100, 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 | 95 +++++++++++++------ .../hwtracing/coresight/coresight-config.h | 12 +++ 2 files changed, 80 insertions(+), 27 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c index 3fd001938324..5b8f635ac50e 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.c +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -6,8 +6,57 @@ #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 +129,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 +139,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;
Now it makes sense.
- 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 +156,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 +188,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 +214,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 +229,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 +308,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 +347,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 +362,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 +440,7 @@ int cscfg_file_read_buffer(const u8 *buffer, const int buflen, if (err) return err; }
- return used;
- return 0;
This belongs in patch 1.
} int cscfg_file_read_buffer_first_name(const u8 *buffer, const int buflen, diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 9cd3c26ce023..fce74e2fbd0c 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 */ @@ -100,6 +107,10 @@ struct cscfg_fs_load_descs { struct cscfg_feature_desc **feat_descs; };
+/* remainder of header is used by the kernel drivers only */ +#ifdef __KERNEL__
/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
@@ -272,4 +283,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.
Add a config file reader and printer. Takes in config files and prints the contents. Uses file reader source from kernel driver.
Signed-off-by: Mike Leach mike.leach@linaro.org --- MAINTAINERS | 2 + .../coresight/coresight-config-file.c | 2 + tools/coresight/Makefile | 51 +++ tools/coresight/coresight-cfg-bufw.c | 303 ++++++++++++++++++ tools/coresight/coresight-cfg-bufw.h | 26 ++ tools/coresight/coresight-cfg-example1.c | 65 ++++ tools/coresight/coresight-cfg-examples.h | 27 ++ tools/coresight/coresight-cfg-file-read.c | 197 ++++++++++++ tools/coresight/coresight-cfg-filegen.c | 58 ++++ tools/include/uapi/coresight-config-uapi.h | 76 +++++ 10 files changed, 807 insertions(+) create mode 100644 tools/coresight/Makefile create mode 100644 tools/coresight/coresight-cfg-bufw.c create mode 100644 tools/coresight/coresight-cfg-bufw.h create mode 100644 tools/coresight/coresight-cfg-example1.c create mode 100644 tools/coresight/coresight-cfg-examples.h create mode 100644 tools/coresight/coresight-cfg-file-read.c create mode 100644 tools/coresight/coresight-cfg-filegen.c create mode 100644 tools/include/uapi/coresight-config-uapi.h
diff --git a/MAINTAINERS b/MAINTAINERS index 61d9f114c37f..4e59486e75b5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1985,6 +1985,8 @@ F: drivers/hwtracing/coresight/* F: include/dt-bindings/arm/coresight-cti-dt.h F: include/linux/coresight* F: samples/coresight/* +F: tools/coresight/* +F: tools/include/uapi/coresight-config-uapi.h F: tools/perf/arch/arm/util/auxtrace.c F: tools/perf/arch/arm/util/cs-etm.c F: tools/perf/arch/arm/util/cs-etm.h diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c index 5b8f635ac50e..4a8b64405d84 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.c +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -36,6 +36,8 @@ static void *cscfg_zalloc(size_t size) #include <string.h> #include <stdlib.h>
+#include "uapi/coresight-config-uapi.h" + static void *cscfg_calloc(size_t num, size_t size) { return calloc(num, size); diff --git a/tools/coresight/Makefile b/tools/coresight/Makefile new file mode 100644 index 000000000000..4004c315d65c --- /dev/null +++ b/tools/coresight/Makefile @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only +include ../scripts/Makefile.include +include ../scripts/Makefile.arch + +# Makefile to build the coresight configuration file reader and generator tools + +this-makefile := $(lastword $(MAKEFILE_LIST)) +tools-src := $(realpath $(dir $(this-makefile))) +srctree := $(realpath $(dir $(tools-src)/../../.)) + +# ensure we use all as the default - skip anything in included Makefile +.DEFAULT_GOAL = all +# MAKECMDGOALS isn't set if there's no explicit goal in the +# command line, so set the default. +MAKECMDGOALS ?= $(.DEFAULT_GOAL) + +# compile flags +CFLAGS += $(CPPFLAGS) -c -Wall -DLINUX -Wno-switch -Wlogical-op -fPIC -I$(srctree)/drivers/hwtracing/coresight -I$(srctree)/tools/include/ -I$(srctree)/tools/include/uapi + +# object files +coresight-cfg-file-gen-objs := coresight-cfg-filegen.o coresight-cfg-bufw.o coresight-cfg-example1.o +coresight-cfg-file-read-objs := coresight-cfg-file-read.o coresight-config-file.o + +# debug variant +ifdef DEBUG +CFLAGS += -g -O0 -DDEBUG +else +CFLAGS += -O2 -DNDEBUG +endif + +.PHONY: all +all: coresight-cfg-file-gen coresight-cfg-file-read + +coresight-config-file.o: src_copy + $(CC) $(CFLAGS) coresight-config-file.c -o coresight-config-file.o + +.PHONY: src_copy +src_copy: + @cp $(srctree)/drivers/hwtracing/coresight/coresight-config-file.c $(srctree)/tools/coresight/. + +coresight-cfg-file-gen: $(coresight-cfg-file-gen-objs) + $(CC) $(LDFLAGS) $(coresight-cfg-file-gen-objs) -o coresight-cfg-file-gen + +coresight-cfg-file-read: $(coresight-cfg-file-read-objs) + $(CC) $(LDFLAGS) $(coresight-cfg-file-read-objs) -o coresight-cfg-file-read + +clean: + rm -f coresight-cfg-file-gen coresight-cfg-file-read + rm -f *.o + rm -f coresight-config-file.c + rm -f *.cscfg diff --git a/tools/coresight/coresight-cfg-bufw.c b/tools/coresight/coresight-cfg-bufw.c new file mode 100644 index 000000000000..73223de2b7e0 --- /dev/null +++ b/tools/coresight/coresight-cfg-bufw.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#include <string.h> + +#include "coresight-cfg-bufw.h" +#include "uapi/coresight-config-uapi.h" + +/* + * Set of macros to make writing the buffer code easier. + *. + * Uses naming convention as 'buffer' for the buffer pointer and + * 'used' as the current bytes used by the encosing function. + */ +#define cscfg_write_u64(val64) { \ + *(u64 *)(buffer + used) = val64; \ + used += sizeof(u64); \ + } + +#define cscfg_write_u32(val32) { \ + *(u32 *)(buffer + used) = val32; \ + used += sizeof(u32); \ + } + +#define cscfg_write_u16(val16) { \ + *(u16 *)(buffer + used) = val16; \ + used += sizeof(u16); \ + } + +#define cscfg_write_u8(val8) { \ + *(buffer + used) = val8; \ + used++; \ + } + +#define CHECK_WRET(rval) { \ + if (rval < 0) \ + return rval; \ + used += rval; \ + } + +/* write the header at the start of the buffer */ +static int cscfg_file_write_fhdr(u8 *buffer, const int buflen, + const struct cscfg_file_header *fhdr) +{ + int used = 0; + + cscfg_write_u32(fhdr->magic_version); + cscfg_write_u16(fhdr->length); + cscfg_write_u16(fhdr->nr_features); + return used; +} + +static int cscfg_file_write_string(u8 *buffer, const int buflen, const char *string) +{ + int len, used = 0; + + len = strlen(string); + if (len > CSCFG_FILE_STR_MAXSIZE) + return -EINVAL; + + if (buflen < (len + 1 + sizeof(u16))) + return -EINVAL; + + cscfg_write_u16((u16)(len + 1)); + strcpy((char *)(buffer + used), string); + used += (len + 1); + + return used; +} + +static int cscfg_file_write_elem_hdr(u8 *buffer, const int buflen, + struct cscfg_file_elem_header *ehdr) +{ + int used = 0; + + if (buflen < (sizeof(u16) + sizeof(u8))) + return -EINVAL; + + cscfg_write_u16(ehdr->elem_length); + cscfg_write_u8(ehdr->elem_type); + + return used; +} + + +static int cscfg_file_write_config(u8 *buffer, const int buflen, + struct cscfg_config_desc *config_desc) +{ + int used = 0, bytes_w, space_req, preset_bytes, i; + struct cscfg_file_elem_header ehdr; + + ehdr.elem_length = 0; + ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_CFG; + + /* write element header at current buffer location */ + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); + CHECK_WRET(bytes_w); + + /* write out the configuration name */ + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, + config_desc->name); + CHECK_WRET(bytes_w); + + /* write out the description string */ + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, + config_desc->description); + CHECK_WRET(bytes_w); + + /* + * calculate the space needed for variables + presets + * [u16 value - nr_presets] + * [u32 value - nr_total_params] + * [u16 value - nr_feat_refs] + * [u64 values] * (nr_presets * nr_total_params) + */ + preset_bytes = sizeof(u64) * config_desc->nr_presets * config_desc->nr_total_params; + space_req = (sizeof(u16) * 2) + sizeof(u32) + preset_bytes; + + if ((buflen - used) < space_req) + return -EINVAL; + + cscfg_write_u16((u16)config_desc->nr_presets); + cscfg_write_u32((u32)config_desc->nr_total_params); + cscfg_write_u16((u16)config_desc->nr_feat_refs); + if (preset_bytes) { + memcpy(buffer + used, (u8 *)config_desc->presets, preset_bytes); + used += preset_bytes; + } + + /* now write the feature ref names */ + for (i = 0; i < config_desc->nr_feat_refs; i++) { + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, + config_desc->feat_ref_names[i]); + CHECK_WRET(bytes_w); + } + + /* rewrite the element header with the correct length */ + ehdr.elem_length = used; + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); + /* no CHECK_WRET as used must not be updated */ + if (bytes_w < 0) + return bytes_w; + + return used; +} + +/* + * write a parameter structure into the buffer in following format: + * [cscfg_file_elem_str] - parameter name. + * [u64 value: param_value] - initial value. + */ +static int cscfg_file_write_param(u8 *buffer, const int buflen, + struct cscfg_parameter_desc *param_desc) +{ + int used = 0, bytes_w; + + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, + param_desc->name); + CHECK_WRET(bytes_w); + + if ((buflen - used) < sizeof(u64)) + return -EINVAL; + + cscfg_write_u64(param_desc->value); + return used; +} +/* + * Write a feature element from cscfg_feature_desc in following format: + * + * [cscfg_file_elem_header] - header length is total bytes to end of param structures. + * [cscfg_file_elem_str] - feature name. + * [cscfg_file_elem_str] - feature description. + * [u32 value: match_flags] + * [u16 value: nr_regs] - number of registers. + * [u16 value: nr_params] - number of parameters. + * [cscfg_regval_desc struct] * nr_regs + * [PARAM_ELEM] * nr_params + * + * + */ +static int cscfg_file_write_feat(u8 *buffer, const int buflen, + struct cscfg_feature_desc *feat_desc) +{ + struct cscfg_file_elem_header ehdr; + struct cscfg_regval_desc *p_reg_desc; + int used = 0, bytes_w, i, space_req; + u32 val32; + + ehdr.elem_length = 0; + ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_FEAT; + + /* write element header at current buffer location */ + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); + CHECK_WRET(bytes_w); + + /* write out the name string */ + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, + feat_desc->name); + CHECK_WRET(bytes_w) + + /* write out the description string */ + bytes_w = cscfg_file_write_string(buffer + used, buflen - used, + feat_desc->description); + CHECK_WRET(bytes_w); + + /* check for space for variables and register structures */ + space_req = (sizeof(u16) * 2) + sizeof(u32) + + (sizeof(struct cscfg_regval_desc) * feat_desc->nr_regs); + if ((buflen - used) < space_req) + return -EINVAL; + + /* write the variables */ + cscfg_write_u32((u32)feat_desc->match_flags); + cscfg_write_u16((u16)feat_desc->nr_regs); + cscfg_write_u16((u16)feat_desc->nr_params); + + /*write the registers */ + for (i = 0; i < feat_desc->nr_regs; i++) { + p_reg_desc = (struct cscfg_regval_desc *)&feat_desc->regs_desc[i]; + CSCFG_FILE_REG_DESC_INFO_TO_U32(val32, p_reg_desc); + cscfg_write_u32(val32); + cscfg_write_u64(feat_desc->regs_desc[i].val64); + } + + /* write any parameters */ + for (i = 0; i < feat_desc->nr_params; i++) { + bytes_w = cscfg_file_write_param(buffer + used, buflen - used, + &feat_desc->params_desc[i]); + CHECK_WRET(bytes_w); + } + + /* + * rewrite the element header at the start of the buffer block + * with the correct length + */ + ehdr.elem_length = used; + bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr); + /* no CHECK_WRET as used must not be updated */ + if (bytes_w < 0) + return bytes_w; + + return used; +} + +/* + * write a buffer from the configuration and feature + * descriptors to write into a file for configfs. + * + * Will only write one config, and/or a number of features, + * per the file standard. + */ +int cscfg_file_write_buffer(u8 *buffer, const int buflen, + struct cscfg_config_desc *config_desc, + struct cscfg_feature_desc **feat_descs) +{ + struct cscfg_file_header fhdr; + int used = 0, bytes_w, i; + + /* init the file header */ + fhdr.magic_version = CSCFG_FILE_MAGIC_VERSION; + fhdr.length = 0; + fhdr.nr_features = 0; + + /* count the features */ + if (feat_descs) { + while (feat_descs[fhdr.nr_features]) + fhdr.nr_features++; + } + + /* need a buffer and at least one config or feature */ + if ((!config_desc && !fhdr.nr_features) || + !buffer || (buflen > CSCFG_FILE_MAXSIZE)) + return -EINVAL; + + /* write a header at the start to get the length of the header */ + bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr); + CHECK_WRET(bytes_w); + + /* write a single config */ + if (config_desc) { + bytes_w = cscfg_file_write_config(buffer + used, buflen - used, + config_desc); + CHECK_WRET(bytes_w); + } + + /* write any features */ + for (i = 0; i < fhdr.nr_features; i++) { + bytes_w = cscfg_file_write_feat(buffer + used, buflen - used, + feat_descs[i]); + CHECK_WRET(bytes_w); + } + + /* finally re-write the header at the buffer start with the correct length */ + fhdr.length = (u16)used; + bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr); + /* no CHECK_WRET as used must not be updated */ + if (bytes_w < 0) + return bytes_w; + return used; +} diff --git a/tools/coresight/coresight-cfg-bufw.h b/tools/coresight/coresight-cfg-bufw.h new file mode 100644 index 000000000000..562df97599fc --- /dev/null +++ b/tools/coresight/coresight-cfg-bufw.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#ifndef _CORESIGHT_CFG_BUFW_H +#define _CORESIGHT_CFG_BUFW_H + +#include <linux/types.h> + +#include "coresight-config-file.h" + +/* + * Function to take coresight configurations and features and + * write them into a supplied memory buffer for serialisation + * into a file. + * + * Resulting file can then be loaded into the coresight + * infrastructure via configfs. + */ +int cscfg_file_write_buffer(u8 *buffer, const int buflen, + struct cscfg_config_desc *config_desc, + struct cscfg_feature_desc **feat_descs); + +#endif /* _CORESIGHT_CFG_BUFW_H */ diff --git a/tools/coresight/coresight-cfg-example1.c b/tools/coresight/coresight-cfg-example1.c new file mode 100644 index 000000000000..a71a6e43d7b3 --- /dev/null +++ b/tools/coresight/coresight-cfg-example1.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ +#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <unistd.h> + +#include "coresight-cfg-bufw.h" +#include "coresight-cfg-examples.h" + +/* + * create a configuration only example using the strobing feature + */ + +/* we will provide 4 sets of preset parameter values */ +#define AFDO3_NR_PRESETS 4 +/* the total number of parameters in used features - strobing has 2 */ +#define AFDO3_NR_PARAM_SUM 2 + +static const char *afdo3_ref_names[] = { + "strobing", +}; + +/* + * set of presets leaves strobing window constant while varying period to allow + * experimentation with mark / space ratios for various workloads + */ +static u64 afdo3_presets[AFDO3_NR_PRESETS][AFDO3_NR_PARAM_SUM] = { + { 2000, 100 }, + { 2000, 1000 }, + { 2000, 5000 }, + { 2000, 10000 }, +}; + +struct cscfg_config_desc afdo3 = { + .name = "autofdo3", + .description = "Setup ETMs with strobing for autofdo\n" + "Supplied presets allow experimentation with mark-space ratio for various loads\n", + .nr_feat_refs = ARRAY_SIZE(afdo3_ref_names), + .feat_ref_names = afdo3_ref_names, + .nr_presets = AFDO3_NR_PRESETS, + .nr_total_params = AFDO3_NR_PARAM_SUM, + .presets = &afdo3_presets[0][0], +}; + +static struct cscfg_feature_desc *sample_feats[] = { + NULL +}; + +static struct cscfg_config_desc *sample_cfgs[] = { + &afdo3, + NULL +}; + +#define CSCFG_EG1_FILENAME "example1.cscfg" + +struct cscfg_file_eg_info buff_info_eg1 = { + .example_name = "example1", + .filename = CSCFG_EG1_FILENAME, + .config_descs = sample_cfgs, + .feat_descs = sample_feats, +}; diff --git a/tools/coresight/coresight-cfg-examples.h b/tools/coresight/coresight-cfg-examples.h new file mode 100644 index 000000000000..5c6908745201 --- /dev/null +++ b/tools/coresight/coresight-cfg-examples.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#ifndef _CORESIGHT_CFG_EXAMPLES_H +#define _CORESIGHT_CFG_EXAMPLES_H + +#include <linux/kernel.h> + +#include "uapi/coresight-config-uapi.h" +#include "coresight-cfg-bufw.h" + +/* structure to pass configuraiton information to generator program */ +struct cscfg_file_eg_info { + const char *example_name; + const char *filename; + struct cscfg_config_desc **config_descs; + struct cscfg_feature_desc **feat_descs; +}; + + +/* references to the configuration and feature example structures */ +extern struct cscfg_file_eg_info buff_info_eg1; + +#endif /* _CORESIGHT_CFG_EXAMPLES_H */ diff --git a/tools/coresight/coresight-cfg-file-read.c b/tools/coresight/coresight-cfg-file-read.c new file mode 100644 index 000000000000..da7b831eb2df --- /dev/null +++ b/tools/coresight/coresight-cfg-file-read.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "coresight-config-file.h" +#include "uapi/coresight-config-uapi.h" + +/* + * tool to read and print a generated configuration + * re-uses the read code source from the driver. + */ + +static void print_configs(struct cscfg_fs_load_descs *load_descs) +{ + struct cscfg_config_desc *config_desc = load_descs->config_descs[0]; + int i, j, p; + + if (!config_desc) { + printf("File contains no configurations.\n\n"); + return; + } + + printf("Configuration name : %s\n", config_desc->name); + printf("Uses %d features:-\n", config_desc->nr_feat_refs); + for (i = 0; i < config_desc->nr_feat_refs; i++) + printf("Feature-%d: %s\n", i + 1, config_desc->feat_ref_names[i]); + + printf("\nProvides %d sets of preset values, %d presets per set\n", config_desc->nr_presets, + config_desc->nr_total_params); + if (config_desc->nr_presets) { + for (i = 0; i < config_desc->nr_presets; i++) { + printf("set[%d]: ", i); + for (j = 0; j < config_desc->nr_total_params; j++) { + p = (i * config_desc->nr_total_params) + j; + printf("0x%lx, ", config_desc->presets[p]); + } + printf("\n"); + } + } + printf("\n\n"); +} + +static void print_reg_type_info(u8 type) +{ + if (type & CS_CFG_REG_TYPE_STD) + printf("std_reg "); + if (type & CS_CFG_REG_TYPE_RESOURCE) + printf("resource "); + if (type & CS_CFG_REG_TYPE_VAL_PARAM) + printf("param_index "); + if (type & CS_CFG_REG_TYPE_VAL_64BIT) + printf("64_bit "); + else + printf("32_bit "); + if (type & CS_CFG_REG_TYPE_VAL_MASK) + printf("masked "); + if (type & CS_CFG_REG_TYPE_VAL_SAVE) + printf("save_on_disable "); + +} + +static void print_regs(int nr, struct cscfg_regval_desc *regs_desc_array) +{ + int i; + struct cscfg_regval_desc *reg_desc; + u8 type; + u16 offset; + u16 info; + + for (i = 0; i < nr; i++) { + reg_desc = ®s_desc_array[i]; + type = (u8)reg_desc->type; + offset = (u16)reg_desc->offset; + info = (u16)reg_desc->hw_info; + + printf("Reg(%d): Type 0x%x: ", i, type); + print_reg_type_info(type); + printf("\nOffset: 0x%03x; HW Info: 0x%03x\n", offset, info); + printf("Value: "); + if (type & CS_CFG_REG_TYPE_VAL_64BIT) + printf("0x%lx\n", reg_desc->val64); + else if (type & CS_CFG_REG_TYPE_VAL_PARAM) + printf("idx = %d\n", reg_desc->param_idx); + else { + printf("0x%x ", reg_desc->val32); + if (type & CS_CFG_REG_TYPE_VAL_MASK) + printf(" mask: 0x%x", reg_desc->mask32); + printf("\n"); + } + } +} + +static void print_params(int nr, struct cscfg_parameter_desc *params_desc) +{ + int i; + + for (i = 0; i < nr; i++) + printf("Param(%d) : %s; Init value 0x%lx\n", i, + params_desc[i].name, params_desc[i].value); +} + +static void print_features(struct cscfg_fs_load_descs *load_descs) +{ + struct cscfg_feature_desc *feat_desc = 0; + int idx = 0; + + feat_desc = load_descs->feat_descs[idx]; + if (!feat_desc) { + printf("File contains no features\n\n"); + return; + } + + while (feat_desc) { + printf("Feature %d name : %s\n", idx+1, feat_desc->name); + printf("Description: %s\n", feat_desc->description); + printf("Match flags: 0x%x\n", feat_desc->match_flags); + printf("Number of Paraneters: %d\n", feat_desc->nr_params); + if (feat_desc->nr_params) + print_params(feat_desc->nr_params, feat_desc->params_desc); + printf("Number of Registers: %d\n", feat_desc->nr_regs); + if (feat_desc->nr_regs) + print_regs(feat_desc->nr_regs, feat_desc->regs_desc); + printf("\n\n"); + + /* next feature */ + idx++; + feat_desc = load_descs->feat_descs[idx]; + } +} + +int main(int argc, char **argv) +{ + FILE *fp; + struct cscfg_fs_load_descs *load_descs; + int err, fsize; + u8 buffer[CSCFG_FILE_MAXSIZE]; + + printf("CoreSight Configuration file reader\n\n"); + + /* need a filename */ + if (argc <= 1) { + printf("Please provide filename on command line\n"); + return -EINVAL; + } + + /* open file and read into the buffer. */ + fp = fopen(argv[1], "rb"); + if (fp == NULL) { + printf("Error opening file %s\n", argv[1]); + return -EINVAL; + } + + fseek(fp, 0, SEEK_END); + fsize = ftell(fp); + rewind(fp); + if (fsize > CSCFG_FILE_MAXSIZE) { + printf("Error: Input file too large."); + fclose(fp); + return -EINVAL; + } + err = fread(buffer, sizeof(u8), fsize, fp); + fclose(fp); + + if (err < fsize) { + printf("Error reading file %s\n", argv[1]); + return -EINVAL; + } + + /* allocate the descriptor structures to be populated by read operation */ + load_descs = malloc(sizeof(struct cscfg_fs_load_descs)); + if (!load_descs) { + printf("Error allocating load descs structure.\n"); + return -ENOMEM; + } + + /* read the buffer and create the configuration and feature structures */ + err = cscfg_file_read_buffer(buffer, fsize, load_descs); + if (err) { + printf("Error reading configuration file\n"); + goto exit_free_mem; + } + /* print the contents of the structures */ + print_configs(load_descs); + print_features(load_descs); + +exit_free_mem: + free(load_descs); + return err; +} diff --git a/tools/coresight/coresight-cfg-filegen.c b/tools/coresight/coresight-cfg-filegen.c new file mode 100644 index 000000000000..cd0589661d92 --- /dev/null +++ b/tools/coresight/coresight-cfg-filegen.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <unistd.h> + +#include "uapi/coresight-config-uapi.h" +#include "coresight-cfg-bufw.h" +#include "coresight-cfg-examples.h" + + +/* array of example files to generate */ +struct cscfg_file_eg_info *info_ptrs[] = { + &buff_info_eg1, + NULL, +}; + +int main(int argc, char **argv) +{ + struct cscfg_config_desc *config_desc; + struct cscfg_feature_desc **feat_descs; + u8 buffer[CSCFG_FILE_MAXSIZE]; + int used, idx = 0; + FILE *fp; + const char *filename; + + printf("Coresight Configuration file Generator\n\n"); + + while (info_ptrs[idx]) { + printf("Generating %s example\n", info_ptrs[idx]->example_name); + config_desc = info_ptrs[idx]->config_descs[0]; + feat_descs = info_ptrs[idx]->feat_descs; + filename = info_ptrs[idx]->filename; + used = cscfg_file_write_buffer(buffer, CSCFG_FILE_MAXSIZE, + config_desc, feat_descs); + + if (used < 0) { + printf("Error %d writing configuration %s into buffer\n", + used, info_ptrs[idx]->example_name); + return used; + } + + fp = fopen(filename, "wb"); + if (fp == NULL) { + printf("Error opening file %s\n", filename); + return -1; + } + fwrite(buffer, used, sizeof(u8), fp); + fclose(fp); + idx++; + } + return 0; +} diff --git a/tools/include/uapi/coresight-config-uapi.h b/tools/include/uapi/coresight-config-uapi.h new file mode 100644 index 000000000000..d051c01ea982 --- /dev/null +++ b/tools/include/uapi/coresight-config-uapi.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach mike.leach@linaro.org + */ + +#ifndef _CORESIGHT_CORESIGHT_CONFIG_UAPI_H +#define _CORESIGHT_CORESIGHT_CONFIG_UAPI_H + +#include <linux/types.h> +#include <asm-generic/errno-base.h> + +#include "coresight-config.h" + +/* + * Userspace versions of the configuration and feature descriptors. + * Used in the tools/coresight programs. + * + * Compatible with structures in coresight-config.h for use in + * coresight-config-file.c common reader source file. + */ + +/** + * Device feature descriptor - combination of registers and parameters to + * program a device to implement a specific complex function. + * + * UAPI version - removed kernel constructs. + * + * @name: feature name. + * @description: brief description of the feature. + * @match_flags: matching information if loading into a device + * @nr_params: number of parameters used. + * @params_desc: array of parameters used. + * @nr_regs: number of registers used. + * @regs_desc: array of registers used. + */ +struct cscfg_feature_desc { + const char *name; + const char *description; + u32 match_flags; + int nr_params; + struct cscfg_parameter_desc *params_desc; + int nr_regs; + struct cscfg_regval_desc *regs_desc; +}; + +/** + * Configuration descriptor - describes selectable system configuration. + * + * A configuration describes device features in use, and may provide preset + * values for the parameters in those features. + * + * A single set of presets is the sum of the parameters declared by + * all the features in use - this value is @nr_total_params. + * + * UAPI version - removed kernel constructs. + * + * @name: name of the configuration - used for selection. + * @description: description of the purpose of the configuration. + * @nr_feat_refs: Number of features used in this configuration. + * @feat_ref_names: references to features used in this configuration. + * @nr_presets: Number of sets of presets supplied by this configuration. + * @nr_total_params: Sum of all parameters declared by used features + * @presets: Array of preset values. + */ +struct cscfg_config_desc { + const char *name; + const char *description; + int nr_feat_refs; + const char **feat_ref_names; + int nr_presets; + int nr_total_params; + const u64 *presets; /* nr_presets * nr_total_params */ +}; + +#endif /* _CORESIGHT_CORESIGHT_CONFIG_UAPI_H */
On Thu, Apr 14, 2022 at 07:44:56AM +0100, Mike Leach wrote:
Add an example file generator to test loading configurations via a binary attribute in configfs.
Provides a file buffer writer function that can be re-used in other userspace programs.
Buffer write format matches that expected by the corresponding reader in the configfs driver code.
Add a config file reader and printer. Takes in config files and prints the contents. Uses file reader source from kernel driver.
Signed-off-by: Mike Leach mike.leach@linaro.org
MAINTAINERS | 2 + .../coresight/coresight-config-file.c | 2 + tools/coresight/Makefile | 51 +++ tools/coresight/coresight-cfg-bufw.c | 303 ++++++++++++++++++ tools/coresight/coresight-cfg-bufw.h | 26 ++ tools/coresight/coresight-cfg-example1.c | 65 ++++ tools/coresight/coresight-cfg-examples.h | 27 ++ tools/coresight/coresight-cfg-file-read.c | 197 ++++++++++++ tools/coresight/coresight-cfg-filegen.c | 58 ++++ tools/include/uapi/coresight-config-uapi.h | 76 +++++ 10 files changed, 807 insertions(+) create mode 100644 tools/coresight/Makefile create mode 100644 tools/coresight/coresight-cfg-bufw.c create mode 100644 tools/coresight/coresight-cfg-bufw.h create mode 100644 tools/coresight/coresight-cfg-example1.c create mode 100644 tools/coresight/coresight-cfg-examples.h create mode 100644 tools/coresight/coresight-cfg-file-read.c create mode 100644 tools/coresight/coresight-cfg-filegen.c create mode 100644 tools/include/uapi/coresight-config-uapi.h
diff --git a/MAINTAINERS b/MAINTAINERS index 61d9f114c37f..4e59486e75b5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1985,6 +1985,8 @@ F: drivers/hwtracing/coresight/* F: include/dt-bindings/arm/coresight-cti-dt.h F: include/linux/coresight* F: samples/coresight/* +F: tools/coresight/* +F: tools/include/uapi/coresight-config-uapi.h F: tools/perf/arch/arm/util/auxtrace.c F: tools/perf/arch/arm/util/cs-etm.c F: tools/perf/arch/arm/util/cs-etm.h diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c index 5b8f635ac50e..4a8b64405d84 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.c +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -36,6 +36,8 @@ static void *cscfg_zalloc(size_t size) #include <string.h> #include <stdlib.h> +#include "uapi/coresight-config-uapi.h"
static void *cscfg_calloc(size_t num, size_t size) { return calloc(num, size); diff --git a/tools/coresight/Makefile b/tools/coresight/Makefile new file mode 100644 index 000000000000..4004c315d65c --- /dev/null +++ b/tools/coresight/Makefile @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only +include ../scripts/Makefile.include +include ../scripts/Makefile.arch
+# Makefile to build the coresight configuration file reader and generator tools
+this-makefile := $(lastword $(MAKEFILE_LIST)) +tools-src := $(realpath $(dir $(this-makefile))) +srctree := $(realpath $(dir $(tools-src)/../../.))
+# ensure we use all as the default - skip anything in included Makefile +.DEFAULT_GOAL = all +# MAKECMDGOALS isn't set if there's no explicit goal in the +# command line, so set the default. +MAKECMDGOALS ?= $(.DEFAULT_GOAL)
+# compile flags +CFLAGS += $(CPPFLAGS) -c -Wall -DLINUX -Wno-switch -Wlogical-op -fPIC -I$(srctree)/drivers/hwtracing/coresight -I$(srctree)/tools/include/ -I$(srctree)/tools/include/uapi
+# object files +coresight-cfg-file-gen-objs := coresight-cfg-filegen.o coresight-cfg-bufw.o coresight-cfg-example1.o +coresight-cfg-file-read-objs := coresight-cfg-file-read.o coresight-config-file.o
+# debug variant +ifdef DEBUG +CFLAGS += -g -O0 -DDEBUG +else +CFLAGS += -O2 -DNDEBUG +endif
+.PHONY: all +all: coresight-cfg-file-gen coresight-cfg-file-read
+coresight-config-file.o: src_copy
- $(CC) $(CFLAGS) coresight-config-file.c -o coresight-config-file.o
+.PHONY: src_copy +src_copy:
- @cp $(srctree)/drivers/hwtracing/coresight/coresight-config-file.c $(srctree)/tools/coresight/.
+coresight-cfg-file-gen: $(coresight-cfg-file-gen-objs)
- $(CC) $(LDFLAGS) $(coresight-cfg-file-gen-objs) -o coresight-cfg-file-gen
+coresight-cfg-file-read: $(coresight-cfg-file-read-objs)
- $(CC) $(LDFLAGS) $(coresight-cfg-file-read-objs) -o coresight-cfg-file-read
+clean:
- rm -f coresight-cfg-file-gen coresight-cfg-file-read
- rm -f *.o
- rm -f coresight-config-file.c
- rm -f *.cscfg
diff --git a/tools/coresight/coresight-cfg-bufw.c b/tools/coresight/coresight-cfg-bufw.c new file mode 100644 index 000000000000..73223de2b7e0 --- /dev/null +++ b/tools/coresight/coresight-cfg-bufw.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <string.h>
+#include "coresight-cfg-bufw.h" +#include "uapi/coresight-config-uapi.h"
+/*
- Set of macros to make writing the buffer code easier.
- *.
- Uses naming convention as 'buffer' for the buffer pointer and
- 'used' as the current bytes used by the encosing function.
- */
+#define cscfg_write_u64(val64) { \
- *(u64 *)(buffer + used) = val64; \
- used += sizeof(u64); \
- }
+#define cscfg_write_u32(val32) { \
- *(u32 *)(buffer + used) = val32; \
- used += sizeof(u32); \
- }
+#define cscfg_write_u16(val16) { \
- *(u16 *)(buffer + used) = val16; \
- used += sizeof(u16); \
- }
+#define cscfg_write_u8(val8) { \
- *(buffer + used) = val8; \
- used++; \
- }
+#define CHECK_WRET(rval) { \
- if (rval < 0) \
return rval; \
- used += rval; \
- }
Either use a single space between the code and the '' character or align them all on the same column.
+/* write the header at the start of the buffer */ +static int cscfg_file_write_fhdr(u8 *buffer, const int buflen,
const struct cscfg_file_header *fhdr)
+{
- int used = 0;
- cscfg_write_u32(fhdr->magic_version);
- cscfg_write_u16(fhdr->length);
- cscfg_write_u16(fhdr->nr_features);
- return used;
+}
+static int cscfg_file_write_string(u8 *buffer, const int buflen, const char *string) +{
- int len, used = 0;
- len = strlen(string);
- if (len > CSCFG_FILE_STR_MAXSIZE)
return -EINVAL;
- if (buflen < (len + 1 + sizeof(u16)))
return -EINVAL;
- cscfg_write_u16((u16)(len + 1));
- strcpy((char *)(buffer + used), string);
- used += (len + 1);
- return used;
+}
+static int cscfg_file_write_elem_hdr(u8 *buffer, const int buflen,
struct cscfg_file_elem_header *ehdr)
+{
- int used = 0;
- if (buflen < (sizeof(u16) + sizeof(u8)))
return -EINVAL;
- cscfg_write_u16(ehdr->elem_length);
- cscfg_write_u8(ehdr->elem_type);
- return used;
+}
Extra line.
+static int cscfg_file_write_config(u8 *buffer, const int buflen,
struct cscfg_config_desc *config_desc)
+{
- int used = 0, bytes_w, space_req, preset_bytes, i;
- struct cscfg_file_elem_header ehdr;
- ehdr.elem_length = 0;
- ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_CFG;
- /* write element header at current buffer location */
- bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
- CHECK_WRET(bytes_w);
- /* write out the configuration name */
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
config_desc->name);
- CHECK_WRET(bytes_w);
- /* write out the description string */
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
config_desc->description);
- CHECK_WRET(bytes_w);
- /*
* calculate the space needed for variables + presets
* [u16 value - nr_presets]
* [u32 value - nr_total_params]
* [u16 value - nr_feat_refs]
* [u64 values] * (nr_presets * nr_total_params)
*/
- preset_bytes = sizeof(u64) * config_desc->nr_presets * config_desc->nr_total_params;
- space_req = (sizeof(u16) * 2) + sizeof(u32) + preset_bytes;
- if ((buflen - used) < space_req)
return -EINVAL;
- cscfg_write_u16((u16)config_desc->nr_presets);
- cscfg_write_u32((u32)config_desc->nr_total_params);
- cscfg_write_u16((u16)config_desc->nr_feat_refs);
- if (preset_bytes) {
memcpy(buffer + used, (u8 *)config_desc->presets, preset_bytes);
used += preset_bytes;
- }
- /* now write the feature ref names */
- for (i = 0; i < config_desc->nr_feat_refs; i++) {
bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
config_desc->feat_ref_names[i]);
CHECK_WRET(bytes_w);
- }
- /* rewrite the element header with the correct length */
- ehdr.elem_length = used;
- bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
- /* no CHECK_WRET as used must not be updated */
- if (bytes_w < 0)
return bytes_w;
- return used;
+}
+/*
- write a parameter structure into the buffer in following format:
- [cscfg_file_elem_str] - parameter name.
- [u64 value: param_value] - initial value.
- */
+static int cscfg_file_write_param(u8 *buffer, const int buflen,
struct cscfg_parameter_desc *param_desc)
+{
- int used = 0, bytes_w;
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
param_desc->name);
- CHECK_WRET(bytes_w);
- if ((buflen - used) < sizeof(u64))
return -EINVAL;
- cscfg_write_u64(param_desc->value);
- return used;
+}
Add an extra line.
+/*
- Write a feature element from cscfg_feature_desc in following format:
- [cscfg_file_elem_header] - header length is total bytes to end of param structures.
- [cscfg_file_elem_str] - feature name.
- [cscfg_file_elem_str] - feature description.
- [u32 value: match_flags]
- [u16 value: nr_regs] - number of registers.
- [u16 value: nr_params] - number of parameters.
- [cscfg_regval_desc struct] * nr_regs
- [PARAM_ELEM] * nr_params
Two extra lines.
- */
+static int cscfg_file_write_feat(u8 *buffer, const int buflen,
struct cscfg_feature_desc *feat_desc)
+{
- struct cscfg_file_elem_header ehdr;
- struct cscfg_regval_desc *p_reg_desc;
- int used = 0, bytes_w, i, space_req;
- u32 val32;
- ehdr.elem_length = 0;
- ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_FEAT;
- /* write element header at current buffer location */
- bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
- CHECK_WRET(bytes_w);
- /* write out the name string */
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
feat_desc->name);
- CHECK_WRET(bytes_w)
- /* write out the description string */
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
feat_desc->description);
- CHECK_WRET(bytes_w);
- /* check for space for variables and register structures */
- space_req = (sizeof(u16) * 2) + sizeof(u32) +
(sizeof(struct cscfg_regval_desc) * feat_desc->nr_regs);
- if ((buflen - used) < space_req)
return -EINVAL;
- /* write the variables */
- cscfg_write_u32((u32)feat_desc->match_flags);
- cscfg_write_u16((u16)feat_desc->nr_regs);
- cscfg_write_u16((u16)feat_desc->nr_params);
- /*write the registers */
- for (i = 0; i < feat_desc->nr_regs; i++) {
p_reg_desc = (struct cscfg_regval_desc *)&feat_desc->regs_desc[i];
CSCFG_FILE_REG_DESC_INFO_TO_U32(val32, p_reg_desc);
cscfg_write_u32(val32);
cscfg_write_u64(feat_desc->regs_desc[i].val64);
- }
- /* write any parameters */
- for (i = 0; i < feat_desc->nr_params; i++) {
bytes_w = cscfg_file_write_param(buffer + used, buflen - used,
&feat_desc->params_desc[i]);
CHECK_WRET(bytes_w);
- }
- /*
* rewrite the element header at the start of the buffer block
* with the correct length
*/
- ehdr.elem_length = used;
- bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
- /* no CHECK_WRET as used must not be updated */
- if (bytes_w < 0)
return bytes_w;
- return used;
+}
+/*
- write a buffer from the configuration and feature
- descriptors to write into a file for configfs.
- Will only write one config, and/or a number of features,
- per the file standard.
- */
+int cscfg_file_write_buffer(u8 *buffer, const int buflen,
struct cscfg_config_desc *config_desc,
struct cscfg_feature_desc **feat_descs)
+{
- struct cscfg_file_header fhdr;
- int used = 0, bytes_w, i;
- /* init the file header */
- fhdr.magic_version = CSCFG_FILE_MAGIC_VERSION;
- fhdr.length = 0;
- fhdr.nr_features = 0;
- /* count the features */
- if (feat_descs) {
while (feat_descs[fhdr.nr_features])
fhdr.nr_features++;
- }
- /* need a buffer and at least one config or feature */
- if ((!config_desc && !fhdr.nr_features) ||
!buffer || (buflen > CSCFG_FILE_MAXSIZE))
return -EINVAL;
- /* write a header at the start to get the length of the header */
- bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr);
- CHECK_WRET(bytes_w);
- /* write a single config */
- if (config_desc) {
bytes_w = cscfg_file_write_config(buffer + used, buflen - used,
config_desc);
CHECK_WRET(bytes_w);
- }
- /* write any features */
- for (i = 0; i < fhdr.nr_features; i++) {
bytes_w = cscfg_file_write_feat(buffer + used, buflen - used,
feat_descs[i]);
CHECK_WRET(bytes_w);
- }
- /* finally re-write the header at the buffer start with the correct length */
- fhdr.length = (u16)used;
- bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr);
- /* no CHECK_WRET as used must not be updated */
- if (bytes_w < 0)
return bytes_w;
- return used;
+} diff --git a/tools/coresight/coresight-cfg-bufw.h b/tools/coresight/coresight-cfg-bufw.h new file mode 100644 index 000000000000..562df97599fc --- /dev/null +++ b/tools/coresight/coresight-cfg-bufw.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CFG_BUFW_H +#define _CORESIGHT_CFG_BUFW_H
+#include <linux/types.h>
+#include "coresight-config-file.h"
+/*
- Function to take coresight configurations and features and
- write them into a supplied memory buffer for serialisation
- into a file.
- Resulting file can then be loaded into the coresight
- infrastructure via configfs.
- */
+int cscfg_file_write_buffer(u8 *buffer, const int buflen,
struct cscfg_config_desc *config_desc,
struct cscfg_feature_desc **feat_descs);
+#endif /* _CORESIGHT_CFG_BUFW_H */ diff --git a/tools/coresight/coresight-cfg-example1.c b/tools/coresight/coresight-cfg-example1.c new file mode 100644 index 000000000000..a71a6e43d7b3 --- /dev/null +++ b/tools/coresight/coresight-cfg-example1.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <unistd.h>
+#include "coresight-cfg-bufw.h"
There is no need to include coresight-cfg-bufw.h.
+#include "coresight-cfg-examples.h"
+/*
- create a configuration only example using the strobing feature
- */
+/* we will provide 4 sets of preset parameter values */ +#define AFDO3_NR_PRESETS 4 +/* the total number of parameters in used features - strobing has 2 */ +#define AFDO3_NR_PARAM_SUM 2
+static const char *afdo3_ref_names[] = {
- "strobing",
+};
+/*
- set of presets leaves strobing window constant while varying period to allow
- experimentation with mark / space ratios for various workloads
- */
+static u64 afdo3_presets[AFDO3_NR_PRESETS][AFDO3_NR_PARAM_SUM] = {
- { 2000, 100 },
- { 2000, 1000 },
- { 2000, 5000 },
- { 2000, 10000 },
+};
+struct cscfg_config_desc afdo3 = {
- .name = "autofdo3",
- .description = "Setup ETMs with strobing for autofdo\n"
- "Supplied presets allow experimentation with mark-space ratio for various loads\n",
- .nr_feat_refs = ARRAY_SIZE(afdo3_ref_names),
- .feat_ref_names = afdo3_ref_names,
- .nr_presets = AFDO3_NR_PRESETS,
- .nr_total_params = AFDO3_NR_PARAM_SUM,
- .presets = &afdo3_presets[0][0],
+};
+static struct cscfg_feature_desc *sample_feats[] = {
- NULL
+};
+static struct cscfg_config_desc *sample_cfgs[] = {
- &afdo3,
- NULL
+};
+#define CSCFG_EG1_FILENAME "example1.cscfg"
Not sure there is any value in specifying a define... I'd just hard code it the same way it was done for "example1".
+struct cscfg_file_eg_info buff_info_eg1 = {
- .example_name = "example1",
- .filename = CSCFG_EG1_FILENAME,
- .config_descs = sample_cfgs,
- .feat_descs = sample_feats,
+}; diff --git a/tools/coresight/coresight-cfg-examples.h b/tools/coresight/coresight-cfg-examples.h new file mode 100644 index 000000000000..5c6908745201 --- /dev/null +++ b/tools/coresight/coresight-cfg-examples.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CFG_EXAMPLES_H +#define _CORESIGHT_CFG_EXAMPLES_H
+#include <linux/kernel.h>
+#include "uapi/coresight-config-uapi.h" +#include "coresight-cfg-bufw.h"
Same here.
+/* structure to pass configuraiton information to generator program */ +struct cscfg_file_eg_info {
- const char *example_name;
- const char *filename;
- struct cscfg_config_desc **config_descs;
- struct cscfg_feature_desc **feat_descs;
+};
+/* references to the configuration and feature example structures */ +extern struct cscfg_file_eg_info buff_info_eg1;
I would put this in coresight-cfg-filegen.c. That way people only have to change a single file rather than two.
More comments to follow on this file. I am not sure there is a need to read .cscfg files.
+#endif /* _CORESIGHT_CFG_EXAMPLES_H */ diff --git a/tools/coresight/coresight-cfg-file-read.c b/tools/coresight/coresight-cfg-file-read.c new file mode 100644 index 000000000000..da7b831eb2df --- /dev/null +++ b/tools/coresight/coresight-cfg-file-read.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h>
+#include "coresight-config-file.h" +#include "uapi/coresight-config-uapi.h"
+/*
- tool to read and print a generated configuration
- re-uses the read code source from the driver.
- */
+static void print_configs(struct cscfg_fs_load_descs *load_descs) +{
- struct cscfg_config_desc *config_desc = load_descs->config_descs[0];
- int i, j, p;
- if (!config_desc) {
printf("File contains no configurations.\n\n");
return;
- }
- printf("Configuration name : %s\n", config_desc->name);
- printf("Uses %d features:-\n", config_desc->nr_feat_refs);
- for (i = 0; i < config_desc->nr_feat_refs; i++)
printf("Feature-%d: %s\n", i + 1, config_desc->feat_ref_names[i]);
- printf("\nProvides %d sets of preset values, %d presets per set\n", config_desc->nr_presets,
config_desc->nr_total_params);
- if (config_desc->nr_presets) {
for (i = 0; i < config_desc->nr_presets; i++) {
printf("set[%d]: ", i);
for (j = 0; j < config_desc->nr_total_params; j++) {
p = (i * config_desc->nr_total_params) + j;
printf("0x%lx, ", config_desc->presets[p]);
}
printf("\n");
}
- }
- printf("\n\n");
+}
+static void print_reg_type_info(u8 type) +{
- if (type & CS_CFG_REG_TYPE_STD)
printf("std_reg ");
- if (type & CS_CFG_REG_TYPE_RESOURCE)
printf("resource ");
- if (type & CS_CFG_REG_TYPE_VAL_PARAM)
printf("param_index ");
- if (type & CS_CFG_REG_TYPE_VAL_64BIT)
printf("64_bit ");
- else
printf("32_bit ");
- if (type & CS_CFG_REG_TYPE_VAL_MASK)
printf("masked ");
- if (type & CS_CFG_REG_TYPE_VAL_SAVE)
printf("save_on_disable ");
+}
+static void print_regs(int nr, struct cscfg_regval_desc *regs_desc_array) +{
- int i;
- struct cscfg_regval_desc *reg_desc;
- u8 type;
- u16 offset;
- u16 info;
- for (i = 0; i < nr; i++) {
reg_desc = ®s_desc_array[i];
type = (u8)reg_desc->type;
offset = (u16)reg_desc->offset;
info = (u16)reg_desc->hw_info;
printf("Reg(%d): Type 0x%x: ", i, type);
print_reg_type_info(type);
printf("\nOffset: 0x%03x; HW Info: 0x%03x\n", offset, info);
printf("Value: ");
if (type & CS_CFG_REG_TYPE_VAL_64BIT)
printf("0x%lx\n", reg_desc->val64);
else if (type & CS_CFG_REG_TYPE_VAL_PARAM)
printf("idx = %d\n", reg_desc->param_idx);
else {
printf("0x%x ", reg_desc->val32);
if (type & CS_CFG_REG_TYPE_VAL_MASK)
printf(" mask: 0x%x", reg_desc->mask32);
printf("\n");
}
- }
+}
+static void print_params(int nr, struct cscfg_parameter_desc *params_desc) +{
- int i;
- for (i = 0; i < nr; i++)
printf("Param(%d) : %s; Init value 0x%lx\n", i,
params_desc[i].name, params_desc[i].value);
+}
+static void print_features(struct cscfg_fs_load_descs *load_descs) +{
- struct cscfg_feature_desc *feat_desc = 0;
- int idx = 0;
- feat_desc = load_descs->feat_descs[idx];
- if (!feat_desc) {
printf("File contains no features\n\n");
return;
- }
- while (feat_desc) {
printf("Feature %d name : %s\n", idx+1, feat_desc->name);
printf("Description: %s\n", feat_desc->description);
printf("Match flags: 0x%x\n", feat_desc->match_flags);
printf("Number of Paraneters: %d\n", feat_desc->nr_params);
if (feat_desc->nr_params)
print_params(feat_desc->nr_params, feat_desc->params_desc);
printf("Number of Registers: %d\n", feat_desc->nr_regs);
if (feat_desc->nr_regs)
print_regs(feat_desc->nr_regs, feat_desc->regs_desc);
printf("\n\n");
/* next feature */
idx++;
feat_desc = load_descs->feat_descs[idx];
- }
+}
+int main(int argc, char **argv) +{
- FILE *fp;
- struct cscfg_fs_load_descs *load_descs;
- int err, fsize;
- u8 buffer[CSCFG_FILE_MAXSIZE];
- printf("CoreSight Configuration file reader\n\n");
- /* need a filename */
- if (argc <= 1) {
printf("Please provide filename on command line\n");
return -EINVAL;
- }
- /* open file and read into the buffer. */
- fp = fopen(argv[1], "rb");
- if (fp == NULL) {
printf("Error opening file %s\n", argv[1]);
return -EINVAL;
- }
- fseek(fp, 0, SEEK_END);
- fsize = ftell(fp);
- rewind(fp);
- if (fsize > CSCFG_FILE_MAXSIZE) {
printf("Error: Input file too large.");
fclose(fp);
return -EINVAL;
- }
- err = fread(buffer, sizeof(u8), fsize, fp);
- fclose(fp);
- if (err < fsize) {
printf("Error reading file %s\n", argv[1]);
return -EINVAL;
- }
- /* allocate the descriptor structures to be populated by read operation */
- load_descs = malloc(sizeof(struct cscfg_fs_load_descs));
- if (!load_descs) {
printf("Error allocating load descs structure.\n");
return -ENOMEM;
- }
- /* read the buffer and create the configuration and feature structures */
- err = cscfg_file_read_buffer(buffer, fsize, load_descs);
- if (err) {
printf("Error reading configuration file\n");
goto exit_free_mem;
- }
- /* print the contents of the structures */
- print_configs(load_descs);
- print_features(load_descs);
+exit_free_mem:
- free(load_descs);
- return err;
+} diff --git a/tools/coresight/coresight-cfg-filegen.c b/tools/coresight/coresight-cfg-filegen.c new file mode 100644 index 000000000000..cd0589661d92 --- /dev/null +++ b/tools/coresight/coresight-cfg-filegen.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <unistd.h>
+#include "uapi/coresight-config-uapi.h" +#include "coresight-cfg-bufw.h" +#include "coresight-cfg-examples.h"
+/* array of example files to generate */ +struct cscfg_file_eg_info *info_ptrs[] = {
- &buff_info_eg1,
- NULL,
+};
+int main(int argc, char **argv) +{
- struct cscfg_config_desc *config_desc;
- struct cscfg_feature_desc **feat_descs;
- u8 buffer[CSCFG_FILE_MAXSIZE];
- int used, idx = 0;
- FILE *fp;
- const char *filename;
- printf("Coresight Configuration file Generator\n\n");
- while (info_ptrs[idx]) {
printf("Generating %s example\n", info_ptrs[idx]->example_name);
config_desc = info_ptrs[idx]->config_descs[0];
feat_descs = info_ptrs[idx]->feat_descs;
filename = info_ptrs[idx]->filename;
used = cscfg_file_write_buffer(buffer, CSCFG_FILE_MAXSIZE,
config_desc, feat_descs);
if (used < 0) {
printf("Error %d writing configuration %s into buffer\n",
used, info_ptrs[idx]->example_name);
return used;
}
fp = fopen(filename, "wb");
if (fp == NULL) {
printf("Error opening file %s\n", filename);
return -1;
}
fwrite(buffer, used, sizeof(u8), fp);
fclose(fp);
idx++;
- }
- return 0;
+} diff --git a/tools/include/uapi/coresight-config-uapi.h b/tools/include/uapi/coresight-config-uapi.h new file mode 100644 index 000000000000..d051c01ea982 --- /dev/null +++ b/tools/include/uapi/coresight-config-uapi.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CORESIGHT_CONFIG_UAPI_H +#define _CORESIGHT_CORESIGHT_CONFIG_UAPI_H
+#include <linux/types.h> +#include <asm-generic/errno-base.h>
+#include "coresight-config.h"
+/*
- Userspace versions of the configuration and feature descriptors.
- Used in the tools/coresight programs.
- Compatible with structures in coresight-config.h for use in
- coresight-config-file.c common reader source file.
- */
+/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
- UAPI version - removed kernel constructs.
- @name: feature name.
- @description: brief description of the feature.
- @match_flags: matching information if loading into a device
- @nr_params: number of parameters used.
- @params_desc: array of parameters used.
- @nr_regs: number of registers used.
- @regs_desc: array of registers used.
- */
+struct cscfg_feature_desc {
- const char *name;
- const char *description;
- u32 match_flags;
- int nr_params;
- struct cscfg_parameter_desc *params_desc;
- int nr_regs;
- struct cscfg_regval_desc *regs_desc;
+};
+/**
- Configuration descriptor - describes selectable system configuration.
- A configuration describes device features in use, and may provide preset
- values for the parameters in those features.
- A single set of presets is the sum of the parameters declared by
- all the features in use - this value is @nr_total_params.
- UAPI version - removed kernel constructs.
- @name: name of the configuration - used for selection.
- @description: description of the purpose of the configuration.
- @nr_feat_refs: Number of features used in this configuration.
- @feat_ref_names: references to features used in this configuration.
- @nr_presets: Number of sets of presets supplied by this configuration.
- @nr_total_params: Sum of all parameters declared by used features
- @presets: Array of preset values.
- */
+struct cscfg_config_desc {
- const char *name;
- const char *description;
- int nr_feat_refs;
- const char **feat_ref_names;
- int nr_presets;
- int nr_total_params;
- const u64 *presets; /* nr_presets * nr_total_params */
+};
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_UAPI_H */
2.17.1
On Thu, Apr 14, 2022 at 07:44:56AM +0100, Mike Leach wrote:
Add an example file generator to test loading configurations via a binary attribute in configfs.
Provides a file buffer writer function that can be re-used in other userspace programs.
Buffer write format matches that expected by the corresponding reader in the configfs driver code.
Add a config file reader and printer. Takes in config files and prints the contents. Uses file reader source from kernel driver.
Signed-off-by: Mike Leach mike.leach@linaro.org
MAINTAINERS | 2 + .../coresight/coresight-config-file.c | 2 + tools/coresight/Makefile | 51 +++ tools/coresight/coresight-cfg-bufw.c | 303 ++++++++++++++++++ tools/coresight/coresight-cfg-bufw.h | 26 ++ tools/coresight/coresight-cfg-example1.c | 65 ++++ tools/coresight/coresight-cfg-examples.h | 27 ++ tools/coresight/coresight-cfg-file-read.c | 197 ++++++++++++ tools/coresight/coresight-cfg-filegen.c | 58 ++++ tools/include/uapi/coresight-config-uapi.h | 76 +++++ 10 files changed, 807 insertions(+) create mode 100644 tools/coresight/Makefile create mode 100644 tools/coresight/coresight-cfg-bufw.c create mode 100644 tools/coresight/coresight-cfg-bufw.h create mode 100644 tools/coresight/coresight-cfg-example1.c create mode 100644 tools/coresight/coresight-cfg-examples.h create mode 100644 tools/coresight/coresight-cfg-file-read.c create mode 100644 tools/coresight/coresight-cfg-filegen.c create mode 100644 tools/include/uapi/coresight-config-uapi.h
diff --git a/MAINTAINERS b/MAINTAINERS index 61d9f114c37f..4e59486e75b5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1985,6 +1985,8 @@ F: drivers/hwtracing/coresight/* F: include/dt-bindings/arm/coresight-cti-dt.h F: include/linux/coresight* F: samples/coresight/* +F: tools/coresight/* +F: tools/include/uapi/coresight-config-uapi.h F: tools/perf/arch/arm/util/auxtrace.c F: tools/perf/arch/arm/util/cs-etm.c F: tools/perf/arch/arm/util/cs-etm.h diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c index 5b8f635ac50e..4a8b64405d84 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.c +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -36,6 +36,8 @@ static void *cscfg_zalloc(size_t size) #include <string.h> #include <stdlib.h> +#include "uapi/coresight-config-uapi.h"
static void *cscfg_calloc(size_t num, size_t size) { return calloc(num, size); diff --git a/tools/coresight/Makefile b/tools/coresight/Makefile new file mode 100644 index 000000000000..4004c315d65c --- /dev/null +++ b/tools/coresight/Makefile @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only +include ../scripts/Makefile.include +include ../scripts/Makefile.arch
+# Makefile to build the coresight configuration file reader and generator tools
+this-makefile := $(lastword $(MAKEFILE_LIST)) +tools-src := $(realpath $(dir $(this-makefile))) +srctree := $(realpath $(dir $(tools-src)/../../.))
+# ensure we use all as the default - skip anything in included Makefile +.DEFAULT_GOAL = all +# MAKECMDGOALS isn't set if there's no explicit goal in the +# command line, so set the default. +MAKECMDGOALS ?= $(.DEFAULT_GOAL)
+# compile flags +CFLAGS += $(CPPFLAGS) -c -Wall -DLINUX -Wno-switch -Wlogical-op -fPIC -I$(srctree)/drivers/hwtracing/coresight -I$(srctree)/tools/include/ -I$(srctree)/tools/include/uapi
+# object files +coresight-cfg-file-gen-objs := coresight-cfg-filegen.o coresight-cfg-bufw.o coresight-cfg-example1.o +coresight-cfg-file-read-objs := coresight-cfg-file-read.o coresight-config-file.o
+# debug variant +ifdef DEBUG +CFLAGS += -g -O0 -DDEBUG +else +CFLAGS += -O2 -DNDEBUG +endif
+.PHONY: all +all: coresight-cfg-file-gen coresight-cfg-file-read
+coresight-config-file.o: src_copy
- $(CC) $(CFLAGS) coresight-config-file.c -o coresight-config-file.o
+.PHONY: src_copy +src_copy:
- @cp $(srctree)/drivers/hwtracing/coresight/coresight-config-file.c $(srctree)/tools/coresight/.
+coresight-cfg-file-gen: $(coresight-cfg-file-gen-objs)
- $(CC) $(LDFLAGS) $(coresight-cfg-file-gen-objs) -o coresight-cfg-file-gen
+coresight-cfg-file-read: $(coresight-cfg-file-read-objs)
- $(CC) $(LDFLAGS) $(coresight-cfg-file-read-objs) -o coresight-cfg-file-read
+clean:
- rm -f coresight-cfg-file-gen coresight-cfg-file-read
- rm -f *.o
- rm -f coresight-config-file.c
- rm -f *.cscfg
diff --git a/tools/coresight/coresight-cfg-bufw.c b/tools/coresight/coresight-cfg-bufw.c new file mode 100644 index 000000000000..73223de2b7e0 --- /dev/null +++ b/tools/coresight/coresight-cfg-bufw.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <string.h>
+#include "coresight-cfg-bufw.h" +#include "uapi/coresight-config-uapi.h"
+/*
- Set of macros to make writing the buffer code easier.
- *.
- Uses naming convention as 'buffer' for the buffer pointer and
- 'used' as the current bytes used by the encosing function.
- */
+#define cscfg_write_u64(val64) { \
- *(u64 *)(buffer + used) = val64; \
- used += sizeof(u64); \
- }
+#define cscfg_write_u32(val32) { \
- *(u32 *)(buffer + used) = val32; \
- used += sizeof(u32); \
- }
+#define cscfg_write_u16(val16) { \
- *(u16 *)(buffer + used) = val16; \
- used += sizeof(u16); \
- }
+#define cscfg_write_u8(val8) { \
- *(buffer + used) = val8; \
- used++; \
- }
+#define CHECK_WRET(rval) { \
- if (rval < 0) \
return rval; \
- used += rval; \
- }
+/* write the header at the start of the buffer */ +static int cscfg_file_write_fhdr(u8 *buffer, const int buflen,
const struct cscfg_file_header *fhdr)
+{
- int used = 0;
- cscfg_write_u32(fhdr->magic_version);
- cscfg_write_u16(fhdr->length);
- cscfg_write_u16(fhdr->nr_features);
- return used;
+}
+static int cscfg_file_write_string(u8 *buffer, const int buflen, const char *string) +{
- int len, used = 0;
- len = strlen(string);
- if (len > CSCFG_FILE_STR_MAXSIZE)
return -EINVAL;
- if (buflen < (len + 1 + sizeof(u16)))
return -EINVAL;
- cscfg_write_u16((u16)(len + 1));
- strcpy((char *)(buffer + used), string);
- used += (len + 1);
- return used;
+}
+static int cscfg_file_write_elem_hdr(u8 *buffer, const int buflen,
struct cscfg_file_elem_header *ehdr)
+{
- int used = 0;
- if (buflen < (sizeof(u16) + sizeof(u8)))
return -EINVAL;
- cscfg_write_u16(ehdr->elem_length);
- cscfg_write_u8(ehdr->elem_type);
- return used;
+}
+static int cscfg_file_write_config(u8 *buffer, const int buflen,
struct cscfg_config_desc *config_desc)
+{
- int used = 0, bytes_w, space_req, preset_bytes, i;
- struct cscfg_file_elem_header ehdr;
- ehdr.elem_length = 0;
- ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_CFG;
- /* write element header at current buffer location */
- bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
- CHECK_WRET(bytes_w);
- /* write out the configuration name */
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
config_desc->name);
- CHECK_WRET(bytes_w);
- /* write out the description string */
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
config_desc->description);
- CHECK_WRET(bytes_w);
- /*
* calculate the space needed for variables + presets
* [u16 value - nr_presets]
* [u32 value - nr_total_params]
* [u16 value - nr_feat_refs]
* [u64 values] * (nr_presets * nr_total_params)
*/
- preset_bytes = sizeof(u64) * config_desc->nr_presets * config_desc->nr_total_params;
- space_req = (sizeof(u16) * 2) + sizeof(u32) + preset_bytes;
- if ((buflen - used) < space_req)
return -EINVAL;
- cscfg_write_u16((u16)config_desc->nr_presets);
- cscfg_write_u32((u32)config_desc->nr_total_params);
- cscfg_write_u16((u16)config_desc->nr_feat_refs);
- if (preset_bytes) {
memcpy(buffer + used, (u8 *)config_desc->presets, preset_bytes);
used += preset_bytes;
- }
- /* now write the feature ref names */
- for (i = 0; i < config_desc->nr_feat_refs; i++) {
bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
config_desc->feat_ref_names[i]);
CHECK_WRET(bytes_w);
- }
- /* rewrite the element header with the correct length */
- ehdr.elem_length = used;
- bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
- /* no CHECK_WRET as used must not be updated */
- if (bytes_w < 0)
return bytes_w;
- return used;
+}
+/*
- write a parameter structure into the buffer in following format:
- [cscfg_file_elem_str] - parameter name.
- [u64 value: param_value] - initial value.
- */
+static int cscfg_file_write_param(u8 *buffer, const int buflen,
struct cscfg_parameter_desc *param_desc)
+{
- int used = 0, bytes_w;
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
param_desc->name);
- CHECK_WRET(bytes_w);
- if ((buflen - used) < sizeof(u64))
return -EINVAL;
- cscfg_write_u64(param_desc->value);
- return used;
+} +/*
- Write a feature element from cscfg_feature_desc in following format:
- [cscfg_file_elem_header] - header length is total bytes to end of param structures.
- [cscfg_file_elem_str] - feature name.
- [cscfg_file_elem_str] - feature description.
- [u32 value: match_flags]
- [u16 value: nr_regs] - number of registers.
- [u16 value: nr_params] - number of parameters.
- [cscfg_regval_desc struct] * nr_regs
- [PARAM_ELEM] * nr_params
- */
+static int cscfg_file_write_feat(u8 *buffer, const int buflen,
struct cscfg_feature_desc *feat_desc)
+{
- struct cscfg_file_elem_header ehdr;
- struct cscfg_regval_desc *p_reg_desc;
- int used = 0, bytes_w, i, space_req;
- u32 val32;
- ehdr.elem_length = 0;
- ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_FEAT;
- /* write element header at current buffer location */
- bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
- CHECK_WRET(bytes_w);
- /* write out the name string */
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
feat_desc->name);
- CHECK_WRET(bytes_w)
- /* write out the description string */
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
feat_desc->description);
- CHECK_WRET(bytes_w);
- /* check for space for variables and register structures */
- space_req = (sizeof(u16) * 2) + sizeof(u32) +
(sizeof(struct cscfg_regval_desc) * feat_desc->nr_regs);
- if ((buflen - used) < space_req)
return -EINVAL;
- /* write the variables */
- cscfg_write_u32((u32)feat_desc->match_flags);
- cscfg_write_u16((u16)feat_desc->nr_regs);
- cscfg_write_u16((u16)feat_desc->nr_params);
- /*write the registers */
- for (i = 0; i < feat_desc->nr_regs; i++) {
p_reg_desc = (struct cscfg_regval_desc *)&feat_desc->regs_desc[i];
CSCFG_FILE_REG_DESC_INFO_TO_U32(val32, p_reg_desc);
cscfg_write_u32(val32);
cscfg_write_u64(feat_desc->regs_desc[i].val64);
- }
- /* write any parameters */
- for (i = 0; i < feat_desc->nr_params; i++) {
bytes_w = cscfg_file_write_param(buffer + used, buflen - used,
&feat_desc->params_desc[i]);
CHECK_WRET(bytes_w);
- }
- /*
* rewrite the element header at the start of the buffer block
* with the correct length
*/
- ehdr.elem_length = used;
- bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
- /* no CHECK_WRET as used must not be updated */
- if (bytes_w < 0)
return bytes_w;
- return used;
+}
+/*
- write a buffer from the configuration and feature
- descriptors to write into a file for configfs.
- Will only write one config, and/or a number of features,
- per the file standard.
- */
+int cscfg_file_write_buffer(u8 *buffer, const int buflen,
struct cscfg_config_desc *config_desc,
struct cscfg_feature_desc **feat_descs)
+{
- struct cscfg_file_header fhdr;
- int used = 0, bytes_w, i;
- /* init the file header */
- fhdr.magic_version = CSCFG_FILE_MAGIC_VERSION;
- fhdr.length = 0;
- fhdr.nr_features = 0;
- /* count the features */
- if (feat_descs) {
while (feat_descs[fhdr.nr_features])
fhdr.nr_features++;
- }
- /* need a buffer and at least one config or feature */
- if ((!config_desc && !fhdr.nr_features) ||
!buffer || (buflen > CSCFG_FILE_MAXSIZE))
return -EINVAL;
- /* write a header at the start to get the length of the header */
- bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr);
- CHECK_WRET(bytes_w);
- /* write a single config */
- if (config_desc) {
bytes_w = cscfg_file_write_config(buffer + used, buflen - used,
config_desc);
CHECK_WRET(bytes_w);
- }
- /* write any features */
- for (i = 0; i < fhdr.nr_features; i++) {
bytes_w = cscfg_file_write_feat(buffer + used, buflen - used,
feat_descs[i]);
CHECK_WRET(bytes_w);
- }
- /* finally re-write the header at the buffer start with the correct length */
- fhdr.length = (u16)used;
- bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr);
- /* no CHECK_WRET as used must not be updated */
- if (bytes_w < 0)
return bytes_w;
- return used;
+} diff --git a/tools/coresight/coresight-cfg-bufw.h b/tools/coresight/coresight-cfg-bufw.h new file mode 100644 index 000000000000..562df97599fc --- /dev/null +++ b/tools/coresight/coresight-cfg-bufw.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CFG_BUFW_H +#define _CORESIGHT_CFG_BUFW_H
+#include <linux/types.h>
+#include "coresight-config-file.h"
+/*
- Function to take coresight configurations and features and
- write them into a supplied memory buffer for serialisation
- into a file.
- Resulting file can then be loaded into the coresight
- infrastructure via configfs.
- */
+int cscfg_file_write_buffer(u8 *buffer, const int buflen,
struct cscfg_config_desc *config_desc,
struct cscfg_feature_desc **feat_descs);
+#endif /* _CORESIGHT_CFG_BUFW_H */ diff --git a/tools/coresight/coresight-cfg-example1.c b/tools/coresight/coresight-cfg-example1.c new file mode 100644 index 000000000000..a71a6e43d7b3 --- /dev/null +++ b/tools/coresight/coresight-cfg-example1.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <unistd.h>
+#include "coresight-cfg-bufw.h" +#include "coresight-cfg-examples.h"
+/*
- create a configuration only example using the strobing feature
- */
+/* we will provide 4 sets of preset parameter values */ +#define AFDO3_NR_PRESETS 4 +/* the total number of parameters in used features - strobing has 2 */ +#define AFDO3_NR_PARAM_SUM 2
+static const char *afdo3_ref_names[] = {
- "strobing",
+};
+/*
- set of presets leaves strobing window constant while varying period to allow
- experimentation with mark / space ratios for various workloads
- */
+static u64 afdo3_presets[AFDO3_NR_PRESETS][AFDO3_NR_PARAM_SUM] = {
- { 2000, 100 },
- { 2000, 1000 },
- { 2000, 5000 },
- { 2000, 10000 },
+};
+struct cscfg_config_desc afdo3 = {
- .name = "autofdo3",
- .description = "Setup ETMs with strobing for autofdo\n"
- "Supplied presets allow experimentation with mark-space ratio for various loads\n",
- .nr_feat_refs = ARRAY_SIZE(afdo3_ref_names),
- .feat_ref_names = afdo3_ref_names,
- .nr_presets = AFDO3_NR_PRESETS,
- .nr_total_params = AFDO3_NR_PARAM_SUM,
- .presets = &afdo3_presets[0][0],
+};
+static struct cscfg_feature_desc *sample_feats[] = {
- NULL
+};
+static struct cscfg_config_desc *sample_cfgs[] = {
- &afdo3,
- NULL
+};
+#define CSCFG_EG1_FILENAME "example1.cscfg"
+struct cscfg_file_eg_info buff_info_eg1 = {
- .example_name = "example1",
- .filename = CSCFG_EG1_FILENAME,
- .config_descs = sample_cfgs,
- .feat_descs = sample_feats,
+}; diff --git a/tools/coresight/coresight-cfg-examples.h b/tools/coresight/coresight-cfg-examples.h new file mode 100644 index 000000000000..5c6908745201 --- /dev/null +++ b/tools/coresight/coresight-cfg-examples.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CFG_EXAMPLES_H +#define _CORESIGHT_CFG_EXAMPLES_H
+#include <linux/kernel.h>
+#include "uapi/coresight-config-uapi.h" +#include "coresight-cfg-bufw.h"
+/* structure to pass configuraiton information to generator program */ +struct cscfg_file_eg_info {
- const char *example_name;
- const char *filename;
- struct cscfg_config_desc **config_descs;
- struct cscfg_feature_desc **feat_descs;
+};
+/* references to the configuration and feature example structures */ +extern struct cscfg_file_eg_info buff_info_eg1;
+#endif /* _CORESIGHT_CFG_EXAMPLES_H */ diff --git a/tools/coresight/coresight-cfg-file-read.c b/tools/coresight/coresight-cfg-file-read.c new file mode 100644 index 000000000000..da7b831eb2df --- /dev/null +++ b/tools/coresight/coresight-cfg-file-read.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h>
+#include "coresight-config-file.h" +#include "uapi/coresight-config-uapi.h"
+/*
- tool to read and print a generated configuration
- re-uses the read code source from the driver.
- */
+static void print_configs(struct cscfg_fs_load_descs *load_descs) +{
- struct cscfg_config_desc *config_desc = load_descs->config_descs[0];
- int i, j, p;
- if (!config_desc) {
printf("File contains no configurations.\n\n");
return;
- }
- printf("Configuration name : %s\n", config_desc->name);
- printf("Uses %d features:-\n", config_desc->nr_feat_refs);
- for (i = 0; i < config_desc->nr_feat_refs; i++)
printf("Feature-%d: %s\n", i + 1, config_desc->feat_ref_names[i]);
- printf("\nProvides %d sets of preset values, %d presets per set\n", config_desc->nr_presets,
config_desc->nr_total_params);
- if (config_desc->nr_presets) {
for (i = 0; i < config_desc->nr_presets; i++) {
printf("set[%d]: ", i);
for (j = 0; j < config_desc->nr_total_params; j++) {
p = (i * config_desc->nr_total_params) + j;
printf("0x%lx, ", config_desc->presets[p]);
}
printf("\n");
}
- }
- printf("\n\n");
+}
+static void print_reg_type_info(u8 type) +{
- if (type & CS_CFG_REG_TYPE_STD)
printf("std_reg ");
- if (type & CS_CFG_REG_TYPE_RESOURCE)
printf("resource ");
- if (type & CS_CFG_REG_TYPE_VAL_PARAM)
printf("param_index ");
- if (type & CS_CFG_REG_TYPE_VAL_64BIT)
printf("64_bit ");
- else
printf("32_bit ");
- if (type & CS_CFG_REG_TYPE_VAL_MASK)
printf("masked ");
- if (type & CS_CFG_REG_TYPE_VAL_SAVE)
printf("save_on_disable ");
+}
+static void print_regs(int nr, struct cscfg_regval_desc *regs_desc_array) +{
- int i;
- struct cscfg_regval_desc *reg_desc;
- u8 type;
- u16 offset;
- u16 info;
- for (i = 0; i < nr; i++) {
reg_desc = ®s_desc_array[i];
type = (u8)reg_desc->type;
offset = (u16)reg_desc->offset;
info = (u16)reg_desc->hw_info;
printf("Reg(%d): Type 0x%x: ", i, type);
print_reg_type_info(type);
printf("\nOffset: 0x%03x; HW Info: 0x%03x\n", offset, info);
printf("Value: ");
if (type & CS_CFG_REG_TYPE_VAL_64BIT)
printf("0x%lx\n", reg_desc->val64);
else if (type & CS_CFG_REG_TYPE_VAL_PARAM)
printf("idx = %d\n", reg_desc->param_idx);
else {
printf("0x%x ", reg_desc->val32);
if (type & CS_CFG_REG_TYPE_VAL_MASK)
printf(" mask: 0x%x", reg_desc->mask32);
printf("\n");
}
- }
+}
+static void print_params(int nr, struct cscfg_parameter_desc *params_desc) +{
- int i;
- for (i = 0; i < nr; i++)
printf("Param(%d) : %s; Init value 0x%lx\n", i,
params_desc[i].name, params_desc[i].value);
+}
+static void print_features(struct cscfg_fs_load_descs *load_descs) +{
- struct cscfg_feature_desc *feat_desc = 0;
- int idx = 0;
- feat_desc = load_descs->feat_descs[idx];
- if (!feat_desc) {
printf("File contains no features\n\n");
return;
- }
- while (feat_desc) {
printf("Feature %d name : %s\n", idx+1, feat_desc->name);
printf("Description: %s\n", feat_desc->description);
printf("Match flags: 0x%x\n", feat_desc->match_flags);
printf("Number of Paraneters: %d\n", feat_desc->nr_params);
if (feat_desc->nr_params)
print_params(feat_desc->nr_params, feat_desc->params_desc);
printf("Number of Registers: %d\n", feat_desc->nr_regs);
if (feat_desc->nr_regs)
print_regs(feat_desc->nr_regs, feat_desc->regs_desc);
printf("\n\n");
/* next feature */
idx++;
feat_desc = load_descs->feat_descs[idx];
- }
+}
+int main(int argc, char **argv) +{
- FILE *fp;
- struct cscfg_fs_load_descs *load_descs;
- int err, fsize;
- u8 buffer[CSCFG_FILE_MAXSIZE];
- printf("CoreSight Configuration file reader\n\n");
- /* need a filename */
- if (argc <= 1) {
printf("Please provide filename on command line\n");
return -EINVAL;
- }
- /* open file and read into the buffer. */
- fp = fopen(argv[1], "rb");
- if (fp == NULL) {
printf("Error opening file %s\n", argv[1]);
return -EINVAL;
- }
- fseek(fp, 0, SEEK_END);
- fsize = ftell(fp);
- rewind(fp);
- if (fsize > CSCFG_FILE_MAXSIZE) {
printf("Error: Input file too large.");
fclose(fp);
return -EINVAL;
- }
- err = fread(buffer, sizeof(u8), fsize, fp);
- fclose(fp);
- if (err < fsize) {
printf("Error reading file %s\n", argv[1]);
return -EINVAL;
- }
- /* allocate the descriptor structures to be populated by read operation */
- load_descs = malloc(sizeof(struct cscfg_fs_load_descs));
- if (!load_descs) {
printf("Error allocating load descs structure.\n");
return -ENOMEM;
- }
- /* read the buffer and create the configuration and feature structures */
- err = cscfg_file_read_buffer(buffer, fsize, load_descs);
- if (err) {
printf("Error reading configuration file\n");
goto exit_free_mem;
- }
- /* print the contents of the structures */
- print_configs(load_descs);
- print_features(load_descs);
+exit_free_mem:
- free(load_descs);
- return err;
+} diff --git a/tools/coresight/coresight-cfg-filegen.c b/tools/coresight/coresight-cfg-filegen.c new file mode 100644 index 000000000000..cd0589661d92 --- /dev/null +++ b/tools/coresight/coresight-cfg-filegen.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <unistd.h>
+#include "uapi/coresight-config-uapi.h" +#include "coresight-cfg-bufw.h" +#include "coresight-cfg-examples.h"
+/* array of example files to generate */ +struct cscfg_file_eg_info *info_ptrs[] = {
- &buff_info_eg1,
- NULL,
+};
+int main(int argc, char **argv) +{
- struct cscfg_config_desc *config_desc;
- struct cscfg_feature_desc **feat_descs;
- u8 buffer[CSCFG_FILE_MAXSIZE];
- int used, idx = 0;
- FILE *fp;
- const char *filename;
- printf("Coresight Configuration file Generator\n\n");
- while (info_ptrs[idx]) {
printf("Generating %s example\n", info_ptrs[idx]->example_name);
config_desc = info_ptrs[idx]->config_descs[0];
feat_descs = info_ptrs[idx]->feat_descs;
filename = info_ptrs[idx]->filename;
used = cscfg_file_write_buffer(buffer, CSCFG_FILE_MAXSIZE,
config_desc, feat_descs);
if (used < 0) {
printf("Error %d writing configuration %s into buffer\n",
used, info_ptrs[idx]->example_name);
return used;
}
fp = fopen(filename, "wb");
if (fp == NULL) {
printf("Error opening file %s\n", filename);
return -1;
}
fwrite(buffer, used, sizeof(u8), fp);
fclose(fp);
idx++;
- }
- return 0;
+} diff --git a/tools/include/uapi/coresight-config-uapi.h b/tools/include/uapi/coresight-config-uapi.h new file mode 100644 index 000000000000..d051c01ea982 --- /dev/null +++ b/tools/include/uapi/coresight-config-uapi.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CORESIGHT_CONFIG_UAPI_H +#define _CORESIGHT_CORESIGHT_CONFIG_UAPI_H
+#include <linux/types.h> +#include <asm-generic/errno-base.h>
+#include "coresight-config.h"
+/*
- Userspace versions of the configuration and feature descriptors.
- Used in the tools/coresight programs.
- Compatible with structures in coresight-config.h for use in
- coresight-config-file.c common reader source file.
- */
+/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
- UAPI version - removed kernel constructs.
- @name: feature name.
- @description: brief description of the feature.
- @match_flags: matching information if loading into a device
- @nr_params: number of parameters used.
- @params_desc: array of parameters used.
- @nr_regs: number of registers used.
- @regs_desc: array of registers used.
- */
+struct cscfg_feature_desc {
- const char *name;
- const char *description;
- u32 match_flags;
- int nr_params;
- struct cscfg_parameter_desc *params_desc;
- int nr_regs;
- struct cscfg_regval_desc *regs_desc;
+};
+/**
- Configuration descriptor - describes selectable system configuration.
- A configuration describes device features in use, and may provide preset
- values for the parameters in those features.
- A single set of presets is the sum of the parameters declared by
- all the features in use - this value is @nr_total_params.
- UAPI version - removed kernel constructs.
- @name: name of the configuration - used for selection.
- @description: description of the purpose of the configuration.
- @nr_feat_refs: Number of features used in this configuration.
- @feat_ref_names: references to features used in this configuration.
- @nr_presets: Number of sets of presets supplied by this configuration.
- @nr_total_params: Sum of all parameters declared by used features
- @presets: Array of preset values.
- */
+struct cscfg_config_desc {
- const char *name;
- const char *description;
- int nr_feat_refs;
- const char **feat_ref_names;
- int nr_presets;
- int nr_total_params;
- const u64 *presets; /* nr_presets * nr_total_params */
+};
I would call the above cscfg_feature_fs_desc and cscfg_config_fs_desc to make sure they don't get confused with the kernel's internal structures of the same name.
Moreover, I would keep this file private to tools/coresight/ and rename it coresight-config.h.
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_UAPI_H */
2.17.1
Hi Mathieu,
I've fixed up the minor comments from your previous mail
On Fri, 27 May 2022 at 17:25, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Apr 14, 2022 at 07:44:56AM +0100, Mike Leach wrote:
Add an example file generator to test loading configurations via a binary attribute in configfs.
Provides a file buffer writer function that can be re-used in other userspace programs.
Buffer write format matches that expected by the corresponding reader in the configfs driver code.
Add a config file reader and printer. Takes in config files and prints the contents. Uses file reader source from kernel driver.
Signed-off-by: Mike Leach mike.leach@linaro.org
MAINTAINERS | 2 + .../coresight/coresight-config-file.c | 2 + tools/coresight/Makefile | 51 +++ tools/coresight/coresight-cfg-bufw.c | 303 ++++++++++++++++++ tools/coresight/coresight-cfg-bufw.h | 26 ++ tools/coresight/coresight-cfg-example1.c | 65 ++++ tools/coresight/coresight-cfg-examples.h | 27 ++ tools/coresight/coresight-cfg-file-read.c | 197 ++++++++++++ tools/coresight/coresight-cfg-filegen.c | 58 ++++ tools/include/uapi/coresight-config-uapi.h | 76 +++++ 10 files changed, 807 insertions(+) create mode 100644 tools/coresight/Makefile create mode 100644 tools/coresight/coresight-cfg-bufw.c create mode 100644 tools/coresight/coresight-cfg-bufw.h create mode 100644 tools/coresight/coresight-cfg-example1.c create mode 100644 tools/coresight/coresight-cfg-examples.h create mode 100644 tools/coresight/coresight-cfg-file-read.c create mode 100644 tools/coresight/coresight-cfg-filegen.c create mode 100644 tools/include/uapi/coresight-config-uapi.h
diff --git a/MAINTAINERS b/MAINTAINERS index 61d9f114c37f..4e59486e75b5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1985,6 +1985,8 @@ F: drivers/hwtracing/coresight/* F: include/dt-bindings/arm/coresight-cti-dt.h F: include/linux/coresight* F: samples/coresight/* +F: tools/coresight/* +F: tools/include/uapi/coresight-config-uapi.h F: tools/perf/arch/arm/util/auxtrace.c F: tools/perf/arch/arm/util/cs-etm.c F: tools/perf/arch/arm/util/cs-etm.h diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c index 5b8f635ac50e..4a8b64405d84 100644 --- a/drivers/hwtracing/coresight/coresight-config-file.c +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -36,6 +36,8 @@ static void *cscfg_zalloc(size_t size) #include <string.h> #include <stdlib.h>
+#include "uapi/coresight-config-uapi.h"
static void *cscfg_calloc(size_t num, size_t size) { return calloc(num, size); diff --git a/tools/coresight/Makefile b/tools/coresight/Makefile new file mode 100644 index 000000000000..4004c315d65c --- /dev/null +++ b/tools/coresight/Makefile @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only +include ../scripts/Makefile.include +include ../scripts/Makefile.arch
+# Makefile to build the coresight configuration file reader and generator tools
+this-makefile := $(lastword $(MAKEFILE_LIST)) +tools-src := $(realpath $(dir $(this-makefile))) +srctree := $(realpath $(dir $(tools-src)/../../.))
+# ensure we use all as the default - skip anything in included Makefile +.DEFAULT_GOAL = all +# MAKECMDGOALS isn't set if there's no explicit goal in the +# command line, so set the default. +MAKECMDGOALS ?= $(.DEFAULT_GOAL)
+# compile flags +CFLAGS += $(CPPFLAGS) -c -Wall -DLINUX -Wno-switch -Wlogical-op -fPIC -I$(srctree)/drivers/hwtracing/coresight -I$(srctree)/tools/include/ -I$(srctree)/tools/include/uapi
+# object files +coresight-cfg-file-gen-objs := coresight-cfg-filegen.o coresight-cfg-bufw.o coresight-cfg-example1.o +coresight-cfg-file-read-objs := coresight-cfg-file-read.o coresight-config-file.o
+# debug variant +ifdef DEBUG +CFLAGS += -g -O0 -DDEBUG +else +CFLAGS += -O2 -DNDEBUG +endif
+.PHONY: all +all: coresight-cfg-file-gen coresight-cfg-file-read
+coresight-config-file.o: src_copy
$(CC) $(CFLAGS) coresight-config-file.c -o coresight-config-file.o
+.PHONY: src_copy +src_copy:
@cp $(srctree)/drivers/hwtracing/coresight/coresight-config-file.c $(srctree)/tools/coresight/.
+coresight-cfg-file-gen: $(coresight-cfg-file-gen-objs)
$(CC) $(LDFLAGS) $(coresight-cfg-file-gen-objs) -o coresight-cfg-file-gen
+coresight-cfg-file-read: $(coresight-cfg-file-read-objs)
$(CC) $(LDFLAGS) $(coresight-cfg-file-read-objs) -o coresight-cfg-file-read
+clean:
rm -f coresight-cfg-file-gen coresight-cfg-file-read
rm -f *.o
rm -f coresight-config-file.c
rm -f *.cscfg
diff --git a/tools/coresight/coresight-cfg-bufw.c b/tools/coresight/coresight-cfg-bufw.c new file mode 100644 index 000000000000..73223de2b7e0 --- /dev/null +++ b/tools/coresight/coresight-cfg-bufw.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <string.h>
+#include "coresight-cfg-bufw.h" +#include "uapi/coresight-config-uapi.h"
+/*
- Set of macros to make writing the buffer code easier.
- *.
- Uses naming convention as 'buffer' for the buffer pointer and
- 'used' as the current bytes used by the encosing function.
- */
+#define cscfg_write_u64(val64) { \
*(u64 *)(buffer + used) = val64; \
used += sizeof(u64); \
}
+#define cscfg_write_u32(val32) { \
*(u32 *)(buffer + used) = val32; \
used += sizeof(u32); \
}
+#define cscfg_write_u16(val16) { \
*(u16 *)(buffer + used) = val16; \
used += sizeof(u16); \
}
+#define cscfg_write_u8(val8) { \
*(buffer + used) = val8; \
used++; \
}
+#define CHECK_WRET(rval) { \
if (rval < 0) \
return rval; \
used += rval; \
}
+/* write the header at the start of the buffer */ +static int cscfg_file_write_fhdr(u8 *buffer, const int buflen,
const struct cscfg_file_header *fhdr)
+{
int used = 0;
cscfg_write_u32(fhdr->magic_version);
cscfg_write_u16(fhdr->length);
cscfg_write_u16(fhdr->nr_features);
return used;
+}
+static int cscfg_file_write_string(u8 *buffer, const int buflen, const char *string) +{
int len, used = 0;
len = strlen(string);
if (len > CSCFG_FILE_STR_MAXSIZE)
return -EINVAL;
if (buflen < (len + 1 + sizeof(u16)))
return -EINVAL;
cscfg_write_u16((u16)(len + 1));
strcpy((char *)(buffer + used), string);
used += (len + 1);
return used;
+}
+static int cscfg_file_write_elem_hdr(u8 *buffer, const int buflen,
struct cscfg_file_elem_header *ehdr)
+{
int used = 0;
if (buflen < (sizeof(u16) + sizeof(u8)))
return -EINVAL;
cscfg_write_u16(ehdr->elem_length);
cscfg_write_u8(ehdr->elem_type);
return used;
+}
+static int cscfg_file_write_config(u8 *buffer, const int buflen,
struct cscfg_config_desc *config_desc)
+{
int used = 0, bytes_w, space_req, preset_bytes, i;
struct cscfg_file_elem_header ehdr;
ehdr.elem_length = 0;
ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_CFG;
/* write element header at current buffer location */
bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
CHECK_WRET(bytes_w);
/* write out the configuration name */
bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
config_desc->name);
CHECK_WRET(bytes_w);
/* write out the description string */
bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
config_desc->description);
CHECK_WRET(bytes_w);
/*
* calculate the space needed for variables + presets
* [u16 value - nr_presets]
* [u32 value - nr_total_params]
* [u16 value - nr_feat_refs]
* [u64 values] * (nr_presets * nr_total_params)
*/
preset_bytes = sizeof(u64) * config_desc->nr_presets * config_desc->nr_total_params;
space_req = (sizeof(u16) * 2) + sizeof(u32) + preset_bytes;
if ((buflen - used) < space_req)
return -EINVAL;
cscfg_write_u16((u16)config_desc->nr_presets);
cscfg_write_u32((u32)config_desc->nr_total_params);
cscfg_write_u16((u16)config_desc->nr_feat_refs);
if (preset_bytes) {
memcpy(buffer + used, (u8 *)config_desc->presets, preset_bytes);
used += preset_bytes;
}
/* now write the feature ref names */
for (i = 0; i < config_desc->nr_feat_refs; i++) {
bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
config_desc->feat_ref_names[i]);
CHECK_WRET(bytes_w);
}
/* rewrite the element header with the correct length */
ehdr.elem_length = used;
bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
/* no CHECK_WRET as used must not be updated */
if (bytes_w < 0)
return bytes_w;
return used;
+}
+/*
- write a parameter structure into the buffer in following format:
- [cscfg_file_elem_str] - parameter name.
- [u64 value: param_value] - initial value.
- */
+static int cscfg_file_write_param(u8 *buffer, const int buflen,
struct cscfg_parameter_desc *param_desc)
+{
int used = 0, bytes_w;
bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
param_desc->name);
CHECK_WRET(bytes_w);
if ((buflen - used) < sizeof(u64))
return -EINVAL;
cscfg_write_u64(param_desc->value);
return used;
+} +/*
- Write a feature element from cscfg_feature_desc in following format:
- [cscfg_file_elem_header] - header length is total bytes to end of param structures.
- [cscfg_file_elem_str] - feature name.
- [cscfg_file_elem_str] - feature description.
- [u32 value: match_flags]
- [u16 value: nr_regs] - number of registers.
- [u16 value: nr_params] - number of parameters.
- [cscfg_regval_desc struct] * nr_regs
- [PARAM_ELEM] * nr_params
- */
+static int cscfg_file_write_feat(u8 *buffer, const int buflen,
struct cscfg_feature_desc *feat_desc)
+{
struct cscfg_file_elem_header ehdr;
struct cscfg_regval_desc *p_reg_desc;
int used = 0, bytes_w, i, space_req;
u32 val32;
ehdr.elem_length = 0;
ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_FEAT;
/* write element header at current buffer location */
bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
CHECK_WRET(bytes_w);
/* write out the name string */
bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
feat_desc->name);
CHECK_WRET(bytes_w)
/* write out the description string */
bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
feat_desc->description);
CHECK_WRET(bytes_w);
/* check for space for variables and register structures */
space_req = (sizeof(u16) * 2) + sizeof(u32) +
(sizeof(struct cscfg_regval_desc) * feat_desc->nr_regs);
if ((buflen - used) < space_req)
return -EINVAL;
/* write the variables */
cscfg_write_u32((u32)feat_desc->match_flags);
cscfg_write_u16((u16)feat_desc->nr_regs);
cscfg_write_u16((u16)feat_desc->nr_params);
/*write the registers */
for (i = 0; i < feat_desc->nr_regs; i++) {
p_reg_desc = (struct cscfg_regval_desc *)&feat_desc->regs_desc[i];
CSCFG_FILE_REG_DESC_INFO_TO_U32(val32, p_reg_desc);
cscfg_write_u32(val32);
cscfg_write_u64(feat_desc->regs_desc[i].val64);
}
/* write any parameters */
for (i = 0; i < feat_desc->nr_params; i++) {
bytes_w = cscfg_file_write_param(buffer + used, buflen - used,
&feat_desc->params_desc[i]);
CHECK_WRET(bytes_w);
}
/*
* rewrite the element header at the start of the buffer block
* with the correct length
*/
ehdr.elem_length = used;
bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
/* no CHECK_WRET as used must not be updated */
if (bytes_w < 0)
return bytes_w;
return used;
+}
+/*
- write a buffer from the configuration and feature
- descriptors to write into a file for configfs.
- Will only write one config, and/or a number of features,
- per the file standard.
- */
+int cscfg_file_write_buffer(u8 *buffer, const int buflen,
struct cscfg_config_desc *config_desc,
struct cscfg_feature_desc **feat_descs)
+{
struct cscfg_file_header fhdr;
int used = 0, bytes_w, i;
/* init the file header */
fhdr.magic_version = CSCFG_FILE_MAGIC_VERSION;
fhdr.length = 0;
fhdr.nr_features = 0;
/* count the features */
if (feat_descs) {
while (feat_descs[fhdr.nr_features])
fhdr.nr_features++;
}
/* need a buffer and at least one config or feature */
if ((!config_desc && !fhdr.nr_features) ||
!buffer || (buflen > CSCFG_FILE_MAXSIZE))
return -EINVAL;
/* write a header at the start to get the length of the header */
bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr);
CHECK_WRET(bytes_w);
/* write a single config */
if (config_desc) {
bytes_w = cscfg_file_write_config(buffer + used, buflen - used,
config_desc);
CHECK_WRET(bytes_w);
}
/* write any features */
for (i = 0; i < fhdr.nr_features; i++) {
bytes_w = cscfg_file_write_feat(buffer + used, buflen - used,
feat_descs[i]);
CHECK_WRET(bytes_w);
}
/* finally re-write the header at the buffer start with the correct length */
fhdr.length = (u16)used;
bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr);
/* no CHECK_WRET as used must not be updated */
if (bytes_w < 0)
return bytes_w;
return used;
+} diff --git a/tools/coresight/coresight-cfg-bufw.h b/tools/coresight/coresight-cfg-bufw.h new file mode 100644 index 000000000000..562df97599fc --- /dev/null +++ b/tools/coresight/coresight-cfg-bufw.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CFG_BUFW_H +#define _CORESIGHT_CFG_BUFW_H
+#include <linux/types.h>
+#include "coresight-config-file.h"
+/*
- Function to take coresight configurations and features and
- write them into a supplied memory buffer for serialisation
- into a file.
- Resulting file can then be loaded into the coresight
- infrastructure via configfs.
- */
+int cscfg_file_write_buffer(u8 *buffer, const int buflen,
struct cscfg_config_desc *config_desc,
struct cscfg_feature_desc **feat_descs);
+#endif /* _CORESIGHT_CFG_BUFW_H */ diff --git a/tools/coresight/coresight-cfg-example1.c b/tools/coresight/coresight-cfg-example1.c new file mode 100644 index 000000000000..a71a6e43d7b3 --- /dev/null +++ b/tools/coresight/coresight-cfg-example1.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <unistd.h>
+#include "coresight-cfg-bufw.h" +#include "coresight-cfg-examples.h"
+/*
- create a configuration only example using the strobing feature
- */
+/* we will provide 4 sets of preset parameter values */ +#define AFDO3_NR_PRESETS 4 +/* the total number of parameters in used features - strobing has 2 */ +#define AFDO3_NR_PARAM_SUM 2
+static const char *afdo3_ref_names[] = {
"strobing",
+};
+/*
- set of presets leaves strobing window constant while varying period to allow
- experimentation with mark / space ratios for various workloads
- */
+static u64 afdo3_presets[AFDO3_NR_PRESETS][AFDO3_NR_PARAM_SUM] = {
{ 2000, 100 },
{ 2000, 1000 },
{ 2000, 5000 },
{ 2000, 10000 },
+};
+struct cscfg_config_desc afdo3 = {
.name = "autofdo3",
.description = "Setup ETMs with strobing for autofdo\n"
"Supplied presets allow experimentation with mark-space ratio for various loads\n",
.nr_feat_refs = ARRAY_SIZE(afdo3_ref_names),
.feat_ref_names = afdo3_ref_names,
.nr_presets = AFDO3_NR_PRESETS,
.nr_total_params = AFDO3_NR_PARAM_SUM,
.presets = &afdo3_presets[0][0],
+};
+static struct cscfg_feature_desc *sample_feats[] = {
NULL
+};
+static struct cscfg_config_desc *sample_cfgs[] = {
&afdo3,
NULL
+};
+#define CSCFG_EG1_FILENAME "example1.cscfg"
+struct cscfg_file_eg_info buff_info_eg1 = {
.example_name = "example1",
.filename = CSCFG_EG1_FILENAME,
.config_descs = sample_cfgs,
.feat_descs = sample_feats,
+}; diff --git a/tools/coresight/coresight-cfg-examples.h b/tools/coresight/coresight-cfg-examples.h new file mode 100644 index 000000000000..5c6908745201 --- /dev/null +++ b/tools/coresight/coresight-cfg-examples.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CFG_EXAMPLES_H +#define _CORESIGHT_CFG_EXAMPLES_H
+#include <linux/kernel.h>
+#include "uapi/coresight-config-uapi.h" +#include "coresight-cfg-bufw.h"
+/* structure to pass configuraiton information to generator program */ +struct cscfg_file_eg_info {
const char *example_name;
const char *filename;
struct cscfg_config_desc **config_descs;
struct cscfg_feature_desc **feat_descs;
+};
+/* references to the configuration and feature example structures */ +extern struct cscfg_file_eg_info buff_info_eg1;
+#endif /* _CORESIGHT_CFG_EXAMPLES_H */ diff --git a/tools/coresight/coresight-cfg-file-read.c b/tools/coresight/coresight-cfg-file-read.c new file mode 100644 index 000000000000..da7b831eb2df --- /dev/null +++ b/tools/coresight/coresight-cfg-file-read.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h>
+#include "coresight-config-file.h" +#include "uapi/coresight-config-uapi.h"
+/*
- tool to read and print a generated configuration
- re-uses the read code source from the driver.
- */
+static void print_configs(struct cscfg_fs_load_descs *load_descs) +{
struct cscfg_config_desc *config_desc = load_descs->config_descs[0];
int i, j, p;
if (!config_desc) {
printf("File contains no configurations.\n\n");
return;
}
printf("Configuration name : %s\n", config_desc->name);
printf("Uses %d features:-\n", config_desc->nr_feat_refs);
for (i = 0; i < config_desc->nr_feat_refs; i++)
printf("Feature-%d: %s\n", i + 1, config_desc->feat_ref_names[i]);
printf("\nProvides %d sets of preset values, %d presets per set\n", config_desc->nr_presets,
config_desc->nr_total_params);
if (config_desc->nr_presets) {
for (i = 0; i < config_desc->nr_presets; i++) {
printf("set[%d]: ", i);
for (j = 0; j < config_desc->nr_total_params; j++) {
p = (i * config_desc->nr_total_params) + j;
printf("0x%lx, ", config_desc->presets[p]);
}
printf("\n");
}
}
printf("\n\n");
+}
+static void print_reg_type_info(u8 type) +{
if (type & CS_CFG_REG_TYPE_STD)
printf("std_reg ");
if (type & CS_CFG_REG_TYPE_RESOURCE)
printf("resource ");
if (type & CS_CFG_REG_TYPE_VAL_PARAM)
printf("param_index ");
if (type & CS_CFG_REG_TYPE_VAL_64BIT)
printf("64_bit ");
else
printf("32_bit ");
if (type & CS_CFG_REG_TYPE_VAL_MASK)
printf("masked ");
if (type & CS_CFG_REG_TYPE_VAL_SAVE)
printf("save_on_disable ");
+}
+static void print_regs(int nr, struct cscfg_regval_desc *regs_desc_array) +{
int i;
struct cscfg_regval_desc *reg_desc;
u8 type;
u16 offset;
u16 info;
for (i = 0; i < nr; i++) {
reg_desc = ®s_desc_array[i];
type = (u8)reg_desc->type;
offset = (u16)reg_desc->offset;
info = (u16)reg_desc->hw_info;
printf("Reg(%d): Type 0x%x: ", i, type);
print_reg_type_info(type);
printf("\nOffset: 0x%03x; HW Info: 0x%03x\n", offset, info);
printf("Value: ");
if (type & CS_CFG_REG_TYPE_VAL_64BIT)
printf("0x%lx\n", reg_desc->val64);
else if (type & CS_CFG_REG_TYPE_VAL_PARAM)
printf("idx = %d\n", reg_desc->param_idx);
else {
printf("0x%x ", reg_desc->val32);
if (type & CS_CFG_REG_TYPE_VAL_MASK)
printf(" mask: 0x%x", reg_desc->mask32);
printf("\n");
}
}
+}
+static void print_params(int nr, struct cscfg_parameter_desc *params_desc) +{
int i;
for (i = 0; i < nr; i++)
printf("Param(%d) : %s; Init value 0x%lx\n", i,
params_desc[i].name, params_desc[i].value);
+}
+static void print_features(struct cscfg_fs_load_descs *load_descs) +{
struct cscfg_feature_desc *feat_desc = 0;
int idx = 0;
feat_desc = load_descs->feat_descs[idx];
if (!feat_desc) {
printf("File contains no features\n\n");
return;
}
while (feat_desc) {
printf("Feature %d name : %s\n", idx+1, feat_desc->name);
printf("Description: %s\n", feat_desc->description);
printf("Match flags: 0x%x\n", feat_desc->match_flags);
printf("Number of Paraneters: %d\n", feat_desc->nr_params);
if (feat_desc->nr_params)
print_params(feat_desc->nr_params, feat_desc->params_desc);
printf("Number of Registers: %d\n", feat_desc->nr_regs);
if (feat_desc->nr_regs)
print_regs(feat_desc->nr_regs, feat_desc->regs_desc);
printf("\n\n");
/* next feature */
idx++;
feat_desc = load_descs->feat_descs[idx];
}
+}
+int main(int argc, char **argv) +{
FILE *fp;
struct cscfg_fs_load_descs *load_descs;
int err, fsize;
u8 buffer[CSCFG_FILE_MAXSIZE];
printf("CoreSight Configuration file reader\n\n");
/* need a filename */
if (argc <= 1) {
printf("Please provide filename on command line\n");
return -EINVAL;
}
/* open file and read into the buffer. */
fp = fopen(argv[1], "rb");
if (fp == NULL) {
printf("Error opening file %s\n", argv[1]);
return -EINVAL;
}
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
rewind(fp);
if (fsize > CSCFG_FILE_MAXSIZE) {
printf("Error: Input file too large.");
fclose(fp);
return -EINVAL;
}
err = fread(buffer, sizeof(u8), fsize, fp);
fclose(fp);
if (err < fsize) {
printf("Error reading file %s\n", argv[1]);
return -EINVAL;
}
/* allocate the descriptor structures to be populated by read operation */
load_descs = malloc(sizeof(struct cscfg_fs_load_descs));
if (!load_descs) {
printf("Error allocating load descs structure.\n");
return -ENOMEM;
}
/* read the buffer and create the configuration and feature structures */
err = cscfg_file_read_buffer(buffer, fsize, load_descs);
if (err) {
printf("Error reading configuration file\n");
goto exit_free_mem;
}
/* print the contents of the structures */
print_configs(load_descs);
print_features(load_descs);
+exit_free_mem:
free(load_descs);
return err;
+} diff --git a/tools/coresight/coresight-cfg-filegen.c b/tools/coresight/coresight-cfg-filegen.c new file mode 100644 index 000000000000..cd0589661d92 --- /dev/null +++ b/tools/coresight/coresight-cfg-filegen.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <unistd.h>
+#include "uapi/coresight-config-uapi.h" +#include "coresight-cfg-bufw.h" +#include "coresight-cfg-examples.h"
+/* array of example files to generate */ +struct cscfg_file_eg_info *info_ptrs[] = {
&buff_info_eg1,
NULL,
+};
+int main(int argc, char **argv) +{
struct cscfg_config_desc *config_desc;
struct cscfg_feature_desc **feat_descs;
u8 buffer[CSCFG_FILE_MAXSIZE];
int used, idx = 0;
FILE *fp;
const char *filename;
printf("Coresight Configuration file Generator\n\n");
while (info_ptrs[idx]) {
printf("Generating %s example\n", info_ptrs[idx]->example_name);
config_desc = info_ptrs[idx]->config_descs[0];
feat_descs = info_ptrs[idx]->feat_descs;
filename = info_ptrs[idx]->filename;
used = cscfg_file_write_buffer(buffer, CSCFG_FILE_MAXSIZE,
config_desc, feat_descs);
if (used < 0) {
printf("Error %d writing configuration %s into buffer\n",
used, info_ptrs[idx]->example_name);
return used;
}
fp = fopen(filename, "wb");
if (fp == NULL) {
printf("Error opening file %s\n", filename);
return -1;
}
fwrite(buffer, used, sizeof(u8), fp);
fclose(fp);
idx++;
}
return 0;
+} diff --git a/tools/include/uapi/coresight-config-uapi.h b/tools/include/uapi/coresight-config-uapi.h new file mode 100644 index 000000000000..d051c01ea982 --- /dev/null +++ b/tools/include/uapi/coresight-config-uapi.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CORESIGHT_CONFIG_UAPI_H +#define _CORESIGHT_CORESIGHT_CONFIG_UAPI_H
+#include <linux/types.h> +#include <asm-generic/errno-base.h>
+#include "coresight-config.h"
+/*
- Userspace versions of the configuration and feature descriptors.
- Used in the tools/coresight programs.
- Compatible with structures in coresight-config.h for use in
- coresight-config-file.c common reader source file.
- */
+/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
- UAPI version - removed kernel constructs.
- @name: feature name.
- @description: brief description of the feature.
- @match_flags: matching information if loading into a device
- @nr_params: number of parameters used.
- @params_desc: array of parameters used.
- @nr_regs: number of registers used.
- @regs_desc: array of registers used.
- */
+struct cscfg_feature_desc {
const char *name;
const char *description;
u32 match_flags;
int nr_params;
struct cscfg_parameter_desc *params_desc;
int nr_regs;
struct cscfg_regval_desc *regs_desc;
+};
+/**
- Configuration descriptor - describes selectable system configuration.
- A configuration describes device features in use, and may provide preset
- values for the parameters in those features.
- A single set of presets is the sum of the parameters declared by
- all the features in use - this value is @nr_total_params.
- UAPI version - removed kernel constructs.
- @name: name of the configuration - used for selection.
- @description: description of the purpose of the configuration.
- @nr_feat_refs: Number of features used in this configuration.
- @feat_ref_names: references to features used in this configuration.
- @nr_presets: Number of sets of presets supplied by this configuration.
- @nr_total_params: Sum of all parameters declared by used features
- @presets: Array of preset values.
- */
+struct cscfg_config_desc {
const char *name;
const char *description;
int nr_feat_refs;
const char **feat_ref_names;
int nr_presets;
int nr_total_params;
const u64 *presets; /* nr_presets * nr_total_params */
+};
I would call the above cscfg_feature_fs_desc and cscfg_config_fs_desc to make sure they don't get confused with the kernel's internal structures of the same name.
The issue here is that the common reader code expects structs of these names.
The alternative was to put multiple #if _KERNEL__ defines in the middle of the structures in the kernel headers to eliminate kernel only elements- which you pointed out in your comments to v2 of this set was a maintenence issue.
This is a least worst alternative. We have common reader code, there are minimal changes to the kernel headers - some of the structures in coresight-config.h are backeted by a __KERNEL__ define but those without kernel specific elements are used in full.
The cost is maintaining these two structures to be the same as the kernel versions - which I believe to be minimal as I do not expect the data format to change going forwards.
Moreover, I would keep this file private to tools/coresight/ and rename it coresight-config.h.
I can and have moved it. Howver this file includes the kernel coresight-config.h, so renaming is a non-starter.
Thanks and Regards
Mike
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_UAPI_H */
2.17.1
[...]
diff --git a/tools/include/uapi/coresight-config-uapi.h b/tools/include/uapi/coresight-config-uapi.h new file mode 100644 index 000000000000..d051c01ea982 --- /dev/null +++ b/tools/include/uapi/coresight-config-uapi.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CORESIGHT_CONFIG_UAPI_H +#define _CORESIGHT_CORESIGHT_CONFIG_UAPI_H
+#include <linux/types.h> +#include <asm-generic/errno-base.h>
+#include "coresight-config.h"
+/*
- Userspace versions of the configuration and feature descriptors.
- Used in the tools/coresight programs.
- Compatible with structures in coresight-config.h for use in
- coresight-config-file.c common reader source file.
- */
+/**
- Device feature descriptor - combination of registers and parameters to
- program a device to implement a specific complex function.
- UAPI version - removed kernel constructs.
- @name: feature name.
- @description: brief description of the feature.
- @match_flags: matching information if loading into a device
- @nr_params: number of parameters used.
- @params_desc: array of parameters used.
- @nr_regs: number of registers used.
- @regs_desc: array of registers used.
- */
+struct cscfg_feature_desc {
const char *name;
const char *description;
u32 match_flags;
int nr_params;
struct cscfg_parameter_desc *params_desc;
int nr_regs;
struct cscfg_regval_desc *regs_desc;
+};
+/**
- Configuration descriptor - describes selectable system configuration.
- A configuration describes device features in use, and may provide preset
- values for the parameters in those features.
- A single set of presets is the sum of the parameters declared by
- all the features in use - this value is @nr_total_params.
- UAPI version - removed kernel constructs.
- @name: name of the configuration - used for selection.
- @description: description of the purpose of the configuration.
- @nr_feat_refs: Number of features used in this configuration.
- @feat_ref_names: references to features used in this configuration.
- @nr_presets: Number of sets of presets supplied by this configuration.
- @nr_total_params: Sum of all parameters declared by used features
- @presets: Array of preset values.
- */
+struct cscfg_config_desc {
const char *name;
const char *description;
int nr_feat_refs;
const char **feat_ref_names;
int nr_presets;
int nr_total_params;
const u64 *presets; /* nr_presets * nr_total_params */
+};
I would call the above cscfg_feature_fs_desc and cscfg_config_fs_desc to make sure they don't get confused with the kernel's internal structures of the same name.
The issue here is that the common reader code expects structs of these names.
The alternative was to put multiple #if _KERNEL__ defines in the middle of the structures in the kernel headers to eliminate kernel only elements- which you pointed out in your comments to v2 of this set was a maintenence issue.
This is a least worst alternative. We have common reader code, there are minimal changes to the kernel headers - some of the structures in coresight-config.h are backeted by a __KERNEL__ define but those without kernel specific elements are used in full.
The cost is maintaining these two structures to be the same as the kernel versions - which I believe to be minimal as I do not expect the data format to change going forwards.
I agree with you - the current implementation is the least intrusive and easiest to maintain. Unless someone finds an alternative it is better to keep the current solution.
Moreover, I would keep this file private to tools/coresight/ and rename it coresight-config.h.
I can and have moved it. Howver this file includes the kernel coresight-config.h, so renaming is a non-starter.
Yes, you are correct.
Thanks and Regards
Mike
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_UAPI_H */
2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK
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 | 166 +++++++++++++++++- 1 file changed, 160 insertions(+), 6 deletions(-)
diff --git a/Documentation/trace/coresight/coresight-config.rst b/Documentation/trace/coresight/coresight-config.rst index 6d5ffa6f7347..9354cfcc04e3 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,16 @@ 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 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 +296,153 @@ 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. + +An example of a custom configuration module is found in './samples/coresight'. + +Using a Binary Configuration File +--------------------------------- + +The './tools/coresight' directory contains example programs to generate and +read and print binary configuration files. + +Building the tools creates the 'coresight-cfg-file-gen' 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-example1.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. Alternatively, addition examples can be added to the +'coresight-cfg-file-gen' program:: + + $ ./coresight-cfg-file-gen + Coresight Configuration file Generator + Generating example1 example + +The program 'coresight-cfg-file-read' can read back and print a configuration +binary. This is built using the file reader from the driver code +(coresight-config-file.c), which is copied over into './tools/coresight' at +build time.:: + + ./coresight-cfg-file-read example1.cscfg + CoreSight Configuration file reader + + Configuration name : autofdo3 + Uses 1 features:- + Feature-1: strobing + + Provides 4 sets of preset values, 2 presets per set + set[0]: 0x7d0, 0x64, + set[1]: 0x7d0, 0x3e8, + set[2]: 0x7d0, 0x1388, + set[3]: 0x7d0, 0x2710, + + File contains no features + +There are additional attributes in the configurations directory - load and +unload 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 load unload + $ cat example1.cscfg > /config/cs-syscfg/configurations/load + $ ls /config/cs-syscfg/configurations/ + autofdo autofdo3 last_load_status load unload + +To unload, use the same file in the unload attribute:: + + $ cat example1.cscfg > /config/cs-syscfg/configurations/unload + ls /config/cs-syscfg/configurations/ + autofdo load unload + + + +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.
On Thu, Apr 14, 2022 at 07:44:57AM +0100, 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 | 166 +++++++++++++++++- 1 file changed, 160 insertions(+), 6 deletions(-)
diff --git a/Documentation/trace/coresight/coresight-config.rst b/Documentation/trace/coresight/coresight-config.rst index 6d5ffa6f7347..9354cfcc04e3 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
"last_load_status" has been removed.
$ cd autofdo/ $ ls description feature_refs preset1 preset3 preset5 preset7 preset9
@@ -278,9 +278,16 @@ 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 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 +296,153 @@ 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.
+An example of a custom configuration module is found in './samples/coresight'.
+Using a Binary Configuration File +---------------------------------
+The './tools/coresight' directory contains example programs to generate and +read and print binary configuration files.
+Building the tools creates the 'coresight-cfg-file-gen' 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-example1.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. Alternatively, addition examples can be added to the +'coresight-cfg-file-gen' program::
- $ ./coresight-cfg-file-gen
- Coresight Configuration file Generator
- Generating example1 example
+The program 'coresight-cfg-file-read' can read back and print a configuration +binary. This is built using the file reader from the driver code +(coresight-config-file.c), which is copied over into './tools/coresight' at +build time.::
- ./coresight-cfg-file-read example1.cscfg
- CoreSight Configuration file reader
- Configuration name : autofdo3
- Uses 1 features:-
- Feature-1: strobing
- Provides 4 sets of preset values, 2 presets per set
- set[0]: 0x7d0, 0x64,
- set[1]: 0x7d0, 0x3e8,
- set[2]: 0x7d0, 0x1388,
- set[3]: 0x7d0, 0x2710,
- File contains no features
+There are additional attributes in the configurations directory - load and +unload 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 load unload
- $ cat example1.cscfg > /config/cs-syscfg/configurations/load
- $ ls /config/cs-syscfg/configurations/
- autofdo autofdo3 last_load_status load unload
Same
More comments tomorrow.
Thanks, Mathieu
+To unload, use the same file in the unload attribute::
- $ cat example1.cscfg > /config/cs-syscfg/configurations/unload
- ls /config/cs-syscfg/configurations/
- autofdo load unload
+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
On Thu, Apr 14, 2022 at 07:44:52AM +0100, Mike Leach wrote:
This set extends the configfs support to allow loading and unloading of configurations as binary files via configfs.
Additional attributes - load and unload are provided to in the configurations group to implement the load functionality.
Routines to generate binary configuration files are supplied in ./tools/coresight.
Example generator and reader applications are provided.
Tools may be cross compiled or built for use on host system.
Documentation is updated to describe feature usage.
Changes since v2:
- Rebased & tested oo coresight/next - 5.18-rc2
- Moved coresight config generator and reader programs from samples to
tools/coresight. Docs updated to match. (suggested by Mathieu) 3) userspace builds now use userspace headers from tools/... 4) Other minor fixes from Mathieu's review.
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 (5): 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: tools: Add config file write and reader tools Documentation: coresight: docs for config load via configfs
I have started reviewing this set. Comments will be spread out over several days. I will advise when I am done.
Thanks, Mathieu
.../trace/coresight/coresight-config.rst | 166 +++++- MAINTAINERS | 2 + drivers/hwtracing/coresight/Makefile | 2 +- .../coresight/coresight-config-file.c | 475 ++++++++++++++++++ .../coresight/coresight-config-file.h | 126 +++++ .../hwtracing/coresight/coresight-config.h | 27 + .../coresight/coresight-syscfg-configfs.c | 91 ++++ .../hwtracing/coresight/coresight-syscfg.c | 37 ++ .../hwtracing/coresight/coresight-syscfg.h | 2 + tools/coresight/Makefile | 51 ++ tools/coresight/coresight-cfg-bufw.c | 303 +++++++++++ tools/coresight/coresight-cfg-bufw.h | 26 + tools/coresight/coresight-cfg-example1.c | 65 +++ tools/coresight/coresight-cfg-examples.h | 27 + tools/coresight/coresight-cfg-file-read.c | 197 ++++++++ tools/coresight/coresight-cfg-filegen.c | 58 +++ tools/include/uapi/coresight-config-uapi.h | 76 +++ 17 files changed, 1724 insertions(+), 7 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config-file.c create mode 100644 drivers/hwtracing/coresight/coresight-config-file.h create mode 100644 tools/coresight/Makefile create mode 100644 tools/coresight/coresight-cfg-bufw.c create mode 100644 tools/coresight/coresight-cfg-bufw.h create mode 100644 tools/coresight/coresight-cfg-example1.c create mode 100644 tools/coresight/coresight-cfg-examples.h create mode 100644 tools/coresight/coresight-cfg-file-read.c create mode 100644 tools/coresight/coresight-cfg-filegen.c create mode 100644 tools/include/uapi/coresight-config-uapi.h
-- 2.17.1
On Thu, Apr 14, 2022 at 07:44:52AM +0100, Mike Leach wrote:
This set extends the configfs support to allow loading and unloading of configurations as binary files via configfs.
Additional attributes - load and unload are provided to in the configurations group to implement the load functionality.
Routines to generate binary configuration files are supplied in ./tools/coresight.
Example generator and reader applications are provided.
Tools may be cross compiled or built for use on host system.
Documentation is updated to describe feature usage.
I think this patchset is looking quite good now. The main issue for now is to know if we want to keep the capability to read and print configurations. To me it doesn't provide much for the quirks it adds, i.e patch 3.
James and/or Leo will also have to do a review. As such they should be added, along with Arnaldo, to the next revision.
I am done reviewing this set.
Thanks, Mathieu
Changes since v2:
- Rebased & tested oo coresight/next - 5.18-rc2
- Moved coresight config generator and reader programs from samples to
tools/coresight. Docs updated to match. (suggested by Mathieu) 3) userspace builds now use userspace headers from tools/... 4) Other minor fixes from Mathieu's review.
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 (5): 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: tools: Add config file write and reader tools Documentation: coresight: docs for config load via configfs
.../trace/coresight/coresight-config.rst | 166 +++++- MAINTAINERS | 2 + drivers/hwtracing/coresight/Makefile | 2 +- .../coresight/coresight-config-file.c | 475 ++++++++++++++++++ .../coresight/coresight-config-file.h | 126 +++++ .../hwtracing/coresight/coresight-config.h | 27 + .../coresight/coresight-syscfg-configfs.c | 91 ++++ .../hwtracing/coresight/coresight-syscfg.c | 37 ++ .../hwtracing/coresight/coresight-syscfg.h | 2 + tools/coresight/Makefile | 51 ++ tools/coresight/coresight-cfg-bufw.c | 303 +++++++++++ tools/coresight/coresight-cfg-bufw.h | 26 + tools/coresight/coresight-cfg-example1.c | 65 +++ tools/coresight/coresight-cfg-examples.h | 27 + tools/coresight/coresight-cfg-file-read.c | 197 ++++++++ tools/coresight/coresight-cfg-filegen.c | 58 +++ tools/include/uapi/coresight-config-uapi.h | 76 +++ 17 files changed, 1724 insertions(+), 7 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config-file.c create mode 100644 drivers/hwtracing/coresight/coresight-config-file.h create mode 100644 tools/coresight/Makefile create mode 100644 tools/coresight/coresight-cfg-bufw.c create mode 100644 tools/coresight/coresight-cfg-bufw.h create mode 100644 tools/coresight/coresight-cfg-example1.c create mode 100644 tools/coresight/coresight-cfg-examples.h create mode 100644 tools/coresight/coresight-cfg-file-read.c create mode 100644 tools/coresight/coresight-cfg-filegen.c create mode 100644 tools/include/uapi/coresight-config-uapi.h
-- 2.17.1
HI Mathieu,
On Fri, 27 May 2022 at 17:32, Mathieu Poirier mathieu.poirier@linaro.org wrote:
On Thu, Apr 14, 2022 at 07:44:52AM +0100, Mike Leach wrote:
This set extends the configfs support to allow loading and unloading of configurations as binary files via configfs.
Additional attributes - load and unload are provided to in the configurations group to implement the load functionality.
Routines to generate binary configuration files are supplied in ./tools/coresight.
Example generator and reader applications are provided.
Tools may be cross compiled or built for use on host system.
Documentation is updated to describe feature usage.
I think this patchset is looking quite good now. The main issue for now is to know if we want to keep the capability to read and print configurations. To me it doesn't provide much for the quirks it adds, i.e patch 3.
Given that the binary configuration files are very portable, I think the reader is essential. It is possible to install / use ETM4 configuration files on kernels / systems separate from which they were built for (unlike configurations in loadable modules which are bound to a kernel build).
It may be that a user of a file does not have the original source for that file - which is fine as long as it can be passed through the reader and evaluated by the user to assess suitability for the current target.
James and/or Leo will also have to do a review. As such they should be added, along with Arnaldo, to the next revision.
OK
Thanks
Mike
I am done reviewing this set.
Thanks, Mathieu
Changes since v2:
- Rebased & tested oo coresight/next - 5.18-rc2
- Moved coresight config generator and reader programs from samples to
tools/coresight. Docs updated to match. (suggested by Mathieu) 3) userspace builds now use userspace headers from tools/... 4) Other minor fixes from Mathieu's review.
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 (5): 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: tools: Add config file write and reader tools Documentation: coresight: docs for config load via configfs
.../trace/coresight/coresight-config.rst | 166 +++++- MAINTAINERS | 2 + drivers/hwtracing/coresight/Makefile | 2 +- .../coresight/coresight-config-file.c | 475 ++++++++++++++++++ .../coresight/coresight-config-file.h | 126 +++++ .../hwtracing/coresight/coresight-config.h | 27 + .../coresight/coresight-syscfg-configfs.c | 91 ++++ .../hwtracing/coresight/coresight-syscfg.c | 37 ++ .../hwtracing/coresight/coresight-syscfg.h | 2 + tools/coresight/Makefile | 51 ++ tools/coresight/coresight-cfg-bufw.c | 303 +++++++++++ tools/coresight/coresight-cfg-bufw.h | 26 + tools/coresight/coresight-cfg-example1.c | 65 +++ tools/coresight/coresight-cfg-examples.h | 27 + tools/coresight/coresight-cfg-file-read.c | 197 ++++++++ tools/coresight/coresight-cfg-filegen.c | 58 +++ tools/include/uapi/coresight-config-uapi.h | 76 +++ 17 files changed, 1724 insertions(+), 7 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config-file.c create mode 100644 drivers/hwtracing/coresight/coresight-config-file.h create mode 100644 tools/coresight/Makefile create mode 100644 tools/coresight/coresight-cfg-bufw.c create mode 100644 tools/coresight/coresight-cfg-bufw.h create mode 100644 tools/coresight/coresight-cfg-example1.c create mode 100644 tools/coresight/coresight-cfg-examples.h create mode 100644 tools/coresight/coresight-cfg-file-read.c create mode 100644 tools/coresight/coresight-cfg-filegen.c create mode 100644 tools/include/uapi/coresight-config-uapi.h
-- 2.17.1
-- Mike Leach Principal Engineer, ARM Ltd. Manchester Design Centre. UK