[Sound-open-firmware] [RFC PATCH v2 0/5] APL/CNL: Enable DMA trace on APL/CNL.
From: Yan Wang yan.wang@linux.intel.com
This patch set is only for initial review and trying. It can work fine on my CNL platform. I also tested on BYT MB, It doesn't cause regression.
Yan Wang (5): APL/CNL: Add stream_tag variable for saving parameter from kernel driver. APL/CNL: Implement host DMA copy in existed DMA copy API. APL/CNL: Save stream tag and host buffer size from kernel driver. APL/CNL: Implement host DMA setting and position update on APL/CNL. APL/CNL: Initialize DMA trace data structure and definition on APL/CNL.
src/include/reef/dma-trace.h | 1 + src/include/reef/dma.h | 2 + src/include/uapi/ipc.h | 1 + src/ipc/dma-copy.c | 44 ++++++++++++- src/ipc/intel-ipc.c | 8 ++- src/lib/dma-trace.c | 77 ++++++++++++++++++++++ .../apollolake/include/platform/platform.h | 2 +- src/platform/apollolake/platform.c | 3 + .../cannonlake/include/platform/platform.h | 2 +- src/platform/cannonlake/platform.c | 3 + 10 files changed, 139 insertions(+), 4 deletions(-)
From: Yan Wang yan.wang@linux.intel.com
Add stream_tag variable for IPC message and DMA trace data structure.
Signed-off-by: Yan Wang yan.wang@linux.intel.com --- src/include/reef/dma-trace.h | 1 + src/include/uapi/ipc.h | 1 + 2 files changed, 2 insertions(+)
diff --git a/src/include/reef/dma-trace.h b/src/include/reef/dma-trace.h index dcbd491..f17ffe5 100644 --- a/src/include/reef/dma-trace.h +++ b/src/include/reef/dma-trace.h @@ -63,6 +63,7 @@ struct dma_trace_data { struct work dmat_work; uint32_t enabled; uint32_t copy_in_progress; + uint32_t stream_tag; spinlock_t lock; };
diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h index 0c34013..e44a13f 100644 --- a/src/include/uapi/ipc.h +++ b/src/include/uapi/ipc.h @@ -839,6 +839,7 @@ struct sof_ipc_window { struct sof_ipc_dma_trace_params { struct sof_ipc_hdr hdr; struct sof_ipc_host_buffer buffer; + uint32_t stream_tag; } __attribute__((packed));
/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */
From: Yan Wang yan.wang@linux.intel.com
Get DMA channel based on stream tag when use host DMA. Need also call different API in dma_copy_to_host_nowait().
Signed-off-by: Yan Wang yan.wang@linux.intel.com --- src/include/reef/dma.h | 2 ++ src/ipc/dma-copy.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/src/include/reef/dma.h b/src/include/reef/dma.h index 247bcbf..f137bf5 100644 --- a/src/include/reef/dma.h +++ b/src/include/reef/dma.h @@ -278,4 +278,6 @@ int dma_copy_to_host(struct dma_copy *dc, struct dma_sg_config *host_sg, int dma_copy_to_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg, int32_t host_offset, void *local_ptr, int32_t size);
+int dma_copy_set_stream_tag(struct dma_copy *dc, uint32_t stream_tag); + #endif diff --git a/src/ipc/dma-copy.c b/src/ipc/dma-copy.c index 06f05d5..3c07356 100644 --- a/src/ipc/dma-copy.c +++ b/src/ipc/dma-copy.c @@ -70,6 +70,8 @@ static struct dma_sg_elem *sg_get_elem_at(struct dma_sg_config *host_sg, return NULL; }
+#if !defined CONFIG_DMA_GW + static void dma_complete(void *data, uint32_t type, struct dma_sg_elem *next) { completion_t *comp = (completion_t *)data; @@ -84,6 +86,8 @@ static void dma_complete(void *data, uint32_t type, struct dma_sg_elem *next) next->size = DMA_RELOAD_END; }
+#endif + /* Copy DSP memory to host memory. * copies DSP memory to host in PAGE_SIZE or smaller blocks and waits/sleeps * between blocks. Can't be used in IRQ context. @@ -172,8 +176,26 @@ int dma_copy_to_host(struct dma_copy *dc, struct dma_sg_config *host_sg, * Copies DSP memory to host in a single PAGE_SIZE or smaller block. Does not * waits/sleeps and can be used in IRQ context. */ +#if defined CONFIG_DMA_GW + int dma_copy_to_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg, - int32_t host_offset, void *local_ptr, int32_t size) + int32_t host_offset, void *local_ptr, int32_t size) +{ + int ret; + + /* tell gateway to copy */ + ret = dma_copy(dc->dmac, dc->chan, size); + if (ret < 0) + return ret; + + /* bytes copied */ + return size; +} + +#else + +int dma_copy_to_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg, + int32_t host_offset, void *local_ptr, int32_t size) { struct dma_sg_config config; struct dma_sg_elem *host_sg_elem; @@ -219,6 +241,8 @@ int dma_copy_to_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg, return local_sg_elem.size; }
+#endif + /* Copy host memory to DSP memory. * Copies host memory to host in PAGE_SIZE or smaller blocks and waits/sleeps * between blocks. Cant be used in IRQ context. @@ -359,6 +383,7 @@ int dma_copy_new(struct dma_copy *dc, int dmac) return -ENODEV; }
+#if !defined CONFIG_DMA_GW /* get DMA channel from DMAC0 */ dc->chan = dma_channel_get(dc->dmac, 0); if (dc->chan < 0) { @@ -369,6 +394,23 @@ int dma_copy_new(struct dma_copy *dc, int dmac) dc->complete.timeout = 100; /* wait 100 usecs for DMA to finish */ dma_set_cb(dc->dmac, dc->chan, DMA_IRQ_TYPE_LLIST, dma_complete, &dc->complete); +#endif + + return 0; +} + +#if defined CONFIG_DMA_GW + +int dma_copy_set_stream_tag(struct dma_copy *dc, uint32_t stream_tag) +{ + /* get DMA channel from DMAC */ + dc->chan = dma_channel_get(dc->dmac, stream_tag - 1); + if (dc->chan < 0) { + trace_dma_error("ec1"); + return -EINVAL; + } + return 0; }
+#endif
From: Yan Wang yan.wang@linux.intel.com
It is necessary to save stream tag and host buffer size for host DMA setting.
Signed-off-by: Yan Wang yan.wang@linux.intel.com --- src/ipc/intel-ipc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/ipc/intel-ipc.c b/src/ipc/intel-ipc.c index ffc6f29..8263fff 100644 --- a/src/ipc/intel-ipc.c +++ b/src/ipc/intel-ipc.c @@ -640,12 +640,12 @@ static int ipc_dma_trace_config(uint32_t header) { #ifdef CONFIG_HOST_PTABLE struct intel_ipc_data *iipc = ipc_get_drvdata(_ipc); - struct sof_ipc_dma_trace_params *params = _ipc->comp_data; struct list_item elem_list; struct dma_sg_elem *elem; struct list_item *plist; uint32_t ring_size; #endif + struct sof_ipc_dma_trace_params *params = _ipc->comp_data; struct sof_ipc_reply reply; int err;
@@ -683,6 +683,12 @@ static int ipc_dma_trace_config(uint32_t header) list_item_del(&elem->list); rfree(elem); } +#else + /* stream tag of capture stream for DMA trace */ + _ipc->dmat->stream_tag = params->stream_tag; + + /* host buffer size for DMA trace */ + _ipc->dmat->host_size = params->buffer.size; #endif trace_ipc("DAp");
From: Yan Wang yan.wang@linux.intel.com
The host DMA has the different config method: 1. Get DMA channel based on stream tag. 2. Prepare DMA elem list based on local DMA trace buffer which make sure that one trace record data can be transferred at least. 3. Need start DMA on firmware side before trigger start on kernel side. 4. Because no DMA callback in host DMA, add position update calling at the end of trace_work().
Signed-off-by: Yan Wang yan.wang@linux.intel.com --- src/lib/dma-trace.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+)
diff --git a/src/lib/dma-trace.c b/src/lib/dma-trace.c index b08e7fb..1ff2bd4 100644 --- a/src/lib/dma-trace.c +++ b/src/lib/dma-trace.c @@ -120,6 +120,14 @@ out:
spin_unlock_irq(&d->lock, flags);
+#if defined CONFIG_DMA_GW + /* + * there isn't DMA completion callback in GW DMA copying + * so we send position IPC message after DMA copying API calling + */ + ipc_dma_trace_send_position(); +#endif + /* reschedule the trace copying work */ return DMA_TRACE_PERIOD; } @@ -195,8 +203,77 @@ int dma_trace_host_buffer(struct dma_trace_data *d, struct dma_sg_elem *elem, return 0; }
+#if defined CONFIG_DMA_GW + +static int dma_trace_start(struct dma_trace_data *d) +{ + struct dma_sg_config config; + struct dma_sg_elem *e; + uint32_t elem_size, elem_addr, elem_num; + int err = 0; + int i; + + err = dma_copy_set_stream_tag(&d->dc, d->stream_tag); + if (err < 0) + return err; + + /* size of every trace record */ + elem_size = sizeof(uint64_t) * 2; + + /* Initialize address of local elem */ + elem_addr = (uint32_t)d->dmatb.addr; + + /* the number of elem list */ + elem_num = DMA_TRACE_LOCAL_SIZE / elem_size; + + config.direction = DMA_DIR_LMEM_TO_HMEM; + config.src_width = sizeof(uint32_t); + config.dest_width = sizeof(uint32_t); + config.cyclic = 0; + list_init(&config.elem_list); + + /* generate local elem list for local trace buffer */ + e = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, sizeof(*e) * elem_num); + if (!e) + return -ENOMEM; + + for (i = 0; i < elem_num; i++) { + e[i].dest = 0; + e[i].src = elem_addr; + e[i].size = elem_size; /* the minimum size of DMA copy */ + + list_item_append(&e[i].list, &config.elem_list); + elem_addr += elem_size; + } + + err = dma_set_config(d->dc.dmac, d->dc.chan, &config); + if (err < 0) { + rfree(e); + return err; + } + + err = dma_start(d->dc.dmac, d->dc.chan); + + rfree(e); + return err; +} + +#endif + int dma_trace_enable(struct dma_trace_data *d) { +#if defined CONFIG_DMA_GW + int err; + + /* + * GW DMA need finish DMA config and start before + * host driver trigger start DMA + */ + err = dma_trace_start(d); + if (err < 0) + return err; +#endif + /* validate DMA context */ if (d->dc.dmac == NULL || d->dc.chan < 0) { trace_error_atomic(TRACE_CLASS_BUFFER, "eem");
From: Yan Wang yan.wang@linux.intel.com
Add dma_trace_init_complete() calling on APL/CNL platform. And use DMA_HOST_IN_DMAC as PLATFORM_TRACE_DMAC for DMA trace copying.
Signed-off-by: Yan Wang yan.wang@linux.intel.com --- src/platform/apollolake/include/platform/platform.h | 2 +- src/platform/apollolake/platform.c | 3 +++ src/platform/cannonlake/include/platform/platform.h | 2 +- src/platform/cannonlake/platform.c | 3 +++ 4 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/platform/apollolake/include/platform/platform.h b/src/platform/apollolake/include/platform/platform.h index 8a84308..fd2eba6 100644 --- a/src/platform/apollolake/include/platform/platform.h +++ b/src/platform/apollolake/include/platform/platform.h @@ -98,7 +98,7 @@ struct reef; #define DMA_TRACE_RESCHEDULE_TIME 5000
/* DMAC used for trace DMA */ -#define PLATFORM_TRACE_DMAC DMA_ID_DMAC0 +#define PLATFORM_TRACE_DMAC DMA_HOST_IN_DMAC
/* DSP should be idle in this time frame */ #define PLATFORM_IDLE_TIME 750000 diff --git a/src/platform/apollolake/platform.c b/src/platform/apollolake/platform.c index 9574970..84f8e71 100644 --- a/src/platform/apollolake/platform.c +++ b/src/platform/apollolake/platform.c @@ -262,5 +262,8 @@ int platform_init(struct reef *reef) dai_probe(ssp); }
+ /* Initialize DMA for Trace*/ + dma_trace_init_complete(reef->dmat); + return 0; } diff --git a/src/platform/cannonlake/include/platform/platform.h b/src/platform/cannonlake/include/platform/platform.h index 06a5599..feeeb6c 100644 --- a/src/platform/cannonlake/include/platform/platform.h +++ b/src/platform/cannonlake/include/platform/platform.h @@ -102,7 +102,7 @@ struct reef; #define DMA_TRACE_RESCHEDULE_TIME 5000
/* DMAC used for trace DMA */ -#define PLATFORM_TRACE_DMAC DMA_ID_DMAC0 +#define PLATFORM_TRACE_DMAC DMA_HOST_IN_DMAC
/* DSP should be idle in this time frame */ #define PLATFORM_IDLE_TIME 750000 diff --git a/src/platform/cannonlake/platform.c b/src/platform/cannonlake/platform.c index c9449ed..8bf2d7a 100644 --- a/src/platform/cannonlake/platform.c +++ b/src/platform/cannonlake/platform.c @@ -283,5 +283,8 @@ int platform_init(struct reef *reef) dai_probe(ssp); }
+ /* Initialize DMA for Trace*/ + dma_trace_init_complete(reef->dmat); + return 0; }
On Wed, 2018-03-14 at 14:51 +0800, yan.wang@linux.intel.com wrote:
From: Yan Wang yan.wang@linux.intel.com
This patch set is only for initial review and trying. It can work fine on my CNL platform. I also tested on BYT MB, It doesn't cause regression.
Yan Wang (5): APL/CNL: Add stream_tag variable for saving parameter from kernel driver. APL/CNL: Implement host DMA copy in existed DMA copy API. APL/CNL: Save stream tag and host buffer size from kernel driver. APL/CNL: Implement host DMA setting and position update on APL/CNL. APL/CNL: Initialize DMA trace data structure and definition on APL/CNL.
All applied.
Liam
participants (2)
-
Liam Girdwood
-
yan.wang@linux.intel.com