mirror of https://github.com/thesofproject/sof.git
dp_queue: buf calculation size, add list, cosmetic changes
buf calculation size has been changed to be always 2xmax(IBS,OBS) to allow free read/write in various data chunk sizes and execution periods (of course in/out data rates must be same) detailed examples in dp_queue.h file method and fields allowing connection dp_queues to a list added Signed-off-by: Marcin Szkudlinski <marcin.szkudlinski@intel.com>
This commit is contained in:
parent
46a9d87f1f
commit
e6c3decd38
|
@ -73,7 +73,7 @@ static inline void dp_queue_writeback_shared(struct dp_queue *dp_queue,
|
|||
}
|
||||
|
||||
static inline
|
||||
uint8_t __sparse_cache *dp_queue_get_pointer(struct dp_queue *dp_queue, uint32_t offset)
|
||||
uint8_t __sparse_cache *dp_queue_get_pointer(struct dp_queue *dp_queue, size_t offset)
|
||||
{
|
||||
/* check if offset is not in "double area"
|
||||
* lines below do a quicker version of offset %= dp_queue->data_buffer_size;
|
||||
|
@ -84,7 +84,7 @@ uint8_t __sparse_cache *dp_queue_get_pointer(struct dp_queue *dp_queue, uint32_t
|
|||
}
|
||||
|
||||
static inline
|
||||
uint32_t dp_queue_inc_offset(struct dp_queue *dp_queue, uint32_t offset, uint32_t inc)
|
||||
size_t dp_queue_inc_offset(struct dp_queue *dp_queue, size_t offset, size_t inc)
|
||||
{
|
||||
assert(inc <= dp_queue->data_buffer_size);
|
||||
offset += inc;
|
||||
|
@ -161,20 +161,20 @@ static int dp_queue_get_data(struct sof_source *source, size_t req_size,
|
|||
void const **data_ptr, void const **buffer_start, size_t *buffer_size)
|
||||
{
|
||||
struct dp_queue *dp_queue = dp_queue_from_source(source);
|
||||
__sparse_cache void *_data_ptr;
|
||||
__sparse_cache void *data_ptr_c;
|
||||
|
||||
CORE_CHECK_STRUCT(dp_queue);
|
||||
if (req_size > dp_queue_get_data_available(source))
|
||||
return -ENODATA;
|
||||
|
||||
_data_ptr = dp_queue_get_pointer(dp_queue, dp_queue->_read_offset);
|
||||
data_ptr_c = dp_queue_get_pointer(dp_queue, dp_queue->_read_offset);
|
||||
|
||||
/* clean cache in provided data range */
|
||||
dp_queue_invalidate_shared(dp_queue, _data_ptr, req_size);
|
||||
dp_queue_invalidate_shared(dp_queue, data_ptr_c, req_size);
|
||||
|
||||
*buffer_start = (__sparse_force void *)dp_queue->_data_buffer;
|
||||
*buffer_size = dp_queue->data_buffer_size;
|
||||
*data_ptr = (__sparse_force void *)_data_ptr;
|
||||
*data_ptr = (__sparse_force void *)data_ptr_c;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -262,24 +262,22 @@ struct dp_queue *dp_queue_create(size_t min_available, size_t min_free_space, ui
|
|||
|
||||
CORE_CHECK_STRUCT_INIT(dp_queue, flags & DP_QUEUE_MODE_SHARED);
|
||||
|
||||
/* initiate sink/source */
|
||||
/* initiate structures */
|
||||
source_init(dp_queue_get_source(dp_queue), &dp_queue_source_ops,
|
||||
&dp_queue->audio_stream_params);
|
||||
sink_init(dp_queue_get_sink(dp_queue), &dp_queue_sink_ops,
|
||||
&dp_queue->audio_stream_params);
|
||||
|
||||
list_init(&dp_queue->list);
|
||||
|
||||
/* set obs/ibs in sink/source interfaces */
|
||||
sink_set_min_free_space(&dp_queue->_sink_api, min_free_space);
|
||||
source_set_min_available(&dp_queue->_source_api, min_available);
|
||||
|
||||
uint32_t max_ibs_obs = MAX(min_available, min_free_space);
|
||||
uint32_t min_ibs_obs = MIN(min_available, min_free_space);
|
||||
|
||||
/* calculate required buffer size */
|
||||
if (max_ibs_obs % min_ibs_obs == 0)
|
||||
dp_queue->data_buffer_size = 2 * max_ibs_obs;
|
||||
else
|
||||
dp_queue->data_buffer_size = 3 * max_ibs_obs;
|
||||
dp_queue->data_buffer_size = 2 * max_ibs_obs;
|
||||
|
||||
/* allocate data buffer - always in cached memory alias */
|
||||
dp_queue->data_buffer_size = ALIGN_UP(dp_queue->data_buffer_size, PLATFORM_DCACHE_ALIGN);
|
||||
|
|
|
@ -25,9 +25,38 @@
|
|||
* 1) incoming and outgoing data rate MUST be the same
|
||||
* 2) Both data consumer and data producer declare max chunk sizes they want to use (IBS/OBS)
|
||||
*
|
||||
* required Buffer size:
|
||||
* - 2*MAX(IBS,OBS) if the larger of IBS/OBS is multiplication of smaller
|
||||
* - 3*MAX(IBS,OBS) otherwise
|
||||
* required Buffer size is 2*MAX(IBS,OBS) to allow free read/write in various data chunk sizes
|
||||
* and execution periods (of course in/out data rates must be same)
|
||||
* example:
|
||||
* Consumer reads 5bytes each 3 cycles (IBS = 5)
|
||||
* producer writes 3bytes every 5 cycles (OBS = 3)
|
||||
* - cycle0 buffer empty, producer starting processing, consumer must wait
|
||||
* - cycle3 produce 3 bytes (buf occupation = 3)
|
||||
* - cycle6 produce 3 bytes (buf occupation = 6), consumer becomes ready
|
||||
* in DP thread will start now - asyn to LL cycles
|
||||
* in this example assuming it consumes data in next cycle
|
||||
* - cycle7 consume 5 bytes, (buf occupation = 1)
|
||||
* - cycle9 produce 3 bytes (buf occupation = 4)
|
||||
* - cycle12 (producer goes first) produce 3 bytes (buf occupation = 7)
|
||||
* consume 5 bytes (buf occupation = 2)
|
||||
* - cycle15 produce 3 bytes (buf occupation = 5)
|
||||
* consumer has enough data, but is busy processing prev data
|
||||
* - cycle15 consume 5 bytes (buf occupation = 0)
|
||||
*
|
||||
* ===> max buf occupation = 7
|
||||
*
|
||||
* The worst case is when IBS=OBS and equal periods of consumer/producer
|
||||
* the buffer must be 2*MAX(IBS,OBS) as we do not know who goes first - consumer or producer,
|
||||
* especially when both are located on separate cores and EDF scheduling is used
|
||||
*
|
||||
* Consumer reads 5 bytes every cycle (IBS = 5)
|
||||
* producer writes 5 bytes every cycle (OBS = 5)
|
||||
* - cycle0 consumer goes first - must wait (buf occupation = 0)
|
||||
* producer produce 5 bytes (buf occupation = 5)
|
||||
* - cycle1 producer goes first - produce 5 bytes (buf occupation = 10)
|
||||
* consumer consumes 5 bytes (buf occupation = 5)
|
||||
* ===> max buf occupation = 10
|
||||
*
|
||||
*
|
||||
* The queue may work in 2 modes
|
||||
* 1) local mode
|
||||
|
@ -80,6 +109,9 @@ struct sof_audio_stream_params;
|
|||
struct dp_queue {
|
||||
CORE_CHECK_STRUCT_FIELD;
|
||||
|
||||
/* public */
|
||||
struct list_item list; /**< fields for connection queues in a list */
|
||||
|
||||
/* public: read only */
|
||||
struct sof_audio_stream_params audio_stream_params;
|
||||
size_t data_buffer_size;
|
||||
|
@ -91,8 +123,8 @@ struct dp_queue {
|
|||
uint32_t _flags; /* DP_QUEUE_MODE_* */
|
||||
|
||||
uint8_t __sparse_cache *_data_buffer;
|
||||
uint32_t _write_offset; /* private: to be modified by data producer using API */
|
||||
uint32_t _read_offset; /* private: to be modified by data consumer using API */
|
||||
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 */
|
||||
|
||||
bool _hw_params_configured;
|
||||
};
|
||||
|
@ -110,12 +142,13 @@ struct dp_queue {
|
|||
struct dp_queue *dp_queue_create(size_t min_available, size_t min_free_space, uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief free dp queue memory
|
||||
* @brief remove the queue from the list, free dp queue memory
|
||||
*/
|
||||
static inline
|
||||
void dp_queue_free(struct dp_queue *dp_queue)
|
||||
{
|
||||
CORE_CHECK_STRUCT(dp_queue);
|
||||
list_item_del(&dp_queue->list);
|
||||
rfree((__sparse_force void *)dp_queue->_data_buffer);
|
||||
rfree(dp_queue);
|
||||
}
|
||||
|
@ -164,4 +197,28 @@ bool dp_queue_is_shared(struct dp_queue *dp_queue)
|
|||
return !!(dp_queue->_flags & DP_QUEUE_MODE_SHARED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief append a dp_queue to the list
|
||||
*/
|
||||
static inline void dp_queue_append_to_list(struct dp_queue *item, struct list_item *list)
|
||||
{
|
||||
list_item_append(&item->list, list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief return a pointer to the first dp_queue on the list
|
||||
*/
|
||||
static inline struct dp_queue *dp_queue_get_first_item(struct list_item *list)
|
||||
{
|
||||
return list_first_item(list, struct dp_queue, list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief return a pointer to the next dp_queue on the list
|
||||
*/
|
||||
static inline struct dp_queue *dp_queue_get_next_item(struct dp_queue *item)
|
||||
{
|
||||
return list_next_item(item, list);
|
||||
}
|
||||
|
||||
#endif /* __SOF_DP_QUEUE_H__ */
|
||||
|
|
Loading…
Reference in New Issue