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