Skip to content

Commit 3ffeb87

Browse files
fuyuntsuolgirdwood
authored andcommitted
Host component DMA copy the whole copy_bytes.
Host component stops copying bytes at element's end and resumes copying the remaining bytes in the next round. This leads to jitter between components of the same pipeline. Such jitter might cause buffer overwrite for component which processes block by block. Triggering extra DMA copy until all the copy_bytes are copied can eliminate the jitter and hence no more buffer overwrite occurs. Signed-off-by: fy.tsuo <fy.tsuo@intelli-go.com>
1 parent 1f0efba commit 3ffeb87

File tree

2 files changed

+179
-73
lines changed

2 files changed

+179
-73
lines changed

src/audio/host.c

Lines changed: 170 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,176 @@ static uint32_t host_dma_get_split(struct host_data *hd, uint32_t bytes)
131131
return MAX(split_src, split_dst);
132132
}
133133

134+
#if CONFIG_FORCE_DMA_COPY_WHOLE_BLOCK
135+
136+
static int host_dma_set_config_and_copy(struct comp_dev *dev, uint32_t bytes)
137+
{
138+
struct host_data *hd = comp_get_drvdata(dev);
139+
struct dma_sg_elem *local_elem = hd->config.elem_array.elems;
140+
int ret = 0;
141+
142+
local_elem->size = bytes;
143+
144+
/* reconfigure transfer */
145+
ret = dma_set_config(hd->chan, &hd->config);
146+
if (ret < 0) {
147+
comp_err(dev, "host_dma_set_config_and_copy(): dma_set_config() failed, ret = %d",
148+
ret);
149+
return ret;
150+
}
151+
152+
ret = dma_copy(hd->chan, bytes, DMA_COPY_ONE_SHOT | DMA_COPY_BLOCKING);
153+
if (ret < 0) {
154+
comp_err(dev, "host_dma_set_config_and_copy(): dma_copy() failed, ret = %d",
155+
ret);
156+
return ret;
157+
}
158+
159+
return ret;
160+
}
161+
162+
/**
163+
* Calculates bytes to be copied in one shot mode.
164+
* @param dev Host component device.
165+
* @return Bytes to be copied.
166+
*/
167+
static uint32_t host_get_copy_bytes_one_shot(struct comp_dev *dev)
168+
{
169+
struct host_data *hd = comp_get_drvdata(dev);
170+
struct comp_buffer *buffer = hd->local_buffer;
171+
uint32_t copy_bytes = 0;
172+
173+
buffer = buffer_acquire_irq(buffer);
174+
175+
/* calculate minimum size to copy */
176+
if (dev->direction == SOF_IPC_STREAM_PLAYBACK)
177+
copy_bytes = audio_stream_get_free_bytes(&buffer->stream);
178+
else
179+
copy_bytes = audio_stream_get_avail_bytes(&buffer->stream);
180+
181+
buffer_release_irq(buffer);
182+
183+
/* copy_bytes should be aligned to minimum possible chunk of
184+
* data to be copied by dma.
185+
*/
186+
copy_bytes = ALIGN_DOWN(copy_bytes, hd->dma_copy_align);
187+
188+
return copy_bytes;
189+
}
190+
191+
/**
192+
* Performs copy operation for host component working in one shot mode.
193+
* It means DMA needs to be reconfigured after every transfer.
194+
* @param dev Host component device.
195+
* @return 0 if succeeded, error code otherwise.
196+
*/
197+
static int host_copy_one_shot(struct comp_dev *dev)
198+
{
199+
struct host_data *hd = comp_get_drvdata(dev);
200+
uint32_t copy_bytes = 0;
201+
uint32_t split_value = 0;
202+
int ret = 0;
203+
204+
comp_dbg(dev, "host_copy_one_shot()");
205+
206+
copy_bytes = host_get_copy_bytes_one_shot(dev);
207+
if (!copy_bytes) {
208+
comp_info(dev, "host_copy_one_shot(): no bytes to copy");
209+
return ret;
210+
}
211+
212+
while (copy_bytes) {
213+
/* get split value */
214+
split_value = host_dma_get_split(hd, copy_bytes);
215+
copy_bytes -= split_value;
216+
217+
ret = host_dma_set_config_and_copy(dev, copy_bytes);
218+
if (ret < 0)
219+
return ret;
220+
221+
/* update copy bytes */
222+
copy_bytes = split_value;
223+
}
224+
225+
return ret;
226+
}
227+
228+
#else /* CONFIG_FORCE_DMA_COPY_WHOLE_BLOCK */
229+
230+
/**
231+
* Calculates bytes to be copied in one shot mode.
232+
* @param dev Host component device.
233+
* @return Bytes to be copied.
234+
*/
235+
static uint32_t host_get_copy_bytes_one_shot(struct comp_dev *dev)
236+
{
237+
struct host_data *hd = comp_get_drvdata(dev);
238+
struct dma_sg_elem *local_elem = hd->config.elem_array.elems;
239+
struct comp_buffer *buffer = hd->local_buffer;
240+
uint32_t copy_bytes = 0;
241+
uint32_t split_value;
242+
243+
buffer = buffer_acquire_irq(buffer);
244+
245+
/* calculate minimum size to copy */
246+
if (dev->direction == SOF_IPC_STREAM_PLAYBACK)
247+
copy_bytes = audio_stream_get_free_bytes(&buffer->stream);
248+
else
249+
copy_bytes = audio_stream_get_avail_bytes(&buffer->stream);
250+
251+
buffer_release_irq(buffer);
252+
253+
/* copy_bytes should be aligned to minimum possible chunk of
254+
* data to be copied by dma.
255+
*/
256+
copy_bytes = ALIGN_DOWN(copy_bytes, hd->dma_copy_align);
257+
258+
split_value = host_dma_get_split(hd, copy_bytes);
259+
if (split_value)
260+
copy_bytes -= split_value;
261+
262+
local_elem->size = copy_bytes;
263+
264+
return copy_bytes;
265+
}
266+
267+
/**
268+
* Performs copy operation for host component working in one shot mode.
269+
* It means DMA needs to be reconfigured after every transfer.
270+
* @param dev Host component device.
271+
* @return 0 if succeeded, error code otherwise.
272+
*/
273+
static int host_copy_one_shot(struct comp_dev *dev)
274+
{
275+
struct host_data *hd = comp_get_drvdata(dev);
276+
uint32_t copy_bytes = 0;
277+
int ret = 0;
278+
279+
comp_dbg(dev, "host_copy_one_shot()");
280+
281+
copy_bytes = host_get_copy_bytes_one_shot(dev);
282+
if (!copy_bytes) {
283+
comp_info(dev, "host_copy_one_shot(): no bytes to copy");
284+
return ret;
285+
}
286+
287+
/* reconfigure transfer */
288+
ret = dma_set_config(hd->chan, &hd->config);
289+
if (ret < 0) {
290+
comp_err(dev, "host_copy_one_shot(): dma_set_config() failed, ret = %u", ret);
291+
return ret;
292+
}
293+
294+
ret = dma_copy(hd->chan, copy_bytes, DMA_COPY_ONE_SHOT);
295+
if (ret < 0) {
296+
comp_err(dev, "host_copy_one_shot(): dma_copy() failed, ret = %u", ret);
297+
return ret;
298+
}
299+
300+
return ret;
301+
}
302+
#endif
303+
134304
static void host_update_position(struct comp_dev *dev, uint32_t bytes)
135305
{
136306
struct host_data *hd = comp_get_drvdata(dev);
@@ -256,79 +426,6 @@ static void host_dma_cb(void *arg, enum notify_id type, void *data)
256426
host_one_shot_cb(dev, bytes);
257427
}
258428

