schedule: zephyr_dma_domain: Do not use a registered channel

Current implementation only checks if a channel is used with
current interrupt. But that channel might have been registered
with another interrupt earlier.

So, we need a way to skip channels already used. For this, we iterate
over all registered interrupts and check existing registered channels.

This fixes scenarios where running:

$ arecord -Dhw:0,0 -f S32 -c 2 -r 48000 -t raw |
aplay -Dhw:0,0 -f S32_LE -c 2 -r 48000

will result in an I/O error.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
This commit is contained in:
Daniel Baluta 2023-11-09 19:30:47 +02:00 committed by Daniel Baluta
parent b7d7fb0ed2
commit 1a8b1bf60c
1 changed files with 24 additions and 0 deletions

View File

@ -239,6 +239,26 @@ static struct zephyr_dma_domain_irq *fetch_irq_data(struct zephyr_dma_domain *do
return NULL; return NULL;
} }
bool chan_is_registered(struct zephyr_dma_domain *domain, struct dma_chan_data *chan)
{
struct zephyr_dma_domain_irq *irq_data;
struct zephyr_dma_domain_channel *chan_data;
struct list_item *i, *j;
list_for_item(i, &domain->irqs) {
irq_data = container_of(i, struct zephyr_dma_domain_irq, list);
list_for_item(j, &irq_data->channels) {
chan_data = container_of(j, struct zephyr_dma_domain_channel, list);
if (chan_data->channel == chan)
return true;
}
}
return false;
}
static int register_dma_irq(struct zephyr_dma_domain *domain, static int register_dma_irq(struct zephyr_dma_domain *domain,
struct zephyr_dma_domain_irq **irq_data, struct zephyr_dma_domain_irq **irq_data,
struct zephyr_dma_domain_thread *dt, struct zephyr_dma_domain_thread *dt,
@ -273,6 +293,10 @@ static int register_dma_irq(struct zephyr_dma_domain *domain,
if (core != crt_chan->core) if (core != crt_chan->core)
continue; continue;
/* skip is DMA chan is already registered with domain */
if (chan_is_registered(domain, crt_chan))
continue;
/* get IRQ number for current channel */ /* get IRQ number for current channel */
irq = interrupt_get_irq(dma_chan_irq(crt_dma, j), irq = interrupt_get_irq(dma_chan_irq(crt_dma, j),
dma_chan_irq_name(crt_dma, j)); dma_chan_irq_name(crt_dma, j));