Skip to content

Commit 7673c8a

Browse files
author
Jyri Sarha
committed
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>
1 parent cf4ce75 commit 7673c8a

6 files changed

Lines changed: 326 additions & 0 deletions

File tree

‎src/Kconfig‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ rsource "math/Kconfig"
2323
rsource "library_manager/Kconfig"
2424

2525
rsource "debug/telemetry/Kconfig"
26+
27+
rsource "debug/debug_stream/Kconfig"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
3+
add_local_sources_ifdef(CONFIG_SOF_DEBUG_STREAM_SLOT sof debug_stream_slot.c)

‎src/debug/debug_stream/Kconfig‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
3+
config SOF_DEBUG_STREAM_SLOT
4+
bool "Enable SOF debug stream debug window slot"
5+
help
6+
Debug stream is an abstract stream of records of debug
7+
information from SOF system that are streamed from SOF DSP
8+
to the host side for decoding and presentation. This option
9+
enables transferring the records from DSP to host over a
10+
debug window slot.
11+
12+
if SOF_DEBUG_STREAM_SLOT
13+
14+
config SOF_DEBUG_STREAM_SLOT_NUMBER
15+
int "Debug window slot where to put debug stream slot"
16+
default 3
17+
range 0 14
18+
help
19+
Which debug slot to reserve for Debug Stream. Remember to map
20+
the slot with MEMORY_WIN_2_SIZE in soc/intel/intel_adsp/Kconfig,
21+
in Zephyr source tree. The slots are 4k in size and one slot is
22+
used for descriptors, so for slot 3 to be mapped, the WIN_2_SIZE
23+
must be (1 + 3) * 4k = 16k or greater.
24+
25+
endif
26+
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
//
3+
// Copyright(c) 2024 Intel Corporation.
4+
5+
#include <zephyr/logging/log.h>
6+
#include <zephyr/spinlock.h>
7+
#include <adsp_debug_window.h>
8+
#include <adsp_memory.h>
9+
#include <sof/common.h>
10+
#include <rtos/string.h>
11+
#include <user/debug_stream.h>
12+
#include <user/debug_stream_slot.h>
13+
14+
LOG_MODULE_REGISTER(debug_strem_slot);
15+
16+
struct cpu_mutex {
17+
struct k_mutex m;
18+
} __aligned(CONFIG_DCACHE_LINE_SIZE);
19+
20+
/* CPU specific mutexes for each circular buffer */
21+
static struct cpu_mutex cpu_mutex[CONFIG_MP_MAX_NUM_CPUS];
22+
23+
static const int debug_stream_slot = CONFIG_SOF_DEBUG_STREAM_SLOT_NUMBER;
24+
25+
static struct debug_stream_slot_hdr *debug_stream_get_slot(void)
26+
{
27+
return (struct debug_stream_slot_hdr *)ADSP_DW->slots[debug_stream_slot];
28+
}
29+
30+
static
31+
struct debug_stream_circular_buf *
32+
debug_stream_get_circular_buffer(struct debug_stream_section_descriptor *desc, unsigned int core)
33+
{
34+
struct debug_stream_slot_hdr *hdr = debug_stream_get_slot();
35+
void *ptr;
36+
37+
if (hdr->hdr.magic != DEBUG_STREAM_IDENTIFIER) {
38+
LOG_ERR("Debug stream slot not initialized.");
39+
return NULL;
40+
}
41+
42+
*desc = hdr->section_desc[core];
43+
LOG_DBG("Section %u (desc %u %u %u)", core, desc->core_id, desc->buf_words, desc->offset);
44+
45+
return (struct debug_stream_circular_buf *) (((uint8_t *)hdr) + desc->offset);
46+
}
47+
48+
int debug_stream_slot_send_record(struct debug_stream_record *rec)
49+
{
50+
struct debug_stream_section_descriptor desc;
51+
struct debug_stream_circular_buf *buf =
52+
debug_stream_get_circular_buffer(&desc, arch_proc_id());
53+
uint32_t record_size = rec->size_words;
54+
uint32_t record_start, buf_remain;
55+
56+
LOG_DBG("Sending record %u id %u len %u\n", rec->seqno, rec->id, rec->size_words);
57+
58+
if (!buf)
59+
return -ENODEV;
60+
61+
if (rec->size_words >= desc.buf_words) {
62+
LOG_ERR("Record too big %u >= %u (desc %u %u %u)", rec->size_words,
63+
desc.buf_words, desc.core_id, desc.buf_words, desc.offset);
64+
return -ENOMEM;
65+
}
66+
k_mutex_lock(&cpu_mutex[arch_proc_id()].m, K_FOREVER);
67+
68+
rec->seqno = buf->next_seqno++;
69+
rec->size_words = record_size + 1; /* +1 for size at the end of record */
70+
record_start = buf->w_ptr;
71+
buf->w_ptr = (record_start + record_size) % desc.buf_words;
72+
buf_remain = desc.buf_words - record_start;
73+
if (buf_remain < record_size) {
74+
uint32_t rec_remain = record_size - buf_remain;
75+
int ret;
76+
77+
ret = memcpy_s(&buf->data[record_start], buf_remain * sizeof(uint32_t),
78+
rec, buf_remain * sizeof(uint32_t));
79+
assert(!ret);
80+
ret = memcpy_s(&buf->data[0], desc.buf_words * sizeof(uint32_t),
81+
((uint32_t *) rec) + buf_remain, rec_remain * sizeof(uint32_t));
82+
assert(!ret);
83+
} else {
84+
int ret;
85+
86+
ret = memcpy_s(&buf->data[record_start], buf_remain * sizeof(uint32_t),
87+
rec, record_size * sizeof(uint32_t));
88+
assert(!ret);
89+
}
90+
/* Write record size again after the record */
91+
buf->data[buf->w_ptr] = record_size + 1;
92+
buf->w_ptr = (buf->w_ptr + 1) % desc.buf_words;
93+
94+
k_mutex_unlock(&cpu_mutex[arch_proc_id()].m);
95+
96+
LOG_DBG("Record %u id %u len %u sent\n", rec->seqno, rec->id, record_size);
97+
return 0;
98+
}
99+
100+
static int debug_stream_slot_init(void)
101+
{
102+
struct debug_stream_slot_hdr *hdr = debug_stream_get_slot();
103+
size_t hdr_size = offsetof(struct debug_stream_slot_hdr,
104+
section_desc[CONFIG_MP_MAX_NUM_CPUS]);
105+
size_t section_area_size = ADSP_DW_SLOT_SIZE - hdr_size;
106+
size_t section_size = ALIGN_DOWN(section_area_size /
107+
CONFIG_MP_MAX_NUM_CPUS,
108+
CONFIG_DCACHE_LINE_SIZE);
109+
size_t offset = hdr_size;
110+
int i;
111+
112+
LOG_INF("%u sections of %u bytes, hdr %u, secton area %u\n",
113+
CONFIG_MP_MAX_NUM_CPUS, section_size, hdr_size,
114+
section_area_size);
115+
116+
if (ADSP_DW->descs[debug_stream_slot].type != 0)
117+
LOG_WRN("Slot %d was not free: %u", debug_stream_slot,
118+
ADSP_DW->descs[debug_stream_slot].type);
119+
ADSP_DW->descs[debug_stream_slot].type = ADSP_DW_SLOT_DEBUG_STREAM;
120+
121+
hdr->hdr.magic = DEBUG_STREAM_IDENTIFIER;
122+
hdr->hdr.hdr_size = hdr_size;
123+
hdr->total_size = hdr_size + CONFIG_MP_MAX_NUM_CPUS * section_size;
124+
hdr->num_sections = CONFIG_MP_MAX_NUM_CPUS;
125+
for (i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) {
126+
hdr->section_desc[i].core_id = i;
127+
hdr->section_desc[i].buf_words =
128+
(section_size - offsetof(struct debug_stream_circular_buf, data[0]))/
129+
sizeof(uint32_t);
130+
hdr->section_desc[i].offset = offset;
131+
LOG_INF("sections %u, size %u, offset %u\n",
132+
i, section_size, offset);
133+
offset += section_size;
134+
}
135+
for (i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) {
136+
struct debug_stream_section_descriptor desc;
137+
struct debug_stream_circular_buf *buf =
138+
debug_stream_get_circular_buffer(&desc, i);
139+
140+
buf->next_seqno = 0;
141+
buf->w_ptr = 0;
142+
k_mutex_init(&cpu_mutex[i].m);
143+
/* The core specific mutexes are now .dss which is uncached so the
144+
* following line is commented out. However, since the mutexes are
145+
* core specific there should be nothing preventing from having them
146+
* in cached memory.
147+
*
148+
* sys_cache_data_flush_range(&cpu_mutex[i], sizeof(cpu_mutex[i]));
149+
*/
150+
}
151+
LOG_INF("Debug stream slot initialized\n");
152+
153+
return 0;
154+
}
155+
156+
SYS_INIT(debug_stream_slot_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/* SPDX-License-Identifier: BSD-3-Clause
2+
*
3+
* Copyright(c) 2024 Intel Corporation.
4+
*/
5+
6+
#ifndef __SOC_DEBUG_WINDOW_SLOT_H__
7+
#define __SOC_DEBUG_WINDOW_SLOT_H__
8+
9+
#include <user/debug_stream.h>
10+
11+
/*
12+
* This file describes how Debug Stream can be transported over debug
13+
* window memory slot. The debug stream is an abstract media API for
14+
* passing debug data records from SOF DSP to the host system for
15+
* presentation. The debug stream records are described in debug_stream.h.
16+
*
17+
* This example describes how Debug Stream data is transferred from
18+
* DSP to host side using a debug memory window slot. To learn more
19+
* see soc/intel/intel_adsp/common/include/adsp_debug_window.h
20+
* under Zephyr source tree.
21+
*
22+
* DEBUG_STREAM slot is reserved from SRAM window and a header is
23+
* written in the beginning of the slot. The header is a static data
24+
* structure that is initialized once at DSP boot time. All elements
25+
* in bellow example are 32-bit unsigned integers:
26+
*
27+
* -------------------------------------------------- ---
28+
* | id = DEBUG_STREAM_IDENTIFIER | |
29+
* | total_size = 4096 | 64 bytes
30+
* | num_sections = CONFIG_MP_MAX_NUM_CPUS * | |
31+
* | <padding> | |
32+
* -------------------------------------------------- ---
33+
* | section_descriptor [] = { | |
34+
* | { | |
35+
* | core_id = 0 | |
36+
* | size = 1344 | 64 bytes
37+
* | offset = 64 | |
38+
* | } | |
39+
* | <padding> | |
40+
* -------------------------------------------------- ---
41+
* | { | |
42+
* | core_id = 1 | |
43+
* | size = 1344 | 64 bytes
44+
* | offset = 1344+64 | |
45+
* | } | |
46+
* | <padding> | |
47+
* -------------------------------------------------- ---
48+
* | { | |
49+
* | core_id = 2 | |
50+
* | size = 1344 | 64 bytes
51+
* | offset = 2*1344+64 | |
52+
* | } | |
53+
* | } | |
54+
* | <padding> | |
55+
* -------------------------------------------------- ---
56+
* * CONFIG_MP_MAX_NUM_CPUS is 3 in this example
57+
*
58+
* The header contains generic information like identifier, total
59+
* size, and number of sections. After the generic fields there is an
60+
* array of section descriptors. Each array element is cacheline
61+
* aligned. The array has 'num_sections' number of elements. Each
62+
* element in the array describes a circular buffer, one for each DSP
63+
* core.
64+
*
65+
* The remaining memory in the debug window slot is divided between
66+
* those sections. The buffers are not necessarily of equal size, like
67+
* in this example. The circular buffers are all cache line aligned,
68+
* 64 in this example. One section looks like this:
69+
*
70+
* -------------------------------------------------- ---
71+
* | next_seqno = <counter for written objects> | |
72+
* | w_ptr = <write position in 32-bit words> | 1344 bytes
73+
* | buffer_data[1344/4-2] = { | |
74+
* | <debug data records> | |
75+
* | } | |
76+
* -------------------------------------------------- ---
77+
*
78+
* The data records are described in debug_strem.h. In the case of
79+
* debug window memory slot the next record should always be aligned
80+
* to word (4-byte) boundary.
81+
*
82+
* The debug stream writes the records of abstract data to the
83+
* circular buffer, and updates the w_ptr when the record is
84+
* completely written. The host side receiver tries to keep up with the
85+
* w_ptr and keeps track of its read position. The size of the record
86+
* is written - again - after each record and before the next. This is
87+
* to allow parsing the stream backwards in an overrun recovery
88+
* situation. The w_ptr value is updated last, when the record is
89+
* completely written.
90+
*/
91+
92+
#include <stdint.h>
93+
94+
/* Core specific section descriptor
95+
*
96+
* Section descriptor defines core ID, offset and size of the circular
97+
* buffer in the debug window slot.
98+
*/
99+
struct debug_stream_section_descriptor {
100+
uint32_t core_id; /* Core ID */
101+
uint32_t buf_words; /* Circular buffer size in 32-bit words */
102+
uint32_t offset; /* Core section offset */
103+
} __packed;
104+
105+
/* Debug window slot header for Debug Stream.
106+
*
107+
* The header should be written in the beginning of the slot.
108+
*/
109+
struct debug_stream_slot_hdr {
110+
struct debug_stream_hdr hdr;
111+
uint32_t total_size; /* total size of payload including all sections */
112+
uint32_t num_sections; /* number of core specific sections */
113+
struct debug_stream_section_descriptor section_desc[];
114+
} __packed;
115+
116+
struct debug_stream_circular_buf {
117+
uint32_t next_seqno;
118+
uint32_t w_ptr;
119+
uint32_t data[];
120+
} __aligned(CONFIG_DCACHE_LINE_SIZE);
121+
122+
struct debug_stream_record;
123+
/**
124+
* \brief Send debug stream records over debug window slot
125+
*
126+
* \param[in] rec the record to be written to circular buffer
127+
*
128+
* The debug window slot is initialized automatically at DSP boot
129+
* time, and the core specific circular buffer is selected
130+
* automatically.
131+
*
132+
* \return 0 on success
133+
* -ENODEV if debug stream slot is not configured
134+
* -ENOMEM if the record is too big
135+
*/
136+
int debug_stream_slot_send_record(struct debug_stream_record *rec);
137+
138+
#endif /* __SOC_DEBUG_WINDOW_SLOT_H__ */

‎zephyr/CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ endmacro()
188188
add_subdirectory(../src/init/ init_unused_install/)
189189
add_subdirectory(../src/ipc/ ipc_unused_install/)
190190
add_subdirectory(../src/debug/telemetry/ telemetry_unused_install/)
191+
add_subdirectory(../src/debug/debug_stream/ debug_stream_unused_install/)
191192
add_subdirectory(test/)
192193

193194

0 commit comments

Comments
 (0)