AudioDxe: Fallback to LPIB register when DMA positions buffer is unusable

This commit is contained in:
Goldfish64 2020-06-06 20:20:33 -05:00
parent 97ff599250
commit b0087a6b9a
3 changed files with 61 additions and 2 deletions

View File

@ -63,10 +63,51 @@ HdaControllerStreamOutputPollTimerHandler (
return;
}
if (HdaStream->UseLpib) {
//
// Get stream position through LPIB register.
//
Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthFifoUint32, PCI_HDA_BAR, HDA_REG_SDNLPIB (HdaStream->Index), 1, &HdaStreamDmaPos);
if (EFI_ERROR (Status)) {
HdaControllerStreamAbort (HdaStream);
return;
}
} else {
//
// Get stream position through DMA positions buffer.
//
HdaStreamDmaPos = HdaStream->HdaDev->DmaPositions[HdaStream->Index].Position;
//
// If zero, give the stream a few cycles to catch up before falling back to LPIB.
// Fallback occurs after the set amount of cycles the DMA position is zero.
//
if (HdaStreamDmaPos == 0 && !HdaStream->DmaCheckComplete) {
if (HdaStream->DmaCheckCount >= HDA_STREAM_DMA_CHECK_THRESH) {
HdaStream->UseLpib = TRUE;
}
//
// Get stream position through LPIB register in the meantime.
//
DEBUG ((DEBUG_VERBOSE, "AudioDxe: Falling back to LPIB after %u more tries!\n", HDA_STREAM_DMA_CHECK_THRESH - HdaStream->DmaCheckCount));
Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthFifoUint32, PCI_HDA_BAR, HDA_REG_SDNLPIB (HdaStream->Index), 1, &HdaStreamDmaPos);
if (EFI_ERROR (Status)) {
HdaControllerStreamAbort (HdaStream);
return;
}
}
}
//
// Get stream DMA position.
// Increment cycle counter. Once complete, store status to avoid false fallbacks later on.
//
HdaStreamDmaPos = HdaStream->HdaDev->DmaPositions[HdaStream->Index].Position;
if (HdaStream->DmaCheckCount < HDA_STREAM_DMA_CHECK_THRESH) {
HdaStream->DmaCheckCount++;
} else {
HdaStream->DmaCheckComplete = TRUE;
}
if (HdaStreamDmaPos >= HdaStream->DmaPositionLast) {
DmaChanged = HdaStreamDmaPos - HdaStream->DmaPositionLast;
} else {

View File

@ -111,6 +111,8 @@ typedef struct {
#define HDA_STREAM_POLL_TIME (EFI_TIMER_PERIOD_MILLISECONDS(1))
#define HDA_STREAM_BUFFER_PADDING 0x200 // 512 byte pad.
#define HDA_STREAM_DMA_CHECK_THRESH 5
//
// DMA position structure.
//
@ -148,6 +150,19 @@ typedef struct {
//
BOOLEAN IsBidirectional;
//
// Use LPIB register instead of DMA position buffer.
//
BOOLEAN UseLpib;
//
// Count of times DMA position buffer usability is checked.
//
UINT32 DmaCheckCount;
//
// Indicates whether DMA position buffer usability is complete.
// Ensures we don't accidentally fallback to LPIB if the stream position happens to be zero later on.
//
BOOLEAN DmaCheckComplete;
//
// Buffer Descriptor List.
//
HDA_BDL_ENTRY *BufferList;

View File

@ -584,6 +584,9 @@ HdaControllerResetStream (
HdaStream->DmaPositionTotal = 0;
HdaStream->DmaPositionLast = 0;
HdaStream->DmaPositionChangedMax = 0;
HdaStream->UseLpib = TRUE; // TODO: Allow being forced by NVRAM variable?
HdaStream->DmaCheckCount = 0;
HdaStream->DmaCheckComplete = FALSE;
return TRUE;
}