[Sound-open-firmware] [PATCH] host: fix playback failed from second time issue

Keyon Jie yang.jie at linux.intel.com
Fri Feb 9 13:00:08 CET 2018


For host with gateway, we need create extra dma_sg_elem *
period_count for hd->config.element_list, and free them
at host_reset() time, otherwise, the hd->local elements
may be broken if we use them for config.element_list.

Signed-off-by: Keyon Jie <yang.jie at linux.intel.com>
---
 src/audio/host.c | 48 +++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 41 insertions(+), 7 deletions(-)

diff --git a/src/audio/host.c b/src/audio/host.c
index 17218fe..da5ae3f 100644
--- a/src/audio/host.c
+++ b/src/audio/host.c
@@ -411,6 +411,10 @@ static int create_local_elems(struct comp_dev *dev)
 {
 	struct host_data *hd = comp_get_drvdata(dev);
 	struct dma_sg_elem *e;
+#if defined CONFIG_DMA_GW
+	struct dma_sg_elem *ec;
+	struct dma_sg_elem *local_elem;
+#endif
 	struct list_item *elist;
 	struct list_item *tlist;
 	int i;
@@ -434,13 +438,21 @@ static int create_local_elems(struct comp_dev *dev)
 		list_item_append(&e->list, &hd->local.elem_list);
 #if defined CONFIG_DMA_GW
 		/*
-		 * for dma gateway, we don't allocate extra sg elements, so,
-		 * just reuse local elements for config.elem_list.
+		 * for dma gateway, we don't allocate extra sg elements in
+		 * host_buffer, so, we need create them here and add them
+		 * to config.elem_list.
 		 * And, as the first element has been added at host_new, so
-		 * add from the 2nd element here
+		 * add from the 2nd element here.
 		 */
-		if (i >= 1)
-			list_item_append(&e->list, &hd->config.elem_list);
+		if (!i)
+			continue;
+		/* allocate new host DMA elem and add it to our list */
+		ec = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*ec));
+		if (!ec)
+			goto unwind;
+
+		*ec = *e;
+		list_item_append(&ec->list, &hd->config.elem_list);
 #endif
 	}
 
@@ -452,6 +464,15 @@ unwind:
 		list_item_del(&e->list);
 		rfree(e);
 	}
+#if defined CONFIG_DMA_GW
+	local_elem = list_first_item(&hd->config.elem_list,
+				     struct dma_sg_elem, list);
+	list_for_item_safe(elist, tlist, &local_elem->list) {
+		ec = container_of(elist, struct dma_sg_elem, list);
+		list_item_del(&ec->list);
+		rfree(ec);
+	}
+#endif
 	trace_host_error("el0");
 	return -ENOMEM;
 }
@@ -712,7 +733,6 @@ static int host_reset(struct comp_dev *dev)
 
 	/* free all host DMA elements */
 	list_for_item_safe(elist, tlist, &hd->host.elem_list) {
-
 		e = container_of(elist, struct dma_sg_elem, list);
 		list_item_del(&e->list);
 		rfree(e);
@@ -720,7 +740,6 @@ static int host_reset(struct comp_dev *dev)
 
 	/* free all local DMA elements */
 	list_for_item_safe(elist, tlist, &hd->local.elem_list) {
-
 		e = container_of(elist, struct dma_sg_elem, list);
 		list_item_del(&e->list);
 		rfree(e);
@@ -729,6 +748,21 @@ static int host_reset(struct comp_dev *dev)
 #if defined CONFIG_DMA_GW
 	dma_stop(hd->dma, hd->chan);
 	dma_channel_put(hd->dma, hd->chan);
+
+	e = list_first_item(&hd->config.elem_list,
+			    struct dma_sg_elem, list);
+	/*
+	 * here free dma_sg_elem those allocated in create_local_elems(),
+	 * we should keep header and the first local elem after reset
+	 */
+	list_for_item_safe(elist, tlist, &e->list) {
+		e = container_of(elist, struct dma_sg_elem, list);
+		/* should not free the header, finished */
+		if (elist == &hd->config.elem_list)
+			break;
+		list_item_del(&e->list);
+		rfree(e);
+	}
 #endif
 
 	host_pointer_reset(dev);
-- 
2.11.0



More information about the Sound-open-firmware mailing list