diff --git a/src/audio/dai.c b/src/audio/dai.c index bc437939b36e..77c3c880c19f 100644 --- a/src/audio/dai.c +++ b/src/audio/dai.c @@ -683,9 +683,18 @@ static int dai_reset(struct comp_dev *dev) { struct dai_data *dd = comp_get_drvdata(dev); struct dma_sg_config *config = &dd->config; + int ret; comp_info(dev, "dai_reset()"); + if (dd->chan) { + ret = dma_reset(dd->chan); + if (ret < 0) { + comp_err(dev, "dai_reset(): failed to reset DMA chan"); + return ret; + } + } + dai_config_reset(dev); dma_sg_free(&config->elem_array); diff --git a/src/audio/host.c b/src/audio/host.c index 69479d150469..bd1b45771500 100644 --- a/src/audio/host.c +++ b/src/audio/host.c @@ -855,6 +855,13 @@ static int host_reset(struct comp_dev *dev) comp_dbg(dev, "host_reset()"); if (hd->chan) { + int ret = dma_reset(hd->chan); + + if (ret < 0) { + comp_err(dev, "host_reset(): failed to reset DMA chan"); + return ret; + } + /* remove callback */ notifier_unregister(dev, hd->chan, NOTIFIER_ID_DMA_COPY); dma_channel_put(hd->chan); diff --git a/src/drivers/intel/hda/hda-dma.c b/src/drivers/intel/hda/hda-dma.c index 8d3e56b40bb6..591d528a3e69 100644 --- a/src/drivers/intel/hda/hda-dma.c +++ b/src/drivers/intel/hda/hda-dma.c @@ -50,6 +50,7 @@ DECLARE_TR_CTX(hdma_tr, SOF_UUID(hda_dma_uuid), LOG_LEVEL_INFO); #define DGCS_SCS BIT(31) #define DGCS_GEN BIT(26) #define DGCS_FWCB BIT(23) +#define DGCS_GBUSY BIT(15) #define DGCS_BSC BIT(11) /* NOTE: both XRUN bits are the same, just direction is different */ #define DGCS_BOR BIT(10) /* buffer overrun (input streams) */ @@ -522,7 +523,6 @@ static void hda_dma_channel_put(struct dma_chan_data *channel) static int hda_dma_start(struct dma_chan_data *channel) { uint32_t flags; - uint32_t dgcs; int ret = 0; irq_local_disable(flags); @@ -532,13 +532,12 @@ static int hda_dma_start(struct dma_chan_data *channel) hda_dma_dbg_count_reset(channel); - /* is channel idle, disabled and ready ? */ - dgcs = dma_chan_reg_read(channel, DGCS); - if (channel->status != COMP_STATE_PREPARE || (dgcs & DGCS_GEN)) { + /* is channel active? */ + if (channel->status != COMP_STATE_PREPARE) { ret = -EBUSY; - tr_err(&hdma_tr, "hda-dmac: %d channel %d busy. dgcs 0x%x status %d", + tr_err(&hdma_tr, "hda-dmac: %d channel %d status %d", channel->dma->plat_data.id, - channel->index, dgcs, channel->status); + channel->index, channel->status); goto out; } @@ -618,7 +617,7 @@ static int hda_dma_stop(struct dma_chan_data *channel) hda_dma_host_stop(channel); /* disable the channel */ - dma_chan_reg_update_bits(channel, DGCS, DGCS_GEN | DGCS_FIFORDY, 0); + dma_chan_reg_update_bits(channel, DGCS, DGCS_FIFORDY, 0); channel->status = COMP_STATE_PREPARE; hda_chan = dma_chan_get_data(channel); hda_chan->state = 0; @@ -630,6 +629,28 @@ static int hda_dma_stop(struct dma_chan_data *channel) return 0; } +static int hda_dma_reset(struct dma_chan_data *channel) +{ + uint32_t val, flags; + + irq_local_disable(flags); + + /* reset GEN bit */ + dma_chan_reg_update_bits(channel, DGCS, DGCS_GEN, 0); + + val = dma_chan_reg_read(channel, DGCS); + + irq_local_enable(flags); + + /* and verify if channel is idle */ + if (!(val & DGCS_GBUSY)) + return 0; + + tr_err(&hdma_tr, "hda-dmac: %d channel %d busy", channel->dma->plat_data.id, + channel->index); + return -EBUSY; +} + /* fill in "status" with current DMA channel state and position */ static int hda_dma_status(struct dma_chan_data *channel, struct dma_chan_status *status, uint8_t direction) @@ -1004,6 +1025,7 @@ const struct dma_ops hda_link_dma_ops = { .channel_put = hda_dma_channel_put, .start = hda_dma_start, .stop = hda_dma_stop, + .reset = hda_dma_reset, .copy = hda_dma_link_copy, .pause = hda_dma_pause, .release = hda_dma_release, diff --git a/src/include/sof/lib/dma.h b/src/include/sof/lib/dma.h index 43726b52441c..8b08317a1c0e 100644 --- a/src/include/sof/lib/dma.h +++ b/src/include/sof/lib/dma.h @@ -160,6 +160,7 @@ struct dma_ops { int (*start)(struct dma_chan_data *channel); int (*stop)(struct dma_chan_data *channel); + int (*reset)(struct dma_chan_data *channel); int (*copy)(struct dma_chan_data *channel, int bytes, uint32_t flags); int (*pause)(struct dma_chan_data *channel); int (*release)(struct dma_chan_data *channel); @@ -318,6 +319,14 @@ static inline int dma_stop(struct dma_chan_data *channel) return ret; } +static inline int dma_reset(struct dma_chan_data *channel) +{ + if (channel->dma->ops->reset) + return channel->dma->ops->reset(channel); + + return 0; +} + /** \defgroup sof_dma_copy_func static int dma_copy (struct dma_chan_data * channel, int bytes, uint32_t flags) * * This function is in a separate subgroup to solve a name clash with diff --git a/src/include/sof/trace/dma-trace.h b/src/include/sof/trace/dma-trace.h index 53cd8bac2fb8..493d948fa1e3 100644 --- a/src/include/sof/trace/dma-trace.h +++ b/src/include/sof/trace/dma-trace.h @@ -52,6 +52,7 @@ int dma_trace_host_buffer(struct dma_trace_data *d, struct dma_sg_elem_array *elem_array, uint32_t host_size); int dma_trace_enable(struct dma_trace_data *d); +void dma_trace_disable(struct dma_trace_data *d); void dma_trace_flush(void *destination); void dma_trace_on(void); void dma_trace_off(void); diff --git a/src/ipc/ipc3/handler.c b/src/ipc/ipc3/handler.c index a87dd30ef9d7..d7e3d0a3d28d 100644 --- a/src/ipc/ipc3/handler.c +++ b/src/ipc/ipc3/handler.c @@ -602,6 +602,11 @@ static int ipc_pm_context_save(uint32_t header) //struct sof_ipc_pm_ctx *pm_ctx = _ipc->comp_data; tr_info(&ipc_tr, "ipc: pm -> save"); +#if CONFIG_TRACE + struct dma_trace_data *dmat = dma_trace_data_get(); + + dma_trace_disable(dmat); +#endif sa_exit(sof_get()); diff --git a/src/trace/Kconfig b/src/trace/Kconfig index 2e7cdfc2f1e6..f26aabf5cc73 100644 --- a/src/trace/Kconfig +++ b/src/trace/Kconfig @@ -35,14 +35,14 @@ config TRACEM config TRACE_FILTERING bool "Trace filtering" depends on TRACE - default y + default n help Filtering of trace messages based on their verbosity level and frequency. config TRACE_FILTERING_VERBOSITY bool "Filter by verbosity" depends on TRACE_FILTERING - default y + default n help Filtering by log verbosity level, where maximum verbosity allowed is specified for each context and may be adjusted in runtime. @@ -50,7 +50,7 @@ config TRACE_FILTERING_VERBOSITY config TRACE_FILTERING_ADAPTIVE bool "Adaptive rate limiting" depends on TRACE_FILTERING - default y + default n help Adaptive filtering of trace messages, tracking up to CONFIG_TRACE_RECENT_ENTRIES_COUNT, suppressing all repeated messages for up to CONFIG_TRACE_RECENT_TIME_THRESHOLD cycles. diff --git a/src/trace/dma-trace.c b/src/trace/dma-trace.c index e757c1a94fae..f5c77f1deb3a 100644 --- a/src/trace/dma-trace.c +++ b/src/trace/dma-trace.c @@ -420,6 +420,13 @@ int dma_trace_enable(struct dma_trace_data *d) return err; } +void dma_trace_disable(struct dma_trace_data *d) +{ + schedule_task_cancel(&d->dmat_work); + dma_reset(d->dc.chan); + dma_trace_buffer_free(d); +} + /** Sends all pending DMA messages to mailbox (for emergencies) */ void dma_trace_flush(void *t) {