intel_adsp: Add debug slot manager

Currently all drivers which uses a slot from the debug window have fragile
hardwired slot 'mapping', they are locked to use specific slots even if
there are free slots available for them to take.

The new API hides the management of the slots and descriptors and users
can ask, release or even seize slots that they want to use.

Add a new debug slot manager API and a new default no config option to
allow selection between the hardwired or dynamic debug slot management.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
This commit is contained in:
Peter Ujfalusi
2025-10-06 16:21:27 +03:00
committed by Anas Nashif
parent 2ce9d5f5e3
commit ebb5625bee
9 changed files with 379 additions and 14 deletions

View File

@@ -77,6 +77,15 @@ config MEMORY_WIN_3_SIZE
This window is used for trace.
config INTEL_ADSP_DEBUG_SLOT_MANAGER
bool "Debug slot manager"
help
If selected the debug slot allocation can be only done via
the manager API, direct debug window access and tampering is
forbidden.
The API use allows dynamic slot allocation instead of static
and error prone slot usage.
config ADSP_CLOCK
bool
help

View File

@@ -25,6 +25,10 @@ zephyr_library_sources(
zephyr_library_sources_ifdef(CONFIG_ADSP_CLOCK clk.c)
zephyr_library_sources_ifdef(CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
debug_window.c
)
if(CONFIG_SMP OR CONFIG_MP_MAX_NUM_CPUS GREATER 1)
zephyr_library_sources(multiprocessing.c)
endif()

View File

@@ -0,0 +1,187 @@
/* Copyright (c) 2025 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#include <adsp_memory.h>
#include <adsp_debug_window.h>
#include <zephyr/cache.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(debug_window, CONFIG_SOC_LOG_LEVEL);
struct adsp_debug_window {
struct adsp_dw_desc descs[ADSP_DW_DESC_COUNT];
uint8_t reserved[ADSP_DW_PAGE0_SLOT_OFFSET -
ADSP_DW_DESC_COUNT * sizeof(struct adsp_dw_desc)];
uint8_t partial_page0[ADSP_DW_SLOT_SIZE - ADSP_DW_PAGE0_SLOT_OFFSET];
uint8_t slots[ADSP_DW_SLOT_COUNT][ADSP_DW_SLOT_SIZE];
} __packed;
#define WIN2_MBASE DT_REG_ADDR(DT_PHANDLE(DT_NODELABEL(mem_window2), memory))
#define WIN2_SLOTS ((HP_SRAM_WIN2_SIZE / ADSP_DW_PAGE_SIZE) - 1)
#define ADSP_DW_FULL_SLOTS MIN(WIN2_SLOTS, ADSP_DW_SLOT_COUNT)
#define ADSP_DW ((struct adsp_debug_window *) \
(sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) \
(WIN2_MBASE + WIN2_OFFSET))))
static int adsp_dw_find_unused_slot(bool prefer_partial)
{
int i;
if (prefer_partial) {
if (ADSP_DW->descs[ADSP_DW_SLOT_COUNT].type == ADSP_DW_SLOT_UNUSED) {
return ADSP_DW_SLOT_COUNT;
}
}
for (i = 0; i < ADSP_DW_FULL_SLOTS; i++) {
if (ADSP_DW->descs[i].type == ADSP_DW_SLOT_UNUSED) {
return i;
}
}
if (!prefer_partial) {
if (ADSP_DW->descs[ADSP_DW_SLOT_COUNT].type == ADSP_DW_SLOT_UNUSED) {
return ADSP_DW_SLOT_COUNT;
}
}
return -ENOENT;
}
static int adsp_dw_find_slot_by_type(uint32_t type)
{
int i;
for (i = 0; i < ADSP_DW_FULL_SLOTS; i++) {
if (ADSP_DW->descs[i].type == type) {
return i;
}
}
if (ADSP_DW->descs[ADSP_DW_SLOT_COUNT].type == type) {
return ADSP_DW_SLOT_COUNT;
}
return -ENOENT;
}
void *adsp_dw_request_slot(struct adsp_dw_desc *dw_desc, size_t *slot_size)
{
int slot_idx;
if (!dw_desc->type) {
return NULL;
}
/* Check if a slot has been allocated for this type */
slot_idx = adsp_dw_find_slot_by_type(dw_desc->type);
if (slot_idx >= 0) {
if (slot_size) {
*slot_size = ADSP_DW_SLOT_SIZE;
}
if (slot_idx == ADSP_DW_SLOT_COUNT) {
if (slot_size) {
*slot_size -= ADSP_DW_PAGE0_SLOT_OFFSET;
}
return ADSP_DW->partial_page0;
}
return ADSP_DW->slots[slot_idx];
}
/* Look for an empty slot */
slot_idx = adsp_dw_find_unused_slot(!!slot_size);
if (slot_idx < 0) {
LOG_INF("No available slot for %#x", dw_desc->type);
return NULL;
}
ADSP_DW->descs[slot_idx].resource_id = dw_desc->resource_id;
ADSP_DW->descs[slot_idx].type = dw_desc->type;
ADSP_DW->descs[slot_idx].vma = dw_desc->vma;
if (slot_size) {
*slot_size = ADSP_DW_SLOT_SIZE;
}
if (slot_idx == ADSP_DW_SLOT_COUNT) {
if (slot_size) {
*slot_size -= ADSP_DW_PAGE0_SLOT_OFFSET;
}
LOG_DBG("Allocating partial page0 to be used for %#x", dw_desc->type);
return ADSP_DW->partial_page0;
}
LOG_DBG("Allocating debug slot %d to be used for %#x", slot_idx, dw_desc->type);
return ADSP_DW->slots[slot_idx];
}
void *adsp_dw_seize_slot(uint32_t slot_index, struct adsp_dw_desc *dw_desc,
size_t *slot_size)
{
if ((slot_index >= ADSP_DW_FULL_SLOTS && slot_index != ADSP_DW_SLOT_COUNT) ||
!dw_desc->type) {
return NULL;
}
if (slot_index < ADSP_DW_FULL_SLOTS) {
if (ADSP_DW->descs[slot_index].type != ADSP_DW_SLOT_UNUSED) {
LOG_INF("Overtaking debug slot %d, used by %#x for %#x", slot_index,
ADSP_DW->descs[slot_index].type, dw_desc->type);
}
if (slot_size) {
*slot_size = ADSP_DW_SLOT_SIZE;
}
ADSP_DW->descs[slot_index].resource_id = dw_desc->resource_id;
ADSP_DW->descs[slot_index].type = dw_desc->type;
ADSP_DW->descs[slot_index].vma = dw_desc->vma;
return ADSP_DW->slots[slot_index];
}
/* The caller is not prepared to handle partial debug slot */
if (!slot_size) {
return NULL;
}
if (ADSP_DW->descs[slot_index].type != ADSP_DW_SLOT_UNUSED) {
LOG_INF("Overtaking partial page0, used by %#x for %#x",
ADSP_DW->descs[slot_index].type, dw_desc->type);
}
*slot_size = ADSP_DW_SLOT_SIZE - ADSP_DW_PAGE0_SLOT_OFFSET;
ADSP_DW->descs[slot_index].resource_id = dw_desc->resource_id;
ADSP_DW->descs[slot_index].type = dw_desc->type;
ADSP_DW->descs[slot_index].vma = dw_desc->vma;
return ADSP_DW->partial_page0;
}
void adsp_dw_release_slot(uint32_t type)
{
int slot_idx;
slot_idx = adsp_dw_find_slot_by_type(type);
if (slot_idx < 0) {
return;
}
if (slot_idx == ADSP_DW_SLOT_COUNT) {
LOG_DBG("Releasing partial page0 used by %#x", type);
} else {
LOG_DBG("Releasing debug slot %d used by %#x", slot_idx, type);
}
ADSP_DW->descs[slot_idx].resource_id = 0;
ADSP_DW->descs[slot_idx].type = ADSP_DW_SLOT_UNUSED;
ADSP_DW->descs[slot_idx].vma = 0;
}

