diff --git a/src/trace/dma-trace.c b/src/trace/dma-trace.c index 5bd09877d405..7da18d087b80 100644 --- a/src/trace/dma-trace.c +++ b/src/trace/dma-trace.c @@ -218,35 +218,69 @@ int dma_trace_host_buffer(struct dma_trace_data *d, } #endif -static int dma_trace_buffer_init(struct dma_trace_data *d) +static void dma_trace_buffer_init(struct dma_trace_data *d, void *new_buffer) { struct dma_trace_buf *buffer = &d->dmatb; - void *buf; unsigned int flags; - /* allocate new buffer */ - buf = rballoc(0, SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, - DMA_TRACE_LOCAL_SIZE); - if (!buf) { - tr_err(&dt_tr, "dma_trace_buffer_init(): alloc failed"); - return -ENOMEM; - } - - bzero(buf, DMA_TRACE_LOCAL_SIZE); - dcache_writeback_region(buf, DMA_TRACE_LOCAL_SIZE); - - /* initialise the DMA buffer, whole sequence in section */ spin_lock_irq(&d->lock, flags); - buffer->addr = buf; buffer->size = DMA_TRACE_LOCAL_SIZE; + if (new_buffer) { + buffer->addr = new_buffer; + buffer->end_addr = (char *)buffer->addr + buffer->size; + } buffer->w_ptr = buffer->addr; buffer->r_ptr = buffer->addr; - buffer->end_addr = (char *)buffer->addr + buffer->size; buffer->avail = 0; + bzero(buffer->addr, buffer->size); + dcache_writeback_region(buffer->addr, buffer->size); + + d->old_host_offset = 0; + d->posn.host_offset = 0; + spin_unlock_irq(&d->lock, flags); + /* It should be the very first sent log for easy identification. */ + mtrace_printf(LOG_LEVEL_INFO, + "SHM: FW ABI 0x%x DBG ABI 0x%x tag " SOF_GIT_TAG " src hash 0x%08x (ldc hash " + META_QUOTE(SOF_SRC_HASH) ")", + SOF_ABI_VERSION, SOF_ABI_DBG_VERSION, SOF_SRC_HASH); + + /* Use a different, DMA: prefix to ease identification of log files */ + tr_info(&dt_tr, + "DMA: FW ABI 0x%x DBG ABI 0x%x tag " SOF_GIT_TAG " src hash 0x%08x (ldc hash " + META_QUOTE(SOF_SRC_HASH) ")", + SOF_ABI_VERSION, SOF_ABI_DBG_VERSION, SOF_SRC_HASH); +} + +static int dma_trace_buffer_alloc(struct dma_trace_data *d) +{ + void *buf; + + /* + * Keep the existing dtrace buffer to avoid memory leak, unlikely to + * happen if host correctly using the dma_trace_disable(). + * + * The buffer can not be freed up here as it is likely in use. + * The (re-)initialization will happen in dma_trace_start() when it is + * safe to do (the DMA is stopped) + */ + if (dma_trace_initialized(d)) + return 0; + + /* allocate new buffer */ + buf = rballoc(0, SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, + DMA_TRACE_LOCAL_SIZE); + if (!buf) { + mtrace_printf(LOG_LEVEL_ERROR, "dma_trace_buffer_alloc(): alloc failed"); + return -ENOMEM; + } + + /* Initialize the dma trace buffer */ + dma_trace_buffer_init(d, buf); + return 0; } @@ -284,6 +318,7 @@ static int dma_trace_start(struct dma_trace_data *d) "dma_trace_start(): DMA reconfiguration (active stream_tag: %u)", d->active_stream_tag); + schedule_task_cancel(&d->dmat_work); err = dma_stop(d->dc.chan); if (err < 0) { mtrace_printf(LOG_LEVEL_ERROR, @@ -298,6 +333,9 @@ static int dma_trace_start(struct dma_trace_data *d) d->dc.chan = NULL; err = dma_copy_set_stream_tag(&d->dc, d->stream_tag); } + + /* Re-initialize the dtrace buffer */ + dma_trace_buffer_init(d, NULL); } else { err = dma_copy_set_stream_tag(&d->dc, d->stream_tag); } @@ -407,25 +445,10 @@ int dma_trace_enable(struct dma_trace_data *d) { int err; - /* initialize dma trace buffer */ - err = dma_trace_buffer_init(d); - - if (err < 0) { - mtrace_printf(LOG_LEVEL_ERROR, "dma_trace_enable: buffer_init failed"); - goto out; - } - - /* It should be the very first sent log for easy identification. */ - mtrace_printf(LOG_LEVEL_INFO, - "SHM: FW ABI 0x%x DBG ABI 0x%x tag " SOF_GIT_TAG " src hash 0x%08x (ldc hash " - META_QUOTE(SOF_SRC_HASH) ")", - SOF_ABI_VERSION, SOF_ABI_DBG_VERSION, SOF_SRC_HASH); - - /* Use a different, DMA: prefix to ease identification of log files */ - tr_info(&dt_tr, - "DMA: FW ABI 0x%x DBG ABI 0x%x tag " SOF_GIT_TAG " src hash 0x%08x (ldc hash " - META_QUOTE(SOF_SRC_HASH) ")", - SOF_ABI_VERSION, SOF_ABI_DBG_VERSION, SOF_SRC_HASH); + /* Allocate and initialize the dma trace buffer if needed */ + err = dma_trace_buffer_alloc(d); + if (err < 0) + return err; #if CONFIG_DMA_GW /*