-
Notifications
You must be signed in to change notification settings - Fork 308
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
debug: debug_stream_slot: Debug slot transportation for debug_stream
Implementation for debug stream transportation over debug window slot. The protocol details are documented in debug_stream_slot.h header. Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
- Loading branch information
Jyri Sarha
committed
Sep 5, 2024
1 parent
cf4ce75
commit 7673c8a
Showing
6 changed files
with
326 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
|
||
add_local_sources_ifdef(CONFIG_SOF_DEBUG_STREAM_SLOT sof debug_stream_slot.c) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
|
||
config SOF_DEBUG_STREAM_SLOT | ||
bool "Enable SOF debug stream debug window slot" | ||
help | ||
Debug stream is an abstract stream of records of debug | ||
information from SOF system that are streamed from SOF DSP | ||
to the host side for decoding and presentation. This option | ||
enables transferring the records from DSP to host over a | ||
debug window slot. | ||
|
||
if SOF_DEBUG_STREAM_SLOT | ||
|
||
config SOF_DEBUG_STREAM_SLOT_NUMBER | ||
int "Debug window slot where to put debug stream slot" | ||
default 3 | ||
range 0 14 | ||
help | ||
Which debug slot to reserve for Debug Stream. Remember to map | ||
the slot with MEMORY_WIN_2_SIZE in soc/intel/intel_adsp/Kconfig, | ||
in Zephyr source tree. The slots are 4k in size and one slot is | ||
used for descriptors, so for slot 3 to be mapped, the WIN_2_SIZE | ||
must be (1 + 3) * 4k = 16k or greater. | ||
|
||
endif | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
// | ||
// Copyright(c) 2024 Intel Corporation. | ||
|
||
#include <zephyr/logging/log.h> | ||
#include <zephyr/spinlock.h> | ||
#include <adsp_debug_window.h> | ||
#include <adsp_memory.h> | ||
#include <sof/common.h> | ||
#include <rtos/string.h> | ||
#include <user/debug_stream.h> | ||
#include <user/debug_stream_slot.h> | ||
|
||
LOG_MODULE_REGISTER(debug_strem_slot); | ||
|
||
struct cpu_mutex { | ||
struct k_mutex m; | ||
} __aligned(CONFIG_DCACHE_LINE_SIZE); | ||
|
||
/* CPU specific mutexes for each circular buffer */ | ||
static struct cpu_mutex cpu_mutex[CONFIG_MP_MAX_NUM_CPUS]; | ||
|
||
static const int debug_stream_slot = CONFIG_SOF_DEBUG_STREAM_SLOT_NUMBER; | ||
|
||
static struct debug_stream_slot_hdr *debug_stream_get_slot(void) | ||
{ | ||
return (struct debug_stream_slot_hdr *)ADSP_DW->slots[debug_stream_slot]; | ||
} | ||
|
||
static | ||
struct debug_stream_circular_buf * | ||
debug_stream_get_circular_buffer(struct debug_stream_section_descriptor *desc, unsigned int core) | ||
{ | ||
struct debug_stream_slot_hdr *hdr = debug_stream_get_slot(); | ||
void *ptr; | ||
|
||
if (hdr->hdr.magic != DEBUG_STREAM_IDENTIFIER) { | ||
LOG_ERR("Debug stream slot not initialized."); | ||
return NULL; | ||
} | ||
|
||
*desc = hdr->section_desc[core]; | ||
LOG_DBG("Section %u (desc %u %u %u)", core, desc->core_id, desc->buf_words, desc->offset); | ||
|
||
return (struct debug_stream_circular_buf *) (((uint8_t *)hdr) + desc->offset); | ||
} | ||
|
||
int debug_stream_slot_send_record(struct debug_stream_record *rec) | ||
{ | ||
struct debug_stream_section_descriptor desc; | ||
struct debug_stream_circular_buf *buf = | ||
debug_stream_get_circular_buffer(&desc, arch_proc_id()); | ||
uint32_t record_size = rec->size_words; | ||
uint32_t record_start, buf_remain; | ||
|
||
LOG_DBG("Sending record %u id %u len %u\n", rec->seqno, rec->id, rec->size_words); | ||
|
||
if (!buf) | ||
return -ENODEV; | ||
|
||
if (rec->size_words >= desc.buf_words) { | ||
LOG_ERR("Record too big %u >= %u (desc %u %u %u)", rec->size_words, | ||
desc.buf_words, desc.core_id, desc.buf_words, desc.offset); | ||
return -ENOMEM; | ||
} | ||
k_mutex_lock(&cpu_mutex[arch_proc_id()].m, K_FOREVER); | ||
|
||
rec->seqno = buf->next_seqno++; | ||
rec->size_words = record_size + 1; /* +1 for size at the end of record */ | ||
record_start = buf->w_ptr; | ||
buf->w_ptr = (record_start + record_size) % desc.buf_words; | ||
buf_remain = desc.buf_words - record_start; | ||
if (buf_remain < record_size) { | ||
uint32_t rec_remain = record_size - buf_remain; | ||
int ret; | ||
|
||
ret = memcpy_s(&buf->data[record_start], buf_remain * sizeof(uint32_t), | ||
rec, buf_remain * sizeof(uint32_t)); | ||
assert(!ret); | ||
ret = memcpy_s(&buf->data[0], desc.buf_words * sizeof(uint32_t), | ||
((uint32_t *) rec) + buf_remain, rec_remain * sizeof(uint32_t)); | ||
assert(!ret); | ||
} else { | ||
int ret; | ||
|
||
ret = memcpy_s(&buf->data[record_start], buf_remain * sizeof(uint32_t), | ||
rec, record_size * sizeof(uint32_t)); | ||
assert(!ret); | ||
} | ||
/* Write record size again after the record */ | ||
buf->data[buf->w_ptr] = record_size + 1; | ||
buf->w_ptr = (buf->w_ptr + 1) % desc.buf_words; | ||
|
||
k_mutex_unlock(&cpu_mutex[arch_proc_id()].m); | ||
|
||
LOG_DBG("Record %u id %u len %u sent\n", rec->seqno, rec->id, record_size); | ||
return 0; | ||
} | ||
|
||
static int debug_stream_slot_init(void) | ||
{ | ||
struct debug_stream_slot_hdr *hdr = debug_stream_get_slot(); | ||
size_t hdr_size = offsetof(struct debug_stream_slot_hdr, | ||
section_desc[CONFIG_MP_MAX_NUM_CPUS]); | ||
size_t section_area_size = ADSP_DW_SLOT_SIZE - hdr_size; | ||
size_t section_size = ALIGN_DOWN(section_area_size / | ||
CONFIG_MP_MAX_NUM_CPUS, | ||
CONFIG_DCACHE_LINE_SIZE); | ||
size_t offset = hdr_size; | ||
int i; | ||
|
||
LOG_INF("%u sections of %u bytes, hdr %u, secton area %u\n", | ||
CONFIG_MP_MAX_NUM_CPUS, section_size, hdr_size, | ||
section_area_size); | ||
|
||
if (ADSP_DW->descs[debug_stream_slot].type != 0) | ||
LOG_WRN("Slot %d was not free: %u", debug_stream_slot, | ||
ADSP_DW->descs[debug_stream_slot].type); | ||
ADSP_DW->descs[debug_stream_slot].type = ADSP_DW_SLOT_DEBUG_STREAM; | ||
|
||
hdr->hdr.magic = DEBUG_STREAM_IDENTIFIER; | ||
hdr->hdr.hdr_size = hdr_size; | ||
hdr->total_size = hdr_size + CONFIG_MP_MAX_NUM_CPUS * section_size; | ||
hdr->num_sections = CONFIG_MP_MAX_NUM_CPUS; | ||
for (i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) { | ||
hdr->section_desc[i].core_id = i; | ||
hdr->section_desc[i].buf_words = | ||
(section_size - offsetof(struct debug_stream_circular_buf, data[0]))/ | ||
sizeof(uint32_t); | ||
hdr->section_desc[i].offset = offset; | ||
LOG_INF("sections %u, size %u, offset %u\n", | ||
i, section_size, offset); | ||
offset += section_size; | ||
} | ||
for (i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) { | ||
struct debug_stream_section_descriptor desc; | ||
struct debug_stream_circular_buf *buf = | ||
debug_stream_get_circular_buffer(&desc, i); | ||
|
||
buf->next_seqno = 0; | ||
buf->w_ptr = 0; | ||
k_mutex_init(&cpu_mutex[i].m); | ||
/* The core specific mutexes are now .dss which is uncached so the | ||
* following line is commented out. However, since the mutexes are | ||
* core specific there should be nothing preventing from having them | ||
* in cached memory. | ||
* | ||
* sys_cache_data_flush_range(&cpu_mutex[i], sizeof(cpu_mutex[i])); | ||
*/ | ||
} | ||
LOG_INF("Debug stream slot initialized\n"); | ||
|
||
return 0; | ||
} | ||
|
||
SYS_INIT(debug_stream_slot_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
/* SPDX-License-Identifier: BSD-3-Clause | ||
* | ||
* Copyright(c) 2024 Intel Corporation. | ||
*/ | ||
|
||
#ifndef __SOC_DEBUG_WINDOW_SLOT_H__ | ||
#define __SOC_DEBUG_WINDOW_SLOT_H__ | ||
|
||
#include <user/debug_stream.h> | ||
|
||
/* | ||
* This file describes how Debug Stream can be transported over debug | ||
* window memory slot. The debug stream is an abstract media API for | ||
* passing debug data records from SOF DSP to the host system for | ||
* presentation. The debug stream records are described in debug_stream.h. | ||
* | ||
* This example describes how Debug Stream data is transferred from | ||
* DSP to host side using a debug memory window slot. To learn more | ||
* see soc/intel/intel_adsp/common/include/adsp_debug_window.h | ||
* under Zephyr source tree. | ||
* | ||
* DEBUG_STREAM slot is reserved from SRAM window and a header is | ||
* written in the beginning of the slot. The header is a static data | ||
* structure that is initialized once at DSP boot time. All elements | ||
* in bellow example are 32-bit unsigned integers: | ||
* | ||
* -------------------------------------------------- --- | ||
* | id = DEBUG_STREAM_IDENTIFIER | | | ||
* | total_size = 4096 | 64 bytes | ||
* | num_sections = CONFIG_MP_MAX_NUM_CPUS * | | | ||
* | <padding> | | | ||
* -------------------------------------------------- --- | ||
* | section_descriptor [] = { | | | ||
* | { | | | ||
* | core_id = 0 | | | ||
* | size = 1344 | 64 bytes | ||
* | offset = 64 | | | ||
* | } | | | ||
* | <padding> | | | ||
* -------------------------------------------------- --- | ||
* | { | | | ||
* | core_id = 1 | | | ||
* | size = 1344 | 64 bytes | ||
* | offset = 1344+64 | | | ||
* | } | | | ||
* | <padding> | | | ||
* -------------------------------------------------- --- | ||
* | { | | | ||
* | core_id = 2 | | | ||
* | size = 1344 | 64 bytes | ||
* | offset = 2*1344+64 | | | ||
* | } | | | ||
* | } | | | ||
* | <padding> | | | ||
* -------------------------------------------------- --- | ||
* * CONFIG_MP_MAX_NUM_CPUS is 3 in this example | ||
* | ||
* The header contains generic information like identifier, total | ||
* size, and number of sections. After the generic fields there is an | ||
* array of section descriptors. Each array element is cacheline | ||
* aligned. The array has 'num_sections' number of elements. Each | ||
* element in the array describes a circular buffer, one for each DSP | ||
* core. | ||
* | ||
* The remaining memory in the debug window slot is divided between | ||
* those sections. The buffers are not necessarily of equal size, like | ||
* in this example. The circular buffers are all cache line aligned, | ||
* 64 in this example. One section looks like this: | ||
* | ||
* -------------------------------------------------- --- | ||
* | next_seqno = <counter for written objects> | | | ||
* | w_ptr = <write position in 32-bit words> | 1344 bytes | ||
* | buffer_data[1344/4-2] = { | | | ||
* | <debug data records> | | | ||
* | } | | | ||
* -------------------------------------------------- --- | ||
* | ||
* The data records are described in debug_strem.h. In the case of | ||
* debug window memory slot the next record should always be aligned | ||
* to word (4-byte) boundary. | ||
* | ||
* The debug stream writes the records of abstract data to the | ||
* circular buffer, and updates the w_ptr when the record is | ||
* completely written. The host side receiver tries to keep up with the | ||
* w_ptr and keeps track of its read position. The size of the record | ||
* is written - again - after each record and before the next. This is | ||
* to allow parsing the stream backwards in an overrun recovery | ||
* situation. The w_ptr value is updated last, when the record is | ||
* completely written. | ||
*/ | ||
|
||
#include <stdint.h> | ||
|
||
/* Core specific section descriptor | ||
* | ||
* Section descriptor defines core ID, offset and size of the circular | ||
* buffer in the debug window slot. | ||
*/ | ||
struct debug_stream_section_descriptor { | ||
uint32_t core_id; /* Core ID */ | ||
uint32_t buf_words; /* Circular buffer size in 32-bit words */ | ||
uint32_t offset; /* Core section offset */ | ||
} __packed; | ||
|
||
/* Debug window slot header for Debug Stream. | ||
* | ||
* The header should be written in the beginning of the slot. | ||
*/ | ||
struct debug_stream_slot_hdr { | ||
struct debug_stream_hdr hdr; | ||
uint32_t total_size; /* total size of payload including all sections */ | ||
uint32_t num_sections; /* number of core specific sections */ | ||
struct debug_stream_section_descriptor section_desc[]; | ||
} __packed; | ||
|
||
struct debug_stream_circular_buf { | ||
uint32_t next_seqno; | ||
uint32_t w_ptr; | ||
uint32_t data[]; | ||
} __aligned(CONFIG_DCACHE_LINE_SIZE); | ||
|
||
struct debug_stream_record; | ||
/** | ||
* \brief Send debug stream records over debug window slot | ||
* | ||
* \param[in] rec the record to be written to circular buffer | ||
* | ||
* The debug window slot is initialized automatically at DSP boot | ||
* time, and the core specific circular buffer is selected | ||
* automatically. | ||
* | ||
* \return 0 on success | ||
* -ENODEV if debug stream slot is not configured | ||
* -ENOMEM if the record is too big | ||
*/ | ||
int debug_stream_slot_send_record(struct debug_stream_record *rec); | ||
|
||
#endif /* __SOC_DEBUG_WINDOW_SLOT_H__ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters