Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci Three changes:



details:   https://anonhg.NetBSD.org/src/rev/7cb208b58255
branches:  trunk
changeset: 574773:7cb208b58255
user:      mycroft <mycroft%NetBSD.org@localhost>
date:      Fri Mar 11 22:29:16 2005 +0000

description:
Three changes:
1) After setting an input or output channel to pause, watch for DCH (DMA
   halted) to be set before resetting the registers.  The manual says this is
   required.  This *may* fix random auich lockups.
2) Add auich_{trigger,intr,halt}_pipe(), which can operate on any of the
   input and output channels.  This reduces code duplication quite a bit.
   While I'm at it, fill in the mic interrupt handling.
3) The mic in interrupt is MINT, not MIINT.  (The latter is modem input.)

diffstat:

 sys/dev/pci/auich.c |  254 +++++++++++++++++++++------------------------------
 1 files changed, 106 insertions(+), 148 deletions(-)

diffs (truncated from 394 to 300 lines):

diff -r 0fec79bc6315 -r 7cb208b58255 sys/dev/pci/auich.c
--- a/sys/dev/pci/auich.c       Fri Mar 11 20:55:10 2005 +0000
+++ b/sys/dev/pci/auich.c       Fri Mar 11 22:29:16 2005 +0000
@@ -1,7 +1,7 @@
-/*     $NetBSD: auich.c,v 1.89 2005/02/27 00:27:32 perry Exp $ */
+/*     $NetBSD: auich.c,v 1.90 2005/03/11 22:29:16 mycroft Exp $       */
 
 /*-
- * Copyright (c) 2000, 2004 The NetBSD Foundation, Inc.
+ * Copyright (c) 2000, 2004, 2005 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -118,7 +118,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: auich.c,v 1.89 2005/02/27 00:27:32 perry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: auich.c,v 1.90 2005/03/11 22:29:16 mycroft Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -252,6 +252,7 @@
                    audio_params_t *, stream_filter_list_t *,
                    stream_filter_list_t *);
 static int     auich_round_blocksize(void *, int, int, const audio_params_t *);
+static void    auich_halt_pipe(struct auich_softc *, int);
 static int     auich_halt_output(void *);
 static int     auich_halt_input(void *);
 static int     auich_getdev(void *, struct audio_device *);
@@ -263,6 +264,8 @@
 static size_t  auich_round_buffersize(void *, int, size_t);
 static paddr_t auich_mappage(void *, void *, off_t, int);
 static int     auich_get_props(void *);
+static void    auich_trigger_pipe(struct auich_softc *, int, struct auich_ring *);
+static void    auich_intr_pipe(struct auich_softc *, int, struct auich_ring *);
 static int     auich_trigger_output(void *, void *, void *, int,
                    void (*)(void *), void *, const audio_params_t *);
 static int     auich_trigger_input(void *, void *, void *, int,
@@ -866,6 +869,27 @@
        return blk & ~0x3f;             /* keep good alignment */
 }
 
+static void
+auich_halt_pipe(struct auich_softc *sc, int pipe)
+{
+       int i;
+       uint32_t status;
+
+       bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_CTRL, 0);
+       for (i = 0; i < 100; i++) {
+               status = bus_space_read_4(sc->iot, sc->aud_ioh, pipe + ICH_STS);
+               if (status & ICH_DCH)
+                       break;
+               DELAY(1);
+       }
+       bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_CTRL, ICH_RR);
+
+#if 1
+       if (i > 0)
+               printf("auich_halt_pipe: halt took %d cycles\n", i);
+#endif
+}
+
 static int
 auich_halt_output(void *v)
 {
@@ -874,7 +898,7 @@
        sc = v;
        DPRINTF(ICH_DEBUG_DMA, ("%s: halt_output\n", sc->sc_dev.dv_xname));
 
-       bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_CTRL, ICH_RR);
+       auich_halt_pipe(sc, ICH_PCMO);
        sc->pcmo.intr = NULL;
 
        return 0;
@@ -886,13 +910,9 @@
        struct auich_softc *sc;
 
        sc = v;
-       DPRINTF(ICH_DEBUG_DMA,
-           ("%s: halt_input\n", sc->sc_dev.dv_xname));
+       DPRINTF(ICH_DEBUG_DMA, ("%s: halt_input\n", sc->sc_dev.dv_xname));
 