259-
/**
260-
* Calculates bytes to be copied in one shot mode.
261-
* @param dev Host component device.
262-
* @return Bytes to be copied.
263-
*/
264-
static uint32_t host_get_copy_bytes_one_shot(struct comp_dev *dev)
265-
{
266-
struct host_data *hd = comp_get_drvdata(dev);
267-
struct dma_sg_elem *local_elem = hd->config.elem_array.elems;
268-
struct comp_buffer *buffer = hd->local_buffer;
269-
uint32_t copy_bytes = 0;
270-
uint32_t split_value;
271-
272-
buffer = buffer_acquire_irq(buffer);
273-
274-
/* calculate minimum size to copy */
275-
if (dev->direction == SOF_IPC_STREAM_PLAYBACK)
276-
copy_bytes = audio_stream_get_free_bytes(&buffer->stream);
277-
else
278-
copy_bytes = audio_stream_get_avail_bytes(&buffer->stream);
279-
280-
buffer_release_irq(buffer);
281-
282-
/* copy_bytes should be aligned to minimum possible chunk of
283-
* data to be copied by dma.
284-
*/
285-
copy_bytes = ALIGN_DOWN(copy_bytes, hd->dma_copy_align);
286-
287-
split_value = host_dma_get_split(hd, copy_bytes);
288-
if (split_value)
289-
copy_bytes -= split_value;
290-
291-
local_elem->size = copy_bytes;
292-
293-
return copy_bytes;
294-
}
295-
296-
/**
297-
* Performs copy operation for host component working in one shot mode.
298-
* It means DMA needs to be reconfigured after every transfer.
299-
* @param dev Host component device.
300-
* @return 0 if succeeded, error code otherwise.
301-
*/
302-
static int host_copy_one_shot(struct comp_dev *dev)
303-
{
304-
struct host_data *hd = comp_get_drvdata(dev);
305-
uint32_t copy_bytes = 0;
306-
int ret = 0;
307-
308-
comp_dbg(dev, "host_copy_one_shot()");
309-
310-
copy_bytes = host_get_copy_bytes_one_shot(dev);
311-
if (!copy_bytes) {
312-
comp_info(dev, "host_copy_one_shot(): no bytes to copy");
313-
return ret;
314-
}
315-
316-
/* reconfigure transfer */
317-
ret = dma_set_config(hd->chan, &hd->config);
318-
if (ret < 0) {
319-
comp_err(dev, "host_copy_one_shot(): dma_set_config() failed, ret = %u", ret);
320-
return ret;
321-
}
322-
323-
ret = dma_copy(hd->chan, copy_bytes, DMA_COPY_ONE_SHOT);
324-
if (ret < 0) {
325-
comp_err(dev, "host_copy_one_shot(): dma_copy() failed, ret = %u", ret);
326-
return ret;
327-
}
328-
329-
return ret;
330-
}
331-
332429
/**
333430
* Calculates bytes to be copied in normal mode.
334431
* @param dev Host component device.

src/platform/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,4 +499,13 @@ config XTENSA_EXCLUSIVE
499499
This has to be selected for xtensa exclusive instructions.
500500
There is a definition for EXCLUSIVE option in xtensa-config.h
501501

502+
config FORCE_DMA_COPY_WHOLE_BLOCK
503+
bool
504+
default y if MT8195
505+
default n
506+
depends on HOST_PTABLE
507+
help
508+
The host component forces DMA to copy the block size to avoid
509+
copying byte jitter between the components of the same pipeline.
510+
502511
endmenu

0 commit comments

Comments
 (0)