isadma.c revision 1.61 1 /* $NetBSD: isadma.c,v 1.61 2009/05/12 09:10:15 cegger 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.61 2009/05/12 09:10:15 cegger 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 /*
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