Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/mac68k/obio Rework avdma to fix PR port-mac68k/5613...



details:   https://anonhg.NetBSD.org/src/rev/0d602dabeba1
branches:  trunk
changeset: 369404:0d602dabeba1
user:      rin <rin%NetBSD.org@localhost>
date:      Mon Aug 15 12:16:25 2022 +0000

description:
Rework avdma to fix PR port-mac68k/56131 as well as add synchronous
transfer support.

According to analysis by Michael Zucca, PSC (DMAC for Quadra/Centris AV)
seems to require that DMA buffer is
  (1) aligned to 16-byte boundaries, and
  (2) multiple of 16 bytes in size.
If the buffer does not satisfy these constraints, esp.c rev 1.63 and
prior carry out partial PIO to align or shave off it.

However, partial PIO does not always work correctly for combination of
NCR53C94 and PSC, which results in failures observed as port-mac68k/56131.

Also, PIO spoils synchronous transfer, which is timing critical.

Therefore, for buffers that do not satisfy the boundary conditions,
completely stop using PIO and use DMA with ``bounce'' buffers.

This fixes port-mac68k/56131 and enables sync transfer as a big bonus.

Note that bounce DMA does not hurt performance at all. For filesystem
and swap I/O, buffers always satisfy the constraints above, and bounce
DMA is necessary only
  (a) when disk is attached, or
  (b) for special utilities like fsck(8) or fdisk(8),
as far as I can tell.

Also:

- Stop providing ``DMA-friendly'' sc_imess and sc_omess; transfer for
  MSGIN or MSGOUT does not almost certainly satisfy boundary condition
  (2). Again, this does not affect performance at all.

- SCSI bus frequency is 20MHz (i.e., 5MB/s for sync transfer) for AV
  models, according to ``Quadra 840AV Service Source''.

diffstat:

 sys/arch/mac68k/obio/esp.c    |  353 ++++++++++++-----------------------------
 sys/arch/mac68k/obio/espvar.h |    6 +-
 2 files changed, 112 insertions(+), 247 deletions(-)

diffs (truncated from 580 to 300 lines):

diff -r 2ec058c57b81 -r 0d602dabeba1 sys/arch/mac68k/obio/esp.c
--- a/sys/arch/mac68k/obio/esp.c        Mon Aug 15 11:55:52 2022 +0000
+++ b/sys/arch/mac68k/obio/esp.c        Mon Aug 15 12:16:25 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: esp.c,v 1.63 2022/08/15 11:29:53 rin Exp $     */
+/*     $NetBSD: esp.c,v 1.64 2022/08/15 12:16:25 rin Exp $     */
 
 /*
  * Copyright (c) 1997 Jason R. Thorpe.
@@ -81,7 +81,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: esp.c,v 1.63 2022/08/15 11:29:53 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: esp.c,v 1.64 2022/08/15 12:16:25 rin Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -123,16 +123,14 @@
 static void    esp_dma_go(struct ncr53c9x_softc *);
 static void    esp_dma_stop(struct ncr53c9x_softc *);
 static int     esp_dma_isactive(struct ncr53c9x_softc *);
-static void    esp_quick_write_reg(struct ncr53c9x_softc *, int, uint8_t);
+static void    esp_dma_write_reg(struct ncr53c9x_softc *, int, uint8_t);
 static int     esp_quick_dma_intr(struct ncr53c9x_softc *);
 static int     esp_quick_dma_setup(struct ncr53c9x_softc *, uint8_t **,
                        size_t *, int, size_t *);
 static void    esp_quick_dma_go(struct ncr53c9x_softc *);
 
-static void    esp_av_write_reg(struct ncr53c9x_softc *, int, uint8_t);
 static void    esp_av_dma_reset(struct ncr53c9x_softc *);
 static int     esp_av_dma_intr(struct ncr53c9x_softc *);
-static int     esp_av_pio_intr(struct ncr53c9x_softc *);
 static int     esp_av_dma_setup(struct ncr53c9x_softc *, uint8_t **, size_t *,
                        int, size_t *);
 static void    esp_av_dma_go(struct ncr53c9x_softc *);
@@ -233,12 +231,12 @@
        }
 
        if (quick) {
-               esp_glue.gl_write_reg = esp_quick_write_reg;
+               esp_glue.gl_write_reg = esp_dma_write_reg;
                esp_glue.gl_dma_intr = esp_quick_dma_intr;
                esp_glue.gl_dma_setup = esp_quick_dma_setup;
                esp_glue.gl_dma_go = esp_quick_dma_go;
        } else if (avdma) {
-               esp_glue.gl_write_reg = esp_av_write_reg;
+               esp_glue.gl_write_reg = esp_dma_write_reg;
                esp_glue.gl_dma_reset = esp_av_dma_reset;
                esp_glue.gl_dma_intr = esp_av_dma_intr;
                esp_glue.gl_dma_setup = esp_av_dma_setup;
@@ -260,11 +258,19 @@
                esc->sc_reg = (volatile uint8_t *)SCSIBase;
                via2_register_irq(VIA2_SCSIIRQ, esp_intr, esc);
                irq_mask = V2IF_SCSIIRQ;
-               if (reg_offset == 0x10000) {
+               switch (reg_offset) {
+               case 0x10000:
                        /* From the Q650 developer's note */
                        sc->sc_freq = 16500000;
