summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Meuser <jakemsr@cvs.openbsd.org>2009-12-24 10:12:20 +0000
committerJacob Meuser <jakemsr@cvs.openbsd.org>2009-12-24 10:12:20 +0000
commita9dae394ab644645310e4afaef610a19cdd29e21 (patch)
tree998b7df54489f85c16e0baebb1f990794a514734
parent153807970c24e7b0931c8074c0f569bf46bf0d17 (diff)
do not run the unsolicited event queue from the interrupt handler.
instead, install a timeout(9) to run the queue. fixes a panic reported by wilfried@
-rw-r--r--sys/dev/pci/azalia.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c
index 65e7f2bbb79..064d184f6ea 100644
--- a/sys/dev/pci/azalia.c
+++ b/sys/dev/pci/azalia.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: azalia.c,v 1.165 2009/12/22 08:48:14 jakemsr Exp $ */
+/* $OpenBSD: azalia.c,v 1.166 2009/12/24 10:12:19 jakemsr Exp $ */
/* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */
/*-
@@ -45,6 +45,8 @@
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/timeout.h>
#include <uvm/uvm_param.h>
#include <dev/audio_if.h>
#include <dev/auconv.h>
@@ -167,6 +169,7 @@ typedef struct azalia_t {
int unsolq_wp;
int unsolq_rp;
boolean_t unsolq_kick;
+ struct timeout unsol_to;
boolean_t ok64;
int nistreams, nostreams, nbstreams;
@@ -206,7 +209,7 @@ int azalia_init_rirb(azalia_t *, int);
int azalia_delete_rirb(azalia_t *);
int azalia_set_command(azalia_t *, nid_t, int, uint32_t, uint32_t);
int azalia_get_response(azalia_t *, uint32_t *);
-void azalia_rirb_kick_unsol_events(azalia_t *);
+void azalia_rirb_kick_unsol_events(void *);
void azalia_rirb_intr(azalia_t *);
int azalia_alloc_dmamem(azalia_t *, size_t, size_t, azalia_dma_t *);
int azalia_free_dmamem(const azalia_t *, azalia_dma_t*);
@@ -543,6 +546,7 @@ int
azalia_pci_detach(struct device *self, int flags)
{
azalia_t *az;
+ uint32_t gctl;
int i;
DPRINTF(("%s\n", __func__));
@@ -552,6 +556,12 @@ azalia_pci_detach(struct device *self, int flags)
az->audiodev = NULL;
}
+ /* disable unsolicited response */
+ gctl = AZ_READ_4(az, GCTL);
+ AZ_WRITE_4(az, GCTL, gctl & ~(HDA_GCTL_UNSOL));
+
+ timeout_del(&az->unsol_to);
+
DPRINTF(("%s: delete streams\n", __func__));
azalia_stream_delete(&az->rstream, az);
azalia_stream_delete(&az->pstream, az);
@@ -630,6 +640,8 @@ azalia_shutdown(void *v)
gctl = AZ_READ_4(az, GCTL);
AZ_WRITE_4(az, GCTL, gctl & ~(HDA_GCTL_UNSOL));
+ timeout_del(&az->unsol_to);
+
/* halt CORB/RIRB */
azalia_halt_corb(az);
azalia_halt_rirb(az);
@@ -947,6 +959,7 @@ azalia_init_corb(azalia_t *az, int resuming)
}
DPRINTF(("%s: CORB allocation succeeded.\n", __func__));
}
+ timeout_set(&az->unsol_to, azalia_rirb_kick_unsol_events, az);
AZ_WRITE_4(az, CORBLBASE, (uint32_t)AZALIA_DMA_DMAADDR(&az->corb_dma));
AZ_WRITE_4(az, CORBUBASE, PTR_UPPER32(AZALIA_DMA_DMAADDR(&az->corb_dma)));
@@ -1196,8 +1209,10 @@ azalia_get_response(azalia_t *az, uint32_t *result)
}
void
-azalia_rirb_kick_unsol_events(azalia_t *az)
+azalia_rirb_kick_unsol_events(void *v)
{
+ azalia_t *az = v;
+
if (az->unsolq_kick)
return;
az->unsolq_kick = TRUE;
@@ -1238,7 +1253,7 @@ azalia_rirb_intr(azalia_t *az)
DPRINTF(("%s: dropped solicited response\n", __func__));
}
}
- azalia_rirb_kick_unsol_events(az);
+ timeout_add_msec(&az->unsol_to, 1);
AZ_WRITE_1(az, RIRBSTS,
rirbsts | HDA_RIRBSTS_RIRBOIS | HDA_RIRBSTS_RINTFL);
@@ -1307,6 +1322,8 @@ azalia_suspend(azalia_t *az)
/* disable unsolicited responses */
AZ_WRITE_4(az, GCTL, AZ_READ_4(az, GCTL) & ~HDA_GCTL_UNSOL);
+ timeout_del(&az->unsol_to);
+
azalia_save_mixer(&az->codecs[az->codecno]);
/* azalia_stream_halt() always returns 0.