View File

@@ -57,18 +57,51 @@ static inline int ring_have_data(const volatile struct gdb_sram_ring *ring)
return ring->head != ring->tail;
}
#define RX_UNCACHED (uint8_t *) (HP_SRAM_WIN2_BASE + SOF_GDB_WINDOW_OFFSET)
#define TX_UNCACHED (uint8_t *) (RX_UNCACHED + sizeof(struct gdb_sram_ring))
static volatile struct gdb_sram_ring *rx;
static volatile struct gdb_sram_ring *tx;
#ifndef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
static int gdb_get_debug_slot(void)
{
struct adsp_dw_desc slot_desc = { .type = ADSP_DW_SLOT_GDB_STUB, };
size_t slot_size;
char *slot_addr;
if (rx && tx) {
/* Slot already allocated */
return 0;
}
/* Force use the partial page0 slot */
slot_addr = (char *)adsp_dw_request_slot(&slot_desc, &slot_size);
if (!slot_addr) {
return -ENOMEM;
}
rx = sys_cache_uncached_ptr_get(slot_addr);
tx = sys_cache_uncached_ptr_get(slot_addr + sizeof(struct gdb_sram_ring));
return 0;
}
#define RX_UNCACHED (uint8_t *) (HP_SRAM_WIN2_BASE + SOF_GDB_WINDOW_OFFSET)
#define TX_UNCACHED (uint8_t *) (RX_UNCACHED + sizeof(struct gdb_sram_ring))
#endif
int z_gdb_backend_init(void)
{
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
int ret = gdb_get_debug_slot();
if (ret) {
return ret;
}
#else
__ASSERT_NO_MSG(sizeof(ADSP_DW->descs) <= SOF_GDB_WINDOW_OFFSET);
rx = sys_cache_uncached_ptr_get(RX_UNCACHED);
tx = sys_cache_uncached_ptr_get(TX_UNCACHED);
#endif
rx->head = rx->tail = 0;
tx->head = tx->tail = 0;
@@ -98,7 +131,12 @@ unsigned char z_gdb_getchar(void)
static int gdbstub_backend_sram_init(void)
{
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
return gdb_get_debug_slot();
#else
ADSP_DW->descs[ADSP_DW_SLOT_NUM_GDB].type = ADSP_DW_SLOT_GDB_STUB;
#endif
return 0;
}

View File

@@ -65,14 +65,6 @@
#define ADSP_DW_PAGE0_SLOT_OFFSET 1024
#define ADSP_DW_DESC_COUNT (ADSP_DW_SLOT_COUNT + 1)
/* debug window slots usage, mutually exclusive options can reuse slots */
#define ADSP_DW_SLOT_NUM_SHELL 0
#define ADSP_DW_SLOT_NUM_MTRACE 0
#define ADSP_DW_SLOT_NUM_TRACE 1
#define ADSP_DW_SLOT_NUM_TELEMETRY 1
/* this uses remaining space in the first page after descriptors */
#define ADSP_DW_SLOT_NUM_GDB (ADSP_DW_DESC_COUNT - 1)
/* debug log slot types */
#define ADSP_DW_SLOT_UNUSED 0x00000000
#define ADSP_DW_SLOT_CRITICAL_LOG 0x54524300
@@ -94,6 +86,56 @@ struct adsp_dw_desc {
uint32_t vma;
} __packed;
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
/**
* @brief Request a free debug slot for a function described by desc
*
* if a slot for the same function has been already allocated, the existing slot will be returned
*
* @param dw_desc Description of the slot to be requested for
* @param slot_size Optional pointer to receive back the size of the assigned slot, if not
* provided then the partial slot from window 0 cannot be requested as caller
* must be aware and be able to handle the different size of the slot
*
* @return Pointer to the start of the slot or NULL in case of an error. When NULL is
* returned, the @slot_size value is undefined.
*/
void *adsp_dw_request_slot(struct adsp_dw_desc *dw_desc, size_t *slot_size);
/**
* @brief Forcibly overtake a slot
*
* @param slot_index Index of the slot to take.
* Requesting ADSP_DW_FULL_SLOTS will return the partial slot
* @param dw_desc Description of the slot to be requested for
* @param slot_size Optional pointer to receive back the size of the assigned slot, if not
* provided then the partial slot from window 0 cannot be requested as caller
* must be aware and be able to handle the different size of the slot
*
* @return Pointer to the start of the slot or NULL in case of an error. When NULL is
* returned, the @slot_size value is undefined.
*/
void *adsp_dw_seize_slot(uint32_t slot_index, struct adsp_dw_desc *dw_desc,
size_t *slot_size);
/**(
* @brief Release a slot allocated for type
*
* @param type Slot type to be released
*
* @note Only a single slot can be allocated at the same time for a type
*/
void adsp_dw_release_slot(uint32_t type);
#else /* CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER */
/* debug window slots usage, mutually exclusive options can reuse slots */
#define ADSP_DW_SLOT_NUM_SHELL 0
#define ADSP_DW_SLOT_NUM_MTRACE 0
#define ADSP_DW_SLOT_NUM_TRACE 1
#define ADSP_DW_SLOT_NUM_TELEMETRY 1
/* this uses remaining space in the first page after descriptors */
#define ADSP_DW_SLOT_NUM_GDB (ADSP_DW_DESC_COUNT - 1)
struct adsp_debug_window {
struct adsp_dw_desc descs[ADSP_DW_DESC_COUNT];
uint8_t reserved[ADSP_DW_PAGE0_SLOT_OFFSET -
@@ -108,4 +150,6 @@ struct adsp_debug_window {
(sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) \
(WIN2_MBASE + WIN2_OFFSET))))
#endif /* CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER */
#endif

View File

@@ -20,12 +20,27 @@ LOG_MODULE_REGISTER(coredump, CONFIG_DEBUG_COREDUMP_LOG_LEVEL);
static int error;
static uint32_t mem_wptr;
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
static void *coredump_slot_addr;
#endif
static void coredump_mem_window_backend_start(void)
{
/* Reset error & mem write ptr */
error = 0;
mem_wptr = 0;
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
struct adsp_dw_desc slot_desc = { .type = ADSP_DW_SLOT_TELEMETRY, };
/* Forcibly take debug slot 1 */
coredump_slot_addr = adsp_dw_seize_slot(1, &slot_desc, NULL);
if (!coredump_slot_addr) {
/* Try to get the first slot if slot 1 is not available as fallback */
coredump_slot_addr = adsp_dw_seize_slot(0, &slot_desc, NULL);
}
#else
ADSP_DW->descs[1].type = ADSP_DW_SLOT_TELEMETRY;
#endif
while (LOG_PROCESS()) {
;
@@ -46,10 +61,20 @@ static void coredump_mem_window_backend_end(void)
static void coredump_mem_window_backend_buffer_output(uint8_t *buf, size_t buflen)
{
uint32_t *mem_window_separator = (uint32_t *)(ADSP_DW->slots[1]);
uint8_t *mem_window_sink = (uint8_t *)(ADSP_DW->slots[1]) + 4 + mem_wptr;
uint8_t *coredump_data = buf;
size_t data_left;
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
uint32_t *mem_window_separator = (uint32_t *)coredump_slot_addr;
uint8_t *mem_window_sink = (uint8_t *)coredump_slot_addr + 4 + mem_wptr;
if (!coredump_slot_addr) {
return;
}
#else
uint32_t *mem_window_separator = (uint32_t *)(ADSP_DW->slots[1]);
uint8_t *mem_window_sink = (uint8_t *)(ADSP_DW->slots[1]) + 4 + mem_wptr;
#endif
/* Default place for telemetry dump is in memory window. Each data is easily find using
* separator. For telemetry that separator is 0x0DEC0DEB.
*/

View File

@@ -64,19 +64,41 @@ struct adsp_debug_slot {
uint8_t data[ADSP_DW_SLOT_SIZE - sizeof(uint32_t) * 2];
} __packed;
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
static struct adsp_debug_slot *slot;
#endif
static void mtrace_init(void)
{
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
struct adsp_dw_desc slot_desc = { .type = MTRACE_LOGGING_SLOT_TYPE(MTRACE_CORE), };
if (slot) {
return;
}
slot = adsp_dw_request_slot(&slot_desc, NULL);
#else
if (ADSP_DW->descs[ADSP_DW_SLOT_NUM_MTRACE].type == MTRACE_LOGGING_SLOT_TYPE(MTRACE_CORE)) {
return;
}
ADSP_DW->descs[ADSP_DW_SLOT_NUM_MTRACE].type = MTRACE_LOGGING_SLOT_TYPE(MTRACE_CORE);
#endif
}
static size_t mtrace_out(int8_t *str, size_t len, size_t *space_left)
{
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
/* Debug slot is not allocated */
if (!slot) {
return 0;
}
#else
struct adsp_debug_slot *slot = (struct adsp_debug_slot *)
ADSP_DW->slots[ADSP_DW_SLOT_NUM_MTRACE];
#endif
uint8_t *data = slot->data;
uint32_t r = slot->host_ptr;
uint32_t w = slot->dsp_ptr;

View File

@@ -22,6 +22,10 @@ LOG_MODULE_REGISTER(shell_adsp_memory_window);
BUILD_ASSERT(RX_WINDOW_SIZE < ADSP_DW_SLOT_SIZE);
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
static struct adsp_debug_slot_shell *dw_slot;
#endif
struct adsp_debug_slot_shell {
uint8_t rx_window[RX_WINDOW_SIZE];
uint8_t tx_window[ADSP_DW_SLOT_SIZE - RX_WINDOW_SIZE];
@@ -44,6 +48,15 @@ static int init(const struct shell_transport *transport,
{
struct shell_adsp_memory_window *sh_adsp_mw =
(struct shell_adsp_memory_window *)transport->ctx;
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
struct adsp_dw_desc slot_desc = { .type = ADSP_DW_SLOT_SHELL, };
dw_slot = (struct adsp_debug_slot_shell *)adsp_dw_request_slot(&slot_desc, NULL);
if (!dw_slot) {
return -ENOTSUP;
}
#else
struct adsp_debug_slot_shell *dw_slot;
if (ADSP_DW->descs[ADSP_DW_SLOT_NUM_SHELL].type &&
@@ -55,10 +68,12 @@ static int init(const struct shell_transport *transport,
ADSP_DW->descs[ADSP_DW_SLOT_NUM_SHELL].type = ADSP_DW->descs[ADSP_DW_SLOT_NUM_SHELL].type;
dw_slot = (struct adsp_debug_slot_shell *)ADSP_DW->slots[ADSP_DW_SLOT_NUM_SHELL];
#endif
sh_adsp_mw->shell_handler = evt_handler;
sh_adsp_mw->shell_context = context;
dw_slot = (struct adsp_debug_slot_shell *)ADSP_DW->slots[ADSP_DW_SLOT_NUM_SHELL];
sh_adsp_mw->ws_rx = sys_winstream_init(&dw_slot->rx_window[0], sizeof(dw_slot->rx_window));
sh_adsp_mw->ws_tx = sys_winstream_init(&dw_slot->tx_window[0], sizeof(dw_slot->tx_window));
@@ -80,6 +95,11 @@ static int uninit(const struct shell_transport *transport)
k_timer_stop(&sh_adsp_mw->timer);
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
adsp_dw_release_slot(ADSP_DW_SLOT_SHELL);
dw_slot = NULL;
#endif
return 0;
}

View File

@@ -29,6 +29,12 @@ static void tracing_backend_adsp_memory_window_output(
const struct tracing_backend *backend,
uint8_t *data, uint32_t length)
{
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
if (!mem_window) {
return;
}
#endif
/* copy data to ring buffer,
* to make FW part fast, there's no sync with the data reader
* the reader MUST read data before they got overwritten
@@ -48,6 +54,15 @@ static void tracing_backend_adsp_memory_window_output(
static void tracing_backend_adsp_memory_window_init(void)
{
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
struct adsp_dw_desc slot_desc = { .type = ADSP_DW_SLOT_TRACE, };
mem_window = (struct tracing_backend_adsp_memory_window *)adsp_dw_request_slot(&slot_desc,
NULL);
if (mem_window) {
mem_window->head_offset = 0;
}
#else
volatile struct adsp_debug_window *window = ADSP_DW;
window->descs[ADSP_DW_SLOT_NUM_TRACE].type = ADSP_DW_SLOT_TRACE;
@@ -56,6 +71,7 @@ static void tracing_backend_adsp_memory_window_init(void)
ADSP_DW->slots[ADSP_DW_SLOT_NUM_TRACE];
mem_window->head_offset = 0;
#endif
}
const struct tracing_backend_api tracing_backend_adsp_memory_window_api = {