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