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