PR/52331: ydc driver: sleep-under-spin-mutex bugs in yds_allocmem

Don't hold the spin interrupt mutex while calling yds_init from resume.
Instead use a flag to short-circuit the interrupt while disabled.
This commit is contained in:
christos 2017-06-25 16:07:48 +00:00
parent d8f3d5d812
commit 74bac439bd
2 changed files with 16 additions and 4 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: yds.c,v 1.58 2017/06/01 02:45:11 chs Exp $ */
/* $NetBSD: yds.c,v 1.59 2017/06/25 16:07:48 christos Exp $ */
/*
* Copyright (c) 2000, 2001 Kazuki Sakamoto and Minoura Makoto.
@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: yds.c,v 1.58 2017/06/01 02:45:11 chs Exp $");
__KERNEL_RCSID(0, "$NetBSD: yds.c,v 1.59 2017/06/25 16:07:48 christos Exp $");
#include "mpu.h"
@ -688,6 +688,7 @@ yds_suspend(device_t dv, const pmf_qual_t *qual)
mutex_enter(&sc->sc_lock);
mutex_spin_enter(&sc->sc_intr_lock);
sc->sc_enabled = 0;
sc->sc_dsctrl = pci_conf_read(pc, tag, YDS_PCI_DSCTRL);
sc->sc_legacy = pci_conf_read(pc, tag, YDS_PCI_LEGACY);
sc->sc_ba[0] = pci_conf_read(pc, tag, YDS_PCI_FM_BA);
@ -718,14 +719,15 @@ yds_resume(device_t dv, const pmf_qual_t *qual)
PCI_COMMAND_MASTER_ENABLE);
pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, reg);
reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
mutex_spin_exit(&sc->sc_intr_lock);
if (yds_init(sc)) {
aprint_error_dev(dv, "reinitialize failed\n");
mutex_spin_exit(&sc->sc_intr_lock);
mutex_exit(&sc->sc_lock);
return false;
}
pci_conf_write(pc, tag, YDS_PCI_DSCTRL, sc->sc_dsctrl);
sc->sc_enabled = 1;
mutex_spin_exit(&sc->sc_intr_lock);
sc->sc_codec[0].codec_if->vtbl->restore_ports(sc->sc_codec[0].codec_if);
mutex_exit(&sc->sc_lock);
@ -785,6 +787,7 @@ yds_attach(device_t parent, device_t self, void *aux)
}
aprint_normal_dev(self, "interrupting at %s\n", intrstr);
sc->sc_enabled = 0;
sc->sc_dmatag = pa->pa_dmat;
sc->sc_pc = pc;
sc->sc_pcitag = pa->pa_tag;
@ -940,6 +943,10 @@ detected:
if (!pmf_device_register(self, yds_suspend, yds_resume))
aprint_error_dev(self, "couldn't establish power handler\n");
mutex_spin_enter(&sc->sc_intr_lock);
sc->sc_enabled = 1;
mutex_spin_exit(&sc->sc_intr_lock);
}
static int
@ -1046,6 +1053,10 @@ yds_intr(void *p)
u_int status;
mutex_spin_enter(&sc->sc_intr_lock);
if (!sc->sc_enabled) {
mutex_spin_exit(&sc->sc_intr_lock);
return 0;
}
status = YREAD4(sc, YDS_STATUS);
DPRINTFN(1, ("yds_intr: status=%08x\n", status));

View File

@ -1,4 +1,4 @@
/* $NetBSD: ydsvar.h,v 1.11 2011/11/23 23:07:36 jmcneill Exp $ */
/* $NetBSD: ydsvar.h,v 1.12 2017/06/25 16:07:48 christos Exp $ */
/*
* Copyright (c) 2000, 2001 Kazuki Sakamoto and Minoura Makoto.
@ -66,6 +66,7 @@ struct yds_softc {
bus_space_handle_t memh;
bus_dma_tag_t sc_dmatag; /* DMA tag */
u_int sc_flags;
int sc_enabled;
struct yds_codec_softc sc_codec[2]; /* Primary/Secondary AC97 */