From 589dbebb712f5080c9a3f9b05f51e35ee4f649e8 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 16 Feb 2026 19:27:56 +0200 Subject: [PATCH 1/4] audio: host-zephyr: rework calls to DMA driver, remove channel pointer For historical reasons, host-zephyr has somewhat complicated code to manage the DMA channel instance information. When a DMA channel is allocated, a pointer to the system DMA channel table is acquired and some additional information is stored per channel. This is however redundant as the only piece of information actually needed is the channel index. Simplify the code by not storing the channel pointer anymore, but rather just store the channel index and use that in all calls to the DMA driver. Signed-off-by: Kai Vehmanen --- src/audio/copier/host_copier.h | 6 +++- src/audio/host-zephyr.c | 50 +++++++++++++++------------------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/audio/copier/host_copier.h b/src/audio/copier/host_copier.h index 9db9028a54d7..13a118a3ed81 100644 --- a/src/audio/copier/host_copier.h +++ b/src/audio/copier/host_copier.h @@ -28,6 +28,9 @@ struct io_perf_data_item; typedef void (*copy_callback_t)(struct comp_dev *dev, size_t bytes); +/** DMA channel index value indicating no channel is allocated. */ +#define DMA_CHAN_INVALID (-1) + struct host_data; /** \brief Host copy function interface. */ typedef int (*host_copy_func)(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb); @@ -54,10 +57,11 @@ struct host_data { /* local DMA config */ #if CONFIG_ZEPHYR_NATIVE_DRIVERS struct sof_dma *dma; + int chan_index; #else struct dma *dma; -#endif struct dma_chan_data *chan; +#endif struct dma_sg_config config; #ifdef __ZEPHYR__ struct dma_config z_config; diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index 613b38bcd00f..87fd3068aeed 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -84,7 +84,7 @@ static int host_dma_set_config_and_copy(struct host_data *hd, struct comp_dev *d local_elem->size = bytes; /* reconfigure transfer */ - ret = sof_dma_config(hd->chan->dma, hd->chan->index, &hd->z_config); + ret = sof_dma_config(hd->dma, hd->chan_index, &hd->z_config); if (ret < 0) { comp_err(dev, "dma_config() failed, ret = %d", ret); @@ -93,7 +93,7 @@ static int host_dma_set_config_and_copy(struct host_data *hd, struct comp_dev *d cb(dev, bytes); - ret = sof_dma_reload(hd->chan->dma, hd->chan->index, bytes); + ret = sof_dma_reload(hd->dma, hd->chan_index, bytes); if (ret < 0) { comp_err(dev, "dma_copy() failed, ret = %d", ret); @@ -223,7 +223,7 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_c hd->z_config.head_block->block_size = local_elem->size; /* reconfigure transfer */ - ret = sof_dma_config(hd->chan->dma, hd->chan->index, &hd->z_config); + ret = sof_dma_config(hd->dma, hd->chan_index, &hd->z_config); if (ret < 0) { comp_err(dev, "dma_config() failed, ret = %u", ret); return ret; @@ -231,7 +231,7 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_c cb(dev, copy_bytes); - ret = sof_dma_reload(hd->chan->dma, hd->chan->index, copy_bytes); + ret = sof_dma_reload(hd->dma, hd->chan_index, copy_bytes); if (ret < 0) comp_err(dev, "dma_copy() failed, ret = %u", ret); @@ -369,7 +369,7 @@ static void host_dma_cb(struct comp_dev *dev, size_t bytes) /* get status from dma and check for xrun */ static int host_get_status(struct comp_dev *dev, struct host_data *hd, struct dma_status *stat) { - int ret = sof_dma_get_status(hd->chan->dma, hd->chan->index, stat); + int ret = sof_dma_get_status(hd->dma, hd->chan_index, stat); #if CONFIG_XRUN_NOTIFICATIONS_ENABLE if (ret == -EPIPE && !hd->xrun_notification_sent) { hd->xrun_notification_sent = send_copier_gateway_xrun_notif_msg @@ -556,7 +556,7 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal if (!copy_bytes) { if (hd->partial_size != 0) { if (stream_sync(hd, dev)) { - ret = sof_dma_reload(hd->chan->dma, hd->chan->index, + ret = sof_dma_reload(hd->dma, hd->chan_index, hd->partial_size); if (ret < 0) comp_err(dev, "dma_reload() failed, ret = %u", ret); @@ -583,7 +583,7 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal hd->dma_buffer_size - hd->partial_size <= (2 + threshold) * hd->period_bytes) { if (stream_sync(hd, dev)) { - ret = sof_dma_reload(hd->chan->dma, hd->chan->index, + ret = sof_dma_reload(hd->dma, hd->chan_index, hd->partial_size); if (ret < 0) comp_err(dev, "dma_reload() failed, ret = %u", ret); @@ -651,7 +651,7 @@ int host_common_trigger(struct host_data *hd, struct comp_dev *dev, int cmd) if (cmd != COMP_TRIGGER_START && hd->copy_type == COMP_COPY_ONE_SHOT) return ret; - if (!hd->chan) { + if (hd->chan_index == DMA_CHAN_INVALID) { comp_err(dev, "no dma channel configured"); return -EINVAL; } @@ -659,14 +659,14 @@ int host_common_trigger(struct host_data *hd, struct comp_dev *dev, int cmd) switch (cmd) { case COMP_TRIGGER_START: hd->partial_size = 0; - ret = sof_dma_start(hd->chan->dma, hd->chan->index); + ret = sof_dma_start(hd->dma, hd->chan_index); if (ret < 0) comp_err(dev, "dma_start() failed, ret = %u", ret); break; case COMP_TRIGGER_STOP: case COMP_TRIGGER_XRUN: - ret = sof_dma_stop(hd->chan->dma, hd->chan->index); + ret = sof_dma_stop(hd->dma, hd->chan_index); if (ret < 0) comp_err(dev, "dma stop failed: %d", ret); @@ -726,7 +726,7 @@ __cold int host_common_new(struct host_data *hd, struct comp_dev *dev, sof_dma_put(hd->dma); return -ENOMEM; } - hd->chan = NULL; + hd->chan_index = DMA_CHAN_INVALID; hd->copy_type = COMP_COPY_NORMAL; return 0; @@ -865,7 +865,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, uint32_t buffer_size_preferred; uint32_t addr_align; uint32_t align; - int i, channel, err; + int i, err; bool is_scheduling_source = dev == dev->pipeline->sched_comp; uint32_t round_up_size; @@ -1001,22 +1001,16 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, /* get DMA channel from DMAC * note: stream_tag is ignored by dw-dma */ - channel = sof_dma_request_channel(hd->dma, hda_chan); - if (channel < 0) { + hd->chan_index = sof_dma_request_channel(hd->dma, hda_chan); + if (hd->chan_index < 0) { comp_err(dev, "requested channel %d is busy", hda_chan); return -ENODEV; } - hd->chan = &hd->dma->chan[channel]; uint32_t buffer_addr = 0; uint32_t buffer_bytes = 0; uint32_t addr; - hd->chan->direction = config->direction; - hd->chan->desc_count = config->elem_array.count; - hd->chan->is_scheduling_source = config->is_scheduling_source; - hd->chan->period = config->period; - memset(dma_cfg, 0, sizeof(*dma_cfg)); dma_block_cfg = rzalloc(SOF_MEM_FLAG_USER, @@ -1063,7 +1057,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, break; } - err = sof_dma_config(hd->chan->dma, hd->chan->index, dma_cfg); + err = sof_dma_config(hd->dma, hd->chan_index, dma_cfg); if (err < 0) { comp_err(dev, "dma_config() failed"); goto err_free_block_cfg; @@ -1095,7 +1089,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, */ struct io_perf_data_item init_data = { IO_PERF_HDA_ID, - hd->chan->index, + hd->chan_index, params->direction, IO_PERF_POWERED_UP_ENABLED, IO_PERF_D0IX_POWER_MODE, @@ -1111,8 +1105,8 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, dma_cfg->head_block = NULL; rfree(dma_block_cfg); err_release_channel: - sof_dma_release_channel(hd->dma, hd->chan->index); - hd->chan = NULL; + sof_dma_release_channel(hd->dma, hd->chan_index); + hd->chan_index = DMA_CHAN_INVALID; return err; } @@ -1170,10 +1164,10 @@ static int host_position(struct comp_dev *dev, void host_common_reset(struct host_data *hd, uint16_t state) { - if (hd->chan) { - sof_dma_stop(hd->chan->dma, hd->chan->index); - sof_dma_release_channel(hd->dma, hd->chan->index); - hd->chan = NULL; + if (hd->chan_index != DMA_CHAN_INVALID) { + sof_dma_stop(hd->dma, hd->chan_index); + sof_dma_release_channel(hd->dma, hd->chan_index); + hd->chan_index = DMA_CHAN_INVALID; } /* free all DMA elements */ From b6ca08027dda9916d0e1ab240ea1d899d3482dc8 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 27 Apr 2026 12:30:47 +0300 Subject: [PATCH 2/4] audio: host-zephyr: rework calls to DMA driver, remove channel pointer For historical reasons, host-zephyr has somewhat complicated code to manage the DMA channel instance information. When a DMA channel is allocated, a pointer to the system DMA channel table is acquired and some additional information is stored per channel. This is however redundant as the only piece of information actually needed is the channel index. Simplify the code by not storing the channel pointer anymore, but rather just store the channel index and use that in all calls to the DMA driver. Signed-off-by: Kai Vehmanen --- src/audio/copier/host_copier.h | 3 --- src/audio/host-zephyr.c | 10 +++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/audio/copier/host_copier.h b/src/audio/copier/host_copier.h index 13a118a3ed81..2bc8904e1258 100644 --- a/src/audio/copier/host_copier.h +++ b/src/audio/copier/host_copier.h @@ -28,9 +28,6 @@ struct io_perf_data_item; typedef void (*copy_callback_t)(struct comp_dev *dev, size_t bytes); -/** DMA channel index value indicating no channel is allocated. */ -#define DMA_CHAN_INVALID (-1) - struct host_data; /** \brief Host copy function interface. */ typedef int (*host_copy_func)(struct host_data *hd, struct comp_dev *dev, copy_callback_t cb); diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index 87fd3068aeed..d1251387c278 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -651,7 +651,7 @@ int host_common_trigger(struct host_data *hd, struct comp_dev *dev, int cmd) if (cmd != COMP_TRIGGER_START && hd->copy_type == COMP_COPY_ONE_SHOT) return ret; - if (hd->chan_index == DMA_CHAN_INVALID) { + if (hd->chan_index == -EINVAL) { comp_err(dev, "no dma channel configured"); return -EINVAL; } @@ -726,7 +726,7 @@ __cold int host_common_new(struct host_data *hd, struct comp_dev *dev, sof_dma_put(hd->dma); return -ENOMEM; } - hd->chan_index = DMA_CHAN_INVALID; + hd->chan_index = -EINVAL; hd->copy_type = COMP_COPY_NORMAL; return 0; @@ -1106,7 +1106,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, rfree(dma_block_cfg); err_release_channel: sof_dma_release_channel(hd->dma, hd->chan_index); - hd->chan_index = DMA_CHAN_INVALID; + hd->chan_index = -EINVAL; return err; } @@ -1164,10 +1164,10 @@ static int host_position(struct comp_dev *dev, void host_common_reset(struct host_data *hd, uint16_t state) { - if (hd->chan_index != DMA_CHAN_INVALID) { + if (hd->chan_index != -EINVAL) { sof_dma_stop(hd->dma, hd->chan_index); sof_dma_release_channel(hd->dma, hd->chan_index); - hd->chan_index = DMA_CHAN_INVALID; + hd->chan_index = -EINVAL; } /* free all DMA elements */ From 9805a753a3cb93c459d132e17e4e2e2e0b2fb6ec Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 27 Apr 2026 11:42:02 +0300 Subject: [PATCH 3/4] audio: host-zephyr: clean DMA if channel set at free Add code to check for a valid DMA channel in host_common_free() and if a DMA channel is set, stop the channel and free DMA resources. Issue found in code review. This should not be hit in normal use-cases, but this makes the free implementation more robust in case of errors. Signed-off-by: Kai Vehmanen --- src/audio/host-zephyr.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index d1251387c278..663f2fef524c 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -784,6 +784,13 @@ __cold void host_common_free(struct host_data *hd) } #endif + /* release DMA channel if not already done by reset */ + if (hd->chan_index != -EINVAL) { + sof_dma_stop(hd->dma, hd->chan_index); + sof_dma_release_channel(hd->dma, hd->chan_index); + hd->chan_index = -EINVAL; + } + sof_dma_put(hd->dma); ipc_msg_free(hd->msg); From 746f49e8311f484c9595fea85fc6c19cf872e1c9 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 27 Apr 2026 11:52:58 +0300 Subject: [PATCH 4/4] audio: host-zephyr: fix log print formatting Multiple comp_err() statements refer to incorrect DMA function call names and/or use "%u" to print integer value. Signed-off-by: Kai Vehmanen --- src/audio/host-zephyr.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index 663f2fef524c..da873b9f0f26 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -95,7 +95,7 @@ static int host_dma_set_config_and_copy(struct host_data *hd, struct comp_dev *d ret = sof_dma_reload(hd->dma, hd->chan_index, bytes); if (ret < 0) { - comp_err(dev, "dma_copy() failed, ret = %d", + comp_err(dev, "dma_reload() failed, ret = %d", ret); return ret; } @@ -225,7 +225,7 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_c /* reconfigure transfer */ ret = sof_dma_config(hd->dma, hd->chan_index, &hd->z_config); if (ret < 0) { - comp_err(dev, "dma_config() failed, ret = %u", ret); + comp_err(dev, "dma_config() failed, ret = %d", ret); return ret; } @@ -233,7 +233,7 @@ static int host_copy_one_shot(struct host_data *hd, struct comp_dev *dev, copy_c ret = sof_dma_reload(hd->dma, hd->chan_index, copy_bytes); if (ret < 0) - comp_err(dev, "dma_copy() failed, ret = %u", ret); + comp_err(dev, "dma_reload() failed, ret = %d", ret); return ret; } @@ -428,7 +428,7 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev /* get data sizes from DMA */ ret = host_get_status(dev, hd, &dma_stat); if (ret < 0) { - comp_err(dev, "dma_get_status() failed, ret = %u", + comp_err(dev, "dma_get_status() failed, ret = %d", ret); /* return 0 copy_bytes in case of error to skip DMA copy */ return 0; @@ -559,7 +559,7 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal ret = sof_dma_reload(hd->dma, hd->chan_index, hd->partial_size); if (ret < 0) - comp_err(dev, "dma_reload() failed, ret = %u", ret); + comp_err(dev, "dma_reload() failed, ret = %d", ret); hd->partial_size = 0; } @@ -586,7 +586,7 @@ static int host_copy_normal(struct host_data *hd, struct comp_dev *dev, copy_cal ret = sof_dma_reload(hd->dma, hd->chan_index, hd->partial_size); if (ret < 0) - comp_err(dev, "dma_reload() failed, ret = %u", ret); + comp_err(dev, "dma_reload() failed, ret = %d", ret); hd->partial_size = 0; } @@ -661,7 +661,7 @@ int host_common_trigger(struct host_data *hd, struct comp_dev *dev, int cmd) hd->partial_size = 0; ret = sof_dma_start(hd->dma, hd->chan_index); if (ret < 0) - comp_err(dev, "dma_start() failed, ret = %u", + comp_err(dev, "dma_start() failed, ret = %d", ret); break; case COMP_TRIGGER_STOP: