From c01811bb5bd1cd8d7c23e43f3a3503156801e4fc Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Fri, 22 May 2020 09:54:12 +0200 Subject: [PATCH 1/6] logger: Extract function for conversion between UUID value and UUID key This conversion should be done in function, because of future usage in different places, outside converter.c file. Signed-off-by: Karol Trzcinski --- tools/logger/convert.c | 22 ++++++++++++++++++++-- tools/logger/convert.h | 3 +++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/tools/logger/convert.c b/tools/logger/convert.c index 2fe837a0da4e..cb2dac41aa79 100644 --- a/tools/logger/convert.c +++ b/tools/logger/convert.c @@ -141,6 +141,25 @@ get_uuid_entry(const struct snd_sof_uids_header *uids_dict, uint32_t uid_ptr) uids_dict->base_address); } +/* + * Use uids dictionary content, to convert address of uuid `entry` from logger + * memory space to corresponding uuid key address used in firmware trace system + * (with base UUID_ENTRY_ELF_BASE, 0x1FFFA000 as usual). Function get_uuid_entry + * works in oppopsite direction. + */ +uint32_t get_uuid_key(const struct snd_sof_uids_header *uids_dict, + const struct sof_uuid_entry *entry) +{ + /* + * uids_dict->data_offset and uids_dict->base_address are both constants, + * related with given ldc file. + * Uuid address used in firmware, points unusable memory region, + * so its treated as key value. + */ + return (uintptr_t)entry - (uintptr_t)uids_dict - + uids_dict->data_offset + uids_dict->base_address; +} + const char *format_uid(const struct snd_sof_uids_header *uids_dict, uint32_t uid_ptr, int use_colors) @@ -715,8 +734,7 @@ static int dump_ldc_info(struct convert_config *config, while (remaining > 0) { name = format_uid_raw(&uid_ptr[cnt], 0, 0); - uid_addr = (uintptr_t)&uid_ptr[cnt] - (uintptr_t)uids_dict - - uids_dict->data_offset + uids_dict->base_address; + uid_addr = get_uuid_key(uids_dict, &uid_ptr[cnt]); fprintf(out_fd, "\t0x%lX %s\n", uid_addr, name); if (name) { diff --git a/tools/logger/convert.h b/tools/logger/convert.h index 8a966bfe4348..7b8774a53d00 100644 --- a/tools/logger/convert.h +++ b/tools/logger/convert.h @@ -13,6 +13,7 @@ #include #include #include +#include #define KNRM "\x1B[0m" #define KRED "\x1B[31m" @@ -42,4 +43,6 @@ struct convert_config { struct snd_sof_uids_header *uids_dict; }; +uint32_t get_uuid_key(const struct snd_sof_uids_header *uids_dict, + const struct sof_uuid_entry *entry); int convert(struct convert_config *config); From 408aa4bdaab7b67c003966c658b5df16c2c120e0 Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Mon, 24 Aug 2020 07:38:27 +0200 Subject: [PATCH 2/6] logger: Exclude misc functions from convert file A few, general usage functions where implemented in converter file. They should be moved to separate file, to make it easily accessible form any source file. Moreover removing it from converter file, is a part of this file cleanup. Signed-off-by: Karol Trzcinski --- tools/logger/CMakeLists.txt | 1 + tools/logger/convert.c | 63 +------------------------------- tools/logger/misc.c | 72 +++++++++++++++++++++++++++++++++++++ tools/logger/misc.h | 14 ++++++++ 4 files changed, 88 insertions(+), 62 deletions(-) create mode 100644 tools/logger/misc.c create mode 100644 tools/logger/misc.h diff --git a/tools/logger/CMakeLists.txt b/tools/logger/CMakeLists.txt index 20ade4ad9737..fa0949a633a5 100644 --- a/tools/logger/CMakeLists.txt +++ b/tools/logger/CMakeLists.txt @@ -3,6 +3,7 @@ add_executable(sof-logger logger.c convert.c + misc.c ) target_compile_options(sof-logger PRIVATE diff --git a/tools/logger/convert.c b/tools/logger/convert.c index cb2dac41aa79..4f88ee5213e4 100644 --- a/tools/logger/convert.c +++ b/tools/logger/convert.c @@ -5,7 +5,6 @@ // Author: Bartosz Kokoszko // Artur Kloniecki -#include #include #include #include @@ -16,6 +15,7 @@ #include #include #include "convert.h" +#include "misc.h" #define CEIL(a, b) ((a+b-1)/b) @@ -52,67 +52,6 @@ struct proc_ldc_entry { static const char *BAD_PTR_STR = ""; -char *vasprintf(const char *format, va_list args) -{ - va_list args_copy; - int size; - char localbuf[1]; - char *result; - - va_copy(args_copy, args); - size = vsnprintf(localbuf, 1, format, args_copy); - va_end(args_copy); - - result = calloc(1, size + 1); - if (result) - vsnprintf(result, size + 1, format, args); - return result; -} - -char *asprintf(const char *format, ...) -{ - va_list args; - char *result; - - va_start(args, format); - result = vasprintf(format, args); - va_end(args); - - return result; -} - -static void log_err(FILE *out_fd, const char *fmt, ...) -{ - static const char prefix[] = "error: "; - ssize_t needed_size; - va_list args, args_alloc; - char *buff; - - va_start(args, fmt); - - va_copy(args_alloc, args); - needed_size = vsnprintf(NULL, 0, fmt, args_alloc) + 1; - buff = malloc(needed_size); - va_end(args_alloc); - - if (buff) { - vsprintf(buff, fmt, args); - fprintf(stderr, "%s%s", prefix, buff); - - /* take care about out_fd validity and duplicated logging */ - if (out_fd && out_fd != stderr && out_fd != stdout) { - fprintf(out_fd, "%s%s", prefix, buff); - fflush(out_fd); - } - free(buff); - } else { - fprintf(stderr, "%s", prefix); - vfprintf(stderr, fmt, args); - } - - va_end(args); -} - char *format_uid_raw(const struct sof_uuid_entry *uid_entry, int use_colors, int name_first) { diff --git a/tools/logger/misc.c b/tools/logger/misc.c new file mode 100644 index 000000000000..a1efaa28e27f --- /dev/null +++ b/tools/logger/misc.c @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2020 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski + */ + +#include +#include +#include +#include + +char *vasprintf(const char *format, va_list args) +{ + va_list args_copy; + int size; + char localbuf[1]; + char *result; + + va_copy(args_copy, args); + size = vsnprintf(localbuf, 1, format, args_copy); + va_end(args_copy); + + result = malloc(size + 1); + if (result) + vsnprintf(result, size + 1, format, args); + return result; +} + +char *asprintf(const char *format, ...) +{ + va_list args; + char *result; + + va_start(args, format); + result = vasprintf(format, args); + va_end(args); + + return result; +} + +void log_err(FILE *out_fd, const char *fmt, ...) +{ + static const char prefix[] = "error: "; + ssize_t needed_size; + va_list args, args_alloc; + char *buff; + + va_start(args, fmt); + + va_copy(args_alloc, args); + needed_size = vsnprintf(NULL, 0, fmt, args_alloc) + 1; + buff = malloc(needed_size); + va_end(args_alloc); + + if (buff) { + vsprintf(buff, fmt, args); + fprintf(stderr, "%s%s", prefix, buff); + + /* take care about out_fd validity and duplicated logging */ + if (out_fd && out_fd != stderr && out_fd != stdout) { + fprintf(out_fd, "%s%s", prefix, buff); + fflush(out_fd); + } + free(buff); + } else { + fprintf(stderr, "%s", prefix); + vfprintf(stderr, fmt, args); + } + + va_end(args); +} diff --git a/tools/logger/misc.h b/tools/logger/misc.h new file mode 100644 index 000000000000..214f77bd6048 --- /dev/null +++ b/tools/logger/misc.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2020 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski + */ + +#include +#include + +char *vasprintf(const char *format, va_list args); +char *asprintf(const char *format, ...); + +void log_err(FILE *out_fd, const char *fmt, ...); From 4ffb31e0b62655b4b3ec10423a92cedebdf8c85d Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Fri, 29 May 2020 14:29:40 +0200 Subject: [PATCH 3/6] logger: Store filter config given in command line To parse filter configuration given by user, uuid dictionary must be readed first from ldc file. Otherwise it's impossible to validate given components names. This is reason why filter configuration must be buffered and parsed in later steps. Signed-off-by: Karol Trzcinski --- tools/logger/convert.h | 1 + tools/logger/logger.c | 31 ++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/tools/logger/convert.h b/tools/logger/convert.h index 7b8774a53d00..4aeb550e2f53 100644 --- a/tools/logger/convert.h +++ b/tools/logger/convert.h @@ -30,6 +30,7 @@ struct convert_config { int trace; const char *ldc_file; FILE* ldc_fd; + char *filter_config; int input_std; int version_fw; char *version_file; diff --git a/tools/logger/logger.c b/tools/logger/logger.c index bf82b1954f52..0f5445dd181f 100644 --- a/tools/logger/logger.c +++ b/tools/logger/logger.c @@ -15,6 +15,7 @@ #include #include #include "convert.h" +#include "misc.h" #define APP_NAME "sof-logger" @@ -59,6 +60,8 @@ static void usage(void) APP_NAME); fprintf(stdout, "%s:\t -d *.ldc_file \t\tDump ldc_file information\n", APP_NAME); + fprintf(stdout, "%s:\t -F path\t\tUpdate trace filtering\n", + APP_NAME); exit(0); } @@ -140,9 +143,25 @@ static int configure_uart(const char *file, unsigned int baud) return ret < 0 ? -errno : fd; } +/* Concantenate `config->filter_config` with `input` + `\n` */ +static int append_filter_config(struct convert_config *config, const char *input) +{ + char *old_config = config->filter_config; + + /* filer_config can't be NULL for following steps */ + if (!old_config) + config->filter_config = asprintf(""); + + config->filter_config = asprintf("%s%s\n", config->filter_config, input); + free(old_config); + if (!config->filter_config) + return -ENOMEM; + return 0; +} + int main(int argc, char *argv[]) { - static const char optstring[] = "ho:i:l:ps:c:u:tev:rd:Lf:g"; + static const char optstring[] = "ho:i:l:ps:c:u:tev:rd:Lf:gF:"; struct convert_config config; unsigned int baud = 0; const char *snapshot_file = 0; @@ -167,6 +186,7 @@ int main(int argc, char *argv[]) config.dump_ldc = 0; config.hide_location = 0; config.time_precision = 6; + config.filter_config = NULL; while ((opt = getopt(argc, argv, optstring)) != -1) { switch (opt) { @@ -234,6 +254,11 @@ int main(int argc, char *argv[]) config.dump_ldc = 1; config.ldc_file = optarg; break; + case 'F': + ret = append_filter_config(&config, optarg); + if (ret < 0) + return ret; + break; case 'h': default: /* '?' */ usage(); @@ -309,6 +334,10 @@ int main(int argc, char *argv[]) ret = -convert(&config); out: + /* free memory */ + if (config.filter_config) + free(config.filter_config); + /* close files */ if (config.out_fd) fclose(config.out_fd); From 2efa5c323722deee28b1ec2829ae31ed6df0e7af Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Mon, 24 Aug 2020 08:08:44 +0200 Subject: [PATCH 4/6] logger: Implement whitespace trimming functions They will be needed during trace filering command parsing, to skip whitespaces. As generic functions, their are placed in misc file instead of any feature-related file. Signed-off-by: Karol Trzcinski --- tools/logger/misc.c | 27 +++++++++++++++++++++++++++ tools/logger/misc.h | 9 +++++++++ 2 files changed, 36 insertions(+) diff --git a/tools/logger/misc.c b/tools/logger/misc.c index a1efaa28e27f..d17e7fe4c5ce 100644 --- a/tools/logger/misc.c +++ b/tools/logger/misc.c @@ -5,6 +5,7 @@ * Author: Karol Trzcinski */ +#include #include #include #include @@ -70,3 +71,29 @@ void log_err(FILE *out_fd, const char *fmt, ...) va_end(args); } + +/* trim whitespaces from string begin */ +char *ltrim(char *s) +{ + while (isspace(*s)) + s++; + return s; +} + +/* trim whitespaces from string end */ +char *rtrim(char *s) +{ + char *ptr = s + strlen(s) - 1; + + while (ptr >= s && isspace(*ptr)) { + *ptr = '\0'; + --ptr; + } + return s; +} + +/* trim whitespaces from string begin and end*/ +char *trim(char *s) +{ + return ltrim(rtrim(s)); +} diff --git a/tools/logger/misc.h b/tools/logger/misc.h index 214f77bd6048..5e30005584e7 100644 --- a/tools/logger/misc.h +++ b/tools/logger/misc.h @@ -12,3 +12,12 @@ char *vasprintf(const char *format, va_list args); char *asprintf(const char *format, ...); void log_err(FILE *out_fd, const char *fmt, ...); + +/* trim whitespaces from string begin */ +char *ltrim(char *s); + +/* trim whitespaces from string end */ +char *rtrim(char *s); + +/* trim whitespaces from string begin and end*/ +char *trim(char *s); From f4a3d98cb9f70d8aca7627156976f2b84f9af835 Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Fri, 29 May 2020 14:41:30 +0200 Subject: [PATCH 5/6] logger: Parse runtime filter levels Parse arguments given in -F flag, in form where each -F argument is given as separate line. Format of single -F entry is `=`. must corresponds with .name field from log_level_dict. List of component are build from elements separated with `,` and single element may have one of the following forms: " ." - single component instance " .*" - components with given name on piepeline with pipe_id "*" - each component instance with given name or global component "" - as above "* ." - component on selected pipe_id with given comp_id "* .*" - each component on pipeline with pipe_id "*" - each component in firmware must correspond values of uuid entries from ldc file. Signed-off-by: Karol Trzcinski --- tools/logger/CMakeLists.txt | 1 + tools/logger/convert.c | 11 ++ tools/logger/filter.c | 309 ++++++++++++++++++++++++++++++++++++ tools/logger/filter.h | 14 ++ 4 files changed, 335 insertions(+) create mode 100644 tools/logger/filter.c create mode 100644 tools/logger/filter.h diff --git a/tools/logger/CMakeLists.txt b/tools/logger/CMakeLists.txt index fa0949a633a5..4f1fc9047adf 100644 --- a/tools/logger/CMakeLists.txt +++ b/tools/logger/CMakeLists.txt @@ -3,6 +3,7 @@ add_executable(sof-logger logger.c convert.c + filter.c misc.c ) diff --git a/tools/logger/convert.c b/tools/logger/convert.c index 4f88ee5213e4..019b0768d800 100644 --- a/tools/logger/convert.c +++ b/tools/logger/convert.c @@ -15,6 +15,7 @@ #include #include #include "convert.h" +#include "filter.h" #include "misc.h" #define CEIL(a, b) ((a+b-1)/b) @@ -763,5 +764,15 @@ int convert(struct convert_config *config) if (config->dump_ldc) return dump_ldc_info(config, &snd); + if (config->filter_config) { + ret = filter_update_firmware(config->uids_dict, + config->filter_config); + if (ret) { + log_err(config->out_fd, + "failed to apply trace filter, %d.\n", ret); + return ret; + } + } + return logger_read(config, &snd); } diff --git a/tools/logger/filter.c b/tools/logger/filter.c new file mode 100644 index 000000000000..478ee84b0c98 --- /dev/null +++ b/tools/logger/filter.c @@ -0,0 +1,309 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2020 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "convert.h" +#include "filter.h" +#include "misc.h" + +#define COMPONENTS_SEPARATOR ',' +#define COMPONENT_NAME_SCAN_STRING_LENGTH 32 + +/** map between log level given by user and enum value */ +static const struct { + const char name[16]; + int32_t log_level; +} log_level_dict[] = { + {"verbose", LOG_LEVEL_VERBOSE}, + {"debug", LOG_LEVEL_DEBUG}, + {"info", LOG_LEVEL_INFO}, + {"warning", LOG_LEVEL_WARNING}, + {"error", LOG_LEVEL_ERROR}, + {"critical", LOG_LEVEL_CRITICAL}, + {"v", LOG_LEVEL_VERBOSE}, + {"d", LOG_LEVEL_DEBUG}, + {"i", LOG_LEVEL_INFO}, + {"w", LOG_LEVEL_WARNING}, + {"e", LOG_LEVEL_ERROR}, + {"c", LOG_LEVEL_CRITICAL}, +}; + +struct filter_element { + struct list_item list; + int32_t uuid_id; /**< type id, or -1 when not important */ + int32_t comp_id; /**< component id or -1 when not important */ + int32_t pipe_id; /**< pipeline id or -1 when not important */ + int32_t log_level; /**< new log level value */ +}; + +/** + * Search for uuid entry with given component name in given uids dictionary + * @param uids_dict dictionary to search in + * @param name of uuid entry + * @return pointer to sof_uuid_entry with given name + */ +static struct sof_uuid_entry * +get_uuid_by_name(const struct snd_sof_uids_header *uids_dict, + const char *name) +{ + uintptr_t beg = (uintptr_t)uids_dict + uids_dict->data_offset; + uintptr_t end = beg + uids_dict->data_length; + struct sof_uuid_entry *ptr = (struct sof_uuid_entry *)beg; + + while ((uintptr_t)ptr < end) { + if (strcmp(name, ptr->name) == 0) + return ptr; + ++ptr; + } + return NULL; +} + +/** + * Parse log level name (from log_level_dict) to enum value. + * Take care about possible whitespace at the begin. + * @param value_start pointer to the begin of range to search + * @return enum value for given log level, or -1 for invalid value + */ +static int filter_parse_log_level(const char *value_start) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(log_level_dict); ++i) { + if (strstr(log_level_dict[i].name, value_start)) + return log_level_dict[i].log_level; + } + return -1; +} + +static char *filter_parse_component_name(const struct snd_sof_uids_header *uids_dict, + char *input_str, + struct filter_element *out) +{ + static char scan_format_string[COMPONENT_NAME_SCAN_STRING_LENGTH] = ""; + char comp_name[UUID_NAME_MAX_LEN]; + struct sof_uuid_entry *uuid_entry; + int ret; + + /* if component name is not specified, stay with default out->uuid_id value */ + if (input_str[0] == '*') + return &input_str[1]; + + /* + * Take care about buffer overflows when dealing with input from + * user, so scan no more than UUID_NAME_MAX_LEN bytes to + * `comp_name` variable. Only once initialise scan_format_string. + */ + if (strlen(scan_format_string) == 0) { + ret = snprintf(scan_format_string, sizeof(scan_format_string), + "%%%d[^0-9* ]s", UUID_NAME_MAX_LEN); + if (ret <= 0) + return NULL; + } + ret = sscanf(input_str, scan_format_string, comp_name); + if (ret <= 0) + return NULL; + + /* find component uuid key */ + uuid_entry = get_uuid_by_name(uids_dict, comp_name); + if (!uuid_entry) { + log_err(NULL, "unknown component name `%s`\n", comp_name); + return NULL; + } + out->uuid_id = get_uuid_key(uids_dict, uuid_entry); + return strstr(input_str, comp_name) + strlen(comp_name); +} + +/** + * Parse component definition from input_str. + * + * Possible input_str formats: + * `name pipe_id.comp_id` + * `name pipe_id.*` + * `name *` + * `name` + * `* pipe_id.comp_id` + * `* pipe_id.*` + * `*` + * Whitespace is possible at the begin, end and after `name`. + * `name` must refer to values from given UUID dictionary, + * (so name comes from DECLARE_SOF_UUID macro usage) + + * @param uids_dict dictionary with list of possible `name` values + * @param input_str formatted component definition + * @param out element where component definition should be saved + */ +static int filter_parse_component(const struct snd_sof_uids_header *uids_dict, + char *input_str, + struct filter_element *out) +{ + char *instance_info; + int ret; + + /* trim whitespaces, to easily check first and last char */ + input_str = trim(input_str); + + /* assign default values */ + out->uuid_id = 0; + out->pipe_id = -1; + out->comp_id = -1; + + /* parse component name and store pointer after component name, pointer to instance info */ + instance_info = filter_parse_component_name(uids_dict, input_str, out); + if (!instance_info) { + log_err(NULL, "component name parsing `%s`\n", + input_str); + return -EINVAL; + } + + /* if instance is not specified then stop parsing */ + instance_info = ltrim(instance_info); + if (instance_info[0] == '\0' || + (instance_info[0] == '*' && instance_info[1] == '\0')) { + return 0; + } + + /* now parse last part: `number.x` where x is a number or `*` */ + ret = sscanf(instance_info, "%d.%d", &out->pipe_id, &out->comp_id); + if (ret == 2) + return 0; + else if (ret != 1) + return -EINVAL; + + /* pipeline id parsed but component id is not a number */ + if (instance_info[strlen(instance_info) - 1] == '*') + return 0; + log_err(NULL, "Use * to specify each component on particular pipeline\n"); + return -EINVAL; +} + +/** + * Convert argument from -F flag to sof_ipc_dma_trace_filter_elem struct values. + * + * Possible log_level - see filter_parse_log_level() documentation + * Possible component - list of components separated by `COMPONENTS_SEPARATOR`, + * for single component definition description look at + * filter_parse_component() documentation + * + * Examples: + * `debug="pipe1"` - set debug log level for components from pipeline1 + * `d="pipe1, dai2.3"` - as above, but also for dai2.3 + * `error="FIR*"` - for each FIR component set log level to error + * + * @param dictionary uuid dictionary from ldc file + * @param input_str log level settings in format `log_level=component` + * @param out_list output list with filter_element elements + */ +static int filter_parse_entry(const struct snd_sof_uids_header *uids_dict, + char *input_str, struct list_item *out_list) +{ + struct filter_element *filter; + char *comp_fmt_end; + int32_t log_level; + char *comp_fmt; + int ret; + + /* + * split string on '=' char, left part describes log level, + * the right one is for component description. + */ + comp_fmt = strchr(input_str, '='); + if (!comp_fmt) { + log_err(NULL, "unable to find `=` in `%s`\n", input_str); + return -EINVAL; + } + *comp_fmt = 0; + ++comp_fmt; + + /* find correct log level in given conf string - string before `=` */ + log_level = filter_parse_log_level(input_str); + if (log_level < 0) { + log_err(NULL, "unable to parse log level from `%s`\n", + input_str); + return log_level; + } + + /* + * now parse list of components name and optional instance identifier, + * split string on `COMPONENTS_SEPARATOR` + */ + while (comp_fmt) { + filter = malloc(sizeof(struct filter_element)); + if (!filter) { + log_err(NULL, "unable to malloc memory\n"); + return -ENOMEM; + } + + comp_fmt_end = strchr(comp_fmt, COMPONENTS_SEPARATOR); + if (comp_fmt_end) + *comp_fmt_end = '\0'; + ret = filter_parse_component(uids_dict, comp_fmt, filter); + if (ret < 0) { + log_err(NULL, "unable to parse component from `%s`\n", + comp_fmt); + free(filter); + return ret; + } + filter->log_level = log_level; + + list_item_append(&filter->list, out_list); + comp_fmt = comp_fmt_end ? comp_fmt_end + 1 : 0; + } + + return 0; +} + +/** + * Parse `input_str` content. + * + * `input_str` contain single filter definition element per line. + * Each line is parsed by `filter_parse_entry`, and saved in list. + * + * @param dictionary uuid dictionary from ldc file + * @param format log level settings in format `log_level=component` + */ +int filter_update_firmware(const struct snd_sof_uids_header *uids_dict, + char *input_str) +{ + struct filter_element *filter; + struct list_item filter_list; + struct list_item *list_elem; + struct list_item *list_temp; + char *line_end; + int ret = 0; + + list_init(&filter_list); + + /* parse `input_str` line by line */ + line_end = strchr(input_str, '\n'); + while (line_end) { + line_end[0] = '\0'; + ret = filter_parse_entry(uids_dict, input_str, &filter_list); + if (ret < 0) + goto err; + input_str = line_end + 1; + line_end = strchr(input_str, '\n'); + } + +err: + /* free each component from parsed element list */ + list_for_item_safe(list_elem, list_temp, &filter_list) { + filter = container_of(list_elem, struct filter_element, + list); + free(filter); + } + + return ret; +} diff --git a/tools/logger/filter.h b/tools/logger/filter.h new file mode 100644 index 000000000000..e650724ae0de --- /dev/null +++ b/tools/logger/filter.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2020 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski + */ + +#ifndef __LOGGER_FILTER_H__ +#define __LOGGER_FILTER_H__ + +int filter_update_firmware(const struct snd_sof_uids_header *uids_dict, + char *input_str); + +#endif /* __LOGGER_FILTER_H__ */ From 277c8391ccf4a9f4da44a0e710b562e8305af1ad Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Fri, 29 May 2020 14:55:06 +0200 Subject: [PATCH 6/6] logger: Send parsed runtime log levels to FW via debugFS "/sys/kernel/debug/sof/filter" file is responsible for updating trace log levels. IPC message contain list of new trace threshold, it is represented as single line in file where entries are separated with ";". Single entry has form of: " " Signed-off-by: Karol Trzcinski --- tools/logger/filter.c | 26 +++++++++++++++++++++++++- tools/logger/filter.h | 2 ++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/tools/logger/filter.c b/tools/logger/filter.c index 478ee84b0c98..f1396d5e9759 100644 --- a/tools/logger/filter.c +++ b/tools/logger/filter.c @@ -266,10 +266,13 @@ static int filter_parse_entry(const struct snd_sof_uids_header *uids_dict, } /** - * Parse `input_str` content. + * Parse `input_str` content and send it to FW via debugFS. * * `input_str` contain single filter definition element per line. * Each line is parsed by `filter_parse_entry`, and saved in list. + * List of `sof_ipc_dma_trace_filter_elem` is writend to debugFS, + * and then send as IPC to FW (this action is implemented in driver). + * Each line in debugFS represents single IPC message. * * @param dictionary uuid dictionary from ldc file * @param format log level settings in format `log_level=component` @@ -282,6 +285,7 @@ int filter_update_firmware(const struct snd_sof_uids_header *uids_dict, struct list_item *list_elem; struct list_item *list_temp; char *line_end; + FILE *out_fd; int ret = 0; list_init(&filter_list); @@ -297,7 +301,27 @@ int filter_update_firmware(const struct snd_sof_uids_header *uids_dict, line_end = strchr(input_str, '\n'); } + /* write output to debugFS */ + out_fd = fopen(FILTER_KERNEL_PATH, "w"); + if (!out_fd) { + log_err(NULL, "Unable to open out file '%s'\n", + FILTER_KERNEL_PATH); + ret = -errno; + goto err; + } + + list_for_item(list_elem, &filter_list) { + filter = container_of(list_elem, struct filter_element, + list); + fprintf(out_fd, "%d %X %d %d;", filter->log_level, + filter->uuid_id, filter->pipe_id, filter->comp_id); + } + fprintf(stdout, "\n"); + err: + if (out_fd) + fclose(out_fd); + /* free each component from parsed element list */ list_for_item_safe(list_elem, list_temp, &filter_list) { filter = container_of(list_elem, struct filter_element, diff --git a/tools/logger/filter.h b/tools/logger/filter.h index e650724ae0de..63da8f30a5da 100644 --- a/tools/logger/filter.h +++ b/tools/logger/filter.h @@ -8,6 +8,8 @@ #ifndef __LOGGER_FILTER_H__ #define __LOGGER_FILTER_H__ +#define FILTER_KERNEL_PATH "/sys/kernel/debug/sof/filter" + int filter_update_firmware(const struct snd_sof_uids_header *uids_dict, char *input_str);