Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/drivers/intel/hda/hda-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <sof/lib/dma.h>
#include <sof/lib/pm_runtime.h>
#include <sof/lib/notifier.h>
#include <sof/lib/wait.h>
#include <sof/platform.h>
#include <sof/schedule/schedule.h>
#include <sof/spinlock.h>
Expand Down Expand Up @@ -147,6 +148,9 @@ DECLARE_TR_CTX(hdma_tr, SOF_UUID(hda_dma_uuid), LOG_LEVEL_INFO);
/* DMA host transfer timeout in microseconds */
#define HDA_DMA_TIMEOUT 200

/* DMA idle timeout in microseconds */
#define HDA_DMA_IDLE_TIMEOUT_US 50

/* DMA number of buffer periods */
#define HDA_DMA_BUFFER_PERIOD_COUNT 2

Expand Down Expand Up @@ -646,7 +650,8 @@ static int hda_dma_release(struct dma_chan_data *channel)
static int hda_dma_stop_common(struct dma_chan_data *channel)
{
struct hda_chan_data *hda_chan;
uint32_t flags, dgcs;
uint32_t flags;
int ret;

irq_local_disable(flags);

Expand All @@ -667,14 +672,16 @@ static int hda_dma_stop_common(struct dma_chan_data *channel)
dma_chan_reg_update_bits(channel, DGCS, DGCS_GEN, 0);
}

/* check if channel is idle. No need to wait after clearing the GEN bit */
dgcs = dma_chan_reg_read(channel, DGCS);
if (dgcs & DGCS_GBUSY) {
/* check with timeout if channel is idle */
ret = poll_for_register_delay(dma_chan_base(channel->dma, channel->index) + DGCS,
DGCS_GBUSY, 0, HDA_DMA_IDLE_TIMEOUT_US);
if (ret < 0) {
tr_err(&hdma_tr, "hda-dmac: %d channel %d not idle after stop",
channel->dma->plat_data.id, channel->index);
irq_local_enable(flags);
return -EBUSY;
return ret;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the addition of a wait seems ok, but this is done in code where interrupts are disabled. Isn't that creating a bigger problem?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that is a good point but we have a similar polling with interrutps disabled in

ret = poll_for_register_delay(dma_base(dma) +

Not sayng that code is right, just saying that we have precedence for doing something similar

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ranj063 this change will be fine with @lyakh trigger STOP update. We will also need to make sure it works with DW DMA as above. @lyakh fyi it looks like DW DMA has a 1.5ms poll delay which may mean we need to have a delayed stop (like early BCLK) where we use the LL scheduler ticks to wait on the DW DMA event.

channel->status = COMP_STATE_PREPARE;
hda_chan = dma_chan_get_data(channel);
hda_chan->state = 0;
Expand Down