-               } else
+                       break;
+               case 0x18000:
+                       /* From Quadra 840AV Service Source */
+                       sc->sc_freq = 20000000;
+                       break;
+               default:
                        sc->sc_freq = 25000000;
+                       break;
+               }
        } else {
                esp1 = esc;
 
@@ -322,21 +328,15 @@
                break;
        }
 
-       if (!quick) {
+       if (!quick && !avdma) {
                /*
                 * No synchronous xfers w/o DMA.
-                *
-                * XXXRO
-                * Also disable synchronous xfers for AV Macs;
-                * sync negotiation times out when drive advertises that
-                * capability, even if avdma code is forcibly disabled.
                 */
                sc->sc_minsync = 0;
+
+               sc->sc_maxxfer = 8 * 1024;
        }
 
-       if (!quick && !avdma)
-               sc->sc_maxxfer = 8 * 1024;
-
        /*
         * Configure interrupts.
         */
@@ -354,7 +354,6 @@
                int orsegs, irsegs;
 
                esc->sc_rset = 0;
-               esc->sc_pio = 0;
                esc->sc_dmat = oa->oa_dmat;
 
                if (bus_dmamap_create(esc->sc_dmat, sc->sc_maxxfer, 1,
@@ -365,43 +364,50 @@
                }
 
                /*
-                * Allocate memory which is friendly to the DMA engine
-                * (16-byte aligned) for use as the SCSI message buffers.
-                *
-                * XXX
-                * We need two buffers here. Since bus_dmamem_map(9) for
-                * m68k round size into NBPG.
+                * Allocate ``bounce'' buffers which satisfy constraints
+                * required by PSC, see esp_av_dma_setup().
                 */
                if (bus_dmamem_alloc(esc->sc_dmat, NBPG, 16, NBPG,
                    &osegs, 1, &orsegs, BUS_DMA_NOWAIT)) {
-                       printf("failed to allocate omess buffer.\n");
+                       printf("failed to allocate o-bounce buffer.\n");
                        goto out1;
                }
                if (bus_dmamem_map(esc->sc_dmat, &osegs, orsegs,
-                   NCR_MAX_MSG_LEN, (void **)&sc->sc_omess,
+                   NBPG, (void **)&esc->sc_obuf,
                    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) {
-                       printf("failed to map omess buffer.\n");
+                       printf("failed to map o-bounce buffer.\n");
                        goto out2;
                }
-
                if (bus_dmamem_alloc(esc->sc_dmat, NBPG, 16, NBPG,
                    &isegs, 1, &irsegs, BUS_DMA_NOWAIT)) {
-                       printf("failed to allocate imess buffer.\n");
+                       printf("failed to allocate i-bounce buffer.\n");
                        goto out3;
                }
                if (bus_dmamem_map(esc->sc_dmat, &isegs, irsegs,
-                   NCR_MAX_MSG_LEN + 1, (void **)&sc->sc_imess,
+                   NBPG, (void **)&esc->sc_ibuf,
                    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) {
-                       printf("failed to map imess buffer.\n");
+                       printf("failed to map i-bounce buffer.\n");
 
                        bus_dmamem_free(esc->sc_dmat, &isegs, irsegs);
-               out3:   bus_dmamem_unmap(esc->sc_dmat, sc->sc_omess, NBPG);
-               out2:   bus_dmamem_free(esc->sc_dmat, &osegs, orsegs);
-               out1:   bus_dmamap_destroy(esc->sc_dmat, esc->sc_dmap);
+ out3:                 bus_dmamem_unmap(esc->sc_dmat, sc->sc_omess,
+                           sc->sc_maxxfer);
+ out2:                 bus_dmamem_free(esc->sc_dmat, &osegs, orsegs);
+ out1:                 bus_dmamap_destroy(esc->sc_dmat, esc->sc_dmap);
                        return;
                }
        }
 
+#if 0
+       /*
+        * This degrades performance; FIFO is better than bounce DMA for
+        * short SCSI commands and their responses.
+        */
+       if (avdma) {
+               /* Turn on target selection using the `DMA' method */
+               sc->sc_features |= NCR_F_DMASELECT;
+       }
+#endif
+
        /*
         * Now try to attach all the sub-devices
         */
@@ -569,7 +575,7 @@
 }
 
 static void
-esp_quick_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t val)
+esp_dma_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t val)
 {
        struct esp_softc *esc = (struct esp_softc *)sc;
 
@@ -984,29 +990,16 @@
 }
 
 static void
