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