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