Merge pull request #88 from akloniex/unify-logger
logger/rmbox: unify implementation of new logger tool with old rmbox
This commit is contained in:
commit
e37aa3f422
|
@ -1,4 +1,4 @@
|
||||||
SUBDIRS = logger rmbox topology eqctl
|
SUBDIRS = rmbox topology eqctl
|
||||||
TESTDIR = topology/test
|
TESTDIR = topology/test
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
|
|
|
@ -18,7 +18,6 @@ AC_PROG_CC
|
||||||
|
|
||||||
AC_OUTPUT([
|
AC_OUTPUT([
|
||||||
Makefile
|
Makefile
|
||||||
logger/Makefile
|
|
||||||
rmbox/Makefile
|
rmbox/Makefile
|
||||||
eqctl/Makefile
|
eqctl/Makefile
|
||||||
topology/Makefile
|
topology/Makefile
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
bin_PROGRAMS = sof_logger
|
|
||||||
|
|
||||||
sof_logger_SOURCES = \
|
|
||||||
logger.c
|
|
316
logger/logger.c
316
logger/logger.c
|
@ -1,316 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sof/uapi/logging.h>
|
|
||||||
|
|
||||||
#define CEIL(a, b) ((a+b-1)/b)
|
|
||||||
|
|
||||||
/* elf signature params */
|
|
||||||
#define SND_SOF_LOGS_SIG_SIZE 4
|
|
||||||
#define SND_SOF_LOGS_SIG "Logs"
|
|
||||||
|
|
||||||
struct snd_sof_logs_header {
|
|
||||||
/* "Logs" */
|
|
||||||
unsigned char sig[SND_SOF_LOGS_SIG_SIZE];
|
|
||||||
/* address of log entries section */
|
|
||||||
uint32_t base_address;
|
|
||||||
/* amount of bytes following this header */
|
|
||||||
uint32_t data_length;
|
|
||||||
/* offset to first entry in this file */
|
|
||||||
uint32_t data_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ldc_entry_header {
|
|
||||||
uint32_t level;
|
|
||||||
uint32_t component_id;
|
|
||||||
uint32_t params_num;
|
|
||||||
uint32_t line_idx;
|
|
||||||
uint32_t file_name_len;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ldc_entry {
|
|
||||||
struct ldc_entry_header header;
|
|
||||||
char *file_name;
|
|
||||||
uint32_t text_len;
|
|
||||||
char *text;
|
|
||||||
uint32_t *params;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dma_log {
|
|
||||||
struct log_entry_header header;
|
|
||||||
uint32_t address;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int fetch_entry(FILE *f_ldc, FILE *f_in, uint32_t base_address,
|
|
||||||
uint32_t data_offset, struct dma_log dma_log);
|
|
||||||
static void print_table_header(void);
|
|
||||||
static void print_entry_params(struct dma_log dma_log, struct ldc_entry);
|
|
||||||
static void usage(char *name);
|
|
||||||
|
|
||||||
static inline void print_table_header(void)
|
|
||||||
{
|
|
||||||
fprintf(stdout, "%10s %8s %8s %14s %16s %24s\t%s\n",
|
|
||||||
"ADDRESS",
|
|
||||||
"CORE_ID",
|
|
||||||
"LEVEL",
|
|
||||||
"COMPONENT_ID",
|
|
||||||
"TIMESTAMP",
|
|
||||||
"FILE_NAME",
|
|
||||||
"CONTENT");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_entry_params(struct dma_log dma_log,
|
|
||||||
struct ldc_entry entry)
|
|
||||||
{
|
|
||||||
fprintf(stdout, "%10x %8u %8u %14u %16lu %20s:%u\t",
|
|
||||||
dma_log.address,
|
|
||||||
dma_log.header.core_id,
|
|
||||||
entry.header.level,
|
|
||||||
entry.header.component_id,
|
|
||||||
dma_log.header.timestamp,
|
|
||||||
entry.file_name,
|
|
||||||
entry.header.line_idx);
|
|
||||||
|
|
||||||
switch (entry.header.params_num){
|
|
||||||
case 0:
|
|
||||||
fprintf(stdout, "%s", entry.text);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
fprintf(stdout, entry.text, entry.params[0]);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
fprintf(stdout, entry.text, entry.params[0],
|
|
||||||
entry.params[1]);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
fprintf(stdout, entry.text, entry.params[0], entry.params[1],
|
|
||||||
entry.params[2]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fprintf(stdout, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usage(char *name)
|
|
||||||
{
|
|
||||||
fprintf(stdout, "Usage %s <option(s)> <file(s)>\n", name);
|
|
||||||
fprintf(stdout, "%s:\t \t\t\tParse traces logs\n", name);
|
|
||||||
fprintf(stdout, "%s:\t -l *.ldc_file\t-i in_file\n", name);
|
|
||||||
fprintf(stdout, "%s:\t -t\t\t\tDisplay dma trace data\n", name);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int fetch_entry(FILE *f_ldc, FILE *f_in, uint32_t base_address,
|
|
||||||
uint32_t data_offset, struct dma_log dma_log)
|
|
||||||
{
|
|
||||||
|
|
||||||
struct ldc_entry entry;
|
|
||||||
long int padding;
|
|
||||||
|
|
||||||
uint32_t entry_offset;
|
|
||||||
uint32_t text_len;
|
|
||||||
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
entry.file_name = NULL;
|
|
||||||
entry.text = NULL;
|
|
||||||
entry.params = NULL;
|
|
||||||
|
|
||||||
/* evaluate entry offset in input file */
|
|
||||||
entry_offset = dma_log.address - base_address;
|
|
||||||
|
|
||||||
/* set file position to beginning of processed entry */
|
|
||||||
fseek(f_ldc, entry_offset + data_offset, SEEK_SET);
|
|
||||||
|
|
||||||
/* fetching elf header params */
|
|
||||||
ret = fread(&entry.header, sizeof(entry.header), 1, f_ldc);
|
|
||||||
if (!ret) {
|
|
||||||
ret = -ferror(f_ldc);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.file_name = (char *) malloc(entry.header.file_name_len);
|
|
||||||
if (!entry.file_name){
|
|
||||||
fprintf(stderr, "error: can't allocate %d byte for "
|
|
||||||
"entry.file_name\n", entry.header.file_name_len);
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = fread(entry.file_name, sizeof(char), entry.header.file_name_len,
|
|
||||||
f_ldc);
|
|
||||||
if (ret != entry.header.file_name_len) {
|
|
||||||
ret = -ferror(f_ldc);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* padding - sequences of chars are aligned to DWORDS */
|
|
||||||
fseek(f_ldc, CEIL(entry.header.file_name_len, sizeof(uint32_t)) *
|
|
||||||
sizeof(uint32_t) - entry.header.file_name_len, SEEK_CUR);
|
|
||||||
|
|
||||||
/* fetching text length */
|
|
||||||
ret = fread(&entry.text_len, sizeof(entry.text_len), 1, f_ldc);
|
|
||||||
if (!ret) {
|
|
||||||
ret = -ferror(f_ldc);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fetching text */
|
|
||||||
entry.text = (char *) malloc(entry.text_len);
|
|
||||||
if (entry.text == NULL) {
|
|
||||||
fprintf(stderr, "error: can't allocate %d byte for "
|
|
||||||
"entry.text\n", entry.text_len);
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = fread(entry.text, sizeof(char), entry.text_len, f_ldc);
|
|
||||||
if (ret != entry.text_len) {
|
|
||||||
ret = -ferror(f_ldc);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fetching entry params from dma dump */
|
|
||||||
entry.params = (uint32_t *) malloc(sizeof(uint32_t) *
|
|
||||||
entry.header.params_num);
|
|
||||||
ret = fread(entry.params, sizeof(uint32_t), entry.header.params_num,
|
|
||||||
f_in);
|
|
||||||
if (ret != entry.header.params_num) {
|
|
||||||
ret = -ferror(f_in);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* printing entry content */
|
|
||||||
print_entry_params(dma_log, entry);
|
|
||||||
|
|
||||||
/* set f_ldc file position to the beginning */
|
|
||||||
rewind(f_ldc);
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
out:
|
|
||||||
/* free alocated memory */
|
|
||||||
free(entry.params);
|
|
||||||
free(entry.text);
|
|
||||||
free(entry.file_name);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int logger_read(const char *in_file, FILE *f_ldc, struct snd_sof_logs_header *snd)
|
|
||||||
{
|
|
||||||
struct dma_log dma_log;
|
|
||||||
FILE *f_in = NULL;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
f_in = fopen(in_file, "r");
|
|
||||||
|
|
||||||
if (f_in == NULL) {
|
|
||||||
fprintf(stderr, "Error while opening %s. \n", in_file);
|
|
||||||
ret = errno;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_table_header();
|
|
||||||
|
|
||||||
while (!feof(f_in)) {
|
|
||||||
|
|
||||||
/* getting entry parameters from dma dump */
|
|
||||||
ret = fread(&dma_log, sizeof(dma_log), 1, f_in);
|
|
||||||
if (!ret) {
|
|
||||||
ret = -ferror(f_in);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* checking log address */
|
|
||||||
if ((dma_log.address < snd->base_address) ||
|
|
||||||
(dma_log.address > (snd->base_address + snd->data_length)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* fetching entry from elf dump*/
|
|
||||||
ret = fetch_entry(f_ldc, f_in, snd->base_address,
|
|
||||||
snd->data_offset, dma_log);
|
|
||||||
if (ret)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (f_ldc) fclose(f_ldc);
|
|
||||||
if (f_in) fclose(f_in);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
struct snd_sof_logs_header snd;
|
|
||||||
const char *ldc_file = NULL;
|
|
||||||
const char *in_file = NULL;
|
|
||||||
int opt, trace = 0, ret = 0;
|
|
||||||
FILE *f_ldc = NULL;
|
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "l:i:th")) != -1) {
|
|
||||||
switch (opt) {
|
|
||||||
case 'l':
|
|
||||||
ldc_file = optarg;
|
|
||||||
break;
|
|
||||||
case 'i':
|
|
||||||
in_file = optarg;
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
trace = 1;
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
default:
|
|
||||||
usage(argv[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ldc_file) {
|
|
||||||
fprintf(stderr, "error: invalid ldc file.\n");
|
|
||||||
usage(argv[0]);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
f_ldc = fopen(ldc_file, "r");
|
|
||||||
|
|
||||||
if (f_ldc == NULL) {
|
|
||||||
fprintf(stderr, "Error while opening %s. \n", ldc_file);
|
|
||||||
ret = errno;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set file positions to the beginning */
|
|
||||||
rewind(f_ldc);
|
|
||||||
|
|
||||||
/* veryfing ldc signature */
|
|
||||||
ret = fread(&snd, sizeof(snd), 1, f_ldc);
|
|
||||||
if (!ret) {
|
|
||||||
ret = -ferror(f_ldc);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strncmp(snd.sig, SND_SOF_LOGS_SIG, SND_SOF_LOGS_SIG_SIZE)) {
|
|
||||||
fprintf(stderr, "Error: Invalid ldc file signature. \n");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dma trace requested */
|
|
||||||
if (trace)
|
|
||||||
return logger_read("/sys/kernel/debug/sof/trace", f_ldc, &snd);
|
|
||||||
|
|
||||||
/* default option with no infile is to dump errors/debug data */
|
|
||||||
if (!in_file)
|
|
||||||
return logger_read("/sys/kernel/debug/sof/etrace", f_ldc, &snd);
|
|
||||||
|
|
||||||
return logger_read(in_file, f_ldc, &snd);
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (f_ldc) fclose(f_ldc);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
|
@ -1,4 +1,12 @@
|
||||||
bin_PROGRAMS = rmbox
|
bin_PROGRAMS = rmbox logger
|
||||||
|
|
||||||
rmbox_SOURCES = \
|
rmbox_SOURCES = \
|
||||||
rmbox.c
|
rmbox.c \
|
||||||
|
rmbox_convert.c
|
||||||
|
|
||||||
|
logger_SOURCES = \
|
||||||
|
rmbox.c \
|
||||||
|
logger_convert.c
|
||||||
|
|
||||||
|
logger_CFLAGS = \
|
||||||
|
-DLOGGER_FORMAT
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* debug log converter interface.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018, Intel Corporation.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sof/uapi/logging.h>
|
||||||
|
|
||||||
|
#define KNRM "\x1B[0m"
|
||||||
|
#define KRED "\x1B[31m"
|
||||||
|
|
||||||
|
static double to_usecs(uint64_t time, double clk)
|
||||||
|
{
|
||||||
|
/* trace timestamp uses CPU system clock at default 25MHz ticks */
|
||||||
|
// TODO: support variable clock rates
|
||||||
|
return (double)time / clk;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct convert_config {
|
||||||
|
const char *out_file;
|
||||||
|
const char *in_file;
|
||||||
|
FILE *out_fd;
|
||||||
|
FILE *in_fd;
|
||||||
|
double clock;
|
||||||
|
int trace;
|
||||||
|
#ifdef LOGGER_FORMAT
|
||||||
|
const char *ldc_file;
|
||||||
|
FILE* ldc_fd;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
int convert(struct convert_config *config);
|
|
@ -0,0 +1,286 @@
|
||||||
|
/*
|
||||||
|
* debug log converter, using new logger format.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018, Intel Corporation.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "convert.h"
|
||||||
|
|
||||||
|
#define CEIL(a, b) ((a+b-1)/b)
|
||||||
|
|
||||||
|
/* logs file signature */
|
||||||
|
#define SND_SOF_LOGS_SIG_SIZE 4
|
||||||
|
#define SND_SOF_LOGS_SIG "Logs"
|
||||||
|
|
||||||
|
struct snd_sof_logs_header {
|
||||||
|
/* "Logs" */
|
||||||
|
unsigned char sig[SND_SOF_LOGS_SIG_SIZE];
|
||||||
|
/* address of log entries section */
|
||||||
|
uint32_t base_address;
|
||||||
|
/* amount of bytes following this header */
|
||||||
|
uint32_t data_length;
|
||||||
|
/* offset to first entry in this file */
|
||||||
|
uint32_t data_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ldc_entry_header {
|
||||||
|
uint32_t level;
|
||||||
|
uint32_t component_id;
|
||||||
|
uint32_t params_num;
|
||||||
|
uint32_t line_idx;
|
||||||
|
uint32_t file_name_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ldc_entry {
|
||||||
|
struct ldc_entry_header header;
|
||||||
|
char *file_name;
|
||||||
|
uint32_t text_len;
|
||||||
|
char *text;
|
||||||
|
uint32_t *params;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dma_log {
|
||||||
|
struct log_entry_header header;
|
||||||
|
uint32_t address;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void print_table_header(FILE *out_fd)
|
||||||
|
{
|
||||||
|
fprintf(out_fd, "%5s %6s %8s %16s %16s %24s\t%s\n",
|
||||||
|
"CORE",
|
||||||
|
"LEVEL",
|
||||||
|
"COMP_ID",
|
||||||
|
"TIMESTAMP",
|
||||||
|
"DELTA",
|
||||||
|
"FILE_NAME",
|
||||||
|
"CONTENT");
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CASE(x) \
|
||||||
|
case(TRACE_CLASS_##x): return #x
|
||||||
|
|
||||||
|
static const char * get_component_name(uint32_t component_id) {
|
||||||
|
switch (component_id) {
|
||||||
|
CASE(IRQ);
|
||||||
|
CASE(IPC);
|
||||||
|
CASE(PIPE);
|
||||||
|
CASE(HOST);
|
||||||
|
CASE(DAI);
|
||||||
|
CASE(DMA);
|
||||||
|
CASE(SSP);
|
||||||
|
CASE(COMP);
|
||||||
|
CASE(WAIT);
|
||||||
|
CASE(LOCK);
|
||||||
|
CASE(MEM);
|
||||||
|
CASE(MIXER);
|
||||||
|
CASE(BUFFER);
|
||||||
|
CASE(VOLUME);
|
||||||
|
CASE(SWITCH);
|
||||||
|
CASE(MUX);
|
||||||
|
CASE(SRC);
|
||||||
|
CASE(TONE);
|
||||||
|
CASE(EQ_FIR);
|
||||||
|
CASE(EQ_IIR);
|
||||||
|
CASE(SA);
|
||||||
|
CASE(DMIC);
|
||||||
|
CASE(POWER);
|
||||||
|
default: return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_entry_params(FILE *out_fd, struct dma_log dma_log,
|
||||||
|
struct ldc_entry entry, uint64_t last_timestamp, double clock)
|
||||||
|
{
|
||||||
|
float dt = to_usecs(dma_log.header.timestamp - last_timestamp, clock);
|
||||||
|
if (dt < 0 || dt > 1000.0 * 1000.0 * 1000.0)
|
||||||
|
dt = NAN;
|
||||||
|
|
||||||
|
fprintf(out_fd, "%s%5u %6u %8s %16.6f %16.6f %20s:%u\t",
|
||||||
|
entry.header.level == LOG_LEVEL_CRITICAL ? KRED : KNRM,
|
||||||
|
dma_log.header.core_id,
|
||||||
|
entry.header.level,
|
||||||
|
get_component_name(entry.header.component_id),
|
||||||
|
to_usecs(dma_log.header.timestamp, clock),
|
||||||
|
dt,
|
||||||
|
entry.file_name,
|
||||||
|
entry.header.line_idx);
|
||||||
|
|
||||||
|
switch (entry.header.params_num) {
|
||||||
|
case 0:
|
||||||
|
fprintf(out_fd, "%s", entry.text);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
fprintf(out_fd, entry.text, entry.params[0]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
fprintf(out_fd, entry.text, entry.params[0], entry.params[1]);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
fprintf(out_fd, entry.text, entry.params[0], entry.params[1],
|
||||||
|
entry.params[2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fprintf(out_fd, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fetch_entry(struct convert_config *config, uint32_t base_address,
|
||||||
|
uint32_t data_offset, struct dma_log dma_log, uint64_t *last_timestamp)
|
||||||
|
{
|
||||||
|
struct ldc_entry entry;
|
||||||
|
long int padding;
|
||||||
|
|
||||||
|
uint32_t entry_offset;
|
||||||
|
uint32_t text_len;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
entry.file_name = NULL;
|
||||||
|
entry.text = NULL;
|
||||||
|
entry.params = NULL;
|
||||||
|
|
||||||
|
/* evaluate entry offset in input file */
|
||||||
|
entry_offset = dma_log.address - base_address;
|
||||||
|
|
||||||
|
/* set file position to beginning of processed entry */
|
||||||
|
fseek(config->ldc_fd, entry_offset + data_offset, SEEK_SET);
|
||||||
|
|
||||||
|
/* fetching elf header params */
|
||||||
|
ret = fread(&entry.header, sizeof(entry.header), 1, config->ldc_fd);
|
||||||
|
if (!ret) {
|
||||||
|
ret = -ferror(config->ldc_fd);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.file_name = (char *)malloc(entry.header.file_name_len);
|
||||||
|
if (!entry.file_name) {
|
||||||
|
fprintf(stderr, "error: can't allocate %d byte for "
|
||||||
|
"entry.file_name\n", entry.header.file_name_len);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fread(entry.file_name, sizeof(char), entry.header.file_name_len,
|
||||||
|
config->ldc_fd);
|
||||||
|
if (ret != entry.header.file_name_len) {
|
||||||
|
ret = -ferror(config->ldc_fd);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* padding - sequences of chars are aligned to DWORDS */
|
||||||
|
fseek(config->ldc_fd, CEIL(entry.header.file_name_len, sizeof(uint32_t)) *
|
||||||
|
sizeof(uint32_t) - entry.header.file_name_len, SEEK_CUR);
|
||||||
|
|
||||||
|
/* fetching text length */
|
||||||
|
ret = fread(&entry.text_len, sizeof(entry.text_len), 1, config->ldc_fd);
|
||||||
|
if (!ret) {
|
||||||
|
ret = -ferror(config->ldc_fd);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fetching text */
|
||||||
|
entry.text = (char *)malloc(entry.text_len);
|
||||||
|
if (entry.text == NULL) {
|
||||||
|
fprintf(stderr, "error: can't allocate %d byte for "
|
||||||
|
"entry.text\n", entry.text_len);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fread(entry.text, sizeof(char), entry.text_len, config->ldc_fd);
|
||||||
|
if (ret != entry.text_len) {
|
||||||
|
ret = -ferror(config->ldc_fd);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fetching entry params from dma dump */
|
||||||
|
entry.params = (uint32_t *)malloc(sizeof(uint32_t) *
|
||||||
|
entry.header.params_num);
|
||||||
|
ret = fread(entry.params, sizeof(uint32_t), entry.header.params_num,
|
||||||
|
config->in_fd);
|
||||||
|
if (ret != entry.header.params_num) {
|
||||||
|
ret = -ferror(config->in_fd);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* printing entry content */
|
||||||
|
print_entry_params(config->out_fd, dma_log, entry, *last_timestamp,
|
||||||
|
config->clock);
|
||||||
|
*last_timestamp = dma_log.header.timestamp;
|
||||||
|
|
||||||
|
/* set f_ldc file position to the beginning */
|
||||||
|
rewind(config->ldc_fd);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
|
/* free alocated memory */
|
||||||
|
free(entry.params);
|
||||||
|
free(entry.text);
|
||||||
|
free(entry.file_name);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int logger_read(struct convert_config *config,
|
||||||
|
struct snd_sof_logs_header *snd)
|
||||||
|
{
|
||||||
|
struct dma_log dma_log;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
print_table_header(config->out_fd);
|
||||||
|
uint64_t last_timestamp = 0;
|
||||||
|
|
||||||
|
while (!feof(config->in_fd)) {
|
||||||
|
/* getting entry parameters from dma dump */
|
||||||
|
ret = fread(&dma_log, sizeof(dma_log), 1, config->in_fd);
|
||||||
|
if (!ret) {
|
||||||
|
return -ferror(config->in_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* checking log address */
|
||||||
|
if ((dma_log.address < snd->base_address) ||
|
||||||
|
dma_log.address > snd->base_address + snd->data_length)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* fetching entry from elf dump */
|
||||||
|
ret = fetch_entry(config, snd->base_address, snd->data_offset,
|
||||||
|
dma_log, &last_timestamp);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int convert(struct convert_config *config) {
|
||||||
|
struct snd_sof_logs_header snd;
|
||||||
|
int count, ret = 0;
|
||||||
|
|
||||||
|
count = fread(&snd, sizeof(snd), 1, config->ldc_fd);
|
||||||
|
if (!count) {
|
||||||
|
fprintf(stderr, "Error while reading %s. \n", config->ldc_file);
|
||||||
|
return -ferror(config->ldc_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(snd.sig, SND_SOF_LOGS_SIG, SND_SOF_LOGS_SIG_SIZE)) {
|
||||||
|
fprintf(stderr, "Error: Invalid ldc file signature. \n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return logger_read(config, &snd);
|
||||||
|
}
|
401
rmbox/rmbox.c
401
rmbox/rmbox.c
|
@ -12,259 +12,43 @@
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
* more details.
|
* more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#define KNRM "\x1B[0m"
|
#include "convert.h"
|
||||||
#define KRED "\x1B[31m"
|
|
||||||
|
|
||||||
// TODO: include all this stuff
|
|
||||||
|
|
||||||
#define TRACE_CLASS_IRQ (1 << 24)
|
|
||||||
#define TRACE_CLASS_IPC (2 << 24)
|
|
||||||
#define TRACE_CLASS_PIPE (3 << 24)
|
|
||||||
#define TRACE_CLASS_HOST (4 << 24)
|
|
||||||
#define TRACE_CLASS_DAI (5 << 24)
|
|
||||||
#define TRACE_CLASS_DMA (6 << 24)
|
|
||||||
#define TRACE_CLASS_SSP (7 << 24)
|
|
||||||
#define TRACE_CLASS_COMP (8 << 24)
|
|
||||||
#define TRACE_CLASS_WAIT (9 << 24)
|
|
||||||
#define TRACE_CLASS_LOCK (10 << 24)
|
|
||||||
#define TRACE_CLASS_MEM (11 << 24)
|
|
||||||
#define TRACE_CLASS_MIXER (12 << 24)
|
|
||||||
#define TRACE_CLASS_BUFFER (13 << 24)
|
|
||||||
#define TRACE_CLASS_VOLUME (14 << 24)
|
|
||||||
#define TRACE_CLASS_SWITCH (15 << 24)
|
|
||||||
#define TRACE_CLASS_MUX (16 << 24)
|
|
||||||
#define TRACE_CLASS_SRC (17 << 24)
|
|
||||||
#define TRACE_CLASS_TONE (18 << 24)
|
|
||||||
#define TRACE_CLASS_EQ_FIR (19 << 24)
|
|
||||||
#define TRACE_CLASS_EQ_IIR (20 << 24)
|
|
||||||
#define TRACE_CLASS_SA (21 << 24)
|
|
||||||
#define TRACE_CLASS_DMIC (22 << 24)
|
|
||||||
#define TRACE_CLASS_POWER (23 << 24)
|
|
||||||
|
|
||||||
|
#ifdef LOGGER_FORMAT
|
||||||
|
#define APP_NAME "logger"
|
||||||
|
#else
|
||||||
|
#define APP_NAME "rmbox"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
||||||
|
|
||||||
|
|
||||||
#define TRACE_BLOCK_SIZE 8
|
|
||||||
|
|
||||||
static inline char get_char(uint32_t val, int idx)
|
|
||||||
{
|
|
||||||
char c = (val >> (idx * 8)) & 0xff;
|
|
||||||
if (c < '0' || c > 'z')
|
|
||||||
return '.';
|
|
||||||
else
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usage(char *name)
|
|
||||||
{
|
|
||||||
fprintf(stdout, "Usage %s <option(s)> <file(s)>\n", name);
|
|
||||||
fprintf(stdout, "%s:\t \t\t\tDisplay mailbox contents\n", name);
|
|
||||||
fprintf(stdout, "%s:\t -i infile -o outfile\tDump infile contents to outfile\n", name);
|
|
||||||
fprintf(stdout, "%s:\t -c\t\t\tSet timestamp clock in MHz\n", name);
|
|
||||||
fprintf(stdout, "%s:\t -s\t\t\tTake a snapshot of state\n", name);
|
|
||||||
fprintf(stdout, "%s:\t -t\t\t\tDisplay trace data\n", name);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static double to_usecs(uint64_t time, double clk)
|
|
||||||
{
|
|
||||||
/* trace timestamp uses CPU system clock at default 25MHz ticks */
|
|
||||||
// TODO: support variable clock rates
|
|
||||||
return (double)time / clk;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void show_trace(uint64_t val, uint64_t addr, uint64_t *timestamp, double clk)
|
|
||||||
{
|
|
||||||
const char *trace;
|
|
||||||
uint32_t class;
|
|
||||||
uint64_t delta = val - *timestamp;
|
|
||||||
double fdelta = to_usecs(delta, clk);
|
|
||||||
double us = 0.0f;
|
|
||||||
|
|
||||||
/* timestamp or value ? */
|
|
||||||
if ((addr % (TRACE_BLOCK_SIZE * 2)) == 0) {
|
|
||||||
|
|
||||||
delta = val - *timestamp;
|
|
||||||
fdelta = to_usecs(delta, clk);
|
|
||||||
|
|
||||||
/* 64-bit timestamp */
|
|
||||||
us = to_usecs(val, clk);
|
|
||||||
|
|
||||||
/* empty data ? */
|
|
||||||
if (val == 0) {
|
|
||||||
*timestamp = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* detect wrap around */
|
|
||||||
if (fdelta < 1000.0 * 1000.0 * 1000.0)
|
|
||||||
printf("0x%lx [%6.6f]\tdelta [%6.6f]\t", addr,
|
|
||||||
us / 1000000.0 , fdelta / 1000000.0);
|
|
||||||
else
|
|
||||||
printf("0x%lx [%6.6f]\tdelta [********]\t", addr,
|
|
||||||
us / 1000000.0);
|
|
||||||
|
|
||||||
*timestamp = val;
|
|
||||||
return;
|
|
||||||
} else if (*timestamp == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* check for printable values - otherwise it's a value */
|
|
||||||
if (!isprint((char)(val >> 16)) || !isprint((char)(val >> 8)) || !isprint((char)val)) {
|
|
||||||
printf("value 0x%16.16lx\n", val);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
class = val & 0xff000000;
|
|
||||||
if (class == TRACE_CLASS_IRQ)
|
|
||||||
trace = "irq";
|
|
||||||
else if (class == TRACE_CLASS_IPC)
|
|
||||||
trace = "ipc";
|
|
||||||
else if (class == TRACE_CLASS_PIPE)
|
|
||||||
trace = "pipe";
|
|
||||||
else if (class == TRACE_CLASS_HOST)
|
|
||||||
trace = "host";
|
|
||||||
else if (class == TRACE_CLASS_DAI)
|
|
||||||
trace = "dai";
|
|
||||||
else if (class == TRACE_CLASS_DMA)
|
|
||||||
trace = "dma";
|
|
||||||
else if (class == TRACE_CLASS_SSP)
|
|
||||||
trace = "ssp";
|
|
||||||
else if (class == TRACE_CLASS_COMP)
|
|
||||||
trace = "comp";
|
|
||||||
else if (class == TRACE_CLASS_WAIT)
|
|
||||||
trace = "wait";
|
|
||||||
else if (class == TRACE_CLASS_LOCK)
|
|
||||||
trace = "lock";
|
|
||||||
else if (class == TRACE_CLASS_MEM)
|
|
||||||
trace = "mem";
|
|
||||||
else if (class == TRACE_CLASS_MIXER)
|
|
||||||
trace = "mixer";
|
|
||||||
else if (class == TRACE_CLASS_BUFFER)
|
|
||||||
trace = "buffer";
|
|
||||||
else if (class == TRACE_CLASS_VOLUME)
|
|
||||||
trace = "volume";
|
|
||||||
else if (class == TRACE_CLASS_SWITCH)
|
|
||||||
trace = "switch";
|
|
||||||
else if (class == TRACE_CLASS_MUX)
|
|
||||||
trace = "mux";
|
|
||||||
else if (class == TRACE_CLASS_SRC)
|
|
||||||
trace = "src";
|
|
||||||
else if (class == TRACE_CLASS_TONE)
|
|
||||||
trace = "tone";
|
|
||||||
else if (class == TRACE_CLASS_EQ_FIR)
|
|
||||||
trace = "eq-fir";
|
|
||||||
else if (class == TRACE_CLASS_EQ_IIR)
|
|
||||||
trace = "eq-iir";
|
|
||||||
else if (class == TRACE_CLASS_SA)
|
|
||||||
trace = "sa";
|
|
||||||
else if (class == TRACE_CLASS_DMIC)
|
|
||||||
trace = "dmic";
|
|
||||||
else if (class == TRACE_CLASS_POWER)
|
|
||||||
trace = "pm";
|
|
||||||
else {
|
|
||||||
printf("value 0x%8.8x\n", (uint32_t)val);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ((char)(val >> 16)) {
|
|
||||||
case 'e':
|
|
||||||
case 'E':
|
|
||||||
case 'x':
|
|
||||||
case 'X':
|
|
||||||
printf("%s%s %c%c%c%s\n", KRED, trace,
|
|
||||||
(char)(val >> 16), (char)(val >> 8), (char)val, KNRM);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("%s %c%c%c\n", trace,
|
|
||||||
(char)(val >> 16), (char)(val >> 8), (char)val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int trace_read(const char *in_file, const char *out_file, double clk)
|
|
||||||
{
|
|
||||||
int count, i;
|
|
||||||
FILE *in_fd = NULL, *out_fd = NULL;
|
|
||||||
char c, tmp[TRACE_BLOCK_SIZE] = {0};
|
|
||||||
uint64_t addr = 0, val, timestamp = 0;
|
|
||||||
|
|
||||||
in_fd = fopen(in_file, "r");
|
|
||||||
if (in_fd == NULL) {
|
|
||||||
fprintf(stderr, "error: unable to open %s for reading %d\n",
|
|
||||||
in_file, errno);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_file == NULL)
|
|
||||||
goto trace;
|
|
||||||
|
|
||||||
out_fd = fopen(out_file, "w");
|
|
||||||
if (out_fd == NULL) {
|
|
||||||
fprintf(stderr, "error: unable to open %s for writing %d\n",
|
|
||||||
out_file, errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
trace:
|
|
||||||
fprintf(stdout, "using %2.2fMHz timestamp clock\n", clk);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
count = fread(&tmp[0], 1, TRACE_BLOCK_SIZE, in_fd);
|
|
||||||
if (count != TRACE_BLOCK_SIZE)
|
|
||||||
break;
|
|
||||||
|
|
||||||
val = *((uint64_t*)tmp);
|
|
||||||
|
|
||||||
for (i = 0; i < TRACE_BLOCK_SIZE / 2; i++) {
|
|
||||||
c = tmp[i];
|
|
||||||
tmp[i] = tmp[TRACE_BLOCK_SIZE - i - 1];
|
|
||||||
tmp[TRACE_BLOCK_SIZE - i - 1] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
show_trace(val, addr, ×tamp, clk);
|
|
||||||
|
|
||||||
if (out_fd) {
|
|
||||||
count = fwrite(&tmp[0], 1, TRACE_BLOCK_SIZE, out_fd);
|
|
||||||
if (count != TRACE_BLOCK_SIZE)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr += TRACE_BLOCK_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(in_fd);
|
|
||||||
if (out_fd)
|
|
||||||
fclose(out_fd);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void show_data(uint32_t val, uint32_t addr)
|
|
||||||
{
|
|
||||||
printf("data: 0x%x = \t0x%8.8x \t(%8.8d) \t|%c%c%c%c|\n",
|
|
||||||
(unsigned int)addr,
|
|
||||||
val, val,
|
|
||||||
get_char(val, 3), get_char(val, 2),
|
|
||||||
get_char(val, 1), get_char(val, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const char *debugfs[] = {
|
static const char *debugfs[] = {
|
||||||
"dmac0", "dmac1", "ssp0", "ssp1",
|
"dmac0", "dmac1", "ssp0", "ssp1",
|
||||||
"ssp2", "iram", "dram", "shim",
|
"ssp2", "iram", "dram", "shim",
|
||||||
"mbox", "etrace",
|
"mbox", "etrace",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Usage %s <option(s)> <file(s)>\n", APP_NAME);
|
||||||
|
fprintf(stdout, "%s:\t \t\t\tDisplay mailbox contents\n", APP_NAME);
|
||||||
|
fprintf(stdout, "%s:\t -i infile -o outfile\tDump infile contents to outfile\n", APP_NAME);
|
||||||
|
#ifdef LOGGER_FORMAT
|
||||||
|
fprintf(stdout, "%s:\t -l *.ldc_file\t-i in_file\n", APP_NAME);
|
||||||
|
#endif
|
||||||
|
fprintf(stdout, "%s:\t -c\t\t\tSet timestamp clock in MHz\n", APP_NAME);
|
||||||
|
fprintf(stdout, "%s:\t -s\t\t\tTake a snapshot of state\n", APP_NAME);
|
||||||
|
fprintf(stdout, "%s:\t -t\t\t\tDisplay trace data\n", APP_NAME);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
static int snapshot(const char *name)
|
static int snapshot(const char *name)
|
||||||
{
|
{
|
||||||
const char *path = "/sys/kernel/debug/sof";
|
const char *path = "/sys/kernel/debug/sof";
|
||||||
|
@ -324,99 +108,112 @@ static int snapshot(const char *name)
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int opt, count, trace = 0;
|
struct convert_config config;
|
||||||
const char * out_file = NULL, *in_file = NULL;
|
int opt, count, ret = 0;
|
||||||
FILE *in_fd = NULL, *out_fd = NULL;
|
FILE *in_fd = NULL, *out_fd = NULL;
|
||||||
char c, tmp[8] = {0};
|
char c, tmp[8] = {0};
|
||||||
uint64_t addr = 0, val, timestamp = 0, align = 4, i;
|
uint64_t addr = 0, val, timestamp = 0, align = 4, i;
|
||||||
double clk = 19.2;
|
|
||||||
|
|
||||||
|
config.trace = 0;
|
||||||
|
config.clock = 19.2;
|
||||||
|
config.in_file = NULL;
|
||||||
|
config.out_file = NULL;
|
||||||
|
config.out_fd = NULL;
|
||||||
|
config.in_fd = NULL;
|
||||||
|
#ifdef LOGGER_FORMAT
|
||||||
|
config.ldc_file = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LOGGER_FORMAT
|
||||||
|
while ((opt = getopt(argc, argv, "ho:i:l:s:m:c:t")) != -1) {
|
||||||
|
#else
|
||||||
while ((opt = getopt(argc, argv, "ho:i:s:m:c:t")) != -1) {
|
while ((opt = getopt(argc, argv, "ho:i:s:m:c:t")) != -1) {
|
||||||
|
#endif
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'o':
|
case 'o':
|
||||||
out_file = optarg;
|
config.out_file = optarg;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
in_file = optarg;
|
config.in_file = optarg;
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
trace = 1;
|
config.trace = 1;
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
clk = atof(optarg);
|
config.clock = atof(optarg);
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
return snapshot(optarg);
|
return snapshot(optarg);
|
||||||
|
#ifdef LOGGER_FORMAT
|
||||||
|
case 'l':
|
||||||
|
config.ldc_file = optarg;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case 'h':
|
case 'h':
|
||||||
default: /* '?' */
|
default: /* '?' */
|
||||||
usage(argv[0]);
|
usage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LOGGER_FORMAT
|
||||||
|
if (!config.ldc_file) {
|
||||||
|
fprintf(stderr, "error: Missing ldc file");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
config.ldc_fd = fopen(config.ldc_file, "r");
|
||||||
|
if (!config.ldc_fd) {
|
||||||
|
fprintf(stderr, "error: Unable to open ldc file %s\n",
|
||||||
|
config.ldc_file);
|
||||||
|
ret = -errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (config.out_file) {
|
||||||
|
config.out_fd = fopen(config.out_file, "w");
|
||||||
|
if (!config.out_fd) {
|
||||||
|
fprintf(stderr, "error: Unable to open out file %s\n",
|
||||||
|
config.out_file);
|
||||||
|
ret = -errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config.out_fd = stdout;
|
||||||
|
}
|
||||||
|
|
||||||
/* trace requested ? */
|
/* trace requested ? */
|
||||||
if (trace)
|
if (config.trace)
|
||||||
return trace_read("/sys/kernel/debug/sof/trace",
|
config.in_file = "/sys/kernel/debug/sof/trace";
|
||||||
out_file, clk);
|
|
||||||
|
|
||||||
/* default option with no infile is to dump errors/debug data */
|
/* default option with no infile is to dump errors/debug data */
|
||||||
if (in_file == NULL) {
|
if (!config.in_file)
|
||||||
fprintf(stdout, "\nError log:\n");
|
config.in_file = "/sys/kernel/debug/sof/etrace";
|
||||||
return trace_read("/sys/kernel/debug/sof/etrace",
|
|
||||||
out_file, clk);
|
if (config.in_file) {
|
||||||
|
config.in_fd = fopen(config.in_file, "r");
|
||||||
|
if (!config.in_fd) {
|
||||||
|
fprintf(stderr, "error: Unable to open in file %s\n",
|
||||||
|
config.in_file);
|
||||||
|
ret = -errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open infile for reading */
|
convert(&config);
|
||||||
in_fd = fopen(in_file, "r");
|
|
||||||
if (in_fd == NULL) {
|
|
||||||
fprintf(stderr, "error: unable to open %s for reading %d\n",
|
|
||||||
in_file, errno);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open outfile for writing */
|
|
||||||
if (out_file == NULL)
|
|
||||||
goto convert;
|
|
||||||
|
|
||||||
out_fd = fopen(out_file, "w");
|
|
||||||
if (out_fd == NULL) {
|
|
||||||
fprintf(stderr, "error: unable to open %s for writing %d\n",
|
|
||||||
out_file, errno);
|
|
||||||
fclose(in_fd);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* start to converting mailbox */
|
|
||||||
convert:
|
|
||||||
fprintf(stdout, "using %2.2fMHz timestamp clock\n", clk);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
count = fread(&tmp[0], 1, align, in_fd);
|
|
||||||
if (count != align)
|
|
||||||
break;
|
|
||||||
|
|
||||||
val = *((uint64_t*)tmp);
|
|
||||||
|
|
||||||
for (i = 0; i < align / 2; i++) {
|
|
||||||
c = tmp[i];
|
|
||||||
tmp[i] = tmp[align - i - 1];
|
|
||||||
tmp[align - i - 1] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
show_data(val, addr);
|
|
||||||
|
|
||||||
if (out_fd) {
|
|
||||||
count = fwrite(&tmp[0], 1, align, out_fd);
|
|
||||||
if (count != align)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr += align;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
out:
|
||||||
/* close files */
|
/* close files */
|
||||||
fclose(in_fd);
|
if (config.out_file)
|
||||||
if (out_fd)
|
fclose(config.out_fd);
|
||||||
fclose(out_fd);
|
|
||||||
|
|
||||||
return 0;
|
if (config.in_fd)
|
||||||
|
fclose(config.in_fd);
|
||||||
|
|
||||||
|
#ifdef LOGGER_FORMAT
|
||||||
|
if (config.ldc_fd)
|
||||||
|
fclose(config.ldc_fd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
* debug log converter, using old rmbox format.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018, Intel Corporation.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "convert.h"
|
||||||
|
|
||||||
|
#define TRACE_BLOCK_SIZE 8
|
||||||
|
|
||||||
|
#define CASE(x) case(TRACE_CLASS_##x): trace = #x; break
|
||||||
|
|
||||||
|
static void show_trace(FILE *out_fd, uint64_t val, uint64_t addr,
|
||||||
|
uint64_t *timestamp, double clk)
|
||||||
|
{
|
||||||
|
const char *trace;
|
||||||
|
uint32_t class;
|
||||||
|
uint64_t delta = val - *timestamp;
|
||||||
|
double fdelta = to_usecs(delta, clk);
|
||||||
|
double us = 0.0f;
|
||||||
|
|
||||||
|
/* timestamp or value ? */
|
||||||
|
if ((addr % (TRACE_BLOCK_SIZE * 2)) == 0) {
|
||||||
|
|
||||||
|
delta = val - *timestamp;
|
||||||
|
fdelta = to_usecs(delta, clk);
|
||||||
|
|
||||||
|
/* 64-bit timestamp */
|
||||||
|
us = to_usecs(val, clk);
|
||||||
|
|
||||||
|
/* empty data ? */
|
||||||
|
if (val == 0) {
|
||||||
|
*timestamp = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* detect wrap around */
|
||||||
|
if (fdelta < 1000.0 * 1000.0 * 1000.0)
|
||||||
|
fprintf(out_fd, "0x%lx [%6.6f]\tdelta [%6.6f]\t", addr,
|
||||||
|
us / 1000000.0, fdelta / 1000000.0);
|
||||||
|
else
|
||||||
|
fprintf(out_fd, "0x%lx [%6.6f]\tdelta [********]\t", addr,
|
||||||
|
us / 1000000.0);
|
||||||
|
|
||||||
|
*timestamp = val;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (*timestamp == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* check for printable values - otherwise it's a value */
|
||||||
|
if (!isprint((char)(val >> 16)) || !isprint((char)(val >> 8)) || !isprint((char)val)) {
|
||||||
|
fprintf(out_fd, "value 0x%16.16lx\n", val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
class = val & 0xff000000;
|
||||||
|
switch (class)
|
||||||
|
{
|
||||||
|
CASE(IRQ);
|
||||||
|
CASE(IPC);
|
||||||
|
CASE(PIPE);
|
||||||
|
CASE(HOST);
|
||||||
|
CASE(DAI);
|
||||||
|
CASE(DMA);
|
||||||
|
CASE(SSP);
|
||||||
|
CASE(COMP);
|
||||||
|
CASE(WAIT);
|
||||||
|
CASE(LOCK);
|
||||||
|
CASE(MEM);
|
||||||
|
CASE(MIXER);
|
||||||
|
CASE(BUFFER);
|
||||||
|
CASE(VOLUME);
|
||||||
|
CASE(SWITCH);
|
||||||
|
CASE(MUX);
|
||||||
|
CASE(SRC);
|
||||||
|
CASE(TONE);
|
||||||
|
CASE(EQ_FIR);
|
||||||
|
CASE(EQ_IIR);
|
||||||
|
CASE(SA);
|
||||||
|
CASE(DMIC);
|
||||||
|
CASE(POWER);
|
||||||
|
default:
|
||||||
|
fprintf(out_fd, "value 0x%8.8x\n", (uint32_t)val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ((char)(val >> 16)) {
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
fprintf(out_fd, "%s%s %c%c%c%s\n", KRED, trace,
|
||||||
|
(char)(val >> 16), (char)(val >> 8), (char)val, KNRM);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(out_fd, "%s %c%c%c\n", trace,
|
||||||
|
(char)(val >> 16), (char)(val >> 8), (char)val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int convert(struct convert_config *config)
|
||||||
|
{
|
||||||
|
int count, i;
|
||||||
|
char c, tmp[TRACE_BLOCK_SIZE] = { 0 };
|
||||||
|
uint64_t addr = 0, val, timestamp = 0;
|
||||||
|
|
||||||
|
fprintf(stdout, "using %2.2fMHz timestamp clock\n", config->clock);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
count = fread(&tmp[0], 1, TRACE_BLOCK_SIZE, config->in_fd);
|
||||||
|
if (count != TRACE_BLOCK_SIZE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
val = *((uint64_t*)tmp);
|
||||||
|
|
||||||
|
for (i = 0; i < TRACE_BLOCK_SIZE / 2; i++) {
|
||||||
|
c = tmp[i];
|
||||||
|
tmp[i] = tmp[TRACE_BLOCK_SIZE - i - 1];
|
||||||
|
tmp[TRACE_BLOCK_SIZE - i - 1] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
show_trace(config->out_fd, val, addr, ×tamp, config->clock);
|
||||||
|
|
||||||
|
addr += TRACE_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Intel Corporation
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the Intel Corporation nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file include/uapi/abi.h
|
||||||
|
* \brief ABI definitions
|
||||||
|
* \author Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __INCLUDE_UAPI_ABI_H__
|
||||||
|
#define __INCLUDE_UAPI_ABI_H__
|
||||||
|
|
||||||
|
/** \brief SOF ABI version number. */
|
||||||
|
#define SOF_ABI_VER(major, minor, micro) \
|
||||||
|
(((major)<<8)|((minor)<<4)|(micro))
|
||||||
|
#define SOF_ABI_VERSION_MAJOR(version) (((version)>>8) & 0xff)
|
||||||
|
#define SOF_ABI_VERSION_MINOR(version) (((version)>>4) & 0xf)
|
||||||
|
#define SOF_ABI_VERSION_MICRO(version) ((version) & 0xf)
|
||||||
|
#define SOF_ABI_VERSION_INCOMPATIBLE(sof_ver, client_ver) \
|
||||||
|
(SOF_ABI_VERSION_MAJOR(sof_ver) != SOF_ABI_VERSION_MAJOR(client_ver) ||\
|
||||||
|
(SOF_ABI_VERSION_MAJOR(sof_ver) == SOF_ABI_VERSION_MAJOR(client_ver) &&\
|
||||||
|
SOF_ABI_VERSION_MINOR(sof_ver) != SOF_ABI_VERSION_MINOR(client_ver)))
|
||||||
|
|
||||||
|
#define SOF_ABI_MAJOR 1
|
||||||
|
#define SOF_ABI_MINOR 0
|
||||||
|
#define SOF_ABI_MICRO 0
|
||||||
|
|
||||||
|
#define SOF_ABI_VERSION SOF_ABI_VER(SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_MICRO)
|
||||||
|
|
||||||
|
/** \brief SOF ABI magic number "SOF\0". */
|
||||||
|
#define SOF_ABI_MAGIC 0x00464F53
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Header for all non IPC ABI data.
|
||||||
|
*
|
||||||
|
* Identifies data type, size and ABI.
|
||||||
|
* Used by any bespoke component data structures or binary blobs.
|
||||||
|
*/
|
||||||
|
struct sof_abi_hdr {
|
||||||
|
uint32_t magic; /**< 'S', 'O', 'F', '\0' */
|
||||||
|
uint32_t type; /**< component specific type */
|
||||||
|
uint32_t size; /**< size in bytes of data excl. this struct */
|
||||||
|
uint32_t abi; /**< SOF ABI version */
|
||||||
|
uint32_t comp_abi; /**< component specific ABI version */
|
||||||
|
char data[0]; /**< data */
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Intel Corporation
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the Intel Corporation nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Author: Bartosz Kokoszko <bartoszx.kokoszko@linux.intel.com>
|
||||||
|
* Artur Kloniecki <arturx.kloniecki@linux.intel.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __INCLUDE_LOGGING__
|
||||||
|
#define __INCLUDE_LOGGING__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Host system time.
|
||||||
|
*
|
||||||
|
* This property is used by the driver to pass down information about
|
||||||
|
* current system time. It is expressed in us.
|
||||||
|
* FW translates timestamps (in log entries, probe pockets) to this time
|
||||||
|
* domain.
|
||||||
|
*
|
||||||
|
* (cavs: SystemTime).
|
||||||
|
*/
|
||||||
|
struct system_time {
|
||||||
|
uint32_t val_l; /* Lower dword of current host time value */
|
||||||
|
uint32_t val_u; /* Upper dword of current host time value */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* trace event classes - high 8 bits*/
|
||||||
|
#define TRACE_CLASS_IRQ (1 << 24)
|
||||||
|
#define TRACE_CLASS_IPC (2 << 24)
|
||||||
|
#define TRACE_CLASS_PIPE (3 << 24)
|
||||||
|
#define TRACE_CLASS_HOST (4 << 24)
|
||||||
|
#define TRACE_CLASS_DAI (5 << 24)
|
||||||
|
#define TRACE_CLASS_DMA (6 << 24)
|
||||||
|
#define TRACE_CLASS_SSP (7 << 24)
|
||||||
|
#define TRACE_CLASS_COMP (8 << 24)
|
||||||
|
#define TRACE_CLASS_WAIT (9 << 24)
|
||||||
|
#define TRACE_CLASS_LOCK (10 << 24)
|
||||||
|
#define TRACE_CLASS_MEM (11 << 24)
|
||||||
|
#define TRACE_CLASS_MIXER (12 << 24)
|
||||||
|
#define TRACE_CLASS_BUFFER (13 << 24)
|
||||||
|
#define TRACE_CLASS_VOLUME (14 << 24)
|
||||||
|
#define TRACE_CLASS_SWITCH (15 << 24)
|
||||||
|
#define TRACE_CLASS_MUX (16 << 24)
|
||||||
|
#define TRACE_CLASS_SRC (17 << 24)
|
||||||
|
#define TRACE_CLASS_TONE (18 << 24)
|
||||||
|
#define TRACE_CLASS_EQ_FIR (19 << 24)
|
||||||
|
#define TRACE_CLASS_EQ_IIR (20 << 24)
|
||||||
|
#define TRACE_CLASS_SA (21 << 24)
|
||||||
|
#define TRACE_CLASS_DMIC (22 << 24)
|
||||||
|
#define TRACE_CLASS_POWER (23 << 24)
|
||||||
|
#define TRACE_CLASS_IDC (24 << 24)
|
||||||
|
#define TRACE_CLASS_CPU (25 << 24)
|
||||||
|
|
||||||
|
#define LOG_ENABLE 1 /* Enable logging */
|
||||||
|
#define LOG_DISABLE 0 /* Disable logging */
|
||||||
|
|
||||||
|
#define LOG_LEVEL_CRITICAL 1 /* (FDK fatal) */
|
||||||
|
#define LOG_LEVEL_VERBOSE 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Layout of a log fifo.
|
||||||
|
*/
|
||||||
|
struct log_buffer_layout {
|
||||||
|
uint32_t read_ptr; /*read pointer */
|
||||||
|
uint32_t write_ptr; /* write pointer */
|
||||||
|
uint32_t buffer[0]; /* buffer */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Log buffer status reported by FW.
|
||||||
|
*/
|
||||||
|
struct log_buffer_status {
|
||||||
|
uint32_t core_id; /* ID of core that logged to other half */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Log entry header.
|
||||||
|
*
|
||||||
|
* The header is followed by an array of arguments (uint32_t[]).
|
||||||
|
* Number of arguments is specified by the params_num field of log_entry,
|
||||||
|
* and is 0-based value (entry_len=0 means there is 1 argument).
|
||||||
|
*/
|
||||||
|
struct log_entry_header {
|
||||||
|
uint32_t rsvd : 24; /* Unused */
|
||||||
|
uint32_t core_id : 8; /* Reporting core's id */
|
||||||
|
|
||||||
|
uint64_t timestamp; /* Timestamp (in dsp ticks) */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
#endif //#ifndef __INCLUDE_LOGGING__
|
Loading…
Reference in New Issue