[Sound-open-firmware] [PATCH] ipc: page tables; Make page table API generic for use outside IPC core

Liam Girdwood liam.r.girdwood at linux.intel.com
Thu Apr 12 18:24:27 CEST 2018


Allow users outside of IPC to make use of compressed host page tables.

Signed-off-by: Liam Girdwood <liam.r.girdwood at linux.intel.com>
---
 src/include/sof/intel-ipc.h |   1 -
 src/include/sof/ipc.h       |   8 +++
 src/ipc/handler.c           | 143 +++-----------------------------------------
 src/ipc/ipc.c               | 129 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 146 insertions(+), 135 deletions(-)

diff --git a/src/include/sof/intel-ipc.h b/src/include/sof/intel-ipc.h
index f89e9b57..a59c106f 100644
--- a/src/include/sof/intel-ipc.h
+++ b/src/include/sof/intel-ipc.h
@@ -38,7 +38,6 @@ struct intel_ipc_data {
 	/* DMA */
 	struct dma *dmac;
 	uint8_t *page_table;
-	completion_t complete;
 
 	/* PM */
 	int pm_prepare_D3;	/* do we need to prepare for D3 */
diff --git a/src/include/sof/ipc.h b/src/include/sof/ipc.h
index 2e1818df..06425b34 100644
--- a/src/include/sof/ipc.h
+++ b/src/include/sof/ipc.h
@@ -134,6 +134,14 @@ int ipc_send_short_msg(uint32_t msg);
 void ipc_platform_do_cmd(struct ipc *ipc);
 void ipc_platform_send_msg(struct ipc *ipc);
 
+/* create a SG page table eme list from a compressed page table */
+int ipc_parse_page_descriptors(uint8_t *page_table,
+			       struct sof_ipc_host_buffer *ring,
+			       struct list_item *elem_list,
+			       uint32_t direction);
+int ipc_get_page_descriptors(struct dma *dmac, uint8_t *page_table,
+			     struct sof_ipc_host_buffer *ring);
+
 /*
  * IPC Component creation and destruction.
  */
diff --git a/src/ipc/handler.c b/src/ipc/handler.c
index 6a51765b..581ce9e7 100644
--- a/src/ipc/handler.c
+++ b/src/ipc/handler.c
@@ -83,134 +83,6 @@ static inline struct sof_ipc_hdr *mailbox_validate(void)
 	return hdr;
 }
 
-#ifdef CONFIG_HOST_PTABLE
-static void dma_complete(void *data, uint32_t type, struct dma_sg_elem *next)
-{
-	struct intel_ipc_data *iipc = (struct intel_ipc_data *)data;
-
-	if (type == DMA_IRQ_TYPE_LLIST)
-		wait_completed(&iipc->complete);
-}
-
-/*
- * Copy the audio buffer page tables from the host to the DSP max of 4K.
- */
-static int get_page_descriptors(struct intel_ipc_data *iipc,
-	struct sof_ipc_host_buffer *ring)
-{
-	struct dma_sg_config config;
-	struct dma_sg_elem elem;
-	struct dma *dma;
-	int chan;
-	int ret = 0;
-
-	/* get DMA channel from DMAC */
-	chan = dma_channel_get(iipc->dmac, 0);
-	if (chan < 0) {
-		trace_ipc_error("ePC");
-		return chan;
-	}
-	dma = iipc->dmac;
-
-	/* set up DMA configuration */
-	config.direction = DMA_DIR_HMEM_TO_LMEM;
-	config.src_width = sizeof(uint32_t);
-	config.dest_width = sizeof(uint32_t);
-	config.cyclic = 0;
-	list_init(&config.elem_list);
-
-	/* set up DMA descriptor */
-	elem.dest = (uint32_t)iipc->page_table;
-	elem.src = ring->phy_addr;
-
-	/* source buffer size is always PAGE_SIZE bytes */
-	/* 20 bits for each page, round up to 32 */
-	elem.size = (ring->pages * 5 * 16 + 31) / 32;
-	list_item_prepend(&elem.list, &config.elem_list);
-
-	ret = dma_set_config(dma, chan, &config);
-	if (ret < 0) {
-		trace_ipc_error("ePs");
-		goto out;
-	}
-
-	/* set up callback */
-	dma_set_cb(dma, chan, DMA_IRQ_TYPE_LLIST, dma_complete, iipc);
-
-	wait_init(&iipc->complete);
-
-	/* start the copy of page table to DSP */
-	dma_start(dma, chan);
-
-	/* wait for DMA to complete */
-	iipc->complete.timeout = PLATFORM_HOST_DMA_TIMEOUT;
-	ret = wait_for_completion_timeout(&iipc->complete);
-
-	/* compressed page tables now in buffer at _ipc->page_table */
-out:
-	dma_channel_put(dma, chan);
-	return ret;
-}
-
-/*
- * Parse the host page tables and create the audio DMA SG configuration
- * for host audio DMA buffer. This involves creating a dma_sg_elem for each
- * page table entry and adding each elem to a list in struct dma_sg_config.
- */
-static int parse_page_descriptors(struct intel_ipc_data *iipc,
-	struct sof_ipc_host_buffer *ring, struct list_item *elem_list,
-	uint32_t direction)
-{
-	int i;
-	uint32_t idx;
-	uint32_t phy_addr;
-	struct dma_sg_elem *e;
-
-	/* the ring size may be not multiple of the page size, the last
-	 * page may be not full used. The used size should be in range
-	 * of (ring->pages - 1, ring->pages] * PAGES.
-	 */
-	if ((ring->size <= HOST_PAGE_SIZE * (ring->pages - 1)) ||
-			(ring->size > HOST_PAGE_SIZE * ring->pages)) {
-		/* error buffer size */
-		trace_ipc_error("eBs");
-		return -EINVAL;
-	}
-
-	for (i = 0; i < ring->pages; i++) {
-		idx = (((i << 2) + i)) >> 1;
-		phy_addr = iipc->page_table[idx] | (iipc->page_table[idx + 1] << 8)
-				| (iipc->page_table[idx + 2] << 16);
-
-		if (i & 0x1)
-			phy_addr <<= 8;
-		else
-			phy_addr <<= 12;
-		phy_addr &= 0xfffff000;
-
-		/* allocate new host DMA elem and add it to our list */
-		e = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, sizeof(*e));
-		if (!e)
-			return -ENOMEM;
-
-		if (direction == SOF_IPC_STREAM_PLAYBACK)
-			e->src = phy_addr;
-		else
-			e->dest = phy_addr;
-
-		/* the last page may be not full used */
-		if (i == (ring->pages - 1))
-			e->size = ring->size - HOST_PAGE_SIZE * i;
-		else
-			e->size = HOST_PAGE_SIZE;
-
-		list_item_append(&e->list, elem_list);
-	}
-
-	return 0;
-}
-#endif
-
 /*
  * Stream IPC Operations.
  */
