summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorAlexandre Ratchov <ratchov@cvs.openbsd.org>2015-07-29 21:10:51 +0000
committerAlexandre Ratchov <ratchov@cvs.openbsd.org>2015-07-29 21:10:51 +0000
commitb7f8c531bdd6eae84181af0170a13e3ddca0edde (patch)
tree352e3e62b46f88d1f288114c75e78db46349c636 /sys/dev/pci
parent3a229ae2b14aa48c82609b6e7aa1636a41b2d79d (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.c55
-rw-r--r--sys/dev/pci/envyvar.h5
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 {