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