Add missing braces to comply with MISRA C:2012 Rule 15.6 and also following Zephyr's style guideline. Signed-off-by: Pisit Sawangvonganan <pisit@ndrsolution.com>
230 lines
5.5 KiB
C
230 lines
5.5 KiB
C
/*
|
|
* Copyright (c) 2019,2022 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/logging/log_backend_adsp_mtrace.h>
|
|
#include <zephyr/logging/log_backend.h>
|
|
#include <zephyr/logging/log_core.h>
|
|
#include <zephyr/logging/log_output.h>
|
|
#include <zephyr/logging/log_backend_std.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <soc.h>
|
|
|
|
#include <adsp_memory.h>
|
|
#include <adsp_debug_window.h>
|
|
|
|
/*
|
|
* A lock is needed as log_process() and log_panic() have no internal locks
|
|
* to prevent concurrency. Meaning if log_process is called after
|
|
* log_panic was called previously, log_process may happen from another
|
|
* CPU and calling context than the log processing thread running in
|
|
* the background. On an SMP system this is a race.
|
|
*
|
|
* This caused a race on the output trace such that the logging output
|
|
* was garbled and useless.
|
|
*/
|
|
static struct k_spinlock mtrace_lock;
|
|
|
|
static uint32_t log_format_current = CONFIG_LOG_BACKEND_ADSP_MTRACE_OUTPUT_DEFAULT;
|
|
|
|
static adsp_mtrace_log_hook_t mtrace_hook;
|
|
|
|
static bool mtrace_active;
|
|
|
|
static bool mtrace_panic_mode;
|
|
|
|
/*
|
|
* SRAM window for debug info is organized to equal size slots.
|
|
* The descriptors on first page describe the layout of slots.
|
|
* One type of debug info slot is ADSP_DBG_WIN_SLOT_DEBUG_LOG.
|
|
* These slots (if defined) can be used for mtrace output.
|
|
*
|
|
* The log buffer slots have the following layout:
|
|
*
|
|
* u32 host_read_ptr;
|
|
* u32 dsp_write_ptr;
|
|
* u8 buffer[];
|
|
*
|
|
* The two pointers are offsets within the buffer. Buffer is empty
|
|
* when the two pointers are equal, and full when host read pointer
|
|
* is one ahead of the DSP writer pointer.
|
|
*/
|
|
|
|
#define MTRACE_LOG_BUF_SIZE (ADSP_DW_SLOT_SIZE - 2 * sizeof(uint32_t))
|
|
|
|
#define MTRACE_LOGGING_SLOT_TYPE(n) (ADSP_DW_SLOT_DEBUG_LOG | ((n) & ADSP_DW_SLOT_CORE_MASK))
|
|
|
|
#define MTRACE_CORE 0
|
|
|
|
struct adsp_debug_slot {
|
|
uint32_t host_ptr;
|
|
uint32_t dsp_ptr;
|
|
uint8_t data[ADSP_DW_SLOT_SIZE - sizeof(uint32_t) * 2];
|
|
} __packed;
|
|
|
|
static void mtrace_init(void)
|
|
{
|
|
if (ADSP_DW->descs[0].type == MTRACE_LOGGING_SLOT_TYPE(MTRACE_CORE)) {
|
|
return;
|
|
}
|
|
|
|
ADSP_DW->descs[0].type = MTRACE_LOGGING_SLOT_TYPE(MTRACE_CORE);
|
|
}
|
|
|
|
static size_t mtrace_out(int8_t *str, size_t len, size_t *space_left)
|
|
{
|
|
struct adsp_debug_slot *slot = (struct adsp_debug_slot *)(ADSP_DW->slots[0]);
|
|
uint8_t *data = slot->data;
|
|
uint32_t r = slot->host_ptr;
|
|
uint32_t w = slot->dsp_ptr;
|
|
size_t avail, out;
|
|
|
|
if (w > r) {
|
|
avail = MTRACE_LOG_BUF_SIZE - w + r - 1;
|
|
} else if (w == r) {
|
|
avail = MTRACE_LOG_BUF_SIZE - 1;
|
|
} else {
|
|
avail = r - w - 1;
|
|
}
|
|
|
|
if (len == 0) {
|
|
out = 0;
|
|
goto out;
|
|
}
|
|
|
|
/* data that does not fit is dropped */
|
|
out = MIN(avail, len);
|
|
|
|
if (w + out >= MTRACE_LOG_BUF_SIZE) {
|
|
size_t tail = MTRACE_LOG_BUF_SIZE - w;
|
|
size_t head = out - tail;
|
|
|
|
memcpy(data + w, str, tail);
|
|
memcpy(data, str + tail, head);
|
|
w = head;
|
|
} else {
|
|
memcpy(data + w, str, out);
|
|
w += out;
|
|
}
|
|
|
|
slot->dsp_ptr = w;
|
|
|
|
out:
|
|
if (space_left) {
|
|
*space_left = avail > len ? avail - len : 0;
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
static int char_out(uint8_t *data, size_t length, void *ctx)
|
|
{
|
|
size_t space_left = 0;
|
|
size_t out;
|
|
|
|
/*
|
|
* we handle the data even if mtrace notifier is not
|
|
* active. this ensures we can capture early boot messages.
|
|
*/
|
|
out = mtrace_out(data, length, &space_left);
|
|
|
|
if (mtrace_active && mtrace_hook) {
|
|
|
|
/* if we are in panic mode, need to flush out asap */
|
|
if (unlikely(mtrace_panic_mode)) {
|
|
space_left = 0;
|
|
}
|
|
|
|
mtrace_hook(out, space_left);
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
/**
|
|
* 80 bytes seems to catch most sensibly sized log message lines
|
|
* in one go letting the trace out call output whole complete
|
|
* lines. This avoids the overhead of a spin lock in the trace_out
|
|
* more often as well as avoiding entwined characters from printk if
|
|
* LOG_PRINTK=n.
|
|
*/
|
|
#define LOG_BUF_SIZE 80
|
|
static uint8_t log_buf[LOG_BUF_SIZE];
|
|
|
|
LOG_OUTPUT_DEFINE(log_output_adsp_mtrace, char_out, log_buf, sizeof(log_buf));
|
|
|
|
static uint32_t format_flags(void)
|
|
{
|
|
uint32_t flags = LOG_OUTPUT_FLAG_LEVEL | LOG_OUTPUT_FLAG_TIMESTAMP;
|
|
|
|
if (IS_ENABLED(CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP)) {
|
|
flags |= LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP;
|
|
}
|
|
|
|
return flags;
|
|
}
|
|
|
|
static void panic(struct log_backend const *const backend)
|
|
{
|
|
mtrace_panic_mode = true;
|
|
}
|
|
|
|
static void dropped(const struct log_backend *const backend,
|
|
uint32_t cnt)
|
|
{
|
|
log_output_dropped_process(&log_output_adsp_mtrace, cnt);
|
|
}
|
|
|
|
static void process(const struct log_backend *const backend,
|
|
union log_msg_generic *msg)
|
|
{
|
|
log_format_func_t log_output_func = log_format_func_t_get(log_format_current);
|
|
|
|
k_spinlock_key_t key = k_spin_lock(&mtrace_lock);
|
|
|
|
log_output_func(&log_output_adsp_mtrace, &msg->log, format_flags());
|
|
|
|
k_spin_unlock(&mtrace_lock, key);
|
|
}
|
|
|
|
static int format_set(const struct log_backend *const backend, uint32_t log_type)
|
|
{
|
|
log_format_current = log_type;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Lazily initialized, while the DMA may not be setup we continue
|
|
* to buffer log messages untilt he buffer is full.
|
|
*/
|
|
static void init(const struct log_backend *const backend)
|
|
{
|
|
ARG_UNUSED(backend);
|
|
|
|
mtrace_init();
|
|
}
|
|
|
|
const struct log_backend_api log_backend_adsp_mtrace_api = {
|
|
.process = process,
|
|
.dropped = IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE) ? NULL : dropped,
|
|
.panic = panic,
|
|
.format_set = format_set,
|
|
.init = init,
|
|
};
|
|
|
|
LOG_BACKEND_DEFINE(log_backend_adsp_mtrace, log_backend_adsp_mtrace_api, true);
|
|
|
|
void adsp_mtrace_log_init(adsp_mtrace_log_hook_t hook)
|
|
{
|
|
mtrace_init();
|
|
|
|
mtrace_hook = hook;
|
|
mtrace_active = true;
|
|
}
|
|
|
|
const struct log_backend *log_backend_adsp_mtrace_get(void)
|
|
{
|
|
return &log_backend_adsp_mtrace;
|
|
}
|