Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 48 additions & 28 deletions src/lib/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,11 @@ struct dma *dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags)
struct dma *d = NULL, *dmin = NULL;

if (!lib_dma.num_dmas) {
trace_error(TRACE_CLASS_DMA, "dma_get(): No DMAs installed");
trace_error(TRACE_CLASS_DMA, "dma_get(): No DMACs installed");
return NULL;
}

/* find DMAC with free channels that matches request */
for (d = lib_dma.dma_array; d < lib_dma.dma_array + lib_dma.num_dmas;
d++) {
/* skip if this DMAC does not support the requested dir */
Expand All @@ -73,6 +75,11 @@ struct dma *dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags)
if (dev && (d->plat_data.devs & dev) == 0)
continue;

/* skip if this DMAC has 1 user per avail channel */
/* TODO: this should be fixed in dai.c to allow more users */
if (d->sref >= d->plat_data.channels)
continue;

/* if exclusive access is requested */
if (flags & DMA_ACCESS_EXCLUSIVE) {

Expand All @@ -92,37 +99,50 @@ struct dma *dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags)
}
}

if (!dmin) {
trace_error(TRACE_CLASS_DMA, "No DMAC dir %d caps 0x%x dev 0x%x flags 0x%x",
dir, cap, dev, flags);

for (d = lib_dma.dma_array; d < lib_dma.dma_array + lib_dma.num_dmas;
d++) {
trace_error(TRACE_CLASS_DMA, " DMAC ID %d users %d busy channels %d",
d->plat_data.id, d->sref,
atomic_read(&d->num_channels_busy));
trace_error(TRACE_CLASS_DMA, " caps 0x%x dev 0x%x",
d->plat_data.caps, d->plat_data.devs);
}
return NULL;
}

/* return DMAC */
if (dmin) {
tracev_event(TRACE_CLASS_DMA, "dma_get(), dma-probe id = %d",
dmin->plat_data.id);
/* Shared DMA controllers with multiple channels
* may be requested many times, let the probe()
* do on-first-use initialization.
*/
spin_lock(&dmin->lock);
ret = 0;
if (dmin->sref == 0) {
ret = dma_probe(dmin);
if (ret < 0) {
trace_error(TRACE_CLASS_DMA,
"dma_get() error: dma-probe failed"
" id = %d, ret = %d",
dmin->plat_data.id, ret);
}
tracev_event(TRACE_CLASS_DMA, "dma_get(), dma-probe id = %d",
dmin->plat_data.id);

/* Shared DMA controllers with multiple channels
* may be requested many times, let the probe()
* do on-first-use initialization.
*/
spin_lock(&dmin->lock);

ret = 0;
if (dmin->sref == 0) {
ret = dma_probe(dmin);
if (ret < 0) {
trace_error(TRACE_CLASS_DMA,
"dma_get() error: dma-probe failed"
" id = %d, ret = %d",
dmin->plat_data.id, ret);
}
if (!ret)
dmin->sref++;
trace_event(TRACE_CLASS_DMA, "dma_get(), dmin = %p, sref = %d",
(uintptr_t)dmin, dmin->sref);
spin_unlock(&dmin->lock);
return !ret ? dmin : NULL;
}
if (!ret)
dmin->sref++;

trace_event(TRACE_CLASS_DMA, "dma_get() ID %d sref = %d busy channels %d",
dmin->plat_data.id, dmin->sref,
atomic_read(&dmin->num_channels_busy));

trace_error(TRACE_CLASS_DMA,
"dma_get() error: dir = 0x%x, cap = 0x%x, dev = 0x%x, "
"flags = 0x%x not found", dir, cap, dev, flags);
return NULL;
spin_unlock(&dmin->lock);
return !ret ? dmin : NULL;
}

void dma_put(struct dma *dma)
Expand Down