[Sound-open-firmware] [PATCH 3/4] Add the implementation for DMA tracing.
From: Yan Wang yan.wang@linux.intel.com
1. Initialize the data structure. a) Create local DMA buffer for saving trace data. b) Initialize the tracing work handler for syatem work queue. 2. Implement local circle buffer. a) When the local buffer is full, empty it and reset reading/writing pointer. 3. Save the host buffer PHY addr which is parsed from IPC message. After this config, start trace work in work queue. 4. Provide dtrace_event() for recroding trace string into local buffer. 5. Add rstrlen() utility function for getting the trace string length because DSP side hasn't strlen(). 6. Enbale trace DMA copying once every 500ms or some special cases. a) Schedule the tracing sending work once every 500ms. b) If the local buffer is half full, call trace sending immediately. c) When the wrting pointer will arrive iat the end of local buffer, call trace sending immediately. 7. Use dma_copy_to_host() function to do trace sending.
Signed-off-by: Yan Wang yan.wang@linux.intel.com --- src/audio/Makefile.am | 1 + src/audio/dma-trace.c | 194 ++++++++++++++++++++++ src/include/reef/alloc.h | 1 + src/include/reef/audio/dma-trace.h | 69 ++++++++ src/lib/lib.c | 9 + src/platform/baytrail/include/platform/platform.h | 6 + 6 files changed, 280 insertions(+) create mode 100644 src/audio/dma-trace.c create mode 100644 src/include/reef/audio/dma-trace.h
diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am index 285422e..7ffe01f 100644 --- a/src/audio/Makefile.am +++ b/src/audio/Makefile.am @@ -17,6 +17,7 @@ libaudio_a_SOURCES = \ pipeline.c \ pipeline_static.c \ component.c \ + dma-trace.c \ buffer.c
libaudio_a_CFLAGS = \ diff --git a/src/audio/dma-trace.c b/src/audio/dma-trace.c new file mode 100644 index 0000000..8fc220e --- /dev/null +++ b/src/audio/dma-trace.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Yan Wang yan.wang@linux.intel.com + */ + +#include <reef/trace.h> +#include <reef/audio/dma-trace.h> +#include <reef/ipc.h> +#include <reef/reef.h> +#include <reef/alloc.h> +#include <arch/cache.h> +#include <platform/timer.h> +#include <platform/dma.h> +#include <reef/lock.h> +#include <stdint.h> + +static struct dma_trace_data *trace_data = NULL; + +static int dma_trace_new_buffer(struct dma_trace_data *d, uint32_t buffer_size) +{ + struct dma_trace_buf *buffer = &d->dmatb; + + trace_buffer("nlb"); + + /* validate request */ + if (buffer_size == 0 || buffer_size > HEAP_BUFFER_SIZE) { + trace_buffer_error("ebg"); + trace_value(buffer_size); + return -ENOMEM; + } + + /* allocate new buffer */ + buffer->addr = rballoc(RZONE_RUNTIME, RFLAGS_NONE, buffer_size); + if (buffer->addr == NULL) { + trace_buffer_error("ebm"); + return -ENOMEM; + } + + bzero(buffer->addr, buffer_size); + + buffer->size = buffer_size; + buffer->w_ptr = buffer->r_ptr = buffer->addr; + buffer->end_addr = buffer->addr + buffer->size; + + return 0; +} + +static void trace_send(struct dma_trace_data *d) +{ + struct dma_trace_buf *buffer = &d->dmatb; + struct dma_sg_config *config = &d->config; + uint32_t size = 0; + int32_t offset = 0; + + if (buffer->w_ptr == buffer->r_ptr) + return; + + size = buffer->w_ptr - buffer->r_ptr; + if (d->host_offset + size > d->host_size) + d->host_offset = 0; + + offset = dma_copy_to_host(config, d->host_offset, + buffer->r_ptr, size); + if (offset < 0) { + trace_buffer_error("ebb"); + return; + } + + d->host_offset += size; + buffer->r_ptr += size; + + trace_buffer("dts"); +} + +static uint32_t trace_work(void *data, uint32_t delay) +{ + struct dma_trace_data *d = (struct dma_trace_data *)data; + + trace_send(d); + + /* reschedule the trace copying work */ + return DMA_TRACE_US; +} + +int dma_trace_init(struct dma_trace_data *d) +{ + int err; + + trace_buffer("dtn"); + + /* init buffer elems */ + list_init(&d->config.elem_list); + + /* allocate local DMA buffer */ + err = dma_trace_new_buffer(d, DMA_TRACE_LOCAL_SIZE); + if (err < 0) { + trace_buffer_error("ePb"); + return err; + } + + d->host_offset = 0; + trace_data = d; + + work_init(&d->dmat_work, trace_work, d, WORK_ASYNC); + return 0; +} + +int dma_trace_host_buffer(struct dma_trace_data *d, struct dma_sg_elem *elem, + uint32_t host_size) +{ + struct dma_sg_elem *e; + + /* allocate new host DMA elem and add it to our list */ + e = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*e)); + if (e == NULL) + return -ENOMEM; + + *e = *elem; + d->host_size = host_size; + + list_item_append(&e->list, &d->config.elem_list); + return 0; +} + +void dma_trace_config_ready(struct dma_trace_data *d) +{ + work_schedule_default(&d->dmat_work, DMA_TRACE_US); +} + +void dtrace_event(char *e) +{ + struct dma_trace_buf *buffer = NULL; + int length = rstrlen(e); + int margin = 0; + + if (trace_data == NULL || length < 1) { + trace_buffer_error("ele"); + return; + } + + buffer = &trace_data->dmatb; + if (buffer == NULL) { + trace_buffer_error("ele"); + return; + } + + margin = buffer->end_addr - buffer->w_ptr; + + if (margin > length) { + memcpy(buffer->w_ptr, e, length); + buffer->w_ptr += length; + } else { + memcpy(buffer->w_ptr, e, margin); + buffer->w_ptr += margin; + + trace_send(trace_data); + buffer->w_ptr = buffer->r_ptr = buffer->addr; + bzero(buffer->addr, buffer->size); + + memcpy(buffer->w_ptr, e + margin, length - margin); + buffer->w_ptr += length -margin; + + trace_buffer("ebs"); + } + + length = buffer->w_ptr - buffer->r_ptr; + if (length >= (DMA_TRACE_LOCAL_SIZE / 2)) + trace_send(trace_data); +} diff --git a/src/include/reef/alloc.h b/src/include/reef/alloc.h index d263052..a589959 100644 --- a/src/include/reef/alloc.h +++ b/src/include/reef/alloc.h @@ -82,6 +82,7 @@ void rbfree(void *ptr); /* utility */ void bzero(void *s, size_t n); void *memset(void *s, int c, size_t n); +int rstrlen(char *s);
/* Heap save/restore contents and context for PM D0/D3 events */ uint32_t mm_pm_context_size(void); diff --git a/src/include/reef/audio/dma-trace.h b/src/include/reef/audio/dma-trace.h new file mode 100644 index 0000000..9ee88a0 --- /dev/null +++ b/src/include/reef/audio/dma-trace.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Yan Wang yan.wang@linux.intel.com + */ + +#ifndef __INCLUDE_DMA_TRACE__ +#define __INCLUDE_DMA_TRACE__ + +#include <stdint.h> +#include <stdlib.h> +#include <reef/reef.h> +#include <reef/list.h> +#include <reef/mailbox.h> +#include <reef/debug.h> +#include <reef/timer.h> +#include <reef/dma.h> +#include <reef/work.h> +#include <platform/platform.h> +#include <platform/timer.h> + +struct dma_trace_buf { + void *w_ptr; /* buffer write pointer */ + void *r_ptr; /* buffer read position */ + void *addr; /* buffer base address */ + void *end_addr; /* buffer end address */ + uint32_t size; /* size of buffer in bytes */ +}; + +struct dma_trace_data { + struct dma_sg_config config; + struct dma_trace_buf dmatb; + int32_t host_offset; + uint32_t host_size; + struct work dmat_work; +}; + +int dma_trace_init(struct dma_trace_data *d); +int dma_trace_host_buffer(struct dma_trace_data *d, struct dma_sg_elem *elem, + uint32_t host_size); +void dma_trace_config_ready(struct dma_trace_data *d); + +void dtrace_event(char *e); + +#endif diff --git a/src/lib/lib.c b/src/lib/lib.c index d018f5e..764e53b 100644 --- a/src/lib/lib.c +++ b/src/lib/lib.c @@ -89,3 +89,12 @@ void *memset(void *s, int c, size_t n)
return s; } + +/* generic strlen - TODO: can be optimsed for ARCH ? */ +int rstrlen(char *s) +{ + char *p = s; + + while(*p++ != 0); + return (p - s) - 1; +} diff --git a/src/platform/baytrail/include/platform/platform.h b/src/platform/baytrail/include/platform/platform.h index 1ad0a22..ff3a117 100644 --- a/src/platform/baytrail/include/platform/platform.h +++ b/src/platform/baytrail/include/platform/platform.h @@ -76,6 +76,12 @@ struct reef; /* WorkQ window size in microseconds */ #define PLATFORM_WORKQ_WINDOW 2000
+/* local buffer size of DMA tracing */ +#define DMA_TRACE_LOCAL_SIZE HOST_PAGE_SIZE + +/* the interval of DMA trace copying */ +#define DMA_TRACE_US 500000 + /* Platform defined panic code */ #define platform_panic(__x) \ shim_write(SHIM_IPCXL, ((shim_read(SHIM_IPCXL) & 0xc0000000) |\
participants (1)
-
yan.wang@linux.intel.com