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