Hi Mathieu,
On Fri, 28 Jan 2022 at 18:08, Mathieu Poirier mathieu.poirier@linaro.org wrote:
Good morning Mike,
Please find below (and in upcoming emails) the rest or my comments for this set.
On Tue, Nov 30, 2021 at 10:00:55PM +0000, Mike Leach wrote:
Add in functionality to allow load via configfs.
define a binary file format and provide a reader for that format that will create and populate configuration and feature structures use by the driver infrastructure.
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/Makefile | 2 +- .../coresight/coresight-config-file.c | 432 ++++++++++++++++++ .../coresight/coresight-config-file.h | 118 +++++ .../hwtracing/coresight/coresight-config.h | 17 + .../hwtracing/coresight/coresight-syscfg.h | 1 + 5 files changed, 569 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-config-file.c create mode 100644 drivers/hwtracing/coresight/coresight-config-file.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index b6c4a48140ec..5de2bb79f4ac 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ coresight-sysfs.o coresight-syscfg.o coresight-config.o \ coresight-cfg-preload.o coresight-cfg-afdo.o \
coresight-syscfg-configfs.o
coresight-syscfg-configfs.o coresight-config-file.oobj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config-file.c b/drivers/hwtracing/coresight/coresight-config-file.c new file mode 100644 index 000000000000..3fd001938324 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.c @@ -0,0 +1,432 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include "coresight-config.h" +#include "coresight-config-file.h" +#include "coresight-syscfg.h"
+#define cscfg_extract_u64(val64) { \
val64 = *(u64 *)(buffer + used); \used += sizeof(u64); \}+#define cscfg_extract_u32(val32) { \
val32 = *(u32 *)(buffer + used); \used += sizeof(u32); \}+#define cscfg_extract_u16(val16) { \
val16 = *(u16 *)(buffer + used); \used += sizeof(u16); \}+#define cscfg_extract_u8(val8) { \
val8 = *(buffer + used); \used++; \}+static int cscfg_file_read_hdr(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_header *hdr)+{
/* file header always at the start of the buffer */int used = 0;if (buflen < sizeof(struct cscfg_file_header))return -EINVAL;cscfg_extract_u32(hdr->magic_version);if (hdr->magic_version != CSCFG_FILE_MAGIC_VERSION)return -EINVAL;cscfg_extract_u16(hdr->length);if (hdr->length > buflen)return -EINVAL;cscfg_extract_u16(hdr->nr_features);*buf_used = used;return 0;+}
+static int cscfg_file_read_elem_hdr(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_elem_header *elem_hdr)+{
int used = *buf_used;if ((buflen - used) < (sizeof(u16) + sizeof(u8)))return -EINVAL;/* read length and check enough buffer remains for this element */elem_hdr->elem_length = *(u16 *)(buffer + used);if ((buflen - used) < elem_hdr->elem_length)return -EINVAL;/* don't use extract fn as we update used _after_ the comparison */used += sizeof(u16);/* read type and validate */cscfg_extract_u8(elem_hdr->elem_type);if ((elem_hdr->elem_type < CSCFG_FILE_ELEM_TYPE_FEAT) ||(elem_hdr->elem_type > CSCFG_FILE_ELEM_TYPE_CFG))return -EINVAL;*buf_used = used;return 0;+}
+static int cscfg_file_read_elem_str(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_elem_str *elem_str)+{
int used = *buf_used;if ((buflen - used) < sizeof(u16))return -EINVAL;cscfg_extract_u16(elem_str->str_len);if ((buflen - used) < elem_str->str_len)return -EINVAL;/* check for 0 termination */if (buffer[elem_str->str_len - 1] != 0)return -EINVAL;elem_str->str = devm_kstrdup(cscfg_device(), (char *)buffer, GFP_KERNEL);used += elem_str->str_len;*buf_used = used;return 0;+}
+static int cscfg_file_alloc_desc_arrays(struct cscfg_fs_load_descs *desc_arrays,
int nr_features)+{
/* arrays are 0 terminated - max of 1 config & nr_features features */desc_arrays->config_descs = devm_kcalloc(cscfg_device(), 2,sizeof(struct cscfg_config_desc *),GFP_KERNEL);if (!desc_arrays->config_descs)return -ENOMEM;desc_arrays->feat_descs = devm_kcalloc(cscfg_device(), nr_features + 1,sizeof(struct cscfg_feature_desc *),GFP_KERNEL);if (!desc_arrays->feat_descs)return -ENOMEM;return 0;+}
+static int cscfg_file_read_elem_config(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_fs_load_descs *desc_arrays)+{
struct cscfg_file_elem_header elem_hdr;struct cscfg_file_elem_str elem_str;struct cscfg_config_desc *config_desc;int used = *buf_used, nr_preset_vals, nr_preset_bytes, i;int err = 0;u64 *presets;/** read the header - if not config, then don't update buf_used* pointer on return*/err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr);if (err)return err;if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_CFG)return 0;/* we have a config - allocate the descriptor */config_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_config_desc),GFP_KERNEL);if (!config_desc)return -ENOMEM;/* read the name string */err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);if (err)return err;config_desc->name = elem_str.str;/* read the description string */err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);if (err)return err;config_desc->description = elem_str.str;/* read in some values */if ((buflen - used) < sizeof(u64))return -EINVAL;cscfg_extract_u16(config_desc->nr_presets);cscfg_extract_u32(config_desc->nr_total_params);cscfg_extract_u16(config_desc->nr_feat_refs);/* read the array of 64bit presets if present */nr_preset_vals = config_desc->nr_total_params * config_desc->nr_presets;if (nr_preset_vals) {presets = devm_kcalloc(cscfg_device(), nr_preset_vals,sizeof(u64), GFP_KERNEL);if (!presets)return -ENOMEM;nr_preset_bytes = sizeof(u64) * nr_preset_vals;if ((buflen - used) < nr_preset_bytes)return -EINVAL;memcpy(presets, (buffer + used), nr_preset_bytes);config_desc->presets = presets;used += nr_preset_bytes;}/* read the array of feature names referenced by the config */if (config_desc->nr_feat_refs) {config_desc->feat_ref_names = devm_kcalloc(cscfg_device(),config_desc->nr_feat_refs,sizeof(char *),GFP_KERNEL);if (!config_desc->feat_ref_names)return -ENOMEM;for (i = 0; i < config_desc->nr_feat_refs; i++) {err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);if (err)return err;config_desc->feat_ref_names[i] = elem_str.str;}}desc_arrays->config_descs[0] = config_desc;*buf_used = used;return 0;+}
+/* just read the config name - if there is a config at this position */ +static int cscfg_file_read_elem_config_name(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_elem_str *elem_str)+{
struct cscfg_file_elem_header elem_hdr;int used = *buf_used;int err;elem_str->str_len = 0;/** read the header - if not config, then don't update buf_used* pointer on return*/err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr);if (err)return err;if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_CFG)return 0;/* read the name string */err = cscfg_file_read_elem_str(buffer, buflen, &used, elem_str);if (err)return err;*buf_used = used;return 0;+}
+static int cscfg_file_read_elem_param(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_parameter_desc *param_desc)+{
struct cscfg_file_elem_str elem_str;int err = 0, used = *buf_used;/* parameter name */err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);if (err)return err;param_desc->name = elem_str.str;/* parameter value */if ((buflen - used) < sizeof(u64))return -EINVAL;cscfg_extract_u64(param_desc->value);*buf_used = used;return err;+}
+static int cscfg_file_read_elem_feature(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_fs_load_descs *desc_arrays,const int feat_idx)+{
struct cscfg_file_elem_header elem_hdr;struct cscfg_file_elem_str elem_str;struct cscfg_feature_desc *feat_desc;struct cscfg_regval_desc *p_reg_desc;int used = *buf_used, err, i, nr_regs_bytes;u32 val32;/* allocate the feature descriptor object */feat_desc = devm_kzalloc(cscfg_device(), sizeof(struct cscfg_feature_desc),GFP_KERNEL);if (!feat_desc)return -ENOMEM;/* read and check the element header */err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr);if (err)return err;if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_FEAT)return -EINVAL;/* read the feature name */err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);if (err)return err;feat_desc->name = elem_str.str;/* read the description string */err = cscfg_file_read_elem_str(buffer, buflen, &used, &elem_str);if (err)return err;feat_desc->description = elem_str.str;/** read in some values* [u32 value: match_flags]* [u16 value: nr_regs] - number of registers.* [u16 value: nr_params] - number of parameters.*/cscfg_extract_u32(feat_desc->match_flags);cscfg_extract_u16(feat_desc->nr_regs);cscfg_extract_u16(feat_desc->nr_params);/* register descriptors - 32 bit + 64 bit value */if (feat_desc->nr_regs) {nr_regs_bytes = ((sizeof(u32) + sizeof(u64)) * feat_desc->nr_regs);if ((buflen - used) < nr_regs_bytes)return -EINVAL;feat_desc->regs_desc = devm_kcalloc(cscfg_device(),feat_desc->nr_regs,sizeof(struct cscfg_regval_desc),GFP_KERNEL);if (!feat_desc->regs_desc)return -ENOMEM;for (i = 0; i < feat_desc->nr_regs; i++) {cscfg_extract_u32(val32);p_reg_desc = (struct cscfg_regval_desc *)&feat_desc->regs_desc[i];CSCFG_FILE_U32_TO_REG_DESC_INFO(val32, p_reg_desc);cscfg_extract_u64(feat_desc->regs_desc[i].val64);}}/* parameter descriptors - string + 64 bit value */if (feat_desc->nr_params) {feat_desc->params_desc = devm_kcalloc(cscfg_device(),feat_desc->nr_params,sizeof(struct cscfg_parameter_desc),GFP_KERNEL);if (!feat_desc->params_desc)return -ENOMEM;for (i = 0; i < feat_desc->nr_params; i++) {err = cscfg_file_read_elem_param(buffer, buflen, &used,&feat_desc->params_desc[i]);if (err)return err;}}desc_arrays->feat_descs[feat_idx] = feat_desc;*buf_used = used;return 0;+}
+/* just read the feature name - if there is a feature at this position */ +static int cscfg_file_read_elem_feat_name(const u8 *buffer, const int buflen, int *buf_used,
struct cscfg_file_elem_str *elem_str)+{
struct cscfg_file_elem_header elem_hdr;int used = *buf_used;int err;elem_str->str_len = 0;/** read the header - if not config, then don't update buf_used* pointer on return*/err = cscfg_file_read_elem_hdr(buffer, buflen, &used, &elem_hdr);if (err)return err;if (elem_hdr.elem_type != CSCFG_FILE_ELEM_TYPE_FEAT)return -EINVAL;/* read the feature name */err = cscfg_file_read_elem_str(buffer, buflen, &used, elem_str);if (err)return err;*buf_used = used;return 0;+}
+/*
- Read a buffer and create the configuration and feature
- descriptors to load into the cscfg system
- */
+int cscfg_file_read_buffer(const u8 *buffer, const int buflen,
struct cscfg_fs_load_descs *desc_arrays)+{
struct cscfg_file_header hdr;int used = 0, err, i;/* read in the file header */err = cscfg_file_read_hdr(buffer, buflen, &used, &hdr);if (err)return err;/* allocate the memory for the descriptor pointer arrays */err = cscfg_file_alloc_desc_arrays(desc_arrays, hdr.nr_features);if (err)return err;/* read elements *//* first element could be a config so check */err = cscfg_file_read_elem_config(buffer, buflen, &used, desc_arrays);if (err)return err;/* now read and populate all the feature descriptors */for (i = 0; i < hdr.nr_features; i++) {err = cscfg_file_read_elem_feature(buffer, buflen, &used, desc_arrays, i);if (err)return err;}return used;+}
+int cscfg_file_read_buffer_first_name(const u8 *buffer, const int buflen,
const char **name)+{
struct cscfg_file_header hdr;struct cscfg_file_elem_str elem_str;int used = 0, err = 0;*name = NULL;/* read in the file header */err = cscfg_file_read_hdr(buffer, buflen, &used, &hdr);if (err)return err;err = cscfg_file_read_elem_config_name(buffer, buflen, &used, &elem_str);if (err)return err;/* no config string - get first feature name */if (!elem_str.str_len) {err = cscfg_file_read_elem_feat_name(buffer, buflen, &used, &elem_str);if (err)return err;}if (elem_str.str_len)*name = elem_str.str;return err;+}
I haven't found a problem or a bug in the above.
diff --git a/drivers/hwtracing/coresight/coresight-config-file.h b/drivers/hwtracing/coresight/coresight-config-file.h new file mode 100644 index 000000000000..6c8c5af0a614 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config-file.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CORESIGHT_CONFIG_FILE_H +#define _CORESIGHT_CORESIGHT_CONFIG_FILE_H
+/*
- Structures to represent configuration descriptors in a memory buffer
- to serialise to and from files
- File structure - for loading a configuration + features
- from configfs.
- [cscfg_file_header] - mandatory
- [CONFIG_ELEM] - optional - only one permitted,
- [FEATURE_ELEM] * [cscfg_file_header.nr_features]
- optional - file valid with config only.
- Invalid file if no config or features.
- File structure for [CONFIG_ELEM]:
- [cscfg_file_elem_header] - header length value to end of feature strings.
- [cscfg_file_elem_str] - name of the configuration
- [cscfg_file_elem_str] - description of configuration
- [u16 value - nr_presets]
- [u32 value - nr_total_params]
- [u16 value - nr_feat_refs]
- [u64 values] * (nr_presets * nr_total_params)
- [cscfg_file_elem_str] * nr_feat_refs
- Only one configuration per file.
- File structure for a [FEATURE_ELEM]
- [cscfg_file_elem_header] - header length is total bytes to end of param structures.
- [cscfg_file_elem_str] - feature name.
- [cscfg_file_elem_str] - feature description.
- [u32 value: match_flags]
- [u16 value: nr_regs] - number of registers.
- [u16 value: nr_params] - number of parameters.
- [cscfg_regval_desc struct] * nr_regs
- [PARAM_ELEM] * nr_params
- File structure for [PARAM_ELEM]
- [cscfg_file_elem_str] - parameter name.
- [u64 value: param_value] - initial value.
- */
The above is really really dry, even for someone that is acquainted with the CS subsystem and the complex configuration feature. I doubt someone looking to start with the subsystem will be able to understand what is going on.
I am hoping that the additional documentation in patch 6 should provide additional exaplanation, as the exaplantion appears alongside the details of how the coresight config system works.
+/* major element types - configurations and features */
+#define CSCFG_FILE_ELEM_TYPE_FEAT 0x1 +#define CSCFG_FILE_ELEM_TYPE_CFG 0x2
+#define CSCFG_FILE_MAGIC_VERSION 0xC5CF0001
I like that magic number.
+#define CSCFG_FILE_U32_TO_REG_DESC_INFO(val32, p_desc) \
{ \p_desc->type = (val32 >> 24) & 0xFF; \p_desc->offset = (val32 >> 12) & 0xFFF; \p_desc->hw_info = val32 & 0xFFF; \}+#define CSCFG_FILE_REG_DESC_INFO_TO_U32(val32, p_desc) \
{ \val32 = p_desc->hw_info & 0xFFF; \val32 |= ((p_desc->offset & 0xFFF) << 12); \val32 |= ((p_desc->type & 0xFF) << 24); \}+/* binary attributes in configfs need a max size - declare a value for this. */ +#define CSCFG_FILE_MAXSIZE 16384
+/* limit string sizes */ +#define CSCFG_FILE_STR_MAXSIZE 1024
Extra newline.
will fix
Thanks for the review.
Mike
+/**
- file header.
- @magic_version: magic number / version for file/buffer format.
- @length : total length of all data in the buffer.
- @nr_features : total number of features in the buffer.
- */
+struct cscfg_file_header {
u32 magic_version;u16 length;u16 nr_features;+};
+/**
- element header
- @elem_length: total length of this element
- @elem_type : type of this element - one of CSCFG_FILE_ELEM_TYPE.. defines.
- */
+struct cscfg_file_elem_header {
u16 elem_length;u8 elem_type;+};
+/**
- string file element.
- @str_len: length of string buffer including 0 terminator
- @str : string buffer - 0 terminated.
- */
+struct cscfg_file_elem_str {
u16 str_len;char *str;+};
+#endif /* _CORESIGHT_CORESIGHT_CONFIG_FILE_H */ diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 9bd44b940add..770986316bc2 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -150,6 +150,23 @@ struct cscfg_config_desc { struct config_group *fs_group; };
+/**
- Dynamically loaded descriptor arrays loaded via configfs.
- For builtin or module loaded configurations / features these are
- statically defined at compile time. For configfs we create the arrays
- dynamically so need a structure to handle this.
- @owner_info: associated owner info struct to add to load order list.
- @config_descs: array of config descriptor pointers.
- @feat_descs: array of feature descriptor pointers.
- */
+struct cscfg_fs_load_descs {
void *owner_info;struct cscfg_config_desc **config_descs;struct cscfg_feature_desc **feat_descs;+};
/**
- config register instance - part of a loaded feature.
maps register values to csdev driver structuresdiff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 9106ffab4833..6a6e33585be9 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -66,6 +66,7 @@ struct cscfg_registered_csdev { enum cscfg_load_owner_type { CSCFG_OWNER_PRELOAD, CSCFG_OWNER_MODULE,
CSCFG_OWNER_CONFIGFS,Other than the above comments this patch works.
};
/**
2.17.1