Allow users outside of IPC to make use of compressed host page tables.
Signed-off-by: Liam Girdwood liam.r.girdwood@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, ¶ms->buffer); + err = ipc_get_page_descriptors(iipc->dmac, iipc->page_table, + ¶ms->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, ¶ms->buffer, - &elem_list, SOF_IPC_STREAM_CAPTURE); + err = ipc_parse_page_descriptors(iipc->page_table, ¶ms->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;