Skip to content

Commit d27ec1d

Browse files
authored
Merge pull request #284 from tlauda/topic/dai_remove_wait
dai: remove wait on stop
2 parents 318176f + 344085d commit d27ec1d

2 files changed

Lines changed: 65 additions & 84 deletions

File tree

src/audio/dai.c

Lines changed: 62 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -62,24 +62,66 @@ struct dai_data {
6262
struct dai *dai;
6363
struct dma *dma;
6464
uint32_t period_bytes;
65-
completion_t complete;
6665
int xrun; /* true if we are doing xrun recovery */
6766
int pointer_init; /* true if buffer pointer was initialized */
6867

69-
uint32_t last_bytes; /* the last bytes(<period size) it copies. */
7068
uint32_t dai_pos_blks; /* position in bytes (nearest block) */
7169

7270
volatile uint64_t *dai_pos; /* host can read back this value without IPC */
7371
uint64_t wallclock; /* wall clock at stream start */
7472
};
7573

74+
static void dai_buffer_process(struct comp_dev *dev)
75+
{
76+
struct dai_data *dd = comp_get_drvdata(dev);
77+
struct comp_buffer *dma_buffer;
78+
void *buffer_ptr;
79+
80+
if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) {
81+
dma_buffer = list_first_item(&dev->bsource_list,
82+
struct comp_buffer, sink_list);
83+
84+
/* recalc available buffer space */
85+
comp_update_buffer_consume(dma_buffer, dd->period_bytes);
86+
87+
buffer_ptr = dma_buffer->r_ptr;
88+
89+
/* make sure there is available bytes for next period */
90+
if (dma_buffer->avail < dd->period_bytes) {
91+
trace_dai_error("xru");
92+
comp_underrun(dev, dma_buffer, dd->period_bytes, 0);
93+
}
94+
} else {
95+
dma_buffer = list_first_item(&dev->bsink_list,
96+
struct comp_buffer, source_list);
97+
98+
/* recalc available buffer space */
99+
comp_update_buffer_produce(dma_buffer, dd->period_bytes);
100+
101+
buffer_ptr = dma_buffer->w_ptr;
102+
103+
/* make sure there is free bytes for next period */
104+
if (dma_buffer->free < dd->period_bytes) {
105+
trace_dai_error("xro");
106+
comp_overrun(dev, dma_buffer, dd->period_bytes, 0);
107+
}
108+
}
109+
110+
/* update host position (in bytes offset) for drivers */
111+
dev->position += dd->period_bytes;
112+
if (dd->dai_pos) {
113+
dd->dai_pos_blks += dd->period_bytes;
114+
*dd->dai_pos = dd->dai_pos_blks +
115+
buffer_ptr - dma_buffer->addr;
116+
}
117+
}
118+
76119
/* this is called by DMA driver every time descriptor has completed */
77120
static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
78121
{
79122
struct comp_dev *dev = (struct comp_dev *)data;
80123
struct dai_data *dd = comp_get_drvdata(dev);
81124
struct comp_buffer *dma_buffer;
82-
uint32_t copied_size;
83125

84126
tracev_dai("irq");
85127

@@ -91,9 +133,6 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
91133

92134
/* tell DMA not to reload */
93135
next->size = DMA_RELOAD_END;
94-
95-
/* inform waiters */
96-
wait_completed(&dd->complete);
97136
}
98137

99138
/* is our pipeline handling an XRUN ? */
@@ -111,50 +150,7 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
111150
return;
112151
}
113152

114-
if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) {
115-
dma_buffer = list_first_item(&dev->bsource_list,
116-
struct comp_buffer, sink_list);
117-
118-
copied_size = dd->last_bytes ? dd->last_bytes : dd->period_bytes;
119-
120-
/* recalc available buffer space */
121-
comp_update_buffer_consume(dma_buffer, copied_size);
122-
123-
/* update host position(in bytes offset) for drivers */
124-
dev->position += copied_size;
125-
if (dd->dai_pos) {
126-
dd->dai_pos_blks += copied_size;
127-
*dd->dai_pos = dd->dai_pos_blks +
128-
dma_buffer->r_ptr - dma_buffer->addr;
129-
}
130-
131-
/* make sure there is availble bytes for next period */
132-
if (dma_buffer->avail < dd->period_bytes) {
133-
trace_dai_error("xru");
134-
comp_underrun(dev, dma_buffer, copied_size, 0);
135-
}
136-
137-
} else {
138-
dma_buffer = list_first_item(&dev->bsink_list,
139-
struct comp_buffer, source_list);
140-
141-
/* recalc available buffer space */
142-
comp_update_buffer_produce(dma_buffer, dd->period_bytes);
143-
144-
/* update positions */
145-
dev->position += dd->period_bytes;
146-
if (dd->dai_pos) {
147-
dd->dai_pos_blks += dd->period_bytes;
148-
*dd->dai_pos = dd->dai_pos_blks +
149-
dma_buffer->w_ptr - dma_buffer->addr;
150-
}
151-
152-
/* make sure there is free bytes for next period */
153-
if (dma_buffer->free < dd->period_bytes) {
154-
trace_dai_error("xro");
155-
comp_overrun(dev, dma_buffer, dd->period_bytes, 0);
156-
}
157-
}
153+
dai_buffer_process(dev);
158154