-esp_av_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t val)
-{
-       struct esp_softc *esc = (struct esp_softc *)sc;
-       uint8_t v;
-
-       if (esc->sc_pio && reg == NCR_CMD && val == (NCRCMD_TRANS|NCRCMD_DMA))
-               v = NCRCMD_TRANS;
-       else
-               v = val;
-       esc->sc_reg[reg * 16] = v;
-}
-
-static void
 esp_av_dma_reset(struct ncr53c9x_softc *sc)
 {
        struct esp_softc *esc = (struct esp_softc *)sc;
        uint32_t res;
 
-       if(esc->sc_active && !esc->sc_pio)
+       if (esc->sc_active)
                stop_psc_dma(PSC_DMA_CHANNEL_SCSI, esc->sc_rset, &res,
                    esc->sc_datain);
 
-       esc->sc_active = esc->sc_tc = 0;
+       esc->sc_active = 0;
 }
 
 static int
@@ -1014,14 +1007,10 @@
 {
        struct esp_softc *esc = (struct esp_softc *)sc;
        uint32_t resid;
-       int trans, fifo_count;
+       int trans;
 
        KASSERT(esc->sc_active);
 
-       /* Deal with any PIO transfers */
-       if (esc->sc_pio)
-               return esp_av_pio_intr(sc);
-
 #if DEBUG
        int tc_size;
        tc_size = NCR_READ_REG(sc, NCR_TCM);
@@ -1035,51 +1024,41 @@
 
        if (esc->sc_dmasize == 0) {
                /* A "Transfer Pad" operation completed */
+#if DEBUG
+               printf("%s: TRPAD done\n", __func__);
+#endif
                return 0;
        }
 
+#if 0
+       /*
+        * XXXRO dead code
+        * Left unremoved for reference how to use wait_psc_dma().
+        */
        if ((sc->sc_espintr & NCRINTR_BS) && (sc->sc_espstat & NCRSTAT_TC)) {
                /* Wait for engine to finish the transfer */
                wait_psc_dma(PSC_DMA_CHANNEL_SCSI, esc->sc_rset, &resid);
-#if DEBUG 
+#  if DEBUG
                printf("[av_dma_intr: DMA %s done]\n", esc->sc_datain ?
                    "read" : "write");
+#  endif
+       }
 #endif
-       }
 
        /* Halt the DMA engine */
        stop_psc_dma(PSC_DMA_CHANNEL_SCSI, esc->sc_rset, &resid,
            esc->sc_datain);
+
+#if DEBUG
+       printf("[av_dma_intr: DMA resid %u]\n", resid);
+#endif
        
        bus_dmamap_sync(esc->sc_dmat, esc->sc_dmap, 0, esc->sc_dmasize,
            esc->sc_datain ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
        bus_dmamap_unload(esc->sc_dmat, esc->sc_dmap);
 
-       /* On read, bytes in the FIFO count as residual */
-       if (esc->sc_datain) {
-               fifo_count = (int)(NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF);
-               resid += fifo_count;
-               if (fifo_count) {
-                       /*
-                        * Flush those bytes since we don't know
-                        * what state they were in.
-                        */
-                       NCRCMD(sc, NCRCMD_FLUSH);
-#if DEBUG 
-                       printf("[av_dma_intr: flushed %d bytes from FIFO]\n",
-                           fifo_count) ;
-#endif
-               }
-       }
-
        trans = esc->sc_dmasize - resid;
-       if (trans < 0) {
-               /*
-                * XXXRO
-                * This situation can happen in perfectly normal operation
-                * if the ESP is reselected while using DMA to select
-                * another target.  As such, don't print the warning.
-                */
+       if (__predict_false(trans < 0)) {
 #if DEBUG
                printf("[av_dma_intr: xfer (%d) > req (%zu)]\n",
                    trans, esc->sc_dmasize);
@@ -1092,102 +1071,13 @@
            esc->sc_datain ? "read" : "write", trans, resid);



Home | Main Index | Thread Index | Old Index