xref: /netbsd-src/sys/dev/isa/isadma.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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 
53 struct 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  */
59 static int dmapageport[2][4] = {
60 	{0x7, 0x3, 0x1, 0x2},
61 	{0xf, 0xb, 0x9, 0xa}
62 };
63 
64 static 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 
82 static inline void _isa_dmaunmask(struct isa_dma_state *, int);
83 static inline void _isa_dmamask(struct isa_dma_state *, int);
84 
85 static 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 
108 static 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  */
138 void
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 
203 void
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  */
225 int
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  */
259 int
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 
277 int
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 
286 int
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 
295 bus_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 
307 int
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 
326 void
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  */
346 int
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 
474 void
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 
488 bus_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 
534 int
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 
554 void
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 
580 void
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 
601 void
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 
622 int
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 
646 void
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 
662 int
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 
678 void
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 
690 paddr_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 
709 int
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 
721 void *
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 
753 void
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 
773 paddr_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