159155
/* notify pipeline that DAI needs its buffer processed */
160156
if (dev->state == COMP_STATE_ACTIVE)
@@ -221,7 +217,6 @@ static struct comp_dev *dai_new(struct sof_ipc_comp *comp)
221217
list_init(&dd->config.elem_list);
222218
dd->dai_pos = NULL;
223219
dd->dai_pos_blks = 0;
224-
dd->last_bytes = 0;
225220
dd->xrun = 0;
226221
dd->pointer_init = 0;
227222

@@ -507,7 +502,6 @@ static int dai_reset(struct comp_dev *dev)
507502
if (dd->dai_pos)
508503
*dd->dai_pos = 0;
509504
dd->dai_pos = NULL;
510-
dd->last_bytes = 0;
511505
dd->wallclock = 0;
512506
dev->position = 0;
513507
dd->xrun = 0;
@@ -554,13 +548,12 @@ static void dai_pointer_init(struct comp_dev *dev)
554548
static int dai_comp_trigger(struct comp_dev *dev, int cmd)
555549
{
556550
struct dai_data *dd = comp_get_drvdata(dev);
551+
struct comp_buffer *dma_buffer;
557552
int ret;
558553

559554
trace_dai("trg");
560555
tracev_value(cmd);
561556

562-
wait_init(&dd->complete);
563-
564557
ret = comp_set_state(dev, cmd);
565558
if (ret < 0)
566559
return ret;
@@ -590,14 +583,22 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd)
590583
* this is only supported at capture mode.
591584
*/
592585
if (dev->params.direction == SOF_IPC_STREAM_CAPTURE) {
593-
struct comp_buffer *dma_buffer =
594-
list_first_item(&dev->bsink_list,
595-
struct comp_buffer, source_list);
586+
dma_buffer = list_first_item(&dev->bsink_list,
587+
struct comp_buffer,
588+
source_list);
596589
buffer_zero(dma_buffer);
597590
}
598591

599592
/* only start the DAI if we are not XRUN handling */
600593
if (dd->xrun == 0) {
594+
/* set valid buffer pointer */
595+
dai_buffer_process(dev);
596+
597+
/* recover valid start position */
598+
ret = dma_release(dd->dma, dd->chan);
599+
if (ret < 0)
600+
return ret;
601+
601602
/* start the DAI */
602603
ret = dma_start(dd->dma, dd->chan);
603604
if (ret < 0)
@@ -613,26 +614,13 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd)
613614
case COMP_TRIGGER_XRUN:
614615
trace_dai("txr");
615616
dd->xrun = 1;
616-
/* stop the DAI unconditionally */
617-
dai_trigger(dd->dai, COMP_TRIGGER_STOP, dev->params.direction);
618-
ret = dma_stop(dd->dma, dd->chan);
619-
break;
617+
618+
/* fallthrough */
620619
case COMP_TRIGGER_PAUSE:
621620
case COMP_TRIGGER_STOP:
622621
trace_dai("tsp");
623-
wait_init(&dd->complete);
624-
625-
/* wait for DMA to complete */
626-
dd->complete.timeout = dev->pipeline->ipc_pipe.deadline;
627-
ret = wait_for_completion_timeout(&dd->complete);
628-
if (ret < 0) {
629-
trace_dai_error("ed0");
630-
trace_error_value(cmd);
631-
/* forced stop of DMA+DAI to avoid refcount issues */
632-
dai_trigger(dd->dai, COMP_TRIGGER_STOP,
633-
dev->params.direction);
634-
ret = dma_stop(dd->dma, dd->chan);
635-
}
622+
ret = dma_stop(dd->dma, dd->chan);
623+
dai_trigger(dd->dai, COMP_TRIGGER_STOP, dev->params.direction);
636624
break;
637625
default:
638626
break;

src/drivers/intel/dw-dma.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -457,22 +457,15 @@ static int dw_dma_start(struct dma *dma, int channel)
457457
static int dw_dma_release(struct dma *dma, int channel)
458458
{
459459
struct dma_pdata *p = dma_get_drvdata(dma);
460-
struct dw_lli2 *lli;
461460
uint32_t flags;
462461

463462
spin_lock_irq(&dma->lock, flags);
464463

465464
trace_dma("Dpr");
466465

467-
/* get current lli */
468-
#if DW_USE_HW_LLI
469-
lli = (struct dw_lli2 *)dw_read(dma, DW_LLP(channel));
470-
#else
471-
lli = p->chan[channel].lli_current;
472-
#endif
473-
/* get next lli and recover the lli to head for restart */
474-
lli = (struct dw_lli2 *)lli->llp;
475-
p->chan[channel].lli = lli;
466+
/* get next lli for proper release */
467+
p->chan[channel].lli_current =
468+
(struct dw_lli2 *)p->chan[channel].lli_current->llp;
476469

477470
spin_unlock_irq(&dma->lock, flags);
478471
return 0;

0 commit comments

Comments
 (0)