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