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