-       /* XXX halt both unless known otherwise */
-
-       bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL, ICH_RR);
-       bus_space_write_1(sc->iot, sc->aud_ioh, ICH_MICI + ICH_CTRL, ICH_RR);
+       auich_halt_pipe(sc, ICH_PCMI);
        sc->pcmi.intr = NULL;
 
        return 0;
@@ -1057,38 +1077,8 @@
                if (sts & ICH_FIFOE)
                        printf("%s: fifo underrun\n", sc->sc_dev.dv_xname);
 
-               if (sts & ICH_BCIS) {
-                       struct auich_dmalist *q;
-                       int blksize, qptr, i;
-
-                       blksize = sc->pcmo.blksize;
-                       qptr = sc->pcmo.qptr;
-                       i = bus_space_read_1(sc->iot, sc->aud_ioh,
-                           ICH_PCMO + ICH_CIV);
-
-                       while (qptr != i) {
-                               q = &sc->pcmo.dmalist[qptr];
-
-                               q->base = sc->pcmo.p;
-                               q->len = (blksize >> sc->sc_sample_shift) |
-                                   ICH_DMAF_IOC;
-                               DPRINTF(ICH_DEBUG_INTR,
-                                   ("auich_intr: %p, %p = %x @ 0x%x\n",
-                                   &sc->pcmo.dmalist[i], q, q->len, q->base));
-
-                               sc->pcmo.p += blksize;
-                               if (sc->pcmo.p >= sc->pcmo.end)
-                                       sc->pcmo.p = sc->pcmo.start;
-
-                               qptr = (qptr + 1) & ICH_LVI_MASK;
-                               if (sc->pcmo.intr)
-                                       sc->pcmo.intr(sc->pcmo.arg);
-                       }
-
-                       sc->pcmo.qptr = qptr;
-                       bus_space_write_1(sc->iot, sc->aud_ioh,
-                           ICH_PCMO + ICH_LVI, (qptr - 1) & ICH_LVI_MASK);
-               }
+               if (sts & ICH_BCIS)
+                       auich_intr_pipe(sc, ICH_PCMO, &sc->pcmo);
 
                /* int ack */
                bus_space_write_2(sc->iot, sc->aud_ioh, ICH_PCMO +
@@ -1108,38 +1098,8 @@
                if (sts & ICH_FIFOE)
                        printf("%s: fifo overrun\n", sc->sc_dev.dv_xname);
 
-               if (sts & ICH_BCIS) {
-                       struct auich_dmalist *q;
-                       int blksize, qptr, i;
-
-                       blksize = sc->pcmi.blksize;
-                       qptr = sc->pcmi.qptr;
-                       i = bus_space_read_1(sc->iot, sc->aud_ioh,
-                           ICH_PCMI + ICH_CIV);
-
-                       while (qptr != i) {
-                               q = &sc->pcmi.dmalist[qptr];
-
-                               q->base = sc->pcmi.p;
-                               q->len = (blksize >> sc->sc_sample_shift) |
-                                   ICH_DMAF_IOC;
-                               DPRINTF(ICH_DEBUG_INTR,
-                                   ("auich_intr: %p, %p = %x @ 0x%x\n",
-                                   &sc->pcmi.dmalist[i], q, q->len, q->base));
-
-                               sc->pcmi.p += blksize;
-                               if (sc->pcmi.p >= sc->pcmi.end)
-                                       sc->pcmi.p = sc->pcmi.start;
-
-                               qptr = (qptr + 1) & ICH_LVI_MASK;
-                               if (sc->pcmi.intr)
-                                       sc->pcmi.intr(sc->pcmi.arg);
-                       }
-
-                       sc->pcmi.qptr = qptr;
-                       bus_space_write_1(sc->iot, sc->aud_ioh,
-                           ICH_PCMI + ICH_LVI, (qptr - 1) & ICH_LVI_MASK);
-               }
+               if (sts & ICH_BCIS)
+                       auich_intr_pipe(sc, ICH_PCMI, &sc->pcmi);
 
                /* int ack */
                bus_space_write_2(sc->iot, sc->aud_ioh, ICH_PCMI +
@@ -1148,7 +1108,7 @@
                ret++;
        }
 
-       if (gsts & ICH_MIINT) {
+       if (gsts & ICH_MINT) {
                int sts;
 
                sts = bus_space_read_2(sc->iot, sc->aud_ioh,
@@ -1159,39 +1119,89 @@
                if (sts & ICH_FIFOE)
                        printf("%s: fifo overrun\n", sc->sc_dev.dv_xname);
 
-               /* TODO mic input DMA */
+               if (sts & ICH_BCIS)
+                       auich_intr_pipe(sc, ICH_MICI, &sc->mici);
 
-               bus_space_write_4(sc->iot, sc->aud_ioh, ICH_GSTS, ICH_MIINT);
+               /* int ack */
+               bus_space_write_2(sc->iot, sc->aud_ioh, ICH_MICI +
+                   sc->sc_sts_reg, sts & (ICH_BCIS | ICH_FIFOE));
+               bus_space_write_4(sc->iot, sc->aud_ioh, ICH_GSTS, ICH_MINT);
+               ret++;
        }
 
        return ret;
 }
 
+static void
+auich_trigger_pipe(struct auich_softc *sc, int pipe, struct auich_ring *ring)
+{
+       int blksize, qptr;
+       struct auich_dmalist *q;
+
+       blksize = ring->blksize;
+
+       for (qptr = 0; qptr < ICH_DMALIST_MAX; qptr++) {
+               q = &ring->dmalist[qptr];
+               q->base = ring->p;
+               q->len = (blksize >> sc->sc_sample_shift) | ICH_DMAF_IOC;
+
+               ring->p += blksize;
+               if (ring->p >= ring->end)
+                       ring->p = ring->start;
+       }
+       ring->qptr = 0;
+
+       bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_LVI,
+           (qptr - 1) & ICH_LVI_MASK);
+       bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_CTRL,
+           ICH_IOCE | ICH_FEIE | ICH_RPBM);
+}
+
+static void
+auich_intr_pipe(struct auich_softc *sc, int pipe, struct auich_ring *ring)
+{
+       int blksize, qptr, nqptr;
+       struct auich_dmalist *q;
+
+       blksize = ring->blksize;
+       qptr = ring->qptr;
+       nqptr = bus_space_read_1(sc->iot, sc->aud_ioh, pipe + ICH_CIV);
+
+       while (qptr != nqptr) {
+               q = &ring->dmalist[qptr];
+               q->base = ring->p;
+               q->len = (blksize >> sc->sc_sample_shift) | ICH_DMAF_IOC;
+
+               DPRINTF(ICH_DEBUG_INTR,
+                   ("auich_intr: %p, %p = %x @ 0x%x\n",
+                   &ring->dmalist[qptr], q, q->len, q->base));
+
+               ring->p += blksize;
+               if (ring->p >= ring->end)
+                       ring->p = ring->start;
+
+               qptr = (qptr + 1) & ICH_LVI_MASK;
+               if (ring->intr)
+                       ring->intr(ring->arg);
+       }
+       ring->qptr = qptr;
+
+       bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_LVI,
+           (qptr - 1) & ICH_LVI_MASK);
+}
+
 static int
 auich_trigger_output(void *v, void *start, void *end, int blksize,
     void (*intr)(void *), void *arg, const audio_params_t *param)
 {
        struct auich_softc *sc;
-       struct auich_dmalist *q;
        struct auich_dma *p;
        size_t size;
-       int qptr;
-#ifdef DIAGNOSTIC
-       int csts;
-#endif
 
        DPRINTF(ICH_DEBUG_DMA,
            ("auich_trigger_output(%p, %p, %d, %p, %p, %p)\n",
            start, end, blksize, intr, arg, param));
        sc = v;
-       sc->pcmo.intr = intr;
-       sc->pcmo.arg = arg;
-#ifdef DIAGNOSTIC
-       csts = pci_conf_read(sc->sc_pc, sc->sc_pt, PCI_COMMAND_STATUS_REG);
-       if (csts & PCI_STATUS_MASTER_ABORT) {
-               printf("auich_trigger_output: PCI master abort\n");
-       }
-#endif
 
        for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
                continue;
@@ -1202,35 +1212,16 @@
 
        size = (size_t)((caddr_t)end - (caddr_t)start);
 
-       /*
-        * The logic behind this is:
-        * setup one buffer to play, then LVI dump out the rest
-        * to the scatter-gather chain.
-        */
+       sc->pcmo.intr = intr;
+       sc->pcmo.arg = arg;
        sc->pcmo.start = DMAADDR(p);



Home | Main Index | Thread Index | Old Index