DF-4551 / fix.diff
--- a/sys/dev/sound/pci/als4000.c +++ b/sys/dev/sound/pci/als4000.c @@ -780,11 +780,6 @@ als_resource_grab(device_t dev, struct sc_info *sc) goto bad; } - if (snd_setup_intr(dev, sc->irq, INTR_MPSAFE, als_intr, - sc, &sc->ih)) { - device_printf(dev, "unable to setup interrupt\n"); - goto bad; - } - sc->bufsz = pcm_getbuffersize(dev, 4096, ALS_DEFAULT_BUFSZ, 65536); if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), @@ -838,6 +833,15 @@ als_pci_attach(device_t dev) pcm_addchan(dev, PCMDIR_PLAY, &alspchan_class, sc); pcm_addchan(dev, PCMDIR_REC, &alsrchan_class, sc); + /* Hook the interrupt only after the channels it dispatches to exist + * (pcm_addchan -> alschan_init sets ch->channel). Registering it + * earlier leaves a window where als_intr() runs chn_intr(NULL) and + * panics on any shared-line IRQ. */ + if (snd_setup_intr(dev, sc->irq, INTR_MPSAFE, als_intr, + sc, &sc->ih)) { + device_printf(dev, "unable to setup interrupt\n"); + goto bad_attach; + } + ksnprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s", rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_als4000)); pcm_setstatus(dev, status); @@ -850,6 +854,14 @@ als_resource_free(device_t dev, struct sc_info *sc) { + /* Tear the interrupt down BEFORE releasing the I/O region: a racing + * handler must not bus_space_read/write a released mapping. */ + if (sc->ih) { + bus_teardown_intr(dev, sc->irq, sc->ih); + sc->ih = 0; + } if (sc->reg) { bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg); sc->reg = 0; } - if (sc->ih) { - bus_teardown_intr(dev, sc->irq, sc->ih); - sc->ih = 0; - } if (sc->irq) { bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); sc->irq = 0; |