diff --git a/doc/groups.dox b/doc/groups.dox index 4f30724492f7..0a19d0abdbf8 100644 --- a/doc/groups.dox +++ b/doc/groups.dox @@ -21,23 +21,43 @@ */ /** - * @defgroup module_api Loadable Module & LLEXT Interface - * @brief Dynamic module loading, processing component lifecycle, and buffer streaming endpoints. + * @defgroup module_api Audio Processing Components & Module Interface + * @brief Unified interface contracts, lifecycle callbacks, and streaming endpoints for built-in audio components and dynamic LLEXT processing modules (Volume, Mixer, EQ, DRC, SRC, etc.). */ /** - * @defgroup audio_pipeline_api Pipeline & Buffer Infrastructure - * @brief Audio pipeline execution graphs, stream buffer management, scheduling, and processing threads. + * @defgroup audio_pipeline_api Pipeline Graph & Lifecycle Infrastructure + * @brief Directed Acyclic Graph (DAG) pipeline creation, scheduling binding, traversal, and lifecycle management. */ /** - * @defgroup audio_components_api Audio Processing Components - * @brief Built-in and dynamic audio processing modules (Volume, Mixer, EQ, DRC, SRC, ASRC, etc.). + * @defgroup component_infra_api Audio Component Infrastructure & Driver Model + * @brief Component driver interface, operations vtable, hardware abstraction, IPC binding, and state machines. + */ + +/** + * @defgroup audio_buffer_api Audio Buffer & Stream Infrastructure + * @brief Interconnect buffers, circular stream buffers, abstract audio buffers, and lockless ring buffers. + */ + +/** + * @defgroup audio_format_api Audio Formats & Channel Routing + * @brief Channel map parsing, stream conversion, and audio sample saturation routines. + */ + +/** + * @defgroup scheduling_api Scheduling Infrastructure + * @brief Real-time task schedulers (Low-Latency Timer/DMA, Data Processing preemptible threads, Thread With Budget), scheduling domains, and task state machines. + */ + +/** + * @defgroup memory_api Memory Management Infrastructure + * @brief System heaps, Virtual Memory Heap (VMH), virtual regions, cold DRAM staging, and audio buffer allocators. */ /** * @defgroup rtos_api RTOS Abstraction Layer - * @brief RTOS primitives, synchronization (spinlocks, mutexes), memory allocation, clocks, and cache management. + * @brief RTOS primitives, synchronization (spinlocks, mutexes), task scheduling, clocks, timers, and cache management. */ /** diff --git a/doc/mainpage.dox b/doc/mainpage.dox index 2b0c574c0411..e3cec54263aa 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -70,54 +70,113 @@ * Legacy IPC3 protocol structures, stream control envelopes, DAI/buffer tokens, and mixer controls. * * + * - * Loadable Modules & LLEXT - * @ref module_api + * Pipeline Graph & Lifecycle + * @ref audio_pipeline_api * - * - @ref src/include/module/module/interface.h "module/interface.h"
- * - @ref src/include/module/module/api_ver.h "module/api_ver.h"
- * - @ref src/include/module/module/base.h "module/base.h" + * - @ref src/include/sof/audio/pipeline.h "sof/audio/pipeline.h" * * - * Dynamic ELF module loading infrastructure via Zephyr LLEXT: dynamic symbol linking, module - * interface adapters, processing state machine, parameter configuration, and multi-core routing. + * Audio pipeline Directed Acyclic Graph (DAG) construction, scheduling task binding (LL/DP), + * pipeline hierarchy traversal, and graph-wide state transitions. * * * - * Audio Pipeline & Buffers - * @ref audio_pipeline_api + * Component Infrastructure + * @ref component_infra_api * - * - @ref src/include/sof/audio/pipeline.h "sof/audio/pipeline.h"
* - @ref src/include/sof/audio/component.h "sof/audio/component.h"
+ * - @ref src/include/sof/audio/component_ext.h "sof/audio/component_ext.h" + * + * + * Unified audio component driver model (comp_ops), trigger state machines, IPC module bindings, + * copy limits, and remote multi-core IDC communication. + * + * + * + * Audio Buffers & Streams + * @ref audio_buffer_api + * * - @ref src/include/sof/audio/buffer.h "sof/audio/buffer.h"
* - @ref src/include/sof/audio/audio_buffer.h "sof/audio/audio_buffer.h"
- * - @ref src/include/sof/schedule/schedule.h "sof/schedule/schedule.h" + * - @ref src/include/sof/audio/ring_buffer.h "sof/audio/ring_buffer.h"
+ * - @ref src/include/module/audio/audio_stream.h "module/audio/audio_stream.h"
+ * - @ref src/include/sof/audio/audio_stream.h "sof/audio/audio_stream.h" * * - * Audio pipeline Directed Acyclic Graph (DAG) construction, task scheduling domains (LL-Timer, - * LL-DMA, DP threads), lockless ring buffers, audio format negotiation, and multi-channel interleaved/planar routing. + * Interconnect buffers (comp_buffer), abstract audio buffers (sof_audio_buffer), circular + * stream endpoints, lockless ring buffers, and buffer transaction callbacks. * * * - * Audio Processing Components - * @ref audio_components_api + * Audio Formats & Routing + * @ref audio_format_api * - * - @ref src/include/sof/audio/component.h "sof/audio/component.h"
- * - @ref src/include/sof/audio/component_ext.h "sof/audio/component_ext.h"
- * - @ref src/include/sof/audio/smart_amp/smart_amp.h "smart_amp/smart_amp.h"
- * - Modules: Volume, Mixer, EQ FIR/IIR, DRC, SRC, ASRC, Crossover, DC Block, Copier + * - @ref src/include/sof/audio/channel_map.h "sof/audio/channel_map.h"
+ * - @ref src/include/sof/audio/format_generic.h "sof/audio/format_generic.h" + * + * + * Channel mapping extraction, multi-channel spatial routing, and sample format saturation arithmetic. + * + * + * + * Scheduling Infrastructure + * @ref scheduling_api + * + * - @ref src/include/sof/schedule/schedule.h "sof/schedule/schedule.h"
+ * - @ref src/include/sof/schedule/ll_schedule.h "sof/schedule/ll_schedule.h"
+ * - @ref src/include/sof/schedule/ll_schedule_domain.h "sof/schedule/ll_schedule_domain.h"
+ * - @ref src/include/sof/schedule/dp_schedule.h "sof/schedule/dp_schedule.h"
+ * - @ref src/include/sof/schedule/twb_schedule.h "sof/schedule/twb_schedule.h"
+ * - @ref zephyr/include/rtos/task.h "rtos/task.h" + * + * + * Multi-tiered real-time scheduling infrastructure: Low-Latency (LL) timer and DMA domains, + * Data Processing (DP) preemptible worker threads with dynamic deadline evaluation, + * Thread With Budget (TWB) cycle accounting, and core task state machines. + * + * + * + * Audio Processing Components & Modules + * @ref module_api + * + * - @ref src/include/module/module/interface.h "module/interface.h"
+ * - @ref src/include/module/module/api_ver.h "module/api_ver.h"
+ * - @ref src/include/module/module/base.h "module/base.h"
+ * - @ref src/include/module/audio/sink_api.h "module/audio/sink_api.h"
+ * - @ref src/include/module/audio/source_api.h "module/audio/source_api.h"
+ * - @ref src/include/module/audio/format.h "module/audio/format.h"
+ * - @ref src/include/module/module/system_service.h "module/system_service.h"
+ * - Built-in Modules: Volume, Mixer, EQ FIR/IIR, DRC, Multiband DRC, SRC, ASRC, Crossover, Smart Amp * * - * Standard and optimized DSP audio processing modules: smooth volume ramp, mixing, FIR/IIR - * parametric equalization, dynamic range compression, polyphase sample rate conversion, - * asynchronous sample rate conversion, and DAI copier sinks/sources. + * Standard and dynamic DSP audio processing modules and component contracts: lifecycle callbacks + * (init, prepare, process, config), source/sink streaming endpoints, LLEXT dynamic loading, + * and module adapter glue. + * + * + * + * Memory Management Infrastructure + * @ref memory_api + * + * - @ref zephyr/include/rtos/alloc.h "rtos/alloc.h"
+ * - @ref src/include/sof/lib/vregion.h "sof/lib/vregion.h"
+ * - @ref zephyr/include/sof/lib/regions_mm.h "sof/lib/regions_mm.h"
+ * - @ref zephyr/include/sof/lib/vpage.h "sof/lib/vpage.h"
+ * - @ref src/include/sof/lib/fast-get.h "sof/lib/fast-get.h"
+ * - @ref zephyr/include/sof/lib/memory.h "sof/lib/memory.h" + * + * + * Multi-tier DSP memory subsystem: system heaps (sys_heap), Virtual Memory Heap (VMH), + * pre-allocated virtual regions (vregion lifetime vs interim), cold DRAM dynamic staging (fast_get), + * shared user/kernel buffers, and data cache coherency. * * * * RTOS Abstraction Layer (RAL) * @ref rtos_api * - * - @ref zephyr/include/rtos/alloc.h "rtos/alloc.h"
* - @ref zephyr/include/rtos/spinlock.h "rtos/spinlock.h"
* - @ref zephyr/include/rtos/mutex.h "rtos/mutex.h"
* - @ref zephyr/include/rtos/wait.h "rtos/wait.h"
@@ -126,8 +185,9 @@ * - @ref zephyr/include/rtos/interrupt.h "rtos/interrupt.h" * * - * Operating system abstraction bridging Zephyr RTOS and XTOS: heap management (sys, lpsram, hpsram), - * spinlocks, mutexes, condition variables, hardware timers, and multi-core Inter-Domain Communication (IDC). + * Operating system abstraction bridging Zephyr RTOS and hardware primitives: + * spinlocks, mutexes, condition variables, hardware timers, cache writeback/invalidation, + * and multi-core Inter-Domain Communication (IDC). * * * diff --git a/doc/sof.doxygen.in b/doc/sof.doxygen.in index b9a2867b4f73..bf9a507f2199 100644 --- a/doc/sof.doxygen.in +++ b/doc/sof.doxygen.in @@ -52,6 +52,18 @@ PREDEFINED = "__attribute__(x)= " \ "CONFIG_IPC_MAJOR_4=1" \ "CONFIG_IPC_MAJOR_3=1" \ "CONFIG_COMP_VOLUME=1" \ + "CONFIG_SOF_VREGIONS=1" \ + "CONFIG_INCOHERENT=1" \ + "__ZEPHYR__=1" \ + "CONFIG_LLEXT=1" \ + "CONFIG_LLEXT_TYPE_ELF_RELOCATABLE=1" \ + "CONFIG_SOF_USERSPACE_INTERFACE_ALLOC=1" \ + "CONFIG_SOF_FULL_ZEPHYR_APPLICATION=1" \ + "CONFIG_SOF_USERSPACE_USE_SHARED_HEAP=1" \ + "__DOXYGEN__=1" \ + "__coherent=" \ + "__syscall=" \ + "__must_check=" \ "__packed=" \ "__aligned(x)=" \ "__sparse_cache=" \ diff --git a/posix/include/rtos/task.h b/posix/include/rtos/task.h index f73384b3cd58..8007d9eb850e 100644 --- a/posix/include/rtos/task.h +++ b/posix/include/rtos/task.h @@ -5,6 +5,12 @@ * Author: Liam Girdwood */ +/** + * @file posix/include/rtos/task.h + * @brief POSIX simulation task descriptor, task operations, and task execution state machine. + * @ingroup scheduling_api rtos_api + */ + #ifndef __POSIX_RTOS_TASK_H__ #define __POSIX_RTOS_TASK_H__ @@ -20,63 +26,74 @@ struct comp_dev; struct sof; struct schedule_data; -/** \brief Predefined LL task priorities. */ -#define SOF_TASK_PRI_HIGH 0 /* priority level 0 - high */ -#define SOF_TASK_PRI_MED 4 /* priority level 4 - medium */ -#define SOF_TASK_PRI_LOW 9 /* priority level 9 - low */ +/** @brief Predefined Low-Latency task priority levels. */ +#define SOF_TASK_PRI_HIGH 0 /**< Priority level 0 - high (hard real-time). */ +#define SOF_TASK_PRI_MED 4 /**< Priority level 4 - medium. */ +#define SOF_TASK_PRI_LOW 9 /**< Priority level 9 - low (background/idle). */ -/** \brief Predefined EDF task deadlines. */ -#define SOF_TASK_DEADLINE_IDLE UINT64_MAX -#define SOF_TASK_DEADLINE_ALMOST_IDLE (SOF_TASK_DEADLINE_IDLE - 1) -#define SOF_TASK_DEADLINE_NOW 0 +/** @brief Predefined EDF task deadlines. */ +#define SOF_TASK_DEADLINE_IDLE UINT64_MAX /**< Idle deadline; run only when nothing else is ready. */ +#define SOF_TASK_DEADLINE_ALMOST_IDLE (SOF_TASK_DEADLINE_IDLE - 1) /**< Almost idle deadline. */ +#define SOF_TASK_DEADLINE_NOW 0 /**< Immediate deadline; run as soon as possible. */ -/** \brief Task counter initial value. */ +/** @brief Task counter initial value. */ #define SOF_TASK_SKIP_COUNT 0xFFFFu -/** \brief Task states. */ +/** + * @brief Lifecycle and execution states of an SOF task. + */ enum task_state { - SOF_TASK_STATE_INIT = 0, - SOF_TASK_STATE_QUEUED, - SOF_TASK_STATE_PENDING, - SOF_TASK_STATE_RUNNING, - SOF_TASK_STATE_PREEMPTED, - SOF_TASK_STATE_COMPLETED, - SOF_TASK_STATE_FREE, - SOF_TASK_STATE_CANCEL, - SOF_TASK_STATE_RESCHEDULE, + SOF_TASK_STATE_INIT = 0, /**< Task allocated and initialized, not yet scheduled. */ + SOF_TASK_STATE_QUEUED, /**< Task queued in scheduler run list. */ + SOF_TASK_STATE_PENDING, /**< Task waiting for preconditions or resource availability. */ + SOF_TASK_STATE_RUNNING, /**< Task actively executing in thread or timer/DMA handler. */ + SOF_TASK_STATE_PREEMPTED, /**< Task preempted by higher priority thread or ISR. */ + SOF_TASK_STATE_COMPLETED, /**< Task execution finished; removed from active scheduling. */ + SOF_TASK_STATE_FREE, /**< Task resources released. */ + SOF_TASK_STATE_CANCEL, /**< Task cancelled, pending removal from scheduler. */ + SOF_TASK_STATE_RESCHEDULE, /**< Return code from run callback requesting rescheduling in next period. */ }; -/** \brief Task operations. */ +/** + * @brief Operations and callbacks associated with a scheduling task. + */ struct task_ops { - enum task_state (*run)(void *data); /**< task's main operation */ - void (*complete)(void *data); /**< executed on completion */ - uint64_t (*get_deadline)(void *data); /**< returns current deadline */ + enum task_state (*run)(void *data); /**< Task's main execution callback function. */ + void (*complete)(void *data); /**< Optional callback executed on task completion. */ + uint64_t (*get_deadline)(void *data); /**< Optional callback returning current task deadline timestamp. */ }; -/** \brief Task used by schedulers. */ +/** + * @brief Core task structure managed by SOF schedulers in POSIX simulation. + */ struct task { - uint64_t start; /**< start time in [ms] since now (LL only) */ - const struct sof_uuid_entry *uid; /**< Uuid */ - uint16_t type; /**< type of the task (LL or EDF) */ - int16_t priority; /**< priority of the task (used by LL); lower runs first */ - uint16_t core; /**< execution core */ - uint16_t flags; /**< custom flags */ - struct schedule_data *sch; /**< scheduler bound to task */ - enum task_state state; /**< current state */ - void *data; /**< custom data passed to all ops */ - struct list_item list; /**< used by schedulers to hold tasks */ - void *priv_data; /**< task private data */ - struct task_ops ops; /**< task operations */ + uint64_t start; /**< Scheduler/domain-specific start state (e.g. absolute tick timestamp in LL). */ + const struct sof_uuid_entry *uid; /**< UUID identifying the task or associated component. */ + uint16_t type; /**< Scheduler type identifier (SOF_SCHEDULE_*). */ + int16_t priority; /**< Priority of the task (lower values run first). */ + uint16_t core; /**< Execution core ID affinity. */ + uint16_t flags; /**< Custom task flags. */ + struct schedule_data *sch; /**< Pointer to scheduler instance bound to this task. */ + enum task_state state; /**< Current task lifecycle state. */ + void *data; /**< Custom context pointer passed to task operations. */ + struct list_item list; /**< List node linking task into scheduler run queue. */ + void *priv_data; /**< Scheduler-specific private task context. */ + struct task_ops ops; /**< Task operations callbacks table. */ #if defined(CONFIG_SCHEDULE_LOG_CYCLE_STATISTICS) - uint32_t cycles_sum; - uint32_t cycles_max; - uint32_t cycles_cnt; + uint32_t cycles_sum; /**< Cumulative execution cycles. */ + uint32_t cycles_max; /**< Maximum cycle count recorded in a single run. */ + uint32_t cycles_cnt; /**< Number of completed execution runs. */ #endif #if CONFIG_PERFORMANCE_COUNTERS - struct perf_cnt_data pcd; + struct perf_cnt_data pcd; /**< Performance counter telemetry data. */ #endif }; +/** + * @brief Check whether a task is active (queued, running, pending, or rescheduling). + * @param[in] task Task to check. + * @return true if task is in an active execution state, false otherwise. + */ static inline bool task_is_active(struct task *task) { switch (task->state) { @@ -91,6 +108,11 @@ static inline bool task_is_active(struct task *task) } } +/** + * @brief Execute a task's run callback. + * @param[in,out] task Task to execute. + * @return Resulting task state returned by the run callback. + */ static inline enum task_state task_run(struct task *task) { assert(task->ops.run); @@ -98,12 +120,21 @@ static inline enum task_state task_run(struct task *task) return task->ops.run(task->data); } +/** + * @brief Execute a task's complete callback, if registered. + * @param[in,out] task Task whose completion callback should be invoked. + */ static inline void task_complete(struct task *task) { if (task->ops.complete) task->ops.complete(task->data); } +/** + * @brief Retrieve a task's deadline timestamp. + * @param[in] task Task to query. + * @return Current deadline timestamp. + */ static inline uint64_t task_get_deadline(struct task *task) { assert(task->ops.get_deadline); @@ -111,15 +142,41 @@ static inline uint64_t task_get_deadline(struct task *task) return task->ops.get_deadline(task->data); } +/** + * @brief Primary core main processing loop callback in POSIX simulation. + * @param[in,out] data Context pointer passed to task handler. + * @return Resulting task state. + */ enum task_state task_main_primary_core(void *data); +/** + * @brief Secondary core main processing loop callback in POSIX simulation. + * @param[in,out] data Context pointer passed to task handler. + * @return Resulting task state. + */ enum task_state task_main_secondary_core(void *data); +/** + * @brief Initialize the main task execution infrastructure in POSIX simulation. + */ void task_main_init(void); +/** + * @brief Free resources allocated for the main task infrastructure in POSIX simulation. + */ void task_main_free(void); +/** + * @brief Start the main SOF background task loop in POSIX simulation. + * @param[in,out] sof Global SOF context pointer. + * @return 0 on success, negative error code on failure. + */ int task_main_start(struct sof *sof); + +/** + * @brief Signal completion of system startup in POSIX simulation. + * @return 0 on success, negative error code on failure. + */ int start_complete(void); #endif /* __POSIX_RTOS_TASK_H__ */ diff --git a/src/include/module/audio/audio_stream.h b/src/include/module/audio/audio_stream.h index 97cf38657019..f387ba90e458 100644 --- a/src/include/module/audio/audio_stream.h +++ b/src/include/module/audio/audio_stream.h @@ -6,6 +6,12 @@ * Adrian Warecki */ +/** + * @file module/audio/audio_stream.h + * @brief Circular audio buffer calculation and wrap utilities for processing modules. + * @ingroup module_api + */ + #ifndef __MODULE_AUDIO_AUDIO_STREAM_H__ #define __MODULE_AUDIO_AUDIO_STREAM_H__ @@ -14,6 +20,9 @@ #include #include "../ipc/stream.h" +/** \addtogroup module_api + * @{ + */ /** * @enum sof_audio_buffer_state @@ -269,4 +278,6 @@ static inline const void *source_cir_buf_rewind_wrap(const void *ptr, const void return ptr; } +/** @}*/ + #endif /* __MODULE_AUDIO_AUDIO_STREAM_H__ */ diff --git a/src/include/sof/audio/audio_buffer.h b/src/include/sof/audio/audio_buffer.h index 14ee20c23bf1..f16a50ccd43d 100644 --- a/src/include/sof/audio/audio_buffer.h +++ b/src/include/sof/audio/audio_buffer.h @@ -6,7 +6,7 @@ /** * @file sof/audio/audio_buffer.h * @brief Audio buffer operations, descriptors, and unified audio buffer interfaces. - * @ingroup audio_pipeline_api + * @ingroup audio_buffer_api */ #ifndef __SOF_AUDIO_BUFFER__ @@ -18,48 +18,66 @@ #include #include -#define BUFFER_TYPE_LEGACY_BUFFER 1 -#define BUFFER_TYPE_RING_BUFFER 2 +/** \addtogroup audio_buffer_api + * @{ + */ + +/** \name Buffer type identifiers + * @{ + */ +#define BUFFER_TYPE_LEGACY_BUFFER 1 /**< Legacy comp_buffer type (pipeline 1.0) */ +#define BUFFER_TYPE_RING_BUFFER 2 /**< Lockless async circular ring buffer type (cross-core) */ +/** @}*/ /* forward def */ struct sof_audio_buffer; +/** + * \brief Audio buffer virtual operations table. + */ struct audio_buffer_ops { /** - * @brief this method must free all structures allocated by buffer implementation - * and the buffer itself - * OBLIGATORY + * \brief Free all structures allocated by buffer implementation and the buffer itself. + * + * MANDATORY: audio_buffer_free() invokes this callback unconditionally. + * + * \param[in,out] buffer Buffer to free. */ void (*free)(struct sof_audio_buffer *buffer); /** - * @brief clean all buffer data, set buffer positions to initial, leaving config as is - * the procedure is to be called only when buffer is not in use - * OPTIONAL + * \brief Clean all buffer data and reset positions to initial state, keeping configuration. + * + * OPTIONAL: procedure is to be called only when buffer is not in use. + * + * \param[in,out] buffer Buffer to reset. */ void (*reset)(struct sof_audio_buffer *buffer); /** - * OPTIONAL: Notification to the sink implementation about changes in audio format - * - * Once any of *audio_stream_params elements changes, the implementation of - * sink may need to perform some extra operations. - * This callback will be called immediately after any change - * - * @retval 0 if success, negative if new parameters are not supported + * \brief Notification callback invoked on audio format modification. + * \param[in,out] buffer Buffer whose format changed. + * \retval 0 On success. + * \retval negative If new parameters are not supported. */ int (*on_audio_format_set)(struct sof_audio_buffer *buffer); /** - * OPTIONAL - * see sink_set_params comments + * \brief Configure IPC stream parameters on buffer. + * \param[in,out] buffer Buffer to configure. + * \param[in] params Stream parameters to apply. + * \param[in] force_update If true, overwrite parameters unconditionally. + * \return 0 on success, negative error code on failure. */ int (*audio_set_ipc_params)(struct sof_audio_buffer *buffer, struct sof_ipc_stream_params *params, bool force_update); /** - * OPTIONAL - * see comment for sink_set_alignment_constants + * \brief Configure alignment constraints on buffer. + * \param[in,out] buffer Buffer to configure. + * \param[in] byte_align Byte alignment requirement in bytes. + * \param[in] frame_align_req Frame alignment requirement in frames. + * \return 0 on success, negative error code on failure. */ int (*set_alignment_constants)(struct sof_audio_buffer *buffer, const uint32_t byte_align, @@ -67,106 +85,71 @@ struct audio_buffer_ops { }; struct mod_alloc_ctx; -/* base class for all buffers, all buffers must inherit from it */ + +/** + * \brief Base class for all audio buffers. All audio buffers must inherit from it. + */ struct sof_audio_buffer { CORE_CHECK_STRUCT_FIELD; - /* type of the buffer BUFFER_TYPE_* */ - uint32_t buffer_type; + uint32_t buffer_type; /**< Type of the buffer (BUFFER_TYPE_*) */ - bool is_shared; /* buffer structure is shared between 2 cores */ + bool is_shared; /**< Buffer structure is shared between 2 cores */ #if CONFIG_PIPELINE_2_0 /** - * sink API of an additional buffer - * of any type at data input - * - * to be removed when hybrid buffers are no longer needed + * Sink API of an additional buffer of any type at data input. + * To be removed when hybrid buffers are no longer needed. */ struct sof_audio_buffer *secondary_buffer_sink; /** - * source API of an additional buffer - * at data output + * Source API of an additional buffer at data output. */ struct sof_audio_buffer *secondary_buffer_source; #endif /* CONFIG_PIPELINE_2_0 */ - /* effective runtime stream params - * before pipelin2.0 is ready, stream params may be kept in audio_stream structure - * also for hybrid buffering audio params need to be shared between primary and secondary - * buffers - * - * So currently only a pointer to effective stream params is here. - * Note that the same pointer MUST be set in source and sink api (kept there for - * performance reasons) + /** + * Pointer to effective runtime stream parameters. */ struct sof_audio_stream_params *audio_stream_params; - /* private: */ - struct sof_source _source_api; /**< src api handler */ - struct sof_sink _sink_api; /**< sink api handler */ + struct sof_source _source_api; /**< Source API interface handler */ + struct sof_sink _sink_api; /**< Sink API interface handler */ /* virtual methods */ - const struct audio_buffer_ops *ops; + const struct audio_buffer_ops *ops; /**< Virtual methods table */ - /* - * legacy params, needed for pipeline binding/iterating, not for data buffering - * should not be in struct sof_audio_buffer at all, kept for pipeline2.0 transition - */ - bool walking; /**< indicates if the buffer is being walked */ + bool walking; /**< Indicates if the buffer is being walked in pipeline graph */ - struct mod_alloc_ctx *alloc; + struct mod_alloc_ctx *alloc; /**< Allocation context */ }; #if CONFIG_PIPELINE_2_0 -/* - * attach a secondary buffer (any type) before buffer (when at_input == true) or behind a buffer - * - * before buffer (at_input == true): - * 2.0 mod ==> (sink_API) secondary buffer ==> - * ==> comp_buffer (audio_stream or source API) ==> 1.0 mod - * - * after buffer (at_input == false): - * 1.0 mod ==> (audio_stream or sink API) ==> comp_buffer ==> - * ==> secondary buffer(source API) == 2.0 mod - * - * If a secondary buffer is attached, it replaces source or sink interface of audio_stream - * allowing the module connected to it using all properties of secondary buffer (like - * lockless cross-core connection in case of ring_buffer etc.) keeping legacy interface - * to other modules - * - * buffer_sync_secondary_buffer must be called every 1 ms to move data to/from - * secondary buffer to comp_buffer - * - * @param buffer pointer to a buffer - * @param at_input true indicates that a secondary buffer is located at data input, replacing - * sink API of audio_stream - * false indicates that a secondary buffer is located at data output, replacing - * source API of audio_stream - * @param secondary_buffer pointer to a buffer to be attached - * - * to be removed when hybrid buffers are no longer needed +/** + * \brief Attach a secondary buffer at data input or data output of primary buffer. + * \param[in,out] buffer Pointer to primary audio buffer. + * \param[in] at_input True if secondary buffer is placed at input, false if at output. + * \param[in,out] secondary_buffer Pointer to secondary buffer to attach. + * \return 0 on success, or negative error code on failure. */ int audio_buffer_attach_secondary_buffer(struct sof_audio_buffer *buffer, bool at_input, struct sof_audio_buffer *secondary_buffer); -/* - * move data from/to secondary buffer, must be called periodically as described above - * - * @param buffer pointer to a buffer - * @param limit data copy limit. Indicates maximum amount of data that will be moved from/to - * secondary buffer in an operation - * - * to be removed when hybrid buffers are no longer needed +/** + * \brief Synchronize data between primary and secondary hybrid buffers. + * \param[in,out] buffer Pointer to audio buffer. + * \param[in] limit Maximum number of bytes to move. + * \return 0 on success, or negative error code on failure. */ int audio_buffer_sync_secondary_buffer(struct sof_audio_buffer *buffer, size_t limit); /** - * @brief return a handler to sink API of audio_buffer. - * the handler may be used by helper functions defined in sink_api.h + * \brief Return pointer to sink interface of audio buffer. + * \param[in] buffer Pointer to audio buffer. + * \return Pointer to sink interface. */ static inline struct sof_sink *audio_buffer_get_sink(struct sof_audio_buffer *buffer) @@ -178,8 +161,9 @@ struct sof_sink *audio_buffer_get_sink(struct sof_audio_buffer *buffer) } /** - * @brief return a handler to source API of audio_buffer - * the handler may be used by helper functions defined in source_api.h + * \brief Return pointer to source interface of audio buffer. + * \param[in] buffer Pointer to audio buffer. + * \return Pointer to source interface. */ static inline struct sof_source *audio_buffer_get_source(struct sof_audio_buffer *buffer) @@ -193,8 +177,9 @@ struct sof_source *audio_buffer_get_source(struct sof_audio_buffer *buffer) #else /* CONFIG_PIPELINE_2_0 */ /** - * @brief return a handler to sink API of audio_buffer. - * the handler may be used by helper functions defined in sink_api.h + * \brief Return pointer to sink interface of audio buffer. + * \param[in] buffer Pointer to audio buffer. + * \return Pointer to sink interface. */ static inline struct sof_sink *audio_buffer_get_sink(struct sof_audio_buffer *buffer) @@ -204,8 +189,9 @@ struct sof_sink *audio_buffer_get_sink(struct sof_audio_buffer *buffer) } /** - * @brief return a handler to source API of audio_buffer - * the handler may be used by helper functions defined in source_api.h + * \brief Return pointer to source interface of audio buffer. + * \param[in] buffer Pointer to audio buffer. + * \return Pointer to source interface. */ static inline struct sof_source *audio_buffer_get_source(struct sof_audio_buffer *buffer) @@ -216,48 +202,92 @@ struct sof_source *audio_buffer_get_source(struct sof_audio_buffer *buffer) #endif /* CONFIG_PIPELINE_2_0 */ +/** + * \brief Check if audio buffer is shared across cores. + * \param[in] buffer Pointer to audio buffer. + * \return True if shared, false otherwise. + */ static inline bool audio_buffer_is_shared(struct sof_audio_buffer *buffer) { return buffer->is_shared; } +/** + * \brief Check if buffer hardware parameters are configured. + * \param[in] buffer Pointer to audio buffer. + * \return True if configured, false otherwise. + */ static inline bool audio_buffer_hw_params_configured(struct sof_audio_buffer *buffer) { return buffer->audio_stream_params->state != AUDIOBUF_STATE_INITIAL; } +/** + * \brief Mark buffer hardware parameters as configured (state set to READY). + * \param[in,out] buffer Pointer to audio buffer. + */ static inline void audio_buffer_set_hw_params_configured(struct sof_audio_buffer *buffer) { buffer->audio_stream_params->state = AUDIOBUF_STATE_READY; } +/** + * \brief Reset buffer parameters state to initial. + * \param[in,out] buffer Pointer to audio buffer. + */ static inline void audio_buffer_reset_params(struct sof_audio_buffer *buffer) { buffer->audio_stream_params->state = AUDIOBUF_STATE_INITIAL; } +/** + * \brief Retrieve current buffer state. + * \param[in] buffer Pointer to audio buffer. + * \return Current buffer state (enum sof_audio_buffer_state). + */ static inline enum sof_audio_buffer_state audio_buffer_get_state( const struct sof_audio_buffer *buffer) { return buffer->audio_stream_params->state; } +/** + * \brief Set buffer state. + * \param[in,out] buffer Pointer to audio buffer. + * \param[in] state New state to assign. + */ static inline void audio_buffer_set_state(struct sof_audio_buffer *buffer, enum sof_audio_buffer_state state) { buffer->audio_stream_params->state = state; } +/** + * \brief Mark buffer state as end-of-stream (EOS). + * \param[in,out] buffer Pointer to audio buffer. + */ static inline void audio_buffer_set_eos(struct sof_audio_buffer *buffer) { buffer->audio_stream_params->state = AUDIOBUF_STATE_END_OF_STREAM; } +/** + * \brief Retrieve channel map value for a given channel index. + * \param[in] buffer Pointer to audio buffer. + * \param[in] index Channel index. + * \return Channel map value. + */ static inline uint16_t audio_buffer_get_chmap(struct sof_audio_buffer *buffer, size_t index) { return buffer->audio_stream_params->chmap[index]; } +/** + * \brief Set channel map value for a given channel index. + * \param[in,out] buffer Pointer to audio buffer. + * \param[in] index Channel index. + * \param[in] value Channel map value to set. + */ static inline void audio_buffer_set_chmap(struct sof_audio_buffer *buffer, size_t index, uint16_t value) { @@ -265,7 +295,9 @@ static inline void audio_buffer_set_chmap(struct sof_audio_buffer *buffer, size_ } /** - * @brief return a handler to stream params structure + * \brief Retrieve pointer to runtime stream parameters. + * \param[in] buffer Pointer to audio buffer. + * \return Pointer to runtime stream parameters. */ static inline struct sof_audio_stream_params *audio_buffer_get_stream_params(struct sof_audio_buffer *buffer) @@ -274,9 +306,13 @@ struct sof_audio_stream_params *audio_buffer_get_stream_params(struct sof_audio_ } /** - * @brief return a pointer to struct sof_audio_buffer from sink pointer - * NOTE! ensure that sink is really provided by sof_audio_buffer - * otherwise a random value will be returned + * \brief Retrieve enclosing sof_audio_buffer from sink interface pointer. + * + * NOTE: Ensure that sink is really embedded within a sof_audio_buffer; + * otherwise an invalid derived pointer will be returned. + * + * \param[in] sink Pointer to sink interface. + * \return Pointer to enclosing struct sof_audio_buffer. */ static inline struct sof_audio_buffer *sof_audio_buffer_from_sink(struct sof_sink *sink) { @@ -284,9 +320,13 @@ static inline struct sof_audio_buffer *sof_audio_buffer_from_sink(struct sof_sin } /** - * @brief return a pointer to struct sof_audio_buffer from source pointer - * NOTE! ensure that source is really provided by sof_audio_buffer - * otherwise a random value will be returned + * \brief Retrieve enclosing sof_audio_buffer from source interface pointer. + * + * NOTE: Ensure that source is really embedded within a sof_audio_buffer; + * otherwise an invalid derived pointer will be returned. + * + * \param[in] source Pointer to source interface. + * \return Pointer to enclosing struct sof_audio_buffer. */ static inline struct sof_audio_buffer *sof_audio_buffer_from_source(struct sof_source *source) { @@ -294,23 +334,14 @@ static inline struct sof_audio_buffer *sof_audio_buffer_from_source(struct sof_s } /** - * @brief initialize audio buffer structures - * - * @param buffer pointer to the audio_buffer - * @param buffer_type a type of the buffer, BUFFER_TYPE_* - * @param is_shared indicates if the buffer will be shared between cores - * @param source_ops pointer to virtual methods table for source API - * @param sink_ops pointer to virtual methods table for sink API - * @param audio_buffer_ops pointer to required buffer virtual methods implementation - * @param audio_stream_params pointer to audio stream (currently kept in buffer implementation) - * - * in sink_ops and source_ops API if there's no implemented of following methods: - * on_audio_format_set - * audio_set_ipc_params - * set_alignment_constants - * - * default implementation will be used instead, redirecting those calls to proper - * audio_buffer_ops operations + * \brief Initialize audio buffer structure and virtual operation tables. + * \param[in,out] buffer Pointer to audio buffer. + * \param[in] buffer_type Buffer type identifier (BUFFER_TYPE_*). + * \param[in] is_shared True if buffer is shared between cores. + * \param[in] source_ops Pointer to source operations table. + * \param[in] sink_ops Pointer to sink operations table. + * \param[in] audio_buffer_ops Pointer to audio buffer operations table. + * \param[in,out] audio_stream_params Pointer to audio stream parameters. */ void audio_buffer_init(struct sof_audio_buffer *buffer, uint32_t buffer_type, bool is_shared, const struct source_ops *source_ops, const struct sink_ops *sink_ops, @@ -318,13 +349,14 @@ void audio_buffer_init(struct sof_audio_buffer *buffer, uint32_t buffer_type, bo struct sof_audio_stream_params *audio_stream_params); /** - * @brief free buffer and all allocated resources + * \brief Free audio buffer and all allocated resources. + * \param[in,out] buffer Pointer to audio buffer to free. */ void audio_buffer_free(struct sof_audio_buffer *buffer); /** - * @brief clean all buffer data, set buffer positions to initial, leaving config as is - * the procedure is to be called only when buffer is not in use + * \brief Reset all buffer data and positions leaving configuration intact. + * \param[in,out] buffer Pointer to audio buffer. */ static inline void audio_buffer_reset(struct sof_audio_buffer *buffer) @@ -342,18 +374,70 @@ void audio_buffer_reset(struct sof_audio_buffer *buffer) } /* Audio-buffer wrappers for the source-sink API */ + +/** + * \brief Set IPC stream parameters via source interface wrapper. + * \param[in,out] source Pointer to source interface. + * \param[in] params Stream parameters to apply. + * \param[in] force_update If true, overwrite parameters unconditionally. + * \return 0 on success, or negative error code on failure. + */ int audio_buffer_source_set_ipc_params(struct sof_source *source, struct sof_ipc_stream_params *params, bool force_update); + +/** + * \brief Audio format set callback via source interface wrapper. + * \param[in,out] source Pointer to source interface. + * \return 0 on success, or negative error code on failure. + */ int audio_buffer_source_on_audio_format_set(struct sof_source *source); + +/** + * \brief Set alignment constraints via source interface wrapper. + * \param[in,out] source Pointer to source interface. + * \param[in] byte_align Byte alignment requirement in bytes. + * \param[in] frame_align_req Frame alignment requirement in frames. + * \return 0 on success, or negative error code on failure. + */ int audio_buffer_source_set_alignment_constants(struct sof_source *source, const uint32_t byte_align, const uint32_t frame_align_req); + +/** + * \brief Set IPC stream parameters via sink interface wrapper. + * \param[in,out] sink Pointer to sink interface. + * \param[in] params Stream parameters to apply. + * \param[in] force_update If true, overwrite parameters unconditionally. + * \return 0 on success, or negative error code on failure. + */ int audio_buffer_sink_set_ipc_params(struct sof_sink *sink, struct sof_ipc_stream_params *params, bool force_update); + +/** + * \brief Audio format set callback via sink interface wrapper. + * \param[in,out] sink Pointer to sink interface. + * \return 0 on success, or negative error code on failure. + */ int audio_buffer_sink_on_audio_format_set(struct sof_sink *sink); + +/** + * \brief Set alignment constraints via sink interface wrapper. + * \param[in,out] sink Pointer to sink interface. + * \param[in] byte_align Byte alignment requirement in bytes. + * \param[in] frame_align_req Frame alignment requirement in frames. + * \return 0 on success, or negative error code on failure. + */ int audio_buffer_sink_set_alignment_constants(struct sof_sink *sink, const uint32_t byte_align, const uint32_t frame_align_req); + +/** + * \brief Get linear free time (LFT) duration in microseconds from sink interface wrapper. + * \param[in] sink Pointer to sink interface. + * \return Buffered duration in microseconds (us_in_buffer) calculated from source available data and sample rate. + */ uint32_t audio_buffer_sink_get_lft(struct sof_sink *sink); +/** @}*/ + #endif /* __SOF_AUDIO_BUFFER__ */ diff --git a/src/include/sof/audio/audio_stream.h b/src/include/sof/audio/audio_stream.h index 93d42d095dc1..45adb1e4a38a 100644 --- a/src/include/sof/audio/audio_stream.h +++ b/src/include/sof/audio/audio_stream.h @@ -30,7 +30,7 @@ #include #include -/** \addtogroup audio_pipeline_api +/** \addtogroup audio_buffer_api * @{ */ diff --git a/src/include/sof/audio/buffer.h b/src/include/sof/audio/buffer.h index 6744bbf1b5ef..9f9f7df672b5 100644 --- a/src/include/sof/audio/buffer.h +++ b/src/include/sof/audio/buffer.h @@ -8,7 +8,7 @@ /** * @file sof/audio/buffer.h * @brief Component interconnect buffer allocation and stream handling. - * @ingroup audio_pipeline_api + * @ingroup audio_buffer_api */ #ifndef __SOF_AUDIO_BUFFER_H__ @@ -37,6 +37,10 @@ #include #include +/** \addtogroup audio_buffer_api + * @{ + */ + struct comp_dev; struct buffer_cb_transact; @@ -110,53 +114,63 @@ extern struct tr_ctx buffer_tr; /** @}*/ -/* buffer callback types */ -#define BUFF_CB_TYPE_PRODUCE BIT(0) -#define BUFF_CB_TYPE_CONSUME BIT(1) +/** \name Buffer callback types + * @{ + */ +#define BUFF_CB_TYPE_PRODUCE BIT(0) /**< Callback triggered on buffer produce */ +#define BUFF_CB_TYPE_CONSUME BIT(1) /**< Callback triggered on buffer consume */ +/** @}*/ -#define BUFFER_UPDATE_IF_UNSET 0 -#define BUFFER_UPDATE_FORCE 1 +/** \name Buffer parameter update modes + * @{ + */ +#define BUFFER_UPDATE_IF_UNSET 0 /**< Update buffer parameters only if currently unset */ +#define BUFFER_UPDATE_FORCE 1 /**< Force update buffer parameters regardless of current state */ +/** @}*/ -/* buffer parameters */ -#define BUFF_PARAMS_FRAME_FMT BIT(0) -#define BUFF_PARAMS_BUFFER_FMT BIT(1) -#define BUFF_PARAMS_RATE BIT(2) -#define BUFF_PARAMS_CHANNELS BIT(3) +/** \name Buffer parameter bitmasks + * @{ + */ +#define BUFF_PARAMS_FRAME_FMT BIT(0) /**< Buffer parameter bitmask: frame format */ +#define BUFF_PARAMS_BUFFER_FMT BIT(1) /**< Buffer parameter bitmask: buffer format */ +#define BUFF_PARAMS_RATE BIT(2) /**< Buffer parameter bitmask: sample rate */ +#define BUFF_PARAMS_CHANNELS BIT(3) /**< Buffer parameter bitmask: channels count */ +/** @}*/ -/* buffer usage */ -#define BUFFER_USAGE_SHARED true /* buffer used by multiple DSP core and/or HW blocks */ -#define BUFFER_USAGE_NOT_SHARED false /* buffer only used by one HW block */ +/** \name Buffer memory sharing usage + * @{ + */ +#define BUFFER_USAGE_SHARED true /**< Buffer used by multiple DSP cores and/or HW blocks */ +#define BUFFER_USAGE_NOT_SHARED false /**< Buffer only used by one HW block */ +/** @}*/ -/* - * audio component buffer - connects 2 audio components together in pipeline. - * - * this is a legacy component connector for pipeline 1.0 - * +/** + * \brief Audio component interconnect buffer connecting two pipeline components. */ struct comp_buffer { /* data buffer */ - struct sof_audio_buffer audio_buffer; + struct sof_audio_buffer audio_buffer; /**< Unified audio buffer base class */ - struct audio_stream stream; + struct audio_stream stream; /**< Legacy audio stream representation */ /* configuration */ - uint32_t flags; - uint32_t core; + uint32_t flags; /**< Buffer flags */ + uint32_t core; /**< DSP core ID managing this buffer */ #if !CONFIG_ZEPHYR_LOG - struct tr_ctx tctx; /* trace settings */ + struct tr_ctx tctx; /**< Trace context */ #endif /* connected components */ - struct comp_dev *source; /* source component */ - struct comp_dev *sink; /* sink component */ + struct comp_dev *source; /**< Source component feeding this buffer */ + struct comp_dev *sink; /**< Sink component consuming from this buffer */ /* lists */ - struct list_item source_list; /* list in comp buffers */ - struct list_item sink_list; /* list in comp buffers */ + struct list_item source_list; /**< List node in source component's buffer list */ + struct list_item sink_list; /**< List node in sink component's buffer list */ /* list of buffers, to be used i.e. in raw data processing mode*/ - struct list_item buffers_list; + struct list_item buffers_list; /**< List of buffers used in raw data processing */ #if CONFIG_PROBE /** probe produce callback, called on buffer produce */ @@ -168,56 +182,93 @@ struct comp_buffer { #endif }; -/* - * get a component providing data to the buffer +/** + * \brief Get component providing data to the buffer. + * \param[in] buffer Interconnect buffer. + * \return Pointer to source component device, or NULL if none. */ static inline struct comp_dev *comp_buffer_get_source_component(const struct comp_buffer *buffer) { return buffer->source; } -/* - * get a component consuming data from the buffer +/** + * \brief Get component consuming data from the buffer. + * \param[in] buffer Interconnect buffer. + * \return Pointer to sink component device, or NULL if none. */ static inline struct comp_dev *comp_buffer_get_sink_component(const struct comp_buffer *buffer) { return buffer->sink; } +/** + * \brief Set component providing data to the buffer. + * \param[in,out] buffer Interconnect buffer. + * \param[in] comp Source component device. + */ static inline void comp_buffer_set_source_component(struct comp_buffer *buffer, struct comp_dev *comp) { buffer->source = comp; } +/** + * \brief Set component consuming data from the buffer. + * \param[in,out] buffer Interconnect buffer. + * \param[in] comp Sink component device. + */ static inline void comp_buffer_set_sink_component(struct comp_buffer *buffer, struct comp_dev *comp) { buffer->sink = comp; } +/** + * \brief Reset buffer source list node. + * \param[in,out] buffer Interconnect buffer. + */ static inline void comp_buffer_reset_source_list(struct comp_buffer *buffer) { list_init(&buffer->source_list); } +/** + * \brief Reset buffer sink list node. + * \param[in,out] buffer Interconnect buffer. + */ static inline void comp_buffer_reset_sink_list(struct comp_buffer *buffer) { list_init(&buffer->sink_list); } -/* Used as parameter for probe produce callback */ +/** + * \brief Transaction descriptor passed to buffer probe callbacks. + */ struct buffer_cb_transact { - struct comp_buffer *buffer; - uint32_t transaction_amount; - void *transaction_begin_address; + struct comp_buffer *buffer; /**< Buffer being transacted */ + uint32_t transaction_amount; /**< Number of bytes transacted */ + void *transaction_begin_address; /**< Starting address of transaction */ }; +/** + * \brief Retrieve enclosing comp_buffer from a list node depending on traversal direction. + * \param[in] ptr List item pointer. + * \param[in] dir Pipeline traversal direction (PPL_DIR_DOWNSTREAM or PPL_DIR_UPSTREAM). + * \return Pointer to enclosing struct comp_buffer. + */ #define buffer_from_list(ptr, dir) \ ((dir) == PPL_DIR_DOWNSTREAM ? \ container_of(ptr, struct comp_buffer, source_list) : \ container_of(ptr, struct comp_buffer, sink_list)) +/** + * \brief Set transaction callback on a component buffer. + * \param[in,out] buffer Target component buffer. + * \param[in] func Callback function pointer. + * \param[in] data Callback user data. + * \param[in] type Callback trigger type (BUFF_CB_TYPE_*). + */ #define buffer_set_cb(buffer, func, data, type) \ do { \ buffer->cb = func; \ @@ -227,20 +278,69 @@ struct buffer_cb_transact { struct mod_alloc_ctx; -/* pipeline buffer creation and destruction */ +/** + * \brief Allocate a pipeline component audio buffer with explicit size and alignment. + * \param[in,out] alloc Allocation context (heap and optional vregion). + * \param[in] size Required buffer capacity in bytes. + * \param[in] flags Memory allocation flags (SOF_MEM_FLAG_...). + * \param[in] align Memory alignment requirement in bytes. + * \param[in] is_shared True if the buffer memory is shared across processing domains. + * \return Pointer to allocated comp_buffer, or NULL on failure. + */ struct comp_buffer *buffer_alloc(struct mod_alloc_ctx *alloc, size_t size, uint32_t flags, uint32_t align, bool is_shared); + +/** + * \brief Allocate a pipeline component buffer with an elastic size range. + * \param[in,out] alloc Allocation context. + * \param[in] preferred_size Desired optimal buffer capacity in bytes. + * \param[in] minimum_size Minimum acceptable buffer capacity in bytes. + * \param[in] flags Memory allocation flags (SOF_MEM_FLAG_...). + * \param[in] align Memory alignment requirement in bytes. + * \param[in] is_shared True if the buffer memory is shared across processing domains. + * \return Pointer to allocated comp_buffer, or NULL on failure. + */ struct comp_buffer *buffer_alloc_range(struct mod_alloc_ctx *alloc, size_t preferred_size, size_t minimum_size, uint32_t flags, uint32_t align, bool is_shared); + +/** + * \brief Instantiate a pipeline component buffer from an IPC configuration descriptor. + * \param[in,out] alloc Allocation context. + * \param[in] desc IPC buffer descriptor containing size, flags, and configuration. + * \param[in] is_shared True if the buffer memory is shared across processing domains. + * \return Pointer to newly instantiated comp_buffer, or NULL on failure. + */ struct comp_buffer *buffer_new(struct mod_alloc_ctx *alloc, const struct sof_ipc_buffer *desc, bool is_shared); +/** + * \brief Resize an existing pipeline component buffer. + * \param[in,out] buffer Pointer to comp_buffer to resize. + * \param[in] size New buffer capacity in bytes. + * \param[in] alignment Required memory alignment in bytes. + * \return 0 on success, or negative error code on failure. + */ int buffer_set_size(struct comp_buffer *buffer, uint32_t size, uint32_t alignment); + +/** + * \brief Resize a pipeline component buffer within a preferred-to-minimum range. + * \param[in,out] buffer Pointer to comp_buffer to resize. + * \param[in] preferred_size Desired optimal buffer capacity in bytes. + * \param[in] minimum_size Minimum acceptable buffer capacity in bytes. + * \param[in] alignment Required memory alignment in bytes. + * \return 0 on success, or negative error code on failure. + */ int buffer_set_size_range(struct comp_buffer *buffer, size_t preferred_size, size_t minimum_size, uint32_t alignment); /* legacy wrappers, to be removed. Don't use them if possible */ + +/** + * \brief Retrieve enclosing comp_buffer from an audio source interface pointer. + * \param[in] source Pointer to audio source interface. + * \return Pointer to enclosing struct comp_buffer. + */ static inline struct comp_buffer *comp_buffer_get_from_source(struct sof_source *source) { struct sof_audio_buffer *audio_buffer = sof_audio_buffer_from_source(source); @@ -248,6 +348,11 @@ static inline struct comp_buffer *comp_buffer_get_from_source(struct sof_source return container_of(audio_buffer, struct comp_buffer, audio_buffer); } +/** + * \brief Retrieve enclosing comp_buffer from an audio sink interface pointer. + * \param[in] sink Pointer to audio sink interface. + * \return Pointer to enclosing struct comp_buffer. + */ static inline struct comp_buffer *comp_buffer_get_from_sink(struct sof_sink *sink) { struct sof_audio_buffer *audio_buffer = sof_audio_buffer_from_sink(sink); @@ -255,6 +360,10 @@ static inline struct comp_buffer *comp_buffer_get_from_sink(struct sof_sink *sin return container_of(audio_buffer, struct comp_buffer, audio_buffer); } +/** + * \brief Free an interconnect component buffer and its underlying memory. + * \param[in,out] buffer Component buffer to free. + */ static inline void buffer_free(struct comp_buffer *buffer) { audio_buffer_free(&buffer->audio_buffer); @@ -262,20 +371,51 @@ static inline void buffer_free(struct comp_buffer *buffer) /* end of legacy wrappers */ +/** + * \brief Zero-fill the entire payload of an interconnect buffer. + * \param[in,out] buffer Component buffer to zero. + */ void buffer_zero(struct comp_buffer *buffer); -/* called by a component after producing data into this buffer */ +/** + * \brief Notify buffer that audio data has been produced by a component. + * \param[in,out] buffer Component buffer written to. + * \param[in] bytes Number of bytes produced. + */ void comp_update_buffer_produce(struct comp_buffer *buffer, uint32_t bytes); -/* called by a component after consuming data from this buffer */ +/** + * \brief Notify buffer that audio data has been consumed by a component. + * \param[in,out] buffer Component buffer read from. + * \param[in] bytes Number of bytes consumed. + */ void comp_update_buffer_consume(struct comp_buffer *buffer, uint32_t bytes); +/** + * \brief Set audio stream parameters on a component buffer. + * \param[in,out] buffer Component buffer to configure. + * \param[in] params Stream parameters to apply. + * \param[in] force_update If true, overwrite existing parameters unconditionally. + * \return 0 on success, or negative error code on failure. + */ int buffer_set_params(struct comp_buffer *buffer, struct sof_ipc_stream_params *params, bool force_update); +/** + * \brief Test if buffer stream parameters match requested parameters. + * \param[in] buffer Component buffer to check. + * \param[in] params Stream parameters to compare. + * \param[in] flag Bitmask specifying which parameters to check (BUFF_PARAMS_*). + * \return True if matching, false otherwise. + */ bool buffer_params_match(struct comp_buffer *buffer, struct sof_ipc_stream_params *params, uint32_t flag); +/** + * \brief Invalidate cache for a shared buffer stream if incoherent. + * \param[in,out] buffer Component buffer. + * \param[in] bytes Number of bytes to invalidate. + */ static inline void buffer_stream_invalidate(struct comp_buffer *buffer, uint32_t bytes) { #if CONFIG_INCOHERENT @@ -284,6 +424,11 @@ static inline void buffer_stream_invalidate(struct comp_buffer *buffer, uint32_t #endif } +/** + * \brief Write back cache for a shared buffer stream if incoherent. + * \param[in] buffer Component buffer. + * \param[in] bytes Number of bytes to write back. + */ static inline void buffer_stream_writeback(struct comp_buffer *buffer, uint32_t bytes) { #if CONFIG_INCOHERENT @@ -292,26 +437,40 @@ static inline void buffer_stream_writeback(struct comp_buffer *buffer, uint32_t #endif } - -/* - * Attach a new buffer at the beginning of the list. Note, that "head" must - * really be the head of the list, not a list head within another buffer. We - * don't synchronise its cache, so it must not be embedded in an object, using - * the coherent API. The caller takes care to protect list heads. +/** + * \brief Attach a new buffer at the beginning of a component buffer list. * - * Returns -EINVAL if the buffer is already linked in this direction - * (re-attaching would create a self-loop and corrupt the list). + * Locking: Must be called with interrupts disabled (or userspace LL system mutex held). + * The caller takes care to protect list heads. "head" must really be the head of the + * list, not a list node within another buffer, as its cache is not synchronized and + * must not be embedded in an object using the coherent API. + * + * \param[in,out] buffer Component buffer to attach. + * \param[in,out] head List head to prepend buffer to. + * \param[in] dir Traversal direction (PPL_DIR_DOWNSTREAM or PPL_DIR_UPSTREAM). + * \return 0 on success, or -EALREADY if the buffer is already linked in this direction. */ int buffer_attach(struct comp_buffer *buffer, struct list_item *head, int dir); -/* - * Detach a buffer from anywhere in the list. "head" is again the head of the - * list, we need it to verify, whether this buffer was the first or the last on - * the list. Again it is assumed that the head's cache doesn't need to be - * synchronized. The caller takes care to protect list heads. +/** + * \brief Detach a buffer from anywhere in a component buffer list. + * + * Locking: Must be called with interrupts disabled (or userspace LL system mutex held). + * "head" is the head of the list, assumed not to require cache synchronization. + * The caller takes care to protect list heads. + * + * \param[in,out] buffer Component buffer to detach. + * \param[in,out] head List head buffer is attached to. + * \param[in] dir Traversal direction (PPL_DIR_DOWNSTREAM or PPL_DIR_UPSTREAM). */ void buffer_detach(struct comp_buffer *buffer, struct list_item *head, int dir); +/** + * \brief Get component connected to buffer in specified traversal direction. + * \param[in] buffer Component buffer. + * \param[in] dir Traversal direction (PPL_DIR_DOWNSTREAM or PPL_DIR_UPSTREAM). + * \return Pointer to connected component device. + */ static inline struct comp_dev *buffer_get_comp(struct comp_buffer *buffer, int dir) { struct comp_dev *comp = (dir == PPL_DIR_DOWNSTREAM) ? @@ -320,16 +479,27 @@ static inline struct comp_dev *buffer_get_comp(struct comp_buffer *buffer, int d return comp; } +/** + * \brief Retrieve pipeline ID associated with a component buffer. + * \param[in] buffer Component buffer. + * \return Pipeline ID. + */ static inline uint32_t buffer_pipeline_id(const struct comp_buffer *buffer) { return buffer->stream.runtime_stream_params.pipeline_id; } -/* Run-time buffer re-configuration calls this too, so it must use cached access */ +/** + * \brief Initialize circular stream buffer descriptor for a component buffer. + * \param[in,out] buffer Component buffer to initialize stream for. + * \param[in] size Capacity of the circular stream in bytes. + */ static inline void buffer_init_stream(struct comp_buffer *buffer, size_t size) { /* addr should be set in alloc function */ audio_stream_init(&buffer->stream, buffer->stream.addr, size); } +/** @}*/ + #endif /* __SOF_AUDIO_BUFFER_H__ */ diff --git a/src/include/sof/audio/channel_map.h b/src/include/sof/audio/channel_map.h index a0ec75baca48..64850f7332f1 100644 --- a/src/include/sof/audio/channel_map.h +++ b/src/include/sof/audio/channel_map.h @@ -8,7 +8,7 @@ /** * @file sof/audio/channel_map.h * @brief Audio stream channel map lookup and sizing helpers. - * @ingroup audio_pipeline_api + * @ingroup audio_format_api */ #ifndef __SOF_AUDIO_CHANNEL_MAP_H__ @@ -18,10 +18,14 @@ #include #include +/** \addtogroup audio_format_api + * @{ + */ + /** - * @brief Returns the size of an IPC channel map structure in bytes. - * @param chmap Pointer to the channel map structure. - * @return Total size in bytes including dynamic channel coefficients. + * \brief Returns the size of an IPC channel map structure in bytes. + * \param[in] chmap Pointer to the channel map structure. + * \return Total size in bytes including dynamic channel coefficients. */ static inline uint32_t chmap_get_size(struct sof_ipc_channel_map *chmap) { @@ -30,12 +34,14 @@ static inline uint32_t chmap_get_size(struct sof_ipc_channel_map *chmap) } /** - * @brief Returns a channel map for a given channel index in a stream map. - * @param smap Pointer to the stream map structure. - * @param index Channel index. - * @return Pointer to matching channel map structure, or NULL if not found. + * \brief Returns a channel map for a given channel index in a stream map. + * \param[in] smap Pointer to the stream map structure. + * \param[in] index Channel index. + * \return Pointer to matching channel map structure, or NULL if not found. */ struct sof_ipc_channel_map *chmap_get(struct sof_ipc_stream_map *smap, int index); +/** @}*/ + #endif /* __SOF_AUDIO_CHANNEL_MAP_H__ */ diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index c290001107d2..f8d91c8d8212 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -38,7 +38,7 @@ struct dai_hw_params; struct timestamp_data; struct dai_ts_data; -/** \addtogroup audio_pipeline_api +/** \addtogroup component_infra_api * @{ */ @@ -276,41 +276,30 @@ struct comp_ipc_config; union ipc_config_specific; struct ipc4_module_bind_unbind; +/** \brief Component module binding endpoint type. */ enum bind_type { - COMP_BIND_TYPE_SOURCE, - COMP_BIND_TYPE_SINK + COMP_BIND_TYPE_SOURCE, /**< Bind to a data source */ + COMP_BIND_TYPE_SINK /**< Bind to a data sink */ }; +/** + * \brief Component module binding metadata and endpoint references. + */ struct bind_info { - /* pointer to IPC4 bind/unbind data */ - const struct ipc4_module_bind_unbind *ipc4_data; - - /* type of binding - * bind call will be called twice for every component, first when binding a data source, - * than when binding data sink. - * - * bind_type is indicating type of binding - */ - enum bind_type bind_type; + const struct ipc4_module_bind_unbind *ipc4_data; /**< Pointer to IPC4 bind/unbind data */ + enum bind_type bind_type; /**< Type of binding (source or sink) */ /* pointers to sink or source API of the data provider/consumer * that is being bound to the module - * - * if bind_type == COMP_BIND_TYPE_SOURCE, the pointer points to source being bound/unbound - * if bind_type == COMP_BIND_TYPE_SINK, the pointer points to sink being bound/unbound - * - * NOTE! As in pipeline2.0 there may be a binding between modules, - * without a buffer in between, it cannot be a pointer to any buffer type, module should - * use sink/source API */ union { - struct sof_source *source; - struct sof_sink *sink; + struct sof_source *source; /**< Source interface pointer when bind_type == COMP_BIND_TYPE_SOURCE */ + struct sof_sink *sink; /**< Sink interface pointer when bind_type == COMP_BIND_TYPE_SINK */ }; }; /** - * Audio component operations. + * \brief Audio component operations table. * * All component operations must return 0 for success, negative values for * errors and 1 to stop the pipeline walk operation unless specified otherwise @@ -318,189 +307,149 @@ struct bind_info { */ struct comp_ops { /** - * Creates a new component device. - * @param drv Parent component driver. - * @param ipc_config Component parameters. - * @param spec Pointer to initialization data - * @return Pointer to the new component device. - * - * Any component-specific private data is allocated separately and - * pointer is connected to the comp_dev::private by using - * comp_set_drvdata() and later retrieved by comp_get_drvdata(). - * - * All parameters should be initialized to their default values. - * Usually can be __cold. + * \brief Creates a new component device. + * \param[in] drv Parent component driver. + * \param[in] ipc_config Component parameters. + * \param[in] spec Pointer to initialization data. + * \return Pointer to the new component device, or NULL on failure. */ struct comp_dev *(*create)(const struct comp_driver *drv, const struct comp_ipc_config *ipc_config, const void *spec); /** - * Called to delete the specified component device. - * @param dev Component device to be deleted. - * - * All data structures previously allocated on the run-time heap - * must be freed by the implementation of free(). - * Usually can be __cold. + * \brief Called to delete the specified component device. + * \param[in,out] dev Component device to be deleted. */ void (*free)(struct comp_dev *dev); /** - * Sets component audio stream parameters. - * @param dev Component device. - * @param params Audio (PCM) stream parameters to be set. - * - * Infrastructure calls comp_verify_params() if this handler is not - * defined, therefore it should be left NULL if no extra steps are - * required. - * Usually shouldn't be __cold. + * \brief Sets component audio stream parameters. + * \param[in,out] dev Component device. + * \param[in,out] params Audio (PCM) stream parameters to be set. + * \return 0 on success, negative error code on failure. */ int (*params)(struct comp_dev *dev, struct sof_ipc_stream_params *params); /** - * Fetches hardware stream parameters. - * @param dev Component device. - * @param params Receives copy of stream parameters retrieved from - * DAI hw settings. - * @param dir Stream direction (see enum sof_ipc_stream_direction). - * - * Mandatory for components that allocate DAI. - * Usually can be __cold. + * \brief Fetches hardware stream parameters. + * \param[in] dev Component device. + * \param[out] params Receives copy of stream parameters retrieved from DAI HW settings. + * \param[in] dir Stream direction (enum sof_ipc_stream_direction). + * \return 0 on success, negative error code on failure. */ int (*dai_get_hw_params)(struct comp_dev *dev, struct sof_ipc_stream_params *params, int dir); /** - * Configures attached DAI. - * @param dev Component device. - * @param dai_config DAI configuration. - * - * Mandatory for components that allocate DAI. - * Usually can be __cold. + * \brief Configures attached DAI. + * \param[in,out] dd DAI data context. + * \param[in,out] dev Component device. + * \param[in] dai_config DAI configuration. + * \param[in] dai_spec_config DAI specific configuration data. + * \return 0 on success, negative error code on failure. */ int (*dai_config)(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai *dai_config, const void *dai_spec_config); #if CONFIG_IPC_MAJOR_3 || CONFIG_LIBRARY /** - * Used to pass standard and bespoke commands (with optional data). - * @param dev Component device. - * @param cmd Command. - * @param data Command data. - * @param max_data_size Max size of returned data acceptable by the - * caller in case of 'get' commands. + * \brief Used to pass standard and bespoke commands (with optional data). + * \param[in,out] dev Component device. + * \param[in] cmd Command. + * \param[in,out] data Command data. + * \param[in] max_data_size Max size of returned data acceptable by caller for 'get' commands. + * \return 0 on success, negative error code on failure. */ int (*cmd)(struct comp_dev *dev, int cmd, void *data, int max_data_size); #endif /** - * Trigger, atomic - used to start/stop/pause stream operations. - * @param dev Component device. - * @param cmd Command, one of COMP_TRIGGER_... - * - * Usually shouldn't be __cold. + * \brief Trigger, atomic - used to start/stop/pause stream operations. + * \param[in,out] dev Component device. + * \param[in] cmd Command, one of COMP_TRIGGER_... + * \return 0 on success, negative error code on failure. */ int (*trigger)(struct comp_dev *dev, int cmd); /** - * Prepares component after params are set. - * @param dev Component device. - * - * Prepare should be used to get the component ready for starting - * processing after it's hw_params are known or after an XRUN. - * Usually shouldn't be __cold. + * \brief Prepares component after params are set. + * \param[in,out] dev Component device. + * \return 0 on success, negative error code on failure. */ int (*prepare)(struct comp_dev *dev); /** - * Resets component. - * @param dev Component device. - * - * Resets the component state and any hw_params to default component - * state. Should also free any resources acquired during hw_params. - * Usually shouldn't be __cold. + * \brief Resets component. + * \param[in,out] dev Component device. + * \return 0 on success, negative error code on failure. */ int (*reset)(struct comp_dev *dev); /** - * Copy and process stream data from source to sink buffers. - * @param dev Component device. - * @return Number of copied frames. - * - * Usually shouldn't be __cold. + * \brief Copy and process stream data from source to sink buffers. + * \param[in,out] dev Component device. + * \return Number of copied frames, or negative error code on failure. */ int (*copy)(struct comp_dev *dev); /** - * Retrieves component rendering position. - * @param dev Component device. - * @param posn Receives reported position. - * - * Usually shouldn't be __cold. + * \brief Retrieves component rendering position. + * \param[in] dev Component device. + * \param[out] posn Receives reported position. + * \return 0 on success, negative error code on failure. */ int (*position)(struct comp_dev *dev, struct sof_ipc_stream_posn *posn); /** - * Gets attribute in component. - * @param dev Component device. - * @param type Attribute type. - * @param value Attribute value. - * @return 0 if succeeded, error code otherwise. - * - * Usually can be __cold. + * \brief Gets attribute in component. + * \param[in] dev Component device. + * \param[in] type Attribute type. + * \param[out] value Attribute value buffer. + * \return 0 if succeeded, error code otherwise. */ int (*get_attribute)(struct comp_dev *dev, uint32_t type, void *value); /** - * Sets attribute in component. - * @param dev Component device. - * @param type Attribute type. - * @param value Attribute value. - * @return 0 if succeeded, error code otherwise. - * - * Usually can be __cold. + * \brief Sets attribute in component. + * \param[in,out] dev Component device. + * \param[in] type Attribute type. + * \param[in] value Attribute value. + * \return 0 if succeeded, error code otherwise. */ int (*set_attribute)(struct comp_dev *dev, uint32_t type, void *value); /** - * Configures timestamping in attached DAI. - * @param dev Component device. - * - * Mandatory for components that allocate DAI. - * Usually can be __cold. + * \brief Configures timestamping in attached DAI. + * \param[in,out] dev Component device. + * \return 0 on success, negative error code on failure. */ int (*dai_ts_config)(struct comp_dev *dev); /** - * Starts timestamping. - * @param dev Component device. - * - * Mandatory for components that allocate DAI. - * Usually can be __cold. + * \brief Starts timestamping. + * \param[in,out] dev Component device. + * \return 0 on success, negative error code on failure. */ int (*dai_ts_start)(struct comp_dev *dev); /** - * Stops timestamping. - * @param dev Component device. - * - * Mandatory for components that allocate DAI. - * Usually can be __cold. + * \brief Stops timestamping. + * \param[in,out] dev Component device. + * \return 0 on success, negative error code on failure. */ int (*dai_ts_stop)(struct comp_dev *dev); /** - * Gets timestamp. - * @param dev Component device. - * @param tsd Receives timestamp data. - * - * Mandatory for components that allocate DAI. - * Usually shouldn't be __cold. + * \brief Gets timestamp. + * \param[in] dev Component device. + * \param[out] tsd Receives timestamp data. + * \return 0 on success, negative error code on failure. */ #if CONFIG_ZEPHYR_NATIVE_DRIVERS int (*dai_ts_get)(struct comp_dev *dev, struct dai_ts_data *tsd); @@ -510,36 +459,30 @@ struct comp_ops { #endif /** - * Bind, atomic - used to notify component of bind event. - * @param dev Component device. - * @param data Bind info - * - * Usually can be __cold. + * \brief Bind, atomic - used to notify component of bind event. + * \param[in,out] dev Component device. + * \param[in] bind_data Bind info. + * \return 0 on success, negative error code on failure. */ int (*bind)(struct comp_dev *dev, const struct bind_info *bind_data); /** - * Unbind, atomic - used to notify component of unbind event. - * @param dev Component device. - * @param data unBind info - * - * Usually can be __cold. + * \brief Unbind, atomic - used to notify component of unbind event. + * \param[in,out] dev Component device. + * \param[in] unbind_data Unbind info. + * \return 0 on success, negative error code on failure. */ int (*unbind)(struct comp_dev *dev, const struct bind_info *unbind_data); /** - * Gets config in component. - * @param dev Component device - * @param param_id param id for each component - * @param first_block first block of large block. - * @param last_block last block of large block. - * @param data_offset block offset filled by callee. - * @param data block data. - * @return 0 if succeeded, error code otherwise. - * - * Callee fills up *data with config data and save the config - * size in *data_offset for host to reconstruct the config - * Usually can be __cold. + * \brief Gets large config in component. + * \param[in,out] dev Component device. + * \param[in] param_id Parameter ID for each component. + * \param[in] first_block First block of large block. + * \param[in] last_block Last block of large block. + * \param[in,out] data_offset Block offset filled by callee. + * \param[out] data Block data buffer. + * \return 0 if succeeded, error code otherwise. */ int (*get_large_config)(struct comp_dev *dev, uint32_t param_id, bool first_block, @@ -548,19 +491,14 @@ struct comp_ops { char *data); /** - * Set config in component. - * @param dev Component device - * @param param_id param id for each component - * @param first_block first block of large block. - * @param last_block last block of large block. - * @param data_offset block offset in large block. - * @param data block data. - * @return 0 if succeeded, error code otherwise. - * - * Host divides large block into small blocks and sends them - * to fw. The data_offset indicates the offset in the large - * block data. - * Usually can be __cold. + * \brief Set large config in component. + * \param[in,out] dev Component device. + * \param[in] param_id Parameter ID for each component. + * \param[in] first_block First block of large block. + * \param[in] last_block Last block of large block. + * \param[in] data_offset Block offset in large block. + * \param[in] data Block data payload. + * \return 0 if succeeded, error code otherwise. */ int (*set_large_config)(struct comp_dev *dev, uint32_t param_id, bool first_block, @@ -569,13 +507,11 @@ struct comp_ops { const char *data); /** - * Returns total data processed in number bytes. - * @param dev Component device - * @param stream_no Index of input/output stream - * @param input Selects between input (true) or output (false) stream direction - * @return total data processed if succeeded, 0 otherwise. - * - * Usually shouldn't be __cold. + * \brief Returns total data processed in number of bytes. + * \param[in] dev Component device. + * \param[in] stream_no Index of input/output stream. + * \param[in] input Selects between input (true) or output (false) stream direction. + * \return Total data processed if succeeded, 0 otherwise. */ uint64_t (*get_total_data_processed)(struct comp_dev *dev, uint32_t stream_no, bool input); }; @@ -612,113 +548,95 @@ struct comp_driver_info { struct list_item list; /**< list of component drivers */ }; -#define COMP_PROCESSING_DOMAIN_LL 0 -#define COMP_PROCESSING_DOMAIN_DP 1 +/** \name Component processing domains + * @{ + */ +#define COMP_PROCESSING_DOMAIN_LL 0 /**< Low latency processing domain */ +#define COMP_PROCESSING_DOMAIN_DP 1 /**< Data processing / worker thread domain */ +/** @}*/ /** - * Audio component base configuration from IPC at creation. + * \brief Audio component base configuration from IPC at creation. */ struct comp_ipc_config { - uint32_t core; /**< core we run on */ - uint32_t id; /**< component id */ - uint32_t pipeline_id; /**< component pipeline id */ - uint32_t proc_domain; /**< processing domain - LL or DP */ - enum sof_comp_type type; /**< component type */ - uint32_t periods_sink; /**< 0 means variable */ - uint32_t periods_source; /**< 0 means variable */ - uint32_t frame_fmt; /**< SOF_IPC_FRAME_ */ - uint32_t xrun_action; /**< action we should take on XRUN */ + uint32_t core; /**< Core we run on */ + uint32_t id; /**< Component ID */ + uint32_t pipeline_id; /**< Component pipeline ID */ + uint32_t proc_domain; /**< Processing domain (COMP_PROCESSING_DOMAIN_*) */ + enum sof_comp_type type; /**< Component type (SOF_COMP_*) */ + uint32_t periods_sink; /**< Sink periods (0 means variable) */ + uint32_t periods_source; /**< Source periods (0 means variable) */ + uint32_t frame_fmt; /**< Frame format (SOF_IPC_FRAME_*) */ + uint32_t xrun_action; /**< Action to take on XRUN */ #if CONFIG_IPC_MAJOR_4 - bool ipc_extended_init; /**< true if extended init is included in ipc payload */ - uint32_t ipc_config_size; /**< size of a config received by ipc */ + bool ipc_extended_init; /**< True if extended init is included in IPC payload */ + uint32_t ipc_config_size; /**< Size of config received by IPC */ #endif }; +/** + * \brief Component performance measurement tracking data. + */ struct comp_perf_data { - /* maximum measured cpc on run-time. - * - * if current measured cpc exceeds peak_of_measured_cpc_ then - * ResoruceEvent(BUDGET_VIOLATION) notification must be send. - * Otherwise there is no new information for host to care about - */ - size_t peak_of_measured_cpc; - /* Pointer to performance data structure. */ - struct perf_data_item_comp *perf_data_item; + size_t peak_of_measured_cpc; /**< Maximum measured CPC at runtime */ + struct perf_data_item_comp *perf_data_item; /**< Pointer to performance data item */ }; /** - * Audio component base device "class" - * - used by other component types. + * \brief Audio component base device "class" used by all other component types. */ struct comp_dev { - /* runtime */ - uint16_t state; /**< COMP_STATE_ */ - uint32_t frames; /**< number of frames we copy to sink */ - bool expect_eos; /**< end of stream expected */ - struct pipeline *pipeline; /**< pipeline we belong to */ - - struct task *task; /**< component's processing task used - * 1) for components running on different core - * than the rest of the pipeline - * 2) for all DP tasks - */ - uint32_t size; /**< component's allocated size */ - uint32_t period; /**< component's processing period - * for LL modules is set to LL pipeline's period - * for DP module its meaning is "the time the module MUST - * provide data that allows the following module to perform - * without glitches" - */ - uint32_t priority; /**< component's processing priority */ - bool is_shared; /**< indicates whether component is shared - * across cores - */ + uint16_t state; /**< Component state (COMP_STATE_*) */ + uint32_t frames; /**< Number of frames copied to sink */ + bool expect_eos; /**< End of stream expected flag */ + struct pipeline *pipeline; /**< Parent pipeline reference */ + + struct task *task; /**< Component processing task (cross-core or DP) */ + uint32_t size; /**< Component allocated size in bytes */ + uint32_t period; /**< Component processing period in microseconds */ + uint32_t priority; /**< Component processing priority */ + bool is_shared; /**< True if component is shared across cores */ struct comp_ipc_config ipc_config; /**< Component IPC configuration */ #if !CONFIG_ZEPHYR_LOG - struct tr_ctx tctx; /**< trace settings */ + struct tr_ctx tctx; /**< Trace settings */ #endif /* common runtime configuration for downstream/upstream */ - uint32_t direction; /**< enum sof_ipc_stream_direction */ - bool direction_set; /**< flag indicating that the direction has been set */ + uint32_t direction; /**< Stream direction (enum sof_ipc_stream_direction) */ + bool direction_set; /**< Flag indicating that direction has been set */ - const struct comp_driver *drv; /**< driver */ + const struct comp_driver *drv; /**< Component driver */ - struct processing_module *mod; /**< self->mod->dev == self, NULL if component is not using - * module adapter - */ + struct processing_module *mod; /**< Module adapter reference */ /* lists */ - struct list_item bsource_list; /**< list of source buffers */ - struct list_item bsink_list; /**< list of sink buffers */ + struct list_item bsource_list; /**< List of source buffers */ + struct list_item bsink_list; /**< List of sink buffers */ /* performance data*/ - struct comp_perf_data perf_data; - /* Input Buffer Size for pin 0, add array for other pins if needed */ - size_t ibs; - /* Output Buffers Size for pin 0, add array for other pins if needed */ - size_t obs; - /* max dsp cycles per chunk */ - size_t cpc; - /* size of 1ms for input format in bytes */ - size_t ll_chunk_size : 16; + struct comp_perf_data perf_data; /**< Performance data */ + size_t ibs; /**< Input Buffer Size for pin 0 */ + size_t obs; /**< Output Buffer Size for pin 0 */ + size_t cpc; /**< Max DSP cycles per chunk */ + size_t ll_chunk_size : 16; /**< Size of 1ms input format chunk in bytes */ /* private data - core does not touch this */ - void *priv_data; /**< private data */ + void *priv_data; /**< Driver private data */ #if CONFIG_PERFORMANCE_COUNTERS_COMPONENT - struct perf_cnt_data pcd; + struct perf_cnt_data pcd; /**< Performance counter data */ #endif #if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL - int32_t kcps_inc[CONFIG_CORE_COUNT]; + int32_t kcps_inc[CONFIG_CORE_COUNT]; /**< KCPS clock demand per core */ #endif }; /** - * Get a pointer to the first comp_buffer object providing data to the component - * The function will return NULL if there's no data provider + * \brief Get a pointer to the first comp_buffer object providing data to the component. + * \param[in] component Target component device. + * \return Pointer to first producer comp_buffer, or NULL if none. */ static inline struct comp_buffer *comp_dev_get_first_data_producer(struct comp_dev *component) { @@ -727,9 +645,10 @@ static inline struct comp_buffer *comp_dev_get_first_data_producer(struct comp_d } /** - * Get a pointer to the next comp_buffer object providing data to the component - * The function will return NULL if there're no more data providers - * _save version also checks if producer != NULL + * \brief Get a pointer to the next comp_buffer object providing data to the component. + * \param[in] component Target component device. + * \param[in] producer Current producer buffer. + * \return Pointer to next producer comp_buffer, or NULL if none. */ static inline struct comp_buffer *comp_dev_get_next_data_producer(struct comp_dev *component, struct comp_buffer *producer) @@ -738,6 +657,12 @@ static inline struct comp_buffer *comp_dev_get_next_data_producer(struct comp_de list_item(producer->sink_list.next, struct comp_buffer, sink_list); } +/** + * \brief Safely get a pointer to the next comp_buffer object providing data to the component. + * \param[in] component Target component device. + * \param[in] producer Current producer buffer, or NULL. + * \return Pointer to next producer comp_buffer, or NULL if none. + */ static inline struct comp_buffer *comp_dev_get_next_data_producer_safe(struct comp_dev *component, struct comp_buffer *producer) { @@ -745,8 +670,9 @@ static inline struct comp_buffer *comp_dev_get_next_data_producer_safe(struct co } /** - * Get a pointer to the first comp_buffer object receiving data from the component - * The function will return NULL if there's no data consumers + * \brief Get a pointer to the first comp_buffer object receiving data from the component. + * \param[in] component Target component device. + * \return Pointer to first consumer comp_buffer, or NULL if none. */ static inline struct comp_buffer *comp_dev_get_first_data_consumer(struct comp_dev *component) { @@ -755,9 +681,10 @@ static inline struct comp_buffer *comp_dev_get_first_data_consumer(struct comp_d } /** - * Get a pointer to the next comp_buffer object receiving data from the component - * The function will return NULL if there're no more data consumers - * _safe version also checks if consumer is != NULL + * \brief Get a pointer to the next comp_buffer object receiving data from the component. + * \param[in] component Target component device. + * \param[in] consumer Current consumer buffer. + * \return Pointer to next consumer comp_buffer, or NULL if none. */ static inline struct comp_buffer *comp_dev_get_next_data_consumer(struct comp_dev *component, struct comp_buffer *consumer) @@ -766,25 +693,33 @@ static inline struct comp_buffer *comp_dev_get_next_data_consumer(struct comp_de list_item(consumer->source_list.next, struct comp_buffer, source_list); } +/** + * \brief Safely get a pointer to the next comp_buffer object receiving data from the component. + * \param[in] component Target component device. + * \param[in] consumer Current consumer buffer, or NULL. + * \return Pointer to next consumer comp_buffer, or NULL if none. + */ static inline struct comp_buffer *comp_dev_get_next_data_consumer_safe(struct comp_dev *component, struct comp_buffer *consumer) { return consumer ? comp_dev_get_next_data_consumer(component, consumer) : NULL; } -/* - * a macro for easy iteration through component's list of producers +/** + * \brief Macro to iterate through component's list of producer buffers. + * \param[in] _dev Target component device. + * \param[out] _producer Buffer pointer iterator variable. */ #define comp_dev_for_each_producer(_dev, _producer) \ for (_producer = comp_dev_get_first_data_producer(_dev); \ _producer != NULL; \ _producer = comp_dev_get_next_data_producer(_dev, _producer)) -/* - * a macro for easy iteration through component's list of producers - * allowing deletion of a buffer during iteration - * - * additional "safe storage" pointer to struct comp_buffer must be provided +/** + * \brief Safe macro to iterate through component's producer buffers allowing buffer deletion. + * \param[in] _dev Target component device. + * \param[out] _producer Buffer pointer iterator variable. + * \param[out] _next_producer Storage pointer for next buffer. */ #define comp_dev_for_each_producer_safe(_dev, _producer, _next_producer) \ for (_producer = comp_dev_get_first_data_producer(_dev), \ @@ -793,19 +728,21 @@ static inline struct comp_buffer *comp_dev_get_next_data_consumer_safe(struct co _producer = _next_producer, \ _next_producer = comp_dev_get_next_data_producer_safe(_dev, _producer)) -/* - * a macro for easy iteration through component's list of consumers +/** + * \brief Macro to iterate through component's list of consumer buffers. + * \param[in] _dev Target component device. + * \param[out] _consumer Buffer pointer iterator variable. */ #define comp_dev_for_each_consumer(_dev, _consumer) \ for (_consumer = comp_dev_get_first_data_consumer(_dev); \ _consumer != NULL; \ _consumer = comp_dev_get_next_data_consumer(_dev, _consumer)) \ -/* - * a macro for easy iteration through component's list of consumers - * allowing deletion of a buffer during iteration - * - * additional "safe storage" pointer to struct comp_buffer must be provided +/** + * \brief Safe macro to iterate through component's consumer buffers allowing buffer deletion. + * \param[in] _dev Target component device. + * \param[out] _consumer Buffer pointer iterator variable. + * \param[out] _next_consumer Storage pointer for next buffer. */ #define comp_dev_for_each_consumer_safe(_dev, _consumer, _next_consumer) \ for (_consumer = comp_dev_get_first_data_consumer(_dev), \ @@ -814,29 +751,23 @@ static inline struct comp_buffer *comp_dev_get_next_data_consumer_safe(struct co _consumer = _next_consumer, \ _next_consumer = comp_dev_get_next_data_consumer_safe(_dev, _consumer)) -/** @}*/ - /* Common helper function used internally by the component implementations * begin here. */ -/** \addtogroup audio_pipeline_api - * @{ - */ - /** \brief Struct for use with comp_get_copy_limits() function. */ struct comp_copy_limits { - int frames; - int source_bytes; - int sink_bytes; - int source_frame_bytes; - int sink_frame_bytes; + int frames; /**< Number of frames that can be copied */ + int source_bytes; /**< Available bytes in source */ + int sink_bytes; /**< Free bytes in sink */ + int source_frame_bytes; /**< Frame size in bytes in source */ + int sink_frame_bytes; /**< Frame size in bytes in sink */ }; /** - * Retrieves Component id from device. - * @param dev Device. - * @return Component id. + * \brief Retrieves Component ID from device. + * \param[in] dev Component device. + * \return Component ID. */ static inline uint32_t dev_comp_id(const struct comp_dev *dev) { @@ -844,9 +775,9 @@ static inline uint32_t dev_comp_id(const struct comp_dev *dev) } /** - * Retrieves Component pipeline id from device. - * @param dev Device. - * @return Component pipeline id. + * \brief Retrieves Component pipeline ID from device. + * \param[in] dev Component device. + * \return Component pipeline ID. */ static inline uint32_t dev_comp_pipe_id(const struct comp_dev *dev) { @@ -854,9 +785,9 @@ static inline uint32_t dev_comp_pipe_id(const struct comp_dev *dev) } /** - * Retrieves component type from device. - * @param dev Device. - * @return Component type. + * \brief Retrieves component type from device. + * \param[in] dev Component device. + * \return Component type (enum sof_comp_type). */ static inline enum sof_comp_type dev_comp_type(const struct comp_dev *dev) { @@ -864,10 +795,10 @@ static inline enum sof_comp_type dev_comp_type(const struct comp_dev *dev) } /** - * Initialize common part of a component device - * @param drv Parent component driver. - * @param dev Device. - * @param bytes Size of the component device in bytes. + * \brief Initialize common part of a component device. + * \param[in] drv Parent component driver. + * \param[in,out] dev Component device. + * \param[in] bytes Size of the component device in bytes. */ static inline void comp_init(const struct comp_driver *drv, struct comp_dev *dev, size_t bytes) @@ -884,10 +815,10 @@ static inline void comp_init(const struct comp_driver *drv, } /** - * Allocates memory for the component device and initializes common part. - * @param drv Parent component driver. - * @param bytes Size of the component device in bytes. - * @return Pointer to the component device. + * \brief Allocates memory for the component device and initializes common part. + * \param[in] drv Parent component driver. + * \param[in] bytes Size of the component device in bytes. + * \return Pointer to the allocated component device, or NULL on failure. */ static inline struct comp_dev *comp_alloc(const struct comp_driver *drv, size_t bytes) { @@ -909,12 +840,11 @@ static inline struct comp_dev *comp_alloc(const struct comp_driver *drv, size_t } /** - * Frees memory allocated for component device. + * \brief Frees memory allocated for component device. * - * This is a counterpart to comp_alloc() and not to be confused with - * comp_free(). + * This is a counterpart to comp_alloc() and not to be confused with comp_free(). * - * @param dev Pointer to the component device. + * \param[in,out] dev Pointer to the component device to free. */ static inline void comp_free_device(struct comp_dev *dev) { @@ -922,8 +852,9 @@ static inline void comp_free_device(struct comp_dev *dev) } /** - * \brief Module adapter associated with a component - * @param dev Component device + * \brief Module adapter associated with a component. + * \param[in] dev Component device. + * \return Pointer to associated processing module, or NULL if none. */ static inline struct processing_module *comp_mod(const struct comp_dev *dev) { @@ -932,16 +863,16 @@ static inline struct processing_module *comp_mod(const struct comp_dev *dev) /** * \brief Assigns private data to component device. - * @param c Component device. - * @param data Private data. + * \param[in,out] c Component device. + * \param[in] data Private data pointer. */ #define comp_set_drvdata(c, data) \ (c->priv_data = data) /** * \brief Retrieves driver private data from component device. - * @param c Component device. - * @return Private data. + * \param[in] c Component device. + * \return Private data pointer. */ #define comp_get_drvdata(c) \ (c->priv_data) @@ -1010,34 +941,33 @@ void sys_comp_module_volume_interface_init(void); */ /** - * Registers the component driver on the list of available components. - * @param drv Component driver to be registered. - * @return 0 if succeeded, error code otherwise. + * \brief Registers the component driver on the list of available components. + * \param[in,out] drv Component driver to be registered. + * \return 0 if succeeded, error code otherwise. */ int comp_register(struct comp_driver_info *drv); /** - * Unregisters the component driver from the list of available components. - * @param drv Component driver to be unregistered. + * \brief Unregisters the component driver from the list of available components. + * \param[in,out] drv Component driver to be unregistered. */ void comp_unregister(struct comp_driver_info *drv); /** - * Set adapter ops for a dynamically created driver. - * - * @param drv Component driver to update. - * @param ops Module interface operations. - * @return 0 or a negative error code + * \brief Set adapter ops for a dynamically created driver. + * \param[in,out] drv Component driver to update. + * \param[in] ops Module interface operations. + * \return 0 or a negative error code. */ int comp_set_adapter_ops(const struct comp_driver *drv, const struct module_interface *ops); /** @}*/ /** - * Component state set. - * @param dev Component device. - * @param cmd Command, one of COMP_TRIGGER_.... - * @return 0 if succeeded, error code otherwise. + * \brief Component state transition handling. + * \param[in,out] dev Component device. + * \param[in] cmd Command, one of COMP_TRIGGER_... + * \return 0 if succeeded, error code otherwise. * * This function should be called by a component implementation at the beginning * of its state transition to verify whether the trigger is valid in the @@ -1054,7 +984,11 @@ int comp_set_adapter_ops(const struct comp_driver *drv, const struct module_inte */ int comp_set_state(struct comp_dev *dev, int cmd); -/* \brief Set component period frames */ +/** + * \brief Set component period frames based on sample rate and period. + * \param[in,out] current Target component device. + * \param[in] rate Sample rate in Hz. + */ static inline void component_set_nearest_period_frames(struct comp_dev *current, uint32_t rate) { @@ -1093,10 +1027,10 @@ static inline void component_set_nearest_period_frames(struct comp_dev *current, */ /** - * Called by the component device when underrun is detected. - * @param dev Component device. - * @param source Source buffer. - * @param copy_bytes Requested size of data to be available. + * \brief Called by the component device when underrun is detected. + * \param[in,out] dev Component device. + * \param[in] source Source buffer. + * \param[in] copy_bytes Requested size of data in bytes. */ static inline void comp_underrun(struct comp_dev *dev, struct comp_buffer *source, @@ -1116,10 +1050,10 @@ static inline void comp_underrun(struct comp_dev *dev, } /** - * Called by component device when overrun is detected. - * @param dev Component device. - * @param sink Sink buffer. - * @param copy_bytes Requested size of free space to be available. + * \brief Called by component device when overrun is detected. + * \param[in,out] dev Component device. + * \param[in] sink Sink buffer. + * \param[in] copy_bytes Requested size of free space in bytes. */ static inline void comp_overrun(struct comp_dev *dev, struct comp_buffer *sink, uint32_t copy_bytes) @@ -1138,38 +1072,34 @@ static inline void comp_overrun(struct comp_dev *dev, struct comp_buffer *sink, /** @}*/ /** - * Computes source to sink copy operation boundaries including maximum number - * of frames that can be transferred (data available in source vs. free space - * available in sink). + * \brief Computes source to sink copy operation boundaries including maximum number + * of frames that can be transferred. * - * @param[in] source Source buffer. - * @param[in] sink Sink buffer. - * @param[out] cl Current copy limits. + * \param[in] source Source buffer. + * \param[in] sink Sink buffer. + * \param[out] cl Current copy limits. */ void comp_get_copy_limits(struct comp_buffer *source, struct comp_buffer *sink, struct comp_copy_limits *cl); /** - * Computes source to sink copy operation boundaries including maximum number - * of frames aligned with requirement that can be transferred (data available in - * source vs. free space available in sink). + * \brief Computes source to sink copy operation boundaries including maximum number + * of frames aligned with requirement that can be transferred. * - * @param[in] source Buffer of source. - * @param[in] sink Buffer of sink. - * @param[out] cl Current copy limits. + * \param[in] source Buffer of source. + * \param[in] sink Buffer of sink. + * \param[out] cl Current copy limits. */ void comp_get_copy_limits_frame_aligned(const struct comp_buffer *source, const struct comp_buffer *sink, struct comp_copy_limits *cl); /** - * Get component state. - * - * @param dev Component from which user wants to read status. - * - * @retval COMP_STATE_NOT_EXIST if there's no connected component - * @return state of the component + * \brief Get component state. + * \param[in] dev Component from which user wants to read status. + * \retval COMP_STATE_NOT_EXIST If there's no connected component. + * \return State of the component (COMP_STATE_*). */ static inline int comp_get_state(const struct comp_dev *dev) { @@ -1179,12 +1109,10 @@ static inline int comp_get_state(const struct comp_dev *dev) } /** - * @brief helper, provide state of a component connected to a buffer as a data provider - * - * @param buffer a buffer to be checked - * - * @retval COMP_STATE_NOT_EXIST if there's no connected component - * @return state of the component + * \brief Provide state of a component connected to a buffer as a data provider. + * \param[in] buffer Interconnect buffer to be checked. + * \retval COMP_STATE_NOT_EXIST If there's no connected component. + * \return State of the component. */ static inline int comp_buffer_get_source_state(const struct comp_buffer *buffer) { @@ -1192,12 +1120,10 @@ static inline int comp_buffer_get_source_state(const struct comp_buffer *buffer) } /** - * @brief helper, provide state of a component connected to a buffer as a data consumer - * - * @param buffer a buffer to be checked - * - * @retval COMP_STATE_NOT_EXIST if there's no connected component - * @return state of the component + * \brief Provide state of a component connected to a buffer as a data consumer. + * \param[in] buffer Interconnect buffer to be checked. + * \retval COMP_STATE_NOT_EXIST If there's no connected component. + * \return State of the component. */ static inline int comp_buffer_get_sink_state(const struct comp_buffer *buffer) { @@ -1205,46 +1131,45 @@ static inline int comp_buffer_get_sink_state(const struct comp_buffer *buffer) } /** - * Warning: duplicate declaration in topology.h + * \brief Verify and set component audio parameters. * - * Called by component in params() function in order to set and update some of - * downstream (playback) or upstream (capture) buffer parameters with pcm - * parameters. There is a possibility to specify which of parameters won't be - * overwritten (e.g. SRC component should not overwrite rate parameter, because - * it is able to change it). + * Called by component in params() function in order to set and update some of + * downstream (playback) or upstream (capture) buffer parameters with PCM + * parameters. * - * @param dev Component device - * @param flag Specifies which parameter should not be updated - * @param params pcm params + * \param[in,out] dev Component device. + * \param[in] flag Specifies which parameter should not be updated. + * \param[in,out] params PCM stream parameters. + * \return 0 on success, negative error code on failure. */ int comp_verify_params(struct comp_dev *dev, uint32_t flag, struct sof_ipc_stream_params *params); -/** @}*/ - /** - * Update ibs, obs, cpc, ll chunk size for component. - * - * @param dev Component to update. + * \brief Update IBS, OBS, CPC, LL chunk size for component. + * \param[in,out] dev Component to update. */ void comp_update_ibs_obs_cpc(struct comp_dev *dev); /** - * If component has assigned slot in performance measurement window, - * initialize its fields. - * @param dev Component to init. + * \brief Initialize performance data fields if component has assigned slot in measurement window. + * \param[in,out] dev Component to init. */ void comp_init_performance_data(struct comp_dev *dev); /** - * Update performance data entry for component. Also checks for budget violation. - * - * @param dev Component to update. - * @param cycles_used Execution time. - * @return true if budget violation occurred + * \brief Update performance data entry for component and check for budget violation. + * \param[in,out] dev Component to update. + * \param[in] cycles_used Execution time. + * \return True if budget violation occurred, false otherwise. */ bool comp_update_performance_data(struct comp_dev *dev, uint32_t cycles_used); +/** + * \brief Get memory region flag for component buffer allocations. + * \param[in] drv Component driver pointer. + * \return Memory flag (SOF_MEM_FLAG_*). + */ static inline int user_get_buffer_memory_region(const struct comp_driver *drv) { #if CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP @@ -1253,4 +1178,7 @@ static inline int user_get_buffer_memory_region(const struct comp_driver *drv) return SOF_MEM_FLAG_USER; #endif } + +/** @}*/ + #endif /* __SOF_AUDIO_COMPONENT_H__ */ diff --git a/src/include/sof/audio/component_ext.h b/src/include/sof/audio/component_ext.h index 4bb88cce72e2..74562203864e 100644 --- a/src/include/sof/audio/component_ext.h +++ b/src/include/sof/audio/component_ext.h @@ -19,7 +19,7 @@ #include #include -/** \addtogroup audio_pipeline_api +/** \addtogroup component_infra_api * @{ */ @@ -28,19 +28,35 @@ struct comp_driver_list { struct list_item list; /**< list of component drivers */ }; -/** \brief Retrieves the component device buffer list. */ +/** \brief Retrieves the component device buffer list based on direction. + * \param[in] comp Component device pointer. + * \param[in] dir Direction (PPL_DIR_DOWNSTREAM or PPL_DIR_UPSTREAM). + * \return Pointer to sink list or source list. + */ #define comp_buffer_list(comp, dir) \ ((dir) == PPL_DIR_DOWNSTREAM ? &(comp)->bsink_list : \ &(comp)->bsource_list) -/** See comp_ops::new */ #if CONFIG_IPC_MAJOR_3 +/** + * \brief Instantiate a new component device from IPC3 descriptor. + * \param[in] comp IPC3 component descriptor. + * \return Pointer to new component device, or NULL on failure. + */ struct comp_dev *comp_new(struct sof_ipc_comp *comp); #elif CONFIG_IPC_MAJOR_4 +/** + * \brief Instantiate a new component device from IPC4 module initialization descriptor. + * \param[in] module_init IPC4 module initialization data. + * \return Pointer to new component device, or NULL on failure. + */ struct comp_dev *comp_new_ipc4(const struct ipc4_module_init_instance *module_init); #endif -/** See comp_ops::free */ +/** + * \brief Free component device via driver ops. + * \param[in,out] dev Component device to free. + */ static inline void comp_free(struct comp_dev *dev) { const struct comp_driver *drv = dev->drv; @@ -55,10 +71,10 @@ static inline void comp_free(struct comp_dev *dev) } /** - * Parameter init for component on other core. - * @param dev Component device. - * @param params Parameters to be set. - * @return 0 if succeeded, error code otherwise. + * \brief Parameter initialization for component on remote core. + * \param[in,out] dev Component device. + * \param[in] params Stream parameters to be set. + * \return 0 if succeeded, error code otherwise. */ static inline int comp_params_remote(struct comp_dev *dev, struct sof_ipc_stream_params *params) @@ -69,7 +85,12 @@ static inline int comp_params_remote(struct comp_dev *dev, return idc_send_msg(&msg, IDC_BLOCKING); } -/** See comp_ops::params */ +/** + * \brief Configure audio stream parameters for component device. + * \param[in,out] dev Component device. + * \param[in,out] params Audio (PCM) stream parameters to configure. + * \return 0 on success, negative error code on failure. + */ static inline int comp_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) { @@ -97,7 +118,13 @@ static inline int comp_params(struct comp_dev *dev, return ret; } -/** See comp_ops::dai_get_hw_params */ +/** + * \brief Retrieve DAI hardware parameters from component device. + * \param[in] dev Component device. + * \param[out] params Stream parameters to populate. + * \param[in] dir Stream direction (enum sof_ipc_stream_direction). + * \return 0 on success, negative error code on failure. + */ static inline int comp_dai_get_hw_params(struct comp_dev *dev, struct sof_ipc_stream_params *params, int dir) @@ -109,7 +136,14 @@ static inline int comp_dai_get_hw_params(struct comp_dev *dev, } #if CONFIG_IPC_MAJOR_3 -/** See comp_ops::cmd */ +/** + * \brief Dispatch IPC3 command to component device. + * \param[in,out] dev Component device. + * \param[in] cmd Command code. + * \param[in,out] data Command data buffer. + * \param[in] max_data_size Maximum acceptable size of returned data. + * \return 0 on success, negative error code on failure. + */ static inline int comp_cmd(struct comp_dev *dev, int cmd, void *data, int max_data_size) { @@ -133,7 +167,10 @@ static inline int comp_cmd(struct comp_dev *dev, int cmd, void *data, #endif /** - * Runs comp_ops::trigger on the core the target component is assigned to. + * \brief Run trigger command on remote core for target component. + * \param[in,out] dev Component device. + * \param[in] cmd Trigger command (COMP_TRIGGER_*). + * \return 0 on success, negative error code on failure. */ static inline int comp_trigger_remote(struct comp_dev *dev, int cmd) { @@ -144,6 +181,12 @@ static inline int comp_trigger_remote(struct comp_dev *dev, int cmd) return idc_send_msg(&msg, IDC_BLOCKING); } +/** + * \brief Run trigger command locally on current core for target component. + * \param[in,out] dev Component device. + * \param[in] cmd Trigger command (COMP_TRIGGER_*). + * \return 0 on success, negative error code on failure. + */ static inline int comp_trigger_local(struct comp_dev *dev, int cmd) { int ret; @@ -170,7 +213,12 @@ static inline int comp_trigger_local(struct comp_dev *dev, int cmd) return ret; } -/** See comp_ops::trigger */ +/** + * \brief Dispatch trigger command to component (local or remote). + * \param[in,out] dev Component device. + * \param[in] cmd Trigger command (COMP_TRIGGER_*). + * \return 0 on success, negative error code on failure. + */ static inline int comp_trigger(struct comp_dev *dev, int cmd) { int ret; @@ -184,7 +232,11 @@ static inline int comp_trigger(struct comp_dev *dev, int cmd) return ret; } -/** Runs comp_ops::prepare on the target component's core */ +/** + * \brief Run prepare command on remote core for target component. + * \param[in,out] dev Component device. + * \return 0 on success, negative error code on failure. + */ static inline int comp_prepare_remote(struct comp_dev *dev) { struct idc_msg msg = { IDC_MSG_PREPARE, @@ -193,7 +245,11 @@ static inline int comp_prepare_remote(struct comp_dev *dev) return idc_send_msg(&msg, IDC_BLOCKING); } -/** See comp_ops::prepare */ +/** + * \brief Prepare component device for streaming (local or remote). + * \param[in,out] dev Component device. + * \return 0 on success, negative error code on failure. + */ static inline int comp_prepare(struct comp_dev *dev) { if (dev->drv->ops.prepare) @@ -203,14 +259,29 @@ static inline int comp_prepare(struct comp_dev *dev) return 0; } +/** + * \brief Process and copy audio data through component. + * \param[in,out] dev Component device. + * \return Number of copied frames, or negative error code on failure. + */ int comp_copy(struct comp_dev *dev); #if CONFIG_IPC_MAJOR_4 +/** + * \brief Remote payload for component get_attribute IPC4 message. + */ struct get_attribute_remote_payload { - uint32_t type; - void *value; + uint32_t type; /**< Attribute type (COMP_ATTR_*) */ + void *value; /**< Pointer to attribute value storage */ }; +/** + * \brief Retrieve component attribute from a remote core (IPC4). + * \param[in,out] dev Component device. + * \param[in] type Attribute type (COMP_ATTR_*). + * \param[out] value Pointer to buffer where attribute value is copied. + * \return 0 on success, negative error code on failure. + */ static inline int comp_ipc4_get_attribute_remote(struct comp_dev *dev, uint32_t type, void *value) { @@ -243,7 +314,13 @@ static inline int comp_ipc4_get_attribute_remote(struct comp_dev *dev, uint32_t } #endif /* CONFIG_IPC_MAJOR_4 */ -/** See comp_ops::get_attribute */ +/** + * \brief Get component attribute. + * \param[in,out] dev Component device. + * \param[in] type Attribute type (COMP_ATTR_*). + * \param[out] value Pointer to buffer where attribute value is returned. + * \return 0 on success, negative error code on failure. + */ static inline int comp_get_attribute(struct comp_dev *dev, uint32_t type, void *value) { @@ -262,7 +339,13 @@ static inline int comp_get_attribute(struct comp_dev *dev, uint32_t type, #endif } -/** See comp_ops::set_attribute */ +/** + * \brief Set component attribute. + * \param[in,out] dev Component device. + * \param[in] type Attribute type (COMP_ATTR_*). + * \param[in] value Pointer to attribute value to set. + * \return 0 on success, negative error code on failure. + */ static inline int comp_set_attribute(struct comp_dev *dev, uint32_t type, void *value) { @@ -272,7 +355,11 @@ static inline int comp_set_attribute(struct comp_dev *dev, uint32_t type, return 0; } -/** Runs comp_ops::reset on the target component's core */ +/** + * \brief Run reset command on remote core for target component. + * \param[in,out] dev Component device. + * \return 0 on success, negative error code on failure. + */ static inline int comp_reset_remote(struct comp_dev *dev) { struct idc_msg msg = { IDC_MSG_RESET, @@ -282,9 +369,9 @@ static inline int comp_reset_remote(struct comp_dev *dev) } /** - * Component reset and free runtime resources. - * @param dev Component device. - * @return 0 if succeeded, error code otherwise. + * \brief Reset component and free runtime resources (local or remote). + * \param[in,out] dev Component device. + * \return 0 on success, negative error code on failure. */ static inline int comp_reset(struct comp_dev *dev) { @@ -296,7 +383,13 @@ static inline int comp_reset(struct comp_dev *dev) } #if CONFIG_IPC_MAJOR_3 -/** See comp_ops::dai_config */ +/** + * \brief Configure DAI component. + * \param[in,out] dev Component device. + * \param[in] config IPC DAI configuration. + * \param[in] spec_config Spec-specific configuration data. + * \return 0 on success, negative error code on failure. + */ static inline int comp_dai_config(struct comp_dev *dev, struct ipc_config_dai *config, const void *spec_config) { @@ -308,6 +401,14 @@ static inline int comp_dai_config(struct comp_dev *dev, struct ipc_config_dai *c return 0; } #elif CONFIG_IPC_MAJOR_4 +/** + * \brief Configure DAI component (IPC4). + * \param[in,out] dd DAI driver data. + * \param[in,out] dev Component device. + * \param[in] config IPC DAI configuration. + * \param[in] spec_config Spec-specific configuration data. + * \return 0 on success, negative error code on failure. + */ static inline int comp_dai_config(struct dai_data *dd, struct comp_dev *dev, struct ipc_config_dai *config, const void *spec_config) { @@ -316,7 +417,13 @@ static inline int comp_dai_config(struct dai_data *dd, struct comp_dev *dev, #else #error Unknown IPC major version #endif -/** See comp_ops::position */ + +/** + * \brief Retrieve stream position from component. + * \param[in,out] dev Component device. + * \param[out] posn Stream position structure to populate. + * \return 0 on success, negative error code on failure. + */ static inline int comp_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn) { @@ -327,16 +434,19 @@ static inline int comp_position(struct comp_dev *dev, } /** - * Allocates and initializes audio component list. + * \brief Allocates and initializes audio component list. + * * To be called once at boot time. + * + * \param[in,out] sof SOF global system context. */ void sys_comp_init(struct sof *sof); /** - * Checks if two component devices belong to the same parent pipeline. - * @param current Component device. - * @param previous Another component device. - * @return 1 if children of the same pipeline, 0 otherwise. + * \brief Checks if two component devices belong to the same parent pipeline. + * \param[in] current Component device. + * \param[in] previous Another component device. + * \return 1 if children of the same pipeline, 0 otherwise. */ static inline int comp_is_single_pipeline(struct comp_dev *current, struct comp_dev *previous) @@ -345,9 +455,9 @@ static inline int comp_is_single_pipeline(struct comp_dev *current, } /** - * Checks if component device is active. - * @param current Component device. - * @return 1 if active, 0 otherwise. + * \brief Checks if component device is active. + * \param[in] current Component device. + * \return 1 if active, 0 otherwise. */ static inline int comp_is_active(struct comp_dev *current) { @@ -355,9 +465,9 @@ static inline int comp_is_active(struct comp_dev *current) } /** - * Returns component state based on requested command. - * @param cmd Request command. - * @return Component state. + * \brief Returns component state based on requested command. + * \param[in] cmd Request command (COMP_TRIGGER_*). + * \return Component state (COMP_STATE_*). */ static inline int comp_get_requested_state(int cmd) { @@ -390,8 +500,8 @@ static inline int comp_get_requested_state(int cmd) /** * \brief Returns endpoint type of given component. - * @param dev Component device - * @return Endpoint type, one of comp_endpoint_type. + * \param[in] dev Component device. + * \return Endpoint type, one of comp_endpoint_type (COMP_ENDPOINT_*). */ static inline int comp_get_endpoint_type(struct comp_dev *dev) { @@ -406,9 +516,9 @@ static inline int comp_get_endpoint_type(struct comp_dev *dev) } /** - * Called to check whether component schedules its pipeline. - * @param dev Component device. - * @return True if this is scheduling component, false otherwise. + * \brief Called to check whether component schedules its pipeline. + * \param[in] dev Component device. + * \return True if this is scheduling component, false otherwise. */ static inline bool comp_is_scheduling_source(struct comp_dev *dev) { @@ -416,8 +526,8 @@ static inline bool comp_is_scheduling_source(struct comp_dev *dev) } /** - * Called to mark component as shared between cores - * @param dev Component device. + * \brief Called to mark component as shared between cores. + * \param[in,out] dev Component device. */ static inline void comp_make_shared(struct comp_dev *dev) { @@ -425,8 +535,8 @@ static inline void comp_make_shared(struct comp_dev *dev) } /** - * Get the global component driver list. - * @return Pointer to the component driver list. + * \brief Get the global component driver list. + * \return Pointer to the component driver list. */ #ifdef CONFIG_SOF_USERSPACE_LL struct comp_driver_list *comp_drivers_get(void); @@ -438,6 +548,12 @@ static inline struct comp_driver_list *comp_drivers_get(void) #endif #if CONFIG_IPC_MAJOR_4 +/** + * \brief Send bind message to component on remote core (IPC4). + * \param[in,out] dev Component device. + * \param[in] bind_data Binding information. + * \return 0 on success, negative error code on failure. + */ static inline int comp_ipc4_bind_remote(struct comp_dev *dev, const struct bind_info *bind_data) { struct idc_msg msg = { IDC_MSG_BIND, @@ -448,6 +564,12 @@ static inline int comp_ipc4_bind_remote(struct comp_dev *dev, const struct bind_ } #endif +/** + * \brief Bind component to downstream/upstream component or buffer. + * \param[in,out] dev Component device. + * \param[in] bind_data Binding information. + * \return 0 on success, negative error code on failure. + */ static inline int comp_bind(struct comp_dev *dev, const struct bind_info *bind_data) { #if CONFIG_IPC_MAJOR_4 @@ -467,6 +589,12 @@ static inline int comp_bind(struct comp_dev *dev, const struct bind_info *bind_d } #if CONFIG_IPC_MAJOR_4 +/** + * \brief Send unbind message to component on remote core (IPC4). + * \param[in,out] dev Component device. + * \param[in] unbind_data Unbinding information. + * \return 0 on success, negative error code on failure. + */ static inline int comp_ipc4_unbind_remote(struct comp_dev *dev, const struct bind_info *unbind_data) { struct idc_msg msg = { IDC_MSG_UNBIND, @@ -477,6 +605,12 @@ static inline int comp_ipc4_unbind_remote(struct comp_dev *dev, const struct bin } #endif +/** + * \brief Unbind component from downstream/upstream component or buffer. + * \param[in,out] dev Component device. + * \param[in] unbind_data Unbinding information. + * \return 0 on success, negative error code on failure. + */ static inline int comp_unbind(struct comp_dev *dev, const struct bind_info *unbind_data) { #if CONFIG_IPC_MAJOR_4 @@ -496,6 +630,13 @@ static inline int comp_unbind(struct comp_dev *dev, const struct bind_info *unbi #endif } +/** + * \brief Retrieve total data processed by component. + * \param[in] dev Component device. + * \param[in] stream_no Stream index. + * \param[in] input True for input data, false for output data. + * \return Total processed data in bytes. + */ static inline uint64_t comp_get_total_data_processed(struct comp_dev *dev, uint32_t stream_no, bool input) { @@ -507,7 +648,12 @@ static inline uint64_t comp_get_total_data_processed(struct comp_dev *dev, uint3 return ret; } -/** Returns true if the component's pipeline matches the specified direction */ +/** + * \brief Returns true if the component's pipeline matches the specified direction. + * \param[in] comp Component device. + * \param[in] dir Stream direction (SOF_IPC_STREAM_PLAYBACK or SOF_IPC_STREAM_CAPTURE). + * \return True if matching direction, false otherwise. + */ static inline bool comp_same_dir(struct comp_dev *comp, enum sof_ipc_stream_direction dir) { int end_type = comp_get_endpoint_type(comp->pipeline->sink_comp); diff --git a/src/include/sof/audio/format_generic.h b/src/include/sof/audio/format_generic.h index f5f2179ecee0..3902fc244ed0 100644 --- a/src/include/sof/audio/format_generic.h +++ b/src/include/sof/audio/format_generic.h @@ -6,7 +6,7 @@ /** * @file sof/audio/format_generic.h * @brief Generic audio sample saturation helpers. - * @ingroup audio_pipeline_api + * @ingroup audio_format_api */ #ifndef __SOF_AUDIO_FORMAT_GENERIC_H__ @@ -14,10 +14,14 @@ #include +/** \addtogroup audio_format_api + * @{ + */ + /** - * @brief Saturate a 64-bit integer to signed 32-bit integer range. - * @param x Input 64-bit integer. - * @return Saturated 32-bit integer clamped between INT32_MIN and INT32_MAX. + * \brief Saturate a 64-bit integer to signed 32-bit integer range. + * \param[in] x Input 64-bit integer. + * \return Saturated 32-bit integer clamped between INT32_MIN and INT32_MAX. */ static inline int32_t sat_int32(int64_t x) { @@ -30,9 +34,9 @@ static inline int32_t sat_int32(int64_t x) } /** - * @brief Saturate a 32-bit integer to signed 24-bit integer range. - * @param x Input 32-bit integer. - * @return Saturated 24-bit integer clamped between INT24_MINVALUE and INT24_MAXVALUE. + * \brief Saturate a 32-bit integer to signed 24-bit integer range. + * \param[in] x Input 32-bit integer. + * \return Saturated 24-bit integer clamped between INT24_MINVALUE and INT24_MAXVALUE. */ static inline int32_t sat_int24(int32_t x) { @@ -45,9 +49,9 @@ static inline int32_t sat_int24(int32_t x) } /** - * @brief Saturate a 32-bit integer to signed 16-bit integer range. - * @param x Input 32-bit integer. - * @return Saturated 16-bit integer clamped between INT16_MIN and INT16_MAX. + * \brief Saturate a 32-bit integer to signed 16-bit integer range. + * \param[in] x Input 32-bit integer. + * \return Saturated 16-bit integer clamped between INT16_MIN and INT16_MAX. */ static inline int16_t sat_int16(int32_t x) { @@ -60,9 +64,9 @@ static inline int16_t sat_int16(int32_t x) } /** - * @brief Saturate a 32-bit integer to signed 8-bit integer range. - * @param x Input 32-bit integer. - * @return Saturated 8-bit integer clamped between INT8_MIN and INT8_MAX. + * \brief Saturate a 32-bit integer to signed 8-bit integer range. + * \param[in] x Input 32-bit integer. + * \return Saturated 8-bit integer clamped between INT8_MIN and INT8_MAX. */ static inline int8_t sat_int8(int32_t x) { @@ -74,4 +78,6 @@ static inline int8_t sat_int8(int32_t x) return (int8_t)x; } +/** @}*/ + #endif /* __SOF_AUDIO_FORMAT_GENERIC_H__ */ diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index b708ef46093c..1e0d82d23380 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -191,18 +191,66 @@ struct module_processing_data { /*****************************************************************************/ int module_load_config(struct comp_dev *dev, const void *cfg, size_t size); int module_init(struct processing_module *mod); +/** + * @brief Allocate aligned stream buffer memory for a processing module. + * + * Allocates buffer memory via the module's allocation context using + * #SOF_MEM_FLAG_USER and #SOF_MEM_FLAG_LARGE_BUFFER. Tracked in module + * resources and automatically freed on module teardown. + * + * @param mod Pointer to processing module. + * @param size Buffer size in bytes. + * @param alignment Required alignment in bytes. + * @return Pointer to allocated buffer, or NULL on failure. + */ #if defined(__ZEPHYR__) && defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) __syscall void *mod_balloc_align(struct processing_module *mod, size_t size, size_t alignment); #else void *z_impl_mod_balloc_align(struct processing_module *mod, size_t size, size_t alignment); #define mod_balloc_align z_impl_mod_balloc_align #endif + +/** + * @brief Initialize module resource management locks and containers. + * @param mod Pointer to processing module. + */ void mod_resource_init(struct processing_module *mod); + +/** + * @brief Query module memory heap boundary and size. + * @param mod Pointer to processing module. + * @param size Pointer to receive heap size in bytes. + * @param start Pointer to receive heap start address. + */ void mod_heap_info(struct processing_module *mod, size_t *size, uintptr_t *start); + +/** + * @brief Allocate memory for a module with explicit flags and alignment. + * + * Allocates memory from the module's allocation context (mod_alloc_ctx). + * Automatically registered in module resources and released on module removal. + * + * @param mod Pointer to processing module. + * @param flags Memory allocation flags (SOF_MEM_FLAG_...). + * @param size Size in bytes to allocate. + * @param alignment Required alignment in bytes. + * @return Pointer to allocated memory, or NULL on failure. + */ #if defined(__ZEPHYR__) && defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) __syscall void *mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t size, size_t alignment); +/** + * @brief Free a memory block previously allocated for a module. + * @param mod Pointer to processing module. + * @param ptr Pointer to memory to free. + * @return 0 on success, negative error code on failure. + */ __syscall int mod_free(struct processing_module *mod, const void *ptr); + +/** + * @brief Free all heap resources currently tracked for a module. + * @param mod Pointer to processing module. + */ __syscall void mod_free_all(struct processing_module *mod); #else void *z_impl_mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t size, @@ -215,11 +263,11 @@ void z_impl_mod_free_all(struct processing_module *mod); #endif /** - * Allocates aligned memory block for module. - * @param mod Pointer to the module this memory block is allocated for. - * @param size Size in bytes. - * @param alignment Alignment in bytes. - * @return Pointer to the allocated memory or NULL if failed. + * @brief Allocate aligned memory block for module with user privileges. + * @param mod Pointer to processing module. + * @param size Size in bytes. + * @param alignment Alignment in bytes. + * @return Pointer to allocated memory, or NULL on failure. * * The allocated memory is automatically freed when the module is unloaded. */ @@ -228,16 +276,34 @@ static inline void *mod_alloc_align(struct processing_module *mod, size_t size, return mod_alloc_ext(mod, SOF_MEM_FLAG_USER, size, alignment); } +/** + * @brief Allocate stream buffer memory for module with natural alignment. + * @param mod Pointer to processing module. + * @param size Size in bytes. + * @return Pointer to allocated buffer, or NULL on failure. + */ static inline void *mod_balloc(struct processing_module *mod, size_t size) { return mod_balloc_align(mod, size, 0); } +/** + * @brief Allocate memory block for module with default natural alignment. + * @param mod Pointer to processing module. + * @param size Size in bytes. + * @return Pointer to allocated memory, or NULL on failure. + */ static inline void *mod_alloc(struct processing_module *mod, size_t size) { return mod_alloc_align(mod, size, 0); } +/** + * @brief Allocate zero-initialized memory block for module. + * @param mod Pointer to processing module. + * @param size Size in bytes. + * @return Pointer to zero-initialized allocated memory, or NULL on failure. + */ static inline void *mod_zalloc(struct processing_module *mod, size_t size) { void *ret = mod_alloc(mod, size); diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index 5fa2f860021f..a621aee488ab 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -27,6 +27,10 @@ #include #include +/** \addtogroup audio_pipeline_api + * @{ + */ + struct comp_buffer; struct comp_dev; struct ipc; @@ -34,124 +38,138 @@ struct ipc_msg; struct k_heap; struct mod_alloc_ctx; -/* - * Pipeline status to stop execution of current path, but to keep the - * pipeline alive, when processing COMP_TRIGGER_STOP or COMP_TRIGGER_PAUSE +/** + * \brief Pipeline status to stop execution of current path, but to keep the + * pipeline alive, when processing COMP_TRIGGER_STOP or COMP_TRIGGER_PAUSE. */ #define PPL_STATUS_PATH_STOP 1 -/* - * Pipeline status to stop execution of current path, and to terminate the - * pipeline, when processing COMP_TRIGGER_STOP or COMP_TRIGGER_PAUSE + +/** + * \brief Pipeline status to stop execution of current path, and to terminate the + * pipeline, when processing COMP_TRIGGER_STOP or COMP_TRIGGER_PAUSE. */ #define PPL_STATUS_PATH_TERMINATE 2 -/* Pipeline scheduled in another thread other than ipc thread */ +/** \brief Pipeline scheduled in another thread other than IPC thread. */ #define PPL_STATUS_SCHEDULED 2 -/* pipeline connection directions */ -#define PPL_CONN_DIR_COMP_TO_BUFFER 0 -#define PPL_CONN_DIR_BUFFER_TO_COMP 1 +/** \name Pipeline connection directions + * @{ + */ +#define PPL_CONN_DIR_COMP_TO_BUFFER 0 /**< Connection from component to buffer */ +#define PPL_CONN_DIR_BUFFER_TO_COMP 1 /**< Connection from buffer to component */ +/** @}*/ -/* pipeline processing directions */ -#define PPL_DIR_DOWNSTREAM 0 -#define PPL_DIR_UPSTREAM 1 +/** \name Pipeline processing directions + * @{ + */ +#define PPL_DIR_DOWNSTREAM 0 /**< Downstream playback/processing direction */ +#define PPL_DIR_UPSTREAM 1 /**< Upstream capture/processing direction */ +/** @}*/ -/* - * Audio pipeline. +/** + * \brief Audio pipeline structure representing a stream graph and execution context. */ struct pipeline { - struct mod_alloc_ctx *alloc; /**< alloc context used for allocating this pipeline */ - uint32_t comp_id; /**< component id for pipeline */ - uint32_t pipeline_id; /**< pipeline id */ - uint32_t sched_id; /**< Scheduling component id */ - uint32_t core; /**< core we run on */ - uint32_t period; /**< execution period in us*/ - uint32_t priority; /**< priority level 0 (low) to 10 (max) */ - uint32_t period_mips; /**< worst case instruction count per period */ - uint32_t frames_per_sched;/**< output frames of pipeline, 0 is variable */ - uint32_t xrun_limit_usecs; /**< report xruns greater than limit */ - uint32_t time_domain; /**< scheduling time domain */ - uint32_t attributes; /**< pipeline attributes from IPC extension msg/ */ + struct mod_alloc_ctx *alloc; /**< Alloc context used for allocating this pipeline */ + uint32_t comp_id; /**< Component ID for pipeline */ + uint32_t pipeline_id; /**< Pipeline ID */ + uint32_t sched_id; /**< Scheduling component ID */ + uint32_t core; /**< Core we run on */ + uint32_t period; /**< Execution period in microseconds */ + uint32_t priority; /**< Priority level 0 (low) to 10 (max) */ + uint32_t period_mips; /**< Worst case instruction count per period */ + uint32_t frames_per_sched;/**< Output frames of pipeline, 0 is variable */ + uint32_t xrun_limit_usecs; /**< Report xruns greater than limit */ + uint32_t time_domain; /**< Scheduling time domain */ + uint32_t attributes; /**< Pipeline attributes from IPC extension message */ /* runtime status */ - int32_t xrun_bytes; /* last xrun length */ - uint32_t status; /* pipeline status */ - struct tr_ctx tctx; /* trace settings */ + int32_t xrun_bytes; /**< Last xrun length in bytes */ + uint32_t status; /**< Pipeline status flags */ + struct tr_ctx tctx; /**< Trace settings */ /* scheduling */ #ifdef CONFIG_IPC_MAJOR_4 - struct task *trigger_task; /* IPC4 pipeline trigger task */ + struct task *trigger_task; /**< IPC4 pipeline trigger task */ #endif - struct task *pipe_task; /* IPC3 pipeline processing task or IPC4 pipeline copy task */ - struct pipeline *sched_next; /* pipeline scheduled after this */ - struct pipeline *sched_prev; /* pipeline scheduled before this */ + struct task *pipe_task; /**< IPC3 pipeline processing task or IPC4 pipeline copy task */ + struct pipeline *sched_next; /**< Pipeline scheduled after this */ + struct pipeline *sched_prev; /**< Pipeline scheduled before this */ /* component that drives scheduling in this pipe */ - struct comp_dev *sched_comp; + struct comp_dev *sched_comp; /**< Component that drives scheduling in this pipe */ /* source component for this pipe */ - struct comp_dev *source_comp; + struct comp_dev *source_comp; /**< Source component for this pipe */ /* sink component for this pipe */ - struct comp_dev *sink_comp; + struct comp_dev *sink_comp; /**< Sink component for this pipe */ - struct list_item list; /**< list in walk context */ + struct list_item list; /**< List item in walk context */ /* position update */ - uint32_t posn_offset; /* position update array offset*/ - struct ipc_msg *msg; + uint32_t posn_offset; /**< Position update array offset */ + struct ipc_msg *msg; /**< IPC message pointer for position updates */ struct { - int cmd; - struct comp_dev *host; - unsigned int delay; /* period count */ - bool aborted; /* STOP or PAUSE failed, stay active */ - bool pending; /* trigger scheduled but not executed yet */ - } trigger; + int cmd; /**< Trigger command */ + struct comp_dev *host; /**< Associated host component device */ + unsigned int delay; /**< Period count delay */ + bool aborted; /**< STOP or PAUSE failed, stay active */ + bool pending; /**< Trigger scheduled but not executed yet */ + } trigger; /**< Pipeline trigger control structure */ }; +/** + * \brief Pipeline traversal walk context for graph exploration and operations. + */ struct pipeline_walk_context { + /** Callback function invoked for each component in walk */ int (*comp_func)(struct comp_dev *cd, struct comp_buffer *buffer, struct pipeline_walk_context *ctx, int dir); - void *comp_data; + void *comp_data; /**< Component callback user data */ + /** Callback function invoked for each buffer in walk */ void (*buff_func)(struct comp_buffer *buffer, void *data); - void *buff_data; - struct comp_buffer *incoming; - /**< pipelines to be scheduled after trigger walk */ - struct list_item pipelines; + void *buff_data; /**< Buffer callback user data */ + struct comp_buffer *incoming; /**< Incoming buffer context */ + struct list_item pipelines; /**< Pipelines to be scheduled after trigger walk */ /* * If this flag is set, pipeline_for_each_comp() will skip all * incompletely initialised components, i.e. those, whose .pipeline == * NULL. Such components should not be skipped during initialisation * and clean up, but they should be skipped during streaming. */ - bool skip_incomplete; + bool skip_incomplete; /**< Skip incompletely initialized components */ }; -/* generic pipeline data used by pipeline_comp_* functions */ +/** + * \brief Generic pipeline data used by pipeline_comp_* functions. + */ struct pipeline_data { - struct comp_dev *start; - struct sof_ipc_pcm_params *params; - struct sof_ipc_stream_posn *posn; - struct pipeline *p; - int cmd; - uint32_t delay_ms; /* between PRE_{START,RELEASE} and {START,RELEASE} */ + struct comp_dev *start; /**< Starting component device */ + struct sof_ipc_pcm_params *params; /**< Stream PCM parameters */ + struct sof_ipc_stream_posn *posn; /**< Stream position structure */ + struct pipeline *p; /**< Target pipeline */ + int cmd; /**< Command code */ + uint32_t delay_ms; /**< Delay in milliseconds between pre and main trigger phases */ #if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL - int32_t kcps[CONFIG_CORE_COUNT]; /**< the max count of KCPS */ + int32_t kcps[CONFIG_CORE_COUNT]; /**< The max count of KCPS per core */ #endif }; /** \brief Task type registered by pipelines. */ struct pipeline_task { - struct task task; /**< parent structure */ - bool registrable; /**< should task be registered on irq */ - struct comp_dev *sched_comp; /**< pipeline scheduling component */ + struct task task; /**< Parent task structure */ + bool registrable; /**< Should task be registered on IRQ */ + struct comp_dev *sched_comp; /**< Pipeline scheduling component */ }; struct ipc4_pipeline_ext_obj_mem_data; -/** \brief For storing IPC payload data. */ +/** \brief For storing IPC payload data during pipeline creation. */ struct create_pipeline_params { - const struct ipc4_pipeline_ext_obj_mem_data *mem_data; + const struct ipc4_pipeline_ext_obj_mem_data *mem_data; /**< IPC4 pipeline external memory descriptor */ }; +/** \brief Retrieves the enclosing pipeline_task structure from a task pointer. */ #define pipeline_task_get(t) container_of(t, struct pipeline_task, task) /* @@ -163,113 +181,113 @@ struct create_pipeline_params { /** * \brief Creates a new pipeline. - * \param[in] heap Heap to allocate the pipeline on, or NULL for default. + * \param[in,out] heap Heap to allocate the pipeline on, or NULL for default. * \param[in] pipeline_id Pipeline ID number. * \param[in] priority Pipeline scheduling priority. * \param[in] comp_id Pipeline component ID number. - * \param[in] pparams Pipeline parameters from IPC payload, maybe NULL. - * \return New pipeline pointer or NULL. + * \param[in] pparams Pipeline parameters from IPC payload, may be NULL. + * \return Pointer to new pipeline on success, or NULL on failure. */ struct pipeline *pipeline_new(struct k_heap *heap, uint32_t pipeline_id, uint32_t priority, uint32_t comp_id, struct create_pipeline_params *pparams); /** - * \brief Free's a pipeline. - * \param[in] p pipeline. - * \return 0 on success. + * \brief Frees a pipeline and its associated resources. + * \param[in,out] p Pipeline to free. + * \return 0 on success, or negative error code on failure. */ int pipeline_free(struct pipeline *p); /** * \brief Connect components in a pipeline. - * \param[in] comp connecting component. - * \param[in] buffer connecting buffer. - * \param[in] dir Connection direction. - * \return 0 on success. + * \param[in,out] comp Connecting component device. + * \param[in,out] buffer Connecting buffer. + * \param[in] dir Connection direction (PPL_CONN_DIR_*). + * \return 0 on success, or negative error code on failure. */ int pipeline_connect(struct comp_dev *comp, struct comp_buffer *buffer, int dir); /** - * \brief Creates a new pipeline. - * \param[in] comp connecting component. - * \param[in] buffer connecting buffer. - * \param[in] dir Connection direction. + * \brief Disconnect components and buffers in a pipeline. + * \param[in,out] comp Connecting component device. + * \param[in,out] buffer Connecting buffer. + * \param[in] dir Connection direction (PPL_CONN_DIR_*). */ void pipeline_disconnect(struct comp_dev *comp, struct comp_buffer *buffer, int dir); /** - * \brief Completes a pipeline. - * \param[in] p pipeline. - * \param[in] source Pipeline component device. - * \param[in] sink Pipeline component device. - * \return 0 on success. + * \brief Completes a pipeline setup by verifying connectivity between source and sink. + * \param[in,out] p Pipeline to complete. + * \param[in,out] source Pipeline source component device. + * \param[in,out] sink Pipeline sink component device. + * \return 0 on success, or negative error code on failure. */ int pipeline_complete(struct pipeline *p, struct comp_dev *source, struct comp_dev *sink); /** * \brief Initializes pipeline position structure. - * \param[in,out] sof Pointer to sof structure. + * \param[in,out] sof Pointer to global SOF system context. */ void pipeline_posn_init(struct sof *sof); #ifdef CONFIG_SOF_USERSPACE_LL /** * \brief Grants user-space thread access to pipeline position mutex. - * \param[in] thread Thread to grant access to. + * \param[in,out] thread Thread to grant access to. */ void pipeline_posn_grant_access(struct k_thread *thread); #endif /** - * \brief Resets the pipeline and free runtime resources. - * \param[in] p pipeline. - * \param[in] host_cd Host DMA component device. - * \return 0 on success. + * \brief Resets the pipeline and frees runtime resources. + * \param[in,out] p Pipeline to reset. + * \param[in,out] host_cd Host DMA component device. + * \return 0 on success, or negative error code on failure. */ int pipeline_reset(struct pipeline *p, struct comp_dev *host_cd); /** * \brief Sets End Of Stream state for all devices in the pipeline. - * \param[in] p pipeline. - * \param[in] eos End Of Stream state. + * \param[in,out] p Target pipeline. + * \param[in] eos End Of Stream flag state. */ void pipeline_set_eos(struct pipeline *p, bool eos); /** * \brief Walks the pipeline graph for each component. - * \param[in] current Current pipeline component. - * \param[in] ctx Pipeline graph walk context. - * \param[in] dir Walk direction. - * \return 0 on success. + * \param[in,out] current Current pipeline component to start traversal from. + * \param[in,out] ctx Pipeline graph walk context. + * \param[in] dir Walk direction (PPL_DIR_*). + * \return 0 on success, or negative error code on failure. */ int pipeline_for_each_comp(struct comp_dev *current, struct pipeline_walk_context *ctx, int dir); /** - * \brief Walks pipeline graph to find dai component. - * \param[in] pipeline_id is the start pipeline id. - * \param[in] dir is the direction of the traversal. - * \return dai component. + * \brief Walks pipeline graph to find DAI component. + * \param[in] pipeline_id Start pipeline ID. + * \param[in] dir Direction of traversal (PPL_DIR_*). + * \return Pointer to DAI component device, or NULL if not found. */ struct comp_dev *pipeline_get_dai_comp(uint32_t pipeline_id, int dir); #if CONFIG_IPC_MAJOR_4 /** - * \brief Walks pipeline graph to find dai component and latency. - * \param[in] pipeline_id is the start pipeline id. - * \param[out] latency to dai. - * \return dai component. + * \brief Walks pipeline graph to find DAI component and latency. + * \param[in] pipeline_id Start pipeline ID. + * \param[out] latency Receives latency to DAI as a count of buffered processing blocks (input_data/ibs - output_data/obs). + * \return Pointer to DAI component device, or NULL if not found. */ struct comp_dev *pipeline_get_dai_comp_latency(uint32_t pipeline_id, uint32_t *latency); #endif /** - * Retrieves pipeline id from pipeline. - * @param p pipeline. - * @return pipeline id. + * \brief Retrieves pipeline ID from pipeline structure. + * \param[in] p Target pipeline. + * \return Pipeline ID. */ static inline uint32_t pipeline_id(struct pipeline *p) { @@ -283,20 +301,20 @@ static inline uint32_t pipeline_id(struct pipeline *p) */ /** - * \brief Creates a new pipeline. - * \param[in] p pipeline. - * \param[in] cd Pipeline component device. - * \param[in] params Pipeline parameters. - * \return 0 on success. + * \brief Sets pipeline runtime audio stream parameters. + * \param[in,out] p Pipeline to configure. + * \param[in,out] cd Pipeline component device. + * \param[in] params Stream PCM parameters. + * \return 0 on success, or negative error code on failure. */ int pipeline_params(struct pipeline *p, struct comp_dev *cd, struct sof_ipc_pcm_params *params); /** - * \brief Prepares pipeline for processing. - * \param[in] p pipeline. + * \brief Prepares pipeline for audio processing. + * \param[in,out] p Pipeline to prepare. * \param[in,out] cd Pipeline component device. - * \return 0 on success. + * \return 0 on success, or negative error code on failure. */ int pipeline_prepare(struct pipeline *p, struct comp_dev *cd); @@ -307,35 +325,35 @@ int pipeline_prepare(struct pipeline *p, struct comp_dev *cd); */ /** - * \brief Trigger pipeline - IPC context - * \param[in] p pipeline. - * \param[in] host Host DMA component. - * \param[in] cmd Pipeline trigger command. - * \return 0 on success. + * \brief Trigger pipeline in IPC context. + * \param[in,out] p Target pipeline. + * \param[in,out] host Host DMA component device. + * \param[in] cmd Pipeline trigger command (COMP_TRIGGER_*). + * \return 0 on success, or negative error code on failure. */ int pipeline_trigger(struct pipeline *p, struct comp_dev *host, int cmd); /** - * \brief Trigger pipeline - either IPC or pipeline task context - * \param[in] p pipeline. - * \param[in] host Host DMA component. - * \param[in] cmd Pipeline trigger command. - * \return 0 on success. + * \brief Trigger pipeline in either IPC or pipeline task context. + * \param[in,out] p Target pipeline. + * \param[in,out] host Host DMA component device. + * \param[in] cmd Pipeline trigger command (COMP_TRIGGER_*). + * \return 0 on success, or negative error code on failure. */ int pipeline_trigger_run(struct pipeline *p, struct comp_dev *host, int cmd); /** - * \brief Copy data along a pipeline. - * \param[in] p pipeline. - * \return 0 on success. + * \brief Copy and process stream data along a pipeline. + * \param[in,out] p Target pipeline. + * \return 0 on success, or negative error code on failure. */ int pipeline_copy(struct pipeline *p); /** - * \brief Get time pipeline timestamps from host to dai. - * \param[in] p pipeline. - * \param[in] host_dev Host DMA component. - * \param[in,out] posn Pipeline stream position. + * \brief Get pipeline timestamps from host to DAI. + * \param[in] p Target pipeline. + * \param[in] host_dev Host DMA component device. + * \param[in,out] posn Pipeline stream position structure to populate. */ void pipeline_get_timestamp(struct pipeline *p, struct comp_dev *host_dev, struct sof_ipc_stream_posn *posn); @@ -347,10 +365,10 @@ void pipeline_get_timestamp(struct pipeline *p, struct comp_dev *host_dev, */ /** - * \brief Checks if two pipelines have the same scheduling component. - * \param[in] current This pipeline. - * \param[in] previous Other pipeline. - * \return true if both pipelines are scheduled together. + * \brief Checks if two pipelines share the same scheduling component. + * \param[in] current First pipeline. + * \param[in] previous Second pipeline. + * \return True if both pipelines are scheduled together, false otherwise. */ static inline bool pipeline_is_same_sched_comp(struct pipeline *current, struct pipeline *previous) @@ -359,9 +377,9 @@ static inline bool pipeline_is_same_sched_comp(struct pipeline *current, } /** - * \brief Is pipeline is scheduled with timer. - * \param[in] p pipeline. - * \return true if pipeline uses timer based scheduling. + * \brief Checks if pipeline is scheduled with timer. + * \param[in] p Target pipeline. + * \return True if pipeline uses timer-based scheduling, false otherwise. */ static inline bool pipeline_is_timer_driven(struct pipeline *p) { @@ -369,9 +387,9 @@ static inline bool pipeline_is_timer_driven(struct pipeline *p) } /** - * \brief Is pipeline is scheduled on this core. - * \param[in] p pipeline. - * \return true if pipeline core ID == current core ID. + * \brief Checks if pipeline is scheduled on the current core. + * \param[in] p Target pipeline. + * \return True if pipeline core ID matches current core ID, false otherwise. */ static inline bool pipeline_is_this_cpu(struct pipeline *p) { @@ -379,57 +397,57 @@ static inline bool pipeline_is_this_cpu(struct pipeline *p) } /** - * \brief Init an LL task for a pipeline. - * \param[in] p pipeline. - * \return 0 on success. + * \brief Initializes a low-latency (LL) task for a pipeline. + * \param[in,out] p Target pipeline. + * \return 0 on success, or negative error code on failure. */ int pipeline_comp_ll_task_init(struct pipeline *p); /** - * \brief Free the LL tasks owned by a pipeline. - * \param[in] p pipeline. + * \brief Frees the low-latency (LL) tasks owned by a pipeline. + * \param[in,out] p Target pipeline. */ void pipeline_comp_ll_task_free(struct pipeline *p); /** - * \brief Init a DP task for a component - * \param[in] comp a component the task is created for - * \return 0 on success. + * \brief Initializes a data processing (DP) task for a component. + * \param[in,out] comp Component device for which the task is created. + * \return 0 on success, or negative error code on failure. */ int pipeline_comp_dp_task_init(struct comp_dev *comp); /** - * \brief Schedule a pipeline copy to run after a delay - * \param[in] p pipeline. + * \brief Schedules a pipeline copy operation to run after a delay. + * \param[in,out] p Target pipeline. * \param[in] start Pipeline start time in microseconds. */ void pipeline_schedule_copy(struct pipeline *p, uint64_t start); /** - * \brief Trigger pipeline's scheduling component. - * \param[in] p pipeline. + * \brief Triggers pipeline's scheduling component. + * \param[in,out] p Target pipeline. * \param[in,out] comp Pipeline component device. - * \param[in] ctx Pipeline graph walk context. + * \param[in,out] ctx Pipeline graph walk context. */ void pipeline_comp_trigger_sched_comp(struct pipeline *p, struct comp_dev *comp, struct pipeline_walk_context *ctx); /** - * \brief Schedule all triggered pipelines. - * \param[in] ctx Pipeline graph walk context. - * \param[in] cmd Trigger command. + * \brief Schedules all triggered pipelines collected during traversal. + * \param[in,out] ctx Pipeline graph walk context. + * \param[in] cmd Trigger command (COMP_TRIGGER_*). */ void pipeline_schedule_triggered(struct pipeline_walk_context *ctx, int cmd); /** - * \brief Configure pipeline scheduling. - * \param[in] p pipeline. + * \brief Configures pipeline scheduling parameters. + * \param[in,out] p Target pipeline. * \param[in] sched_id Scheduling component ID. - * \param[in] core DSP core pipeline runs on. - * \param[in] period Pipeline scheduling period in us. - * \param[in] period_mips Pipeline worst case MCPS per period. + * \param[in] core DSP core the pipeline runs on. + * \param[in] period Pipeline scheduling period in microseconds. + * \param[in] period_mips Pipeline worst-case MCPS per period. * \param[in] frames_per_sched Pipeline frames processed per schedule. * \param[in] time_domain Pipeline scheduling time domain. */ @@ -445,40 +463,43 @@ void pipeline_schedule_config(struct pipeline *p, uint32_t sched_id, */ /** - * \brief Recover the pipeline from a XRUN condition. - * \param[in] p pipeline. - * \return 0 on success. + * \brief Recovers the pipeline from an XRUN condition. + * \param[in,out] p Target pipeline. + * \return 0 on success, or negative error code on failure. */ int pipeline_xrun_recover(struct pipeline *p); /** - * \brief Perform xrun recovery. - * \param[in] p pipeline. - * \param[in] cmd Trigger command. - * \return 0 on success. + * \brief Performs XRUN recovery trigger handling. + * \param[in,out] p Target pipeline. + * \param[in] cmd Trigger command (COMP_TRIGGER_*). + * \return 0 on success, or negative error code on failure. */ int pipeline_xrun_handle_trigger(struct pipeline *p, int cmd); /** - * \brief notify host that we have XRUN. - * \param[in] p pipeline. - * \param[in] dev Pipeline component device. - * \param[in] bytes Number of bytes we have over or under run. + * \brief Notifies host and pipeline that an XRUN condition occurred. + * \param[in,out] p Target pipeline. + * \param[in,out] dev Pipeline component device where XRUN occurred. + * \param[in] bytes Number of overrun or underrun bytes. */ void pipeline_xrun(struct pipeline *p, struct comp_dev *dev, int32_t bytes); /** - * \brief Set tolerance for pipeline xrun handling. - * \param[in] p pipeline. - * \param[in] xrun_limit_usecs Limit in micro secs that pipeline will tolerate. + * \brief Sets tolerance limit for pipeline XRUN handling. + * \param[in,out] p Target pipeline. + * \param[in] xrun_limit_usecs Limit in microseconds that pipeline will tolerate before reporting. + * \return 0 on success, or negative error code on failure. */ int pipeline_xrun_set_limit(struct pipeline *p, uint32_t xrun_limit_usecs); /** - * \brief Sends an ipc notification that an error occurred in the module's processing function. - * \param[in] component The component in which the error occurred. - * \param[in] error_code Error code. + * \brief Sends an IPC notification that an error occurred in a module's processing function. + * \param[in] component Component device in which the error occurred. + * \param[in] error_code Error code to report. */ void pipeline_comp_copy_error_notify(const struct comp_dev *component, int error_code); +/** @}*/ + #endif /* __SOF_AUDIO_PIPELINE_H__ */ diff --git a/src/include/sof/audio/ring_buffer.h b/src/include/sof/audio/ring_buffer.h index 1ef712a56743..61b1b1e4d83c 100644 --- a/src/include/sof/audio/ring_buffer.h +++ b/src/include/sof/audio/ring_buffer.h @@ -4,6 +4,12 @@ * */ +/** + * @file sof/audio/ring_buffer.h + * @brief Lockless async circular ring buffer for cross-core audio processing. + * @ingroup audio_buffer_api + */ + #ifndef __SOF_RING_BUFFER_H__ #define __SOF_RING_BUFFER_H__ @@ -16,6 +22,10 @@ #include #include +/** \addtogroup audio_buffer_api + * @{ + */ + /** * ring_buffer is a lockless async circular buffer * providing safe consumer/producer cached operations cross cores that may be write/read @@ -101,31 +111,33 @@ struct comp_dev; struct ring_buffer; struct sof_audio_stream_params; -/* the ring_buffer structure */ +/** + * \brief Lockless asynchronous circular ring buffer structure. + */ struct ring_buffer { /* public: read only */ - struct sof_audio_buffer audio_buffer; + struct sof_audio_buffer audio_buffer; /**< Embedded audio buffer base structure */ - size_t data_buffer_size; + size_t data_buffer_size; /**< Total allocated data buffer capacity in bytes */ - uint8_t __sparse_cache *_data_buffer; - size_t _write_offset; /* private: to be modified by data producer using API */ - size_t _read_offset; /* private: to be modified by data consumer using API */ + uint8_t __sparse_cache *_data_buffer; /**< Pointer to circular data buffer memory */ + size_t _write_offset; /**< Producer write offset in bytes */ + size_t _read_offset; /**< Consumer read offset in bytes */ }; /** - * - * @param dev pointer to the DP module device structure - * @param min_available minimum data available in queue required by the module using - * ring_buffer's source api - * @param min_free_space minimum buffer space in queue required by the module using - * ring_buffer's sink api - * @param is_shared indicates if the buffer will be shared between cores - * @param id a stream ID, accessible later by sink_get_id/source_get_id - * + * \brief Create and allocate a lockless async circular ring buffer. + * \param[in,out] dev Pointer to component device creating this buffer. + * \param[in] min_available Minimum data available required by source API consumer. + * \param[in] min_free_space Minimum buffer space required by sink API producer. + * \param[in] is_shared True if buffer memory is shared across processing cores. + * \param[in] id Stream identifier accessible via sink/source interface. + * \return Pointer to newly allocated ring_buffer, or NULL on failure. */ struct ring_buffer *ring_buffer_create(struct comp_dev *dev, size_t min_available, size_t min_free_space, bool is_shared, uint32_t id); +/** @}*/ + #endif /* __SOF_RING_BUFFER_H__ */ diff --git a/src/include/sof/audio/sink_api.h b/src/include/sof/audio/sink_api.h index 11ffc6e08c3d..0059353c123e 100644 --- a/src/include/sof/audio/sink_api.h +++ b/src/include/sof/audio/sink_api.h @@ -4,41 +4,62 @@ * */ +/** + * \file sof/audio/sink_api.h + * \brief Audio sink API helpers and stream configuration. + * \ingroup module_api + */ + #ifndef __SOF_SINK_API_H__ #define __SOF_SINK_API_H__ #include +/** \addtogroup module_api + * @{ + */ + /** - * Init of the API, must be called before any operation + * \brief Initialize sink API structure before any operation. + * + * NOTE: audio_stream_params must be accessible by the caller core, and the + * implementation must ensure coherent access to the parameters (e.g. for a + * cross-core shared queue, it must be located in non-cached memory). * - * @param sink pointer to the structure - * @param ops pointer to API operations - * @param audio_stream_params pointer to structure with audio parameters - * note that the audio_stream_params must be accessible by the caller core - * the implementation must ensure coherent access to the parameteres - * in case of i.e. cross core shared queue, it must be located in non-cached memory + * \param[in,out] sink Pointer to sink structure. + * \param[in] ops Pointer to API operations vtable. + * \param[in] audio_stream_params Pointer to structure with audio parameters. */ void sink_init(struct sof_sink *sink, const struct sink_ops *ops, struct sof_audio_stream_params *audio_stream_params); /** - * Get total number of bytes processed by the sink (meaning - committed by sink_commit_buffer()) - * - * @param sink a handler to sink - * @return total number of processed data + * \brief Get total number of bytes processed by the sink (committed by sink_commit_buffer()). + * \param[in] sink Pointer to sink structure. + * \return Total number of processed bytes. */ size_t sink_get_num_of_processed_bytes(struct sof_sink *sink); /** - * sets counter of total number of bytes processed to zero + * \brief Reset counter of total processed bytes to zero. + * \param[in,out] sink Pointer to sink structure. */ void sink_reset_num_of_processed_bytes(struct sof_sink *sink); -/** set of functions for retrieve audio parameters */ +/** + * \brief Check if buffer overrun is permitted on sink stream. + * \param[in] sink Pointer to sink structure. + * \return True if overrun is permitted by audio stream params, false otherwise. + */ bool sink_get_overrun(struct sof_sink *sink); -/** set of functions for setting audio parameters */ +/** + * \brief Set minimum free space required in sink buffer. + * \param[in,out] sink Pointer to sink structure. + * \param[in] min_free_space Minimum free space in bytes. + */ void sink_set_min_free_space(struct sof_sink *sink, size_t min_free_space); +/** @}*/ + #endif /* __SOF_SINK_API_H__ */ diff --git a/src/include/sof/audio/source_api.h b/src/include/sof/audio/source_api.h index 2f84e1948ebe..3721cdfaec4f 100644 --- a/src/include/sof/audio/source_api.h +++ b/src/include/sof/audio/source_api.h @@ -4,76 +4,151 @@ * */ +/** + * \file sof/audio/source_api.h + * \brief Audio source API helpers and stream configuration. + * \ingroup module_api + */ + #ifndef __SOF_SOURCE_API_H__ #define __SOF_SOURCE_API_H__ #include +/** \addtogroup module_api + * @{ + */ + /** - * Init of the API, must be called before any operation + * \brief Initialize source API structure before any operation. * - * @param source pointer to the structure - * @param ops pointer to API operations - * @param audio_stream_params pointer to structure with audio parameters - * note that the audio_stream_params must be accessible by the caller core - * the implementation must ensure coherent access to the parameteres - * in case of i.e. cross core shared queue, it must be located in non-cached memory + * NOTE: audio_stream_params must be accessible by the caller core, and the + * implementation must ensure coherent access to the parameters (e.g. for a + * cross-core shared queue, it must be located in non-cached memory). + * + * \param[in,out] source Pointer to source structure. + * \param[in] ops Pointer to API operations vtable. + * \param[in] audio_stream_params Pointer to structure with audio parameters. */ void source_init(struct sof_source *source, const struct source_ops *ops, struct sof_audio_stream_params *audio_stream_params); /** - * Get total number of bytes processed by the source (meaning - freed by source_release_data()) + * \brief Get total number of bytes processed by the source (freed by source_release_data()). + * \param[in] source Pointer to source structure. + * \return Total number of processed bytes. */ size_t source_get_num_of_processed_bytes(struct sof_source *source); /** - * sets counter of total number of bytes processed to zero + * \brief Reset counter of total processed bytes to zero. + * \param[in,out] source Pointer to source structure. */ void source_reset_num_of_processed_bytes(struct sof_source *source); -/** set of functions for retrieve audio parameters */ +/** + * \brief Check if buffer underrun is permitted on source stream. + * \param[in] source Pointer to source structure. + * \return True if underrun is permitted by audio stream params, false otherwise. + */ bool source_get_underrun(struct sof_source *source); + +/** + * \brief Get unique stream identifier for source. + * \param[in] source Pointer to source structure. + * \return Stream identifier. + */ uint32_t source_get_id(struct sof_source *source); -/** set of functions for setting audio parameters */ +/** + * \brief Set audio frame format for source. + * \param[in,out] source Pointer to source structure. + * \param[in] frm_fmt Audio frame format. + * \return 0 on success, negative error code on failure. + */ int source_set_frm_fmt(struct sof_source *source, enum sof_ipc_frame frm_fmt); + +/** + * \brief Set valid sample format for source. + * \param[in,out] source Pointer to source structure. + * \param[in] valid_sample_fmt Valid sample format. + * \return 0 on success, negative error code on failure. + */ int source_set_valid_fmt(struct sof_source *source, enum sof_ipc_frame valid_sample_fmt); + +/** + * \brief Set sample rate for source. + * \param[in,out] source Pointer to source structure. + * \param[in] rate Sample rate in Hz. + * \return 0 on success, negative error code on failure. + */ int source_set_rate(struct sof_source *source, unsigned int rate); + +/** + * \brief Set channel count for source. + * \param[in,out] source Pointer to source structure. + * \param[in] channels Number of audio channels. + * \return 0 on success, negative error code on failure. + */ int source_set_channels(struct sof_source *source, unsigned int channels); + +/** + * \brief Configure whether underrun is permitted on source. + * \param[in,out] source Pointer to source structure. + * \param[in] underrun_permitted True if underrun is permitted, false otherwise. + * \return 0 on success, negative error code on failure. + */ int source_set_underrun(struct sof_source *source, bool underrun_permitted); + +/** + * \brief Set buffer format for source. + * \param[in,out] source Pointer to source structure. + * \param[in] buffer_fmt Buffer format identifier. + * \return 0 on success, negative error code on failure. + */ int source_set_buffer_fmt(struct sof_source *source, uint32_t buffer_fmt); + +/** + * \brief Set minimum available data requirement in bytes. + * \param[in,out] source Pointer to source structure. + * \param[in] min_available Minimum available bytes. + */ void source_set_min_available(struct sof_source *source, size_t min_available); /** - * initial set of audio parameters, provided in sof_ipc_stream_params - * - * @param source a handler to source - * @param params the set of parameters - * @param force_update tells the implementation that the params should override actual settings - * @return 0 if success + * \brief Configure initial set of audio parameters. + * \param[in,out] source Pointer to source structure. + * \param[in] params Audio stream parameters. + * \param[in] force_update True to force parameters override. + * \return 0 on success, negative error code on failure. */ int source_set_params(struct sof_source *source, struct sof_ipc_stream_params *params, bool force_update); /** - * Set frame_align_shift and frame_align of stream according to byte_align and - * frame_align_req alignment requirement. Once the channel number,frame size - * are determined, the frame_align and frame_align_shift are determined too. - * these two feature will be used in audio_stream_get_avail_frames_aligned - * to calculate the available frames. it should be called in component prepare - * or param functions only once before stream copy. if someone forgets to call - * this first, there would be unexampled error such as nothing is copied at all. + * \brief Set byte and frame alignment constants for source stream. * - * @param source a handler to source - * @param byte_align Processing byte alignment requirement. - * @param frame_align_req Processing frames alignment requirement. + * Sets frame_align_shift and frame_align of stream according to byte_align and + * frame_align_req requirements. Once the channel number and frame size are + * determined, the frame_align and frame_align_shift are determined too. + * These features are used by audio_stream_get_avail_frames_aligned() to + * calculate available frames. * - * @return 0 if success + * @note This must be called in component prepare or param functions only once + * after channel count and frame size are known and before stream copying begins. + * If omitted or called late, aligned availability can evaluate to zero and + * no data will be copied. + * + * \param[in,out] source Pointer to source structure. + * \param[in] byte_align Processing byte alignment requirement. + * \param[in] frame_align_req Processing frames alignment requirement. + * \return 0 on success, negative error code on failure. */ int source_set_alignment_constants(struct sof_source *source, const uint32_t byte_align, const uint32_t frame_align_req); +/** @}*/ + #endif /* __SOF_SOURCE_API_H__ */ diff --git a/src/include/sof/coherent.h b/src/include/sof/coherent.h index 172e45b4ed92..8b4e49142f3c 100644 --- a/src/include/sof/coherent.h +++ b/src/include/sof/coherent.h @@ -5,6 +5,12 @@ * Author: Liam Girdwood */ +/** + * @file sof/coherent.h + * @brief Cache-coherent multi-core shared memory access abstractions. + * @ingroup memory_api + */ + #ifndef __SOF_COHERENT_H__ #define __SOF_COHERENT_H__ @@ -17,6 +23,11 @@ #include #include +/** \addtogroup memory_api + * @{ + */ + +/** @brief Cache line alignment specifier for coherent shared memory objects. */ #define __coherent __aligned(PLATFORM_DCACHE_ALIGN) /* @@ -52,21 +63,27 @@ * This structure must not be accessed outside of these APIs. * The shared flag is only set at coherent init and thereafter it's RO. */ + +/** + * @brief Header embedded at start of multi-core shared memory objects for cache coherence. + * + * Ensures cache line alignment and synchronizes cached/uncached state transitions across DSP cores. + * Must only be manipulated via coherent_* APIs. + */ struct coherent { union { struct { - struct k_spinlock lock; /* locking mechanism */ - k_spinlock_key_t key; /* lock flags */ + struct k_spinlock lock; /**< Spinlock synchronizing multi-core access. */ + k_spinlock_key_t key; /**< Spinlock key storing interrupt flags. */ }; #ifdef __ZEPHYR__ - struct k_mutex mutex; + struct k_mutex mutex; /**< Mutex synchronizing thread-level access when sleeping is allowed. */ #endif }; - uint8_t sleep_allowed; /* the object will never be acquired or released - * in atomic context */ - uint8_t shared; /* shared on other non coherent cores */ - uint16_t core; /* owner core if not shared */ - struct list_item list; /* coherent list iteration */ + uint8_t sleep_allowed; /**< Non-zero if context allows sleeping/blocking mutex operations. */ + uint8_t shared; /**< Non-zero if object is shared across non-coherent cores. */ + uint16_t core; /**< Owner core ID when object is not shared. */ + struct list_item list; /**< Node for coherent tracking list iteration. */ } __coherent; #if CONFIG_INCOHERENT @@ -120,7 +137,17 @@ STATIC_ASSERT(sizeof(struct coherent) <= DCACHE_LINE_SIZE, DCACHE_LINE_SIZE_too #endif #if CONFIG_INCOHERENT -/* When coherent_acquire() is called, we are sure not to have cache for this memory */ +/** + * @brief Acquire exclusive access to a cache-coherent shared object in atomic/spinlock context. + * + * For incoherent hardware platforms, validates uncache alias, acquires the spinlock, + * and invalidates the local data cache over the object range so local accesses observe + * fresh multi-core updates. + * + * @param[in,out] c Pointer to uncached coherent object header. + * @param[in] size Size of the coherent object including header in bytes. + * @return Pointer to the cached memory view of the coherent object. + */ __must_check static inline struct coherent __sparse_cache *coherent_acquire(struct coherent *c, const size_t size) { @@ -155,6 +182,15 @@ __must_check static inline struct coherent __sparse_cache *coherent_acquire(stru return cc; } +/** + * @brief Release exclusive access to a cache-coherent shared object in atomic/spinlock context. + * + * Writes back dirty cache lines across the object range to physical memory, + * invalidates local cache lines, and releases the multi-core spinlock. + * + * @param[in,out] c Pointer to cached memory view of the coherent object. + * @param[in] size Size of the coherent object including header in bytes. + */ static inline void coherent_release(struct coherent __sparse_cache *c, const size_t size) { @@ -175,6 +211,16 @@ static inline void coherent_release(struct coherent __sparse_cache *c, } } +/** + * @brief Internal helper to allocate and initialize a coherent shared object. + * + * Allocates cache-aligned uncached memory with SOF_MEM_FLAG_COHERENT and initializes + * the coherent spinlock, tracking list, and owner core ID. + * + * @param[in] offset Byte offset of the struct coherent member within the allocated object. + * @param[in] size Total size in bytes of the container object. + * @return Pointer to the newly allocated coherent object, or NULL on failure. + */ static inline void *__coherent_init(size_t offset, const size_t size) { /* @@ -203,10 +249,26 @@ static inline void *__coherent_init(size_t offset, const size_t size) return object; } +/** + * @brief Allocate and initialize a coherent shared object with spinlock protection. + * + * Wrapper around __coherent_init() computing the member offset and container type size. + * + * @param[in] type Type of the container structure. + * @param[in] member Member name of the embedded struct coherent. + */ #define coherent_init(type, member) __coherent_init(offsetof(type, member), \ sizeof(type)) -/* set the object to shared mode with coherency managed by SW */ +/** + * @brief Internal helper to mark an allocated coherent object as actively shared. + * + * Transitions the coherent object state to shared mode under spinlock protection + * and invalidates local cache. + * + * @param[in,out] c Pointer to uncached coherent object header. + * @param[in] size Total size in bytes of the coherent object. + */ static inline void __coherent_shared(struct coherent *c, const size_t size) { /* assert if someone passes a cache/local address in here. */ @@ -219,11 +281,29 @@ static inline void __coherent_shared(struct coherent *c, const size_t size) k_spin_unlock(&c->lock, c->key); } +/** + * @brief Mark an allocated coherent object as actively shared across multiple DSP cores. + * + * Wrapper around __coherent_shared() computing the member address and container size. + * + * @param[in,out] object Pointer to the container structure. + * @param[in] member Member name of the embedded struct coherent. + */ #define coherent_shared(object, member) __coherent_shared(&(object)->member, \ sizeof(*object)) #ifdef __ZEPHYR__ +/** + * @brief Acquire exclusive access to a cache-coherent shared object in thread/mutex context. + * + * Locks the embedded mutex (blocking if necessary) and invalidates the local data + * cache region so thread-level accesses observe updates from other cores. + * + * @param[in,out] c Pointer to uncached coherent object header. + * @param[in] size Size of the coherent object including header in bytes. + * @return Pointer to the cached memory view of the coherent object. + */ __must_check static inline struct coherent __sparse_cache *coherent_acquire_thread( struct coherent *c, const size_t size) { @@ -248,6 +328,15 @@ __must_check static inline struct coherent __sparse_cache *coherent_acquire_thre return cc; } +/** + * @brief Release exclusive access to a cache-coherent shared object in thread/mutex context. + * + * Writes back dirty cache lines to physical memory, invalidates local cache, + * and unlocks the embedded mutex. + * + * @param[in,out] c Pointer to cached memory view of the coherent object. + * @param[in] size Size of the coherent object including header in bytes. + */ static inline void coherent_release_thread(struct coherent __sparse_cache *c, const size_t size) { @@ -269,6 +358,16 @@ static inline void coherent_release_thread(struct coherent __sparse_cache *c, } } +/** + * @brief Internal helper to allocate and initialize a thread-capable coherent shared object. + * + * Allocates cache-aligned uncached memory with SOF_MEM_FLAG_COHERENT and initializes + * the embedded mutex and list header with sleeping allowed. + * + * @param[in] offset Byte offset of the struct coherent member within the allocated object. + * @param[in] size Total size in bytes of the container object. + * @return Pointer to the newly allocated coherent object, or NULL on failure. + */ static inline void *__coherent_init_thread(size_t offset, const size_t size) { /* As above - prevent cache line sharing */ @@ -293,9 +392,26 @@ static inline void *__coherent_init_thread(size_t offset, const size_t size) return object; } +/** + * @brief Allocate and initialize a coherent shared object with mutex protection for thread context. + * + * Wrapper around __coherent_init_thread() computing the member offset and container type size. + * + * @param[in] type Type of the container structure. + * @param[in] member Member name of the embedded struct coherent. + */ #define coherent_init_thread(type, member) __coherent_init_thread(offsetof(type, member), \ sizeof(type)) +/** + * @brief Internal helper to mark a thread-capable coherent object as actively shared. + * + * Transitions the coherent object state to shared mode under mutex protection + * and invalidates local cache. + * + * @param[in,out] c Pointer to uncached coherent object header. + * @param[in] size Total size in bytes of the coherent object. + */ static inline void __coherent_shared_thread(struct coherent *c, const size_t size) { /* assert if someone passes a cache/local address in here. */ @@ -309,11 +425,27 @@ static inline void __coherent_shared_thread(struct coherent *c, const size_t siz k_mutex_unlock(&c->mutex); } +/** + * @brief Mark a thread-capable coherent object as shared across multiple DSP cores. + * + * Wrapper around __coherent_shared_thread() computing the member address and container size. + * + * @param[in,out] object Pointer to the container structure. + * @param[in] member Member name of the embedded struct coherent. + */ #define coherent_shared_thread(object, member) __coherent_shared_thread(&(object)->member, \ sizeof(*object)) #endif /* __ZEPHYR__ */ +/** + * @brief Invalidate cache and free a coherent shared memory object. + * + * Flushes dirty cache lines back to physical memory and frees the memory block via rfree(). + * + * @param[in,out] object Pointer to the container structure. + * @param[in] member Member name of the embedded struct coherent. + */ #define coherent_free(object, member) \ do { \ /* assert if someone passes a cache address in here. */ \ @@ -324,7 +456,7 @@ static inline void __coherent_shared_thread(struct coherent *c, const size_t siz rfree(object); \ } while (0) -#else /* CONFIG_INCOHERENT */ +#else /* * Coherent devices only require locking to manage shared access. @@ -442,7 +574,24 @@ static inline void __coherent_shared_thread(struct coherent *c, const size_t siz #define coherent_shared_thread coherent_shared #endif +/** + * @brief Free a thread-capable coherent shared memory object. + * + * Flushes dirty cache lines back to physical memory and frees the memory block via rfree(). + * + * @param[in,out] object Pointer to the container structure. + * @param[in] member Member name of the embedded struct coherent. + */ #define coherent_free_thread coherent_free +/** + * @brief Query whether a coherent object is configured for multi-core shared mode. + * @param[in] object Pointer to the container structure. + * @param[in] member Member name of the embedded struct coherent. + * @return Non-zero if shared mode is enabled, 0 otherwise. + */ #define is_coherent_shared(object, member) ((object)->member.shared) + +/** @}*/ + #endif diff --git a/src/include/sof/ipc/schedule.h b/src/include/sof/ipc/schedule.h index 3f3e12059701..5fe616b57974 100644 --- a/src/include/sof/ipc/schedule.h +++ b/src/include/sof/ipc/schedule.h @@ -6,6 +6,12 @@ * Keyon Jie */ +/** + * @file sof/ipc/schedule.h + * @brief Host IPC message dispatch and scheduling task interface. + * @ingroup scheduling_api ipc4_api + */ + #ifndef __SOF_IPC_SCHEDULE_H__ #define __SOF_IPC_SCHEDULE_H__ @@ -14,14 +20,19 @@ #include #include -/** \brief Scheduling period for IPC task in microseconds. */ +/** \addtogroup scheduling_api + * @{ + */ + +/** @brief Scheduling period for host IPC worker task in microseconds. */ #define IPC_PERIOD_USEC 100 struct ipc; /** - * \brief Get IPC command processing deadline. - * @param data Task structure. + * @brief Retrieve IPC command processing deadline. + * @param[in] data Task structure context pointer. + * @return Task deadline timestamp (@ref SOF_TASK_DEADLINE_NOW). */ static inline uint64_t ipc_task_deadline(void *data) { @@ -35,9 +46,11 @@ static inline uint64_t ipc_task_deadline(void *data) } /** - * \brief Schedule processing of the next IPC command from host. - * @param ipc The global IPC context. + * @brief Schedule processing of the next pending IPC command received from host. + * @param[in,out] ipc Global IPC subsystem context pointer. */ void ipc_schedule_process(struct ipc *ipc); +/** @}*/ + #endif diff --git a/src/include/sof/lib/fast-get.h b/src/include/sof/lib/fast-get.h index 05f098a752cc..dfea81410470 100644 --- a/src/include/sof/lib/fast-get.h +++ b/src/include/sof/lib/fast-get.h @@ -5,11 +5,21 @@ * Author: Jyri Sarha */ +/** + * @file sof/lib/fast-get.h + * @brief Dynamic SRAM staging and cache mechanisms for cold DRAM-resident modules. + * @ingroup memory_api + */ + #ifndef __SOF_LIB_FAST_GET_H__ #define __SOF_LIB_FAST_GET_H__ #include +/** \addtogroup memory_api + * @{ + */ + struct k_mem_domain; struct mod_alloc_ctx; @@ -25,7 +35,23 @@ struct mod_alloc_ctx; #if (CONFIG_COLD_STORE_EXECUTE_DRAM && \ (CONFIG_LLEXT_TYPE_ELF_RELOCATABLE || !defined(LL_EXTENSION_BUILD))) || \ !CONFIG_SOF_FULL_ZEPHYR_APPLICATION +/** + * @brief Stage DRAM-resident code or data into fast SRAM for execution. + * @param[in,out] alloc Pointer to allocation context. + * @param[in] dram_ptr Pointer to source data resident in DRAM. + * @param[in] size Size in bytes to stage. + * @return Pointer to staged SRAM memory, or NULL on allocation failure. + */ const void *fast_get(struct mod_alloc_ctx *alloc, const void * const dram_ptr, size_t size); + +/** + * @brief Release fast SRAM memory previously allocated by fast_get(). + * @param[in,out] alloc Pointer to allocation context. + * @param[in,out] mdom Pointer to memory domain. Can be NULL for kernel threads or small allocations + * (<= FAST_GET_MAX_COPY_SIZE); required for large userspace staging buffers to + * remove the partition and prevent memory domain partition leaks. + * @param[in,out] sram_ptr Pointer to staged SRAM memory to release. + */ void fast_put(struct mod_alloc_ctx *alloc, struct k_mem_domain *mdom, const void *sram_ptr); #else static inline const void *fast_get(struct mod_alloc_ctx *alloc, const void * const dram_ptr, @@ -37,4 +63,6 @@ static inline void fast_put(struct mod_alloc_ctx *alloc, struct k_mem_domain *md const void *sram_ptr) {} #endif +/** @}*/ + #endif /* __SOF_LIB_FAST_GET_H__ */ diff --git a/src/include/sof/lib/vregion.h b/src/include/sof/lib/vregion.h index 559c47ed3431..fb5ae60e8c67 100644 --- a/src/include/sof/lib/vregion.h +++ b/src/include/sof/lib/vregion.h @@ -1,7 +1,12 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright(c) 2025 Intel Corporation. -/* Pre Allocated Contiguous Virtual Region */ +/** + * @file sof/lib/vregion.h + * @brief Pre-allocated contiguous virtual memory region allocator (lifetime vs interim). + * @ingroup memory_api + */ + #ifndef __SOF_LIB_VREGION_H__ #define __SOF_LIB_VREGION_H__ @@ -13,20 +18,28 @@ extern "C" { #endif +/** \addtogroup memory_api + * @{ + */ + +/** + * @brief Virtual region descriptor managing lifetime and interim heap partitions. + */ struct vregion; /** - * @brief Memory types for virtual region allocations. - * Used to specify the type of memory allocation within a virtual region. + * @brief Memory allocation modes within a virtual memory region. * - * @note - * - interim: allocation that can be freed i.e. get/set large config, kcontrols. - * - lifetime: allocation that cannot be freed i.e. init data, pipeline data. + * Distinguishes lifetime allocations (bound to pipeline topology, cannot be freed until teardown) + * from interim allocations (dynamically created and released during runtime operations). */ enum vregion_mem_type { - VREGION_MEM_TYPE_INTERIM, /* interim allocation that can be freed */ - VREGION_MEM_TYPE_LIFETIME, /* lifetime allocation */ - VREGION_MEM_TYPE_INVALID, /* Interim heap initialization failed */ + /** @brief Interim allocation that can be freed dynamically (e.g. large config set/get, controls). */ + VREGION_MEM_TYPE_INTERIM, + /** @brief Lifetime allocation that persists until region destruction (e.g. topology, module instances). */ + VREGION_MEM_TYPE_LIFETIME, + /** @brief Invalid memory type indicating initialization error or exhaustion. */ + VREGION_MEM_TYPE_INVALID, }; #if CONFIG_SOF_VREGIONS @@ -37,15 +50,20 @@ enum vregion_mem_type { * Create a new virtual region instance with specified memory size. * Allocations start in LIFETIME mode. * - * @param[in] memsize Total size of the virtual region memory. - * @return struct vregion* Pointer to the new virtual region instance, or NULL on failure. + * @param[in] memsize Total size of the virtual region memory in bytes. + * @return Pointer to the new virtual region instance, or NULL on failure. */ struct vregion *vregion_create(size_t memsize); /** - * @brief Create and map a new virtual region instance. + * @brief Create and map a new virtual region instance accessible by user-space domains. * - * Like above, but usable by userspace and can add domain access. + * Allocates contiguous virtual memory and configures memory protection domain permissions. + * + * @param[out] vreg_start Output pointer receiving the virtual start address of the region. + * @param[in,out] vreg_size Input pointer specifying the requested size in bytes (must be non-zero); + * updated on return with the actual mapped size in bytes. + * @return Pointer to the allocated virtual region instance, or NULL on failure. */ __syscall struct vregion *vregion_create_map(uintptr_t *vreg_start, size_t *vreg_size); @@ -96,16 +114,20 @@ __syscall struct vregion *vregion_put(struct vregion *vr); __syscall void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment); /** - * @brief like vregion_alloc_align() but allocates coherent memory + * @brief Allocate aligned coherent (uncached) memory from the specified virtual region. + * @param[in,out] vr Pointer to the virtual region instance. + * @param[in] size Size of memory to allocate in bytes. + * @param[in] alignment Alignment of memory to allocate in bytes. + * @return Pointer to the allocated coherent memory, or NULL on failure. */ __syscall void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment); /** * @brief Allocate memory from the specified virtual region. * - * @param[in] vr Pointer to the virtual region instance. + * @param[in,out] vr Pointer to the virtual region instance. * @param[in] size Size of memory to allocate in bytes. - * @return void* Pointer to the allocated memory, or NULL on failure. + * @return Pointer to the allocated memory, or NULL on failure. */ static inline void *vregion_alloc(struct vregion *vr, size_t size) { @@ -113,7 +135,10 @@ static inline void *vregion_alloc(struct vregion *vr, size_t size) } /** - * @brief like vregion_alloc() but allocates coherent memory + * @brief Allocate naturally aligned coherent (uncached) memory from the specified virtual region. + * @param[in,out] vr Pointer to the virtual region instance. + * @param[in] size Size of memory to allocate in bytes. + * @return Pointer to the allocated coherent memory, or NULL on failure. */ static inline void *vregion_alloc_coherent(struct vregion *vr, size_t size) { @@ -125,8 +150,8 @@ static inline void *vregion_alloc_coherent(struct vregion *vr, size_t size) * * Free memory previously allocated from the specified virtual region. * - * @param[in] vr Pointer to the virtual region instance. - * @param[in] ptr Pointer to the memory to free. + * @param[in,out] vr Pointer to the virtual region instance. + * @param[in,out] ptr Pointer to the memory to free. */ __syscall void vregion_free(struct vregion *vr, void *ptr); @@ -138,19 +163,24 @@ __syscall void vregion_free(struct vregion *vr, void *ptr); void vregion_info(struct vregion *vr); /** - * @brief Get virtual region memory start and size. + * @brief Retrieve virtual region memory base address and size. * * @param[in] vr Pointer to the virtual region instance. - * @param[in] size Pointer to size - * @param[in] start Pointer to start + * @param[out] size Output pointer receiving total region size in bytes. + * @param[out] start Output pointer receiving starting virtual address. */ void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t *start); +/** + * @brief Validate that a virtual region handle is genuine and isolated from user space. + * @param[in] vr Pointer to virtual region instance to verify. + * @return True if handle is valid and secure, false otherwise. + */ bool vregion_verify(struct vregion *vr); #include -#else /* CONFIG_SOF_VREGIONS */ +#else struct vregion { unsigned int use_count; @@ -201,6 +231,8 @@ static inline bool vregion_verify(struct vregion *vr) {return false;} #endif /* CONFIG_SOF_VREGIONS */ +/** @}*/ + #ifdef __cplusplus } #endif diff --git a/src/include/sof/schedule/dp_schedule.h b/src/include/sof/schedule/dp_schedule.h index 1d6a3066e07f..1dac74b600ef 100644 --- a/src/include/sof/schedule/dp_schedule.h +++ b/src/include/sof/schedule/dp_schedule.h @@ -8,7 +8,22 @@ /** * @file sof/schedule/dp_schedule.h * @brief Data Processing (DP) preemptible worker thread scheduler. - * @ingroup audio_pipeline_api + * @ingroup scheduling_api + * + * The Data Processing (DP) scheduler manages compute-intensive audio processing + * tasks by assigning a dedicated preemptible Zephyr thread to each SOF task. + * + * ### Key Architectural Properties + * - **Preemptible Execution**: Each DP task executes in its own Zephyr thread at a priority + * lower than the hard real-time Low-Latency (LL) scheduler thread. + * - **LL-Synchronized Evaluation**: At the end of each Low-Latency tick, `scheduler_dp_ll_tick()` + * evaluates all queued DP tasks. If a task's sources contain enough audio data and its sinks + * have sufficient buffer space, its deadline is calculated and applied to the Zephyr thread + * via `k_thread_absolute_deadline_set()`. + * - **Task States & Return Values**: + * - @ref SOF_TASK_STATE_RESCHEDULE : Task completed a data chunk and requests rescheduling next period. + * - @ref SOF_TASK_STATE_COMPLETED : Task completed processing and self-terminates until triggered again. + * - @ref SOF_TASK_STATE_CANCEL : Task was cancelled and will be removed from the active queue. */ #ifndef __SOF_SCHEDULE_DP_SCHEDULE_H__ @@ -23,61 +38,35 @@ #include #include +/** \addtogroup scheduling_api + * @{ + */ + struct processing_module; struct module_ext_init_data; /** + * @brief Initialize the Data Processing (DP) scheduler on the calling core. * - * DP scheduler is a scheduler that creates a separate preemptible Zephyr thread for each SOF task - * - * The task execution may be delayed and task may be re-scheduled periodically - * NOTE: delayed start and rescheduling takes place in sync with LL scheduler, meaning the - * DP scheduler is triggered on each core after all LL task have been completed - * - * Task run() may return: - * SOF_TASK_STATE_RESCHEDULE - the task will be rescheduled as specified in scheduler period - * note that task won't ever be rescheduled if LL is not running - * SOF_TASK_STATE_COMPLETED - the task will be removed from scheduling, - * calling schedule_task will add the task to processing again - * task_complete() will be called - * SOF_TASK_STATE_CANCEL - the task will be removed from scheduling, - * calling schedule_task will add the task to processing again - * task_complete() won't be called - * other statuses - assert will go off + * Allocates per-core DP scheduler state and initializes its driving LL tick source task. * - * NOTE: task - means a SOF task - * thread - means a Zephyr preemptible thread - * - * TODO - EDF: - * Threads run on the same priority, lower than thread running LL tasks. Zephyr EDF mechanism - * is used for decision which thread/task is to be scheduled next. The DP scheduler calculates - * the task deadline and set it in Zephyr thread properties, the final scheduling decision is made - * by Zephyr. - * - * Each time tick the scheduler iterates through the list of all active tasks and calculates - * a deadline based on - * - knowledge how the modules are bound - * - declared time required by a task to complete processing - * - the deadline of the last module - * - */ - -/** - * \brief Init the Data Processing scheduler + * @return 0 on success, negative error code (-ENOMEM) on failure. */ int scheduler_dp_init(void); /** - * \brief initialize a DP task and add it to scheduling - * It must be called on core the task is declared to run on + * @brief Initialize a Data Processing task and attach a dedicated Zephyr worker thread. + * + * Must be invoked on the same core that the task is configured to execute on. * - * \param[out] task pointer, pointer to allocated task structure will be return - * \param[in] uid pointer to UUID of the task - * \param[in] ops pointer to task functions - * \param[in] mod pointer to the module to be run - * \param[in] core CPU the thread should run on - * \param[in] stack_size size of stack for a zephyr task - * \param[in] options task options used for creation + * @param[out] task Pointer to store the allocated @ref task structure. + * @param[in] uid UUID identifying the task/module. + * @param[in] ops Task operations callbacks (@ref task_ops). + * @param[in] mod Processing module descriptor bound to this task. + * @param[in] core DSP core affinity for the task thread. + * @param[in] stack_size Stack byte size for the Zephyr worker thread. + * @param[in] options Task configuration flags. + * @return 0 on success, negative error code on failure. */ int scheduler_dp_task_init(struct task **task, const struct sof_uuid_entry *uid, @@ -88,25 +77,36 @@ int scheduler_dp_task_init(struct task **task, uint32_t options); #if defined(__ZEPHYR__) && CONFIG_SOF_FULL_ZEPHYR_APPLICATION +/** + * @brief Free kernel-side internal resources associated with a DP task. + * @param[in,out] task Task being freed. + */ __syscall void scheduler_dp_internal_free(struct task *task); + /** * @brief Tick notification from the Low-Latency (LL) timer domain to the DP scheduler. * - * Checks if queued DP tasks require execution or synchronization following an LL period. + * Invoked on each core after all LL tasks complete. Evaluates readiness for all + * queued DP tasks, updates their absolute deadlines, and signals worker threads. */ __syscall void scheduler_dp_ll_tick(void); #include #endif /** - * \brief Extract information about scheduler's tasks + * @brief Extract telemetry information about Data Processing scheduler tasks. * - * \param scheduler_props Structure to be filled - * \param data_off_size Pointer to the current size of the scheduler_props, to be updated + * Populates @ref scheduler_props with `COMP_PROCESSING_DOMAIN_DP` and active DP tasks. + * + * @param[out] scheduler_props Structure to be filled with DP scheduler properties. + * @param[in,out] data_off_size Pointer to the current size of scheduler_props buffer. */ void scheduler_get_task_info_dp(struct scheduler_props *scheduler_props, uint32_t *data_off_size); +/** + * @brief Events signaled to Data Processing (DP) worker threads. + */ enum { DP_TASK_EVENT_PROCESS = BIT(0), /* Need to process data */ DP_TASK_EVENT_CANCEL = BIT(1), /* Thread cancellation */ @@ -157,10 +157,14 @@ union scheduler_dp_thread_ipc_param { }; /** - * @brief Dispatch an IPC command to a Data Processing (DP) worker thread. - * @param pmod Pointer to the processing module descriptor. - * @param cmd IPC command identifier to execute. - * @param param Parameters payload for the IPC command. + * @brief Dispatch an IPC command synchronously to a Data Processing (DP) worker thread. + * + * Posts DP_TASK_EVENT_IPC to the thread's event queue and blocks waiting on completion + * (via dp_sync with a 100 ms timeout) before returning. + * + * @param[in,out] pmod Pointer to the processing module descriptor. + * @param[in] cmd IPC command identifier to execute. + * @param[in,out] param Parameters payload for the IPC command. * @return 0 on success, negative error code on failure. */ #if CONFIG_ZEPHYR_DP_SCHEDULER @@ -174,5 +178,7 @@ static inline int scheduler_dp_thread_ipc(struct processing_module *pmod, return 0; } #endif + +/** @}*/ #endif /* __SOF_SCHEDULE_DP_SCHEDULE_H__ */ diff --git a/src/include/sof/schedule/edf_schedule.h b/src/include/sof/schedule/edf_schedule.h index 1cc14f54d8d8..64bcbbaa2ed6 100644 --- a/src/include/sof/schedule/edf_schedule.h +++ b/src/include/sof/schedule/edf_schedule.h @@ -7,8 +7,13 @@ /** * @file sof/schedule/edf_schedule.h - * @brief Earliest Deadline First (EDF) scheduler interface. - * @ingroup audio_pipeline_api + * @brief Legacy Earliest Deadline First (EDF) workqueue scheduler interface. + * @ingroup scheduling_api + * @deprecated Deprecated for modern audio pipeline processing. In Zephyr-based builds, + * EDF is implemented as a delayed workqueue (edf_workq) retained for + * host IPC processing and legacy KPB draining tasks until migration. + * Audio pipeline components should use @ref SOF_SCHEDULE_DP with native + * Zephyr thread deadlines or @ref SOF_SCHEDULE_LL_TIMER / @ref SOF_SCHEDULE_LL_DMA. */ #ifndef __SOF_SCHEDULE_EDF_SCHEDULE_H__ @@ -19,33 +24,57 @@ #include #include +/** \addtogroup scheduling_api + * @{ + */ + +/** + * @brief Set private data pointer of an EDF task. + * @param[in,out] task Pointer to the target @ref task structure. + * @param[in] data Pointer to private context data. + * @deprecated See @ref sof/schedule/edf_schedule.h. + */ #define edf_sch_set_pdata(task, data) \ (task->priv_data = data) +/** + * @brief Retrieve private data pointer of an EDF task. + * @param[in] task Pointer to the target @ref task structure. + * @return Pointer to private context data. + * @deprecated See @ref sof/schedule/edf_schedule.h. + */ #define edf_sch_get_pdata(task) task->priv_data +/** + * @brief Legacy EDF task private data container. + * @deprecated Deprecated along with @ref SOF_SCHEDULE_EDF. + */ struct edf_task_pdata { - void *ctx; + void *ctx; /**< Task context pointer. */ }; /** - * @brief Initialize the Earliest Deadline First (EDF) scheduler. + * @brief Initialize the Earliest Deadline First (EDF) workqueue scheduler. + * @deprecated Deprecated for audio pipelines; retained for host IPC and legacy KPB draining. * @return 0 on success, negative error code on failure. */ int scheduler_init_edf(void); /** - * @brief Initialize a task for Earliest Deadline First execution. - * @param task Pointer to task structure. - * @param uid UUID identifying the task. - * @param ops Task operations callbacks. - * @param data Context pointer. - * @param core Target DSP core ID. - * @param flags Scheduling flags. + * @brief Initialize a task for Earliest Deadline First (EDF) workqueue execution. + * @deprecated Deprecated for audio pipelines; use @ref scheduler_dp_task_init() instead. + * @param[out] task Pointer to task structure to initialize. + * @param[in] uid UUID identifying the task. + * @param[in] ops Task operations callbacks (@ref task_ops). + * @param[in] data Context pointer passed to task callbacks. + * @param[in] core Target DSP core ID. + * @param[in] flags Scheduling flags. * @return 0 on success, negative error code on failure. */ int schedule_task_init_edf(struct task *task, const struct sof_uuid_entry *uid, const struct task_ops *ops, void *data, uint16_t core, uint32_t flags); +/** @}*/ + #endif /* __SOF_SCHEDULE_EDF_SCHEDULE_H__ */ diff --git a/src/include/sof/schedule/ll_schedule.h b/src/include/sof/schedule/ll_schedule.h index 5252b46267c8..41e8f9f42558 100644 --- a/src/include/sof/schedule/ll_schedule.h +++ b/src/include/sof/schedule/ll_schedule.h @@ -7,8 +7,8 @@ /** * @file sof/schedule/ll_schedule.h - * @brief Low-Latency (LL) timer-driven scheduler interface. - * @ingroup audio_pipeline_api + * @brief Low-Latency (LL) timer and DMA-driven deterministic task scheduler interface. + * @ingroup scheduling_api * * Delayed or scheduled work. Work runs in the same context as its timer * or DMA interrupt source. It executes deterministically and must not sleep or wait. @@ -23,40 +23,57 @@ #include #include +/** \addtogroup scheduling_api + * @{ + */ + struct ll_schedule_domain; /* ll tracing */ extern struct tr_ctx ll_tr; +/** + * @brief Set the private data pointer of a Low-Latency task. + * @param[in,out] task Pointer to the target @ref task structure. + * @param[in] data Pointer to private context data (e.g. @ref ll_task_pdata). + */ #define ll_sch_set_pdata(task, data) \ do { (task)->priv_data = (data); } while (0) +/** + * @brief Retrieve the private data pointer of a Low-Latency task. + * @param[in] task Pointer to the target @ref task structure. + * @return Pointer to private context data. + */ #define ll_sch_get_pdata(task) ((task)->priv_data) +/** + * @brief Low-Latency task private scheduling parameters. + */ struct ll_task_pdata { - uint64_t period; - uint16_t ratio; /**< ratio of periods compared to the registrable task */ - uint16_t skip_cnt; /**< how many times the task was skipped for execution */ + uint64_t period; /**< Execution period in microseconds. */ + uint16_t ratio; /**< Ratio of periods compared to the base registrable task. */ + uint16_t skip_cnt; /**< Counter tracking how many periods the task was skipped for rate alignment. */ }; +#if !defined(__ZEPHYR__) /** * @brief Initialize a Low-Latency scheduler for the specified domain. - * @param domain Pointer to the Low-Latency schedule domain (timer or DMA). + * @param[in,out] domain Pointer to the Low-Latency schedule domain (timer or DMA). * @return 0 on success, negative error code on failure. */ -#if !defined(__ZEPHYR__) int scheduler_init_ll(struct ll_schedule_domain *domain); /** * @brief Initialize a Low-Latency real-time task. - * @param task Pointer to task structure to initialize. - * @param uid UUID identifying the task/component. - * @param type Task type identifier. - * @param priority Task scheduling priority. - * @param run Callback function executing the task work. - * @param data Private context pointer passed to run callback. - * @param core Core affinity for the task. - * @param flags Scheduling flags (e.g. dynamic/static). + * @param[out] task Pointer to task structure to initialize. + * @param[in] uid UUID identifying the task/component. + * @param[in] type Task type identifier (SOF_SCHEDULE_LL_TIMER or SOF_SCHEDULE_LL_DMA). + * @param[in] priority Task scheduling priority (lower values indicate higher priority). + * @param[in] run Callback function executing the task work. + * @param[in] data Private context pointer passed to run callback. + * @param[in] core Core affinity for the task. + * @param[in] flags Scheduling flags (e.g. dynamic/static). * @return 0 on success, negative error code on failure. */ int schedule_task_init_ll(struct task *task, @@ -66,21 +83,21 @@ int schedule_task_init_ll(struct task *task, #else /** * @brief Initialize the Zephyr Low-Latency scheduler domain. - * @param domain Pointer to the Low-Latency schedule domain. + * @param[in,out] domain Pointer to the Low-Latency schedule domain. * @return 0 on success, negative error code on failure. */ int zephyr_ll_scheduler_init(struct ll_schedule_domain *domain); /** * @brief Initialize a Zephyr Low-Latency task. - * @param task Pointer to task structure. - * @param uid UUID identifying the task. - * @param type Task type identifier. - * @param priority Task priority. - * @param run Work callback function. - * @param data Context pointer. - * @param core Target DSP core ID. - * @param flags Scheduling flags. + * @param[out] task Pointer to task structure. + * @param[in] uid UUID identifying the task. + * @param[in] type Task type identifier (SOF_SCHEDULE_LL_TIMER or SOF_SCHEDULE_LL_DMA). + * @param[in] priority Task priority (lower values indicate higher priority). + * @param[in] run Work callback function. + * @param[in] data Context pointer. + * @param[in] core Target DSP core ID. + * @param[in] flags Scheduling flags. * @return 0 on success, negative error code on failure. */ int zephyr_ll_task_init(struct task *task, @@ -94,12 +111,16 @@ int zephyr_ll_task_init(struct task *task, #endif /** - * \brief Extract information about scheduler's tasks + * @brief Extract telemetry information about Low-Latency scheduler tasks. + * + * Populates @ref scheduler_props with `COMP_PROCESSING_DOMAIN_LL` and active LL 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[out] scheduler_props Structure to be filled with LL scheduler properties. + * @param[in,out] data_off_size Pointer to the current size of scheduler_props buffer. */ 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/ll_schedule_domain.h b/src/include/sof/schedule/ll_schedule_domain.h index cfd0043995db..6858929d97b3 100644 --- a/src/include/sof/schedule/ll_schedule_domain.h +++ b/src/include/sof/schedule/ll_schedule_domain.h @@ -5,6 +5,12 @@ * Author: Tomasz Lauda */ +/** + * @file sof/schedule/ll_schedule_domain.h + * @brief Low-Latency (LL) scheduling domain architecture, timer/DMA drivers, and core domain operations. + * @ingroup scheduling_api + */ + #ifndef __SOF_SCHEDULE_LL_SCHEDULE_DOMAIN_H__ #define __SOF_SCHEDULE_LL_SCHEDULE_DOMAIN_H__ @@ -22,115 +28,262 @@ #include #include +/** \addtogroup scheduling_api + * @{ + */ + #if defined(CONFIG_AMD) -#define LL_TIMER_PERIOD_US 500ULL /* 500us period for AMD ACP platforms */ +/** @brief Low-Latency timer scheduling period in microseconds (500us for AMD ACP platforms). */ +#define LL_TIMER_PERIOD_US 500ULL #else -#define LL_TIMER_PERIOD_US 1000ULL /* default period in microseconds */ +/** @brief Default Low-Latency timer scheduling period in microseconds (1000us / 1ms). */ +#define LL_TIMER_PERIOD_US 1000ULL #endif -/* Default ll watchdog timeout in microseconds. - * It was decided to have a timeout of two periods to give a safe margin of time between the start - * of the watchdog and its first feeding. +/** + * @brief Default Low-Latency watchdog timeout in microseconds. + * + * Configured as two periods to provide a safe margin between watchdog start + * and initial task feeding. */ #define LL_WATCHDOG_TIMEOUT_US (2 * LL_TIMER_PERIOD_US) - struct dma; struct ll_schedule_domain; struct task; struct timer; struct comp_dev; +/** + * @brief Low-Latency schedule domain operations table. + * + * Implements driver-level primitives for timer and DMA scheduling domains. + */ struct ll_schedule_domain_ops { + /** + * @brief Register a real-time task with the domain. + * @param[in,out] domain Target scheduling domain. + * @param[in,out] task Task being registered. + * @param[in] handler Domain tick handler callback. + * @param[in,out] arg Context argument passed to tick handler. + * @return 0 on success, negative error code on failure. + */ int (*domain_register)(struct ll_schedule_domain *domain, struct task *task, void (*handler)(void *arg), void *arg); + + /** + * @brief Unregister a task from the domain. + * @param[in,out] domain Target scheduling domain. + * @param[in,out] task Task being unregistered. + * @param[in] num_tasks Current total task count. + * @return 0 on success, negative error code on failure. + */ int (*domain_unregister)(struct ll_schedule_domain *domain, struct task *task, uint32_t num_tasks); + #if CONFIG_SOF_USERSPACE_LL - /* - * Initialize the scheduling thread and perform all privileged setup - * (thread creation, timer init, access grants). Called once from - * kernel context before any user-space domain_register() calls. + /** + * @brief Initialize the scheduling thread and privileged resources. + * + * Must be called from kernel context before any user-space tasks register. + * @param[in,out] domain Target scheduling domain. + * @param[in,out] task Task requiring privileged setup. + * @return 0 on success, negative error code on failure. */ int (*domain_thread_init)(struct ll_schedule_domain *domain, struct task *task); - /* Free resources acquired by domain_thread_init(). Called from - * kernel context when the scheduling context is being torn down. + + /** + * @brief Free resources acquired by domain_thread_init(). + * @param[in,out] domain Target scheduling domain. + * @param[in] num_tasks Current total task count. */ void (*domain_thread_free)(struct ll_schedule_domain *domain, uint32_t num_tasks); #endif + + /** + * @brief Enable domain interrupts/triggers on the specified core. + * @param[in,out] domain Target scheduling domain. + * @param[in] core Core index to enable. + */ void (*domain_enable)(struct ll_schedule_domain *domain, int core); + + /** + * @brief Disable domain interrupts/triggers on the specified core. + * @param[in,out] domain Target scheduling domain. + * @param[in] core Core index to disable. + */ void (*domain_disable)(struct ll_schedule_domain *domain, int core); + #if CONFIG_CROSS_CORE_STREAM - /* - * Unlike domain_disable(), these are intended to temporary block LL from - * starting its next cycle. Triggering (e.g., by means of timer interrupt) - * is still enabled and registered but execution of next cycle is blocked. - * Once unblocked, if triggering were previously registered in a blocked - * state -- next cycle execution could start immediately. + /** + * @brief Temporarily block domain execution across cores without disabling interrupt triggers. + * @param[in,out] domain Target scheduling domain. */ void (*domain_block)(struct ll_schedule_domain *domain); + + /** + * @brief Unblock domain execution across cores. + * @param[in,out] domain Target scheduling domain. + */ void (*domain_unblock)(struct ll_schedule_domain *domain); #endif + + /** + * @brief Set the next tick timestamp for the domain. + * @param[in,out] domain Target scheduling domain. + * @param[in] start Next execution start timestamp in clock ticks. + */ void (*domain_set)(struct ll_schedule_domain *domain, uint64_t start); + + /** + * @brief Clear scheduled domain interrupt / tick timer. + * @param[in,out] domain Target scheduling domain. + */ void (*domain_clear)(struct ll_schedule_domain *domain); + + /** + * @brief Query whether a task in the domain has pending execution work. + * @param[in] domain Target scheduling domain. + * @param[in] task Task to check. + * @param[out] comp Pointer to associated component device, if any. + * @return true if work is pending, false otherwise. + */ bool (*domain_is_pending)(struct ll_schedule_domain *domain, struct task *task, struct comp_dev **comp); + + /** + * @brief Notification hook invoked when a task within the domain is cancelled. + * @param[in,out] domain Target scheduling domain. + * @param[in,out] task Task being cancelled. + */ void (*domain_task_cancel)(struct ll_schedule_domain *domain, struct task *task); }; +/** + * @brief Low-Latency scheduling domain instance descriptor. + */ struct ll_schedule_domain { - uint64_t next_tick; /**< ticks just set for next run */ - uint64_t new_target_tick; /**< for the next set, used during the reschedule stage */ + uint64_t next_tick; /**< Ticks just set for next run. */ + uint64_t new_target_tick; /**< For the next set, used during the reschedule stage. */ #ifdef CONFIG_SOF_USERSPACE_LL - struct k_mutex *lock; /**< standard lock */ + struct k_mutex *lock; /**< Domain mutex for user-space access. */ #else - struct k_spinlock lock; /**< standard lock */ + struct k_spinlock lock; /**< Standard spinlock. */ #endif - atomic_t total_num_tasks; /**< total number of registered tasks */ - atomic_t enabled_cores; /**< number of enabled cores */ - uint32_t ticks_per_ms; /**< number of clock ticks per ms */ - int type; /**< domain type */ - int clk; /**< source clock */ - bool synchronous; /**< are tasks should be synchronous */ - bool full_sync; /**< tasks should be full synchronous, no time dependent */ - void *priv_data; /**< pointer to private data */ - bool enabled[CONFIG_CORE_COUNT]; /**< enabled cores */ - const struct ll_schedule_domain_ops *ops; /**< domain ops */ + atomic_t total_num_tasks; /**< Total number of registered tasks across all cores. */ + atomic_t enabled_cores; /**< Number of currently enabled cores. */ + uint32_t ticks_per_ms; /**< Number of clock ticks per millisecond. */ + int type; /**< Domain type (SOF_SCHEDULE_LL_TIMER or SOF_SCHEDULE_LL_DMA). */ + int clk; /**< Source clock identifier. */ + bool synchronous; /**< True if tasks in this domain execute synchronously. */ + bool full_sync; /**< True if tasks are fully synchronous with no time dependency. */ + void *priv_data; /**< Pointer to private domain driver data. */ + bool enabled[CONFIG_CORE_COUNT]; /**< Per-core enablement flags. */ + const struct ll_schedule_domain_ops *ops; /**< Domain operations table. */ }; +/** + * @brief Set the private data pointer of a Low-Latency scheduling domain. + * @param[in,out] domain Target domain. + * @param[in] data Private context pointer. + */ #define ll_sch_domain_set_pdata(domain, data) ((domain)->priv_data = (data)) +/** + * @brief Retrieve the private data pointer of a Low-Latency scheduling domain. + * @param[in] domain Target domain. + * @return Pointer to domain-specific context data. + */ #define ll_sch_domain_get_pdata(domain) ((domain)->priv_data) +/** + * @brief Get the primary platform timer scheduling domain. + * @return Pointer to global timer scheduling domain. + */ static inline struct ll_schedule_domain *timer_domain_get(void) { return sof_get()->platform_timer_domain; } +/** + * @brief Get the primary platform DMA scheduling domain. + * @return Pointer to global DMA scheduling domain. + */ static inline struct ll_schedule_domain *dma_domain_get(void) { return sof_get()->platform_dma_domain; } #ifdef CONFIG_SOF_USERSPACE_LL +/** + * @brief Allocate a task structure in the user-space LL heap. + * @return Pointer to allocated task, or NULL on failure. + */ struct task *zephyr_ll_task_alloc(void); + +/** + * @brief Get the user-space heap for Low-Latency scheduling structures. + * @return Pointer to the k_heap instance. + */ struct k_heap *zephyr_ll_user_heap(void); + +/** + * @brief Verify that a pointer belongs to the user-space LL heap. + * @param[in] heap Heap handle to check. + * @return true if valid, false otherwise. + */ bool zephyr_ll_user_heap_verify(struct k_heap *heap); + +/** + * @brief Initialize user-space memory partitions and access permissions for LL scheduling. + */ void zephyr_ll_user_resources_init(void); + +/** + * @brief Grant thread access to per-core Low-Latency mutexes. + * @param[in,out] thread Target thread. + * @param[in] core Target core ID. + */ void user_ll_grant_access(struct k_thread *thread, int core); + +/** + * @brief Acquire per-core user Low-Latency scheduling lock. + * @param[in] core Target core ID. + */ void user_ll_lock_sched(int core); + +/** + * @brief Release per-core user Low-Latency scheduling lock. + * @param[in] core Target core ID. + */ void user_ll_unlock_sched(int core); + #ifdef CONFIG_ASSERT -/* Assert that the calling context already holds the LL lock for 'core'. */ +/** + * @brief Assert that the calling context holds the user Low-Latency lock for a core. + * @param[in] core Target core ID. + */ void user_ll_assert_locked(int core); #else static inline void user_ll_assert_locked(int core) { ARG_UNUSED(core); } #endif #endif /* CONFIG_SOF_USERSPACE_LL */ +/** + * @brief Initialize a Low-Latency scheduling domain descriptor. + * + * Allocates a @ref ll_schedule_domain on the user or kernel heap, initializes + * synchronization locks, resets task and core counters, and computes tick conversion constants. + * + * @param[in] type Domain type (@ref SOF_SCHEDULE_LL_TIMER or @ref SOF_SCHEDULE_LL_DMA). + * @param[in] clk Source clock identifier. + * @param[in] synchronous True if domain tasks must run synchronously. + * @param[in] ops Domain operations table pointer. + * @return Pointer to initialized domain, or NULL on allocation failure. + */ static inline struct ll_schedule_domain *domain_init (int type, int clk, bool synchronous, const struct ll_schedule_domain_ops *ops) @@ -178,7 +331,11 @@ static inline struct ll_schedule_domain *domain_init return domain; } -/* configure the next interrupt for domain */ +/** + * @brief Configure the next interrupt or tick timestamp for the domain. + * @param[in,out] domain Target scheduling domain. + * @param[in] start Next execution start timestamp in clock ticks. + */ static inline void domain_set(struct ll_schedule_domain *domain, uint64_t start) { if (domain->ops->domain_set) @@ -187,7 +344,10 @@ static inline void domain_set(struct ll_schedule_domain *domain, uint64_t start) domain->next_tick = start; } -/* clear the interrupt for domain */ +/** + * @brief Clear/disarm the interrupt tick for the domain. + * @param[in,out] domain Target scheduling domain. + */ static inline void domain_clear(struct ll_schedule_domain *domain) { if (domain->ops->domain_clear) @@ -197,7 +357,11 @@ static inline void domain_clear(struct ll_schedule_domain *domain) domain->next_tick = UINT64_MAX; } -/* let the domain know that a task has been cancelled */ +/** + * @brief Notify the domain that a task has been cancelled. + * @param[in,out] domain Target scheduling domain. + * @param[in,out] task Cancelled task pointer. + */ static inline void domain_task_cancel(struct ll_schedule_domain *domain, struct task *task) { @@ -206,9 +370,14 @@ static inline void domain_task_cancel(struct ll_schedule_domain *domain, } #if CONFIG_SOF_USERSPACE_LL -/* - * Initialize the scheduling thread and do all privileged setup. +/** + * @brief Initialize domain scheduling thread and perform privileged resource allocation. + * * Must be called from kernel context before user-space tasks register. + * + * @param[in,out] domain Target scheduling domain. + * @param[in,out] task Task requiring privileged setup. + * @return 0 on success, negative error code on failure. */ static inline int domain_thread_init(struct ll_schedule_domain *domain, struct task *task) @@ -218,9 +387,13 @@ static inline int domain_thread_init(struct ll_schedule_domain *domain, return domain->ops->domain_thread_init(domain, task); } -/* - * Free resources acquired by domain_thread_init(). +/** + * @brief Free resources acquired by domain_thread_init(). + * * Must be called from kernel context. + * + * @param[in,out] domain Target scheduling domain. + * @param[in] num_tasks Current task count. */ static inline void domain_thread_free(struct ll_schedule_domain *domain, uint32_t num_tasks) @@ -230,6 +403,14 @@ static inline void domain_thread_free(struct ll_schedule_domain *domain, } #endif +/** + * @brief Register a real-time task with the scheduling domain. + * @param[in,out] domain Target scheduling domain. + * @param[in,out] task Task to register. + * @param[in] handler Work handler callback function. + * @param[in,out] arg Private context argument passed to handler. + * @return 0 on success, negative error code on failure. + */ static inline int domain_register(struct ll_schedule_domain *domain, struct task *task, void (*handler)(void *arg), void *arg) @@ -247,6 +428,12 @@ static inline int domain_register(struct ll_schedule_domain *domain, return ret; } +/** + * @brief Unregister a real-time task from the scheduling domain. + * @param[in,out] domain Target scheduling domain. + * @param[in,out] task Task to unregister. + * @param[in] num_tasks Current total registered task count. + */ static inline void domain_unregister(struct ll_schedule_domain *domain, struct task *task, uint32_t num_tasks) { @@ -268,6 +455,11 @@ static inline void domain_unregister(struct ll_schedule_domain *domain, atomic_add(&domain->total_num_tasks, 1); } +/** + * @brief Enable Low-Latency scheduling domain execution on the specified core. + * @param[in,out] domain Target scheduling domain. + * @param[in] core Target core ID. + */ static inline void domain_enable(struct ll_schedule_domain *domain, int core) { if (!domain->enabled[core] && domain->ops->domain_enable) { @@ -277,6 +469,11 @@ static inline void domain_enable(struct ll_schedule_domain *domain, int core) } } +/** + * @brief Disable Low-Latency scheduling domain execution on the specified core. + * @param[in,out] domain Target scheduling domain. + * @param[in] core Target core ID. + */ static inline void domain_disable(struct ll_schedule_domain *domain, int core) { if (domain->enabled[core] && domain->ops->domain_disable) { @@ -287,12 +484,20 @@ static inline void domain_disable(struct ll_schedule_domain *domain, int core) } #if CONFIG_CROSS_CORE_STREAM +/** + * @brief Temporarily block domain tick processing across cores without disabling interrupt triggers. + * @param[in,out] domain Target scheduling domain. + */ static inline void domain_block(struct ll_schedule_domain *domain) { if (domain->ops->domain_block) domain->ops->domain_block(domain); } +/** + * @brief Resume domain tick processing across cores. + * @param[in,out] domain Target scheduling domain. + */ static inline void domain_unblock(struct ll_schedule_domain *domain) { if (domain->ops->domain_unblock) @@ -300,6 +505,13 @@ static inline void domain_unblock(struct ll_schedule_domain *domain) } #endif +/** + * @brief Query whether a task in the domain has pending execution work. + * @param[in] domain Target scheduling domain. + * @param[in] task Task to inspect. + * @param[out] comp Pointer to associated component device pointer, if any. + * @return true if work is pending, false otherwise. + */ static inline bool domain_is_pending(struct ll_schedule_domain *domain, struct task *task, struct comp_dev **comp) { @@ -314,26 +526,85 @@ static inline bool domain_is_pending(struct ll_schedule_domain *domain, #ifndef __ZEPHYR__ +/** + * @brief Initialize timer-driven Low-Latency scheduling domain for non-Zephyr platforms. + * @param[in,out] timer Hardware timer device pointer. + * @param[in] clk Source clock identifier. + * @return Pointer to initialized scheduling domain. + */ struct ll_schedule_domain *timer_domain_init(struct timer *timer, int clk); #else #if CONFIG_DMA_DOMAIN #define dma_multi_chan_domain_init(dma_array, num_dma, clk, aggregated_irq)\ zephyr_dma_domain_init(dma_array, num_dma, clk) +/** + * @brief Initialize DMA interrupt-driven Low-Latency scheduling domain on Zephyr. + * @param[in] dma_array Array of DMA controllers tied to the domain. + * @param[in] num_dma Number of DMA controllers in the array. + * @param[in] clk Clock source identifier. + * @return Pointer to initialized scheduling domain, or NULL on error. + */ struct ll_schedule_domain *zephyr_dma_domain_init(struct dma *dma_array, uint32_t num_dma, int clk); #endif /* CONFIG_DMA_DOMAIN */ + +/** + * @brief Retrieve the global Low-Latency timer scheduling domain descriptor on Zephyr. + * @return Pointer to active domain descriptor. + */ struct ll_schedule_domain *zephyr_ll_domain(void); + +/** + * @brief Initialize the primary timer-driven Low-Latency scheduling domain on Zephyr. + * @param[in] clk Clock source identifier. + * @return Pointer to initialized scheduling domain, or NULL on failure. + */ struct ll_schedule_domain *zephyr_domain_init(int clk); + #define timer_domain_init(timer, clk) zephyr_domain_init(clk) + #ifdef CONFIG_SOF_USERSPACE_LL +/** + * @brief Retrieve the Zephyr domain thread TID for the domain on the current core. + * @param[in] domain Target scheduling domain. + * @return Pointer to k_thread instance. + */ struct k_thread *zephyr_domain_thread_tid(struct ll_schedule_domain *domain); + +/** + * @brief Retrieve the Zephyr domain thread TID for the domain on a specific core. + * @param[in] core Target core ID. + * @return Pointer to k_thread instance. + */ struct k_thread *zephyr_domain_thread_tid_for_core(int core); + +/** + * @brief Retrieve the user-space LL memory domain. + * @return Pointer to k_mem_domain. + */ struct k_mem_domain *zephyr_ll_mem_domain(void); + +/** + * @brief Retrieve the Zephyr LL thread handle for the calling core. + * @return Pointer to k_thread instance. + */ struct k_thread *zephyr_ll_domain_thread(void); #endif /* CONFIG_SOF_USERSPACE_LL */ + #ifdef CONFIG_SOF_FULL_ZEPHYR_APPLICATION +/** + * @brief Allocate a completion semaphore for a Low-Latency task. + * @param[in,out] task Target task. + * @return 0 on success, negative error code on failure. + */ __syscall int zephyr_ll_task_sem_alloc(struct task *task); + +/** + * @brief Free a completion semaphore for a Low-Latency task. + * @param[in,out] task Target task. + * @return 0 on success, negative error code on failure. + */ __syscall int zephyr_ll_task_sem_free(struct task *task); #include #else @@ -344,12 +615,29 @@ int z_impl_zephyr_ll_task_sem_free(struct task *task); #endif /* CONFIG_SOF_FULL_ZEPHYR_APPLICATION */ #endif /* __ZEPHYR__ */ +/** + * @brief Initialize multi-channel DMA scheduling domain. + * @param[in] dma_array Array of DMA controllers. + * @param[in] num_dma Number of DMA controllers. + * @param[in] clk Clock source identifier. + * @param[in] aggregated_irq True if IRQs from channels are aggregated into a single line. + * @return Pointer to initialized scheduling domain. + */ struct ll_schedule_domain *dma_multi_chan_domain_init(struct dma *dma_array, uint32_t num_dma, int clk, bool aggregated_irq); +/** + * @brief Initialize single-channel DMA scheduling domain. + * @param[in] dma_array Array of DMA controllers. + * @param[in] num_dma Number of DMA controllers. + * @param[in] clk Clock source identifier. + * @return Pointer to initialized scheduling domain. + */ struct ll_schedule_domain *dma_single_chan_domain_init(struct dma *dma_array, uint32_t num_dma, int clk); +/** @}*/ + #endif /* __SOF_SCHEDULE_LL_SCHEDULE_DOMAIN_H__ */ diff --git a/src/include/sof/schedule/schedule.h b/src/include/sof/schedule/schedule.h index 56dbbdc83a94..f5f646cfbc50 100644 --- a/src/include/sof/schedule/schedule.h +++ b/src/include/sof/schedule/schedule.h @@ -5,7 +5,12 @@ * Author: Bartosz Kokoszko */ -/* Generic schedule api header */ +/** + * @file sof/schedule/schedule.h + * @brief Generic scheduler interface, scheduler operations, and task management. + * @ingroup scheduling_api + */ + #ifndef __SOF_SCHEDULE_SCHEDULE_H__ #define __SOF_SCHEDULE_SCHEDULE_H__ @@ -19,51 +24,74 @@ #include #include -/** \addtogroup audio_pipeline_api +/** \addtogroup scheduling_api * @{ */ -/** \brief Type of scheduler, comes from topology. */ enum { - SOF_SCHEDULE_EDF = 0, /**< EDF, schedules based on task's deadline */ - SOF_SCHEDULE_LL_TIMER, /**< Low latency timer, schedules immediately - * on selected timer's tick - */ - SOF_SCHEDULE_LL_DMA, /**< Low latency DMA, schedules immediately - * on scheduling component's DMA interrupt - */ - SOF_SCHEDULE_DP, /**< DataProcessing scheduler - * Scheduler based on Zephyr peemptive threads - * TODO: DP will become the Zephyr EDF scheduler type - * and will be unified with SOF_SCHEDULE_EDF for Zephyr builds - * current implementation of Zephyr based EDF is depreciated now - */ - SOF_SCHEDULE_TWB, /**< Tasks With Budget scheduler based on Zephyr peemptive threads - * for each SOF task that has pre-allocated MCPS budget - * renewed with every system tick. - */ - SOF_SCHEDULE_COUNT /**< indicates number of scheduler types */ + /** + * @brief Earliest Deadline First (EDF) scheduler. + * @deprecated Deprecated for modern audio pipeline processing. In Zephyr-based builds, + * EDF is implemented as a delayed workqueue (edf_workq) retained for + * host IPC processing and legacy KPB draining tasks until migration. + * Audio pipeline components should use @ref SOF_SCHEDULE_DP for preemptible + * deadline-driven tasks or @ref SOF_SCHEDULE_LL_TIMER / @ref SOF_SCHEDULE_LL_DMA + * for hard real-time tasks. + */ + SOF_SCHEDULE_EDF = 0, + /** + * @brief Low Latency timer domain scheduler. + * + * Executes tasks immediately upon expiration of the primary hardware timer tick. + */ + SOF_SCHEDULE_LL_TIMER, + /** + * @brief Low Latency DMA interrupt domain scheduler. + * + * Executes tasks immediately upon scheduling component's DMA transfer completion interrupt. + */ + SOF_SCHEDULE_LL_DMA, + /** + * @brief Data Processing (DP) worker thread scheduler. + * + * Preemptible Zephyr worker thread per SOF task. Evaluates task readiness + * after each Low-Latency (LL) tick, setting absolute deadlines in Zephyr EDF. + */ + SOF_SCHEDULE_DP, + /** + * @brief Tasks With Budget (TWB) scheduler. + * + * Preemptible Zephyr thread per SOF task with a pre-allocated cycle budget + * renewed every system tick. Drops thread priority on budget exhaustion to + * prevent system starvation. + */ + SOF_SCHEDULE_TWB, + /** + * @brief Indicates total number of scheduler types. + */ + SOF_SCHEDULE_COUNT }; -/** \brief Scheduler free available flags */ -#define SOF_SCHEDULER_FREE_IRQ_ONLY BIT(0) /**< Free function disables only - * interrupts - */ +/** @brief Scheduler free available flags. */ +#define SOF_SCHEDULER_FREE_IRQ_ONLY BIT(0) /**< Free function disables interrupts only, keeping data structures intact. */ + /** - * Scheduler operations. + * @brief Scheduler operations interface table. * - * Almost all schedule operations must return 0 for success and negative values - * for errors. Only the scheduler_free operation is allowed to not return any - * status. + * Schedulers implement this interface to plug into the unified SOF scheduling abstraction. + * Almost all schedule operations must return 0 for success and negative values for errors. + * Only the optional scheduler_free operation returns void. */ struct scheduler_ops { /** - * Schedules task with given scheduling parameters. - * @param data Private data of selected scheduler. - * @param task Task to be scheduled. - * @param start Start time of given task (in microseconds). - * @param period Scheduling period of given task (in microseconds). - * @return 0 if succeeded, error code otherwise. + * @brief Schedule a task with the given timing parameters. + * @param[in,out] data Private state of the selected scheduler. + * @param[in,out] task Task descriptor to be scheduled. + * @param[in] start Start timing parameter (scheduler-specific, e.g. start delay or absolute tick for LL). + * @param[in] period Repetition period in microseconds for periodic schedulers (such as LL, where 0 denotes + * one-shot). Schedulers such as DP and TWB ignore this parameter as rescheduling is + * governed by the task's returned execution state. + * @return 0 on success, negative error code on failure. * * This operation is mandatory. */ @@ -71,13 +99,13 @@ struct scheduler_ops { uint64_t period); /** - * Schedules task with given scheduling parameters. - * @param data Private data of selected scheduler. - * @param task Task to be scheduled. - * @param start Start time of given task (in microseconds). - * @param period Scheduling period of given task (in microseconds). - * @param before Task to be scheduled before - * @return 0 if succeeded, error code otherwise. + * @brief Schedule a task to execute before a specified reference task. + * @param[in,out] data Private state of the selected scheduler. + * @param[in,out] task Task descriptor to be scheduled. + * @param[in] start Start timing parameter (scheduler-specific). + * @param[in] period Repetition period in microseconds (scheduler-specific). + * @param[in] before Reference task before which this task must be enqueued. + * @return 0 on success, negative error code on failure. * * This operation is optional. */ @@ -85,13 +113,13 @@ struct scheduler_ops { uint64_t period, struct task *before); /** - * Schedules task with given scheduling parameters. - * @param data Private data of selected scheduler. - * @param task Task to be scheduled. - * @param start Start time of given task (in microseconds). - * @param period Scheduling period of given task (in microseconds). - * @param after Task to be scheduled after - * @return 0 if succeeded, error code otherwise. + * @brief Schedule a task to execute after a specified reference task. + * @param[in,out] data Private state of the selected scheduler. + * @param[in,out] task Task descriptor to be scheduled. + * @param[in] start Start timing parameter (scheduler-specific). + * @param[in] period Repetition period in microseconds (scheduler-specific). + * @param[in] after Reference task after which this task must be enqueued. + * @return 0 on success, negative error code on failure. * * This operation is optional. */ @@ -99,42 +127,41 @@ struct scheduler_ops { uint64_t period, struct task *after); /** - * Sets task into running state along with executing additional - * scheduler specific operations. - * @param data Private data of selected scheduler. - * @param task Task to be set into running state. - * @return 0 if succeeded, error code otherwise. + * @brief Transition a task to running state and perform scheduler-specific execution hooks. + * @param[in,out] data Private state of the selected scheduler. + * @param[in,out] task Task transitioning to running state. + * @return 0 on success, negative error code on failure. * * This operation is optional. */ int (*schedule_task_running)(void *data, struct task *task); /** - * Reschedules already scheduled task with new start time. - * @param data Private data of selected scheduler. - * @param task Task to be rescheduled. - * @param start New start time of given task (in microseconds). - * @return 0 if succeeded, error code otherwise. + * @brief Reschedule an already scheduled task with an updated start delay. + * @param[in,out] data Private state of the selected scheduler. + * @param[in,out] task Task descriptor to reschedule. + * @param[in] start New start delay in microseconds. + * @return 0 on success, negative error code on failure. * * This operation is optional. */ int (*reschedule_task)(void *data, struct task *task, uint64_t start); /** - * Cancels previously scheduled task. - * @param data Private data of selected scheduler. - * @param task Task to be canceled. - * @return 0 if succeeded, error code otherwise. + * @brief Cancel a previously scheduled task. + * @param[in,out] data Private state of the selected scheduler. + * @param[in,out] task Task descriptor to cancel. + * @return 0 on success, negative error code on failure. * * This operation is mandatory. */ int (*schedule_task_cancel)(void *data, struct task *task); /** - * Frees task's resources. - * @param data Private data of selected scheduler. - * @param task Task to be freed. - * @return 0 if succeeded, error code otherwise. + * @brief Free scheduler resources associated with a task. + * @param[in,out] data Private state of the selected scheduler. + * @param[in,out] task Task descriptor whose resources are to be freed. + * @return 0 on success, negative error code on failure. * * This operation is mandatory. */ @@ -142,63 +169,76 @@ struct scheduler_ops { #if CONFIG_SOF_BOOT_TEST_STANDALONE || CONFIG_LIBRARY /** - * Frees scheduler's resources. - * @param data Private data of selected scheduler. - * @param flags Function specific flags. - * @return 0 if succeeded, error code otherwise. + * @brief Free the scheduler instance and release its underlying resources. + * @param[in,out] data Private state of the selected scheduler. + * @param[in] flags Scheduler-specific free flags (e.g. @ref SOF_SCHEDULER_FREE_IRQ_ONLY). * - * This operation is optional. + * This operation is optional (used only in standalone testing and library testbench). */ void (*scheduler_free)(void *data, uint32_t flags); #endif /** - * Initializes context - * @param data Private data of selected scheduler. - * @param task task that needs to be scheduled - * @return thread that will be used to run the scheduled task + * @brief Initialize execution thread context for a scheduled task. + * @param[in,out] data Private state of the selected scheduler. + * @param[in,out] task Task requiring dedicated execution context. + * @return Pointer to allocated Zephyr thread object, or NULL on error or unsupported. * * This operation is optional. */ struct k_thread *(*scheduler_init_context)(void *data, struct task *task); }; -/** \brief Holds information about scheduler. */ +/** + * @brief Descriptor container representing a registered scheduler instance. + */ struct schedule_data { - struct list_item list; /**< list of schedulers */ - int type; /**< SOF_SCHEDULE_ type */ - const struct scheduler_ops *ops; /**< scheduler operations */ - void *data; /**< pointer to private data */ + struct list_item list; /**< List node linking this scheduler into the per-core schedulers list. */ + int type; /**< Scheduler type identifier (SOF_SCHEDULE_*). */ + const struct scheduler_ops *ops; /**< Pointer to scheduler operations table. */ + void *data; /**< Pointer to scheduler-specific private context data. */ }; -/** \brief Holds list of all registered schedulers. */ +/** + * @brief Container holding the linked list of all registered schedulers on a core. + */ struct schedulers { - struct list_item list; /**< list of schedulers */ + struct list_item list; /**< Head of the linked list of registered schedulers. */ }; /** - * Retrieves registered schedulers. - * @return List of registered schedulers. + * @brief Retrieve the array of registered kernel-space schedulers for the current core. + * + * Must only be called from privileged/kernel context (!k_is_user_context()). + * + * @return Pointer to the per-core schedulers list head pointer. */ struct schedulers **arch_schedulers_get(void); /** - * @brief Retrieves registered schedulers for user-space threads on the current core. - * @return Pointer to array of registered scheduler pointers. + * @brief Retrieve registered schedulers for user-space threads on the current core. + * + * Invokes cpu_get_id(), so this function must only be called from kernel context. + * User-space callers should use @ref arch_user_schedulers_get_for_core instead. + * + * @return Pointer to the per-core user schedulers list head pointer, or NULL if user LL is disabled. */ struct schedulers **arch_user_schedulers_get(void); /** - * @brief Retrieves registered schedulers for user-space threads on a specific core. - * @param core Target DSP core ID. - * @return Pointer to array of registered scheduler pointers for the specified core. + * @brief Retrieve registered schedulers for user-space threads on a specific core. + * + * Safe to invoke from user-space contexts because the target core ID is explicitly provided. + * + * @param[in] core Target DSP core ID. + * @return Pointer to the user schedulers list head pointer for the specified core, or NULL if disabled. */ struct schedulers **arch_user_schedulers_get_for_core(int core); /** - * @brief Lookup scheduler private context data by scheduler type. - * @param schedulers Schedulers list container. - * @param type Scheduler type identifier (SOF_SCHEDULE_LL, SOF_SCHEDULE_EDF, etc.). + * @brief Lookup scheduler private context data by scheduler type from a schedulers container. + * @param[in] schedulers Schedulers list container. + * @param[in] type Scheduler type identifier (SOF_SCHEDULE_*). * @return Pointer to scheduler-specific private data, or NULL if not found. */ static inline void *scheduler_list_get_data(struct schedulers *schedulers, uint16_t type) @@ -219,9 +259,9 @@ static inline void *scheduler_list_get_data(struct schedulers *schedulers, uint1 } /** - * Retrieves scheduler's data. - * @param type SOF_SCHEDULE_ type. - * @return Pointer to scheduler's data. + * @brief Retrieve private data of a registered kernel scheduler on the current core. + * @param[in] type Scheduler type (SOF_SCHEDULE_*). + * @return Pointer to scheduler private data, or NULL if not found. */ static inline void *scheduler_get_data(uint16_t type) { @@ -229,16 +269,20 @@ static inline void *scheduler_get_data(uint16_t type) } /** - * Retrieves userspace scheduler's data. - * @param type SOF_SCHEDULE_ type. - * @return Pointer to scheduler's data. + * @brief Retrieve private data of a registered user-space scheduler on the current core. + * @param[in] type Scheduler type (SOF_SCHEDULE_*). + * @return Pointer to scheduler private data, or NULL if not found. */ static inline void *scheduler_get_user_data(uint16_t type) { return scheduler_list_get_data(*arch_user_schedulers_get(), type); } -/** See scheduler_ops::schedule_task_running */ +/** + * @brief Notify the scheduler that a task is transitioning to the running state. + * @param[in,out] task Task being set to running. + * @return 0 on success, or negative error code from scheduler ops. + */ static inline int schedule_task_running(struct task *task) { struct schedule_data *sch; @@ -252,7 +296,13 @@ static inline int schedule_task_running(struct task *task) return sch->ops->schedule_task_running(sch->data, task); } -/** See scheduler_ops::schedule_task */ +/** + * @brief Schedule a task for execution with start delay and period. + * @param[in,out] task Task to schedule. + * @param[in] start Start delay in microseconds from now. + * @param[in] period Repetition period in microseconds (0 for one-shot execution). + * @return 0 on success, -EINVAL if task is NULL, or negative error code from scheduler ops. + */ static inline int schedule_task(struct task *task, uint64_t start, uint64_t period) { @@ -266,7 +316,19 @@ static inline int schedule_task(struct task *task, uint64_t start, return sch->ops->schedule_task(sch->data, task, start, period); } -/** See scheduler_ops::schedule_task_before */ +/** + * @brief Schedule a task to execute before a specified reference task. + * + * @note Relative task ordering is optional and scheduler-specific. If the underlying + * scheduler does not implement schedule_task_before, this wrapper falls back to + * ordinary schedule_task() and ignores @p before. + * + * @param[in,out] task Task to schedule. + * @param[in] start Start timing parameter (scheduler-specific). + * @param[in] period Repetition period in microseconds (scheduler-specific). + * @param[in] before Reference task before which this task must run. + * @return 0 on success, -EINVAL if arguments are invalid, or negative error code from scheduler ops. + */ static inline int schedule_task_before(struct task *task, uint64_t start, uint64_t period, struct task *before) { @@ -284,7 +346,19 @@ static inline int schedule_task_before(struct task *task, uint64_t start, return sch->ops->schedule_task(sch->data, task, start, period); } -/** See scheduler_ops::schedule_task_after */ +/** + * @brief Schedule a task to execute after a specified reference task. + * + * @note Relative task ordering is optional and scheduler-specific. If the underlying + * scheduler does not implement schedule_task_after, this wrapper falls back to + * ordinary schedule_task() and ignores @p after. + * + * @param[in,out] task Task to schedule. + * @param[in] start Start timing parameter (scheduler-specific). + * @param[in] period Repetition period in microseconds (scheduler-specific). + * @param[in] after Reference task after which this task must run. + * @return 0 on success, -EINVAL if arguments are invalid, or negative error code from scheduler ops. + */ static inline int schedule_task_after(struct task *task, uint64_t start, uint64_t period, struct task *after) { @@ -302,7 +376,12 @@ static inline int schedule_task_after(struct task *task, uint64_t start, return sch->ops->schedule_task(sch->data, task, start, period); } -/** See scheduler_ops::reschedule_task */ +/** + * @brief Reschedule an already scheduled task with an updated start time. + * @param[in,out] task Task to reschedule. + * @param[in] start New start delay in microseconds. + * @return 0 on success, or negative error code from scheduler ops. + */ static inline int reschedule_task(struct task *task, uint64_t start) { struct schedule_data *sch; @@ -317,7 +396,11 @@ static inline int reschedule_task(struct task *task, uint64_t start) return sch->ops->reschedule_task(sch->data, task, start); } -/** See scheduler_ops::schedule_task_cancel */ +/** + * @brief Cancel a scheduled or queued task. + * @param[in,out] task Task to cancel. + * @return 0 on success, -EINVAL if task or bound scheduler is NULL, or negative error code from scheduler ops. + */ static inline int schedule_task_cancel(struct task *task) { struct schedule_data *sch; @@ -330,7 +413,11 @@ static inline int schedule_task_cancel(struct task *task) return sch->ops->schedule_task_cancel(sch->data, task); } -/** See scheduler_ops::schedule_task_free */ +/** + * @brief Free scheduler resources associated with a task. + * @param[in,out] task Task whose resources should be freed. + * @return 0 on success, -EINVAL if task or bound scheduler is NULL, or negative error code from scheduler ops. + */ static inline int schedule_task_free(struct task *task) { struct schedule_data *sch; @@ -345,7 +432,10 @@ static inline int schedule_task_free(struct task *task) /* Only used in a stand-alone test and in a testbench test */ #if CONFIG_SOF_BOOT_TEST_STANDALONE || CONFIG_LIBRARY -/** See scheduler_ops::scheduler_free */ +/** + * @brief Free all registered schedulers and their resources (testing/library only). + * @param[in] flags Scheduler-specific free flags (e.g. @ref SOF_SCHEDULER_FREE_IRQ_ONLY). + */ static inline void schedule_free(uint32_t flags) { struct schedulers *schedulers = *arch_schedulers_get(); @@ -360,7 +450,11 @@ static inline void schedule_free(uint32_t flags) } #endif -/** See scheduler_ops::scheduler_init_context */ +/** + * @brief Initialize thread execution context for a task. + * @param[in,out] task Task requiring execution context initialization. + * @return Pointer to allocated Zephyr thread, or NULL if unsupported or failed. + */ static inline struct k_thread *scheduler_init_context(struct task *task) { struct schedule_data *sch; @@ -375,16 +469,23 @@ static inline struct k_thread *scheduler_init_context(struct task *task) } /** - * Initializes scheduling task. - * @param task Task to be initialized. - * @param uid Statically assigned task uuid. - * @param type SOF_SCHEDULE_ type. - * @param priority Task's priority. - * @param run Pointer to task's execution function. - * @param data Pointer to task's execution data. - * @param core Core on which task should be run. - * @param flags Special scheduling flags. - * @return 0 if succeeded, error code otherwise. + * @brief Initialize a scheduling task and bind it to the registered scheduler for its type and core. + * + * Validates scheduler type and searches registered schedulers. User schedulers look up the + * target core via arch_user_schedulers_get_for_core(core), whereas kernel schedulers look up + * via arch_schedulers_get() on the calling core. Therefore, kernel task initialization must + * execute directly on the target core. Initializes task properties, priority, execution callback, + * and sets task state to @ref SOF_TASK_STATE_INIT. + * + * @param[out] task Task structure to initialize. + * @param[in] uid Statically assigned task UUID entry. + * @param[in] type Scheduler type (SOF_SCHEDULE_*). + * @param[in] priority Task scheduling priority (lower values indicate higher priority). + * @param[in] run Execution callback function returning @ref task_state. + * @param[in] data Private context pointer passed to run callback. + * @param[in] core DSP core ID on which the task should execute. + * @param[in] flags Task-specific scheduling flags. + * @return 0 on success, -EINVAL if type >= SOF_SCHEDULE_COUNT, -ENODEV if scheduler cannot be found. */ int schedule_task_init(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, @@ -392,18 +493,26 @@ int schedule_task_init(struct task *task, void *data, uint16_t core, uint32_t flags); /** - * Initializes scheduler - * @param type SOF_SCHEDULE_ type. - * @param ops Pointer to scheduler's operations. - * @param data Scheduler's private data. + * @brief Register a scheduler type instance with its operations table and private context data. + * + * Allocates a @ref schedule_data container on the system (or user) heap, links it into + * the active core scheduler list, and associates the provided operations. + * + * @param[in] type Scheduler type identifier (SOF_SCHEDULE_*). + * @param[in] ops Pointer to scheduler operations table (must provide schedule_task, schedule_task_cancel, schedule_task_free). + * @param[in] data Pointer to scheduler private instance data. */ 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 + * @brief Extract scheduler task telemetry and properties for IPC4 base firmware. + * + * Populates @ref scheduler_props with the calling core ID and total task count, + * appending @ref task_props structures for each active task in the list. + * + * @param[out] scheduler_props Properties structure to be filled. + * @param[in,out] data_off_size Pointer to running byte size of scheduler_props buffer. + * @param[in] tasks Linked list of tasks to inspect. */ void scheduler_get_task_info(struct scheduler_props *scheduler_props, uint32_t *data_off_size, struct list_item *tasks); diff --git a/src/include/sof/schedule/twb_schedule.h b/src/include/sof/schedule/twb_schedule.h index be7c06d0706f..586c880123ff 100644 --- a/src/include/sof/schedule/twb_schedule.h +++ b/src/include/sof/schedule/twb_schedule.h @@ -5,78 +5,85 @@ * Author: Adrian Bonislawski */ +/** + * @file sof/schedule/twb_schedule.h + * @brief Thread With Budget (TWB) scheduler interface and cycle accounting. + * @ingroup scheduling_api + * + * The Thread With Budget (TWB) scheduler creates a separate preemptible Zephyr thread + * for each SOF task that has a pre-allocated MCPS budget renewed with every system tick. + * + * ### Key Architectural Properties + * - **Dynamic Priority Switching**: The TWB scheduler assigns either `MEDIUM_PRIORITY` or + * `LOW_PRIORITY` to the task thread based on the budget remaining in the current system tick. + * - **Opportunistic Execution**: If there is no higher-priority ready task, the thread can continue + * executing at low priority even after its budget is exhausted. + * - **Cycle & Tick Accounting**: + * - `cycles_granted`: Budget in Zephyr system clock ticks per period (passed to `k_thread_time_slice_set()`). + * - `cycles_consumed`: Actual execution time consumed during the current period, measured in DSP hardware clock cycles. + * - **Budget Exhaustion & Replenishment**: + * - When consumed cycles exceed granted cycles, Zephyr time slicing triggers `scheduler_twb_task_cb()`, + * which lowers thread priority to `CONFIG_TWB_THREAD_LOW_PRIORITY`. + * - On the next Low-Latency tick (`scheduler_twb_ll_tick()`), consumed cycles are reset to 0, + * and the original thread priority is restored. Unused budget is not carried over. + */ + #ifndef __SOF_SCHEDULE_TWB_SCHEDULE_H__ #define __SOF_SCHEDULE_TWB_SCHEDULE_H__ #include #include -/** - * @brief Task With Budget (TWB) Scheduler - * - * TWB scheduler is a scheduler that creates a separate preemptible Zephyr thread - * for each SOF task that has a pre-allocated MCPS budget renewed with every system tick. - * The TWB scheduler assigns either MEDIUM_PRIORITY or LOW_PRIORITY to the task thread - * based on the budget left in the current system tick. - * It allows for opportunistic execution if there is no other ready task - * with a higher priority while the budget is already spent. - * - * Examples of tasks with budget include IPC Task and IDC Task. - * - * The TWB scheduler has two key parameters assigned: - * - cycles granted: the budget per system tick - * - cycles consumed: the number of cycles consumed in a given system tick for task execution - * - * The number of cycles consumed is reset to 0 at the beginning of each system tick, - * renewing the TWB budget. - * When the number of cycles consumed exceeds the cycles granted, - * the task is switchedfrom MEDIUM to LOW priority. - * When the task with budget thread is created, the MPP Scheduling is responsible - * for setting the thread time slice equal to the task budget, along with - * setting a callback on time slice timeout. - * Thread time slicing guarantees that the Zephyr scheduler will interrupt execution - * when the budget is spent, - * so the MPP Scheduling timeout callback can re-evaluate the task priority. - * - * If there is a budget left in some system tick - * (i.e., the task spent less time or started executing closeto the system tick - * that preempts execution), it is reset and not carried over to the next tick. - * - * More info: - * https://thesofproject.github.io/latest/architectures/firmware/sof-zephyr/mpp_layer/mpp_scheduling.html +/** \addtogroup scheduling_api + * @{ */ /** - * \brief default static stack size for each TWB thread + * @brief Default static stack size in bytes for each TWB worker thread. */ #define ZEPHYR_TWB_STACK_SIZE 8192 /** - * \brief max budget limit + * @brief Maximum budget limit in system clock ticks per period. */ #define ZEPHYR_TWB_BUDGET_MAX (CONFIG_SYS_CLOCK_TICKS_PER_SEC / 1000) +/** + * @brief Convert Zephyr system clock ticks to DSP hardware clock cycles. + * @param[in] x System ticks. + */ #define SYS_TICKS_TO_HW_CYCLES(x) (x * CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC) + +/** + * @brief Convert DSP hardware clock cycles to Zephyr system clock ticks. + * @param[in] x Hardware cycles. + */ #define HW_CYCLES_TO_SYS_TICKS(x) (x * CONFIG_SYS_CLOCK_TICKS_PER_SEC / CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) /** - * \brief Init the Tasks with Budget scheduler + * @brief Initialize the Thread With Budget (TWB) scheduler on the calling core. + * + * Allocates per-core TWB scheduler state and binds its driving LL tick source task. + * + * @return 0 on success, negative error code (-ENOMEM) on failure. */ int scheduler_twb_init(void); /** - * \brief initialize a TWB task and add it to scheduling - * It must be called on core the task is declared to run on + * @brief Initialize a TWB task with a dedicated Zephyr worker thread and cycle budget. * - * \param[out] task pointer, pointer to allocated task structure will be return - * \param[in] uid pointer to UUID of the task - * \param[in] ops pointer to task functions - * \param[in] data pointer to the task data - * \param[in] core CPU the thread should run on - * \param[in] name zephyr thread name - * \param[in] stack_size size of stack for a zephyr thread - * \param[in] thread_priority priority of the zephyr thread - * \param[in] cycles_granted cycles budget for the zephyr thread + * Must be invoked on the same core that the task is configured to execute on. + * + * @param[out] task Pointer to store the allocated @ref task structure. + * @param[in] uid UUID identifying the task. + * @param[in] ops Task operations callbacks (@ref task_ops). + * @param[in] data Private context pointer passed to task callbacks. + * @param[in] core DSP core affinity for the worker thread. + * @param[in] name Debug name assigned to the Zephyr thread. + * @param[in] stack_size Stack byte size for the worker thread. + * @param[in] thread_priority Default preemptible thread priority (must be >= 0). + * @param[in] cycles_granted Budget in Zephyr system clock ticks per period (0 or >= ZEPHYR_TWB_BUDGET_MAX for unlimited). + * @return 0 on success, negative error code (-EINVAL, -ENOMEM, -EFAULT) on failure. */ int scheduler_twb_task_init(struct task **task, const struct sof_uuid_entry *uid, @@ -88,4 +95,6 @@ int scheduler_twb_task_init(struct task **task, int32_t thread_priority, uint32_t cycles_granted); +/** @}*/ + #endif /* __SOF_SCHEDULE_TWB_SCHEDULE_H__ */ diff --git a/src/platform/library/include/platform/lib/ll_schedule.h b/src/platform/library/include/platform/lib/ll_schedule.h index b5ba7f94da6a..0a5a2cf9d70a 100644 --- a/src/platform/library/include/platform/lib/ll_schedule.h +++ b/src/platform/library/include/platform/lib/ll_schedule.h @@ -3,6 +3,12 @@ * Copyright(c) 2016 Intel Corporation. All rights reserved. */ +/** + * @file platform/lib/ll_schedule.h + * @brief Platform library / testbench Low-Latency scheduler mock declarations. + * @ingroup scheduling_api + */ + #ifndef __LIBRARY_INCLUDE_LIB_SCHEDULE_H__ #define __LIBRARY_INCLUDE_LIB_SCHEDULE_H__ @@ -13,10 +19,30 @@ struct task; struct sof_uuid_entry; struct ll_schedule_domain; +/** + * @brief Run one iteration of all active Low-Latency tasks (library testbench harness). + */ void schedule_ll_run_tasks(void); +/** + * @brief Initialize Low-Latency scheduler on library/testbench platform. + * @param[in,out] domain Low-Latency scheduling domain. + * @return 0 on success, negative error code on failure. + */ int scheduler_init_ll(struct ll_schedule_domain *domain); +/** + * @brief Initialize a Low-Latency task descriptor for library/testbench execution. + * @param[out] task Task structure to initialize. + * @param[in] uid UUID identifying the task or associated component. + * @param[in] type Scheduler type identifier (SOF_SCHEDULE_LL_TIMER or SOF_SCHEDULE_LL_DMA). + * @param[in] priority Scheduling priority level (lower values run first). + * @param[in] run Main execution callback function. + * @param[in] data Context pointer passed to run callback. + * @param[in] core Target DSP core ID. + * @param[in] flags Task-specific scheduling flags. + * @return 0 on success, negative error code on failure. + */ int schedule_task_init_ll(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, int16_t priority, enum task_state (*run)(void *data), diff --git a/src/schedule/zephyr_dp_schedule.h b/src/schedule/zephyr_dp_schedule.h index d33e6895507c..07d8ee4a4754 100644 --- a/src/schedule/zephyr_dp_schedule.h +++ b/src/schedule/zephyr_dp_schedule.h @@ -5,6 +5,12 @@ * Author: Marcin Szkudlinski */ +/** + * @file src/schedule/zephyr_dp_schedule.h + * @brief Internal Data Processing (DP) scheduler structures, memory partitions, and thread helpers. + * @ingroup scheduling_api + */ + #include #include #include @@ -15,46 +21,84 @@ #include #include +/** + * @brief Per-core Data Processing (DP) scheduler private state. + */ struct scheduler_dp_data { - struct list_item tasks; /* list of active dp tasks */ - struct task ll_tick_src; /* LL task - source of DP tick */ - uint32_t last_ll_tick_timestamp;/* a timestamp as k_cycle_get_32 of last LL tick, - * "NOW" for DP deadline calculation - */ + struct list_item tasks; /**< Head of the linked list of active DP tasks. */ + struct task ll_tick_src; /**< Low-Latency driver task generating periodic DP tick notifications. */ + uint32_t last_ll_tick_timestamp; /**< Timestamp (via k_cycle_get_32()) of last LL tick, defining "NOW" for DP deadline calculation. */ }; +/** + * @brief User-space memory partition types for isolated DP module execution. + */ enum sof_dp_part_type { - SOF_DP_PART_HEAP, - SOF_DP_PART_HEAP_CACHE, - SOF_DP_PART_CFG, - SOF_DP_PART_CFG_CACHE, - SOF_DP_PART_TYPE_COUNT, + SOF_DP_PART_HEAP, /**< Heap memory partition for dynamic allocations. */ + SOF_DP_PART_HEAP_CACHE, /**< Cached heap memory partition. */ + SOF_DP_PART_CFG, /**< Module configuration and parameters memory partition. */ + SOF_DP_PART_CFG_CACHE, /**< Cached module configuration partition. */ + SOF_DP_PART_TYPE_COUNT, /**< Total number of DP partition types. */ }; struct ipc4_flat; +/** + * @brief Private data container associated with a Data Processing (DP) task. + */ struct task_dp_pdata { - k_tid_t thread_id; /* zephyr thread ID */ - struct k_thread *thread; /* pointer to the kernels' thread object */ - struct k_thread thread_struct; /* thread object for kernel threads */ - uint32_t deadline_clock_ticks; /* dp module deadline in Zephyr ticks */ - k_thread_stack_t *p_stack; /* pointer to thread stack */ - struct processing_module *mod; /* the module to be scheduled */ - uint32_t ll_cycles_to_start; /* current number of LL cycles till delayed start */ + k_tid_t thread_id; /**< Zephyr thread identifier for the worker thread. */ + struct k_thread *thread; /**< Pointer to the Zephyr kernel thread object. */ + struct k_thread thread_struct; /**< Embedded thread control block for kernel-mode worker threads. */ + uint32_t deadline_clock_ticks; /**< Processing module deadline in Zephyr system clock ticks. */ + k_thread_stack_t *p_stack; /**< Pointer to dedicated stack memory allocated for the thread. */ + struct processing_module *mod; /**< Processing module descriptor bound to this scheduling task. */ + uint32_t ll_cycles_to_start; /**< Current count of LL cycles remaining until delayed start. */ #if CONFIG_SOF_USERSPACE_APPLICATION - uint8_t *ipc_config_data; - struct ipc4_flat *flat; - struct k_mem_partition mpart[SOF_DP_PART_TYPE_COUNT]; + uint8_t *ipc_config_data; /**< Staged IPC configuration buffer for user-space module. */ + struct ipc4_flat *flat; /**< Flat IPC4 container for user-space parameter passing. */ + struct k_mem_partition mpart[SOF_DP_PART_TYPE_COUNT]; /**< Memory partitions assigned to the user thread. */ #endif - struct k_event *event; /* pointer to event for task scheduling */ - struct k_event event_struct; /* event for task scheduling for kernel threads */ + struct k_event *event; /**< Pointer to Zephyr event object signaling work availability. */ + struct k_event event_struct; /**< Embedded event object for kernel-mode worker threads. */ #if IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) - struct k_work_user *ipc_work_item; /* work item for IPC handling */ + struct k_work_user *ipc_work_item; /**< User work item for dispatching asynchronous module IPC commands. */ #endif }; +/** + * @brief Recalculate deadlines and evaluate readiness for all active DP tasks on an LL tick. + * @param[in,out] dp_sch Pointer to per-core DP scheduler state container. + */ void scheduler_dp_recalculate(struct scheduler_dp_data *dp_sch); + +/** + * @brief Worker thread entry point function for Data Processing tasks. + * + * Runs an infinite event loop waiting on `pdata->event` for process, IPC, or cancel signals. + * + * @param[in] p1 Pointer to the bound @ref task structure. + * @param[in] p2 Unused parameter (NULL). + * @param[in] p3 Unused parameter (NULL). + */ void dp_thread_fn(void *p1, void *p2, void *p3); + +/** + * @brief Acquire the per-core Data Processing scheduler synchronization lock. + * @param[in] core DSP core ID whose lock should be acquired. + * @return Lock key (core ID) to be passed to @ref scheduler_dp_unlock. + */ unsigned int scheduler_dp_lock(uint16_t core); + +/** + * @brief Release the per-core Data Processing scheduler synchronization lock. + * @param[in] key Lock key returned by @ref scheduler_dp_lock. + */ void scheduler_dp_unlock(unsigned int key); + +/** + * @brief Grant user-space DP worker thread access to core synchronization primitives and events. + * @param[in] thread_id Target Zephyr thread ID. + * @param[in] core Target DSP core ID. + */ void scheduler_dp_grant(k_tid_t thread_id, uint16_t core); diff --git a/zephyr/include/rtos/alloc.h b/zephyr/include/rtos/alloc.h index a146aa0ead92..6b2d89b05b6d 100644 --- a/zephyr/include/rtos/alloc.h +++ b/zephyr/include/rtos/alloc.h @@ -6,7 +6,7 @@ /** * @file rtos/alloc.h * @brief Memory allocation API, zones, heaps, and alignment utilities. - * @ingroup rtos_api + * @ingroup memory_api */ #ifndef __ZEPHYR_RTOS_ALLOC_H__ @@ -21,7 +21,7 @@ #include #include -/** \addtogroup rtos_api +/** \addtogroup memory_api * @{ */ @@ -35,59 +35,114 @@ * @{ */ - /** \brief Allocate DMA-able memory. */ +/** \brief Allocate memory accessible by DMA controllers (e.g. Host or DSP DMA). */ #define SOF_MEM_FLAG_DMA BIT(2) -/** \brief realloc() skips copying the original content. */ +/** + * \brief realloc() skips copying the original content. + * @deprecated Legacy realloc optimization flag. rbrealloc() and rbrealloc_align() + * have been removed from the allocation API. + */ #define SOF_MEM_FLAG_NO_COPY BIT(3) -/** \brief Allocate uncached address. */ +/** + * \brief Allocate uncached / coherent memory address. + * + * Directs the allocator to return an uncached pointer (e.g. bypassing cache alias + * or mapping uncached). Mandatory for DMA descriptors, mailboxes, and cross-core + * shared variables. Not supported for L3 memory. + */ #define SOF_MEM_FLAG_COHERENT BIT(4) -/** \brief Allocate L3 address. */ +/** + * \brief Allocate from L3 address space (IMR / external DRAM heap). + * + * Allocates from the L3 heap (l3_heap). Only cached allocations are supported; + * requesting coherent L3 memory will fail and return NULL. + */ #define SOF_MEM_FLAG_L3 BIT(5) -/** \brief Allocate Low power memory address. */ +/** + * \brief Allocate Low power memory address. + * @deprecated Legacy flag from XTOS memory partitions; no-op in modern Zephyr heap manager. + */ #define SOF_MEM_FLAG_LOW_POWER BIT(6) -/** \brief Allocate kernel memory address. */ +/** \brief Base allocation flag denoting memory allocated for kernel-space data structures. */ #define SOF_MEM_FLAG_KERNEL BIT(7) -/** \brief Allocate user memory address. */ +/** \brief Base allocation flag denoting memory allocated for user-space threads and module execution. */ #define SOF_MEM_FLAG_USER BIT(8) -/** \brief Allocate shared user memory address. */ +/** \brief Allocate from shared user memory heap (shared_buffer_heap) accessible across user/kernel domains. */ #define SOF_MEM_FLAG_USER_SHARED_BUFFER BIT(9) -/** \brief Use allocation method for large buffers. */ +/** \brief Route allocation to the Virtual Memory Heap (VMH / virtual_buffers_heap) for large stream buffers. */ #define SOF_MEM_FLAG_LARGE_BUFFER BIT(10) /** @} */ /** - * Allocates memory block. - * @param flags Flags, see SOF_MEM_FLAG_.... - * @param bytes Size in bytes. - * @param alignment Alignment in bytes. - * @return Pointer to the allocated memory or NULL if failed. + * @brief Allocate memory block with explicit alignment and heap selection flags. * + * Core RTOS memory allocator. Evaluates @p flags to select the appropriate heap: + * - #SOF_MEM_FLAG_L3: Allocates from the L3 IMR / external DRAM heap (cached only). + * - #SOF_MEM_FLAG_USER_SHARED_BUFFER: Allocates from shared_buffer_heap. + * - Default: Allocates from system heap (sof_heap). + * + * If #SOF_MEM_FLAG_COHERENT is specified, returns an uncached (coherent) pointer. + * Otherwise, returns a cached pointer. When CONFIG_VIRTUAL_HEAP is enabled and + * system heap allocation fails, transparently attempts fallback allocation from + * the Virtual Memory Heap (VMH). + * + * @param[in] flags Memory allocation flags, see SOF_MEM_FLAG_... + * @param[in] bytes Size in bytes to allocate. + * @param[in] alignment Required alignment in bytes (0 for default/natural alignment). + * @return Pointer to the allocated memory block, or NULL on allocation failure. */ void *rmalloc_align(uint32_t flags, size_t bytes, uint32_t alignment); /** - * Similar to rmalloc_align(), but no alignment can be specified. + * @brief Allocate memory block with default natural alignment. + * + * Convenience wrapper calling rmalloc_align() with alignment set to 0. + * + * @param[in] flags Memory allocation flags, see SOF_MEM_FLAG_... + * @param[in] bytes Size in bytes to allocate. + * @return Pointer to the allocated memory block, or NULL on allocation failure. */ void *rmalloc(uint32_t flags, size_t bytes); /** - * Similar to rmalloc(), guarantees that returned block is zeroed. + * @brief Allocate zero-initialized memory block with default natural alignment. + * + * Allocates memory via rmalloc() and, if successful, zeroes the entire block + * with memset() before returning. + * + * @param[in] flags Memory allocation flags, see SOF_MEM_FLAG_... + * @param[in] bytes Size in bytes to allocate. + * @return Pointer to zero-initialized memory block, or NULL on allocation failure. */ void *rzalloc(uint32_t flags, size_t bytes); /** - * Allocates memory block. - * @param flags Flags, see SOF_MEM_FLAG_... - * @param bytes Size in bytes. - * @param alignment Alignment in bytes. - * @return Pointer to the allocated memory or NULL if failed. + * @brief Allocate runtime stream buffer with explicit alignment. + * + * Runtime buffer allocator designed for audio stream buffers. Unlike rmalloc_align(), + * rballoc_align() actively prioritizes the Virtual Memory Heap (VMH / virtual_buffers_heap) + * when CONFIG_VIRTUAL_HEAP is enabled to preserve internal SRAM. Supports + * #SOF_MEM_FLAG_L3 and #SOF_MEM_FLAG_USER_SHARED_BUFFER. Respects + * #SOF_MEM_FLAG_COHERENT for system and shared heaps, but note that the L3 heap + * path returns cached memory directly and does not support coherent uncached views. + * + * @param[in] flags Memory allocation flags, see SOF_MEM_FLAG_... + * @param[in] bytes Size in bytes to allocate. + * @param[in] alignment Required alignment in bytes. + * @return Pointer to allocated buffer, or NULL on allocation failure. */ void *rballoc_align(uint32_t flags, size_t bytes, uint32_t alignment); /** - * Similar to rballoc_align(), returns buffer aligned to PLATFORM_DCACHE_ALIGN. + * @brief Allocate runtime stream buffer aligned to platform data cache line size. + * + * Helper calling rballoc_align() with alignment set to PLATFORM_DCACHE_ALIGN. + * + * @param[in] flags Memory allocation flags, see SOF_MEM_FLAG_... + * @param[in] bytes Size in bytes to allocate. + * @return Pointer to allocated buffer aligned to cache line, or NULL on failure. */ static inline void *rballoc(uint32_t flags, size_t bytes) { @@ -95,22 +150,31 @@ static inline void *rballoc(uint32_t flags, size_t bytes) } /** - * Frees the memory block. - * @param ptr Pointer to the memory block. + * @brief Free memory block allocated by SOF RTOS allocators. + * + * Unified memory deallocator. Automatically determines the origin heap + * (L3 heap, Virtual Memory Heap, shared buffer heap, or system heap) using + * address boundary checks and returns memory to the respective pool. + * Passing a NULL pointer is safely treated as a no-op. + * + * @param[in,out] ptr Pointer to the memory block to free (can be NULL). */ void rfree(void *ptr); /** - * Save L3 heap over DSP reset + * @brief Save and flush L3 heap state and metadata across DSP reset or power gating. + * + * Flushes dirty cache lines for the L3 heap region and copies metadata into + * preserved storage to ensure data persistence across low-power reset cycles. */ void l3_heap_save(void); /** * @brief Allocate memory from a specified Zephyr heap or default system heap. - * @param heap Target Zephyr k_heap (or NULL to let implementation choose). - * @param flags Memory allocation flags (SOF_MEM_FLAG_...). - * @param bytes Size in bytes to allocate. - * @param alignment Required memory alignment in bytes. + * @param[in,out] heap Target Zephyr k_heap (or NULL to let implementation choose). + * @param[in] flags Memory allocation flags (SOF_MEM_FLAG_...). + * @param[in] bytes Size in bytes to allocate. + * @param[in] alignment Required memory alignment in bytes. * @return Pointer to allocated buffer, or NULL on allocation failure. */ #ifdef CONFIG_SOF_USERSPACE_INTERFACE_ALLOC @@ -118,25 +182,20 @@ __syscall void *sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes size_t alignment); /** * @brief Free memory allocated via sof_heap_alloc(). - * @param heap Target Zephyr k_heap. - * @param addr Address of allocated buffer to free. + * @param[in,out] heap Target Zephyr k_heap. + * @param[in,out] addr Address of allocated buffer to free. */ __syscall void sof_heap_free(struct k_heap *heap, void *addr); #include #else void *sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes, size_t alignment); -/** - * @brief Free memory allocated via sof_heap_alloc(). - * @param heap Target Zephyr k_heap. - * @param addr Address of allocated buffer to free. - */ void sof_heap_free(struct k_heap *heap, void *addr); #endif /** * @brief Get the system kernel heap descriptor. - * @return Pointer to the global system k_heap structure. + * @return Pointer to the global system k_heap structure (sof_heap), or NULL in unit test mode. */ #if CONFIG_SOF_FULL_ZEPHYR_APPLICATION struct k_heap *sof_sys_heap_get(void); @@ -149,41 +208,36 @@ static inline struct k_heap *sof_sys_heap_get(void) #endif /** - * Returns heap object to use for SOF heap allocations - * for audio application code. + * @brief Get the heap object to use for audio application allocations. * - * The returned value may be NULL. This matches with semantics - * of sof_heap_alloc() that allows passing NULL as the 'heap'. - * In this case, the heap implementation will choose the heap to - * use. + * Returns zephyr_ll_user_heap() when CONFIG_SOF_USERSPACE_LL is enabled, + * or NULL to allow sof_heap_alloc() to pick the default heap. * - * The function should not be used for heap allocations for objects that - * are only used in SOF kernel space. + * @note Audio processing modules should use mod_alloc() instead. * - * Note: audio modules should use mod_alloc() instead! + * @return Pointer to application k_heap, or NULL for default heap selection. */ struct k_heap *sof_sys_user_heap_get(void); /** * @brief Trace and log memory allocation statistics across all active heaps. - * @param force Force dumping heap trace even if logging threshold is not met. + * @deprecated No-op stub. Heap diagnostics are tracked via Zephyr runtime + * statistics (CONFIG_SYS_HEAP_RUNTIME_STATS), IPC4 telemetry, + * and VMH diagnostics (vmh_log_stats()). + * @param[in] force Force dumping heap trace even if logging threshold is not met. */ static inline void heap_trace_all(int force) {} -/** @}*/ - #if CONFIG_SOF_USERSPACE_USE_SHARED_HEAP /** - * Returns the start address of shared memory heap for buffers. - * - * @return pointer to shared memory heap start + * @brief Returns the start address of shared memory heap for buffers. + * @return Pointer address to shared memory heap start. */ uintptr_t get_shared_buffer_heap_start(void); /** - * Returns the size of shared memory heap for buffers. - * - * @return size of shared memory heap start + * @brief Returns the total size of shared memory heap for buffers. + * @return Total size of shared memory heap in bytes. */ size_t get_shared_buffer_heap_size(void); @@ -191,23 +245,27 @@ size_t get_shared_buffer_heap_size(void); #include +/** + * @brief Module and pipeline allocation context aggregating a Zephyr heap and optional virtual region. + */ struct mod_alloc_ctx { - struct k_heap *heap; - struct vregion *vreg; + struct k_heap *heap; /**< Underlying Zephyr heap descriptor. */ + struct vregion *vreg; /**< Optional virtual region for interim/lifetime partitioning. */ }; /** - * Allocate memory from a mod_alloc_ctx context. + * @brief Allocate memory from an allocation context. * - * When the context has a vregion, allocates from the vregion interim - * partition. Coherent memory is used when SOF_MEM_FLAG_COHERENT is set - * in flags. Falls back to sof_heap_alloc() otherwise. + * When the context has an associated vregion, allocates from the vregion interim + * partition using vregion_alloc_coherent_align() (if #SOF_MEM_FLAG_COHERENT is set) + * or vregion_alloc_align(). When no vregion is attached, falls back to + * sof_heap_alloc(). * - * @param ctx Allocation context (heap + optional vregion). - * @param flags Allocation flags (SOF_MEM_FLAG_*). - * @param size Size in bytes. - * @param alignment Required alignment in bytes. - * @return Pointer to allocated memory or NULL on failure. + * @param[in,out] ctx Allocation context (heap + optional vregion). + * @param[in] flags Allocation flags (SOF_MEM_FLAG_*). + * @param[in] size Size in bytes to allocate. + * @param[in] alignment Required alignment in bytes. + * @return Pointer to allocated memory, or NULL on failure. */ static inline void *sof_ctx_alloc(struct mod_alloc_ctx *ctx, uint32_t flags, size_t size, size_t alignment) @@ -222,12 +280,15 @@ static inline void *sof_ctx_alloc(struct mod_alloc_ctx *ctx, uint32_t flags, } /** - * Allocate zero-initialized memory from a mod_alloc_ctx context. - * @param ctx Allocation context. - * @param flags Allocation flags (SOF_MEM_FLAG_*). - * @param size Size in bytes. - * @param alignment Required alignment in bytes. - * @return Pointer to allocated memory or NULL on failure. + * @brief Allocate zero-initialized memory from an allocation context. + * + * Allocates memory via sof_ctx_alloc() and clears it with memset() if successful. + * + * @param[in,out] ctx Allocation context. + * @param[in] flags Allocation flags (SOF_MEM_FLAG_*). + * @param[in] size Size in bytes to allocate. + * @param[in] alignment Required alignment in bytes. + * @return Pointer to zero-initialized allocated memory, or NULL on failure. */ static inline void *sof_ctx_zalloc(struct mod_alloc_ctx *ctx, uint32_t flags, size_t size, size_t alignment) @@ -241,9 +302,13 @@ static inline void *sof_ctx_zalloc(struct mod_alloc_ctx *ctx, uint32_t flags, } /** - * Free memory allocated from a mod_alloc_ctx context. - * @param ctx Allocation context. - * @param ptr Pointer to free. + * @brief Free memory allocated from an allocation context. + * + * If the context contains a vregion, frees via vregion_free(); otherwise delegates + * to sof_heap_free(). Passing a NULL pointer is safely treated as a no-op. + * + * @param[in,out] ctx Allocation context. + * @param[in,out] ptr Pointer to memory to free (can be NULL). */ static inline void sof_ctx_free(struct mod_alloc_ctx *ctx, void *ptr) { @@ -256,4 +321,6 @@ static inline void sof_ctx_free(struct mod_alloc_ctx *ctx, void *ptr) sof_heap_free(ctx ? ctx->heap : NULL, ptr); } +/** @}*/ + #endif /* __ZEPHYR_RTOS_ALLOC_H__ */ diff --git a/zephyr/include/rtos/task.h b/zephyr/include/rtos/task.h index 82fedcfff9fa..199f3e552156 100644 --- a/zephyr/include/rtos/task.h +++ b/zephyr/include/rtos/task.h @@ -5,6 +5,12 @@ * Author: Liam Girdwood */ +/** + * @file rtos/task.h + * @brief Core task descriptor, task operations, and task execution state machine. + * @ingroup scheduling_api rtos_api + */ + #ifndef __ZEPHYR_RTOS_TASK_H__ #define __ZEPHYR_RTOS_TASK_H__ @@ -15,66 +21,90 @@ #include #include +/** \addtogroup scheduling_api + * @{ + */ + struct comp_dev; struct sof; struct schedule_data; -/** \brief Predefined LL task priorities. */ -#define SOF_TASK_PRI_HIGH 0 /* priority level 0 - high */ -#define SOF_TASK_PRI_MED 4 /* priority level 4 - medium */ -#define SOF_TASK_PRI_LOW 9 /* priority level 9 - low */ +/** @brief Predefined Low-Latency task priority levels. */ +#define SOF_TASK_PRI_HIGH 0 /**< Priority level 0 - high (hard real-time). */ +#define SOF_TASK_PRI_MED 4 /**< Priority level 4 - medium. */ +#define SOF_TASK_PRI_LOW 9 /**< Priority level 9 - low (background/idle). */ -/** \brief Predefined EDF task deadlines. */ -#define SOF_TASK_DEADLINE_IDLE UINT64_MAX -#define SOF_TASK_DEADLINE_ALMOST_IDLE (SOF_TASK_DEADLINE_IDLE - 1) -#define SOF_TASK_DEADLINE_NOW 0 +/** @brief Predefined EDF task deadlines. */ +#define SOF_TASK_DEADLINE_IDLE UINT64_MAX /**< Idle deadline; run only when nothing else is ready. */ +#define SOF_TASK_DEADLINE_ALMOST_IDLE (SOF_TASK_DEADLINE_IDLE - 1) /**< Almost idle deadline. */ +#define SOF_TASK_DEADLINE_NOW 0 /**< Immediate deadline; run as soon as possible. */ -/** \brief Task counter initial value. */ +/** @brief Task counter initial value. */ #define SOF_TASK_SKIP_COUNT 0xFFFFu -/** \brief Task states. */ +/** + * @brief Lifecycle and execution states of an SOF task. + */ enum task_state { + /** @brief Task allocated and initialized, not yet scheduled. */ SOF_TASK_STATE_INIT = 0, + /** @brief Task queued in scheduler run list awaiting tick or trigger. */ SOF_TASK_STATE_QUEUED, + /** @brief Task waiting for preconditions, audio data, or buffer space. */ SOF_TASK_STATE_PENDING, + /** @brief Task actively executing in thread or timer/DMA handler. */ SOF_TASK_STATE_RUNNING, + /** @brief Task preempted by higher priority thread or ISR. */ SOF_TASK_STATE_PREEMPTED, + /** @brief Task execution finished; removed from active scheduling. */ SOF_TASK_STATE_COMPLETED, + /** @brief Task resources released. */ SOF_TASK_STATE_FREE, + /** @brief Task cancelled, pending removal from scheduler. */ SOF_TASK_STATE_CANCEL, + /** @brief Return code from run callback requesting rescheduling in next period. */ SOF_TASK_STATE_RESCHEDULE, }; -/** \brief Task operations. */ +/** + * @brief Operations and callbacks associated with a scheduling task. + */ struct task_ops { - enum task_state (*run)(void *data); /**< task's main operation */ - void (*complete)(void *data); /**< executed on completion */ - uint64_t (*get_deadline)(void *data); /**< returns current deadline */ + enum task_state (*run)(void *data); /**< Task's main execution callback function. */ + void (*complete)(void *data); /**< Optional callback executed on task completion. */ + uint64_t (*get_deadline)(void *data); /**< Optional callback returning current task deadline timestamp. */ }; -/** \brief Task used by schedulers. */ +/** + * @brief Core task structure managed by SOF schedulers. + */ struct task { - uint64_t start; /**< start time in [ms] since now (LL only) */ - const struct sof_uuid_entry *uid; /**< Uuid */ - uint16_t type; /**< type of the task (LL or EDF) */ - int16_t priority; /**< priority of the task (used by LL); lower runs first */ - uint16_t core; /**< execution core */ - uint16_t flags; /**< custom flags */ - struct schedule_data *sch; /**< scheduler bound to task */ - enum task_state state; /**< current state */ - void *data; /**< custom data passed to all ops */ - struct list_item list; /**< used by schedulers to hold tasks */ - void *priv_data; /**< task private data */ - struct task_ops ops; /**< task operations */ - struct k_work_delayable z_delayed_work; - uint32_t cycles_sum; - uint32_t cycles_max; - uint32_t cycles_cnt; + uint64_t start; /**< Scheduler/domain-specific start state (e.g. absolute next-run tick timestamp in LL). */ + const struct sof_uuid_entry *uid; /**< UUID identifying the task or associated component. */ + uint16_t type; /**< Scheduler type identifier (SOF_SCHEDULE_*). */ + int16_t priority; /**< Priority of the task (lower values run first). */ + uint16_t core; /**< Execution core ID affinity. */ + uint16_t flags; /**< Custom task flags. */ + struct schedule_data *sch; /**< Pointer to scheduler instance bound to this task. */ + enum task_state state; /**< Current task lifecycle state. */ + void *data; /**< Custom context pointer passed to task operations. */ + struct list_item list; /**< List node linking task into scheduler run queue. */ + void *priv_data; /**< Scheduler-specific private task context. */ + struct task_ops ops; /**< Task operations callbacks table. */ + struct k_work_delayable z_delayed_work; /**< Zephyr delayable work item (used by legacy EDF). */ + uint32_t cycles_sum; /**< Cumulative execution cycles. */ + uint32_t cycles_max; /**< Maximum cycle count recorded in a single run. */ + uint32_t cycles_cnt; /**< Number of completed execution runs. */ #if CONFIG_PERFORMANCE_COUNTERS - struct perf_cnt_data pcd; + struct perf_cnt_data pcd; /**< Performance counter telemetry data. */ #endif }; +/** + * @brief Check whether a task is active (queued, running, pending, or rescheduling). + * @param[in] task Task to check. + * @return true if task is in an active execution state, false otherwise. + */ static inline bool task_is_active(struct task *task) { switch (task->state) { @@ -89,6 +119,11 @@ static inline bool task_is_active(struct task *task) } } +/** + * @brief Execute a task's run callback. + * @param[in,out] task Task to execute. + * @return Resulting task state returned by the run callback. + */ static inline enum task_state task_run(struct task *task) { assert(task->ops.run); @@ -96,12 +131,21 @@ static inline enum task_state task_run(struct task *task) return task->ops.run(task->data); } +/** + * @brief Execute a task's complete callback, if registered. + * @param[in,out] task Task whose completion callback should be invoked. + */ static inline void task_complete(struct task *task) { if (task->ops.complete) task->ops.complete(task->data); } +/** + * @brief Retrieve a task's deadline timestamp. + * @param[in] task Task to query. + * @return Current deadline timestamp. + */ static inline uint64_t task_get_deadline(struct task *task) { assert(task->ops.get_deadline); @@ -109,7 +153,19 @@ static inline uint64_t task_get_deadline(struct task *task) return task->ops.get_deadline(task->data); } +/** + * @brief Start the main SOF background task. + * @param[in,out] sof Global SOF context pointer. + * @return 0 on success, negative error code on failure. + */ int task_main_start(struct sof *sof); + +/** + * @brief Signal completion of system startup. + * @return 0 on success, negative error code on failure. + */ int start_complete(void); +/** @}*/ + #endif /* __ZEPHYR_RTOS_TASK_H__ */ diff --git a/zephyr/include/sof/lib/memory.h b/zephyr/include/sof/lib/memory.h index 2b5a225b7067..09bbaa0de627 100644 --- a/zephyr/include/sof/lib/memory.h +++ b/zephyr/include/sof/lib/memory.h @@ -3,16 +3,35 @@ * Copyright(c) 2024 Intel Corporation. */ +/** + * @file sof/lib/memory.h + * @brief Memory attributes, cold/hot execution paths, and platform memory inclusions. + * @ingroup memory_api + */ + #ifndef __SOF_LIB_MEMORY_H__ #define __SOF_LIB_MEMORY_H__ #include #include +/** \addtogroup memory_api + * @{ + */ + +/** + * @brief Attribute marking non-latency-critical code for placement in cold memory sections. + * + * Cold code (e.g. initialization, IPC setup, or offload modules) may be placed in + * DRAM / L3 memory or powered-down banks to conserve high-speed internal SRAM. + */ #ifndef __cold #define __cold #endif +/** + * @brief Attribute marking read-only constants for placement in cold memory sections. + */ #ifndef __cold_rodata #define __cold_rodata #endif @@ -26,11 +45,31 @@ bool ll_sch_is_current(void); #if CONFIG_COLD_STORE_EXECUTE_DEBUG #include +/** + * @brief Start monitoring hot execution paths for cold storage violations. + */ void dbg_path_hot_start_watching(void); + +/** + * @brief Stop monitoring hot execution paths. + */ void dbg_path_hot_stop_watching(void); + +/** + * @brief Confirm that execution remained on expected hot paths. + */ void dbg_path_hot_confirm(void); + +/** + * @brief Record entry into a cold execution function. + * @param[in] fn Calling function name. + */ void dbg_path_cold_enter(const char *fn); +/** + * @brief Internal assertion validating that a function can safely execute on cold storage. + * @param[in] fn Calling function name. + */ static inline void __assert_can_be_cold(const char *fn) { if (k_is_user_context()) @@ -39,13 +78,22 @@ static inline void __assert_can_be_cold(const char *fn) __ASSERT(!ll_sch_is_current(), "%s() called from an LL thread!", fn); dbg_path_cold_enter(fn); } + +/** + * @brief Assert that the current function is not executing from a latency-critical LL thread. + */ #define assert_can_be_cold() __assert_can_be_cold(__func__) #else #define dbg_path_hot_start_watching() do {} while (0) #define dbg_path_hot_stop_watching() do {} while (0) #define dbg_path_hot_confirm() do {} while (0) #define dbg_path_cold_enter() do {} while (0) +/** + * @brief Assert that the current function is not executing from a latency-critical LL thread. + */ #define assert_can_be_cold() do {} while (0) #endif +/** @}*/ + #endif /* __SOF_LIB_MEMORY_H__ */ diff --git a/zephyr/include/sof/lib/mm_heap.h b/zephyr/include/sof/lib/mm_heap.h index 634b336d9e40..d2423acdeb1e 100644 --- a/zephyr/include/sof/lib/mm_heap.h +++ b/zephyr/include/sof/lib/mm_heap.h @@ -3,6 +3,15 @@ * Copyright(c) 2024 Intel Corporation. */ +/** + * @file sof/lib/mm_heap.h + * @brief Legacy XTOS heap compatibility header. + * @ingroup memory_api + * @deprecated Legacy XTOS heap management header. On Zephyr platforms, heap operations + * are managed by RTOS allocators in `` and Zephyr k_heap; + * this header is retained solely as an empty compatibility shim. + */ + #ifndef __SOF_LIB_MM_HEAP_H__ #define __SOF_LIB_MM_HEAP_H__ diff --git a/zephyr/include/sof/lib/regions_mm.h b/zephyr/include/sof/lib/regions_mm.h index 0e3b51c8bdce..259091ab4df3 100644 --- a/zephyr/include/sof/lib/regions_mm.h +++ b/zephyr/include/sof/lib/regions_mm.h @@ -5,6 +5,12 @@ * Author: Jakub Dabek */ +/** + * @file sof/lib/regions_mm.h + * @brief Virtual Memory Heap (VMH) and multi-block region allocator API. + * @ingroup memory_api + */ + #ifndef ZEPHYR_LIB_REGIONS_MM_H_ #define ZEPHYR_LIB_REGIONS_MM_H_ @@ -17,41 +23,43 @@ #include #include -/* Attributes for memory regions */ -#define VIRTUAL_REGION_SHARED_HEAP_ATTR 1U /*< region for shared virtual heap */ -#define VIRTUAL_REGION_LLEXT_LIBRARIES_ATTR 2U /*< region for LLEXT libraries */ -#define VIRTUAL_REGION_VPAGES_ATTR 3U /*< region for virtual page allocator */ - -/* Dependency on ipc/topology.h created due to memory capability definitions - * that are defined there +/** \addtogroup memory_api + * @{ + * + * @note **Re-entrancy Contract**: This API is **NOT re-entrant**. While runtime + * allocation and deallocation operations (vmh_alloc(), vmh_free()) synchronize + * internally via the heap mutex, heap lifecycle management operations (such as + * vmh_free_heap()) do not use mutual exclusion. It is assumed that only system + * management code performs heap lifecycle operations, and concurrent heap + * management with runtime allocations must be avoided. */ -/* API is NOT re-entry safe. - * This is due to our assumption that only management code will ever handle - * memory operations on heaps themselves. - */ +/** @brief Region attribute for shared virtual memory heap. */ +#define VIRTUAL_REGION_SHARED_HEAP_ATTR 1U +/** @brief Region attribute for loadable LLEXT libraries. */ +#define VIRTUAL_REGION_LLEXT_LIBRARIES_ATTR 2U +/** @brief Region attribute for virtual page allocator. */ +#define VIRTUAL_REGION_VPAGES_ATTR 3U -/* Defines maximum amount of memory block allocators in one heap - * since minimum realistic block should be cache line size - * and block sizes in allocator must be powers of 2 - * so logically it gives limited block sizes - * eg allocator of block size 64 128 256 512 2048 4096 1024 8192 - * would end up in 8 allocators. - * It is expected that allocations bigger than that would - * either be spanned on specifically configured heap or have - * individual configs with bigger block sizes. +/** + * @brief Maximum amount of memory block allocators in one heap. + * + * Since minimum realistic block is cache line size and block sizes + * must be powers of 2 (e.g. 64, 128, 256, 512, 1024, 2048, 4096, 8192). */ #define MAX_MEMORY_ALLOCATORS_COUNT 10 -/* vmh_get_default_heap_config() function will try to split the region - * down the given count. Only applicable when API client did not - * use its config. +/** + * @brief Default number of power-of-2 block allocators partitioned across a region. */ #define DEFAULT_CONFIG_ALOCATORS_COUNT 5 +/** + * @brief Descriptor for a power-of-2 block size bundle in a virtual memory heap. + */ struct vmh_block_bundle_descriptor { - size_t block_size; /**< size of memory block. */ - size_t number_of_blocks; /**< number of memory blocks. */ + size_t block_size; /**< Size of memory block in bytes. */ + size_t number_of_blocks; /**< Number of memory blocks in this bundle. */ }; /* @@ -72,22 +80,65 @@ struct vmh_heap_config { struct vmh_block_bundle_descriptor block_bundles_table[MAX_MEMORY_ALLOCATORS_COUNT]; }; +/** + * @brief Initialize a virtual memory heap with the given bundle configuration. + * @param[in] cfg Pointer to heap bundle configuration. + * @param[in] allocating_continuously If true, allows allocations to span a contiguous run + * of VMH block slots within a bundle; does not guarantee + * contiguous physical backing pages. + * @return Pointer to initialized vmh_heap, or NULL on failure. + */ struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, bool allocating_continuously); + +/** + * @brief Allocate a memory block from the virtual memory heap. + * @param[in,out] heap Pointer to target vmh_heap instance. + * @param[in] alloc_size Allocation size in bytes. + * @return Pointer to allocated buffer, or NULL on failure. + */ void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size); + +/** + * @brief Destroy a virtual memory heap and unmap all backing pages. + * @param[in,out] heap Pointer to vmh_heap instance to destroy. + * @return 0 on success, negative error code on failure. + */ int vmh_free_heap(struct vmh_heap *heap); + +/** + * @brief Free a memory block previously allocated from a virtual memory heap. + * @param[in,out] heap Pointer to vmh_heap instance. + * @param[in,out] ptr Pointer to memory block to free. + * @return 0 on success, negative error code on failure. + */ int vmh_free(struct vmh_heap *heap, void *ptr); + +/** + * @brief Generate a default heap partition configuration for a memory driver region. + * @param[in] region Driver region describing base and size. + * @param[out] cfg Destination configuration structure to populate. + */ void vmh_get_default_heap_config(const struct sys_mm_drv_region *region, struct vmh_heap_config *cfg); #ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS +/** + * @brief Log aggregate runtime statistics for the virtual memory heap. + * @param[in] heap Pointer to vmh_heap instance. + */ void vmh_log_stats(struct vmh_heap *heap); + +/** + * @brief Log per-bundle block allocation statistics for the virtual memory heap. + * @param[in] heap Pointer to vmh_heap instance. + */ void vmh_log_alloc_stats(struct vmh_heap *heap); #endif /** - * @brief Checks if ptr is in range of given memory range + * @brief Checks if ptr is in range of given memory range. * - * @param ptr checked ptr - * @param range_start start of checked memory range - * @param range_size size of checked memory range. + * @param[in] ptr Checked pointer address. + * @param[in] range_start Start of checked memory range. + * @param[in] range_size Size of checked memory range in bytes. * * @retval false if no overlap detected. * @retval true if any overlap detected. @@ -98,4 +149,6 @@ static inline bool vmh_is_ptr_in_memory_range(uintptr_t ptr, uintptr_t range_sta return ptr >= range_start && ptr < range_start + range_size; } +/** @}*/ + #endif /* ZEPHYR_LIB_REGIONS_MM_H_ */ diff --git a/zephyr/include/sof/lib/vpage.h b/zephyr/include/sof/lib/vpage.h index f3fc8b89e968..ef66ce0ae533 100644 --- a/zephyr/include/sof/lib/vpage.h +++ b/zephyr/include/sof/lib/vpage.h @@ -1,7 +1,12 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright(c) 2025 Intel Corporation. -/* Virtual Page Allocator API */ +/** + * @file sof/lib/vpage.h + * @brief Virtual Page Allocator API for mapping contiguous memory pages. + * @ingroup memory_api + */ + #ifndef __SOF_LIB_VPAGE_H__ #define __SOF_LIB_VPAGE_H__ @@ -12,25 +17,32 @@ extern "C" { #endif +/** \addtogroup memory_api + * @{ + */ + /** - * @brief Allocate virtual pages - * Allocates a specified number of contiguous virtual memory pages by mapping - * physical pages. + * @brief Allocate contiguous virtual pages. * - * @param[in] pages Number of pages (usually 4kB large) to allocate. + * Allocates a specified number of contiguous virtual memory pages by mapping + * physical backing pages into the DSP page table. * + * @param[in] pages Number of pages (typically 4KB per page) to allocate. * @return Pointer to the allocated virtual memory region, or NULL on failure. */ void *vpage_alloc(unsigned int pages); /** - * @brief Free virtual pages - * Frees previously allocated virtual memory pages and unmaps them. + * @brief Free virtual pages. * - * @param[in] ptr Pointer to the memory pages to free. + * Frees previously allocated virtual memory pages and unmaps them from the page table. + * + * @param[in,out] ptr Pointer to the virtual memory pages to free. */ void vpage_free(void *ptr); +/** @}*/ + #ifdef __cplusplus } #endif