xref: /openbsd/sys/arch/amd64/isa/isa_machdep.c (revision 3d8817e4)
1 /*	$OpenBSD: isa_machdep.c,v 1.22 2010/11/20 20:58:51 miod Exp $	*/
2 /*	$NetBSD: isa_machdep.c,v 1.22 1997/06/12 23:57:32 thorpej Exp $	*/
3 
4 #define ISA_DMA_STATS
5 
6 /*-
7  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to The NetBSD Foundation
11  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
12  * NASA Ames Research Center.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /*-
37  * Copyright (c) 1993, 1994, 1996, 1997
38  *	Charles M. Hannum.  All rights reserved.
39  * Copyright (c) 1991 The Regents of the University of California.
40  * All rights reserved.
41  *
42  * This code is derived from software contributed to Berkeley by
43  * William Jolitz.
44  *
45  * Redistribution and use in source and binary forms, with or without
46  * modification, are permitted provided that the following conditions
47  * are met:
48  * 1. Redistributions of source code must retain the above copyright
49  *    notice, this list of conditions and the following disclaimer.
50  * 2. Redistributions in binary form must reproduce the above copyright
51  *    notice, this list of conditions and the following disclaimer in the
52  *    documentation and/or other materials provided with the distribution.
53  * 3. Neither the name of the University nor the names of its contributors
54  *    may be used to endorse or promote products derived from this software
55  *    without specific prior written permission.
56  *
57  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67  * SUCH DAMAGE.
68  *
69  *	@(#)isa.c	7.2 (Berkeley) 5/13/91
70  */
71 
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/syslog.h>
75 #include <sys/device.h>
76 #include <sys/malloc.h>
77 #include <sys/proc.h>
78 
79 #include <uvm/uvm_extern.h>
80 
81 #include "ioapic.h"
82 
83 #if NIOAPIC > 0
84 #include <machine/i82093var.h>
85 #include <machine/mpbiosvar.h>
86 #endif
87 
88 #include <machine/bus.h>
89 
90 #include <machine/intr.h>
91 #include <machine/pio.h>
92 #include <machine/cpufunc.h>
93 #include <machine/i8259.h>
94 
95 #include <dev/isa/isareg.h>
96 #include <dev/isa/isavar.h>
97 #if 0
98 #include <dev/isa/isadmavar.h>
99 #endif
100 #include <i386/isa/isa_machdep.h>
101 
102 #include "isadma.h"
103 
104 extern	paddr_t avail_end;
105 
106 #define	IDTVEC(name)	__CONCAT(X,name)
107 /* default interrupt vector table entries */
108 typedef int (*vector)(void);
109 extern vector IDTVEC(intr)[];
110 void isa_strayintr(int);
111 int fakeintr(void *);
112 
113 #if NISADMA > 0
114 int	_isa_bus_dmamap_create(bus_dma_tag_t, bus_size_t, int,
115 	    bus_size_t, bus_size_t, int, bus_dmamap_t *);
116 void	_isa_bus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
117 int	_isa_bus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *,
118 	    bus_size_t, struct proc *, int);
119 int	_isa_bus_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t,
120 	    struct mbuf *, int);
121 int	_isa_bus_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t,
122 	    struct uio *, int);
123 int	_isa_bus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
124 	    bus_dma_segment_t *, int, bus_size_t, int);
125 void	_isa_bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
126 void	_isa_bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t,
127 	    bus_addr_t, bus_size_t, int);
128 
129 int	_isa_bus_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t,
130 	    bus_size_t, bus_dma_segment_t *, int, int *, int);
131 
132 int	_isa_dma_check_buffer(void *, bus_size_t, int, bus_size_t,
133 	    struct proc *);
134 int	_isa_dma_alloc_bouncebuf(bus_dma_tag_t, bus_dmamap_t,
135 	    bus_size_t, int);
136 void	_isa_dma_free_bouncebuf(bus_dma_tag_t, bus_dmamap_t);
137 
138 /*
139  * Entry points for ISA DMA.  These are mostly wrappers around
140  * the generic functions that understand how to deal with bounce
141  * buffers, if necessary.
142  */
143 struct bus_dma_tag isa_bus_dma_tag = {
144 	NULL,			/* _cookie */
145 	_isa_bus_dmamap_create,
146 	_isa_bus_dmamap_destroy,
147 	_isa_bus_dmamap_load,
148 	_isa_bus_dmamap_load_mbuf,
149 	_isa_bus_dmamap_load_uio,
150 	_isa_bus_dmamap_load_raw,
151 	_isa_bus_dmamap_unload,
152 	_isa_bus_dmamap_sync,
153 	_isa_bus_dmamem_alloc,
154 	_bus_dmamem_free,
155 	_bus_dmamem_map,
156 	_bus_dmamem_unmap,
157 	_bus_dmamem_mmap,
158 };
159 #endif /* NISADMA > 0 */
160 
161 #define GICODE_SEL	10
162 
163 u_long  intrstray[ICU_LEN];
164 
165 /*
166  * Caught a stray interrupt, notify
167  */
168 void
169 isa_strayintr(int irq)
170 {
171         /*
172          * Stray interrupts on irq 7 occur when an interrupt line is raised
173          * and then lowered before the CPU acknowledges it.  This generally
174          * means either the device is screwed or something is cli'ing too
175          * long and it's timing out.
176          */
177 	if (++intrstray[irq] <= 5)
178 		log(LOG_ERR, "stray interrupt %d%s\n", irq,
179 		    intrstray[irq] >= 5 ? "; stopped logging" : "");
180 }
181 
182 int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
183 int iminlevel[ICU_LEN], imaxlevel[ICU_LEN];
184 struct intrhand *intrhand[ICU_LEN];
185 
186 int
187 fakeintr(void *arg)
188 {
189 	return 0;
190 }
191 
192 #define	LEGAL_IRQ(x)	((x) >= 0 && (x) < ICU_LEN && (x) != 2)
193 
194 int
195 isa_intr_alloc(isa_chipset_tag_t ic, int mask, int type, int *irq)
196 {
197 	int i, bestirq, count;
198 	int tmp;
199 	struct intrhand **p, *q;
200 
201 	if (type == IST_NONE)
202 		panic("intr_alloc: bogus type");
203 
204 	bestirq = -1;
205 	count = -1;
206 
207 	/* some interrupts should never be dynamically allocated */
208 	mask &= 0xdef8;
209 
210 	/*
211 	 * XXX some interrupts will be used later (6 for fdc, 12 for pms).
212 	 * the right answer is to do "breadth-first" searching of devices.
213 	 */
214 	mask &= 0xefbf;
215 
216 	for (i = 0; i < ICU_LEN; i++) {
217 		if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0)
218 			continue;
219 
220 		switch(intrtype[i]) {
221 		case IST_NONE:
222 			/*
223 			 * if nothing's using the irq, just return it
224 			 */
225 			*irq = i;
226 			return (0);
227 
228 		case IST_EDGE:
229 		case IST_LEVEL:
230 			if (type != intrtype[i])
231 				continue;
232 			/*
233 			 * if the irq is shareable, count the number of other
234 			 * handlers, and if it's smaller than the last irq like
235 			 * this, remember it
236 			 *
237 			 * XXX We should probably also consider the
238 			 * interrupt level and stick IPL_TTY with other
239 			 * IPL_TTY, etc.
240 			 */
241 			for (p = &intrhand[i], tmp = 0; (q = *p) != NULL;
242 			     p = &q->ih_next, tmp++)
243 				;
244 			if ((bestirq == -1) || (count > tmp)) {
245 				bestirq = i;
246 				count = tmp;
247 			}
248 			break;
249 
250 		case IST_PULSE:
251 			/* this just isn't shareable */
252 			continue;
253 		}
254 	}
255 
256 	if (bestirq == -1)
257 		return (1);
258 
259 	*irq = bestirq;
260 
261 	return (0);
262 }
263 
264 /*
265  * Just check to see if an IRQ is available/can be shared.
266  * 0 = interrupt not available
267  * 1 = interrupt shareable
268  * 2 = interrupt all to ourself
269  */
270 int
271 isa_intr_check(isa_chipset_tag_t ic, int irq, int type)
272 {
273 	if (!LEGAL_IRQ(irq) || type == IST_NONE)
274 		return (0);
275 
276 	switch (intrtype[irq]) {
277 	case IST_NONE:
278 		return (2);
279 		break;
280 	case IST_LEVEL:
281 		if (type != intrtype[irq])
282 			return (0);
283 		return (1);
284 		break;
285 	case IST_EDGE:
286 	case IST_PULSE:
287 		if (type != IST_NONE)
288 			return (0);
289 	}
290 	return (1);
291 }
292 
293 /*
294  * Set up an interrupt handler to start being called.
295  * XXX PRONE TO RACE CONDITIONS, UGLY, 'INTERESTING' INSERTION ALGORITHM.
296  */
297 void *
298 isa_intr_establish(isa_chipset_tag_t ic, int irq, int type, int level,
299     int (*ih_fun)(void *), void *ih_arg, char *ih_what)
300 {
301 	struct pic *pic = &i8259_pic;
302 	int pin = irq;
303 
304 #if NIOAPIC > 0
305 	struct mp_intr_map *mip;
306 
307  	if (mp_busses != NULL) {
308 		if (mp_isa_bus == NULL)
309 			panic("no isa bus");
310 
311 		for (mip = mp_isa_bus->mb_intrs; mip != NULL;
312 		    mip = mip->next) {
313  			if (mip->bus_pin == pin) {
314 				pin = APIC_IRQ_PIN(mip->ioapic_ih);
315 				pic = &mip->ioapic->sc_pic;
316  				break;
317  			}
318  		}
319  	}
320 #endif
321 
322 	KASSERT(pic);
323 
324 	return intr_establish(irq, pic, pin, type, level, ih_fun,
325 	    ih_arg, ih_what);
326 }
327 
328 /*
329  * Deregister an interrupt handler.
330  */
331 void
332 isa_intr_disestablish(isa_chipset_tag_t ic, void *arg)
333 {
334 	intr_disestablish(arg);
335 	return;
336 }
337 
338 void
339 isa_attach_hook(struct device *parent, struct device *self,
340     struct isabus_attach_args *iba)
341 {
342 	extern int isa_has_been_seen;
343 
344 	/*
345 	 * Notify others that might need to know that the ISA bus
346 	 * has now been attached.
347 	 */
348 	if (isa_has_been_seen)
349 		panic("isaattach: ISA bus already seen!");
350 	isa_has_been_seen = 1;
351 }
352 
353 #if NISADMA > 0
354 /**********************************************************************
355  * bus.h dma interface entry points
356  **********************************************************************/
357 
358 #ifdef ISA_DMA_STATS
359 #define	STAT_INCR(v)	(v)++
360 #define	STAT_DECR(v)	do { \
361 		if ((v) == 0) \
362 			printf("%s:%d -- Already 0!\n", __FILE__, __LINE__); \
363 		else \
364 			(v)--; \
365 		} while (0)
366 u_long	isa_dma_stats_loads;
367 u_long	isa_dma_stats_bounces;
368 u_long	isa_dma_stats_nbouncebufs;
369 #else
370 #define	STAT_INCR(v)
371 #define	STAT_DECR(v)
372 #endif
373 
374 /*
375  * Create an ISA DMA map.
376  */
377 int
378 _isa_bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
379     bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp)
380 {
381 	struct isa_dma_cookie *cookie;
382 	bus_dmamap_t map;
383 	int error, cookieflags;
384 	void *cookiestore;
385 	size_t cookiesize;
386 
387 	/* Call common function to create the basic map. */
388 	error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary,
389 	    flags, dmamp);
390 	if (error)
391 		return (error);
392 
393 	map = *dmamp;
394 	map->_dm_cookie = NULL;
395 
396 	cookiesize = sizeof(struct isa_dma_cookie);
397 
398 	/*
399 	 * ISA only has 24-bits of address space.  This means
400 	 * we can't DMA to pages over 16M.  In order to DMA to
401 	 * arbitrary buffers, we use "bounce buffers" - pages
402 	 * in memory below the 16M boundary.  On DMA reads,
403 	 * DMA happens to the bounce buffers, and is copied into
404 	 * the caller's buffer.  On writes, data is copied into
405 	 * the bounce buffer, and the DMA happens from those
406 	 * pages.  To software using the DMA mapping interface,
407 	 * this looks simply like a data cache.
408 	 *
409 	 * If we have more than 16M of RAM in the system, we may
410 	 * need bounce buffers.  We check and remember that here.
411 	 *
412 	 * There are exceptions, however.  VLB devices can do
413 	 * 32-bit DMA, and indicate that here.
414 	 *
415 	 * ...or, there is an opposite case.  The most segments
416 	 * a transfer will require is (maxxfer / NBPG) + 1.  If
417 	 * the caller can't handle that many segments (e.g. the
418 	 * ISA DMA controller), we may have to bounce it as well.
419 	 */
420 	cookieflags = 0;
421 	if ((avail_end > ISA_DMA_BOUNCE_THRESHOLD &&
422 	    (flags & ISABUS_DMA_32BIT) == 0) ||
423 	    ((map->_dm_size / NBPG) + 1) > map->_dm_segcnt) {
424 		cookieflags |= ID_MIGHT_NEED_BOUNCE;
425 		cookiesize += (sizeof(bus_dma_segment_t) * map->_dm_segcnt);
426 	}
427 
428 	/*
429 	 * Allocate our cookie.
430 	 */
431 	if ((cookiestore = malloc(cookiesize, M_DEVBUF,
432 	    (flags & BUS_DMA_NOWAIT) ?
433 	        (M_NOWAIT|M_ZERO) : (M_WAITOK|M_ZERO))) == NULL) {
434 		error = ENOMEM;
435 		goto out;
436 	}
437 	cookie = (struct isa_dma_cookie *)cookiestore;
438 	cookie->id_flags = cookieflags;
439 	map->_dm_cookie = cookie;
440 
441 	if (cookieflags & ID_MIGHT_NEED_BOUNCE) {
442 		/*
443 		 * Allocate the bounce pages now if the caller
444 		 * wishes us to do so.
445 		 */
446 		if ((flags & BUS_DMA_ALLOCNOW) == 0)
447 			goto out;
448 
449 		error = _isa_dma_alloc_bouncebuf(t, map, size, flags);
450 	}
451 
452  out:
453 	if (error) {
454 		if (map->_dm_cookie != NULL)
455 			free(map->_dm_cookie, M_DEVBUF);
456 		_bus_dmamap_destroy(t, map);
457 	}
458 	return (error);
459 }
460 
461 /*
462  * Destroy an ISA DMA map.
463  */
464 void
465 _isa_bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
466 {
467 	struct isa_dma_cookie *cookie = map->_dm_cookie;
468 
469 	/*
470 	 * Free any bounce pages this map might hold.
471 	 */
472 	if (cookie->id_flags & ID_HAS_BOUNCE)
473 		_isa_dma_free_bouncebuf(t, map);
474 
475 	free(cookie, M_DEVBUF);
476 	_bus_dmamap_destroy(t, map);
477 }
478 
479 /*
480  * Load an ISA DMA map with a linear buffer.
481  */
482 int
483 _isa_bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
484     bus_size_t buflen, struct proc *p, int flags)
485 {
486 	struct isa_dma_cookie *cookie = map->_dm_cookie;
487 	int error;
488 
489 	STAT_INCR(isa_dma_stats_loads);
490 
491 	/*
492 	 * Check to see if we might need to bounce the transfer.
493 	 */
494 	if (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) {
495 		/*
496 		 * Check if all pages are below the bounce
497 		 * threshold.  If they are, don't bother bouncing.
498 		 */
499 		if (_isa_dma_check_buffer(buf, buflen,
500 		    map->_dm_segcnt, map->_dm_boundary, p) == 0)
501 			return (_bus_dmamap_load(t, map, buf, buflen,
502 			    p, flags));
503 
504 		STAT_INCR(isa_dma_stats_bounces);
505 
506 		/*
507 		 * Allocate bounce pages, if necessary.
508 		 */
509 		if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) {
510 			error = _isa_dma_alloc_bouncebuf(t, map, buflen,
511 			    flags);
512 			if (error)
513 				return (error);
514 		}
515 
516 		/*
517 		 * Cache a pointer to the caller's buffer and
518 		 * load the DMA map with the bounce buffer.
519 		 */
520 		cookie->id_origbuf = buf;
521 		cookie->id_origbuflen = buflen;
522 		error = _bus_dmamap_load(t, map, cookie->id_bouncebuf,
523 		    buflen, p, flags);
524 
525 		if (error) {
526 			/*
527 			 * Free the bounce pages, unless our resources
528 			 * are reserved for our exclusive use.
529 			 */
530 			if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0)
531 				_isa_dma_free_bouncebuf(t, map);
532 		}
533 
534 		/* ...so _isa_bus_dmamap_sync() knows we're bouncing */
535 		cookie->id_flags |= ID_IS_BOUNCING;
536 	} else {
537 		/*
538 		 * Just use the generic load function.
539 		 */
540 		error = _bus_dmamap_load(t, map, buf, buflen, p, flags);
541 	}
542 
543 	return (error);
544 }
545 
546 /*
547  * Like _isa_bus_dmamap_load(), but for mbufs.
548  */
549 int
550 _isa_bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m,
551     int flags)
552 {
553 
554 	panic("_isa_bus_dmamap_load_mbuf: not implemented");
555 }
556 
557 /*
558  * Like _isa_bus_dmamap_load(), but for uios.
559  */
560 int
561 _isa_bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio,
562     int flags)
563 {
564 
565 	panic("_isa_bus_dmamap_load_uio: not implemented");
566 }
567 
568 /*
569  * Like _isa_bus_dmamap_load(), but for raw memory allocated with
570  * bus_dmamem_alloc().
571  */
572 int
573 _isa_bus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
574     bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
575 {
576 
577 	panic("_isa_bus_dmamap_load_raw: not implemented");
578 }
579 
580 /*
581  * Unload an ISA DMA map.
582  */
583 void
584 _isa_bus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
585 {
586 	struct isa_dma_cookie *cookie = map->_dm_cookie;
587 
588 	/*
589 	 * If we have bounce pages, free them, unless they're
590 	 * reserved for our exclusive use.
591 	 */
592 	if ((cookie->id_flags & ID_HAS_BOUNCE) &&
593 	    (map->_dm_flags & BUS_DMA_ALLOCNOW) == 0)
594 		_isa_dma_free_bouncebuf(t, map);
595 
596 	cookie->id_flags &= ~ID_IS_BOUNCING;
597 
598 	/*
599 	 * Do the generic bits of the unload.
600 	 */
601 	_bus_dmamap_unload(t, map);
602 }
603 
604 /*
605  * Synchronize an ISA DMA map.
606  */
607 void
608 _isa_bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
609     bus_size_t len, int op)
610 {
611 	struct isa_dma_cookie *cookie = map->_dm_cookie;
612 
613 #ifdef DEBUG
614 	if ((op & (BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD)) != 0) {
615 		if (offset >= map->dm_mapsize)
616 			panic("_isa_bus_dmamap_sync: bad offset");
617 		if (len == 0 || (offset + len) > map->dm_mapsize)
618 			panic("_isa_bus_dmamap_sync: bad length");
619 	}
620 #endif
621 #ifdef DIAGNOSTIC
622 	if ((op & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) != 0 &&
623 	    (op & (BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)) != 0)
624 		panic("_isa_bus_dmamap_sync: mix PRE and POST");
625 #endif /* DIAGNOSTIC */
626 
627 	/* PREREAD and POSTWRITE are no-ops */
628 	if (op & BUS_DMASYNC_PREWRITE) {
629 		/*
630 		 * If we're bouncing this transfer, copy the
631 		 * caller's buffer to the bounce buffer.
632 		 */
633 		if (cookie->id_flags & ID_IS_BOUNCING)
634 			bcopy(cookie->id_origbuf + offset,
635 			    cookie->id_bouncebuf + offset,
636 			    len);
637 	} else if (op & BUS_DMASYNC_POSTREAD) {
638 		/*
639 		 * If we're bouncing this transfer, copy the
640 		 * bounce buffer to the caller's buffer.
641 		 */
642 		if (cookie->id_flags & ID_IS_BOUNCING)
643 			bcopy(cookie->id_bouncebuf + offset,
644 			    cookie->id_origbuf + offset,
645 			    len);
646 	}
647 
648 #if 0
649 	/* This is a noop anyhow, so why bother calling it? */
650 	_bus_dmamap_sync(t, map, op);
651 #endif
652 }
653 
654 /*
655  * Allocate memory safe for ISA DMA.
656  */
657 int
658 _isa_bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment,
659     bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
660     int flags)
661 {
662 	int error;
663 
664 	/* Try in ISA addressable region first */
665 	error = _bus_dmamem_alloc_range(t, size, alignment, boundary,
666 	    segs, nsegs, rsegs, flags, 0, ISA_DMA_BOUNCE_THRESHOLD);
667 	if (!error)
668 		return (error);
669 
670 	/* Otherwise try anywhere (we'll bounce later) */
671 	error = _bus_dmamem_alloc_range(t, size, alignment, boundary,
672 	    segs, nsegs, rsegs, flags, (paddr_t)0, (paddr_t)-1);
673 	return (error);
674 }
675 
676 /**********************************************************************
677  * ISA DMA utility functions
678  **********************************************************************/
679 
680 /*
681  * Return 0 if all pages in the passed buffer lie within the DMA'able
682  * range RAM.
683  */
684 int
685 _isa_dma_check_buffer(void *buf, bus_size_t buflen, int segcnt,
686     bus_size_t boundary, struct proc *p)
687 {
688 	vaddr_t vaddr = (vaddr_t)buf;
689 	vaddr_t endva;
690 	paddr_t pa, lastpa;
691 	u_long pagemask = ~(boundary - 1);
692 	pmap_t pmap;
693 	int nsegs;
694 
695 	endva = round_page(vaddr + buflen);
696 
697 	nsegs = 1;
698 	lastpa = 0;
699 
700 	if (p != NULL)
701 		pmap = p->p_vmspace->vm_map.pmap;
702 	else
703 		pmap = pmap_kernel();
704 
705 	for (; vaddr < endva; vaddr += NBPG) {
706 		/*
707 		 * Get physical address for this segment.
708 		 */
709 		pmap_extract(pmap, (vaddr_t)vaddr, &pa);
710 		pa = trunc_page(pa);
711 
712 		/*
713 		 * Is it below the DMA'able threshold?
714 		 */
715 		if (pa > ISA_DMA_BOUNCE_THRESHOLD)
716 			return (EINVAL);
717 
718 		if (lastpa) {
719 			/*
720 			 * Check excessive segment count.
721 			 */
722 			if (lastpa + NBPG != pa) {
723 				if (++nsegs > segcnt)
724 					return (EFBIG);
725 			}
726 
727 			/*
728 			 * Check boundary restriction.
729 			 */
730 			if (boundary) {
731 				if ((lastpa ^ pa) & pagemask)
732 					return (EINVAL);
733 			}
734 		}
735 		lastpa = pa;
736 	}
737 
738 	return (0);
739 }
740 
741 int
742 _isa_dma_alloc_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map, bus_size_t size,
743     int flags)
744 {
745 	struct isa_dma_cookie *cookie = map->_dm_cookie;
746 	int error = 0;
747 
748 	cookie->id_bouncebuflen = round_page(size);
749 	error = _bus_dmamem_alloc_range(t, cookie->id_bouncebuflen,
750 	    NBPG, map->_dm_boundary, cookie->id_bouncesegs,
751 	    map->_dm_segcnt, &cookie->id_nbouncesegs, flags,
752 	    0, ISA_DMA_BOUNCE_THRESHOLD);
753 	if (error)
754 		goto out;
755 	error = _bus_dmamem_map(t, cookie->id_bouncesegs,
756 	    cookie->id_nbouncesegs, cookie->id_bouncebuflen,
757 	    (caddr_t *)&cookie->id_bouncebuf, flags);
758 
759  out:
760 	if (error) {
761 		_bus_dmamem_free(t, cookie->id_bouncesegs,
762 		    cookie->id_nbouncesegs);
763 		cookie->id_bouncebuflen = 0;
764 		cookie->id_nbouncesegs = 0;
765 	} else {
766 		cookie->id_flags |= ID_HAS_BOUNCE;
767 		STAT_INCR(isa_dma_stats_nbouncebufs);
768 	}
769 
770 	return (error);
771 }
772 
773 void
774 _isa_dma_free_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map)
775 {
776 	struct isa_dma_cookie *cookie = map->_dm_cookie;
777 
778 	STAT_DECR(isa_dma_stats_nbouncebufs);
779 
780 	_bus_dmamem_unmap(t, cookie->id_bouncebuf,
781 	    cookie->id_bouncebuflen);
782 	_bus_dmamem_free(t, cookie->id_bouncesegs,
783 	    cookie->id_nbouncesegs);
784 	cookie->id_bouncebuflen = 0;
785 	cookie->id_nbouncesegs = 0;
786 	cookie->id_flags &= ~ID_HAS_BOUNCE;
787 }
788 #endif /* NISADMA > 0 */
789