1 /* $NetBSD: dma.c,v 1.5 1997/06/26 02:47:09 jeremy 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/types.h> 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/errno.h> 38 #include <sys/ioctl.h> 39 #include <sys/device.h> 40 #include <sys/malloc.h> 41 #include <sys/buf.h> 42 #include <sys/proc.h> 43 #include <sys/user.h> 44 45 #include <machine/autoconf.h> 46 #include <machine/dvma.h> 47 48 #include <scsi/scsi_all.h> 49 #include <scsi/scsiconf.h> 50 51 #include <dev/ic/ncr53c9xreg.h> 52 #include <dev/ic/ncr53c9xvar.h> 53 54 #include <sun3x/dev/dmareg.h> 55 #include <sun3x/dev/dmavar.h> 56 57 /* 58 * Pseudo-attach function. Called from the esp driver during its 59 * attach function. This needs to be silent. 60 */ 61 void 62 dmaattach(parent, self, aux) 63 struct device *parent, *self; 64 void *aux; 65 { 66 struct dma_softc *sc = (void *)self; 67 68 /* 69 * The esp driver has filled in the virtual address used to 70 * address the dma registers at this point. Normally we would 71 * map them in here and assign them ourselves. 72 * 73 * It has also filled itself in to our sc->sc_esp register. 74 */ 75 76 /* 77 * Get transfer burst size from PROM and plug it into the 78 * controller registers. This is needed on the Sun4m; do 79 * others need it too? 80 * 81 * Sun3x works ok (so far) without it. 82 */ 83 84 sc->sc_rev = sc->sc_regs->csr & D_DEV_ID; 85 86 #if 0 87 /* indirect functions */ 88 sc->intr = espdmaintr; 89 sc->enintr = dma_enintr; 90 sc->isintr = dma_isintr; 91 sc->reset = dma_reset; 92 sc->setup = dma_setup; 93 sc->go = dma_go; 94 #endif 95 } 96 97 void 98 dma_print_rev(sc) 99 struct dma_softc *sc; 100 { 101 102 printf("espdma: rev "); 103 switch (sc->sc_rev) { 104 case DMAREV_0: 105 printf("0"); 106 break; 107 case DMAREV_ESC: 108 printf("esc"); 109 break; 110 case DMAREV_1: 111 printf("1"); 112 break; 113 case DMAREV_PLUS: 114 printf("1+"); 115 break; 116 case DMAREV_2: 117 printf("2"); 118 break; 119 default: 120 printf("unknown (0x%x)", sc->sc_rev); 121 } 122 printf("\n"); 123 } 124 125 126 #define DMAWAIT(SC, COND, MSG, DONTPANIC) do if (COND) { \ 127 int count = 500000; \ 128 while ((COND) && --count > 0) DELAY(1); \ 129 if (count == 0) { \ 130 printf("%s: line %d: CSR = %lx\n", __FILE__, __LINE__, \ 131 (SC)->sc_regs->csr); \ 132 if (DONTPANIC) \ 133 printf(MSG); \ 134 else \ 135 panic(MSG); \ 136 } \ 137 } while (0) 138 139 #define DMA_DRAIN(sc, dontpanic) do { \ 140 /* \ 141 * DMA rev0 & rev1: we are not allowed to touch the DMA "flush" \ 142 * and "drain" bits while it is still thinking about a \ 143 * request. \ 144 * other revs: D_R_PEND bit reads as 0 \ 145 */ \ 146 DMAWAIT(sc, sc->sc_regs->csr & D_R_PEND, "R_PEND", dontpanic); \ 147 /* \ 148 * Select drain bit based on revision \ 149 * also clears errors and D_TC flag \ 150 */ \ 151 if (sc->sc_rev == DMAREV_1 || sc->sc_rev == DMAREV_0) \ 152 DMACSR(sc) |= D_DRAIN; \ 153 else \ 154 DMACSR(sc) |= D_INVALIDATE; \ 155 /* \ 156 * Wait for draining to finish \ 157 * rev0 & rev1 call this PACKCNT \ 158 */ \ 159 DMAWAIT(sc, sc->sc_regs->csr & D_DRAINING, "DRAINING", dontpanic);\ 160 } while(0) 161 162 void 163 dma_reset(sc) 164 struct dma_softc *sc; 165 { 166 DMA_DRAIN(sc, 1); 167 DMACSR(sc) &= ~D_EN_DMA; /* Stop DMA */ 168 DMACSR(sc) |= D_RESET; /* reset DMA */ 169 DELAY(200); /* what should this be ? */ 170 /*DMAWAIT1(sc); why was this here? */ 171 DMACSR(sc) &= ~D_RESET; /* de-assert reset line */ 172 DMACSR(sc) |= D_INT_EN; /* enable interrupts */ 173 174 sc->sc_active = 0; /* and of course we aren't */ 175 } 176 177 178 void 179 dma_enintr(sc) 180 struct dma_softc *sc; 181 { 182 sc->sc_regs->csr |= D_INT_EN; 183 } 184 185 int 186 dma_isintr(sc) 187 struct dma_softc *sc; 188 { 189 return (sc->sc_regs->csr & (D_INT_PEND|D_ERR_PEND)); 190 } 191 192 #define DMAMAX(a) (0x01000000 - ((a) & 0x00ffffff)) 193 194 195 /* 196 * setup a dma transfer 197 */ 198 int 199 dma_setup(sc, addr, len, datain, dmasize) 200 struct dma_softc *sc; 201 caddr_t *addr; 202 size_t *len; 203 int datain; 204 size_t *dmasize; /* IN-OUT */ 205 { 206 u_long csr; 207 208 DMA_DRAIN(sc, 0); 209 210 #if 0 211 DMACSR(sc) &= ~D_INT_EN; 212 #endif 213 sc->sc_dmaaddr = addr; 214 sc->sc_dmalen = len; 215 216 NCR_DMA(("%s: start %d@%p,%d\n", sc->sc_dev.dv_xname, 217 *sc->sc_dmalen, *sc->sc_dmaaddr, datain ? 1 : 0)); 218 219 /* 220 * the rules say we cannot transfer more than the limit 221 * of this DMA chip (64k for old and 16Mb for new), 222 * and we cannot cross a 16Mb boundary. 223 */ 224 *dmasize = sc->sc_dmasize = 225 min(*dmasize, DMAMAX((size_t) *sc->sc_dmaaddr)); 226 227 NCR_DMA(("dma_setup: dmasize = %d\n", sc->sc_dmasize)); 228 229 /* Program the DMA address */ 230 if (sc->sc_dmasize) { 231 /* 232 * Use dvma mapin routines to map the buffer into DVMA space. 233 */ 234 sc->sc_dvmaaddr = *sc->sc_dmaaddr; 235 sc->sc_dvmakaddr = dvma_mapin(sc->sc_dvmaaddr, 236 sc->sc_dmasize, 0); 237 if (sc->sc_dvmakaddr == NULL) 238 panic("dma: cannot allocate DVMA address"); 239 sc->sc_dmasaddr = dvma_kvtopa(sc->sc_dvmakaddr, BUS_OBIO); 240 DMADDR(sc) = sc->sc_dmasaddr; 241 } else 242 DMADDR(sc) = (u_long) *sc->sc_dmaaddr; 243 244 if (sc->sc_rev == DMAREV_ESC) { 245 /* DMA ESC chip bug work-around */ 246 register long bcnt = sc->sc_dmasize; 247 register long eaddr = bcnt + (long)*sc->sc_dmaaddr; 248 if ((eaddr & PGOFSET) != 0) 249 bcnt = roundup(bcnt, NBPG); 250 DMACNT(sc) = bcnt; 251 } 252 /* Setup DMA control register */ 253 csr = DMACSR(sc); 254 if (datain) 255 csr |= D_WRITE; 256 else 257 csr &= ~D_WRITE; 258 csr |= D_INT_EN; 259 DMACSR(sc) = csr; 260 261 return 0; 262 } 263 264 void 265 dma_go(sc) 266 struct dma_softc *sc; 267 { 268 269 /* Start DMA */ 270 DMACSR(sc) |= D_EN_DMA; 271 sc->sc_active = 1; 272 } 273 274 /* 275 * Pseudo (chained) interrupt from the esp driver to kick the 276 * current running DMA transfer. I am replying on espintr() to 277 * pickup and clean errors for now 278 * 279 * return 1 if it was a DMA continue. 280 */ 281 int 282 espdmaintr(sc) 283 struct dma_softc *sc; 284 { 285 struct ncr53c9x_softc *nsc = sc->sc_esp; 286 char bits[64]; 287 int trans, resid; 288 u_long csr; 289 csr = DMACSR(sc); 290 291 NCR_DMA(("%s: intr: addr %x, csr %s\n", 292 sc->sc_dev.dv_xname, DMADDR(sc), 293 bitmask_snprintf(csr, DMACSRBITS, bits, sizeof(bits)))); 294 295 if (csr & D_ERR_PEND) { 296 DMACSR(sc) &= ~D_EN_DMA; /* Stop DMA */ 297 DMACSR(sc) |= D_INVALIDATE; 298 printf("%s: error: csr=%s\n", sc->sc_dev.dv_xname, 299 bitmask_snprintf(csr, DMACSRBITS, bits, sizeof(bits))); 300 return -1; 301 } 302 303 /* This is an "assertion" :) */ 304 if (sc->sc_active == 0) 305 panic("dmaintr: DMA wasn't active"); 306 307 DMA_DRAIN(sc, 0); 308 309 /* DMA has stopped */ 310 DMACSR(sc) &= ~D_EN_DMA; 311 sc->sc_active = 0; 312 313 if (sc->sc_dmasize == 0) { 314 /* A "Transfer Pad" operation completed */ 315 NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n", 316 NCR_READ_REG(nsc, NCR_TCL) | 317 (NCR_READ_REG(nsc, NCR_TCM) << 8), 318 NCR_READ_REG(nsc, NCR_TCL), 319 NCR_READ_REG(nsc, NCR_TCM))); 320 return 0; 321 } 322 323 resid = 0; 324 /* 325 * If a transfer onto the SCSI bus gets interrupted by the device 326 * (e.g. for a SAVEPOINTER message), the data in the FIFO counts 327 * as residual since the ESP counter registers get decremented as 328 * bytes are clocked into the FIFO. 329 */ 330 if (!(csr & D_WRITE) && 331 (resid = (NCR_READ_REG(nsc, NCR_FFLAG) & NCRFIFO_FF)) != 0) { 332 NCR_DMA(("dmaintr: empty esp FIFO of %d ", resid)); 333 } 334 335 if ((nsc->sc_espstat & NCRSTAT_TC) == 0) { 336 /* 337 * `Terminal count' is off, so read the residue 338 * out of the ESP counter registers. 339 */ 340 resid += (NCR_READ_REG(nsc, NCR_TCL) | 341 (NCR_READ_REG(nsc, NCR_TCM) << 8) | 342 ((nsc->sc_cfg2 & NCRCFG2_FE) 343 ? (NCR_READ_REG(nsc, NCR_TCH) << 16) 344 : 0)); 345 346 if (resid == 0 && sc->sc_dmasize == 65536 && 347 (nsc->sc_cfg2 & NCRCFG2_FE) == 0) 348 /* A transfer of 64K is encoded as `TCL=TCM=0' */ 349 resid = 65536; 350 } 351 352 trans = sc->sc_dmasize - resid; 353 if (trans < 0) { /* transferred < 0 ? */ 354 #if 0 355 /* 356 * This situation can happen in perfectly normal operation 357 * if the ESP is reselected while using DMA to select 358 * another target. As such, don't print the warning. 359 */ 360 printf("%s: xfer (%d) > req (%d)\n", 361 sc->sc_dev.dv_xname, trans, sc->sc_dmasize); 362 #endif 363 trans = sc->sc_dmasize; 364 } 365 366 NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n", 367 NCR_READ_REG(nsc, NCR_TCL), 368 NCR_READ_REG(nsc, NCR_TCM), 369 (nsc->sc_cfg2 & NCRCFG2_FE) 370 ? NCR_READ_REG(nsc, NCR_TCH) : 0, 371 trans, resid)); 372 373 #ifdef SUN3X_470_EVENTUALLY 374 if (csr & D_WRITE) 375 cache_flush(*sc->sc_dmaaddr, trans); 376 #endif 377 378 if (sc->sc_dvmakaddr) 379 dvma_mapout(sc->sc_dvmakaddr, sc->sc_dmasize); 380 381 *sc->sc_dmalen -= trans; 382 *sc->sc_dmaaddr += trans; 383 384 #if 0 /* this is not normal operation just yet */ 385 if (*sc->sc_dmalen == 0 || 386 nsc->sc_phase != nsc->sc_prevphase) 387 return 0; 388 389 /* and again */ 390 dma_start(sc, sc->sc_dmaaddr, sc->sc_dmalen, DMACSR(sc) & D_WRITE); 391 return 1; 392 #endif 393 return 0; 394 } 395