From ec95d571da791a297995ec5be072a92750464ab8 Mon Sep 17 00:00:00 2001 From: kettenis Date: Fri, 17 May 2024 19:43:45 +0000 Subject: [PATCH] The INTSTS register is read-only, so the attempt to clear interrupts by writing to it doesn't actually work. Therefore we have to keep processing interrupts until all the bits corresponding to enabled interrupts are cleared. This makes MSIs actually work, also on the AMD implementations for which we currently disable MSIs. Based on some digging by martijn@ ok ratchov@, martijn@, stsp@ --- sys/dev/pci/azalia.c | 68 +++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c index 4dc1a6c3e8a..b23a01aba97 100644 --- a/sys/dev/pci/azalia.c +++ b/sys/dev/pci/azalia.c @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.c,v 1.286 2024/03/06 00:11:25 jsg Exp $ */ +/* $OpenBSD: azalia.c,v 1.287 2024/05/17 19:43:45 kettenis Exp $ */ /* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */ /*- @@ -176,6 +176,7 @@ typedef struct azalia_t { int nistreams, nostreams, nbstreams; stream_t pstream; stream_t rstream; + uint32_t intctl; } azalia_t; #define XNAME(sc) ((sc)->dev.dv_xname) #define AZ_READ_1(z, r) bus_space_read_1((z)->iot, (z)->ioh, HDA_##r) @@ -556,16 +557,6 @@ azalia_pci_attach(struct device *parent, struct device *self, void *aux) azalia_pci_write(sc->pc, sc->tag, ICH_PCI_MMC, reg); } - /* disable MSI for AMD Summit Ridge/Raven Ridge HD Audio */ - if (PCI_VENDOR(sc->pciid) == PCI_VENDOR_AMD) { - switch (PCI_PRODUCT(sc->pciid)) { - case PCI_PRODUCT_AMD_17_HDA: - case PCI_PRODUCT_AMD_17_1X_HDA: - case PCI_PRODUCT_AMD_HUDSON2_HDA: - pa->pa_flags &= ~PCI_FLAGS_MSI_ENABLED; - } - } - /* interrupt */ if (pci_intr_map_msi(pa, &ih) && pci_intr_map(pa, &ih)) { printf(": can't map interrupt\n"); @@ -684,7 +675,6 @@ azalia_pci_detach(struct device *self, int flags) AZ_WRITE_4(az, INTCTL, 0); DPRINTF(("%s: clear interrupts\n", __func__)); - AZ_WRITE_4(az, INTSTS, HDA_INTSTS_CIS | HDA_INTSTS_GIS); AZ_WRITE_2(az, STATESTS, HDA_STATESTS_SDIWAKE); AZ_WRITE_1(az, RIRBSTS, HDA_RIRBSTS_RINTFL | HDA_RIRBSTS_RIRBOIS); } @@ -711,29 +701,27 @@ azalia_intr(void *v) int ret = 0; mtx_enter(&audio_lock); - intsts = AZ_READ_4(az, INTSTS); - if (intsts == 0 || intsts == 0xffffffff) { - mtx_leave(&audio_lock); - return (ret); - } - - AZ_WRITE_4(az, INTSTS, intsts); + for (;;) { + intsts = AZ_READ_4(az, INTSTS); + if ((intsts & az->intctl) == 0 || intsts == 0xffffffff) + break; - if (intsts & az->pstream.intr_bit) { - azalia_stream_intr(&az->pstream); - ret = 1; - } + if (intsts & az->pstream.intr_bit) { + azalia_stream_intr(&az->pstream); + ret = 1; + } - if (intsts & az->rstream.intr_bit) { - azalia_stream_intr(&az->rstream); - ret = 1; - } + if (intsts & az->rstream.intr_bit) { + azalia_stream_intr(&az->rstream); + ret = 1; + } - if ((intsts & HDA_INTSTS_CIS) && - (AZ_READ_1(az, RIRBCTL) & HDA_RIRBCTL_RINTCTL) && - (AZ_READ_1(az, RIRBSTS) & HDA_RIRBSTS_RINTFL)) { - azalia_rirb_intr(az); - ret = 1; + if ((intsts & HDA_INTSTS_CIS) && + (AZ_READ_1(az, RIRBCTL) & HDA_RIRBCTL_RINTCTL) && + (AZ_READ_1(az, RIRBSTS) & HDA_RIRBSTS_RINTFL)) { + azalia_rirb_intr(az); + ret = 1; + } } mtx_leave(&audio_lock); return (ret); @@ -918,7 +906,6 @@ azalia_init(azalia_t *az, int resuming) /* clear interrupt status */ AZ_WRITE_2(az, STATESTS, HDA_STATESTS_SDIWAKE); AZ_WRITE_1(az, RIRBSTS, HDA_RIRBSTS_RINTFL | HDA_RIRBSTS_RIRBOIS); - AZ_WRITE_4(az, INTSTS, HDA_INTSTS_CIS | HDA_INTSTS_GIS); AZ_WRITE_4(az, DPLBASE, 0); AZ_WRITE_4(az, DPUBASE, 0); @@ -932,8 +919,8 @@ azalia_init(azalia_t *az, int resuming) if (err) return(err); - AZ_WRITE_4(az, INTCTL, - AZ_READ_4(az, INTCTL) | HDA_INTCTL_CIE | HDA_INTCTL_GIE); + az->intctl = HDA_INTCTL_CIE | HDA_INTCTL_GIE; + AZ_WRITE_4(az, INTCTL, az->intctl); return(0); } @@ -1421,7 +1408,6 @@ azalia_suspend(azalia_t *az) /* stop interrupts and clear status registers */ AZ_WRITE_4(az, INTCTL, 0); - AZ_WRITE_4(az, INTSTS, HDA_INTSTS_CIS | HDA_INTSTS_GIS); AZ_WRITE_2(az, STATESTS, HDA_STATESTS_SDIWAKE); AZ_WRITE_1(az, RIRBSTS, HDA_RIRBSTS_RINTFL | HDA_RIRBSTS_RIRBOIS); @@ -3723,7 +3709,6 @@ azalia_stream_start(stream_t *this) bdlist_entry_t *bdlist; bus_addr_t dmaaddr, dmaend; int err, index; - uint32_t intctl; uint8_t ctl2; err = azalia_stream_reset(this); @@ -3768,9 +3753,8 @@ azalia_stream_start(stream_t *this) if (err) return EINVAL; - intctl = AZ_READ_4(this->az, INTCTL); - intctl |= this->intr_bit; - AZ_WRITE_4(this->az, INTCTL, intctl); + this->az->intctl |= this->intr_bit; + AZ_WRITE_4(this->az, INTCTL, this->az->intctl); STR_WRITE_1(this, CTL, STR_READ_1(this, CTL) | HDA_SD_CTL_DEIE | HDA_SD_CTL_FEIE | HDA_SD_CTL_IOCE | @@ -3786,8 +3770,8 @@ azalia_stream_halt(stream_t *this) ctl = STR_READ_2(this, CTL); ctl &= ~(HDA_SD_CTL_DEIE | HDA_SD_CTL_FEIE | HDA_SD_CTL_IOCE | HDA_SD_CTL_RUN); STR_WRITE_2(this, CTL, ctl); - AZ_WRITE_4(this->az, INTCTL, - AZ_READ_4(this->az, INTCTL) & ~this->intr_bit); + this->az->intctl &= ~this->intr_bit; + AZ_WRITE_4(this->az, INTCTL, this->az->intctl); azalia_codec_disconnect_stream(this); return (0); -- 2.20.1