Good morning Mike,
On Tue, Nov 30, 2021 at 10:00:58PM +0000, Mike Leach wrote:
Add an example file generator to test loading configurations via a binary attribute in configfs.
Provides a file buffer writer function that can be re-used in other userspace programs.
Buffer write format matches that expected by the corresponding reader in the configfs driver code.
Despite trying quite hard I haven't found a single bug in this patchset, which is a feat for user space code.
Please see comments below...
Signed-off-by: Mike Leach mike.leach@linaro.org
samples/coresight/Makefile | 7 + samples/coresight/coresight-cfg-bufw.c | 302 ++++++++++++++++++++++ samples/coresight/coresight-cfg-bufw.h | 24 ++ samples/coresight/coresight-cfg-filegen.c | 89 +++++++ 4 files changed, 422 insertions(+) create mode 100644 samples/coresight/coresight-cfg-bufw.c create mode 100644 samples/coresight/coresight-cfg-bufw.h create mode 100644 samples/coresight/coresight-cfg-filegen.c
diff --git a/samples/coresight/Makefile b/samples/coresight/Makefile index b3fce4af2347..07bfd99d7a68 100644 --- a/samples/coresight/Makefile +++ b/samples/coresight/Makefile @@ -1,4 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-only +# coresight config - loadable module configuration. obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG) += coresight-cfg-sample.o ccflags-y += -I$(srctree)/drivers/hwtracing/coresight
+# coresight config - configfs loadable binary config generator +userprogs-always-y += coresight-cfg-filegen
+coresight-cfg-filegen-objs := coresight-cfg-filegen.o coresight-cfg-bufw.o +userccflags += -I$(srctree)/drivers/hwtracing/coresight diff --git a/samples/coresight/coresight-cfg-bufw.c b/samples/coresight/coresight-cfg-bufw.c new file mode 100644 index 000000000000..8c32a8509eef --- /dev/null +++ b/samples/coresight/coresight-cfg-bufw.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
Are you sure you want to keep this to 2020? Here and in all other files.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <string.h>
+#include "coresight-cfg-bufw.h"
+/*
- Set of macros to make writing the buffer code easier.
- *.
Extra '.'
- Uses naming convention as 'buffer' for the buffer pointer and
- 'used' as the current bytes used by the encosing function.
- */
+#define cscfg_write_u64(val64) { \
- *(u64 *)(buffer + used) = val64; \
- used += sizeof(u64); \
- }
+#define cscfg_write_u32(val32) { \
- *(u32 *)(buffer + used) = val32; \
- used += sizeof(u32); \
- }
+#define cscfg_write_u16(val16) { \
- *(u16 *)(buffer + used) = val16; \
- used += sizeof(u16); \
- }
+#define cscfg_write_u8(val8) { \
- *(buffer + used) = val8; \
- used++; \
- }
+#define CHECK_WRET(rval) { \
- if (rval < 0) \
return rval; \
- used += rval; \
- }
+/* write the header at the start of the buffer */ +static int cscfg_file_write_fhdr(u8 *buffer, const int buflen,
const struct cscfg_file_header *fhdr)
+{
- int used = 0;
- cscfg_write_u32(fhdr->magic_version);
- cscfg_write_u16(fhdr->length);
- cscfg_write_u16(fhdr->nr_features);
- return used;
+}
+static int cscfg_file_write_string(u8 *buffer, const int buflen, const char *string) +{
- int len, used = 0;
- len = strlen(string);
- if (len > CSCFG_FILE_STR_MAXSIZE)
return -EINVAL;
- if (buflen < (len + 1 + sizeof(u16)))
return -EINVAL;
- cscfg_write_u16((u16)(len + 1));
- strcpy((char *)(buffer + used), string);
- used += (len + 1);
- return used;
+}
+static int cscfg_file_write_elem_hdr(u8 *buffer, const int buflen,
struct cscfg_file_elem_header *ehdr)
+{
- int used = 0;
- if (buflen < (sizeof(u16) + sizeof(u8)))
return -EINVAL;
- cscfg_write_u16(ehdr->elem_length);
- cscfg_write_u8(ehdr->elem_type);
- return used;
+}
Extra newline
+static int cscfg_file_write_config(u8 *buffer, const int buflen,
struct cscfg_config_desc *config_desc)
+{
- int used = 0, bytes_w, space_req, preset_bytes, i;
- struct cscfg_file_elem_header ehdr;
- ehdr.elem_length = 0;
- ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_CFG;
- /* write element header at current buffer location */
- bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
- CHECK_WRET(bytes_w);
- /* write out the configuration name */
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
config_desc->name);
- CHECK_WRET(bytes_w);
- /* write out the description string */
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
config_desc->description);
- CHECK_WRET(bytes_w);
- /*
* calculate the space needed for variables + presets
* [u16 value - nr_presets]
* [u32 value - nr_total_params]
* [u16 value - nr_feat_refs]
* [u64 values] * (nr_presets * nr_total_params)
*/
- preset_bytes = sizeof(u64) * config_desc->nr_presets * config_desc->nr_total_params;
- space_req = (sizeof(u16) * 2) + sizeof(u32) + preset_bytes;
- if ((buflen - used) < space_req)
return -EINVAL;
- cscfg_write_u16((u16)config_desc->nr_presets);
- cscfg_write_u32((u32)config_desc->nr_total_params);
- cscfg_write_u16((u16)config_desc->nr_feat_refs);
- if (preset_bytes) {
memcpy(buffer + used, (u8 *)config_desc->presets, preset_bytes);
used += preset_bytes;
- }
- /* now write the feature ref names */
- for (i = 0; i < config_desc->nr_feat_refs; i++) {
bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
config_desc->feat_ref_names[i]);
CHECK_WRET(bytes_w);
- }
- /* rewrite the element header with the correct length */
- ehdr.elem_length = used;
- bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
- /* no CHECK_WRET as used must not be updated */
- if (bytes_w < 0)
return bytes_w;
- return used;
+}
+/*
- write a parameter structure into the buffer in following format:
- [cscfg_file_elem_str] - parameter name.
- [u64 value: param_value] - initial value.
- */
+static int cscfg_file_write_param(u8 *buffer, const int buflen,
struct cscfg_parameter_desc *param_desc)
+{
- int used = 0, bytes_w;
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
param_desc->name);
- CHECK_WRET(bytes_w);
- if ((buflen - used) < sizeof(u64))
return -EINVAL;
- cscfg_write_u64(param_desc->value);
- return used;
+} +/*
- Write a feature element from cscfg_feature_desc in following format:
- [cscfg_file_elem_header] - header length is total bytes to end of param structures.
- [cscfg_file_elem_str] - feature name.
- [cscfg_file_elem_str] - feature description.
- [u32 value: match_flags]
- [u16 value: nr_regs] - number of registers.
- [u16 value: nr_params] - number of parameters.
- [cscfg_regval_desc struct] * nr_regs
- [PARAM_ELEM] * nr_params
Extra newlines
- */
+static int cscfg_file_write_feat(u8 *buffer, const int buflen,
struct cscfg_feature_desc *feat_desc)
+{
- struct cscfg_file_elem_header ehdr;
- struct cscfg_regval_desc *p_reg_desc;
- int used = 0, bytes_w, i, space_req;
- u32 val32;
- ehdr.elem_length = 0;
- ehdr.elem_type = CSCFG_FILE_ELEM_TYPE_FEAT;
- /* write element header at current buffer location */
- bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
- CHECK_WRET(bytes_w);
- /* write out the name string */
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
feat_desc->name);
- CHECK_WRET(bytes_w)
- /* write out the description string */
- bytes_w = cscfg_file_write_string(buffer + used, buflen - used,
feat_desc->description);
- CHECK_WRET(bytes_w);
- /* check for space for variables and register structures */
- space_req = (sizeof(u16) * 2) + sizeof(u32) +
(sizeof(struct cscfg_regval_desc) * feat_desc->nr_regs);
- if ((buflen - used) < space_req)
return -EINVAL;
- /* write the variables */
- cscfg_write_u32((u32)feat_desc->match_flags);
- cscfg_write_u16((u16)feat_desc->nr_regs);
- cscfg_write_u16((u16)feat_desc->nr_params);
- /*write the registers */
- for (i = 0; i < feat_desc->nr_regs; i++) {
p_reg_desc = (struct cscfg_regval_desc *)&feat_desc->regs_desc[i];
CSCFG_FILE_REG_DESC_INFO_TO_U32(val32, p_reg_desc);
cscfg_write_u32(val32);
cscfg_write_u64(feat_desc->regs_desc[i].val64);
- }
- /* write any parameters */
- for (i = 0; i < feat_desc->nr_params; i++) {
bytes_w = cscfg_file_write_param(buffer + used, buflen - used,
&feat_desc->params_desc[i]);
CHECK_WRET(bytes_w);
- }
- /*
* rewrite the element header at the start of the buffer block
* with the correct length
*/
- ehdr.elem_length = used;
- bytes_w = cscfg_file_write_elem_hdr(buffer, buflen, &ehdr);
- /* no CHECK_WRET as used must not be updated */
- if (bytes_w < 0)
return bytes_w;
- return used;
+}
+/*
- write a buffer from the configuration and feature
- descriptors to write into a file for configfs.
- Will only write one config, and/or a number of features,
- per the file standard.
- */
+int cscfg_file_write_buffer(u8 *buffer, const int buflen,
struct cscfg_config_desc *config_desc,
struct cscfg_feature_desc **feat_descs)
+{
- struct cscfg_file_header fhdr;
- int used = 0, bytes_w, i;
- /* init the file header */
- fhdr.magic_version = CSCFG_FILE_MAGIC_VERSION;
- fhdr.length = 0;
- fhdr.nr_features = 0;
- /* count the features */
- if (feat_descs) {
while (feat_descs[fhdr.nr_features])
fhdr.nr_features++;
- }
- /* need a buffer and at least one config or feature */
- if ((!config_desc && !fhdr.nr_features) ||
!buffer || (buflen > CSCFG_FILE_MAXSIZE))
return -EINVAL;
- /* write a header at the start to get the length of the header */
- bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr);
- CHECK_WRET(bytes_w);
- /* write a single config */
- if (config_desc) {
bytes_w = cscfg_file_write_config(buffer + used, buflen - used,
config_desc);
CHECK_WRET(bytes_w);
- }
- /* write any features */
- for (i = 0; i < fhdr.nr_features; i++) {
bytes_w = cscfg_file_write_feat(buffer + used, buflen - used,
feat_descs[i]);
CHECK_WRET(bytes_w);
- }
- /* finally re-write the header at the buffer start with the correct length */
- fhdr.length = (u16)used;
- bytes_w = cscfg_file_write_fhdr(buffer, buflen, &fhdr);
- /* no CHECK_WRET as used must not be updated */
- if (bytes_w < 0)
return bytes_w;
- return used;
+} diff --git a/samples/coresight/coresight-cfg-bufw.h b/samples/coresight/coresight-cfg-bufw.h new file mode 100644 index 000000000000..00b16c583cad --- /dev/null +++ b/samples/coresight/coresight-cfg-bufw.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#ifndef _CORESIGHT_CFG_BUFW_H +#define _CORESIGHT_CFG_BUFW_H
+#include "coresight-config-file.h"
+/*
- Function to take coresight configurations and features and
- write them into a supplied memory buffer for serialisation
- into a file.
- Resulting file can then be loaded into the coresight
- infrastructure via configfs.
- */
+int cscfg_file_write_buffer(u8 *buffer, const int buflen,
struct cscfg_config_desc *config_desc,
struct cscfg_feature_desc **feat_descs);
+#endif /* _CORESIGHT_CFG_BUFW_H */ diff --git a/samples/coresight/coresight-cfg-filegen.c b/samples/coresight/coresight-cfg-filegen.c new file mode 100644 index 000000000000..c8be18ee97b6 --- /dev/null +++ b/samples/coresight/coresight-cfg-filegen.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (c) 2020 Linaro Limited, All rights reserved.
- Author: Mike Leach mike.leach@linaro.org
- */
+#include <linux/types.h> +#include <linux/unistd.h> +#include <stdio.h> +#include <unistd.h>
+#include "coresight-cfg-bufw.h"
+/*
- generate example binary coresight configuration files for loading
- into the coresight subsystem via configfs
- */
+/* create a similar configuration example as the coresight-cfg-sample.c file. */
+/* we will provide 4 sets of preset parameter values */ +#define AFDO2_NR_PRESETS 4 +/* the total number of parameters in used features - strobing has 2 */ +#define AFDO2_NR_PARAM_SUM 2
+static const char *afdo2_ref_names[] = {
- "strobing",
+};
+/*
- set of presets leaves strobing window constant while varying period to allow
- experimentation with mark / space ratios for various workloads
- */
+static u64 afdo2_presets[AFDO2_NR_PRESETS][AFDO2_NR_PARAM_SUM] = {
- { 2000, 100 },
- { 2000, 1000 },
- { 2000, 5000 },
- { 2000, 10000 },
+};
+struct cscfg_config_desc afdo3 = {
- .name = "autofdo3",
- .description = "Setup ETMs with strobing for autofdo\n"
- "Supplied presets allow experimentation with mark-space ratio for various loads\n",
- .nr_feat_refs = ARRAY_SIZE(afdo2_ref_names),
- .feat_ref_names = afdo2_ref_names,
- .nr_presets = AFDO2_NR_PRESETS,
- .nr_total_params = AFDO2_NR_PARAM_SUM,
- .presets = &afdo2_presets[0][0],
+};
+static struct cscfg_feature_desc *sample_feats[] = {
- NULL
+};
For completeness there would be value in providing an example that requires features.
+static struct cscfg_config_desc *sample_cfgs[] = {
- &afdo3,
- NULL
+};
Any reason to declare sample_cfgs[] when there can only be one configuration?
Lastly I get the following [1] when compiling this set - I have not investigated further.
Thanks, Mathieu
[1]. https://pastebin.com/Nw2DTqTC
+#define CSCFG_BIN_FILENAME "example1.cscfg"
+int main(int argc, char **argv) +{
- u8 buffer[CSCFG_FILE_MAXSIZE];
- int used;
- FILE *fp;
- printf("Coresight Configuration file Generator\n\n");
- used = cscfg_file_write_buffer(buffer, CSCFG_FILE_MAXSIZE,
sample_cfgs[0], sample_feats);
- if (used < 0) {
printf("Error %d writing configuration %s into buffer\n",
used, sample_cfgs[0]->name);
return used;
- }
- fp = fopen(CSCFG_BIN_FILENAME, "wb");
- if (fp == NULL) {
printf("Error opening file %s\n", CSCFG_BIN_FILENAME);
return -1;
- }
- fwrite(buffer, used, sizeof(u8), fp);
- fclose(fp);
- return 0;
+}
2.17.1