This source file includes following definitions.
- isadmamatch
- isadmaattach
- isa_dmaunmask
- isa_dmamask
- isa_dmacascade
- isa_dmamap_create
- isa_dmamap_destroy
- isa_dmastart
- isa_dmaabort
- isa_dmacount
- isa_dmafinished
- isa_dmadone
- isa_dmamem_alloc
- isa_dmamem_free
- isa_dmamem_map
- isa_dmamem_unmap
- isa_dmamem_mmap
- isa_drq_isfree
- isa_malloc
- isa_free
- isa_mappage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/proc.h>
48 #include <sys/device.h>
49
50 #include <uvm/uvm_extern.h>
51
52 #include <machine/bus.h>
53
54 #include <dev/isa/isareg.h>
55 #include <dev/isa/isavar.h>
56 #include <dev/isa/isadmavar.h>
57 #include <dev/isa/isadmareg.h>
58
59 #ifdef __ISADMA_COMPAT
60
61 struct device *isa_dev;
62
63 bus_dmamap_t isadma_dmam[8];
64 #endif
65
66
67 #include <sys/malloc.h>
68 struct isa_mem {
69 struct device *isadev;
70 int chan;
71 bus_size_t size;
72 bus_addr_t addr;
73 caddr_t kva;
74 struct isa_mem *next;
75 } *isa_mem_head = 0;
76
77
78
79
80
81 static int dmapageport[2][4] = {
82 {0x7, 0x3, 0x1, 0x2},
83 {0xf, 0xb, 0x9, 0xa}
84 };
85
86 static u_int8_t dmamode[4] = {
87 DMA37MD_READ | DMA37MD_SINGLE,
88 DMA37MD_WRITE | DMA37MD_SINGLE,
89 DMA37MD_READ | DMA37MD_SINGLE | DMA37MD_LOOP,
90 DMA37MD_WRITE | DMA37MD_SINGLE | DMA37MD_LOOP
91 };
92
93 int isadmamatch(struct device *, void *, void *);
94 void isadmaattach(struct device *, struct device *, void *);
95
96 struct cfattach isadma_ca = {
97 sizeof(struct device), isadmamatch, isadmaattach
98 };
99
100 struct cfdriver isadma_cd = {
101 NULL, "isadma", DV_DULL, 1
102 };
103
104 int
105 isadmamatch(parent, match, aux)
106 struct device *parent;
107 void *match, *aux;
108 {
109 struct isa_attach_args *ia = aux;
110
111
112 ia->ia_iosize = 0;
113 return (1);
114 }
115
116 void
117 isadmaattach(parent, self, aux)
118 struct device *parent, *self;
119 void *aux;
120 {
121 #ifdef __ISADMA_COMPAT
122 int i, sz;
123 struct isa_softc *sc = (struct isa_softc *)parent;
124
125
126 isa_dev = parent;
127
128 for (i = 0; i < 8; i++) {
129 sz = (i & 4) ? 1 << 17 : 1 << 16;
130 if ((bus_dmamap_create(sc->sc_dmat, sz, 1, sz, sz,
131 BUS_DMA_24BIT|BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
132 &isadma_dmam[i])) != 0)
133 panic("isadmaattach: can not create DMA map");
134 }
135 #endif
136
137
138
139 printf("\n");
140 }
141
142 static inline void isa_dmaunmask(struct isa_softc *, int);
143 static inline void isa_dmamask(struct isa_softc *, int);
144
145 static inline void
146 isa_dmaunmask(sc, chan)
147 struct isa_softc *sc;
148 int chan;
149 {
150 int ochan = chan & 3;
151
152
153 if ((chan & 4) == 0)
154 bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
155 DMA1_SMSK, ochan | DMA37SM_CLEAR);
156 else
157 bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
158 DMA2_SMSK, ochan | DMA37SM_CLEAR);
159 }
160
161 static inline void
162 isa_dmamask(sc, chan)
163 struct isa_softc *sc;
164 int chan;
165 {
166 int ochan = chan & 3;
167
168
169 if ((chan & 4) == 0) {
170 bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
171 DMA1_SMSK, ochan | DMA37SM_SET);
172 bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
173 DMA1_FFC, 0);
174 } else {
175 bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
176 DMA2_SMSK, ochan | DMA37SM_SET);
177 bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
178 DMA2_FFC, 0);
179 }
180 }
181
182
183
184
185
186 void
187 isa_dmacascade(isadev, chan)
188 struct device *isadev;
189 int chan;
190 {
191 struct isa_softc *sc = (struct isa_softc *)isadev;
192 int ochan = chan & 3;
193
194 if (chan < 0 || chan > 7) {
195 printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
196 goto lose;
197 }
198
199 if (ISA_DRQ_ISFREE(sc, chan) == 0) {
200 printf("%s: DRQ %d is not free\n", sc->sc_dev.dv_xname, chan);
201 goto lose;
202 }
203
204 ISA_DRQ_ALLOC(sc, chan);
205
206
207 if ((chan & 4) == 0)
208 bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
209 DMA1_MODE, ochan | DMA37MD_CASCADE);
210 else
211 bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
212 DMA2_MODE, ochan | DMA37MD_CASCADE);
213
214 isa_dmaunmask(sc, chan);
215 return;
216
217 lose:
218 panic("isa_dmacascade");
219 }
220
221 int
222 isa_dmamap_create(isadev, chan, size, flags)
223 struct device *isadev;
224 int chan;
225 bus_size_t size;
226 int flags;
227 {
228 struct isa_softc *sc = (struct isa_softc *)isadev;
229 bus_size_t maxsize;
230
231 if (chan < 0 || chan > 7) {
232 printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
233 goto lose;
234 }
235
236 if (chan & 4)
237 maxsize = (1 << 17);
238 else
239 maxsize = (1 << 16);
240
241 if (size > maxsize)
242 return (EINVAL);
243
244 if (ISA_DRQ_ISFREE(sc, chan) == 0) {
245 printf("%s: drq %d is not free\n", sc->sc_dev.dv_xname, chan);
246 goto lose;
247 }
248
249 ISA_DRQ_ALLOC(sc, chan);
250
251 return (bus_dmamap_create(sc->sc_dmat, size, 1, size, maxsize,
252 flags, &sc->sc_dmamaps[chan]));
253
254 lose:
255 panic("isa_dmamap_create");
256 }
257
258 void
259 isa_dmamap_destroy(isadev, chan)
260 struct device *isadev;
261 int chan;
262 {
263 struct isa_softc *sc = (struct isa_softc *)isadev;
264
265 if (chan < 0 || chan > 7) {
266 printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
267 goto lose;
268 }
269
270 if (ISA_DRQ_ISFREE(sc, chan)) {
271 printf("%s: drq %d is already free\n",
272 sc->sc_dev.dv_xname, chan);
273 goto lose;
274 }
275
276 ISA_DRQ_FREE(sc, chan);
277
278 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamaps[chan]);
279 return;
280
281 lose:
282 panic("isa_dmamap_destroy");
283 }
284
285
286
287
288
289 int
290 isa_dmastart(isadev, chan, addr, nbytes, p, flags, busdmaflags)
291 struct device *isadev;
292 int chan;
293 void *addr;
294 bus_size_t nbytes;
295 struct proc *p;
296 int flags;
297 int busdmaflags;
298 {
299 struct isa_softc *sc = (struct isa_softc *)isadev;
300 bus_dmamap_t dmam;
301 bus_addr_t dmaaddr;
302 int waport;
303 int ochan = chan & 3;
304 int error;
305 #ifdef __ISADMA_COMPAT
306 int compat = busdmaflags & BUS_DMA_BUS1;
307
308 busdmaflags &= ~BUS_DMA_BUS1;
309 #endif
310
311 if (chan < 0 || chan > 7) {
312 printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
313 goto lose;
314 }
315
316 #ifdef ISADMA_DEBUG
317 printf("isa_dmastart: drq %d, addr %p, nbytes 0x%lx, p %p, "
318 "flags 0x%x, dmaflags 0x%x\n",
319 chan, addr, nbytes, p, flags, busdmaflags);
320 #endif
321
322 if (chan & 4) {
323 if (nbytes > (1 << 17) || nbytes & 1 || (u_long)addr & 1) {
324 printf("%s: drq %d, nbytes 0x%lx, addr %p\n",
325 sc->sc_dev.dv_xname, chan, nbytes, addr);
326 goto lose;
327 }
328 } else {
329 if (nbytes > (1 << 16)) {
330 printf("%s: drq %d, nbytes 0x%lx\n",
331 sc->sc_dev.dv_xname, chan, nbytes);
332 goto lose;
333 }
334 }
335
336 dmam = sc->sc_dmamaps[chan];
337 if (dmam == NULL) {
338 #ifdef __ISADMA_COMPAT
339 if (compat)
340 dmam = sc->sc_dmamaps[chan] = isadma_dmam[chan];
341 else
342 #endif
343 panic("isa_dmastart: no DMA map for chan %d", chan);
344 }
345
346 error = bus_dmamap_load(sc->sc_dmat, dmam, addr, nbytes, p,
347 busdmaflags);
348 if (error)
349 return (error);
350
351 #ifdef ISADMA_DEBUG
352 __asm(".globl isa_dmastart_afterload ; isa_dmastart_afterload:");
353 #endif
354
355 if (flags & DMAMODE_READ) {
356 bus_dmamap_sync(sc->sc_dmat, dmam, 0, dmam->dm_mapsize,
357 BUS_DMASYNC_PREREAD);
358 sc->sc_dmareads |= (1 << chan);
359 } else {
360 bus_dmamap_sync(sc->sc_dmat, dmam, 0, dmam->dm_mapsize,
361 BUS_DMASYNC_PREWRITE);
362 sc->sc_dmareads &= ~(1 << chan);
363 }
364
365 dmaaddr = dmam->dm_segs[0].ds_addr;
366
367 #ifdef ISADMA_DEBUG
368 printf(" dmaaddr 0x%lx\n", dmaaddr);
369
370 __asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:");
371 #endif
372
373 sc->sc_dmalength[chan] = nbytes;
374
375 isa_dmamask(sc, chan);
376 sc->sc_dmafinished &= ~(1 << chan);
377
378 if ((chan & 4) == 0) {
379
380 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, DMA1_MODE,
381 ochan | dmamode[flags]);
382
383
384 waport = DMA1_CHN(ochan);
385 bus_space_write_1(sc->sc_iot, sc->sc_dmapgh,
386 dmapageport[0][ochan], (dmaaddr >> 16) & 0xff);
387 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport,
388 dmaaddr & 0xff);
389 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport,
390 (dmaaddr >> 8) & 0xff);
391
392
393 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport + 1,
394 (--nbytes) & 0xff);
395 bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport + 1,
396 (nbytes >> 8) & 0xff);
397 } else {
398
399 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, DMA2_MODE,
400 ochan | dmamode[flags]);
401
402
403 waport = DMA2_CHN(ochan);
404 bus_space_write_1(sc->sc_iot, sc->sc_dmapgh,
405 dmapageport[1][ochan], (dmaaddr >> 16) & 0xff);
406 dmaaddr >>= 1;
407 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport,
408 dmaaddr & 0xff);
409 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport,
410 (dmaaddr >> 8) & 0xff);
411
412
413 nbytes >>= 1;
414 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport + 2,
415 (--nbytes) & 0xff);
416 bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport + 2,
417 (nbytes >> 8) & 0xff);
418 }
419
420 isa_dmaunmask(sc, chan);
421 return (0);
422
423 lose:
424 panic("isa_dmastart");
425 }
426
427 void
428 isa_dmaabort(isadev, chan)
429 struct device *isadev;
430 int chan;
431 {
432 struct isa_softc *sc = (struct isa_softc *)isadev;
433
434 if (chan < 0 || chan > 7) {
435 panic("isa_dmaabort: %s: bogus drq %d", sc->sc_dev.dv_xname,
436 chan);
437 }
438
439 isa_dmamask(sc, chan);
440 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamaps[chan]);
441 sc->sc_dmareads &= ~(1 << chan);
442 }
443
444 bus_size_t
445 isa_dmacount(isadev, chan)
446 struct device *isadev;
447 int chan;
448 {
449 struct isa_softc *sc = (struct isa_softc *)isadev;
450 int waport;
451 bus_size_t nbytes;
452 int ochan = chan & 3;
453
454 if (chan < 0 || chan > 7) {
455 panic("isa_dmacount: %s: bogus drq %d", sc->sc_dev.dv_xname,
456 chan);
457 }
458
459 isa_dmamask(sc, chan);
460
461
462
463
464
465
466
467
468
469 if ((chan & 4) == 0) {
470 waport = DMA1_CHN(ochan);
471 nbytes = bus_space_read_1(sc->sc_iot, sc->sc_dma1h,
472 waport + 1) + 1;
473 nbytes += bus_space_read_1(sc->sc_iot, sc->sc_dma1h,
474 waport + 1) << 8;
475 nbytes &= 0xffff;
476 } else {
477 waport = DMA2_CHN(ochan);
478 nbytes = bus_space_read_1(sc->sc_iot, sc->sc_dma2h,
479 waport + 2) + 1;
480 nbytes += bus_space_read_1(sc->sc_iot, sc->sc_dma2h,
481 waport + 2) << 8;
482 nbytes <<= 1;
483 nbytes &= 0x1ffff;
484 }
485
486 if (nbytes == sc->sc_dmalength[chan])
487 nbytes = 0;
488
489 isa_dmaunmask(sc, chan);
490 return (nbytes);
491 }
492
493 int
494 isa_dmafinished(isadev, chan)
495 struct device *isadev;
496 int chan;
497 {
498 struct isa_softc *sc = (struct isa_softc *)isadev;
499
500 if (chan < 0 || chan > 7) {
501 panic("isa_dmafinished: %s: bogus drq %d", sc->sc_dev.dv_xname,
502 chan);
503 }
504
505
506 if ((chan & 4) == 0)
507 sc->sc_dmafinished |= bus_space_read_1(sc->sc_iot,
508 sc->sc_dma1h, DMA1_SR) & 0x0f;
509 else
510 sc->sc_dmafinished |= (bus_space_read_1(sc->sc_iot,
511 sc->sc_dma2h, DMA2_SR) & 0x0f) << 4;
512
513 return ((sc->sc_dmafinished & (1 << chan)) != 0);
514 }
515
516 void
517 isa_dmadone(isadev, chan)
518 struct device *isadev;
519 int chan;
520 {
521 struct isa_softc *sc = (struct isa_softc *)isadev;
522 bus_dmamap_t dmam;
523
524 if (chan < 0 || chan > 7) {
525 panic("isa_dmadone: %s: bogus drq %d", sc->sc_dev.dv_xname,
526 chan);
527 }
528
529 dmam = sc->sc_dmamaps[chan];
530
531 isa_dmamask(sc, chan);
532
533 if (isa_dmafinished(isadev, chan) == 0)
534 printf("%s: isa_dmadone: channel %d not finished\n",
535 sc->sc_dev.dv_xname, chan);
536
537 bus_dmamap_sync(sc->sc_dmat, dmam, 0, dmam->dm_mapsize,
538 (sc->sc_dmareads & (1 << chan)) ? BUS_DMASYNC_POSTREAD :
539 BUS_DMASYNC_POSTWRITE);
540
541 bus_dmamap_unload(sc->sc_dmat, dmam);
542 sc->sc_dmareads &= ~(1 << chan);
543 }
544
545 int
546 isa_dmamem_alloc(isadev, chan, size, addrp, flags)
547 struct device *isadev;
548 int chan;
549 bus_size_t size;
550 bus_addr_t *addrp;
551 int flags;
552 {
553 struct isa_softc *sc = (struct isa_softc *)isadev;
554 bus_dma_segment_t seg;
555 int error, boundary, rsegs;
556
557 if (chan < 0 || chan > 7) {
558 panic("isa_dmamem_alloc: %s: bogus drq %d",
559 sc->sc_dev.dv_xname, chan);
560 }
561
562 boundary = (chan & 4) ? (1 << 17) : (1 << 16);
563
564 size = round_page(size);
565
566 error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, boundary,
567 &seg, 1, &rsegs, flags);
568 if (error)
569 return (error);
570
571 *addrp = seg.ds_addr;
572 return (0);
573 }
574
575 void
576 isa_dmamem_free(isadev, chan, addr, size)
577 struct device *isadev;
578 int chan;
579 bus_addr_t addr;
580 bus_size_t size;
581 {
582 struct isa_softc *sc = (struct isa_softc *)isadev;
583 bus_dma_segment_t seg;
584
585 if (chan < 0 || chan > 7) {
586 panic("isa_dmamem_free: %s: bogus drq %d",
587 sc->sc_dev.dv_xname, chan);
588 }
589
590 seg.ds_addr = addr;
591 seg.ds_len = size;
592
593 bus_dmamem_free(sc->sc_dmat, &seg, 1);
594 }
595
596 int
597 isa_dmamem_map(isadev, chan, addr, size, kvap, flags)
598 struct device *isadev;
599 int chan;
600 bus_addr_t addr;
601 bus_size_t size;
602 caddr_t *kvap;
603 int flags;
604 {
605 struct isa_softc *sc = (struct isa_softc *)isadev;
606 bus_dma_segment_t seg;
607
608 if (chan < 0 || chan > 7) {
609 panic("isa_dmamem_map: %s: bogus drq %d", sc->sc_dev.dv_xname,
610 chan);
611 }
612
613 seg.ds_addr = addr;
614 seg.ds_len = size;
615
616 return (bus_dmamem_map(sc->sc_dmat, &seg, 1, size, kvap, flags));
617 }
618
619 void
620 isa_dmamem_unmap(isadev, chan, kva, size)
621 struct device *isadev;
622 int chan;
623 caddr_t kva;
624 size_t size;
625 {
626 struct isa_softc *sc = (struct isa_softc *)isadev;
627
628 if (chan < 0 || chan > 7) {
629 panic("isa_dmamem_unmap: %s: bogus drq %d",
630 sc->sc_dev.dv_xname, chan);
631 }
632
633 bus_dmamem_unmap(sc->sc_dmat, kva, size);
634 }
635
636 int
637 isa_dmamem_mmap(isadev, chan, addr, size, off, prot, flags)
638 struct device *isadev;
639 int chan;
640 bus_addr_t addr;
641 bus_size_t size;
642 int off, prot, flags;
643 {
644 struct isa_softc *sc = (struct isa_softc *)isadev;
645 bus_dma_segment_t seg;
646
647 if (chan < 0 || chan > 7) {
648 panic("isa_dmamem_mmap: %s: bogus drq %d", sc->sc_dev.dv_xname,
649 chan);
650 }
651
652 if (off < 0)
653 return (-1);
654
655 seg.ds_addr = addr;
656 seg.ds_len = size;
657
658 return (bus_dmamem_mmap(sc->sc_dmat, &seg, 1, off, prot, flags));
659 }
660
661 int
662 isa_drq_isfree(isadev, chan)
663 struct device *isadev;
664 int chan;
665 {
666 struct isa_softc *sc = (struct isa_softc *)isadev;
667 if (chan < 0 || chan > 7) {
668 panic("isa_drq_isfree: %s: bogus drq %d", sc->sc_dev.dv_xname,
669 chan);
670 }
671 return ISA_DRQ_ISFREE(sc, chan);
672 }
673
674 void *
675 isa_malloc(isadev, chan, size, pool, flags)
676 struct device *isadev;
677 int chan;
678 size_t size;
679 int pool;
680 int flags;
681 {
682 bus_addr_t addr;
683 caddr_t kva;
684 int bflags;
685 struct isa_mem *m;
686
687 bflags = flags & M_NOWAIT ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
688
689 if (isa_dmamem_alloc(isadev, chan, size, &addr, bflags))
690 return 0;
691 if (isa_dmamem_map(isadev, chan, addr, size, &kva, bflags)) {
692 isa_dmamem_free(isadev, chan, addr, size);
693 return 0;
694 }
695 m = malloc(sizeof(*m), pool, flags);
696 if (m == 0) {
697 isa_dmamem_unmap(isadev, chan, kva, size);
698 isa_dmamem_free(isadev, chan, addr, size);
699 return 0;
700 }
701 m->isadev = isadev;
702 m->chan = chan;
703 m->size = size;
704 m->addr = addr;
705 m->kva = kva;
706 m->next = isa_mem_head;
707 isa_mem_head = m;
708 return (void *)kva;
709 }
710
711 void
712 isa_free(addr, pool)
713 void *addr;
714 int pool;
715 {
716 struct isa_mem **mp, *m;
717 caddr_t kva = (caddr_t)addr;
718
719 for(mp = &isa_mem_head; *mp && (*mp)->kva != kva; mp = &(*mp)->next)
720 ;
721 m = *mp;
722 if (!m) {
723 printf("isa_free: freeing unallocated memory\n");
724 return;
725 }
726 *mp = m->next;
727 isa_dmamem_unmap(m->isadev, m->chan, kva, m->size);
728 isa_dmamem_free(m->isadev, m->chan, m->addr, m->size);
729 free(m, pool);
730 }
731
732 paddr_t
733 isa_mappage(mem, off, prot)
734 void *mem;
735 off_t off;
736 int prot;
737 {
738 struct isa_mem *m;
739
740 for(m = isa_mem_head; m && m->kva != (caddr_t)mem; m = m->next)
741 ;
742 if (!m) {
743 printf("isa_mappage: mapping unallocated memory\n");
744 return -1;
745 }
746 return (isa_dmamem_mmap(m->isadev, m->chan, m->addr, m->size, off,
747 prot, BUS_DMA_WAITOK));
748 }