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