diff options
author | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2015-07-29 21:10:51 +0000 |
---|---|---|
committer | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2015-07-29 21:10:51 +0000 |
commit | b7f8c531bdd6eae84181af0170a13e3ddca0edde (patch) | |
tree | 352e3e62b46f88d1f288114c75e78db46349c636 /sys/dev/pci | |
parent | 3a229ae2b14aa48c82609b6e7aa1636a41b2d79d (diff) |
Use DMA pointer determine the number of times the audio(4) layer has
to advance in time. This is needed to properly recover, when
interrupts are blocked for too long. Fixes permanent distortion on MP
systems.
ok deraadt
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/envy.c | 55 | ||||
-rw-r--r-- | sys/dev/pci/envyvar.h | 5 |
2 files changed, 52 insertions, 8 deletions
diff --git a/sys/dev/pci/envy.c b/sys/dev/pci/envy.c index a71b7c3f5ee..883b936a185 100644 --- a/sys/dev/pci/envy.c +++ b/sys/dev/pci/envy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: envy.c,v 1.60 2015/06/25 06:43:46 ratchov Exp $ */ +/* $OpenBSD: envy.c,v 1.61 2015/07/29 21:10:50 ratchov Exp $ */ /* * Copyright (c) 2007 Alexandre Ratchov <alex@caoua.org> * @@ -1921,6 +1921,7 @@ int envy_intr(void *self) { struct envy_softc *sc = (struct envy_softc *)self; + unsigned int reg, hwpos, cnt; int mintr, mstat, mdata; int st, err, ctl; int max; @@ -1965,9 +1966,26 @@ envy_intr(void *self) } } if (st & ENVY_MT_INTR_PACK) { - if (sc->oactive) - sc->ointr(sc->oarg); - else { + if (sc->oactive) { + reg = envy_mt_read_2(sc, ENVY_MT_PBUFSZ); + hwpos = sc->obuf.bufsz - 4 * (reg + 1); + if (hwpos >= sc->obuf.bufsz) + hwpos -= sc->obuf.bufsz; + DPRINTFN(2, "%s: play: reg = %u, pos: %u -> %u\n", + DEVNAME(sc), reg, sc->obuf.swpos, hwpos); + cnt = 0; + while (hwpos - sc->obuf.swpos >= sc->obuf.blksz) { + sc->ointr(sc->oarg); + sc->obuf.swpos += sc->obuf.blksz; + if (sc->obuf.swpos == sc->obuf.bufsz) + sc->obuf.swpos = 0; + cnt++; + } + if (cnt != 1) { + DPRINTFN(2, "%s: play: %u intrs\n", + DEVNAME(sc), cnt); + } + } else { ctl = envy_mt_read_1(sc, ENVY_MT_CTL); if (ctl & ENVY_MT_CTL_PSTART) { envy_mt_write_1(sc, @@ -1983,9 +2001,26 @@ envy_intr(void *self) } } if (st & ENVY_MT_INTR_RACK) { - if (sc->iactive) - sc->iintr(sc->iarg); - else { + if (sc->iactive) { + reg = envy_mt_read_2(sc, ENVY_MT_RBUFSZ); + hwpos = sc->ibuf.bufsz - 4 * (reg + 1); + if (hwpos >= sc->ibuf.bufsz) + hwpos -= sc->ibuf.bufsz; + DPRINTFN(2, "%s: rec: reg = %u, pos: %u -> %u\n", + DEVNAME(sc), reg, sc->ibuf.swpos, hwpos); + cnt = 0; + while (hwpos - sc->ibuf.swpos >= sc->ibuf.blksz) { + sc->iintr(sc->iarg); + sc->ibuf.swpos += sc->ibuf.blksz; + if (sc->ibuf.swpos == sc->ibuf.bufsz) + sc->ibuf.swpos = 0; + cnt++; + } + if (cnt != 1) { + DPRINTFN(2, "%s: rec: %u intrs\n", + DEVNAME(sc), cnt); + } + } else { ctl = envy_mt_read_1(sc, ENVY_MT_CTL); if (ctl & ENVY_MT_CTL_RSTART(sc)) { envy_mt_write_1(sc, @@ -2034,6 +2069,9 @@ envy_trigger_output(void *self, void *start, void *end, int blksz, nanouptime(&sc->start_ts); } #endif + sc->obuf.bufsz = bufsz; + sc->obuf.blksz = blksz; + sc->obuf.swpos = 0; sc->ointr = intr; sc->oarg = arg; sc->oactive = 1; @@ -2077,6 +2115,9 @@ envy_trigger_input(void *self, void *start, void *end, int blksz, nanouptime(&sc->start_ts); } #endif + sc->ibuf.bufsz = bufsz; + sc->ibuf.blksz = blksz; + sc->ibuf.swpos = 0; sc->iintr = intr; sc->iarg = arg; sc->iactive = 1; diff --git a/sys/dev/pci/envyvar.h b/sys/dev/pci/envyvar.h index c9347f7125f..99164478275 100644 --- a/sys/dev/pci/envyvar.h +++ b/sys/dev/pci/envyvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: envyvar.h,v 1.16 2010/10/04 09:32:43 ratchov Exp $ */ +/* $OpenBSD: envyvar.h,v 1.17 2015/07/29 21:10:50 ratchov Exp $ */ /* * Copyright (c) 2007 Alexandre Ratchov <alex@caoua.org> * @@ -31,6 +31,9 @@ struct envy_buf { bus_dmamap_t map; caddr_t addr; size_t size; + unsigned int swpos; + unsigned int bufsz; + unsigned int blksz; }; struct envy_codec { |