1 /* $NetBSD: isadma.c,v 1.39 1998/11/19 15:38:25 mrg Exp $ */ 2 3 /*- 4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Device driver for the ISA on-board DMA controller. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/proc.h> 47 #include <sys/device.h> 48 #include <sys/malloc.h> 49 50 #include <vm/vm.h> 51 52 #include <machine/bus.h> 53 54 #include <dev/isa/isareg.h> 55 #include <dev/isa/isavar.h> 56 #include <dev/isa/isadmavar.h> 57 #include <dev/isa/isadmareg.h> 58 59 struct isa_mem *isa_mem_head; 60 61 /* 62 * High byte of DMA address is stored in this DMAPG register for 63 * the Nth DMA channel. 64 */ 65 static int dmapageport[2][4] = { 66 {0x7, 0x3, 0x1, 0x2}, 67 {0xf, 0xb, 0x9, 0xa} 68 }; 69 70 static u_int8_t dmamode[] = { 71 /* write to device/read from device */ 72 DMA37MD_READ | DMA37MD_SINGLE, 73 DMA37MD_WRITE | DMA37MD_SINGLE, 74 75 /* write to device/read from device - DMAMODE_LOOP */ 76 DMA37MD_READ | DMA37MD_SINGLE | DMA37MD_LOOP, 77 DMA37MD_WRITE | DMA37MD_SINGLE | DMA37MD_LOOP, 78 79 /* write to device/read from device - DMAMODE_LOOPDEMAND */ 80 DMA37MD_READ | DMA37MD_DEMAND | DMA37MD_LOOP, 81 DMA37MD_WRITE | DMA37MD_DEMAND | DMA37MD_LOOP, 82 }; 83 84 static inline void _isa_dmaunmask __P((struct isa_dma_state *, int)); 85 static inline void _isa_dmamask __P((struct isa_dma_state *, int)); 86 87 static inline void 88 _isa_dmaunmask(ids, chan) 89 struct isa_dma_state *ids; 90 int chan; 91 { 92 int ochan = chan & 3; 93 94 ISA_DMA_MASK_CLR(ids, chan); 95 96 /* 97 * If DMA is frozen, don't unmask it now. It will be 98 * unmasked when DMA is thawed again. 99 */ 100 if (ids->ids_frozen) 101 return; 102 103 /* set dma channel mode, and set dma channel mode */ 104 if ((chan & 4) == 0) 105 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, 106 DMA1_SMSK, ochan | DMA37SM_CLEAR); 107 else 108 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, 109 DMA2_SMSK, ochan | DMA37SM_CLEAR); 110 } 111 112 static inline void 113 _isa_dmamask(ids, chan) 114 struct isa_dma_state *ids; 115 int chan; 116 { 117 int ochan = chan & 3; 118 119 ISA_DMA_MASK_SET(ids, chan); 120 121 /* 122 * XXX Should we avoid masking the channel if DMA is 123 * XXX frozen? It seems like what we're doing should 124 * XXX be safe, and we do need to reset FFC... 125 */ 126 127 /* set dma channel mode, and set dma channel mode */ 128 if ((chan & 4) == 0) { 129 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, 130 DMA1_SMSK, ochan | DMA37SM_SET); 131 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, 132 DMA1_FFC, 0); 133 } else { 134 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, 135 DMA2_SMSK, ochan | DMA37SM_SET); 136 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, 137 DMA2_FFC, 0); 138 } 139 } 140 141 /* 142 * _isa_dmainit(): Initialize the isa_dma_state for this chipset. 143 */ 144 void 145 _isa_dmainit(ids, bst, dmat, dev) 146 struct isa_dma_state *ids; 147 bus_space_tag_t bst; 148 bus_dma_tag_t dmat; 149 struct device *dev; 150 { 151 152 ids->ids_dev = dev; 153 154 if (ids->ids_initialized) { 155 /* 156 * Some systems may have e.g. `ofisa' (OpenFirmware 157 * configuration of ISA bus) and a regular `isa'. 158 * We allow both to call the initialization function, 159 * and take the device name from the last caller 160 * (assuming it will be the indirect ISA bus). Since 161 * `ofisa' and `isa' are the same bus with different 162 * configuration mechanisms, the space and dma tags 163 * must be the same! 164 */ 165 if (ids->ids_bst != bst || ids->ids_dmat != dmat) 166 panic("_isa_dmainit: inconsistent ISA tags"); 167 } else { 168 ids->ids_bst = bst; 169 ids->ids_dmat = dmat; 170 171 /* 172 * Map the registers used by the ISA DMA controller. 173 */ 174 if (bus_space_map(ids->ids_bst, IO_DMA1, DMA1_IOSIZE, 0, 175 &ids->ids_dma1h)) 176 panic("_isa_dmainit: unable to map DMA controller #1"); 177 if (bus_space_map(ids->ids_bst, IO_DMA2, DMA2_IOSIZE, 0, 178 &ids->ids_dma2h)) 179 panic("_isa_dmainit: unable to map DMA controller #2"); 180 if (bus_space_map(ids->ids_bst, IO_DMAPG, 0xf, 0, 181 &ids->ids_dmapgh)) 182 panic("_isa_dmainit: unable to map DMA page registers"); 183 184 /* 185 * All 8 DMA channels start out "masked". 186 */ 187 ids->ids_masked = 0xff; 188 189 ids->ids_initialized = 1; 190 191 /* 192 * DRQ 4 is used to chain the two 8237s together; make 193 * sure it's always cascaded, and that it will be unmasked 194 * when DMA is thawed. 195 */ 196 _isa_dmacascade(ids, 4); 197 } 198 } 199 200 /* 201 * _isa_dmacascade(): program 8237 DMA controller channel to accept 202 * external dma control by a board. 203 */ 204 int 205 _isa_dmacascade(ids, chan) 206 struct isa_dma_state *ids; 207 int chan; 208 { 209 int ochan = chan & 3; 210 211 if (chan < 0 || chan > 7) { 212 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 213 return (EINVAL); 214 } 215 216 if (ISA_DMA_DRQ_ISFREE(ids, chan) == 0) { 217 printf("%s: DRQ %d is not free\n", ids->ids_dev->dv_xname, 218 chan); 219 return (EAGAIN); 220 } 221 222 ISA_DMA_DRQ_ALLOC(ids, chan); 223 224 /* set dma channel mode, and set dma channel mode */ 225 if ((chan & 4) == 0) 226 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, 227 DMA1_MODE, ochan | DMA37MD_CASCADE); 228 else 229 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, 230 DMA2_MODE, ochan | DMA37MD_CASCADE); 231 232 _isa_dmaunmask(ids, chan); 233 return (0); 234 } 235 236 int 237 _isa_dmamap_create(ids, chan, size, flags) 238 struct isa_dma_state *ids; 239 int chan; 240 bus_size_t size; 241 int flags; 242 { 243 bus_size_t maxsize; 244 245 if (chan < 0 || chan > 7) { 246 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 247 return (EINVAL); 248 } 249 250 if (chan & 4) 251 maxsize = (1 << 17); 252 else 253 maxsize = (1 << 16); 254 255 if (size > maxsize) 256 return (EINVAL); 257 258 if (ISA_DMA_DRQ_ISFREE(ids, chan) == 0) { 259 printf("%s: drq %d is not free\n", ids->ids_dev->dv_xname, 260 chan); 261 return (EAGAIN); 262 } 263 264 ISA_DMA_DRQ_ALLOC(ids, chan); 265 266 return (bus_dmamap_create(ids->ids_dmat, size, 1, size, maxsize, 267 flags, &ids->ids_dmamaps[chan])); 268 } 269 270 void 271 _isa_dmamap_destroy(ids, chan) 272 struct isa_dma_state *ids; 273 int chan; 274 { 275 276 if (chan < 0 || chan > 7) { 277 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 278 goto lose; 279 } 280 281 if (ISA_DMA_DRQ_ISFREE(ids, chan)) { 282 printf("%s: drq %d is already free\n", 283 ids->ids_dev->dv_xname, chan); 284 goto lose; 285 } 286 287 ISA_DMA_DRQ_FREE(ids, chan); 288 289 bus_dmamap_destroy(ids->ids_dmat, ids->ids_dmamaps[chan]); 290 return; 291 292 lose: 293 panic("_isa_dmamap_destroy"); 294 } 295 296 /* 297 * _isa_dmastart(): program 8237 DMA controller channel and set it 298 * in motion. 299 */ 300 int 301 _isa_dmastart(ids, chan, addr, nbytes, p, flags, busdmaflags) 302 struct isa_dma_state *ids; 303 int chan; 304 void *addr; 305 bus_size_t nbytes; 306 struct proc *p; 307 int flags; 308 int busdmaflags; 309 { 310 bus_dmamap_t dmam; 311 bus_addr_t dmaaddr; 312 int waport; 313 int ochan = chan & 3; 314 int error; 315 316 if (chan < 0 || chan > 7) { 317 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 318 goto lose; 319 } 320 321 #ifdef ISADMA_DEBUG 322 printf("_isa_dmastart: drq %d, addr %p, nbytes 0x%lx, p %p, " 323 "flags 0x%x, dmaflags 0x%x\n", 324 chan, addr, nbytes, p, flags, busdmaflags); 325 #endif 326 327 /* Can't specify LOOP and LOOPDEMAND together. */ 328 if ((flags & (DMAMODE_LOOP|DMAMODE_LOOPDEMAND)) == 329 (DMAMODE_LOOP|DMAMODE_LOOPDEMAND)) 330 return (EINVAL); 331 332 if (chan & 4) { 333 if (nbytes > (1 << 17) || nbytes & 1 || (u_long)addr & 1) { 334 printf("%s: drq %d, nbytes 0x%lx, addr %p\n", 335 ids->ids_dev->dv_xname, chan, nbytes, addr); 336 goto lose; 337 } 338 } else { 339 if (nbytes > (1 << 16)) { 340 printf("%s: drq %d, nbytes 0x%lx\n", 341 ids->ids_dev->dv_xname, chan, nbytes); 342 goto lose; 343 } 344 } 345 346 dmam = ids->ids_dmamaps[chan]; 347 if (dmam == NULL) 348 panic("_isa_dmastart: no DMA map for chan %d\n", chan); 349 350 error = bus_dmamap_load(ids->ids_dmat, dmam, addr, nbytes, 351 p, busdmaflags); 352 if (error) 353 return (error); 354 355 #ifdef ISADMA_DEBUG 356 __asm(".globl isa_dmastart_afterload ; isa_dmastart_afterload:"); 357 #endif 358 359 if (flags & DMAMODE_READ) { 360 bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize, 361 BUS_DMASYNC_PREREAD); 362 ids->ids_dmareads |= (1 << chan); 363 } else { 364 bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize, 365 BUS_DMASYNC_PREWRITE); 366 ids->ids_dmareads &= ~(1 << chan); 367 } 368 369 dmaaddr = dmam->dm_segs[0].ds_addr; 370 371 #ifdef ISADMA_DEBUG 372 printf(" dmaaddr 0x%lx\n", dmaaddr); 373 374 __asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:"); 375 #endif 376 377 ids->ids_dmalength[chan] = nbytes; 378 379 _isa_dmamask(ids, chan); 380 ids->ids_dmafinished &= ~(1 << chan); 381 382 if ((chan & 4) == 0) { 383 /* set dma channel mode */ 384 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, DMA1_MODE, 385 ochan | dmamode[flags]); 386 387 /* send start address */ 388 waport = DMA1_CHN(ochan); 389 bus_space_write_1(ids->ids_bst, ids->ids_dmapgh, 390 dmapageport[0][ochan], (dmaaddr >> 16) & 0xff); 391 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport, 392 dmaaddr & 0xff); 393 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport, 394 (dmaaddr >> 8) & 0xff); 395 396 /* send count */ 397 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1, 398 (--nbytes) & 0xff); 399 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1, 400 (nbytes >> 8) & 0xff); 401 } else { 402 /* set dma channel mode */ 403 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, DMA2_MODE, 404 ochan | dmamode[flags]); 405 406 /* send start address */ 407 waport = DMA2_CHN(ochan); 408 bus_space_write_1(ids->ids_bst, ids->ids_dmapgh, 409 dmapageport[1][ochan], (dmaaddr >> 16) & 0xff); 410 dmaaddr >>= 1; 411 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport, 412 dmaaddr & 0xff); 413 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport, 414 (dmaaddr >> 8) & 0xff); 415 416 /* send count */ 417 nbytes >>= 1; 418 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport + 2, 419 (--nbytes) & 0xff); 420 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport + 2, 421 (nbytes >> 8) & 0xff); 422 } 423 424 _isa_dmaunmask(ids, chan); 425 return (0); 426 427 lose: 428 panic("_isa_dmastart"); 429 } 430 431 void 432 _isa_dmaabort(ids, chan) 433 struct isa_dma_state *ids; 434 int chan; 435 { 436 437 if (chan < 0 || chan > 7) { 438 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 439 panic("_isa_dmaabort"); 440 } 441 442 _isa_dmamask(ids, chan); 443 bus_dmamap_unload(ids->ids_dmat, ids->ids_dmamaps[chan]); 444 ids->ids_dmareads &= ~(1 << chan); 445 } 446 447 bus_size_t 448 _isa_dmacount(ids, chan) 449 struct isa_dma_state *ids; 450 int chan; 451 { 452 int waport; 453 bus_size_t nbytes; 454 int ochan = chan & 3; 455 456 if (chan < 0 || chan > 7) { 457 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 458 panic("isa_dmacount"); 459 } 460 461 _isa_dmamask(ids, chan); 462 463 /* 464 * We have to shift the byte count by 1. If we're in auto-initialize 465 * mode, the count may have wrapped around to the initial value. We 466 * can't use the TC bit to check for this case, so instead we compare 467 * against the original byte count. 468 * If we're not in auto-initialize mode, then the count will wrap to 469 * -1, so we also handle that case. 470 */ 471 if ((chan & 4) == 0) { 472 waport = DMA1_CHN(ochan); 473 nbytes = bus_space_read_1(ids->ids_bst, ids->ids_dma1h, 474 waport + 1) + 1; 475 nbytes += bus_space_read_1(ids->ids_bst, ids->ids_dma1h, 476 waport + 1) << 8; 477 nbytes &= 0xffff; 478 } else { 479 waport = DMA2_CHN(ochan); 480 nbytes = bus_space_read_1(ids->ids_bst, ids->ids_dma2h, 481 waport + 2) + 1; 482 nbytes += bus_space_read_1(ids->ids_bst, ids->ids_dma2h, 483 waport + 2) << 8; 484 nbytes <<= 1; 485 nbytes &= 0x1ffff; 486 } 487 488 if (nbytes == ids->ids_dmalength[chan]) 489 nbytes = 0; 490 491 _isa_dmaunmask(ids, chan); 492 return (nbytes); 493 } 494 495 int 496 _isa_dmafinished(ids, chan) 497 struct isa_dma_state *ids; 498 int chan; 499 { 500 501 if (chan < 0 || chan > 7) { 502 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 503 panic("_isa_dmafinished"); 504 } 505 506 /* check that the terminal count was reached */ 507 if ((chan & 4) == 0) 508 ids->ids_dmafinished |= bus_space_read_1(ids->ids_bst, 509 ids->ids_dma1h, DMA1_SR) & 0x0f; 510 else 511 ids->ids_dmafinished |= (bus_space_read_1(ids->ids_bst, 512 ids->ids_dma2h, DMA2_SR) & 0x0f) << 4; 513 514 return ((ids->ids_dmafinished & (1 << chan)) != 0); 515 } 516 517 void 518 _isa_dmadone(ids, chan) 519 struct isa_dma_state *ids; 520 int chan; 521 { 522 bus_dmamap_t dmam; 523 524 if (chan < 0 || chan > 7) { 525 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 526 panic("_isa_dmadone"); 527 } 528 529 dmam = ids->ids_dmamaps[chan]; 530 531 _isa_dmamask(ids, chan); 532 533 if (_isa_dmafinished(ids, chan) == 0) 534 printf("%s: _isa_dmadone: channel %d not finished\n", 535 ids->ids_dev->dv_xname, chan); 536 537 bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize, 538 (ids->ids_dmareads & (1 << chan)) ? BUS_DMASYNC_POSTREAD : 539 BUS_DMASYNC_POSTWRITE); 540 541 bus_dmamap_unload(ids->ids_dmat, dmam); 542 ids->ids_dmareads &= ~(1 << chan); 543 } 544 545 void 546 _isa_dmafreeze(ids) 547 struct isa_dma_state *ids; 548 { 549 int s; 550 551 s = splhigh(); 552 553 if (ids->ids_frozen == 0) { 554 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, 555 DMA1_MASK, 0x0f); 556 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, 557 DMA2_MASK, 0x0f); 558 } 559 560 ids->ids_frozen++; 561 if (ids->ids_frozen < 1) 562 panic("_isa_dmafreeze: overflow"); 563 564 splx(s); 565 } 566 567 void 568 _isa_dmathaw(ids) 569 struct isa_dma_state *ids; 570 { 571 int s; 572 573 s = splhigh(); 574 575 ids->ids_frozen--; 576 if (ids->ids_frozen < 0) 577 panic("_isa_dmathaw: underflow"); 578 579 if (ids->ids_frozen == 0) { 580 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, 581 DMA1_MASK, ids->ids_masked & 0x0f); 582 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, 583 DMA2_MASK, (ids->ids_masked >> 4) & 0x0f); 584 } 585 586 splx(s); 587 } 588 589 int 590 _isa_dmamem_alloc(ids, chan, size, addrp, flags) 591 struct isa_dma_state *ids; 592 int chan; 593 bus_size_t size; 594 bus_addr_t *addrp; 595 int flags; 596 { 597 bus_dma_segment_t seg; 598 int error, boundary, rsegs; 599 600 if (chan < 0 || chan > 7) { 601 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 602 panic("_isa_dmamem_alloc"); 603 } 604 605 boundary = (chan & 4) ? (1 << 17) : (1 << 16); 606 607 size = round_page(size); 608 609 error = bus_dmamem_alloc(ids->ids_dmat, size, NBPG, boundary, 610 &seg, 1, &rsegs, flags); 611 if (error) 612 return (error); 613 614 *addrp = seg.ds_addr; 615 return (0); 616 } 617 618 void 619 _isa_dmamem_free(ids, chan, addr, size) 620 struct isa_dma_state *ids; 621 int chan; 622 bus_addr_t addr; 623 bus_size_t size; 624 { 625 bus_dma_segment_t seg; 626 627 if (chan < 0 || chan > 7) { 628 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 629 panic("_isa_dmamem_free"); 630 } 631 632 seg.ds_addr = addr; 633 seg.ds_len = size; 634 635 bus_dmamem_free(ids->ids_dmat, &seg, 1); 636 } 637 638 int 639 _isa_dmamem_map(ids, chan, addr, size, kvap, flags) 640 struct isa_dma_state *ids; 641 int chan; 642 bus_addr_t addr; 643 bus_size_t size; 644 caddr_t *kvap; 645 int flags; 646 { 647 bus_dma_segment_t seg; 648 649 if (chan < 0 || chan > 7) { 650 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 651 panic("_isa_dmamem_map"); 652 } 653 654 seg.ds_addr = addr; 655 seg.ds_len = size; 656 657 return (bus_dmamem_map(ids->ids_dmat, &seg, 1, size, kvap, flags)); 658 } 659 660 void 661 _isa_dmamem_unmap(ids, chan, kva, size) 662 struct isa_dma_state *ids; 663 int chan; 664 caddr_t kva; 665 size_t size; 666 { 667 668 if (chan < 0 || chan > 7) { 669 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 670 panic("_isa_dmamem_unmap"); 671 } 672 673 bus_dmamem_unmap(ids->ids_dmat, kva, size); 674 } 675 676 int 677 _isa_dmamem_mmap(ids, chan, addr, size, off, prot, flags) 678 struct isa_dma_state *ids; 679 int chan; 680 bus_addr_t addr; 681 bus_size_t size; 682 int off, prot, flags; 683 { 684 bus_dma_segment_t seg; 685 686 if (chan < 0 || chan > 7) { 687 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 688 panic("_isa_dmamem_mmap"); 689 } 690 691 if (off < 0) 692 return (-1); 693 694 seg.ds_addr = addr; 695 seg.ds_len = size; 696 697 return (bus_dmamem_mmap(ids->ids_dmat, &seg, 1, off, prot, flags)); 698 } 699 700 int 701 _isa_drq_isfree(ids, chan) 702 struct isa_dma_state *ids; 703 int chan; 704 { 705 706 if (chan < 0 || chan > 7) { 707 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 708 panic("_isa_drq_isfree"); 709 } 710 711 return ISA_DMA_DRQ_ISFREE(ids, chan); 712 } 713 714 void * 715 _isa_malloc(ids, chan, size, pool, flags) 716 struct isa_dma_state *ids; 717 int chan; 718 size_t size; 719 int pool; 720 int flags; 721 { 722 bus_addr_t addr; 723 caddr_t kva; 724 int bflags; 725 struct isa_mem *m; 726 727 bflags = flags & M_WAITOK ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT; 728 729 if (_isa_dmamem_alloc(ids, chan, size, &addr, bflags)) 730 return 0; 731 if (_isa_dmamem_map(ids, chan, addr, size, &kva, bflags)) { 732 _isa_dmamem_free(ids, chan, addr, size); 733 return 0; 734 } 735 m = malloc(sizeof(*m), pool, flags); 736 if (m == 0) { 737 _isa_dmamem_unmap(ids, chan, kva, size); 738 _isa_dmamem_free(ids, chan, addr, size); 739 return 0; 740 } 741 m->ids = ids; 742 m->chan = chan; 743 m->size = size; 744 m->addr = addr; 745 m->kva = kva; 746 m->next = isa_mem_head; 747 isa_mem_head = m; 748 return (void *)kva; 749 } 750 751 void 752 _isa_free(addr, pool) 753 void *addr; 754 int pool; 755 { 756 struct isa_mem **mp, *m; 757 caddr_t kva = (caddr_t)addr; 758 759 for(mp = &isa_mem_head; *mp && (*mp)->kva != kva; 760 mp = &(*mp)->next) 761 ; 762 m = *mp; 763 if (!m) { 764 printf("_isa_free: freeing unallocted memory\n"); 765 return; 766 } 767 *mp = m->next; 768 _isa_dmamem_unmap(m->ids, m->chan, kva, m->size); 769 _isa_dmamem_free(m->ids, m->chan, m->addr, m->size); 770 free(m, pool); 771 } 772 773 int 774 _isa_mappage(mem, off, prot) 775 void *mem; 776 int off; 777 int prot; 778 { 779 struct isa_mem *m; 780 781 for(m = isa_mem_head; m && m->kva != (caddr_t)mem; m = m->next) 782 ; 783 if (!m) { 784 printf("_isa_mappage: mapping unallocted memory\n"); 785 return -1; 786 } 787 return _isa_dmamem_mmap(m->ids, m->chan, m->addr, 788 m->size, off, prot, BUS_DMA_WAITOK); 789 } 790