xref: /netbsd-src/sys/dev/isa/isadma.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
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