1 /* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright(c) 2017 Intel Corporation. All rights reserved.
4 *
5 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6 */
7
8 #ifndef __SOF_AUDIO_BUFFER_H__
9 #define __SOF_AUDIO_BUFFER_H__
10
11 #include <sof/audio/audio_stream.h>
12 #include <sof/audio/pipeline.h>
13 #include <sof/math/numbers.h>
14 #include <sof/common.h>
15 #include <rtos/panic.h>
16 #include <rtos/alloc.h>
17 #include <rtos/cache.h>
18 #include <sof/lib/uuid.h>
19 #include <sof/list.h>
20 #include <sof/coherent.h>
21 #include <sof/math/numbers.h>
22 #include <rtos/spinlock.h>
23 #include <rtos/string.h>
24 #include <sof/trace/trace.h>
25 #include <ipc/stream.h>
26 #include <ipc/topology.h>
27 #include <user/trace.h>
28 #include <sof/audio/format.h>
29
30 #include <stdbool.h>
31 #include <stddef.h>
32 #include <stdint.h>
33
34 struct comp_dev;
35
36 /** \name Trace macros
37 * @{
38 */
39
40 /* buffer tracing */
41 extern struct tr_ctx buffer_tr;
42
43 /** \brief Retrieves trace context from the buffer */
44 #define trace_buf_get_tr_ctx(buf_ptr) (&(buf_ptr)->tctx)
45
46 /** \brief Retrieves id (pipe id) from the buffer */
47 #define trace_buf_get_id(buf_ptr) ((buf_ptr)->pipeline_id)
48
49 /** \brief Retrieves subid (comp id) from the buffer */
50 #define trace_buf_get_subid(buf_ptr) ((buf_ptr)->id)
51
52 #if defined(__ZEPHYR__) && defined(CONFIG_ZEPHYR_LOG)
53
54 #if CONFIG_IPC_MAJOR_4
55 #define __BUF_FMT "buf:%u %#x "
56 #else
57 #define __BUF_FMT "buf:%u.%u "
58 #endif
59
60 #define buf_err(buf_ptr, __e, ...) LOG_ERR(__BUF_FMT __e, trace_buf_get_id(buf_ptr), \
61 trace_buf_get_subid(buf_ptr), ##__VA_ARGS__)
62
63 #define buf_warn(buf_ptr, __e, ...) LOG_WRN(__BUF_FMT __e, trace_buf_get_id(buf_ptr), \
64 trace_buf_get_subid(buf_ptr), ##__VA_ARGS__)
65
66 #define buf_info(buf_ptr, __e, ...) LOG_INF(__BUF_FMT __e, trace_buf_get_id(buf_ptr), \
67 trace_buf_get_subid(buf_ptr), ##__VA_ARGS__)
68
69 #define buf_dbg(buf_ptr, __e, ...) LOG_DBG(__BUF_FMT __e, trace_buf_get_id(buf_ptr), \
70 trace_buf_get_subid(buf_ptr), ##__VA_ARGS__)
71
72 #else
73 /** \brief Trace error message from buffer */
74 #define buf_err(buf_ptr, __e, ...) \
75 trace_dev_err(trace_buf_get_tr_ctx, trace_buf_get_id, \
76 trace_buf_get_subid, \
77 (__sparse_force const struct comp_buffer *)buf_ptr, \
78 __e, ##__VA_ARGS__)
79
80 /** \brief Trace warning message from buffer */
81 #define buf_warn(buf_ptr, __e, ...) \
82 trace_dev_warn(trace_buf_get_tr_ctx, trace_buf_get_id, \
83 trace_buf_get_subid, \
84 (__sparse_force const struct comp_buffer *)buf_ptr, \
85 __e, ##__VA_ARGS__)
86
87 /** \brief Trace info message from buffer */
88 #define buf_info(buf_ptr, __e, ...) \
89 trace_dev_info(trace_buf_get_tr_ctx, trace_buf_get_id, \
90 trace_buf_get_subid, \
91 (__sparse_force const struct comp_buffer *)buf_ptr, \
92 __e, ##__VA_ARGS__)
93
94 /** \brief Trace debug message from buffer */
95 #if defined(CONFIG_LIBRARY)
96 #define buf_dbg(buf_ptr, __e, ...)
97 #else
98 #define buf_dbg(buf_ptr, __e, ...) \
99 trace_dev_dbg(trace_buf_get_tr_ctx, trace_buf_get_id, \
100 trace_buf_get_subid, \
101 (__sparse_force const struct comp_buffer *)buf_ptr, \
102 __e, ##__VA_ARGS__)
103 #endif
104
105 #endif /* #if defined(__ZEPHYR__) && defined(CONFIG_ZEPHYR_LOG) */
106
107 /** @}*/
108
109 /* buffer callback types */
110 #define BUFF_CB_TYPE_PRODUCE BIT(0)
111 #define BUFF_CB_TYPE_CONSUME BIT(1)
112
113 #define BUFFER_UPDATE_IF_UNSET 0
114 #define BUFFER_UPDATE_FORCE 1
115
116 /* buffer parameters */
117 #define BUFF_PARAMS_FRAME_FMT BIT(0)
118 #define BUFF_PARAMS_BUFFER_FMT BIT(1)
119 #define BUFF_PARAMS_RATE BIT(2)
120 #define BUFF_PARAMS_CHANNELS BIT(3)
121
122 /*
123 * audio component buffer - connects 2 audio components together in pipeline.
124 *
125 * The buffer is a hot structure that must be shared on certain cache
126 * incoherent architectures.
127 *
128 * Access flow (on cache incoherent architectures only)
129 * 1) buffer acquired by using uncache cache coherent pointer.
130 * 2) buffer is invalidated after lock acquired.
131 * 3) buffer is safe to use cached pointer for access.
132 * 4) release buffer cached pointer
133 * 5) write back cached data and release lock using uncache pointer.
134 */
135 struct comp_buffer {
136 struct coherent c;
137
138 /* data buffer */
139 struct audio_stream stream;
140
141 /* configuration */
142 uint32_t id;
143 uint32_t pipeline_id;
144 uint32_t caps;
145 uint32_t core;
146 struct tr_ctx tctx; /* trace settings */
147
148 /* connected components */
149 struct comp_dev *source; /* source component */
150 struct comp_dev *sink; /* sink component */
151
152 /* lists */
153 struct list_item source_list; /* list in comp buffers */
154 struct list_item sink_list; /* list in comp buffers */
155
156 /* runtime stream params */
157 uint32_t buffer_fmt; /**< enum sof_ipc_buffer_format */
158 uint16_t chmap[SOF_IPC_MAX_CHANNELS]; /**< channel map - SOF_CHMAP_ */
159
160 bool hw_params_configured; /**< indicates whether hw params were set */
161 bool walking; /**< indicates if the buffer is being walked */
162 };
163
164 /* Only to be used for synchronous same-core notifications! */
165 struct buffer_cb_transact {
166 struct comp_buffer __sparse_cache *buffer;
167 uint32_t transaction_amount;
168 void *transaction_begin_address;
169 };
170
171 struct buffer_cb_free {
172 struct comp_buffer *buffer;
173 };
174
175 #define buffer_comp_list(buffer, dir) \
176 ((dir) == PPL_DIR_DOWNSTREAM ? &buffer->source_list : \
177 &buffer->sink_list)
178
179 #define buffer_from_list(ptr, dir) \
180 ((dir) == PPL_DIR_DOWNSTREAM ? \
181 container_of(ptr, struct comp_buffer, source_list) : \
182 container_of(ptr, struct comp_buffer, sink_list))
183
184 #define buffer_set_cb(buffer, func, data, type) \
185 do { \
186 buffer->cb = func; \
187 buffer->cb_data = data; \
188 buffer->cb_type = type; \
189 } while (0)
190
191 /* pipeline buffer creation and destruction */
192 struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t align);
193 struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc);
194 int buffer_set_size(struct comp_buffer __sparse_cache *buffer, uint32_t size);
195 void buffer_free(struct comp_buffer *buffer);
196 void buffer_zero(struct comp_buffer __sparse_cache *buffer);
197
198 /* called by a component after producing data into this buffer */
199 void comp_update_buffer_produce(struct comp_buffer __sparse_cache *buffer, uint32_t bytes);
200
201 /* called by a component after consuming data from this buffer */
202 void comp_update_buffer_consume(struct comp_buffer __sparse_cache *buffer, uint32_t bytes);
203
204 int buffer_set_params(struct comp_buffer __sparse_cache *buffer,
205 struct sof_ipc_stream_params *params, bool force_update);
206
207 bool buffer_params_match(struct comp_buffer __sparse_cache *buffer,
208 struct sof_ipc_stream_params *params, uint32_t flag);
209
buffer_stream_invalidate(struct comp_buffer __sparse_cache * buffer,uint32_t bytes)210 static inline void buffer_stream_invalidate(struct comp_buffer __sparse_cache *buffer,
211 uint32_t bytes)
212 {
213 if (!is_coherent_shared(buffer, c))
214 return;
215
216 audio_stream_invalidate(&buffer->stream, bytes);
217 }
218
buffer_stream_writeback(struct comp_buffer __sparse_cache * buffer,uint32_t bytes)219 static inline void buffer_stream_writeback(struct comp_buffer __sparse_cache *buffer,
220 uint32_t bytes)
221 {
222 if (!is_coherent_shared(buffer, c))
223 return;
224
225 audio_stream_writeback(&buffer->stream, bytes);
226 }
227
buffer_acquire(struct comp_buffer * buffer)228 __must_check static inline struct comp_buffer __sparse_cache *buffer_acquire(
229 struct comp_buffer *buffer)
230 {
231 struct coherent __sparse_cache *c = coherent_acquire_thread(&buffer->c, sizeof(*buffer));
232
233 return attr_container_of(c, struct comp_buffer __sparse_cache, c, __sparse_cache);
234 }
235
buffer_release(struct comp_buffer __sparse_cache * buffer)236 static inline void buffer_release(struct comp_buffer __sparse_cache *buffer)
237 {
238 coherent_release_thread(&buffer->c, sizeof(*buffer));
239 }
240
241 /*
242 * Attach a new buffer at the beginning of the list. Note, that "head" must
243 * really be the head of the list, not a list head within another buffer. We
244 * don't synchronise its cache, so it must not be embedded in an object, using
245 * the coherent API. The caller takes care to protect list heads.
246 */
247 void buffer_attach(struct comp_buffer *buffer, struct list_item *head, int dir);
248
249 /*
250 * Detach a buffer from anywhere in the list. "head" is again the head of the
251 * list, we need it to verify, whether this buffer was the first or the last on
252 * the list. Again it is assumed that the head's cache doesn't need to be
253 * synchronized. The caller takes care to protect list heads.
254 */
255 void buffer_detach(struct comp_buffer *buffer, struct list_item *head, int dir);
256
buffer_get_comp(struct comp_buffer * buffer,int dir)257 static inline struct comp_dev *buffer_get_comp(struct comp_buffer *buffer, int dir)
258 {
259 struct comp_buffer __sparse_cache *buffer_c = buffer_acquire(buffer);
260 struct comp_dev *comp = dir == PPL_DIR_DOWNSTREAM ? buffer_c->sink :
261 buffer_c->source;
262 buffer_release(buffer_c);
263 return comp;
264 }
265
buffer_reset_pos(struct comp_buffer __sparse_cache * buffer,void * data)266 static inline void buffer_reset_pos(struct comp_buffer __sparse_cache *buffer, void *data)
267 {
268 /* reset rw pointers and avail/free bytes counters */
269 audio_stream_reset(&buffer->stream);
270
271 /* clear buffer contents */
272 buffer_zero(buffer);
273 }
274
275 /* Run-time buffer re-configuration calls this too, so it must use cached access */
buffer_init(struct comp_buffer __sparse_cache * buffer,uint32_t size,uint32_t caps)276 static inline void buffer_init(struct comp_buffer __sparse_cache *buffer,
277 uint32_t size, uint32_t caps)
278 {
279 buffer->caps = caps;
280
281 /* addr should be set in alloc function */
282 audio_stream_init(&buffer->stream, buffer->stream.addr, size);
283 }
284
buffer_reset_params(struct comp_buffer __sparse_cache * buffer,void * data)285 static inline void buffer_reset_params(struct comp_buffer __sparse_cache *buffer, void *data)
286 {
287 buffer->hw_params_configured = false;
288 }
289
290 #endif /* __SOF_AUDIO_BUFFER_H__ */
291