isadma.c revision 1.38 1 /* $NetBSD: isadma.c,v 1.38 1998/07/08 05:23:23 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1997, 1998 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 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Device driver for the ISA on-board DMA controller.
42 */
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/proc.h>
47 #include <sys/device.h>
48 #include <sys/malloc.h>
49
50 #include <vm/vm.h>
51
52 #include <machine/bus.h>
53
54 #include <dev/isa/isareg.h>
55 #include <dev/isa/isavar.h>
56 #include <dev/isa/isadmavar.h>
57 #include <dev/isa/isadmareg.h>
58
59 struct isa_mem *isa_mem_head;
60
61 /*
62 * High byte of DMA address is stored in this DMAPG register for
63 * the Nth DMA channel.
64 */
65 static int dmapageport[2][4] = {
66 {0x7, 0x3, 0x1, 0x2},
67 {0xf, 0xb, 0x9, 0xa}
68 };
69
70 static u_int8_t dmamode[] = {
71 /* write to device/read from device */
72 DMA37MD_READ | DMA37MD_SINGLE,
73 DMA37MD_WRITE | DMA37MD_SINGLE,
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 __P((struct isa_dma_state *, int));
85 static inline void _isa_dmamask __P((struct isa_dma_state *, int));
86
87 static inline void
88 _isa_dmaunmask(ids, chan)
89 struct isa_dma_state *ids;
90 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(ids, chan)
114 struct isa_dma_state *ids;
115 int chan;
116 {
117 int ochan = chan & 3;
118
119 ISA_DMA_MASK_SET(ids, chan);
120
121 /*
122 * XXX Should we avoid masking the channel if DMA is
123 * XXX frozen? It seems like what we're doing should
124 * XXX be safe, and we do need to reset FFC...
125 */
126
127 /* set dma channel mode, and set dma channel mode */
128 if ((chan & 4) == 0) {
129 bus_space_write_1(ids->ids_bst, ids->ids_dma1h,
130 DMA1_SMSK, ochan | DMA37SM_SET);
131 bus_space_write_1(ids->ids_bst, ids->ids_dma1h,
132 DMA1_FFC, 0);
133 } else {
134 bus_space_write_1(ids->ids_bst, ids->ids_dma2h,
135 DMA2_SMSK, ochan | DMA37SM_SET);
136 bus_space_write_1(ids->ids_bst, ids->ids_dma2h,
137 DMA2_FFC, 0);
138 }
139 }
140
141 /*
142 * _isa_dmainit(): Initialize the isa_dma_state for this chipset.
143 */
144 void
145 _isa_dmainit(ids, bst, dmat, dev)
146 struct isa_dma_state *ids;
147 bus_space_tag_t bst;
148 bus_dma_tag_t dmat;
149 struct device *dev;
150 {
151
152 ids->ids_dev = dev;
153
154 if (ids->ids_initialized) {
155 /*
156 * Some systems may have e.g. `ofisa' (OpenFirmware
157 * configuration of ISA bus) and a regular `isa'.
158 * We allow both to call the initialization function,
159 * and take the device name from the last caller
160 * (assuming it will be the indirect ISA bus). Since
161 * `ofisa' and `isa' are the same bus with different
162 * configuration mechanisms, the space and dma tags
163 * must be the same!
164 */
165 if (ids->ids_bst != bst || ids->ids_dmat != dmat)
166 panic("_isa_dmainit: inconsistent ISA tags");
167 } else {
168 ids->ids_bst = bst;
169 ids->ids_dmat = dmat;
170
171 /*
172 * Map the registers used by the ISA DMA controller.
173 */
174 if (bus_space_map(ids->ids_bst, IO_DMA1, DMA1_IOSIZE, 0,
175 &ids->ids_dma1h))
176 panic("_isa_dmainit: unable to map DMA controller #1");
177 if (bus_space_map(ids->ids_bst, IO_DMA2, DMA2_IOSIZE, 0,
178 &ids->ids_dma2h))
179 panic("_isa_dmainit: unable to map DMA controller #2");
180 if (bus_space_map(ids->ids_bst, IO_DMAPG, 0xf, 0,
181 &ids->ids_dmapgh))
182 panic("_isa_dmainit: unable to map DMA page registers");
183
184 /*
185 * All 8 DMA channels start out "masked".
186 */
187 ids->ids_masked = 0xff;
188
189 ids->ids_initialized = 1;
190
191 /*
192 * DRQ 4 is used to chain the two 8237s together; make
193 * sure it's always cascaded, and that it will be unmasked
194 * when DMA is thawed.
195 */
196 _isa_dmacascade(ids, 4);
197 }
198 }
199
200 /*
201 * _isa_dmacascade(): program 8237 DMA controller channel to accept
202 * external dma control by a board.
203 */
204 int
205 _isa_dmacascade(ids, chan)
206 struct isa_dma_state *ids;
207 int chan;
208 {
209 int ochan = chan & 3;
210
211 if (chan < 0 || chan > 7) {
212 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
213 return (EINVAL);
214 }
215
216 if (ISA_DMA_DRQ_ISFREE(ids, chan) == 0) {
217 printf("%s: DRQ %d is not free\n", ids->ids_dev->dv_xname,
218 chan);
219 return (EAGAIN);
220 }
221
222 ISA_DMA_DRQ_ALLOC(ids, chan);
223
224 /* set dma channel mode, and set dma channel mode */
225 if ((chan & 4) == 0)
226 bus_space_write_1(ids->ids_bst, ids->ids_dma1h,
227 DMA1_MODE, ochan | DMA37MD_CASCADE);
228 else
229 bus_space_write_1(ids->ids_bst, ids->ids_dma2h,
230 DMA2_MODE, ochan | DMA37MD_CASCADE);
231
232 _isa_dmaunmask(ids, chan);
233 return (0);
234 }
235
236 int
237 _isa_dmamap_create(ids, chan, size, flags)
238 struct isa_dma_state *ids;
239 int chan;
240 bus_size_t size;
241 int flags;
242 {
243 bus_size_t maxsize;
244
245 if (chan < 0 || chan > 7) {
246 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
247 return (EINVAL);
248 }
249
250 if (chan & 4)
251 maxsize = (1 << 17);
252 else
253 maxsize = (1 << 16);
254
255 if (size > maxsize)
256 return (EINVAL);
257
258 if (ISA_DMA_DRQ_ISFREE(ids, chan) == 0) {
259 printf("%s: drq %d is not free\n", ids->ids_dev->dv_xname,
260 chan);
261 return (EAGAIN);
262 }
263
264 ISA_DMA_DRQ_ALLOC(ids, chan);
265
266 return (bus_dmamap_create(ids->ids_dmat, size, 1, size, maxsize,
267 flags, &ids->ids_dmamaps[chan]));
268 }
269
270 void
271 _isa_dmamap_destroy(ids, chan)
272 struct isa_dma_state *ids;
273 int chan;
274 {
275
276 if (chan < 0 || chan > 7) {
277 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
278 goto lose;
279 }
280
281 if (ISA_DMA_DRQ_ISFREE(ids, chan)) {
282 printf("%s: drq %d is already free\n",
283 ids->ids_dev->dv_xname, chan);
284 goto lose;
285 }
286
287 ISA_DMA_DRQ_FREE(ids, chan);
288
289 bus_dmamap_destroy(ids->ids_dmat, ids->ids_dmamaps[chan]);
290 return;
291
292 lose:
293 panic("_isa_dmamap_destroy");
294 }
295
296 /*
297 * _isa_dmastart(): program 8237 DMA controller channel and set it
298 * in motion.
299 */
300 int
301 _isa_dmastart(ids, chan, addr, nbytes, p, flags, busdmaflags)
302 struct isa_dma_state *ids;
303 int chan;
304 void *addr;
305 bus_size_t nbytes;
306 struct proc *p;
307 int flags;
308 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", ids->ids_dev->dv_xname, 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, nbytes, p, flags, busdmaflags);
325 #endif
326
327 /* Can't specify LOOP and LOOPDEMAND together. */
328 if ((flags & (DMAMODE_LOOP|DMAMODE_LOOPDEMAND)) ==
329 (DMAMODE_LOOP|DMAMODE_LOOPDEMAND))
330 return (EINVAL);
331
332 if (chan & 4) {
333 if (nbytes > (1 << 17) || nbytes & 1 || (u_long)addr & 1) {
334 printf("%s: drq %d, nbytes 0x%lx, addr %p\n",
335 ids->ids_dev->dv_xname, chan, nbytes, addr);
336 goto lose;
337 }
338 } else {
339 if (nbytes > (1 << 16)) {
340 printf("%s: drq %d, nbytes 0x%lx\n",
341 ids->ids_dev->dv_xname, chan, nbytes);
342 goto lose;
343 }
344 }
345
346 dmam = ids->ids_dmamaps[chan];
347 if (dmam == NULL)
348 panic("_isa_dmastart: no DMA map for chan %d\n", chan);
349
350 error = bus_dmamap_load(ids->ids_dmat, dmam, addr, nbytes,
351 p, busdmaflags);
352 if (error)
353 return (error);
354
355 #ifdef ISADMA_DEBUG
356 __asm(".globl isa_dmastart_afterload ; isa_dmastart_afterload:");
357 #endif
358
359 if (flags & DMAMODE_READ) {
360 bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize,
361 BUS_DMASYNC_PREREAD);
362 ids->ids_dmareads |= (1 << chan);
363 } else {
364 bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize,
365 BUS_DMASYNC_PREWRITE);
366 ids->ids_dmareads &= ~(1 << chan);
367 }
368
369 dmaaddr = dmam->dm_segs[0].ds_addr;
370
371 #ifdef ISADMA_DEBUG
372 printf(" dmaaddr 0x%lx\n", dmaaddr);
373
374 __asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:");
375 #endif
376
377 ids->ids_dmalength[chan] = nbytes;
378
379 _isa_dmamask(ids, chan);
380 ids->ids_dmafinished &= ~(1 << chan);
381
382 if ((chan & 4) == 0) {
383 /* set dma channel mode */
384 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, DMA1_MODE,
385 ochan | dmamode[flags]);
386
387 /* send start address */
388 waport = DMA1_CHN(ochan);
389 bus_space_write_1(ids->ids_bst, ids->ids_dmapgh,
390 dmapageport[0][ochan], (dmaaddr >> 16) & 0xff);
391 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport,
392 dmaaddr & 0xff);
393 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport,
394 (dmaaddr >> 8) & 0xff);
395
396 /* send count */
397 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1,
398 (--nbytes) & 0xff);
399 bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1,
400 (nbytes >> 8) & 0xff);
401 } else {
402 /* set dma channel mode */
403 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, DMA2_MODE,
404 ochan | dmamode[flags]);
405
406 /* send start address */
407 waport = DMA2_CHN(ochan);
408 bus_space_write_1(ids->ids_bst, ids->ids_dmapgh,
409 dmapageport[1][ochan], (dmaaddr >> 16) & 0xff);
410 dmaaddr >>= 1;
411 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport,
412 dmaaddr & 0xff);
413 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport,
414 (dmaaddr >> 8) & 0xff);
415
416 /* send count */
417 nbytes >>= 1;
418 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport + 2,
419 (--nbytes) & 0xff);
420 bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport + 2,
421 (nbytes >> 8) & 0xff);
422 }
423
424 _isa_dmaunmask(ids, chan);
425 return (0);
426
427 lose:
428 panic("_isa_dmastart");
429 }
430
431 void
432 _isa_dmaabort(ids, chan)
433 struct isa_dma_state *ids;
434 int chan;
435 {
436
437 if (chan < 0 || chan > 7) {
438 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
439 panic("_isa_dmaabort");
440 }
441
442 _isa_dmamask(ids, chan);
443 bus_dmamap_unload(ids->ids_dmat, ids->ids_dmamaps[chan]);
444 ids->ids_dmareads &= ~(1 << chan);
445 }
446
447 bus_size_t
448 _isa_dmacount(ids, chan)
449 struct isa_dma_state *ids;
450 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", ids->ids_dev->dv_xname, 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(ids, chan)
497 struct isa_dma_state *ids;
498 int chan;
499 {
500
501 if (chan < 0 || chan > 7) {
502 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
503 panic("_isa_dmafinished");
504 }
505
506 /* check that the terminal count was reached */
507 if ((chan & 4) == 0)
508 ids->ids_dmafinished |= bus_space_read_1(ids->ids_bst,
509 ids->ids_dma1h, DMA1_SR) & 0x0f;
510 else
511 ids->ids_dmafinished |= (bus_space_read_1(ids->ids_bst,
512 ids->ids_dma2h, DMA2_SR) & 0x0f) << 4;
513
514 return ((ids->ids_dmafinished & (1 << chan)) != 0);
515 }
516
517 void
518 _isa_dmadone(ids, chan)
519 struct isa_dma_state *ids;
520 int chan;
521 {
522 bus_dmamap_t dmam;
523
524 if (chan < 0 || chan > 7) {
525 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
526 panic("_isa_dmadone");
527 }
528
529 dmam = ids->ids_dmamaps[chan];
530
531 _isa_dmamask(ids, chan);
532
533 if (_isa_dmafinished(ids, chan) == 0)
534 printf("%s: _isa_dmadone: channel %d not finished\n",
535 ids->ids_dev->dv_xname, chan);
536
537 bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize,
538 (ids->ids_dmareads & (1 << chan)) ? BUS_DMASYNC_POSTREAD :
539 BUS_DMASYNC_POSTWRITE);
540
541 bus_dmamap_unload(ids->ids_dmat, dmam);
542 ids->ids_dmareads &= ~(1 << chan);
543 }
544
545 void
546 _isa_dmafreeze(ids)
547 struct isa_dma_state *ids;
548 {
549 int s;
550
551 s = splhigh();
552
553 if (ids->ids_frozen == 0) {
554 bus_space_write_1(ids->ids_bst, ids->ids_dma1h,
555 DMA1_MASK, 0x0f);
556 bus_space_write_1(ids->ids_bst, ids->ids_dma2h,
557 DMA2_MASK, 0x0f);
558 }
559
560 ids->ids_frozen++;
561 if (ids->ids_frozen < 1)
562 panic("_isa_dmafreeze: overflow");
563
564 splx(s);
565 }
566
567 void
568 _isa_dmathaw(ids)
569 struct isa_dma_state *ids;
570 {
571 int s;
572
573 s = splhigh();
574
575 ids->ids_frozen--;
576 if (ids->ids_frozen < 0)
577 panic("_isa_dmathaw: underflow");
578
579 if (ids->ids_frozen == 0) {
580 bus_space_write_1(ids->ids_bst, ids->ids_dma1h,
581 DMA1_MASK, ids->ids_masked & 0x0f);
582 bus_space_write_1(ids->ids_bst, ids->ids_dma2h,
583 DMA2_MASK, (ids->ids_masked >> 4) & 0x0f);
584 }
585
586 splx(s);
587 }
588
589 int
590 _isa_dmamem_alloc(ids, chan, size, addrp, flags)
591 struct isa_dma_state *ids;
592 int chan;
593 bus_size_t size;
594 bus_addr_t *addrp;
595 int flags;
596 {
597 bus_dma_segment_t seg;
598 int error, boundary, rsegs;
599
600 if (chan < 0 || chan > 7) {
601 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
602 panic("_isa_dmamem_alloc");
603 }
604
605 boundary = (chan & 4) ? (1 << 17) : (1 << 16);
606
607 size = round_page(size);
608
609 error = bus_dmamem_alloc(ids->ids_dmat, size, NBPG, boundary,
610 &seg, 1, &rsegs, flags);
611 if (error)
612 return (error);
613
614 *addrp = seg.ds_addr;
615 return (0);
616 }
617
618 void
619 _isa_dmamem_free(ids, chan, addr, size)
620 struct isa_dma_state *ids;
621 int chan;
622 bus_addr_t addr;
623 bus_size_t size;
624 {
625 bus_dma_segment_t seg;
626
627 if (chan < 0 || chan > 7) {
628 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
629 panic("_isa_dmamem_free");
630 }
631
632 seg.ds_addr = addr;
633 seg.ds_len = size;
634
635 bus_dmamem_free(ids->ids_dmat, &seg, 1);
636 }
637
638 int
639 _isa_dmamem_map(ids, chan, addr, size, kvap, flags)
640 struct isa_dma_state *ids;
641 int chan;
642 bus_addr_t addr;
643 bus_size_t size;
644 caddr_t *kvap;
645 int flags;
646 {
647 bus_dma_segment_t seg;
648
649 if (chan < 0 || chan > 7) {
650 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
651 panic("_isa_dmamem_map");
652 }
653
654 seg.ds_addr = addr;
655 seg.ds_len = size;
656
657 return (bus_dmamem_map(ids->ids_dmat, &seg, 1, size, kvap, flags));
658 }
659
660 void
661 _isa_dmamem_unmap(ids, chan, kva, size)
662 struct isa_dma_state *ids;
663 int chan;
664 caddr_t kva;
665 size_t size;
666 {
667
668 if (chan < 0 || chan > 7) {
669 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
670 panic("_isa_dmamem_unmap");
671 }
672
673 bus_dmamem_unmap(ids->ids_dmat, kva, size);
674 }
675
676 int
677 _isa_dmamem_mmap(ids, chan, addr, size, off, prot, flags)
678 struct isa_dma_state *ids;
679 int chan;
680 bus_addr_t addr;
681 bus_size_t size;
682 int off, prot, flags;
683 {
684 bus_dma_segment_t seg;
685
686 if (chan < 0 || chan > 7) {
687 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
688 panic("_isa_dmamem_mmap");
689 }
690
691 seg.ds_addr = addr;
692 seg.ds_len = size;
693
694 return (bus_dmamem_mmap(ids->ids_dmat, &seg, 1, off, prot, flags));
695 }
696
697 int
698 _isa_drq_isfree(ids, chan)
699 struct isa_dma_state *ids;
700 int chan;
701 {
702
703 if (chan < 0 || chan > 7) {
704 printf("%s: bogus drq %d\n", ids->ids_dev->dv_xname, chan);
705 panic("_isa_drq_isfree");
706 }
707
708 return ISA_DMA_DRQ_ISFREE(ids, chan);
709 }
710
711 void *
712 _isa_malloc(ids, chan, size, pool, flags)
713 struct isa_dma_state *ids;
714 int chan;
715 size_t size;
716 int pool;
717 int flags;
718 {
719 bus_addr_t addr;
720 caddr_t kva;
721 int bflags;
722 struct isa_mem *m;
723
724 bflags = flags & M_WAITOK ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT;
725
726 if (_isa_dmamem_alloc(ids, chan, size, &addr, bflags))
727 return 0;
728 if (_isa_dmamem_map(ids, chan, addr, size, &kva, bflags)) {
729 _isa_dmamem_free(ids, chan, addr, size);
730 return 0;
731 }
732 m = malloc(sizeof(*m), pool, flags);
733 if (m == 0) {
734 _isa_dmamem_unmap(ids, chan, kva, size);
735 _isa_dmamem_free(ids, chan, addr, size);
736 return 0;
737 }
738 m->ids = ids;
739 m->chan = chan;
740 m->size = size;
741 m->addr = addr;
742 m->kva = kva;
743 m->next = isa_mem_head;
744 isa_mem_head = m;
745 return (void *)kva;
746 }
747
748 void
749 _isa_free(addr, pool)
750 void *addr;
751 int pool;
752 {
753 struct isa_mem **mp, *m;
754 caddr_t kva = (caddr_t)addr;
755
756 for(mp = &isa_mem_head; *mp && (*mp)->kva != kva;
757 mp = &(*mp)->next)
758 ;
759 m = *mp;
760 if (!m) {
761 printf("_isa_free: freeing unallocted memory\n");
762 return;
763 }
764 *mp = m->next;
765 _isa_dmamem_unmap(m->ids, m->chan, kva, m->size);
766 _isa_dmamem_free(m->ids, m->chan, m->addr, m->size);
767 free(m, pool);
768 }
769
770 int
771 _isa_mappage(mem, off, prot)
772 void *mem;
773 int off;
774 int prot;
775 {
776 struct isa_mem *m;
777
778 for(m = isa_mem_head; m && m->kva != (caddr_t)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