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