1 1.18 maxv /* $NetBSD: iopaau.c,v 1.18 2019/03/17 06:36:22 maxv Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.1 thorpej * Copyright (c) 2002 Wasabi Systems, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 1.1 thorpej * 9 1.1 thorpej * Redistribution and use in source and binary forms, with or without 10 1.1 thorpej * modification, are permitted provided that the following conditions 11 1.1 thorpej * are met: 12 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 13 1.1 thorpej * notice, this list of conditions and the following disclaimer. 14 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 16 1.1 thorpej * documentation and/or other materials provided with the distribution. 17 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 18 1.1 thorpej * must display the following acknowledgement: 19 1.1 thorpej * This product includes software developed for the NetBSD Project by 20 1.1 thorpej * Wasabi Systems, Inc. 21 1.1 thorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 thorpej * or promote products derived from this software without specific prior 23 1.1 thorpej * written permission. 24 1.1 thorpej * 25 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 36 1.1 thorpej */ 37 1.1 thorpej 38 1.1 thorpej /* 39 1.1 thorpej * Common code for XScale-based I/O Processor Application Accelerator 40 1.1 thorpej * Unit support. 41 1.1 thorpej * 42 1.1 thorpej * The AAU provides a back-end for the dmover(9) facility. 43 1.1 thorpej */ 44 1.1 thorpej 45 1.1 thorpej #include <sys/cdefs.h> 46 1.18 maxv __KERNEL_RCSID(0, "$NetBSD: iopaau.c,v 1.18 2019/03/17 06:36:22 maxv Exp $"); 47 1.1 thorpej 48 1.1 thorpej #include <sys/param.h> 49 1.1 thorpej #include <sys/pool.h> 50 1.1 thorpej #include <sys/systm.h> 51 1.1 thorpej #include <sys/device.h> 52 1.1 thorpej #include <sys/uio.h> 53 1.16 ad #include <sys/bus.h> 54 1.1 thorpej 55 1.1 thorpej #include <uvm/uvm.h> 56 1.1 thorpej 57 1.1 thorpej #include <arm/xscale/iopaaureg.h> 58 1.1 thorpej #include <arm/xscale/iopaauvar.h> 59 1.1 thorpej 60 1.1 thorpej #ifdef AAU_DEBUG 61 1.1 thorpej #define DPRINTF(x) printf x 62 1.1 thorpej #else 63 1.1 thorpej #define DPRINTF(x) /* nothing */ 64 1.1 thorpej #endif 65 1.1 thorpej 66 1.14 ad pool_cache_t iopaau_desc_4_cache; 67 1.14 ad pool_cache_t iopaau_desc_8_cache; 68 1.1 thorpej 69 1.1 thorpej /* 70 1.1 thorpej * iopaau_desc_ctor: 71 1.1 thorpej * 72 1.1 thorpej * Constructor for all types of descriptors. 73 1.1 thorpej */ 74 1.1 thorpej static int 75 1.1 thorpej iopaau_desc_ctor(void *arg, void *object, int flags) 76 1.1 thorpej { 77 1.1 thorpej struct aau_desc_4 *d = object; 78 1.1 thorpej 79 1.1 thorpej /* 80 1.1 thorpej * Cache the physical address of the hardware portion of 81 1.1 thorpej * the descriptor in the software portion of the descriptor 82 1.1 thorpej * for quick reference later. 83 1.1 thorpej */ 84 1.9 thorpej d->d_pa = vtophys((vaddr_t)d) + SYNC_DESC_4_OFFSET; 85 1.1 thorpej KASSERT((d->d_pa & 31) == 0); 86 1.1 thorpej return (0); 87 1.1 thorpej } 88 1.1 thorpej 89 1.1 thorpej /* 90 1.5 thorpej * iopaau_desc_free: 91 1.1 thorpej * 92 1.5 thorpej * Free a chain of AAU descriptors. 93 1.1 thorpej */ 94 1.1 thorpej void 95 1.5 thorpej iopaau_desc_free(struct pool_cache *dc, void *firstdesc) 96 1.1 thorpej { 97 1.1 thorpej struct aau_desc_4 *d, *next; 98 1.1 thorpej 99 1.1 thorpej for (d = firstdesc; d != NULL; d = next) { 100 1.1 thorpej next = d->d_next; 101 1.5 thorpej pool_cache_put(dc, d); 102 1.1 thorpej } 103 1.1 thorpej } 104 1.1 thorpej 105 1.1 thorpej /* 106 1.1 thorpej * iopaau_start: 107 1.1 thorpej * 108 1.1 thorpej * Start an AAU request. Must be called at splbio(). 109 1.1 thorpej */ 110 1.1 thorpej static void 111 1.1 thorpej iopaau_start(struct iopaau_softc *sc) 112 1.1 thorpej { 113 1.1 thorpej struct dmover_backend *dmb = &sc->sc_dmb; 114 1.1 thorpej struct dmover_request *dreq; 115 1.1 thorpej struct iopaau_function *af; 116 1.1 thorpej int error; 117 1.1 thorpej 118 1.1 thorpej for (;;) { 119 1.1 thorpej 120 1.1 thorpej KASSERT(sc->sc_running == NULL); 121 1.1 thorpej 122 1.1 thorpej dreq = TAILQ_FIRST(&dmb->dmb_pendreqs); 123 1.1 thorpej if (dreq == NULL) 124 1.1 thorpej return; 125 1.1 thorpej 126 1.1 thorpej dmover_backend_remque(dmb, dreq); 127 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_RUNNING; 128 1.1 thorpej 129 1.1 thorpej sc->sc_running = dreq; 130 1.1 thorpej 131 1.1 thorpej /* XXXUNLOCK */ 132 1.1 thorpej 133 1.1 thorpej af = dreq->dreq_assignment->das_algdesc->dad_data; 134 1.1 thorpej error = (*af->af_setup)(sc, dreq); 135 1.1 thorpej 136 1.1 thorpej /* XXXLOCK */ 137 1.1 thorpej 138 1.1 thorpej if (error) { 139 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 140 1.1 thorpej dreq->dreq_error = error; 141 1.1 thorpej sc->sc_running = NULL; 142 1.1 thorpej /* XXXUNLOCK */ 143 1.1 thorpej dmover_done(dreq); 144 1.1 thorpej /* XXXLOCK */ 145 1.1 thorpej continue; 146 1.1 thorpej } 147 1.1 thorpej 148 1.1 thorpej #ifdef DIAGNOSTIC 149 1.1 thorpej if (bus_space_read_4(sc->sc_st, sc->sc_sh, AAU_ASR) & 150 1.1 thorpej AAU_ASR_AAF) 151 1.1 thorpej panic("iopaau_start: AAU already active"); 152 1.1 thorpej #endif 153 1.1 thorpej 154 1.17 matt DPRINTF(("%s: starting dreq %p\n", device_xname(sc->sc_dev), 155 1.1 thorpej dreq)); 156 1.1 thorpej 157 1.1 thorpej bus_space_write_4(sc->sc_st, sc->sc_sh, AAU_ANDAR, 158 1.1 thorpej sc->sc_firstdesc_pa); 159 1.1 thorpej bus_space_write_4(sc->sc_st, sc->sc_sh, AAU_ACR, 160 1.1 thorpej AAU_ACR_AAE); 161 1.1 thorpej 162 1.1 thorpej break; 163 1.1 thorpej } 164 1.1 thorpej } 165 1.1 thorpej 166 1.1 thorpej /* 167 1.1 thorpej * iopaau_finish: 168 1.1 thorpej * 169 1.1 thorpej * Finish the current operation. AAU must be stopped. 170 1.1 thorpej */ 171 1.1 thorpej static void 172 1.1 thorpej iopaau_finish(struct iopaau_softc *sc) 173 1.1 thorpej { 174 1.1 thorpej struct dmover_request *dreq = sc->sc_running; 175 1.1 thorpej struct iopaau_function *af = 176 1.1 thorpej dreq->dreq_assignment->das_algdesc->dad_data; 177 1.1 thorpej void *firstdesc = sc->sc_firstdesc; 178 1.1 thorpej int i, ninputs = dreq->dreq_assignment->das_algdesc->dad_ninputs; 179 1.1 thorpej 180 1.1 thorpej sc->sc_running = NULL; 181 1.1 thorpej 182 1.1 thorpej /* If the function has inputs, unmap them. */ 183 1.1 thorpej for (i = 0; i < ninputs; i++) { 184 1.1 thorpej bus_dmamap_sync(sc->sc_dmat, sc->sc_map_in[i], 0, 185 1.4 thorpej sc->sc_map_in[i]->dm_mapsize, BUS_DMASYNC_POSTWRITE); 186 1.1 thorpej bus_dmamap_unload(sc->sc_dmat, sc->sc_map_in[i]); 187 1.1 thorpej } 188 1.1 thorpej 189 1.1 thorpej /* Unload the output buffer DMA map. */ 190 1.1 thorpej bus_dmamap_sync(sc->sc_dmat, sc->sc_map_out, 0, 191 1.4 thorpej sc->sc_map_out->dm_mapsize, BUS_DMASYNC_POSTREAD); 192 1.1 thorpej bus_dmamap_unload(sc->sc_dmat, sc->sc_map_out); 193 1.1 thorpej 194 1.1 thorpej /* Get the next transfer started. */ 195 1.1 thorpej iopaau_start(sc); 196 1.1 thorpej 197 1.1 thorpej /* Now free descriptors for last transfer. */ 198 1.5 thorpej iopaau_desc_free(af->af_desc_cache, firstdesc); 199 1.1 thorpej 200 1.1 thorpej dmover_done(dreq); 201 1.1 thorpej } 202 1.1 thorpej 203 1.1 thorpej /* 204 1.1 thorpej * iopaau_process: 205 1.1 thorpej * 206 1.1 thorpej * Dmover back-end entry point. 207 1.1 thorpej */ 208 1.1 thorpej void 209 1.1 thorpej iopaau_process(struct dmover_backend *dmb) 210 1.1 thorpej { 211 1.1 thorpej struct iopaau_softc *sc = dmb->dmb_cookie; 212 1.1 thorpej int s; 213 1.1 thorpej 214 1.1 thorpej s = splbio(); 215 1.1 thorpej /* XXXLOCK */ 216 1.1 thorpej 217 1.1 thorpej if (sc->sc_running == NULL) 218 1.1 thorpej iopaau_start(sc); 219 1.1 thorpej 220 1.1 thorpej /* XXXUNLOCK */ 221 1.1 thorpej splx(s); 222 1.1 thorpej } 223 1.1 thorpej 224 1.1 thorpej /* 225 1.3 thorpej * iopaau_func_fill_immed_setup: 226 1.1 thorpej * 227 1.3 thorpej * Common code shared by the zero and fillN setup routines. 228 1.1 thorpej */ 229 1.3 thorpej static int 230 1.3 thorpej iopaau_func_fill_immed_setup(struct iopaau_softc *sc, 231 1.3 thorpej struct dmover_request *dreq, uint32_t immed) 232 1.1 thorpej { 233 1.5 thorpej struct iopaau_function *af = 234 1.5 thorpej dreq->dreq_assignment->das_algdesc->dad_data; 235 1.5 thorpej struct pool_cache *dc = af->af_desc_cache; 236 1.1 thorpej bus_dmamap_t dmamap = sc->sc_map_out; 237 1.1 thorpej uint32_t *prevpa; 238 1.1 thorpej struct aau_desc_4 **prevp, *cur; 239 1.1 thorpej int error, seg; 240 1.1 thorpej 241 1.1 thorpej switch (dreq->dreq_outbuf_type) { 242 1.1 thorpej case DMOVER_BUF_LINEAR: 243 1.1 thorpej error = bus_dmamap_load(sc->sc_dmat, dmamap, 244 1.1 thorpej dreq->dreq_outbuf.dmbuf_linear.l_addr, 245 1.1 thorpej dreq->dreq_outbuf.dmbuf_linear.l_len, NULL, 246 1.4 thorpej BUS_DMA_NOWAIT|BUS_DMA_READ|BUS_DMA_STREAMING); 247 1.1 thorpej break; 248 1.1 thorpej 249 1.1 thorpej case DMOVER_BUF_UIO: 250 1.1 thorpej { 251 1.1 thorpej struct uio *uio = dreq->dreq_outbuf.dmbuf_uio; 252 1.1 thorpej 253 1.1 thorpej if (uio->uio_rw != UIO_READ) 254 1.1 thorpej return (EINVAL); 255 1.1 thorpej 256 1.1 thorpej error = bus_dmamap_load_uio(sc->sc_dmat, dmamap, 257 1.4 thorpej uio, BUS_DMA_NOWAIT|BUS_DMA_READ|BUS_DMA_STREAMING); 258 1.1 thorpej break; 259 1.1 thorpej } 260 1.8 thorpej 261 1.8 thorpej default: 262 1.8 thorpej error = EINVAL; 263 1.1 thorpej } 264 1.1 thorpej 265 1.1 thorpej if (__predict_false(error != 0)) 266 1.1 thorpej return (error); 267 1.1 thorpej 268 1.1 thorpej bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize, 269 1.4 thorpej BUS_DMASYNC_PREREAD); 270 1.1 thorpej 271 1.1 thorpej prevp = (struct aau_desc_4 **) &sc->sc_firstdesc; 272 1.1 thorpej prevpa = &sc->sc_firstdesc_pa; 273 1.1 thorpej 274 1.11 matt cur = NULL; /* XXX: gcc */ 275 1.1 thorpej for (seg = 0; seg < dmamap->dm_nsegs; seg++) { 276 1.5 thorpej cur = pool_cache_get(dc, PR_NOWAIT); 277 1.1 thorpej if (cur == NULL) { 278 1.1 thorpej *prevp = NULL; 279 1.1 thorpej error = ENOMEM; 280 1.1 thorpej goto bad; 281 1.1 thorpej } 282 1.1 thorpej 283 1.1 thorpej *prevp = cur; 284 1.1 thorpej *prevpa = cur->d_pa; 285 1.1 thorpej 286 1.1 thorpej prevp = &cur->d_next; 287 1.1 thorpej prevpa = &cur->d_nda; 288 1.1 thorpej 289 1.1 thorpej /* 290 1.1 thorpej * We don't actually enforce the page alignment 291 1.1 thorpej * constraint, here, because there is only one 292 1.1 thorpej * data stream to worry about. 293 1.1 thorpej */ 294 1.1 thorpej 295 1.4 thorpej cur->d_sar[0] = immed; 296 1.1 thorpej cur->d_dar = dmamap->dm_segs[seg].ds_addr; 297 1.1 thorpej cur->d_bc = dmamap->dm_segs[seg].ds_len; 298 1.1 thorpej cur->d_dc = AAU_DC_B1_CC(AAU_DC_CC_FILL) | AAU_DC_DWE; 299 1.6 thorpej SYNC_DESC(cur, sizeof(struct aau_desc_4)); 300 1.1 thorpej } 301 1.1 thorpej 302 1.1 thorpej *prevp = NULL; 303 1.1 thorpej *prevpa = 0; 304 1.1 thorpej 305 1.1 thorpej cur->d_dc |= AAU_DC_IE; 306 1.6 thorpej SYNC_DESC(cur, sizeof(struct aau_desc_4)); 307 1.1 thorpej 308 1.1 thorpej sc->sc_lastdesc = cur; 309 1.1 thorpej 310 1.1 thorpej return (0); 311 1.1 thorpej 312 1.1 thorpej bad: 313 1.5 thorpej iopaau_desc_free(dc, sc->sc_firstdesc); 314 1.1 thorpej bus_dmamap_unload(sc->sc_dmat, sc->sc_map_out); 315 1.1 thorpej sc->sc_firstdesc = NULL; 316 1.1 thorpej 317 1.1 thorpej return (error); 318 1.1 thorpej } 319 1.1 thorpej 320 1.1 thorpej /* 321 1.3 thorpej * iopaau_func_zero_setup: 322 1.3 thorpej * 323 1.3 thorpej * Setup routine for the "zero" function. 324 1.3 thorpej */ 325 1.3 thorpej int 326 1.3 thorpej iopaau_func_zero_setup(struct iopaau_softc *sc, struct dmover_request *dreq) 327 1.3 thorpej { 328 1.3 thorpej 329 1.3 thorpej return (iopaau_func_fill_immed_setup(sc, dreq, 0)); 330 1.3 thorpej } 331 1.3 thorpej 332 1.3 thorpej /* 333 1.1 thorpej * iopaau_func_fill8_setup: 334 1.1 thorpej * 335 1.1 thorpej * Setup routine for the "fill8" function. 336 1.1 thorpej */ 337 1.1 thorpej int 338 1.1 thorpej iopaau_func_fill8_setup(struct iopaau_softc *sc, struct dmover_request *dreq) 339 1.1 thorpej { 340 1.1 thorpej 341 1.3 thorpej return (iopaau_func_fill_immed_setup(sc, dreq, 342 1.3 thorpej dreq->dreq_immediate[0] | 343 1.1 thorpej (dreq->dreq_immediate[0] << 8) | 344 1.1 thorpej (dreq->dreq_immediate[0] << 16) | 345 1.3 thorpej (dreq->dreq_immediate[0] << 24))); 346 1.1 thorpej } 347 1.1 thorpej 348 1.1 thorpej /* 349 1.4 thorpej * Descriptor command words for varying numbers of inputs. For 1 input, 350 1.4 thorpej * this does a copy. For multiple inputs, we're doing an XOR. In this 351 1.4 thorpej * case, the first block is a "direct fill" to load the store queue, and 352 1.4 thorpej * the remaining blocks are XOR'd to the store queue. 353 1.4 thorpej */ 354 1.4 thorpej static const uint32_t iopaau_dc_inputs[] = { 355 1.4 thorpej 0, /* 0 */ 356 1.4 thorpej 357 1.4 thorpej AAU_DC_B1_CC(AAU_DC_CC_DIRECT_FILL), /* 1 */ 358 1.4 thorpej 359 1.4 thorpej AAU_DC_B1_CC(AAU_DC_CC_DIRECT_FILL)| /* 2 */ 360 1.4 thorpej AAU_DC_B2_CC(AAU_DC_CC_XOR), 361 1.4 thorpej 362 1.4 thorpej AAU_DC_B1_CC(AAU_DC_CC_DIRECT_FILL)| /* 3 */ 363 1.4 thorpej AAU_DC_B2_CC(AAU_DC_CC_XOR)| 364 1.4 thorpej AAU_DC_B3_CC(AAU_DC_CC_XOR), 365 1.4 thorpej 366 1.4 thorpej AAU_DC_B1_CC(AAU_DC_CC_DIRECT_FILL)| /* 4 */ 367 1.4 thorpej AAU_DC_B2_CC(AAU_DC_CC_XOR)| 368 1.4 thorpej AAU_DC_B3_CC(AAU_DC_CC_XOR)| 369 1.4 thorpej AAU_DC_B4_CC(AAU_DC_CC_XOR), 370 1.7 thorpej 371 1.7 thorpej AAU_DC_SBCI_5_8| /* 5 */ 372 1.7 thorpej AAU_DC_B1_CC(AAU_DC_CC_DIRECT_FILL)| 373 1.7 thorpej AAU_DC_B2_CC(AAU_DC_CC_XOR)| 374 1.7 thorpej AAU_DC_B3_CC(AAU_DC_CC_XOR)| 375 1.7 thorpej AAU_DC_B4_CC(AAU_DC_CC_XOR)| 376 1.7 thorpej AAU_DC_B5_CC(AAU_DC_CC_XOR), 377 1.7 thorpej 378 1.7 thorpej AAU_DC_SBCI_5_8| /* 6 */ 379 1.7 thorpej AAU_DC_B1_CC(AAU_DC_CC_DIRECT_FILL)| 380 1.7 thorpej AAU_DC_B2_CC(AAU_DC_CC_XOR)| 381 1.7 thorpej AAU_DC_B3_CC(AAU_DC_CC_XOR)| 382 1.7 thorpej AAU_DC_B4_CC(AAU_DC_CC_XOR)| 383 1.7 thorpej AAU_DC_B5_CC(AAU_DC_CC_XOR)| 384 1.7 thorpej AAU_DC_B6_CC(AAU_DC_CC_XOR), 385 1.7 thorpej 386 1.7 thorpej AAU_DC_SBCI_5_8| /* 7 */ 387 1.7 thorpej AAU_DC_B1_CC(AAU_DC_CC_DIRECT_FILL)| 388 1.7 thorpej AAU_DC_B2_CC(AAU_DC_CC_XOR)| 389 1.7 thorpej AAU_DC_B3_CC(AAU_DC_CC_XOR)| 390 1.7 thorpej AAU_DC_B4_CC(AAU_DC_CC_XOR)| 391 1.7 thorpej AAU_DC_B5_CC(AAU_DC_CC_XOR)| 392 1.7 thorpej AAU_DC_B6_CC(AAU_DC_CC_XOR)| 393 1.7 thorpej AAU_DC_B7_CC(AAU_DC_CC_XOR), 394 1.7 thorpej 395 1.7 thorpej AAU_DC_SBCI_5_8| /* 8 */ 396 1.7 thorpej AAU_DC_B1_CC(AAU_DC_CC_DIRECT_FILL)| 397 1.7 thorpej AAU_DC_B2_CC(AAU_DC_CC_XOR)| 398 1.7 thorpej AAU_DC_B3_CC(AAU_DC_CC_XOR)| 399 1.7 thorpej AAU_DC_B4_CC(AAU_DC_CC_XOR)| 400 1.7 thorpej AAU_DC_B5_CC(AAU_DC_CC_XOR)| 401 1.7 thorpej AAU_DC_B6_CC(AAU_DC_CC_XOR)| 402 1.7 thorpej AAU_DC_B7_CC(AAU_DC_CC_XOR)| 403 1.7 thorpej AAU_DC_B8_CC(AAU_DC_CC_XOR), 404 1.4 thorpej }; 405 1.4 thorpej 406 1.4 thorpej /* 407 1.7 thorpej * iopaau_func_xor_setup: 408 1.1 thorpej * 409 1.7 thorpej * Setup routine for the "copy", "xor2".."xor8" functions. 410 1.1 thorpej */ 411 1.1 thorpej int 412 1.7 thorpej iopaau_func_xor_setup(struct iopaau_softc *sc, struct dmover_request *dreq) 413 1.1 thorpej { 414 1.5 thorpej struct iopaau_function *af = 415 1.5 thorpej dreq->dreq_assignment->das_algdesc->dad_data; 416 1.5 thorpej struct pool_cache *dc = af->af_desc_cache; 417 1.1 thorpej bus_dmamap_t dmamap = sc->sc_map_out; 418 1.4 thorpej bus_dmamap_t *inmap = sc->sc_map_in; 419 1.1 thorpej uint32_t *prevpa; 420 1.7 thorpej struct aau_desc_8 **prevp, *cur; 421 1.4 thorpej int ninputs = dreq->dreq_assignment->das_algdesc->dad_ninputs; 422 1.4 thorpej int i, error, seg; 423 1.6 thorpej size_t descsz = AAU_DESC_SIZE(ninputs); 424 1.4 thorpej 425 1.4 thorpej KASSERT(ninputs <= AAU_MAX_INPUTS); 426 1.1 thorpej 427 1.1 thorpej switch (dreq->dreq_outbuf_type) { 428 1.1 thorpej case DMOVER_BUF_LINEAR: 429 1.1 thorpej error = bus_dmamap_load(sc->sc_dmat, dmamap, 430 1.1 thorpej dreq->dreq_outbuf.dmbuf_linear.l_addr, 431 1.1 thorpej dreq->dreq_outbuf.dmbuf_linear.l_len, NULL, 432 1.4 thorpej BUS_DMA_NOWAIT|BUS_DMA_READ|BUS_DMA_STREAMING); 433 1.1 thorpej break; 434 1.1 thorpej 435 1.1 thorpej case DMOVER_BUF_UIO: 436 1.1 thorpej { 437 1.1 thorpej struct uio *uio = dreq->dreq_outbuf.dmbuf_uio; 438 1.1 thorpej 439 1.1 thorpej if (uio->uio_rw != UIO_READ) 440 1.1 thorpej return (EINVAL); 441 1.1 thorpej 442 1.1 thorpej error = bus_dmamap_load_uio(sc->sc_dmat, dmamap, 443 1.4 thorpej uio, BUS_DMA_NOWAIT|BUS_DMA_READ|BUS_DMA_STREAMING); 444 1.1 thorpej break; 445 1.1 thorpej } 446 1.8 thorpej 447 1.8 thorpej default: 448 1.8 thorpej error = EINVAL; 449 1.1 thorpej } 450 1.1 thorpej 451 1.1 thorpej if (__predict_false(error != 0)) 452 1.1 thorpej return (error); 453 1.1 thorpej 454 1.1 thorpej switch (dreq->dreq_inbuf_type) { 455 1.1 thorpej case DMOVER_BUF_LINEAR: 456 1.4 thorpej for (i = 0; i < ninputs; i++) { 457 1.4 thorpej error = bus_dmamap_load(sc->sc_dmat, inmap[i], 458 1.4 thorpej dreq->dreq_inbuf[i].dmbuf_linear.l_addr, 459 1.4 thorpej dreq->dreq_inbuf[i].dmbuf_linear.l_len, NULL, 460 1.4 thorpej BUS_DMA_NOWAIT|BUS_DMA_WRITE|BUS_DMA_STREAMING); 461 1.4 thorpej if (__predict_false(error != 0)) 462 1.4 thorpej break; 463 1.4 thorpej if (dmamap->dm_nsegs != inmap[i]->dm_nsegs) { 464 1.4 thorpej error = EFAULT; /* "address error", sort of. */ 465 1.4 thorpej bus_dmamap_unload(sc->sc_dmat, inmap[i]); 466 1.4 thorpej break; 467 1.4 thorpej } 468 1.4 thorpej } 469 1.1 thorpej break; 470 1.1 thorpej 471 1.1 thorpej case DMOVER_BUF_UIO: 472 1.1 thorpej { 473 1.4 thorpej struct uio *uio; 474 1.1 thorpej 475 1.4 thorpej for (i = 0; i < ninputs; i++) { 476 1.4 thorpej uio = dreq->dreq_inbuf[i].dmbuf_uio; 477 1.4 thorpej 478 1.4 thorpej if (uio->uio_rw != UIO_WRITE) { 479 1.4 thorpej error = EINVAL; 480 1.4 thorpej break; 481 1.4 thorpej } 482 1.4 thorpej 483 1.4 thorpej error = bus_dmamap_load_uio(sc->sc_dmat, inmap[i], uio, 484 1.4 thorpej BUS_DMA_NOWAIT|BUS_DMA_WRITE|BUS_DMA_STREAMING); 485 1.4 thorpej if (__predict_false(error != 0)) { 486 1.4 thorpej break; 487 1.4 thorpej } 488 1.4 thorpej if (dmamap->dm_nsegs != inmap[i]->dm_nsegs) { 489 1.4 thorpej error = EFAULT; /* "address error", sort of. */ 490 1.4 thorpej bus_dmamap_unload(sc->sc_dmat, inmap[i]); 491 1.4 thorpej break; 492 1.4 thorpej } 493 1.1 thorpej } 494 1.1 thorpej break; 495 1.1 thorpej } 496 1.8 thorpej 497 1.8 thorpej default: 498 1.11 matt i = 0; /* XXX: gcc */ 499 1.8 thorpej error = EINVAL; 500 1.1 thorpej } 501 1.1 thorpej 502 1.1 thorpej if (__predict_false(error != 0)) { 503 1.4 thorpej for (--i; i >= 0; i--) 504 1.4 thorpej bus_dmamap_unload(sc->sc_dmat, inmap[i]); 505 1.1 thorpej bus_dmamap_unload(sc->sc_dmat, dmamap); 506 1.1 thorpej return (error); 507 1.1 thorpej } 508 1.1 thorpej 509 1.1 thorpej bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize, 510 1.1 thorpej BUS_DMASYNC_PREREAD); 511 1.4 thorpej for (i = 0; i < ninputs; i++) { 512 1.4 thorpej bus_dmamap_sync(sc->sc_dmat, inmap[i], 0, inmap[i]->dm_mapsize, 513 1.4 thorpej BUS_DMASYNC_PREWRITE); 514 1.4 thorpej } 515 1.1 thorpej 516 1.7 thorpej prevp = (struct aau_desc_8 **) &sc->sc_firstdesc; 517 1.1 thorpej prevpa = &sc->sc_firstdesc_pa; 518 1.1 thorpej 519 1.11 matt cur = NULL; /* XXX: gcc */ 520 1.1 thorpej for (seg = 0; seg < dmamap->dm_nsegs; seg++) { 521 1.5 thorpej cur = pool_cache_get(dc, PR_NOWAIT); 522 1.1 thorpej if (cur == NULL) { 523 1.1 thorpej *prevp = NULL; 524 1.1 thorpej error = ENOMEM; 525 1.1 thorpej goto bad; 526 1.1 thorpej } 527 1.1 thorpej 528 1.1 thorpej *prevp = cur; 529 1.1 thorpej *prevpa = cur->d_pa; 530 1.1 thorpej 531 1.1 thorpej prevp = &cur->d_next; 532 1.1 thorpej prevpa = &cur->d_nda; 533 1.1 thorpej 534 1.4 thorpej for (i = 0; i < ninputs; i++) { 535 1.4 thorpej if (dmamap->dm_segs[seg].ds_len != 536 1.4 thorpej inmap[i]->dm_segs[seg].ds_len) { 537 1.4 thorpej *prevp = NULL; 538 1.4 thorpej error = EFAULT; /* "address" error, sort of. */ 539 1.4 thorpej goto bad; 540 1.4 thorpej } 541 1.7 thorpej if (i < 4) { 542 1.7 thorpej cur->d_sar[i] = 543 1.7 thorpej inmap[i]->dm_segs[seg].ds_addr; 544 1.7 thorpej } else if (i < 8) { 545 1.7 thorpej cur->d_sar5_8[i - 4] = 546 1.7 thorpej inmap[i]->dm_segs[seg].ds_addr; 547 1.7 thorpej } 548 1.1 thorpej } 549 1.1 thorpej cur->d_dar = dmamap->dm_segs[seg].ds_addr; 550 1.1 thorpej cur->d_bc = dmamap->dm_segs[seg].ds_len; 551 1.4 thorpej cur->d_dc = iopaau_dc_inputs[ninputs] | AAU_DC_DWE; 552 1.6 thorpej SYNC_DESC(cur, descsz); 553 1.1 thorpej } 554 1.1 thorpej 555 1.1 thorpej *prevp = NULL; 556 1.1 thorpej *prevpa = 0; 557 1.1 thorpej 558 1.1 thorpej cur->d_dc |= AAU_DC_IE; 559 1.6 thorpej SYNC_DESC(cur, descsz); 560 1.1 thorpej 561 1.1 thorpej sc->sc_lastdesc = cur; 562 1.1 thorpej 563 1.1 thorpej return (0); 564 1.1 thorpej 565 1.1 thorpej bad: 566 1.5 thorpej iopaau_desc_free(dc, sc->sc_firstdesc); 567 1.1 thorpej bus_dmamap_unload(sc->sc_dmat, sc->sc_map_out); 568 1.4 thorpej for (i = 0; i < ninputs; i++) 569 1.4 thorpej bus_dmamap_unload(sc->sc_dmat, sc->sc_map_in[i]); 570 1.1 thorpej sc->sc_firstdesc = NULL; 571 1.1 thorpej 572 1.1 thorpej return (error); 573 1.1 thorpej } 574 1.1 thorpej 575 1.1 thorpej int 576 1.1 thorpej iopaau_intr(void *arg) 577 1.1 thorpej { 578 1.1 thorpej struct iopaau_softc *sc = arg; 579 1.1 thorpej struct dmover_request *dreq; 580 1.1 thorpej uint32_t asr; 581 1.1 thorpej 582 1.1 thorpej /* Clear the interrupt. */ 583 1.1 thorpej asr = bus_space_read_4(sc->sc_st, sc->sc_sh, AAU_ASR); 584 1.1 thorpej if (asr == 0) 585 1.1 thorpej return (0); 586 1.1 thorpej bus_space_write_4(sc->sc_st, sc->sc_sh, AAU_ASR, asr); 587 1.1 thorpej 588 1.1 thorpej /* XXX -- why does this happen? */ 589 1.1 thorpej if (sc->sc_running == NULL) { 590 1.1 thorpej printf("%s: unexpected interrupt, ASR = 0x%08x\n", 591 1.17 matt device_xname(sc->sc_dev), asr); 592 1.1 thorpej return (1); 593 1.1 thorpej } 594 1.1 thorpej dreq = sc->sc_running; 595 1.1 thorpej 596 1.1 thorpej /* Stop the AAU. */ 597 1.1 thorpej bus_space_write_4(sc->sc_st, sc->sc_sh, AAU_ACR, 0); 598 1.1 thorpej 599 1.17 matt DPRINTF(("%s: got interrupt for dreq %p\n", device_xname(sc->sc_dev), 600 1.1 thorpej dreq)); 601 1.1 thorpej 602 1.1 thorpej if (__predict_false((asr & AAU_ASR_ETIF) != 0)) { 603 1.1 thorpej /* 604 1.1 thorpej * We expect to get end-of-chain interrupts, not 605 1.1 thorpej * end-of-transfer interrupts, so panic if we get 606 1.1 thorpej * one of these. 607 1.1 thorpej */ 608 1.1 thorpej panic("aau_intr: got EOT interrupt"); 609 1.1 thorpej } 610 1.1 thorpej 611 1.1 thorpej if (__predict_false((asr & AAU_ASR_MA) != 0)) { 612 1.17 matt aprint_error_dev(sc->sc_dev, "WARNING: got master abort\n"); 613 1.1 thorpej dreq->dreq_flags |= DMOVER_REQ_ERROR; 614 1.1 thorpej dreq->dreq_error = EFAULT; 615 1.1 thorpej } 616 1.1 thorpej 617 1.1 thorpej /* Finish this transfer, start next one. */ 618 1.1 thorpej iopaau_finish(sc); 619 1.1 thorpej 620 1.1 thorpej return (1); 621 1.1 thorpej } 622 1.1 thorpej 623 1.1 thorpej void 624 1.1 thorpej iopaau_attach(struct iopaau_softc *sc) 625 1.1 thorpej { 626 1.1 thorpej int error, i; 627 1.1 thorpej 628 1.1 thorpej error = bus_dmamap_create(sc->sc_dmat, AAU_MAX_XFER, AAU_MAX_SEGS, 629 1.1 thorpej AAU_MAX_XFER, AAU_IO_BOUNDARY, 0, &sc->sc_map_out); 630 1.1 thorpej if (error) { 631 1.17 matt aprint_error_dev(sc->sc_dev, 632 1.17 matt "unable to create output DMA map, error = %d\n", error); 633 1.1 thorpej return; 634 1.1 thorpej } 635 1.1 thorpej 636 1.1 thorpej for (i = 0; i < AAU_MAX_INPUTS; i++) { 637 1.1 thorpej error = bus_dmamap_create(sc->sc_dmat, AAU_MAX_XFER, 638 1.1 thorpej AAU_MAX_SEGS, AAU_MAX_XFER, AAU_IO_BOUNDARY, 0, 639 1.1 thorpej &sc->sc_map_in[i]); 640 1.1 thorpej if (error) { 641 1.17 matt aprint_error_dev(sc->sc_dev, 642 1.17 matt "unable to create input %d DMA map, error = %d\n", 643 1.17 matt i, error); 644 1.1 thorpej return; 645 1.1 thorpej } 646 1.1 thorpej } 647 1.1 thorpej 648 1.1 thorpej /* 649 1.1 thorpej * Initialize global resources. Ok to do here, since there's 650 1.18 maxv * only one AAU. The structures are 32-byte aligned. 651 1.1 thorpej */ 652 1.14 ad iopaau_desc_4_cache = pool_cache_init(sizeof(struct aau_desc_4), 653 1.18 maxv 8 * 4, 0, 0, "aaud4pl", 654 1.14 ad NULL, IPL_VM, iopaau_desc_ctor, NULL, NULL); 655 1.15 ad iopaau_desc_8_cache = pool_cache_init(sizeof(struct aau_desc_8), 656 1.18 maxv 8 * 4, 0, 0, "aaud8pl", 657 1.14 ad NULL, IPL_VM, iopaau_desc_ctor, NULL, NULL); 658 1.1 thorpej 659 1.1 thorpej /* Register us with dmover. */ 660 1.1 thorpej dmover_backend_register(&sc->sc_dmb); 661 1.1 thorpej } 662