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