HDA problems in Qemu
Posted: Thu Dec 30, 2021 3:45 pm
I've got a simple HDA driver going inside Qemu, it can play sound now but needs the following workarounds:
1. To get the CORB DMA to run, I have to set RINTCNT (BAR0 + 0x5A) to a large value. If I leave it at its reset value of 0, the CORB DMA doesn't run at all and its read ptr always reads out as 0.
I saw the following check in Qemu code which prevents CORB DMA from doing anything if RINTCNT is 0 (d->rirb_cnt in this code is RINTCNT)
This looks like a nice way to prevent any RIRB overrun and lost responses, but I didn't find anything in the spec that says RINTCNT must be set to non zero value for the CORB DMA to run. I'm not using interrupts from the controller and my reading of the spec is that this value should not affect CORB DMA operation in this case.
2. Spec says that to reset a stream, this sequence is needed:
a. set reset bit
b. read until it is set
c. clear reset bit
d. read until it is clear
But Qemu clears the reset bit right away on setting, thus causing step b above to hang:
That said, the above code snippets have been in Qemu for many years, and mainstream OSes don't seem to have any issue with HDA in Qemu. Thus I probably missed something.
Could anyone help point out what I might have missed or did you have to apply similar workarounds for HDA to work in Qemu?
1. To get the CORB DMA to run, I have to set RINTCNT (BAR0 + 0x5A) to a large value. If I leave it at its reset value of 0, the CORB DMA doesn't run at all and its read ptr always reads out as 0.
I saw the following check in Qemu code which prevents CORB DMA from doing anything if RINTCNT is 0 (d->rirb_cnt in this code is RINTCNT)
Code: Select all
if (d->rirb_count == d->rirb_cnt) {
dprint(d, 2, "%s: rirb count reached\n", __func__);
return;
}
2. Spec says that to reset a stream, this sequence is needed:
a. set reset bit
b. read until it is set
c. clear reset bit
d. read until it is clear
But Qemu clears the reset bit right away on setting, thus causing step b above to hang:
Code: Select all
if (st->ctl & 0x01) {
/* reset */
dprint(d, 1, "st #%d: reset\n", reg->stream);
st->ctl = SD_STS_FIFO_READY << 24;
}
Could anyone help point out what I might have missed or did you have to apply similar workarounds for HDA to work in Qemu?