This diff allows the audio(4) driver to properly recover, when the
envy(4) device misses interrupts. Fixes permanent distortion on MP
systems.
OK?
Index: envy.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/envy.c,v
retrieving revision 1.60
diff -u -p -u -p -r1.60 envy.c
--- envy.c 25 Jun 2015 06:43:46 -0000 1.60
+++ envy.c 29 Jul 2015 07:48:30 -0000
@@ -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 *st
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 *sta
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;
Index: envyvar.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/envyvar.h,v
retrieving revision 1.16
diff -u -p -u -p -r1.16 envyvar.h
--- envyvar.h 4 Oct 2010 09:32:43 -0000 1.16
+++ envyvar.h 29 Jul 2015 07:48:30 -0000
@@ -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 {