diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2011-04-08 19:26:08 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2011-04-08 19:26:08 +0000 |
commit | e5c62af2422910cca749ba57dbb804ed0e48781e (patch) | |
tree | 0dab5caa0c3b9e8a94f875bc71fa56e53915fcd9 /sys/dev | |
parent | c1bfc86d9b68b9be4b5327c6abcf3a36c3e16720 (diff) |
backout previous (which has some interrupt spin problem, sort of diagnosed
by claudio to be related to this commit) until jakemsr has time to fix it
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/azalia.c | 94 |
1 files changed, 81 insertions, 13 deletions
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c index ae092d17eec..849223b6ac7 100644 --- a/sys/dev/pci/azalia.c +++ b/sys/dev/pci/azalia.c @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.c,v 1.192 2011/04/04 18:05:31 jakemsr Exp $ */ +/* $OpenBSD: azalia.c,v 1.193 2011/04/08 19:26:07 deraadt Exp $ */ /* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */ /*- @@ -209,8 +209,10 @@ int azalia_init_streams(azalia_t *); void azalia_shutdown(void *); int azalia_halt_corb(azalia_t *); int azalia_init_corb(azalia_t *, int); +int azalia_delete_corb(azalia_t *); int azalia_halt_rirb(azalia_t *); 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(void *); @@ -248,6 +250,7 @@ void azalia_widget_print_audio(const widget_t *, const char *); void azalia_widget_print_pin(const widget_t *); int azalia_stream_init(stream_t *, azalia_t *, int, int, int); +int azalia_stream_delete(stream_t *, azalia_t *); int azalia_stream_reset(stream_t *); int azalia_stream_start(stream_t *); int azalia_stream_halt(stream_t *); @@ -567,6 +570,7 @@ int azalia_pci_detach(struct device *self, int flags) { azalia_t *az; + uint32_t gctl; int i; DPRINTF(("%s\n", __func__)); @@ -576,13 +580,15 @@ 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__)); - if (az->rstream.bdlist.addr != NULL) - azalia_free_dmamem(az, &az->rstream.bdlist); - if (az->pstream.bdlist.addr != NULL) - azalia_free_dmamem(az, &az->pstream.bdlist); + azalia_stream_delete(&az->rstream, az); + azalia_stream_delete(&az->pstream, az); DPRINTF(("%s: delete codecs\n", __func__)); for (i = 0; i < az->ncodecs; i++) { @@ -595,14 +601,16 @@ azalia_pci_detach(struct device *self, int flags) } DPRINTF(("%s: delete CORB and RIRB\n", __func__)); - if (az->corb_dma.addr != NULL) - azalia_free_dmamem(az, &az->corb_dma); - if (az->rirb_dma.addr != NULL) - azalia_free_dmamem(az, &az->rirb_dma); - if (az->unsolq != NULL) { - free(az->unsolq, M_DEVBUF); - az->unsolq = NULL; - } + azalia_delete_corb(az); + azalia_delete_rirb(az); + + DPRINTF(("%s: disable interrupts\n", __func__)); + 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); DPRINTF(("%s: delete PCI resources\n", __func__)); if (az->ih != NULL) { @@ -1003,6 +1011,27 @@ azalia_init_corb(azalia_t *az, int resuming) } int +azalia_delete_corb(azalia_t *az) +{ + int i; + uint8_t corbctl; + + if (az->corb_dma.addr == NULL) + return 0; + /* stop the CORB */ + corbctl = AZ_READ_1(az, CORBCTL); + AZ_WRITE_1(az, CORBCTL, corbctl & ~HDA_CORBCTL_CORBRUN); + for (i = 5000; i >= 0; i--) { + DELAY(10); + corbctl = AZ_READ_1(az, CORBCTL); + if ((corbctl & HDA_CORBCTL_CORBRUN) == 0) + break; + } + azalia_free_dmamem(az, &az->corb_dma); + return 0; +} + +int azalia_halt_rirb(azalia_t *az) { int i; @@ -1084,6 +1113,31 @@ azalia_init_rirb(azalia_t *az, int resuming) } int +azalia_delete_rirb(azalia_t *az) +{ + int i; + uint8_t rirbctl; + + if (az->unsolq != NULL) { + free(az->unsolq, M_DEVBUF); + az->unsolq = NULL; + } + if (az->rirb_dma.addr == NULL) + return 0; + /* stop the RIRB */ + rirbctl = AZ_READ_1(az, RIRBCTL); + AZ_WRITE_1(az, RIRBCTL, rirbctl & ~HDA_RIRBCTL_RIRBDMAEN); + for (i = 5000; i >= 0; i--) { + DELAY(10); + rirbctl = AZ_READ_1(az, RIRBCTL); + if ((rirbctl & HDA_RIRBCTL_RIRBDMAEN) == 0) + break; + } + azalia_free_dmamem(az, &az->rirb_dma); + return 0; +} + +int azalia_comresp(const codec_t *codec, nid_t nid, uint32_t control, uint32_t param, uint32_t* result) { @@ -3602,6 +3656,20 @@ azalia_stream_init(stream_t *this, azalia_t *az, int regindex, int strnum, } int +azalia_stream_delete(stream_t *this, azalia_t *az) +{ + if (this->bdlist.addr == NULL) + return 0; + + /* disable stream interrupts */ + STR_WRITE_1(this, CTL, STR_READ_1(this, CTL) | + ~(HDA_SD_CTL_DEIE | HDA_SD_CTL_FEIE | HDA_SD_CTL_IOCE)); + + azalia_free_dmamem(az, &this->bdlist); + return 0; +} + +int azalia_stream_reset(stream_t *this) { int i; |