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