@@ -258,7 +130,8 @@ static int ipc_stream_pcm_params(uint32_t stream)
 	list_init(&elem_list);
 
 	/* use DMA to read in compressed page table ringbuffer from host */
-	err = get_page_descriptors(iipc, &pcm_params->params.buffer);
+	err = ipc_get_page_descriptors(iipc->dmac, iipc->page_table,
+				       &pcm_params->params.buffer);
 	if (err < 0) {
 		trace_ipc_error("eAp");
 		goto error;
@@ -268,8 +141,9 @@ static int ipc_stream_pcm_params(uint32_t stream)
 	host = (struct sof_ipc_comp_host *)&cd->comp;
 	ring_size = pcm_params->params.buffer.size;
 
-	err = parse_page_descriptors(iipc, &pcm_params->params.buffer,
-		&elem_list, host->direction);
+	err = ipc_parse_page_descriptors(iipc->page_table,
+					 &pcm_params->params.buffer,
+					 &elem_list, host->direction);
 	if (err < 0) {
 		trace_ipc_error("eAP");
 		goto error;
@@ -656,7 +530,8 @@ static int ipc_dma_trace_config(uint32_t header)
 	list_init(&elem_list);
 
 	/* use DMA to read in compressed page table ringbuffer from host */
-	err = get_page_descriptors(iipc, &params->buffer);
+	err = ipc_get_page_descriptors(iipc->dmac, iipc->page_table,
+				       &params->buffer);
 	if (err < 0) {
 		trace_ipc_error("eCp");
 		goto error;
@@ -667,8 +542,8 @@ static int ipc_dma_trace_config(uint32_t header)
 	/* Parse host tables */
 	ring_size = params->buffer.size;
 
-	err = parse_page_descriptors(iipc, &params->buffer,
-		&elem_list, SOF_IPC_STREAM_CAPTURE);
+	err = ipc_parse_page_descriptors(iipc->page_table, &params->buffer,
+					 &elem_list, SOF_IPC_STREAM_CAPTURE);
 	if (err < 0) {
 		trace_ipc_error("ePP");
 		goto error;
diff --git a/src/ipc/ipc.c b/src/ipc/ipc.c
index ed2cbb8e..fbb1be6c 100644
--- a/src/ipc/ipc.c
+++ b/src/ipc/ipc.c
@@ -39,6 +39,7 @@
 #include <sof/alloc.h>
 #include <sof/ipc.h>
 #include <sof/debug.h>
+#include <platform/platform.h>
 #include <sof/audio/component.h>
 #include <sof/audio/pipeline.h>
 #include <sof/audio/buffer.h>
@@ -366,6 +367,134 @@ int ipc_comp_dai_config(struct ipc *ipc, struct sof_ipc_dai_config *config)
 	return ret;
 }
 
+#ifdef CONFIG_HOST_PTABLE
+/*
+ * Parse the host page tables and create the audio DMA SG configuration
+ * for host audio DMA buffer. This involves creating a dma_sg_elem for each
+ * page table entry and adding each elem to a list in struct dma_sg_config.
+ */
+int ipc_parse_page_descriptors(uint8_t *page_table,
+			       struct sof_ipc_host_buffer *ring,
+			       struct list_item *elem_list,
+			       uint32_t direction)
+{
+	int i;
+	uint32_t idx;
+	uint32_t phy_addr;
+	struct dma_sg_elem *e;
+
+	/* the ring size may be not multiple of the page size, the last
+	 * page may be not full used. The used size should be in range
+	 * of (ring->pages - 1, ring->pages] * PAGES.
+	 */
+	if ((ring->size <= HOST_PAGE_SIZE * (ring->pages - 1)) ||
+	    (ring->size > HOST_PAGE_SIZE * ring->pages)) {
+		/* error buffer size */
+		trace_ipc_error("eBs");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ring->pages; i++) {
+		idx = (((i << 2) + i)) >> 1;
+		phy_addr = page_table[idx] | (page_table[idx + 1] << 8)
+				| (page_table[idx + 2] << 16);
+
+		if (i & 0x1)
+			phy_addr <<= 8;
+		else
+			phy_addr <<= 12;
+		phy_addr &= 0xfffff000;
+
+		/* allocate new host DMA elem and add it to our list */
+		e = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, sizeof(*e));
+		if (!e)
+			return -ENOMEM;
+
+		if (direction == SOF_IPC_STREAM_PLAYBACK)
+			e->src = phy_addr;
+		else
+			e->dest = phy_addr;
+
+		/* the last page may be not full used */
+		if (i == (ring->pages - 1))
+			e->size = ring->size - HOST_PAGE_SIZE * i;
+		else
+			e->size = HOST_PAGE_SIZE;
+
+		list_item_append(&e->list, elem_list);
+	}
+
+	return 0;
+}
+
+static void dma_complete(void *data, uint32_t type, struct dma_sg_elem *next)
+{
+	completion_t *complete = data;
+
+	if (type == DMA_IRQ_TYPE_LLIST)
+		wait_completed(complete);
+}
+
+/*
+ * Copy the audio buffer page tables from the host to the DSP max of 4K.
+ */
+int ipc_get_page_descriptors(struct dma *dmac, uint8_t *page_table,
+			     struct sof_ipc_host_buffer *ring)
+{
+	struct dma_sg_config config;
+	struct dma_sg_elem elem;
+	completion_t complete;
+	int chan;
+	int ret = 0;
+
+	/* get DMA channel from DMAC */
+	chan = dma_channel_get(dmac, 0);
+	if (chan < 0) {
+		trace_ipc_error("ePC");
+		return chan;
+	}
+
+	/* set up DMA configuration */
+	config.direction = DMA_DIR_HMEM_TO_LMEM;
+	config.src_width = sizeof(uint32_t);
+	config.dest_width = sizeof(uint32_t);
+	config.cyclic = 0;
+	list_init(&config.elem_list);
+
+	/* set up DMA descriptor */
+	elem.dest = (uint32_t)page_table;
+	elem.src = ring->phy_addr;
+
+	/* source buffer size is always PAGE_SIZE bytes */
+	/* 20 bits for each page, round up to 32 */
+	elem.size = (ring->pages * 5 * 16 + 31) / 32;
+	list_item_prepend(&elem.list, &config.elem_list);
+
+	ret = dma_set_config(dmac, chan, &config);
+	if (ret < 0) {
+		trace_ipc_error("ePs");
+		goto out;
+	}
+
+	/* set up callback */
+	dma_set_cb(dmac, chan, DMA_IRQ_TYPE_LLIST, dma_complete, &complete);
+
+	wait_init(&complete);
+
+	/* start the copy of page table to DSP */
+	dma_start(dmac, chan);
+
+	/* wait for DMA to complete */
+	complete.timeout = PLATFORM_HOST_DMA_TIMEOUT;
+	ret = wait_for_completion_timeout(&complete);
+
+	/* compressed page tables now in buffer at _ipc->page_table */
+out:
+	dma_channel_put(dmac, chan);
+	return ret;
+}
+#endif
+
 int ipc_init(struct sof *sof)
 {
 	int i;
-- 
2.14.1



More information about the Sound-open-firmware mailing list