1 /* $NetBSD: dma.c,v 1.25 2024/12/20 23:52:00 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Paul Kranenburg. All rights reserved. 5 * Copyright (c) 1994 Peter Galbavy. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Peter Galbavy. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: dma.c,v 1.25 2024/12/20 23:52:00 tsutsui Exp $"); 35 36 #include <sys/types.h> 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/errno.h> 41 #include <sys/device.h> 42 43 #include <machine/autoconf.h> 44 #include <machine/dvma.h> 45 46 #include <dev/scsipi/scsi_all.h> 47 #include <dev/scsipi/scsipi_all.h> 48 #include <dev/scsipi/scsiconf.h> 49 50 #include <dev/ic/ncr53c9xreg.h> 51 #include <dev/ic/ncr53c9xvar.h> 52 53 #include <sun3/dev/dmareg.h> 54 #include <sun3/dev/dmavar.h> 55 56 #include "ioconf.h" 57 58 #define MAX_DMA_SZ 0x01000000 /* 16MB */ 59 60 static int dmamatch(device_t, cfdata_t, void *); 61 static void dmaattach(device_t, device_t, void *); 62 63 CFATTACH_DECL_NEW(dma, sizeof(struct dma_softc), 64 dmamatch, dmaattach, NULL, NULL); 65 66 static int 67 dmamatch(device_t parent, cfdata_t cf, void *aux) 68 { 69 struct confargs *ca = aux; 70 71 /* 72 * Check for the DMA registers. 73 */ 74 if (bus_peek(ca->ca_bustype, ca->ca_paddr, 4) == -1) 75 return 0; 76 77 /* If default ipl, fill it in. */ 78 if (ca->ca_intpri == -1) 79 ca->ca_intpri = 2; 80 81 return 1; 82 } 83 84 static void 85 dmaattach(device_t parent, device_t self, void *aux) 86 { 87 struct dma_softc *sc = device_private(self); 88 struct confargs *ca = aux; 89 int id; 90 91 sc->sc_dev = self; 92 93 #if 0 94 /* indirect functions */ 95 sc->intr = espdmaintr; 96 sc->setup = dma_setup; 97 sc->reset = dma_reset; 98 #endif 99 100 /* 101 * Map in the registers. 102 */ 103 sc->sc_bst = ca->ca_bustag; 104 sc->sc_dmatag = ca->ca_dmatag; 105 if (bus_space_map(sc->sc_bst, ca->ca_paddr, DMAREG_SIZE, 106 0, &sc->sc_bsh) != 0) { 107 aprint_error(": can't map register\n"); 108 return; 109 } 110 /* 111 * Allocate dmamap. 112 */ 113 if (bus_dmamap_create(sc->sc_dmatag, MAXPHYS, 1, MAXPHYS, 114 0, BUS_DMA_NOWAIT, &sc->sc_dmamap) != 0) { 115 aprint_error(": can't create DMA map\n"); 116 return; 117 } 118 119 sc->sc_rev = DMA_GCSR(sc) & D_DEV_ID; 120 id = (sc->sc_rev >> 28) & 0xf; 121 aprint_normal(": rev %d\n", id); 122 123 /* 124 * Make sure the DMA chip is supported revision. 125 * The Sun3/80 used only the old rev zero chip, 126 * so the initialization has been simplified. 127 */ 128 switch (sc->sc_rev) { 129 case DMAREV_0: 130 case DMAREV_1: 131 break; 132 default: 133 panic("unsupported dma rev"); 134 } 135 } 136 137 /* 138 * This is called by espattach to get our softc. 139 */ 140 struct dma_softc * 141 espdmafind(int unit) 142 { 143 struct dma_softc *dma; 144 145 dma = device_lookup_private(&dma_cd, unit); 146 if (dma == NULL) 147 panic("%s: no dma", __func__); 148 return dma; 149 } 150 151 #define DMAWAIT(SC, COND, MSG, DONTPANIC) do if (COND) { \ 152 int count = 100000; \ 153 while ((COND) && --count > 0) \ 154 DELAY(5); \ 155 if (count == 0) { \ 156 printf("%s: line %d: CSR = 0x%x\n", \ 157 __FILE__, __LINE__, DMA_GCSR(SC)); \ 158 if (DONTPANIC) \ 159 printf(MSG); \ 160 else \ 161 panic(MSG); \ 162 } \ 163 } while (/* CONSTCOND */0) 164 165 #define DMA_DRAIN(sc, dontpanic) do { \ 166 uint32_t _csr; \ 167 /* \ 168 * DMA rev0 & rev1: we are not allowed to touch the DMA "flush" \ 169 * and "drain" bits while it is still thinking about a \ 170 * request. \ 171 * other revs: D_R_PEND bit reads as 0 \ 172 */ \ 173 DMAWAIT(sc, DMA_GCSR(sc) & D_R_PEND, "R_PEND", dontpanic); \ 174 /* \ 175 * Select drain bit (always rev 0,1) \ 176 * also clears errors and D_TC flag \ 177 */ \ 178 _csr = DMA_GCSR(sc); \ 179 _csr |= D_DRAIN; \ 180 DMA_SCSR(sc, _csr); \ 181 /* \ 182 * Wait for draining to finish \ 183 */ \ 184 DMAWAIT(sc, DMA_GCSR(sc) & D_PACKCNT, "DRAINING", dontpanic); \ 185 } while (/* CONSTCOND */0) 186 187 #define DMA_FLUSH(sc, dontpanic) do { \ 188 uint32_t _csr; \ 189 /* \ 190 * DMA rev0 & rev1: we are not allowed to touch the DMA "flush" \ 191 * and "drain" bits while it is still thinking about a \ 192 * request. \ 193 * other revs: D_R_PEND bit reads as 0 \ 194 */ \ 195 DMAWAIT(sc, DMA_GCSR(sc) & D_R_PEND, "R_PEND", dontpanic); \ 196 _csr = DMA_GCSR(sc); \ 197 _csr &= ~(D_WRITE|D_EN_DMA); \ 198 DMA_SCSR(sc, _csr); \ 199 _csr |= D_FLUSH; \ 200 DMA_SCSR(sc, _csr); \ 201 } while (/* CONSTCOND */0) 202 203 void 204 dma_reset(struct dma_softc *sc) 205 { 206 uint32_t csr; 207 208 if (sc->sc_dmamap->dm_nsegs > 0) 209 bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap); 210 211 DMA_FLUSH(sc, 1); 212 csr = DMA_GCSR(sc); 213 214 csr |= D_RESET; /* reset DMA */ 215 DMA_SCSR(sc, csr); 216 DELAY(200); /* what should this be ? */ 217 218 /*DMAWAIT1(sc); why was this here? */ 219 csr = DMA_GCSR(sc); 220 csr &= ~D_RESET; /* de-assert reset line */ 221 DMA_SCSR(sc, csr); 222 DELAY(5); /* allow a few ticks to settle */ 223 224 /* 225 * Get transfer burst size from (?) and plug it into the 226 * controller registers. This is needed on the Sun4m... 227 * Do we need it too? Apparently not, because the 3/80 228 * always has the old, REV zero DMA chip. 229 */ 230 csr = DMA_GCSR(sc); 231 csr |= D_INT_EN; /* enable interrupts */ 232 233 DMA_SCSR(sc, csr); 234 235 sc->sc_active = 0; 236 } 237 238 239 #define DMAMAX(a) (MAX_DMA_SZ - ((a) & (MAX_DMA_SZ-1))) 240 241 /* 242 * setup a dma transfer 243 */ 244 int 245 dma_setup(struct dma_softc *sc, uint8_t **addr, size_t *len, int datain, 246 size_t *dmasize) 247 { 248 uint32_t csr; 249 250 DMA_FLUSH(sc, 0); 251 252 #if 0 253 DMA_SCSR(sc, DMA_GCSR(sc) & ~D_INT_EN); 254 #endif 255 sc->sc_dmaaddr = addr; 256 sc->sc_dmalen = len; 257 258 NCR_DMA(("%s: start %d@%p,%d\n", device_xname(sc->sc_dev), 259 *sc->sc_dmalen, *sc->sc_dmaaddr, datain ? 1 : 0)); 260 261 /* 262 * the rules say we cannot transfer more than the limit 263 * of this DMA chip (64k for old and 16Mb for new), 264 * and we cannot cross a 16Mb boundary. 265 */ 266 *dmasize = sc->sc_dmasize = 267 uimin(*dmasize, DMAMAX((size_t) *sc->sc_dmaaddr)); 268 269 NCR_DMA(("%s: dmasize = %d\n", __func__, sc->sc_dmasize)); 270 271 /* Program the DMA address */ 272 if (sc->sc_dmasize) { 273 if (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap, 274 *sc->sc_dmaaddr, sc->sc_dmasize, 275 NULL /* kernel address */, BUS_DMA_NOWAIT)) 276 panic("%s: cannot allocate DVMA address", 277 device_xname(sc->sc_dev)); 278 bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, 0, sc->sc_dmasize, 279 datain ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 280 bus_space_write_4(sc->sc_bst, sc->sc_bsh, DMA_REG_ADDR, 281 sc->sc_dmamap->dm_segs[0].ds_addr); 282 } 283 284 /* We never have DMAREV_ESC. */ 285 286 /* Setup DMA control register */ 287 csr = DMA_GCSR(sc); 288 if (datain) 289 csr |= D_WRITE; 290 else 291 csr &= ~D_WRITE; 292 csr |= D_INT_EN; 293 DMA_SCSR(sc, csr); 294 295 return 0; 296 } 297 298 /* 299 * Pseudo (chained) interrupt from the esp driver to kick the 300 * current running DMA transfer. I am relying on espintr() to 301 * pickup and clean errors for now 302 * 303 * return 1 if it was a DMA continue. 304 */ 305 int 306 espdmaintr(struct dma_softc *sc) 307 { 308 struct ncr53c9x_softc *nsc = sc->sc_client; 309 char bits[64]; 310 int trans, resid; 311 uint32_t csr; 312 313 csr = DMA_GCSR(sc); 314 315 #ifdef NCR53C9X_DEBUG 316 if (ncr53c9x_debug & NCR_SHOWDMA) 317 snprintb(bits, sizeof(bits), DMACSRBITS, csr); 318 #endif 319 NCR_DMA(("%s: intr: addr 0x%x, csr %s\n", 320 device_xname(sc->sc_dev), DMADDR(sc), bits)); 321 322 if (csr & D_ERR_PEND) { 323 snprintb(bits, sizeof(bits), DMACSRBITS, csr); 324 printf("%s: error: csr=%s\n", device_xname(sc->sc_dev), bits); 325 csr &= ~D_EN_DMA; /* Stop DMA */ 326 DMA_SCSR(sc, csr); 327 csr |= D_FLUSH; 328 DMA_SCSR(sc, csr); 329 return -1; 330 } 331 332 /* This is an "assertion" :) */ 333 if (sc->sc_active == 0) 334 panic("%s: DMA wasn't active", __func__); 335 336 DMA_DRAIN(sc, 0); 337 338 /* DMA has stopped */ 339 csr &= ~D_EN_DMA; 340 DMA_SCSR(sc, csr); 341 sc->sc_active = 0; 342 343 if (sc->sc_dmasize == 0) { 344 /* A "Transfer Pad" operation completed */ 345 NCR_DMA(("%s: discarded %d bytes (tcl=%d, tcm=%d)\n", 346 __func__, 347 NCR_READ_REG(nsc, NCR_TCL) | 348 (NCR_READ_REG(nsc, NCR_TCM) << 8), 349 NCR_READ_REG(nsc, NCR_TCL), 350 NCR_READ_REG(nsc, NCR_TCM))); 351 return 0; 352 } 353 354 resid = 0; 355 /* 356 * If a transfer onto the SCSI bus gets interrupted by the device 357 * (e.g. for a SAVEPOINTER message), the data in the FIFO counts 358 * as residual since the ESP counter registers get decremented as 359 * bytes are clocked into the FIFO. 360 */ 361 if (!(csr & D_WRITE) && 362 (resid = (NCR_READ_REG(nsc, NCR_FFLAG) & NCRFIFO_FF)) != 0) { 363 NCR_DMA(("%s: empty esp FIFO of %d ", __func__, resid)); 364 } 365 366 if ((nsc->sc_espstat & NCRSTAT_TC) == 0) { 367 /* 368 * `Terminal count' is off, so read the residue 369 * out of the ESP counter registers. 370 */ 371 resid += (NCR_READ_REG(nsc, NCR_TCL) | 372 (NCR_READ_REG(nsc, NCR_TCM) << 8) | 373 ((nsc->sc_cfg2 & NCRCFG2_FE) ? 374 (NCR_READ_REG(nsc, NCR_TCH) << 16) : 0)); 375 376 if (resid == 0 && sc->sc_dmasize == 65536 && 377 (nsc->sc_cfg2 & NCRCFG2_FE) == 0) 378 /* A transfer of 64K is encoded as `TCL=TCM=0' */ 379 resid = 65536; 380 } 381 382 trans = sc->sc_dmasize - resid; 383 if (trans < 0) { /* transferred < 0 ? */ 384 #if 0 385 /* 386 * This situation can happen in perfectly normal operation 387 * if the ESP is reselected while using DMA to select 388 * another target. As such, don't print the warning. 389 */ 390 printf("%s: xfer (%d) > req (%d)\n", 391 device_xname(sc->sc_dev), trans, sc->sc_dmasize); 392 #endif 393 trans = sc->sc_dmasize; 394 } 395 396 NCR_DMA(("%s: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n", 397 __func__, 398 NCR_READ_REG(nsc, NCR_TCL), 399 NCR_READ_REG(nsc, NCR_TCM), 400 (nsc->sc_cfg2 & NCRCFG2_FE) ? 401 NCR_READ_REG(nsc, NCR_TCH) : 0, 402 trans, resid)); 403 404 #ifdef SUN3X_470_EVENTUALLY 405 if (csr & D_WRITE) 406 cache_flush(*sc->sc_dmaaddr, trans); 407 #endif 408 409 if (sc->sc_dmamap->dm_nsegs > 0) { 410 bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, 0, sc->sc_dmasize, 411 (csr & D_WRITE) != 0 ? 412 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 413 bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap); 414 } 415 416 *sc->sc_dmalen -= trans; 417 *sc->sc_dmaaddr += trans; 418 419 #if 0 /* this is not normal operation just yet */ 420 if (*sc->sc_dmalen == 0 || 421 nsc->sc_phase != nsc->sc_prevphase) 422 return 0; 423 424 /* and again */ 425 dma_start(sc, sc->sc_dmaaddr, sc->sc_dmalen, DMA_GCSR(sc) & D_WRITE); 426 return 1; 427 #endif 428 return 0; 429 } 430