Fix possible DMA leak and locking violation especially

during suspend <-> resume and module load <-> unload.

PR:		kern/92764
MFC after:	3 days
This commit is contained in:
Ariff Abdullah 2006-02-12 10:42:47 +00:00
parent e3f1789aa0
commit 34733eb529

View File

@ -677,7 +677,6 @@ static int
ich_init(struct sc_info *sc) ich_init(struct sc_info *sc)
{ {
u_int32_t stat; u_int32_t stat;
int sz;
ich_wr(sc, ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD, 4); ich_wr(sc, ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD, 4);
DELAY(600000); DELAY(600000);
@ -701,15 +700,6 @@ ich_init(struct sc_info *sc)
if (sc->hasmic && ich_resetchan(sc, 2)) if (sc->hasmic && ich_resetchan(sc, 2))
return ENXIO; return ENXIO;
if (bus_dmamem_alloc(sc->dmat, (void **)&sc->dtbl, BUS_DMA_NOWAIT, &sc->dtmap))
return ENOSPC;
sz = sizeof(struct ich_desc) * ICH_DTBL_LENGTH * 3;
if (bus_dmamap_load(sc->dmat, sc->dtmap, sc->dtbl, sz, ich_setmap, sc, 0)) {
bus_dmamem_free(sc->dmat, (void **)&sc->dtbl, sc->dtmap);
return ENOSPC;
}
return 0; return 0;
} }
@ -828,6 +818,15 @@ ich_pci_attach(device_t dev)
goto bad; goto bad;
} }
if (bus_dmamem_alloc(sc->dmat, (void **)&sc->dtbl,
BUS_DMA_NOWAIT, &sc->dtmap))
goto bad;
if (bus_dmamap_load(sc->dmat, sc->dtmap, sc->dtbl,
sizeof(struct ich_desc) * ICH_DTBL_LENGTH * 3,
ich_setmap, sc, 0))
goto bad;
sc->codec = AC97_CREATE(dev, sc, ich_ac97); sc->codec = AC97_CREATE(dev, sc, ich_ac97);
if (sc->codec == NULL) if (sc->codec == NULL)
goto bad; goto bad;
@ -895,6 +894,10 @@ ich_pci_attach(device_t dev)
if (sc->nabmbar) if (sc->nabmbar)
bus_release_resource(dev, sc->regtype, bus_release_resource(dev, sc->regtype,
sc->nabmbarid, sc->nabmbar); sc->nabmbarid, sc->nabmbar);
if (sc->dtmap)
bus_dmamap_unload(sc->dmat, sc->dtmap);
if (sc->dmat)
bus_dma_tag_destroy(sc->dmat);
if (sc->ich_lock) if (sc->ich_lock)
snd_mtxfree(sc->ich_lock); snd_mtxfree(sc->ich_lock);
free(sc, M_DEVBUF); free(sc, M_DEVBUF);
@ -916,6 +919,7 @@ ich_pci_detach(device_t dev)
bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
bus_release_resource(dev, sc->regtype, sc->nambarid, sc->nambar); bus_release_resource(dev, sc->regtype, sc->nambarid, sc->nambar);
bus_release_resource(dev, sc->regtype, sc->nabmbarid, sc->nabmbar); bus_release_resource(dev, sc->regtype, sc->nabmbarid, sc->nabmbar);
bus_dmamap_unload(sc->dmat, sc->dtmap);
bus_dma_tag_destroy(sc->dmat); bus_dma_tag_destroy(sc->dmat);
snd_mtxfree(sc->ich_lock); snd_mtxfree(sc->ich_lock);
free(sc, M_DEVBUF); free(sc, M_DEVBUF);
@ -987,24 +991,21 @@ ich_pci_resume(device_t dev)
} }
/* Reinit mixer */ /* Reinit mixer */
ich_pci_codec_reset(sc); ich_pci_codec_reset(sc);
ICH_UNLOCK(sc);
ac97_setextmode(sc->codec, sc->hasvra | sc->hasvrm); ac97_setextmode(sc->codec, sc->hasvra | sc->hasvrm);
if (mixer_reinit(dev) == -1) { if (mixer_reinit(dev) == -1) {
device_printf(dev, "unable to reinitialize the mixer\n"); device_printf(dev, "unable to reinitialize the mixer\n");
ICH_UNLOCK(sc);
return ENXIO; return ENXIO;
} }
/* Re-start DMA engines */ /* Re-start DMA engines */
for (i = 0 ; i < 3; i++) { for (i = 0 ; i < 3; i++) {
struct sc_chinfo *ch = &sc->ch[i]; struct sc_chinfo *ch = &sc->ch[i];
if (sc->ch[i].run_save) { if (sc->ch[i].run_save) {
ICH_UNLOCK(sc);
ichchan_setblocksize(0, ch, ch->blksz); ichchan_setblocksize(0, ch, ch->blksz);
ichchan_setspeed(0, ch, ch->spd); ichchan_setspeed(0, ch, ch->spd);
ichchan_trigger(0, ch, PCMTRIG_START); ichchan_trigger(0, ch, PCMTRIG_START);
ICH_LOCK(sc);
} }
} }
ICH_UNLOCK(sc);
return 0; return 0;
} }