|
| 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); |
0 commit comments