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