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 <sof/debug/panic.h>
16 #include <sof/lib/alloc.h>
17 #include <sof/lib/cache.h>
18 #include <sof/lib/uuid.h>
19 #include <sof/list.h>
20 #include <sof/math/numbers.h>
21 #include <sof/spinlock.h>
22 #include <sof/string.h>
23 #include <sof/trace/trace.h>
24 #include <ipc/stream.h>
25 #include <ipc/topology.h>
26 #include <user/trace.h>
27 #include <sof/audio/format.h>
28
29 #include <stdbool.h>
30 #include <stddef.h>
31 #include <stdint.h>
32
33 struct comp_dev;
34
35 /** \name Trace macros
36 * @{
37 */
38
39 /* buffer tracing */
40 extern struct tr_ctx buffer_tr;
41
42 /** \brief Retrieves trace context from the buffer */
43 #define trace_buf_get_tr_ctx(buf_ptr) (&(buf_ptr)->tctx)
44
45 /** \brief Retrieves id (pipe id) from the buffer */
46 #define trace_buf_get_id(buf_ptr) ((buf_ptr)->pipeline_id)
47
48 /** \brief Retrieves subid (comp id) from the buffer */
49 #define trace_buf_get_subid(buf_ptr) ((buf_ptr)->id)
50
51 /** \brief Trace error message from buffer */
52 #define buf_err(buf_ptr, __e, ...) \
53 trace_dev_err(trace_buf_get_tr_ctx, trace_buf_get_id, \
54 trace_buf_get_subid, buf_ptr, __e, ##__VA_ARGS__)
55
56 /** \brief Trace warning message from buffer */
57 #define buf_warn(buf_ptr, __e, ...) \
58 trace_dev_warn(trace_buf_get_tr_ctx, trace_buf_get_id, \
59 trace_buf_get_subid, buf_ptr, __e, ##__VA_ARGS__)
60
61 /** \brief Trace info message from buffer */
62 #define buf_info(buf_ptr, __e, ...) \
63 trace_dev_info(trace_buf_get_tr_ctx, trace_buf_get_id, \
64 trace_buf_get_subid, buf_ptr, __e, ##__VA_ARGS__)
65
66 /** \brief Trace debug message from buffer */
67 #define buf_dbg(buf_ptr, __e, ...) \
68 trace_dev_dbg(trace_buf_get_tr_ctx, trace_buf_get_id, \
69 trace_buf_get_subid, buf_ptr, __e, ##__VA_ARGS__)
70
71 /** @}*/
72
73 /* buffer callback types */
74 #define BUFF_CB_TYPE_PRODUCE BIT(0)
75 #define BUFF_CB_TYPE_CONSUME BIT(1)
76
77 #define BUFFER_UPDATE_IF_UNSET 0
78 #define BUFFER_UPDATE_FORCE 1
79
80 /* buffer parameters */
81 #define BUFF_PARAMS_FRAME_FMT BIT(0)
82 #define BUFF_PARAMS_BUFFER_FMT BIT(1)
83 #define BUFF_PARAMS_RATE BIT(2)
84 #define BUFF_PARAMS_CHANNELS BIT(3)
85
86 /* audio component buffer - connects 2 audio components together in pipeline */
87 struct comp_buffer {
88 spinlock_t *lock; /* locking mechanism */
89
90 /* data buffer */
91 struct audio_stream stream;
92
93 /* configuration */
94 uint32_t id;
95 uint32_t pipeline_id;
96 uint32_t caps;
97 uint32_t core;
98 bool inter_core; /* true if connected to a comp from another core */
99 struct tr_ctx tctx; /* trace settings */
100
101 /* connected components */
102 struct comp_dev *source; /* source component */
103 struct comp_dev *sink; /* sink component */
104
105 /* lists */
106 struct list_item source_list; /* list in comp buffers */
107 struct list_item sink_list; /* list in comp buffers */
108
109 /* runtime stream params */
110 uint32_t buffer_fmt; /**< enum sof_ipc_buffer_format */
111 uint16_t chmap[SOF_IPC_MAX_CHANNELS]; /**< channel map - SOF_CHMAP_ */
112
113 bool hw_params_configured; /**< indicates whether hw params were set */
114 bool walking; /**< indicates if the buffer is being walking */
115 };
116
117 struct buffer_cb_transact {
118 struct comp_buffer *buffer;
119 uint32_t transaction_amount;
120 void *transaction_begin_address;
121 };
122
123 struct buffer_cb_free {
124 struct comp_buffer *buffer;
125 };
126
127 #define buffer_comp_list(buffer, dir) \
128 ((dir) == PPL_DIR_DOWNSTREAM ? &buffer->source_list : \
129 &buffer->sink_list)
130
131 #define buffer_from_list(ptr, type, dir) \
132 ((dir) == PPL_DIR_DOWNSTREAM ? \
133 container_of(ptr, type, source_list) : \
134 container_of(ptr, type, sink_list))
135
136 #define buffer_get_comp(buffer, dir) \
137 ((dir) == PPL_DIR_DOWNSTREAM ? buffer->sink : \
138 buffer->source)
139
140 #define buffer_set_comp(buffer, comp, dir) \
141 do { \
142 if (dir == PPL_CONN_DIR_COMP_TO_BUFFER) \
143 buffer->source = comp; \
144 else \
145 buffer->sink = comp; \
146 } while (0) \
147
148 #define buffer_set_cb(buffer, func, data, type) \
149 do { \
150 buffer->cb = func; \
151 buffer->cb_data = data; \
152 buffer->cb_type = type; \
153 } while (0)
154
155 /* pipeline buffer creation and destruction */
156 struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t align);
157 struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc);
158 int buffer_set_size(struct comp_buffer *buffer, uint32_t size);
159 void buffer_free(struct comp_buffer *buffer);
160 void buffer_zero(struct comp_buffer *buffer);
161
162 /* called by a component after producing data into this buffer */
163 void comp_update_buffer_produce(struct comp_buffer *buffer, uint32_t bytes);
164
165 /* called by a component after consuming data from this buffer */
166 void comp_update_buffer_consume(struct comp_buffer *buffer, uint32_t bytes);
167
168 int buffer_set_params(struct comp_buffer *buffer, struct sof_ipc_stream_params *params,
169 bool force_update);
170
171 bool buffer_params_match(struct comp_buffer *buffer, struct sof_ipc_stream_params *params,
172 uint32_t flag);
173
buffer_invalidate(struct comp_buffer * buffer,uint32_t bytes)174 static inline void buffer_invalidate(struct comp_buffer *buffer, uint32_t bytes)
175 {
176 if (!buffer->inter_core)
177 return;
178
179 audio_stream_invalidate(&buffer->stream, bytes);
180 }
181
buffer_writeback(struct comp_buffer * buffer,uint32_t bytes)182 static inline void buffer_writeback(struct comp_buffer *buffer, uint32_t bytes)
183 {
184 if (!buffer->inter_core)
185 return;
186
187 audio_stream_writeback(&buffer->stream, bytes);
188 }
189
190 /**
191 * Locks buffer instance for buffers connecting components
192 * running on different cores. Buffer parameters will be invalidated
193 * to make sure the latest data can be retrieved.
194 * @param buffer Buffer instance.
195 * @param flags IRQ flags.
196 */
buffer_lock(struct comp_buffer * buffer,uint32_t * flags)197 static inline void buffer_lock(struct comp_buffer *buffer, uint32_t *flags)
198 {
199 if (!buffer->inter_core) {
200 /* Ignored by buffer_unlock() below, silences "may be
201 * used uninitialized" warning.
202 */
203 *flags = 0xffffffff;
204 return;
205 }
206
207 /* Expands to: *flags = ... */
208 spin_lock_irq(buffer->lock, *flags);
209
210 /* invalidate in case something has changed during our wait */
211 dcache_invalidate_region(buffer, sizeof(*buffer));
212 }
213
214 /**
215 * Unlocks buffer instance for buffers connecting components
216 * running on different cores. Buffer parameters will be flushed
217 * to make sure all the changes are saved. Also they will be invalidated
218 * to spare the need of locking/unlocking buffer, when only reading parameters.
219 * @param buffer Buffer instance.
220 * @param flags IRQ flags.
221 */
buffer_unlock(struct comp_buffer * buffer,uint32_t flags)222 static inline void buffer_unlock(struct comp_buffer *buffer, uint32_t flags)
223 {
224 if (!buffer->inter_core)
225 return;
226
227 /* save lock pointer to avoid memory access after cache flushing */
228 spinlock_t *lock = buffer->lock;
229
230 /* wtb and inv to avoid buffer locking in read only situations */
231 dcache_writeback_invalidate_region(buffer, sizeof(*buffer));
232
233 spin_unlock_irq(lock, flags);
234 }
235
buffer_reset_pos(struct comp_buffer * buffer,void * data)236 static inline void buffer_reset_pos(struct comp_buffer *buffer, void *data)
237 {
238 uint32_t flags = 0;
239
240 buffer_lock(buffer, &flags);
241
242 /* reset rw pointers and avail/free bytes counters */
243 audio_stream_reset(&buffer->stream);
244
245 /* clear buffer contents */
246 buffer_zero(buffer);
247
248 buffer_unlock(buffer, flags);
249 }
250
buffer_init(struct comp_buffer * buffer,uint32_t size,uint32_t caps)251 static inline void buffer_init(struct comp_buffer *buffer, uint32_t size,
252 uint32_t caps)
253 {
254 buffer->caps = caps;
255
256 /* addr should be set in alloc function */
257 audio_stream_init(&buffer->stream, buffer->stream.addr, size);
258 }
259
buffer_reset_params(struct comp_buffer * buffer,void * data)260 static inline void buffer_reset_params(struct comp_buffer *buffer, void *data)
261 {
262 uint32_t flags = 0;
263
264 buffer_lock(buffer, &flags);
265
266 buffer->hw_params_configured = false;
267
268 buffer_unlock(buffer, flags);
269 }
270
271 #endif /* __SOF_AUDIO_BUFFER_H__ */
272