diff --git a/app/boards/intel_adsp_ace15_mtpm.conf b/app/boards/intel_adsp_ace15_mtpm.conf index 4c75272de807..204b8a3e5cb3 100644 --- a/app/boards/intel_adsp_ace15_mtpm.conf +++ b/app/boards/intel_adsp_ace15_mtpm.conf @@ -43,6 +43,7 @@ CONFIG_INTEL_ADSP_TIMER=y CONFIG_MM_DRV_INTEL_ADSP_TLB_REMAP_UNUSED_RAM=y CONFIG_AMS=y CONFIG_COUNTER=y +CONFIG_SOF_TELEMETRY=y CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_L3_HEAP=y @@ -78,6 +79,8 @@ CONFIG_INTEL_ADSP_IPC=y CONFIG_WATCHDOG=y CONFIG_LL_WATCHDOG=y +CONFIG_MEMORY_WIN_2_SIZE=12288 + # Temporary disabled options CONFIG_TRACE=n CONFIG_COMP_KPB=y diff --git a/app/boards/intel_adsp_ace20_lnl.conf b/app/boards/intel_adsp_ace20_lnl.conf index 125e10d65ada..88a8e6522cfe 100644 --- a/app/boards/intel_adsp_ace20_lnl.conf +++ b/app/boards/intel_adsp_ace20_lnl.conf @@ -38,6 +38,7 @@ CONFIG_INTEL_ADSP_TIMER=y CONFIG_MM_DRV_INTEL_ADSP_TLB_REMAP_UNUSED_RAM=y CONFIG_AMS=y CONFIG_COUNTER=y +CONFIG_SOF_TELEMETRY=y CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_L3_HEAP=y @@ -73,6 +74,9 @@ CONFIG_INTEL_ADSP_IPC=y CONFIG_PROBE=y CONFIG_PROBE_DMA_MAX=2 +CONFIG_MEMORY_WIN_2_SIZE=12288 + + # Temporary disabled options CONFIG_TRACE=n CONFIG_COMP_KPB=y diff --git a/src/Kconfig b/src/Kconfig index a98564f16702..d9f66a94bfab 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -21,3 +21,5 @@ rsource "ipc/Kconfig" rsource "math/Kconfig" rsource "library_manager/Kconfig" + +rsource "debug/telemetry/Kconfig" diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index 3940672396bb..85827ab6eadc 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -16,6 +16,18 @@ #if defined(CONFIG_SOC_SERIES_INTEL_ADSP_ACE) #include #endif +#include +#include +#include +#include +/* FIXME: + * Builds for some platforms like tgl fail because their defines related to memory windows are + * already defined somewhere else. Remove this ifdef after it's cleaned up + */ +#ifdef CONFIG_SOF_TELEMETRY +#include "mem_window.h" +#include "adsp_debug_window.h" +#endif #if CONFIG_ACE_V1X_ART_COUNTER || CONFIG_ACE_V1X_RTC_COUNTER #include @@ -455,6 +467,70 @@ static int basefw_set_fw_config(bool first_block, return 0; } +int schedulers_info_get(uint32_t *data_off_size, + char *data, + uint32_t core_id) +{ + /* TODO + * Core id parameter is not yet used. For now we only get scheduler info from current core + * Other cores info can be added by implementing idc request for this data. + * Do this if Schedulers info get ipc has uses for accurate info per core + */ + + struct scheduler_props *scheduler_props; + /* the internal structs have irregular sizes so we cannot use indexing, and have to + * reassign pointers for each element + */ + struct schedulers_info *schedulers_info = (struct schedulers_info *)data; + + schedulers_info->scheduler_count = 0; + + /* smallest response possible is just zero schedulers count + * here we replace max_len from data_off_size to serve as output size + */ + *data_off_size = sizeof(struct schedulers_info); + + /* ===================== LL_TIMER SCHEDULER INFO ============================ */ + schedulers_info->scheduler_count++; + scheduler_props = (struct scheduler_props *)(data + *data_off_size); + scheduler_get_task_info_ll(scheduler_props, data_off_size); + + /* ===================== DP SCHEDULER INFO ============================ */ +#if CONFIG_ZEPHYR_DP_SCHEDULER + schedulers_info->scheduler_count++; + scheduler_props = (struct scheduler_props *)(data + *data_off_size); + scheduler_get_task_info_dp(scheduler_props, data_off_size); +#endif + return 0; +} + +int set_perf_meas_state(const char *data) +{ +#ifdef CONFIG_SOF_TELEMETRY + enum ipc4_perf_measurements_state_set state = *data; + + struct telemetry_wnd_data *wnd_data = + (struct telemetry_wnd_data *)ADSP_DW->slots[SOF_DW_TELEMETRY_SLOT]; + struct system_tick_info *systick_info = + (struct system_tick_info *)wnd_data->system_tick_info; + + switch (state) { + case IPC4_PERF_MEASUREMENTS_DISABLED: + break; + case IPC4_PERF_MEASUREMENTS_STOPPED: + for (int i = 0; i < CONFIG_MAX_CORE_COUNT; i++) + systick_info[i].peak_utilization = 0; + break; + case IPC4_PERF_MEASUREMENTS_STARTED: + case IPC4_PERF_MEASUREMENTS_PAUSED: + break; + default: + return -EINVAL; + } +#endif + return IPC4_SUCCESS; +} + static int basefw_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, @@ -462,9 +538,14 @@ static int basefw_get_large_config(struct comp_dev *dev, uint32_t *data_offset, char *data) { + /* We can use extended param id for both extended and standard param id */ + union ipc4_extended_param_id extended_param_id; + + extended_param_id.full = param_id; + uint32_t ret = -EINVAL; - switch (param_id) { + switch (extended_param_id.part.parameter_type) { case IPC4_PERF_MEASUREMENTS_STATE: case IPC4_GLOBAL_PERF_DATA: break; @@ -473,7 +554,7 @@ static int basefw_get_large_config(struct comp_dev *dev, return -EINVAL; } - switch (param_id) { + switch (extended_param_id.part.parameter_type) { case IPC4_FW_CONFIG: return basefw_config(data_offset, data); case IPC4_HW_CONFIG_GET: @@ -493,13 +574,15 @@ static int basefw_get_large_config(struct comp_dev *dev, break; case IPC4_POWER_STATE_INFO_GET: return basefw_power_state_info_get(data_offset, data); + case IPC4_SCHEDULERS_INFO_GET: + return schedulers_info_get(data_offset, data, + extended_param_id.part.parameter_instance); /* TODO: add more support */ case IPC4_DSP_RESOURCE_STATE: case IPC4_NOTIFICATION_MASK: case IPC4_MODULES_INFO_GET: case IPC4_PIPELINE_LIST_INFO_GET: case IPC4_PIPELINE_PROPS_GET: - case IPC4_SCHEDULERS_INFO_GET: case IPC4_GATEWAYS_INFO_GET: case IPC4_LIBRARIES_INFO_GET: case IPC4_PERF_MEASUREMENTS_STATE: @@ -522,6 +605,8 @@ static int basefw_set_large_config(struct comp_dev *dev, switch (param_id) { case IPC4_FW_CONFIG: return basefw_set_fw_config(first_block, last_block, data_offset, data); + case IPC4_PERF_MEASUREMENTS_STATE: + return set_perf_meas_state(data); case IPC4_SYSTEM_TIME: return basefw_set_system_time(param_id, first_block, last_block, data_offset, data); diff --git a/src/debug/telemetry/CMakeLists.txt b/src/debug/telemetry/CMakeLists.txt new file mode 100644 index 000000000000..f2249490db60 --- /dev/null +++ b/src/debug/telemetry/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_local_sources_ifdef(CONFIG_SOF_TELEMETRY sof telemetry.c) diff --git a/src/debug/telemetry/Kconfig b/src/debug/telemetry/Kconfig new file mode 100644 index 000000000000..54f4b66f590d --- /dev/null +++ b/src/debug/telemetry/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: BSD-3-Clause + +config SOF_TELEMETRY + bool "enable telemetry" + default n + help + Enables telemetry. Enables performance measurements and debug utilities + that use memory window 2 (debug window) as interface. Measurements include + systick_info measurement which measures scheduler task performance and may + slightly affect overall performance. + diff --git a/src/debug/telemetry/telemetry.c b/src/debug/telemetry/telemetry.c new file mode 100644 index 000000000000..ffb0376d3473 --- /dev/null +++ b/src/debug/telemetry/telemetry.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Intel Corporation. All rights reserved. +// +// Author: Tobiasz Dryjanski + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); + +/* Systic variables, one set per core */ +static int telemetry_systick_counter[CONFIG_MAX_CORE_COUNT]; +static int telemetry_prev_ccount[CONFIG_MAX_CORE_COUNT]; +static int telemetry_perf_period_sum[CONFIG_MAX_CORE_COUNT]; +static int telemetry_perf_period_cnt[CONFIG_MAX_CORE_COUNT]; +static struct telemetry_perf_queue telemetry_perf_queue[CONFIG_MAX_CORE_COUNT]; + +static void telemetry_perf_queue_append(struct telemetry_perf_queue *q, size_t element) +{ + if (!q->full) { + q->elements[q->index] = element; + q->sum += element; + q->index++; + q->size++; + if (q->index >= SOF_AVG_PERF_MEAS_DEPTH) { + q->index = 0; + q->size = SOF_AVG_PERF_MEAS_DEPTH; + q->full = true; + } + } else { + /* no space, pop tail */ + q->sum -= q->elements[q->index]; + /* replace tail */ + q->elements[q->index] = element; + q->sum += element; + /* move tail */ + q->index++; + if (q->index >= SOF_AVG_PERF_MEAS_DEPTH) + q->index = 0; + } +} + +static size_t telemetry_perf_queue_avg(struct telemetry_perf_queue *q) +{ + if (!q->size) + return 0; + return q->sum / q->size; +} + +int telemetry_init(void) +{ + /* systick_init */ + uint8_t slot_num = SOF_DW_TELEMETRY_SLOT; + volatile struct adsp_debug_window *window = ADSP_DW; + struct telemetry_wnd_data *wnd_data = (struct telemetry_wnd_data *)ADSP_DW->slots[slot_num]; + struct system_tick_info *systick_info = + (struct system_tick_info *)wnd_data->system_tick_info; + + tr_info(&ipc_tr, "Telemetry enabled. May affect performance"); + + window->descs[slot_num].type = ADSP_DW_SLOT_TELEMETRY; + window->descs[slot_num].resource_id = 0; + wnd_data->separator_1 = 0x0000C0DE; + + /* Zero values per core */ + for (int i = 0; i < CONFIG_MAX_CORE_COUNT; i++) { + systick_info[i].count = 0; + systick_info[i].last_time_elapsed = 0; + systick_info[i].max_time_elapsed = 0; + systick_info[i].last_ccount = 0; + systick_info[i].avg_utilization = 0; + systick_info[i].peak_utilization = 0; + systick_info[i].peak_utilization_4k = 0; + systick_info[i].peak_utilization_8k = 0; + } + return 0; +} + +void telemetry_update(uint32_t begin_stamp, uint32_t current_stamp) +{ + int prid = cpu_get_id(); + + ++telemetry_systick_counter[prid]; + + struct telemetry_wnd_data *wnd_data = + (struct telemetry_wnd_data *)ADSP_DW->slots[SOF_DW_TELEMETRY_SLOT]; + struct system_tick_info *systick_info = + (struct system_tick_info *)wnd_data->system_tick_info; + + systick_info[prid].count = telemetry_systick_counter[prid]; + systick_info[prid].last_time_elapsed = current_stamp - begin_stamp; + systick_info[prid].max_time_elapsed = + MAX(current_stamp - begin_stamp, + systick_info[prid].max_time_elapsed); + systick_info[prid].last_ccount = current_stamp; + +#ifdef SOF_PERFORMANCE_MEASUREMENTS + const size_t measured_systick = begin_stamp - telemetry_prev_ccount[prid]; + + telemetry_prev_ccount[prid] = begin_stamp; + if (telemetry_systick_counter[prid] > 2) { + telemetry_perf_period_sum[prid] += measured_systick; + telemetry_perf_period_cnt[prid] = + (telemetry_perf_period_cnt[prid] + 1) % SOF_AVG_PERF_MEAS_PERIOD; + if (telemetry_perf_period_cnt[prid] == 0) { + /* Append average of last SOF_AVG_PERF_MEAS_PERIOD runs */ + telemetry_perf_queue_append(&telemetry_perf_queue[prid], + telemetry_perf_period_sum[prid] + / SOF_AVG_PERF_MEAS_PERIOD); + telemetry_perf_period_sum[prid] = 0; + /* Calculate average from all buckets */ + systick_info[prid].avg_utilization = + telemetry_perf_queue_avg(&telemetry_perf_queue[prid]); + } + + systick_info[prid].peak_utilization = + MAX(systick_info[prid].peak_utilization, + measured_systick); + systick_info[prid].peak_utilization_4k = + MAX(systick_info[prid].peak_utilization_4k, + measured_systick); + systick_info[prid].peak_utilization_8k = + MAX(systick_info[prid].peak_utilization_8k, + measured_systick); + + /* optimized: counter % 0x1000 */ + if ((telemetry_systick_counter[prid] & 0xfff) == 0) + systick_info[prid].peak_utilization_4k = 0; + /* optimized: counter % 0x2000 */ + if ((telemetry_systick_counter[prid] & 0x1fff) == 0) + systick_info[prid].peak_utilization_8k = 0; + } +#endif +} + +/* init telemetry using Zephyr*/ +SYS_INIT(telemetry_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); + diff --git a/src/include/ipc4/base_fw.h b/src/include/ipc4/base_fw.h index 5aa1f168b675..1d1648d73cd0 100644 --- a/src/include/ipc4/base_fw.h +++ b/src/include/ipc4/base_fw.h @@ -671,4 +671,34 @@ enum ipc4_power_state_type { IPC4_CORE_KCPS = 1, }; +/* Scheduler info get structures */ + +struct task_props { + /* Unique ID of task. */ + uint32_t task_id; + /* Specifies number of items in module_instance_id array. */ + uint32_t module_instance_count; + /* Array of IDs of module instances running inside the task. */ + uint32_t module_instance_id[]; +} __packed __aligned(4); + +struct scheduler_props { + /* Processing domain, one of: + * COMP_PROCESSING_DOMAIN_LL or COMP_PROCESSING_DOMAIN_DP + */ + uint32_t processing_domain; + /* ID of core that scheduler is running on. */ + uint32_t core_id; + /* Specifies number of items in task_info array. */ + uint32_t task_count; + struct task_props task_info[]; +} __packed __aligned(4); + +struct schedulers_info { + /* Specifies number of items in scheduler_info array. */ + uint32_t scheduler_count; + /* Array of scheduler properties. */ + struct scheduler_props scheduler_info[]; +} __packed __aligned(4); + #endif /* __SOF_IPC4_BASE_FW_H__ */ diff --git a/src/include/ipc4/module.h b/src/include/ipc4/module.h index 45a3890d9d46..432d704fb2dd 100644 --- a/src/include/ipc4/module.h +++ b/src/include/ipc4/module.h @@ -55,7 +55,7 @@ enum sof_ipc4_module_type { }; /* - * Structs for Vendor Config Set + * Structs for Vendor Config */ union ipc4_extended_param_id { @@ -66,6 +66,13 @@ union ipc4_extended_param_id { } part; } __attribute__((packed, aligned(4))); +struct ipc4_vendor_error { + /* Index of the failed parameter */ + uint32_t param_idx; + /* Error code */ + uint32_t err_code; +}; + /* * Host Driver sends this message to create a new module instance. */ diff --git a/src/include/sof/debug/telemetry/telemetry.h b/src/include/sof/debug/telemetry/telemetry.h new file mode 100644 index 000000000000..959e379308e4 --- /dev/null +++ b/src/include/sof/debug/telemetry/telemetry.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2024 Intel Corporation. All rights reserved. + */ + +#ifndef __SOF_TELEMETRY_H__ +#define __SOF_TELEMETRY_H__ + +/* Slot in memory window 2 (Debug Window) to be used as telemetry slot */ +#define SOF_DW_TELEMETRY_SLOT 1 +/* Memory of average algorithm of performance queue */ +#define SOF_AVG_PERF_MEAS_DEPTH 64 +/* Number of runs taken to calculate average (algorithm resolution) */ +#define SOF_AVG_PERF_MEAS_PERIOD 16 +/* disables calculating systick_averages */ +#define SOF_PERFORMANCE_MEASUREMENTS + +/* Systick here is not to be confused with neither Zephyr tick nor SOF scheduler tick, + * it's a legacy name for counting execution time + */ +struct system_tick_info { + uint32_t count; + uint32_t last_time_elapsed; + uint32_t max_time_elapsed; + uint32_t last_ccount; + uint32_t avg_utilization; + uint32_t peak_utilization; + uint32_t peak_utilization_4k; + uint32_t peak_utilization_8k; + uint32_t rsvd[2]; +} __packed; + +/* + * This is the structure of telemetry data in memory window. + * If you need to define a field, you should also define the fields before it to + * keep the internal structures aligned with each other. + */ +struct telemetry_wnd_data { + uint32_t separator_1; + struct system_tick_info system_tick_info[CONFIG_MAX_CORE_COUNT]; + /* + * uint32_t separator_2; + * deadlock_info_s deadlock_info[FW_REPORTED_MAX_CORES_COUNT]; + * uint32_t separator_3; + * assert_info_s assert_info; + * uint32_t separator_4; + * xxxruns_info_s xxxruns_info; + * uint32_t separator_5; + * performance_info_s performance_info; + * uint32_t separator_6; + * mem_pools_info_s mem_pools_info; + * uint32_t separator_7; + * timeout_info_s timeout_info; + * uint32_t separator_8; + * ulp_telemetry_s ulp_telemetry; + * uint32_t separator_9; + * transition_info_s evad_transition_info; + * uint32_t separator_10; + * task_info_s task_info[FW_MAX_REPORTED_TASKS]; + * uint32_t separator_11; + * transition_info_s d0i3_info[FW_REPORTED_MAX_CORES_COUNT]; + * uint32_t separator_12; + * interrupt_stats_info_s interrupt_stats; + * uint32_t separator_13; + * loaded_libraries_s loaded_libraries; + * //uint32_t __pad_for_exception_record; + * uint32_t separator_exception; + * CoreExceptionRecord core_exception_record[FW_REPORTED_MAX_CORES_COUNT]; + */ +} __packed; + +/* Reference FW used a normal Queue here. + * Implementing simplified queue just for avg calculation. + * Queue is circular, oldest element replaced by latest + */ +struct telemetry_perf_queue { + size_t elements[SOF_AVG_PERF_MEAS_DEPTH]; + /* next empty element, head if queue is full, else tail */ + size_t index; + uint8_t full; + /* number of items AND index of next empty box */ + size_t size; + size_t sum; +}; + +void telemetry_update(uint32_t begin_ccount, uint32_t current_ccount); + +#endif /*__SOF_TELEMETRY_H__ */ diff --git a/src/include/sof/schedule/dp_schedule.h b/src/include/sof/schedule/dp_schedule.h index 9b7f85c7e798..ba0e8bf063e5 100644 --- a/src/include/sof/schedule/dp_schedule.h +++ b/src/include/sof/schedule/dp_schedule.h @@ -12,6 +12,7 @@ #include #include #include +#include struct processing_module; @@ -76,4 +77,13 @@ int scheduler_dp_task_init(struct task **task, size_t stack_size, uint32_t task_priority); +/** + * \brief Extract information about scheduler's tasks + * + * \param scheduler_props Structure to be filled + * \param data_off_size Pointer to the current size of the scheduler_props, to be updated + */ +void scheduler_get_task_info_dp(struct scheduler_props *scheduler_props, + uint32_t *data_off_size); + #endif /* __SOF_SCHEDULE_DP_SCHEDULE_H__ */ diff --git a/src/include/sof/schedule/ll_schedule.h b/src/include/sof/schedule/ll_schedule.h index 0d2d3d6d13de..241a20daff40 100644 --- a/src/include/sof/schedule/ll_schedule.h +++ b/src/include/sof/schedule/ll_schedule.h @@ -17,6 +17,7 @@ #include #include #include +#include struct ll_schedule_domain; @@ -54,4 +55,13 @@ int zephyr_ll_task_init(struct task *task, #endif +/** + * \brief Extract information about scheduler's tasks + * + * \param scheduler_props Structure to be filled + * \param data_off_size Pointer to the current size of the scheduler_props, to be updated + */ +void scheduler_get_task_info_ll(struct scheduler_props *scheduler_props, + uint32_t *data_off_size); + #endif /* __SOF_SCHEDULE_LL_SCHEDULE_H__ */ diff --git a/src/include/sof/schedule/schedule.h b/src/include/sof/schedule/schedule.h index e503333942ac..ab110997cfcb 100644 --- a/src/include/sof/schedule/schedule.h +++ b/src/include/sof/schedule/schedule.h @@ -17,6 +17,7 @@ #include #include #include +#include /** \addtogroup schedule_api Schedule API * @{ @@ -399,6 +400,15 @@ int schedule_task_init(struct task *task, */ void scheduler_init(int type, const struct scheduler_ops *ops, void *data); +/** + * Extract scheduler's task information from tasks + * @param scheduler_props Structure to be filled + * @param data_off_size Pointer to the current size of the scheduler_props, to be updated + * @param tasks Scheduler's task list + */ +void scheduler_get_task_info(struct scheduler_props *scheduler_props, + uint32_t *data_off_size, struct list_item *tasks); + /** @}*/ #endif /* __SOF_SCHEDULE_SCHEDULE_H__ */ diff --git a/src/include/sof/tlv.h b/src/include/sof/tlv.h index 4008ad3f24a4..24155707dfd4 100644 --- a/src/include/sof/tlv.h +++ b/src/include/sof/tlv.h @@ -25,6 +25,11 @@ struct sof_tlv { char value[]; } __packed __aligned(4); +struct sof_tl { + uint32_t type; + uint32_t max_length; +} __packed __aligned(4); + /** * @brief Allows to step through successive values in a sequence of TLV structures. * diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c index e54b886434bb..60150234615a 100644 --- a/src/ipc/ipc4/handler.c +++ b/src/ipc/ipc4/handler.c @@ -909,6 +909,99 @@ static int ipc4_unbind_module_instance(struct ipc4_message_request *ipc4) return ipc_comp_disconnect(ipc, (ipc_pipe_comp_connect *)&bu); } +static int ipc4_get_vendor_config_module_instance(struct comp_dev *dev, + const struct comp_driver *drv, + bool init_block, + bool final_block, + uint32_t *data_off_size, + char *data_out, + const char *data_in) +{ + const struct sof_tl * const input_tl = (struct sof_tl *)data_in; + int ret; + struct ipc4_vendor_error *error; + + if (init_block && final_block) { + /* we use data_off_size as in/out, + * save value to new variable so it can be used as out size + */ + const int tl_count = *data_off_size / sizeof(struct sof_tl); + size_t produced_data = 0; + + for (int i = 0; i < tl_count; i++) { + /* we go to next output tlv with each iteration */ + uint32_t data_off_size_local; + struct sof_tlv *output_tlv = (struct sof_tlv *)(data_out + produced_data); + + if (produced_data + input_tl[i].max_length > MAILBOX_DSPBOX_SIZE) { + tr_err(&ipc_tr, "error: response payload bigger than DSPBOX size"); + return IPC4_FAILURE; + } + + /* local size is in/out: max msg len goes in, msg len goes out */ + data_off_size_local = input_tl[i].max_length; + ret = drv->ops.get_large_config(dev, input_tl[i].type, + true, + true, + &data_off_size_local, output_tlv->value); + if (ret) { + /* This is how the reference firmware handled error here. Currently + * no memory is allocated for output in case of error, + * so this may be obsolete. + */ + error = (struct ipc4_vendor_error *)data_out; + error->param_idx = input_tl[i].type; + error->err_code = IPC4_FAILURE; + *data_off_size = sizeof(*error); + ipc_cmd_err(&ipc_tr, "error: get_large_config returned %d", ret); + return IPC4_FAILURE; + } + + /* update header */ + output_tlv->type = input_tl[i].type; + output_tlv->length = data_off_size_local; + produced_data += data_off_size_local + sizeof(*output_tlv); + } + *data_off_size = produced_data; + } else { + char *output_buffer; + struct sof_tlv *tl_header; + + if (init_block) { + *data_off_size = input_tl->max_length; + output_buffer = data_out + sizeof(*tl_header); + } else { + output_buffer = data_out; + } + + ret = drv->ops.get_large_config(dev, input_tl->type, + init_block, + final_block, + data_off_size, output_buffer); + + /* on error report which param failed */ + if (ret) { + error = (struct ipc4_vendor_error *)data_out; + error->param_idx = input_tl->type; + error->err_code = IPC4_FAILURE; + *data_off_size = sizeof(*error); + ipc_cmd_err(&ipc_tr, "error: get_large_config returned %d", ret); + return IPC4_FAILURE; + } + + /* for initial block update TL header */ + if (init_block) { + /* we use tlv struct here for clarity, we have length not max_length */ + tl_header = (struct sof_tlv *)data_out; + tl_header->type = input_tl->type; + tl_header->length = *data_off_size; + /* for initial block data_off_size includes also size of TL */ + *data_off_size += sizeof(*tl_header); + } + } + return IPC4_SUCCESS; +} + static int ipc4_get_large_config_module_instance(struct ipc4_message_request *ipc4) { struct ipc4_module_large_config_reply reply; @@ -951,10 +1044,24 @@ static int ipc4_get_large_config_module_instance(struct ipc4_message_request *ip } data_offset = config.extension.r.data_off_size; - ret = drv->ops.get_large_config(dev, config.extension.r.large_param_id, - config.extension.r.init_block, - config.extension.r.final_block, - &data_offset, data); + + /* check for vendor param first */ + if (config.extension.r.large_param_id == VENDOR_CONFIG_PARAM) { + /* For now only vendor_config case uses payload from hostbox */ + dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, + config.extension.r.data_off_size); + ret = ipc4_get_vendor_config_module_instance(dev, drv, + config.extension.r.init_block, + config.extension.r.final_block, + &data_offset, + data, + (const char *)MAILBOX_HOSTBOX_BASE); + } else { + ret = drv->ops.get_large_config(dev, config.extension.r.large_param_id, + config.extension.r.init_block, + config.extension.r.final_block, + &data_offset, data); + } /* set up ipc4 error code for reply data */ if (ret < 0) diff --git a/src/schedule/schedule.c b/src/schedule/schedule.c index aefd13ca9c6a..9955da56394d 100644 --- a/src/schedule/schedule.c +++ b/src/schedule/schedule.c @@ -14,6 +14,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(schedule, CONFIG_SOF_LOG_LEVEL); @@ -75,3 +76,41 @@ void scheduler_init(int type, const struct scheduler_ops *ops, void *data) scheduler_register(sch); } + +/* Locks for the list here should be held by the caller, + * as different schedulers use different locks + */ +void scheduler_get_task_info(struct scheduler_props *scheduler_props, + uint32_t *data_off_size, + struct list_item *tasks) +{ + /* TODO + * - container_of(tlist, struct task, list)->uid->id could possibly be used as task id, + * but currently accessing it crashes, so setting the value to 0 for now + */ + struct task_props *task_props; + struct list_item *tlist; + + scheduler_props->core_id = cpu_get_id(); + scheduler_props->task_count = 0; + *data_off_size += sizeof(*scheduler_props); + + task_props = (struct task_props *)((uint8_t *)scheduler_props + sizeof(*scheduler_props)); + list_for_item(tlist, tasks) { + /* Fill SchedulerProps */ + scheduler_props->task_count++; + + /* Fill TaskProps */ + task_props->task_id = 0; + + /* Left unimplemented */ + task_props->module_instance_count = 0; + + /* TODO: after module instances are implemented, remember to increase + * data_off_size and the offset to next task_props by the amount of + * module instances included + */ + *data_off_size += sizeof(*task_props); + task_props++; + } +} diff --git a/src/schedule/zephyr_dp_schedule.c b/src/schedule/zephyr_dp_schedule.c index 4e95692ed6cb..4460f33a2523 100644 --- a/src/schedule/zephyr_dp_schedule.c +++ b/src/schedule/zephyr_dp_schedule.c @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -530,3 +531,16 @@ int scheduler_dp_task_init(struct task **task, rfree(task_memory); return ret; } + +void scheduler_get_task_info_dp(struct scheduler_props *scheduler_props, uint32_t *data_off_size) +{ + unsigned int lock_key; + + scheduler_props->processing_domain = COMP_PROCESSING_DOMAIN_DP; + struct scheduler_dp_data *dp_sch = + (struct scheduler_dp_data *)scheduler_get_data(SOF_SCHEDULE_DP); + + lock_key = scheduler_dp_lock(); + scheduler_get_task_info(scheduler_props, data_off_size, &dp_sch->tasks); + scheduler_dp_unlock(lock_key); +} diff --git a/src/schedule/zephyr_ll.c b/src/schedule/zephyr_ll.c index 2069bb6585c4..3a9cb41eba57 100644 --- a/src/schedule/zephyr_ll.c +++ b/src/schedule/zephyr_ll.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include LOG_MODULE_REGISTER(ll_schedule, CONFIG_SOF_LOG_LEVEL); @@ -251,6 +253,19 @@ static void zephyr_ll_run(void *data) NOTIFIER_TARGET_CORE_LOCAL, NULL, 0); } +static void schedule_ll_callback(void *data) +{ +#ifdef CONFIG_SOF_TELEMETRY + const uint32_t begin_stamp = (uint32_t)sof_cycle_get_64(); +#endif + zephyr_ll_run(data); +#ifdef CONFIG_SOF_TELEMETRY + const uint32_t current_stamp = (uint32_t)sof_cycle_get_64(); + + telemetry_update(begin_stamp, current_stamp); +#endif +} + /* * Called once for periodic tasks or multiple times for one-shot tasks * TODO: start should be ignored in Zephyr LL scheduler implementation. Tasks @@ -326,7 +341,7 @@ static int zephyr_ll_task_schedule_common(struct zephyr_ll *sch, struct task *ta zephyr_ll_unlock(sch, &flags); - ret = domain_register(sch->ll_domain, task, &zephyr_ll_run, sch); + ret = domain_register(sch->ll_domain, task, &schedule_ll_callback, sch); if (ret < 0) tr_err(&ll_tr, "zephyr_ll_task_schedule: cannot register domain %d", ret); @@ -527,3 +542,16 @@ int zephyr_ll_scheduler_init(struct ll_schedule_domain *domain) return 0; } + +void scheduler_get_task_info_ll(struct scheduler_props *scheduler_props, + uint32_t *data_off_size) +{ + uint32_t flags; + + scheduler_props->processing_domain = COMP_PROCESSING_DOMAIN_LL; + struct zephyr_ll *ll_sch = (struct zephyr_ll *)scheduler_get_data(SOF_SCHEDULE_LL_TIMER); + + zephyr_ll_lock(ll_sch, &flags); + scheduler_get_task_info(scheduler_props, data_off_size, &ll_sch->tasks); + zephyr_ll_unlock(ll_sch, &flags); +} diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 777f812939cc..5b3366292ee6 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -146,6 +146,7 @@ endmacro() add_subdirectory(../src/init/ init_unused_install/) add_subdirectory(../src/ipc/ ipc_unused_install/) +add_subdirectory(../src/debug/telemetry/ telemetry_unused_install/) add_subdirectory(test/)