1 /* $OpenBSD: isadma.c,v 1.37 2022/04/06 18:59:28 naddy Exp $ */
2 /* $NetBSD: isadma.c,v 1.32 1997/09/05 01:48:33 thorpej Exp $ */
3
4 /*-
5 * Copyright (c) 1997 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * Device driver for the ISA on-board DMA controller.
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41
42 #include <uvm/uvm_extern.h>
43
44 #include <machine/bus.h>
45
46 #include <dev/isa/isavar.h>
47 #include <dev/isa/isadmavar.h>
48 #include <dev/isa/isadmareg.h>
49
50 #ifdef __ISADMA_COMPAT
51 /* XXX ugly, but will go away soon... */
52 struct device *isa_dev;
53
54 bus_dmamap_t isadma_dmam[8];
55 #endif
56
57 /* Used by isa_malloc() */
58 #include <sys/malloc.h>
59 struct isa_mem {
60 struct device *isadev;
61 int chan;
62 bus_size_t size;
63 bus_addr_t addr;
64 caddr_t kva;
65 struct isa_mem *next;
66 } *isa_mem_head = 0;
67
68 /*
69 * High byte of DMA address is stored in this DMAPG register for
70 * the Nth DMA channel.
71 */
72 static int dmapageport[2][4] = {
73 {0x7, 0x3, 0x1, 0x2},
74 {0xf, 0xb, 0x9, 0xa}
75 };
76
77 static u_int8_t dmamode[4] = {
78 DMA37MD_READ | DMA37MD_SINGLE,
79 DMA37MD_WRITE | DMA37MD_SINGLE,
80 DMA37MD_READ | DMA37MD_SINGLE | DMA37MD_LOOP,
81 DMA37MD_WRITE | DMA37MD_SINGLE | DMA37MD_LOOP
82 };
83
84 int isadmamatch(struct device *, void *, void *);
85 void isadmaattach(struct device *, struct device *, void *);
86
87 const struct cfattach isadma_ca = {
88 sizeof(struct device), isadmamatch, isadmaattach
89 };
90
91 struct cfdriver isadma_cd = {
92 NULL, "isadma", DV_DULL, CD_INDIRECT
93 };
94
95 int
isadmamatch(struct device * parent,void * match,void * aux)96 isadmamatch(struct device *parent, void *match, void *aux)
97 {
98 struct isa_attach_args *ia = aux;
99
100 /* Sure we exist */
101 ia->ia_iosize = 0;
102 return (1);
103 }
104
105 void
isadmaattach(struct device * parent,struct device * self,void * aux)106 isadmaattach(struct device *parent, struct device *self, void *aux)
107 {
108 #ifdef __ISADMA_COMPAT
109 int i, sz;
110 struct isa_softc *sc = (struct isa_softc *)parent;
111
112 /* XXX ugly, but will go away soon... */
113 isa_dev = parent;
114
115 for (i = 0; i < 8; i++) {
116 sz = (i & 4) ? 1 << 17 : 1 << 16;
117 if ((bus_dmamap_create(sc->sc_dmat, sz, 1, sz, sz,
118 BUS_DMA_24BIT|BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
119 &isadma_dmam[i])) != 0)
120 panic("isadmaattach: can not create DMA map");
121 }
122 #endif
123
124 /* XXX I'd like to map the DMA ports here, see isa.c why not... */
125
126 printf("\n");
127 }
128
129 static inline void isa_dmaunmask(struct isa_softc *, int);
130 static inline void isa_dmamask(struct isa_softc *, int);
131
132 static inline void
isa_dmaunmask(struct isa_softc * sc,int chan)133 isa_dmaunmask(struct isa_softc *sc, int chan)
134 {
135 int ochan = chan & 3;
136
137 /* set dma channel mode, and set dma channel mode */
138 if ((chan & 4) == 0)
139 bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
140 DMA1_SMSK, ochan | DMA37SM_CLEAR);
141 else
142 bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
143 DMA2_SMSK, ochan | DMA37SM_CLEAR);
144 }
145
146 static inline void
isa_dmamask(struct isa_softc * sc,int chan)147 isa_dmamask(struct isa_softc *sc, int chan)
148 {
149 int ochan = chan & 3;
150
151 /* set dma channel mode, and set dma channel mode */
152 if ((chan & 4) == 0) {
153 bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
154 DMA1_SMSK, ochan | DMA37SM_SET);
155 bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
156 DMA1_FFC, 0);
157 } else {
158 bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
159 DMA2_SMSK, ochan | DMA37SM_SET);
160 bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
161 DMA2_FFC, 0);
162 }
163 }
164
165 /*
166 * isa_dmacascade(): program 8237 DMA controller channel to accept
167 * external dma control by a board.
168 */
169 void
isa_dmacascade(struct device * isadev,int chan)170 isa_dmacascade(struct device *isadev, int chan)
171 {
172 struct isa_softc *sc = (struct isa_softc *)isadev;
173 int ochan = chan & 3;
174
175 if (chan < 0 || chan > 7) {
176 printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
177 goto lose;
178 }
179
180 if (ISA_DRQ_ISFREE(sc, chan) == 0) {
181 printf("%s: DRQ %d is not free\n", sc->sc_dev.dv_xname, chan);
182 goto lose;
183 }
184
185 ISA_DRQ_ALLOC(sc, chan);
186
187 /* set dma channel mode, and set dma channel mode */
188 if ((chan & 4) == 0)
189 bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
190 DMA1_MODE, ochan | DMA37MD_CASCADE);
191 else
192 bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
193 DMA2_MODE, ochan | DMA37MD_CASCADE);
194
195 isa_dmaunmask(sc, chan);
196 return;
197
198 lose:
199 panic("isa_dmacascade");
200 }
201
202 int
isa_dmamap_create(struct device * isadev,int chan,bus_size_t size,int flags)203 isa_dmamap_create(struct device *isadev, int chan, bus_size_t size, int flags)
204 {
205 struct isa_softc *sc = (struct isa_softc *)isadev;
206 bus_size_t maxsize;
207
208 if (chan < 0 || chan > 7) {
209 printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
210 goto lose;
211 }
212
213 if (chan & 4)
214 maxsize = (1 << 17);
215 else
216 maxsize = (1 << 16);
217
218 if (size > maxsize)
219 return (EINVAL);
220
221 if (ISA_DRQ_ISFREE(sc, chan) == 0) {
222 printf("%s: drq %d is not free\n", sc->sc_dev.dv_xname, chan);
223 goto lose;
224 }
225
226 ISA_DRQ_ALLOC(sc, chan);
227
228 return (bus_dmamap_create(sc->sc_dmat, size, 1, size, maxsize,
229 flags, &sc->sc_dmamaps[chan]));
230
231 lose:
232 panic("isa_dmamap_create");
233 }
234
235 void
isa_dmamap_destroy(struct device * isadev,int chan)236 isa_dmamap_destroy(struct device *isadev, int chan)
237 {
238 struct isa_softc *sc = (struct isa_softc *)isadev;
239
240 if (chan < 0 || chan > 7) {
241 printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
242 goto lose;
243 }
244
245 if (ISA_DRQ_ISFREE(sc, chan)) {
246 printf("%s: drq %d is already free\n",
247 sc->sc_dev.dv_xname, chan);
248 goto lose;
249 }
250
251 ISA_DRQ_FREE(sc, chan);
252
253 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamaps[chan]);
254 return;
255
256 lose:
257 panic("isa_dmamap_destroy");
258 }
259
260 /*
261 * isa_dmastart(): program 8237 DMA controller channel and set it
262 * in motion.
263 */
264 int
isa_dmastart(struct device * isadev,int chan,void * addr,bus_size_t nbytes,struct proc * p,int flags,int busdmaflags)265 isa_dmastart(struct device *isadev, int chan, void *addr, bus_size_t nbytes,
266 struct proc *p, int flags, int busdmaflags)
267 {
268 struct isa_softc *sc = (struct isa_softc *)isadev;
269 bus_dmamap_t dmam;
270 bus_addr_t dmaaddr;
271 int waport;
272 int ochan = chan & 3;
273 int error;
274 #ifdef __ISADMA_COMPAT
275 int compat = busdmaflags & BUS_DMA_BUS1;
276
277 busdmaflags &= ~BUS_DMA_BUS1;
278 #endif /* __ISADMA_COMPAT */
279
280 if (chan < 0 || chan > 7) {
281 printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
282 goto lose;
283 }
284
285 #ifdef ISADMA_DEBUG
286 printf("isa_dmastart: drq %d, addr %p, nbytes 0x%lx, p %p, "
287 "flags 0x%x, dmaflags 0x%x\n",
288 chan, addr, nbytes, p, flags, busdmaflags);
289 #endif
290
291 if (chan & 4) {
292 if (nbytes > (1 << 17) || nbytes & 1 || (u_long)addr & 1) {
293 printf("%s: drq %d, nbytes 0x%lx, addr %p\n",
294 sc->sc_dev.dv_xname, chan, nbytes, addr);
295 goto lose;
296 }
297 } else {
298 if (nbytes > (1 << 16)) {
299 printf("%s: drq %d, nbytes 0x%lx\n",
300 sc->sc_dev.dv_xname, chan, nbytes);
301 goto lose;
302 }
303 }
304
305 dmam = sc->sc_dmamaps[chan];
306 if (dmam == NULL) {
307 #ifdef __ISADMA_COMPAT
308 if (compat)
309 dmam = sc->sc_dmamaps[chan] = isadma_dmam[chan];
310 else
311 #endif /* __ISADMA_COMPAT */
312 panic("isa_dmastart: no DMA map for chan %d", chan);
313 }
314
315 error = bus_dmamap_load(sc->sc_dmat, dmam, addr, nbytes, p,
316 busdmaflags);
317 if (error)
318 return (error);
319
320 #ifdef ISADMA_DEBUG
321 __asm(".globl isa_dmastart_afterload ; isa_dmastart_afterload:");
322 #endif
323
324 if (flags & DMAMODE_READ) {
325 bus_dmamap_sync(sc->sc_dmat, dmam, 0, dmam->dm_mapsize,
326 BUS_DMASYNC_PREREAD);
327 sc->sc_dmareads |= (1 << chan);
328 } else {
329 bus_dmamap_sync(sc->sc_dmat, dmam, 0, dmam->dm_mapsize,
330 BUS_DMASYNC_PREWRITE);
331 sc->sc_dmareads &= ~(1 << chan);
332 }
333
334 dmaaddr = dmam->dm_segs[0].ds_addr;
335
336 #ifdef ISADMA_DEBUG
337 printf(" dmaaddr 0x%lx\n", dmaaddr);
338
339 __asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:");
340 #endif
341
342 sc->sc_dmalength[chan] = nbytes;
343
344 isa_dmamask(sc, chan);
345 sc->sc_dmafinished &= ~(1 << chan);
346
347 if ((chan & 4) == 0) {
348 /* set dma channel mode */
349 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, DMA1_MODE,
350 ochan | dmamode[flags]);
351
352 /* send start address */
353 waport = DMA1_CHN(ochan);
354 bus_space_write_1(sc->sc_iot, sc->sc_dmapgh,
355 dmapageport[0][ochan], (dmaaddr >> 16) & 0xff);
356 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport,
357 dmaaddr & 0xff);
358 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport,
359 (dmaaddr >> 8) & 0xff);
360
361 /* send count */
362 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport + 1,
363 (--nbytes) & 0xff);
364 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport + 1,
365 (nbytes >> 8) & 0xff);
366 } else {
367 /* set dma channel mode */
368 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, DMA2_MODE,
369 ochan | dmamode[flags]);
370
371 /* send start address */
372 waport = DMA2_CHN(ochan);
373 bus_space_write_1(sc->sc_iot, sc->sc_dmapgh,
374 dmapageport[1][ochan], (dmaaddr >> 16) & 0xff);
375 dmaaddr >>= 1;
376 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport,
377 dmaaddr & 0xff);
378 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport,
379 (dmaaddr >> 8) & 0xff);
380
381 /* send count */
382 nbytes >>= 1;
383 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport + 2,
384 (--nbytes) & 0xff);
385 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport + 2,
386 (nbytes >> 8) & 0xff);
387 }
388
389 isa_dmaunmask(sc, chan);
390 return (0);
391
392 lose:
393 panic("isa_dmastart");
394 }
395
396 void
isa_dmaabort(struct device * isadev,int chan)397 isa_dmaabort(struct device *isadev, int chan)
398 {
399 struct isa_softc *sc = (struct isa_softc *)isadev;
400
401 if (chan < 0 || chan > 7) {
402 panic("isa_dmaabort: %s: bogus drq %d", sc->sc_dev.dv_xname,
403 chan);
404 }
405
406 isa_dmamask(sc, chan);
407 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamaps[chan]);
408 sc->sc_dmareads &= ~(1 << chan);
409 }
410
411 bus_size_t
isa_dmacount(struct device * isadev,int chan)412 isa_dmacount(struct device *isadev, int chan)
413 {
414 struct isa_softc *sc = (struct isa_softc *)isadev;
415 int waport;
416 bus_size_t nbytes;
417 int ochan = chan & 3;
418
419 if (chan < 0 || chan > 7) {
420 panic("isa_dmacount: %s: bogus drq %d", sc->sc_dev.dv_xname,
421 chan);
422 }
423
424 isa_dmamask(sc, chan);
425
426 /*
427 * We have to shift the byte count by 1. If we're in auto-initialize
428 * mode, the count may have wrapped around to the initial value. We
429 * can't use the TC bit to check for this case, so instead we compare
430 * against the original byte count.
431 * If we're not in auto-initialize mode, then the count will wrap to
432 * -1, so we also handle that case.
433 */
434 if ((chan & 4) == 0) {
435 waport = DMA1_CHN(ochan);
436 nbytes = bus_space_read_1(sc->sc_iot, sc->sc_dma1h,
437 waport + 1) + 1;
438 nbytes += bus_space_read_1(sc->sc_iot, sc->sc_dma1h,
439 waport + 1) << 8;
440 nbytes &= 0xffff;
441 } else {
442 waport = DMA2_CHN(ochan);
443 nbytes = bus_space_read_1(sc->sc_iot, sc->sc_dma2h,
444 waport + 2) + 1;
445 nbytes += bus_space_read_1(sc->sc_iot, sc->sc_dma2h,
446 waport + 2) << 8;
447 nbytes <<= 1;
448 nbytes &= 0x1ffff;
449 }
450
451 if (nbytes == sc->sc_dmalength[chan])
452 nbytes = 0;
453
454 isa_dmaunmask(sc, chan);
455 return (nbytes);
456 }
457
458 int
isa_dmafinished(struct device * isadev,int chan)459 isa_dmafinished(struct device *isadev, int chan)
460 {
461 struct isa_softc *sc = (struct isa_softc *)isadev;
462
463 if (chan < 0 || chan > 7) {
464 panic("isa_dmafinished: %s: bogus drq %d", sc->sc_dev.dv_xname,
465 chan);
466 }
467
468 /* check that the terminal count was reached */
469 if ((chan & 4) == 0)
470 sc->sc_dmafinished |= bus_space_read_1(sc->sc_iot,
471 sc->sc_dma1h, DMA1_SR) & 0x0f;
472 else
473 sc->sc_dmafinished |= (bus_space_read_1(sc->sc_iot,
474 sc->sc_dma2h, DMA2_SR) & 0x0f) << 4;
475
476 return ((sc->sc_dmafinished & (1 << chan)) != 0);
477 }
478
479 void
isa_dmadone(struct device * isadev,int chan)480 isa_dmadone(struct device *isadev, int chan)
481 {
482 struct isa_softc *sc = (struct isa_softc *)isadev;
483 bus_dmamap_t dmam;
484
485 if (chan < 0 || chan > 7) {
486 panic("isa_dmadone: %s: bogus drq %d", sc->sc_dev.dv_xname,
487 chan);
488 }
489
490 dmam = sc->sc_dmamaps[chan];
491
492 isa_dmamask(sc, chan);
493
494 if (isa_dmafinished(isadev, chan) == 0)
495 printf("%s: isa_dmadone: channel %d not finished\n",
496 sc->sc_dev.dv_xname, chan);
497
498 bus_dmamap_sync(sc->sc_dmat, dmam, 0, dmam->dm_mapsize,
499 (sc->sc_dmareads & (1 << chan)) ? BUS_DMASYNC_POSTREAD :
500 BUS_DMASYNC_POSTWRITE);
501
502 bus_dmamap_unload(sc->sc_dmat, dmam);
503 sc->sc_dmareads &= ~(1 << chan);
504 }
505
506 int
isa_dmamem_alloc(struct device * isadev,int chan,bus_size_t size,bus_addr_t * addrp,int flags)507 isa_dmamem_alloc(struct device *isadev, int chan, bus_size_t size,
508 bus_addr_t *addrp, int flags)
509 {
510 struct isa_softc *sc = (struct isa_softc *)isadev;
511 bus_dma_segment_t seg;
512 int error, boundary, rsegs;
513
514 if (chan < 0 || chan > 7) {
515 panic("isa_dmamem_alloc: %s: bogus drq %d",
516 sc->sc_dev.dv_xname, chan);
517 }
518
519 boundary = (chan & 4) ? (1 << 17) : (1 << 16);
520
521 size = round_page(size);
522
523 error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, boundary,
524 &seg, 1, &rsegs, flags);
525 if (error)
526 return (error);
527
528 *addrp = seg.ds_addr;
529 return (0);
530 }
531
532 void
isa_dmamem_free(struct device * isadev,int chan,bus_addr_t addr,bus_size_t size)533 isa_dmamem_free(struct device *isadev, int chan, bus_addr_t addr,
534 bus_size_t size)
535 {
536 struct isa_softc *sc = (struct isa_softc *)isadev;
537 bus_dma_segment_t seg;
538
539 if (chan < 0 || chan > 7) {
540 panic("isa_dmamem_free: %s: bogus drq %d",
541 sc->sc_dev.dv_xname, chan);
542 }
543
544 seg.ds_addr = addr;
545 seg.ds_len = size;
546
547 bus_dmamem_free(sc->sc_dmat, &seg, 1);
548 }
549
550 int
isa_dmamem_map(struct device * isadev,int chan,bus_addr_t addr,bus_size_t size,caddr_t * kvap,int flags)551 isa_dmamem_map(struct device *isadev, int chan, bus_addr_t addr,
552 bus_size_t size, caddr_t *kvap, int flags)
553 {
554 struct isa_softc *sc = (struct isa_softc *)isadev;
555 bus_dma_segment_t seg;
556
557 if (chan < 0 || chan > 7) {
558 panic("isa_dmamem_map: %s: bogus drq %d", sc->sc_dev.dv_xname,
559 chan);
560 }
561
562 seg.ds_addr = addr;
563 seg.ds_len = size;
564
565 return (bus_dmamem_map(sc->sc_dmat, &seg, 1, size, kvap, flags));
566 }
567
568 void
isa_dmamem_unmap(struct device * isadev,int chan,caddr_t kva,size_t size)569 isa_dmamem_unmap(struct device *isadev, int chan, caddr_t kva, size_t size)
570 {
571 struct isa_softc *sc = (struct isa_softc *)isadev;
572
573 if (chan < 0 || chan > 7) {
574 panic("isa_dmamem_unmap: %s: bogus drq %d",
575 sc->sc_dev.dv_xname, chan);
576 }
577
578 bus_dmamem_unmap(sc->sc_dmat, kva, size);
579 }
580
581 int
isa_dmamem_mmap(struct device * isadev,int chan,bus_addr_t addr,bus_size_t size,int off,int prot,int flags)582 isa_dmamem_mmap(struct device *isadev, int chan, bus_addr_t addr,
583 bus_size_t size, int off, int prot, int flags)
584 {
585 struct isa_softc *sc = (struct isa_softc *)isadev;
586 bus_dma_segment_t seg;
587
588 if (chan < 0 || chan > 7) {
589 panic("isa_dmamem_mmap: %s: bogus drq %d", sc->sc_dev.dv_xname,
590 chan);
591 }
592
593 if (off < 0)
594 return (-1);
595
596 seg.ds_addr = addr;
597 seg.ds_len = size;
598
599 return (bus_dmamem_mmap(sc->sc_dmat, &seg, 1, off, prot, flags));
600 }
601
602 int
isa_drq_isfree(struct device * isadev,int chan)603 isa_drq_isfree(struct device *isadev, int chan)
604 {
605 struct isa_softc *sc = (struct isa_softc *)isadev;
606 if (chan < 0 || chan > 7) {
607 panic("isa_drq_isfree: %s: bogus drq %d", sc->sc_dev.dv_xname,
608 chan);
609 }
610 return ISA_DRQ_ISFREE(sc, chan);
611 }
612
613 void *
isa_malloc(struct device * isadev,int chan,size_t size,int pool,int flags)614 isa_malloc(struct device *isadev, int chan, size_t size, int pool, int flags)
615 {
616 bus_addr_t addr;
617 caddr_t kva;
618 int bflags;
619 struct isa_mem *m;
620
621 bflags = flags & M_NOWAIT ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
622
623 if (isa_dmamem_alloc(isadev, chan, size, &addr, bflags))
624 return 0;
625 if (isa_dmamem_map(isadev, chan, addr, size, &kva, bflags)) {
626 isa_dmamem_free(isadev, chan, addr, size);
627 return 0;
628 }
629 m = malloc(sizeof(*m), pool, flags);
630 if (m == 0) {
631 isa_dmamem_unmap(isadev, chan, kva, size);
632 isa_dmamem_free(isadev, chan, addr, size);
633 return 0;
634 }
635 m->isadev = isadev;
636 m->chan = chan;
637 m->size = size;
638 m->addr = addr;
639 m->kva = kva;
640 m->next = isa_mem_head;
641 isa_mem_head = m;
642 return (void *)kva;
643 }
644
645 void
isa_free(void * addr,int pool)646 isa_free(void *addr, int pool)
647 {
648 struct isa_mem **mp, *m;
649 caddr_t kva = (caddr_t)addr;
650
651 for(mp = &isa_mem_head; *mp && (*mp)->kva != kva; mp = &(*mp)->next)
652 ;
653 m = *mp;
654 if (!m) {
655 printf("isa_free: freeing unallocated memory\n");
656 return;
657 }
658 *mp = m->next;
659 isa_dmamem_unmap(m->isadev, m->chan, kva, m->size);
660 isa_dmamem_free(m->isadev, m->chan, m->addr, m->size);
661 free(m, pool, 0);
662 }
663
664 paddr_t
isa_mappage(void * mem,off_t off,int prot)665 isa_mappage(void *mem, off_t off, int prot)
666 {
667 struct isa_mem *m;
668
669 for(m = isa_mem_head; m && m->kva != (caddr_t)mem; m = m->next)
670 ;
671 if (!m) {
672 printf("isa_mappage: mapping unallocated memory\n");
673 return -1;
674 }
675 return (isa_dmamem_mmap(m->isadev, m->chan, m->addr, m->size, off,
676 prot, BUS_DMA_WAITOK));
677 }
678