1 /* $NetBSD: isadma.c,v 1.50 2002/09/27 15:37:22 provos 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.50 2002/09/27 15:37:22 provos 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 bus_size_t 256 _isa_dmamaxsize(ids, chan) 257 struct isa_dma_state *ids; 258 int chan; 259 { 260 261 if (chan < 0 || chan > 7) { 262 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 263 return (0); 264 } 265 266 return (ids->ids_maxsize[chan]); 267 } 268 269 int 270 _isa_dmamap_create(ids, chan, size, flags) 271 struct isa_dma_state *ids; 272 int chan; 273 bus_size_t size; 274 int flags; 275 { 276 int error; 277 278 if (chan < 0 || chan > 7) { 279 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 280 return (EINVAL); 281 } 282 283 if (size > ids->ids_maxsize[chan]) 284 return (EINVAL); 285 286 if (ISA_DMA_DRQ_ISFREE(ids, chan) == 0) { 287 printf("%s: drq %d is not free\n", ids->ids_dev->dv_xname, 288 chan); 289 return (EAGAIN); 290 } 291 292 ISA_DMA_DRQ_ALLOC(ids, chan); 293 294 error = bus_dmamap_create(ids->ids_dmat, size, 1, size, 295 ids->ids_maxsize[chan], flags, &ids->ids_dmamaps[chan]); 296 297 if (error) 298 ISA_DMA_DRQ_FREE(ids, chan); 299 300 return (error); 301 } 302 303 void 304 _isa_dmamap_destroy(ids, chan) 305 struct isa_dma_state *ids; 306 int chan; 307 { 308 309 if (chan < 0 || chan > 7) { 310 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 311 goto lose; 312 } 313 314 if (ISA_DMA_DRQ_ISFREE(ids, chan)) { 315 printf("%s: drq %d is already free\n", 316 ids->ids_dev->dv_xname, chan); 317 goto lose; 318 } 319 320 ISA_DMA_DRQ_FREE(ids, chan); 321 322 bus_dmamap_destroy(ids->ids_dmat, ids->ids_dmamaps[chan]); 323 return; 324 325 lose: 326 panic("_isa_dmamap_destroy"); 327 } 328 329 /* 330 * _isa_dmastart(): program 8237 DMA controller channel and set it 331 * in motion. 332 */ 333 int 334 _isa_dmastart(ids, chan, addr, nbytes, p, flags, busdmaflags) 335 struct isa_dma_state *ids; 336 int chan; 337 void *addr; 338 bus_size_t nbytes; 339 struct proc *p; 340 int flags; 341 int busdmaflags; 342 { 343 bus_dmamap_t dmam; 344 bus_addr_t dmaaddr; 345 int waport; 346 int ochan = chan & 3; 347 int error; 348 349 if (chan < 0 || chan > 7) { 350 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 351 goto lose; 352 } 353 354 #ifdef ISADMA_DEBUG 355 printf("_isa_dmastart: drq %d, addr %p, nbytes 0x%lx, p %p, " 356 "flags 0x%x, dmaflags 0x%x\n", 357 chan, addr, nbytes, p, flags, busdmaflags); 358 #endif 359 360 if (chan & 4) { 361 if (nbytes > (1 << 17) || nbytes & 1 || (u_long)addr & 1) { 362 printf("%s: drq %d, nbytes 0x%lx, addr %p\n", 363 ids->ids_dev->dv_xname, chan, 364 (unsigned long) nbytes, addr); 365 goto lose; 366 } 367 } else { 368 if (nbytes > (1 << 16)) { 369 printf("%s: drq %d, nbytes 0x%lx\n", 370 ids->ids_dev->dv_xname, chan, 371 (unsigned long) nbytes); 372 goto lose; 373 } 374 } 375 376 dmam = ids->ids_dmamaps[chan]; 377 if (dmam == NULL) 378 panic("_isa_dmastart: no DMA map for chan %d", chan); 379 380 error = bus_dmamap_load(ids->ids_dmat, dmam, addr, nbytes, 381 p, busdmaflags | 382 ((flags & DMAMODE_READ) ? BUS_DMA_READ : BUS_DMA_WRITE)); 383 if (error) 384 return (error); 385 386 #ifdef ISADMA_DEBUG 387 __asm(".globl isa_dmastart_afterload ; isa_dmastart_afterload:"); 388 #endif 389 390 if (flags & DMAMODE_READ) { 391 bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize, 392 BUS_DMASYNC_PREREAD); 393 ids->ids_dmareads |= (1 << chan); 394 } else { 395 bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize, 396 BUS_DMASYNC_PREWRITE); 397 ids->ids_dmareads &= ~(1 << chan); 398 } 399 400 dmaaddr = dmam->dm_segs[0].ds_addr; 401 402 #ifdef ISADMA_DEBUG 403 printf(" dmaaddr 0x%lx\n", dmaaddr); 404 405 __asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:"); 406 #endif 407 408 ids->ids_dmalength[chan] = nbytes; 409 410 _isa_dmamask(ids, chan); 411 ids->ids_dmafinished &= ~(1 << chan); 412 413 if ((chan & 4) == 0) { 414 /* set dma channel mode */ 415 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, DMA1_MODE, 416 ochan | dmamode[flags]); 417 418 /* send start address */ 419 waport = DMA1_CHN(ochan); 420 bus_space_write_1(ids->ids_bst, ids->ids_dmapgh, 421 dmapageport[0][ochan], (dmaaddr >> 16) & 0xff); 422 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport, 423 dmaaddr & 0xff); 424 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport, 425 (dmaaddr >> 8) & 0xff); 426 427 /* send count */ 428 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1, 429 (--nbytes) & 0xff); 430 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1, 431 (nbytes >> 8) & 0xff); 432 } else { 433 /* set dma channel mode */ 434 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, DMA2_MODE, 435 ochan | dmamode[flags]); 436 437 /* send start address */ 438 waport = DMA2_CHN(ochan); 439 bus_space_write_1(ids->ids_bst, ids->ids_dmapgh, 440 dmapageport[1][ochan], (dmaaddr >> 16) & 0xff); 441 dmaaddr >>= 1; 442 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport, 443 dmaaddr & 0xff); 444 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport, 445 (dmaaddr >> 8) & 0xff); 446 447 /* send count */ 448 nbytes >>= 1; 449 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport + 2, 450 (--nbytes) & 0xff); 451 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport + 2, 452 (nbytes >> 8) & 0xff); 453 } 454 455 _isa_dmaunmask(ids, chan); 456 return (0); 457 458 lose: 459 panic("_isa_dmastart"); 460 } 461 462 void 463 _isa_dmaabort(ids, chan) 464 struct isa_dma_state *ids; 465 int chan; 466 { 467 468 if (chan < 0 || chan > 7) { 469 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 470 panic("_isa_dmaabort"); 471 } 472 473 _isa_dmamask(ids, chan); 474 bus_dmamap_unload(ids->ids_dmat, ids->ids_dmamaps[chan]); 475 ids->ids_dmareads &= ~(1 << chan); 476 } 477 478 bus_size_t 479 _isa_dmacount(ids, chan) 480 struct isa_dma_state *ids; 481 int chan; 482 { 483 int waport; 484 bus_size_t nbytes; 485 int ochan = chan & 3; 486 487 if (chan < 0 || chan > 7) { 488 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 489 panic("isa_dmacount"); 490 } 491 492 _isa_dmamask(ids, chan); 493 494 /* 495 * We have to shift the byte count by 1. If we're in auto-initialize 496 * mode, the count may have wrapped around to the initial value. We 497 * can't use the TC bit to check for this case, so instead we compare 498 * against the original byte count. 499 * If we're not in auto-initialize mode, then the count will wrap to 500 * -1, so we also handle that case. 501 */ 502 if ((chan & 4) == 0) { 503 waport = DMA1_CHN(ochan); 504 nbytes = bus_space_read_1(ids->ids_bst, ids->ids_dma1h, 505 waport + 1) + 1; 506 nbytes += bus_space_read_1(ids->ids_bst, ids->ids_dma1h, 507 waport + 1) << 8; 508 nbytes &= 0xffff; 509 } else { 510 waport = DMA2_CHN(ochan); 511 nbytes = bus_space_read_1(ids->ids_bst, ids->ids_dma2h, 512 waport + 2) + 1; 513 nbytes += bus_space_read_1(ids->ids_bst, ids->ids_dma2h, 514 waport + 2) << 8; 515 nbytes <<= 1; 516 nbytes &= 0x1ffff; 517 } 518 519 if (nbytes == ids->ids_dmalength[chan]) 520 nbytes = 0; 521 522 _isa_dmaunmask(ids, chan); 523 return (nbytes); 524 } 525 526 int 527 _isa_dmafinished(ids, chan) 528 struct isa_dma_state *ids; 529 int chan; 530 { 531 532 if (chan < 0 || chan > 7) { 533 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 534 panic("_isa_dmafinished"); 535 } 536 537 /* check that the terminal count was reached */ 538 if ((chan & 4) == 0) 539 ids->ids_dmafinished |= bus_space_read_1(ids->ids_bst, 540 ids->ids_dma1h, DMA1_SR) & 0x0f; 541 else 542 ids->ids_dmafinished |= (bus_space_read_1(ids->ids_bst, 543 ids->ids_dma2h, DMA2_SR) & 0x0f) << 4; 544 545 return ((ids->ids_dmafinished & (1 << chan)) != 0); 546 } 547 548 void 549 _isa_dmadone(ids, chan) 550 struct isa_dma_state *ids; 551 int chan; 552 { 553 bus_dmamap_t dmam; 554 555 if (chan < 0 || chan > 7) { 556 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 557 panic("_isa_dmadone"); 558 } 559 560 dmam = ids->ids_dmamaps[chan]; 561 562 _isa_dmamask(ids, chan); 563 564 if (_isa_dmafinished(ids, chan) == 0) 565 printf("%s: _isa_dmadone: channel %d not finished\n", 566 ids->ids_dev->dv_xname, chan); 567 568 bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize, 569 (ids->ids_dmareads & (1 << chan)) ? BUS_DMASYNC_POSTREAD : 570 BUS_DMASYNC_POSTWRITE); 571 572 bus_dmamap_unload(ids->ids_dmat, dmam); 573 ids->ids_dmareads &= ~(1 << chan); 574 } 575 576 void 577 _isa_dmafreeze(ids) 578 struct isa_dma_state *ids; 579 { 580 int s; 581 582 s = splhigh(); 583 584 if (ids->ids_frozen == 0) { 585 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, 586 DMA1_MASK, 0x0f); 587 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, 588 DMA2_MASK, 0x0f); 589 } 590 591 ids->ids_frozen++; 592 if (ids->ids_frozen < 1) 593 panic("_isa_dmafreeze: overflow"); 594 595 splx(s); 596 } 597 598 void 599 _isa_dmathaw(ids) 600 struct isa_dma_state *ids; 601 { 602 int s; 603 604 s = splhigh(); 605 606 ids->ids_frozen--; 607 if (ids->ids_frozen < 0) 608 panic("_isa_dmathaw: underflow"); 609 610 if (ids->ids_frozen == 0) { 611 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, 612 DMA1_MASK, ids->ids_masked & 0x0f); 613 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, 614 DMA2_MASK, (ids->ids_masked >> 4) & 0x0f); 615 } 616 617 splx(s); 618 } 619 620 int 621 _isa_dmamem_alloc(ids, chan, size, addrp, flags) 622 struct isa_dma_state *ids; 623 int chan; 624 bus_size_t size; 625 bus_addr_t *addrp; 626 int flags; 627 { 628 bus_dma_segment_t seg; 629 int error, boundary, rsegs; 630 631 if (chan < 0 || chan > 7) { 632 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 633 panic("_isa_dmamem_alloc"); 634 } 635 636 boundary = (chan & 4) ? (1 << 17) : (1 << 16); 637 638 size = round_page(size); 639 640 error = bus_dmamem_alloc(ids->ids_dmat, size, PAGE_SIZE, boundary, 641 &seg, 1, &rsegs, flags); 642 if (error) 643 return (error); 644 645 *addrp = seg.ds_addr; 646 return (0); 647 } 648 649 void 650 _isa_dmamem_free(ids, chan, addr, size) 651 struct isa_dma_state *ids; 652 int chan; 653 bus_addr_t addr; 654 bus_size_t size; 655 { 656 bus_dma_segment_t seg; 657 658 if (chan < 0 || chan > 7) { 659 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 660 panic("_isa_dmamem_free"); 661 } 662 663 seg.ds_addr = addr; 664 seg.ds_len = size; 665 666 bus_dmamem_free(ids->ids_dmat, &seg, 1); 667 } 668 669 int 670 _isa_dmamem_map(ids, chan, addr, size, kvap, flags) 671 struct isa_dma_state *ids; 672 int chan; 673 bus_addr_t addr; 674 bus_size_t size; 675 caddr_t *kvap; 676 int flags; 677 { 678 bus_dma_segment_t seg; 679 680 if (chan < 0 || chan > 7) { 681 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 682 panic("_isa_dmamem_map"); 683 } 684 685 seg.ds_addr = addr; 686 seg.ds_len = size; 687 688 return (bus_dmamem_map(ids->ids_dmat, &seg, 1, size, kvap, flags)); 689 } 690 691 void 692 _isa_dmamem_unmap(ids, chan, kva, size) 693 struct isa_dma_state *ids; 694 int chan; 695 caddr_t kva; 696 size_t size; 697 { 698 699 if (chan < 0 || chan > 7) { 700 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 701 panic("_isa_dmamem_unmap"); 702 } 703 704 bus_dmamem_unmap(ids->ids_dmat, kva, size); 705 } 706 707 paddr_t 708 _isa_dmamem_mmap(ids, chan, addr, size, off, prot, flags) 709 struct isa_dma_state *ids; 710 int chan; 711 bus_addr_t addr; 712 bus_size_t size; 713 off_t off; 714 int prot, flags; 715 { 716 bus_dma_segment_t seg; 717 718 if (chan < 0 || chan > 7) { 719 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 720 panic("_isa_dmamem_mmap"); 721 } 722 723 if (off < 0) 724 return (-1); 725 726 seg.ds_addr = addr; 727 seg.ds_len = size; 728 729 return (bus_dmamem_mmap(ids->ids_dmat, &seg, 1, off, prot, flags)); 730 } 731 732 int 733 _isa_drq_isfree(ids, chan) 734 struct isa_dma_state *ids; 735 int chan; 736 { 737 738 if (chan < 0 || chan > 7) { 739 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan); 740 panic("_isa_drq_isfree"); 741 } 742 743 return ISA_DMA_DRQ_ISFREE(ids, chan); 744 } 745 746 void * 747 _isa_malloc(ids, chan, size, pool, flags) 748 struct isa_dma_state *ids; 749 int chan; 750 size_t size; 751 int pool; 752 int flags; 753 { 754 bus_addr_t addr; 755 caddr_t kva; 756 int bflags; 757 struct isa_mem *m; 758 759 bflags = flags & M_WAITOK ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT; 760 761 if (_isa_dmamem_alloc(ids, chan, size, &addr, bflags)) 762 return 0; 763 if (_isa_dmamem_map(ids, chan, addr, size, &kva, bflags)) { 764 _isa_dmamem_free(ids, chan, addr, size); 765 return 0; 766 } 767 m = malloc(sizeof(*m), pool, flags); 768 if (m == 0) { 769 _isa_dmamem_unmap(ids, chan, kva, size); 770 _isa_dmamem_free(ids, chan, addr, size); 771 return 0; 772 } 773 m->ids = ids; 774 m->chan = chan; 775 m->size = size; 776 m->addr = addr; 777 m->kva = kva; 778 m->next = isa_mem_head; 779 isa_mem_head = m; 780 return (void *)kva; 781 } 782 783 void 784 _isa_free(addr, pool) 785 void *addr; 786 int pool; 787 { 788 struct isa_mem **mp, *m; 789 caddr_t kva = (caddr_t)addr; 790 791 for(mp = &isa_mem_head; *mp && (*mp)->kva != kva; 792 mp = &(*mp)->next) 793 ; 794 m = *mp; 795 if (!m) { 796 printf("_isa_free: freeing unallocted memory\n"); 797 return; 798 } 799 *mp = m->next; 800 _isa_dmamem_unmap(m->ids, m->chan, kva, m->size); 801 _isa_dmamem_free(m->ids, m->chan, m->addr, m->size); 802 free(m, pool); 803 } 804 805 paddr_t 806 _isa_mappage(mem, off, prot) 807 void *mem; 808 off_t off; 809 int prot; 810 { 811 struct isa_mem *m; 812 813 for(m = isa_mem_head; m && m->kva != (caddr_t)mem; m = m->next) 814 ; 815 if (!m) { 816 printf("_isa_mappage: mapping unallocted memory\n"); 817 return -1; 818 } 819 return _isa_dmamem_mmap(m->ids, m->chan, m->addr, 820 m->size, off, prot, BUS_DMA_WAITOK); 821 } 822