From: kettenis Date: Fri, 17 May 2024 19:43:45 +0000 (+0000) Subject: The INTSTS register is read-only, so the attempt to clear interrupts X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=ec95d571da791a297995ec5be072a92750464ab8;p=openbsd 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@ --- 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);