Skip to content

Commit

Permalink
drivers: dma: intel_adsp_hda: fix intel_adsp_hda_unused() check
Browse files Browse the repository at this point in the history
The ringbuffer availability check is subject to race with regards to
update of BF (Buffer Full) and BNE (Buffer Not Empty) bits in DGCS
register, and status of RP (Read Position) and WP (Write Position).

Following sequence is observed without this patch when
calling dma_get_status() on multiple Intel ADSP platforms:

iter 154 pending 1536 RP 768 WP 768, BNE 1, BF 1
-> dma_reload for 384
iter 155 pending 1536 RP 1152 WP 1152, BNE 1, BF 1
-> dma_reload for 384
iter 156 pending 0 RP 0 WP 0, BNE 1, BF 0

Value of pending is not expected to go from 1536 to zero if only 384
bytes have been consumed via dma_reload() since last call to
dma_get_status().

Change the logic to read DGCS register later, after the WP and RP have
been already read, and only check the BNE bit if Read and Write
Positions are equal.

Link: thesofproject/sof#9418
Signed-off-by: Kai Vehmanen <[email protected]>
Co-developed-by: Peter Ujfalusi <[email protected]>
Signed-off-by: Peter Ujfalusi <[email protected]>
  • Loading branch information
kv2019i authored and carlescufi committed Sep 4, 2024
1 parent 0fd7028 commit 81977f2
Showing 1 changed file with 13 additions and 13 deletions.
26 changes: 13 additions & 13 deletions soc/intel/intel_adsp/common/include/intel_adsp_hda.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,24 +273,24 @@ static inline bool intel_adsp_hda_is_enabled(uint32_t base, uint32_t regblock_si
*/
static inline uint32_t intel_adsp_hda_unused(uint32_t base, uint32_t regblock_size, uint32_t sid)
{
uint32_t dgcs = *DGCS(base, regblock_size, sid);
uint32_t dgbs = *DGBS(base, regblock_size, sid);

/* Check if buffer is empty */
if ((dgcs & DGCS_BNE) == 0) {
return dgbs;
}

/* Check if the buffer is full */
if (dgcs & DGCS_BF) {
return 0;
}

int32_t rp = *DGBRP(base, regblock_size, sid);
int32_t wp = *DGBWP(base, regblock_size, sid);
int32_t size = rp - wp;

if (size <= 0) {
if (size == 0) {
uint32_t dgcs = *DGCS(base, regblock_size, sid);

/* Check if buffer is empty */
if ((dgcs & DGCS_BNE) == 0) {
return dgbs;
}

/*
* Buffer is not empty and pointers equal, it can
* only be full, no need to check the DGCS_BF flag
*/
} else if (size < 0) {
size += dgbs;
}

Expand Down

0 comments on commit 81977f2

Please sign in to comment.