1 /*	$OpenBSD: isa_machdep.c,v 1.48 2003/06/02 23:27:47 millert 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  * 3. All advertising materials mentioning features or use of this software
23  *    must display the following acknowledgement:
24  *	This product includes software developed by the NetBSD
25  *	Foundation, Inc. and its contributors.
26  * 4. Neither the name of The NetBSD Foundation nor the names of its
27  *    contributors may be used to endorse or promote products derived
28  *    from this software without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
31  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
34  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40  * POSSIBILITY OF SUCH DAMAGE.
41  */
42 
43 /*-
44  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
45  * All rights reserved.
46  *
47  * This code is derived from software contributed to The NetBSD Foundation
48  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
49  * NASA Ames Research Center.
50  *
51  * Redistribution and use in source and binary forms, with or without
52  * modification, are permitted provided that the following conditions
53  * are met:
54  * 1. Redistributions of source code must retain the above copyright
55  *    notice, this list of conditions and the following disclaimer.
56  * 2. Redistributions in binary form must reproduce the above copyright
57  *    notice, this list of conditions and the following disclaimer in the
58  *    documentation and/or other materials provided with the distribution.
59  * 3. All advertising materials mentioning features or use of this software
60  *    must display the following acknowledgement:
61  *	This product includes software developed by the NetBSD
62  *	Foundation, Inc. and its contributors.
63  * 4. Neither the name of The NetBSD Foundation nor the names of its
64  *    contributors may be used to endorse or promote products derived
65  *    from this software without specific prior written permission.
66  *
67  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
68  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
69  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
70  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
71  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
72  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
73  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
74  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
75  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
76  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
77  * POSSIBILITY OF SUCH DAMAGE.
78  */
79 
80 /*-
81  * Copyright (c) 1993, 1994, 1996, 1997
82  *	Charles M. Hannum.  All rights reserved.
83  * Copyright (c) 1991 The Regents of the University of California.
84  * All rights reserved.
85  *
86  * This code is derived from software contributed to Berkeley by
87  * William Jolitz.
88  *
89  * Redistribution and use in source and binary forms, with or without
90  * modification, are permitted provided that the following conditions
91  * are met:
92  * 1. Redistributions of source code must retain the above copyright
93  *    notice, this list of conditions and the following disclaimer.
94  * 2. Redistributions in binary form must reproduce the above copyright
95  *    notice, this list of conditions and the following disclaimer in the
96  *    documentation and/or other materials provided with the distribution.
97  * 3. Neither the name of the University nor the names of its contributors
98  *    may be used to endorse or promote products derived from this software
99  *    without specific prior written permission.
100  *
101  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
102  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
103  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
104  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
105  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
106  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
107  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
108  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
109  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
110  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
111  * SUCH DAMAGE.
112  *
113  *	@(#)isa.c	7.2 (Berkeley) 5/13/91
114  */
115 
116 #include <sys/param.h>
117 #include <sys/systm.h>
118 #include <sys/syslog.h>
119 #include <sys/device.h>
120 #include <sys/malloc.h>
121 #include <sys/proc.h>
122 
123 #include <uvm/uvm_extern.h>
124 
125 #define _I386_BUS_DMA_PRIVATE
126 #include <machine/bus.h>
127 
128 #include <machine/intr.h>
129 #include <machine/pio.h>
130 #include <machine/cpufunc.h>
131 
132 #include <dev/isa/isareg.h>
133 #include <dev/isa/isavar.h>
134 #include <dev/isa/isadmavar.h>
135 #include <i386/isa/isa_machdep.h>
136 #include <i386/isa/icu.h>
137 
138 #include "isadma.h"
139 
140 /*
141  * ISA can only DMA to 0-16M.
142  */
143 #define	ISA_DMA_BOUNCE_THRESHOLD	0x00ffffff
144 
145 extern	paddr_t avail_end;
146 
147 #define	IDTVEC(name)	__CONCAT(X,name)
148 /* default interrupt vector table entries */
149 typedef int (*vector)(void);
150 extern vector IDTVEC(intr)[];
151 void isa_strayintr(int);
152 void intr_calculatemasks(void);
153 int fakeintr(void *);
154 
155 #if NISADMA > 0
156 int	_isa_bus_dmamap_create(bus_dma_tag_t, bus_size_t, int,
157 	    bus_size_t, bus_size_t, int, bus_dmamap_t *);
158 void	_isa_bus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
159 int	_isa_bus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *,
160 	    bus_size_t, struct proc *, int);
161 int	_isa_bus_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t,
162 	    struct mbuf *, int);
163 int	_isa_bus_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t,
164 	    struct uio *, int);
165 int	_isa_bus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
166 	    bus_dma_segment_t *, int, bus_size_t, int);
167 void	_isa_bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
168 void	_isa_bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t,
169 	    bus_addr_t, bus_size_t, int);
170 
171 int	_isa_bus_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t,
172 	    bus_size_t, bus_dma_segment_t *, int, int *, int);
173 void	_isa_bus_dmamem_free(bus_dma_tag_t,
174 	    bus_dma_segment_t *, int);
175 int	_isa_bus_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *,
176 	    int, size_t, caddr_t *, int);
177 void	_isa_bus_dmamem_unmap(bus_dma_tag_t, caddr_t, size_t);
178 paddr_t	_isa_bus_dmamem_mmap(bus_dma_tag_t, bus_dma_segment_t *,
179 	    int, off_t, int, int);
180 
181 int	_isa_dma_check_buffer(void *, bus_size_t, int, bus_size_t,
182 	    struct proc *);
183 int	_isa_dma_alloc_bouncebuf(bus_dma_tag_t, bus_dmamap_t,
184 	    bus_size_t, int);
185 void	_isa_dma_free_bouncebuf(bus_dma_tag_t, bus_dmamap_t);
186 
187 /*
188  * Entry points for ISA DMA.  These are mostly wrappers around
189  * the generic functions that understand how to deal with bounce
190  * buffers, if necessary.
191  */
192 struct i386_bus_dma_tag isa_bus_dma_tag = {
193 	NULL,			/* _cookie */
194 	_isa_bus_dmamap_create,
195 	_isa_bus_dmamap_destroy,
196 	_isa_bus_dmamap_load,
197 	_isa_bus_dmamap_load_mbuf,
198 	_isa_bus_dmamap_load_uio,
199 	_isa_bus_dmamap_load_raw,
200 	_isa_bus_dmamap_unload,
201 	_isa_bus_dmamap_sync,
202 	_isa_bus_dmamem_alloc,
203 	_isa_bus_dmamem_free,
204 	_isa_bus_dmamem_map,
205 	_isa_bus_dmamem_unmap,
206 	_isa_bus_dmamem_mmap,
207 };
208 #endif /* NISADMA > 0 */
209 
210 /*
211  * Fill in default interrupt table (in case of spurious interrupt
212  * during configuration of kernel, setup interrupt control unit
213  */
214 void
isa_defaultirq()215 isa_defaultirq()
216 {
217 	int i;
218 
219 	/* icu vectors */
220 	for (i = 0; i < ICU_LEN; i++)
221 		setgate(&idt[ICU_OFFSET + i], IDTVEC(intr)[i], 0,
222 		    SDT_SYS386IGT, SEL_KPL, GICODE_SEL);
223 
224 	/* initialize 8259's */
225 	outb(IO_ICU1, 0x11);		/* reset; program device, four bytes */
226 	outb(IO_ICU1+1, ICU_OFFSET);	/* starting at this vector index */
227 	outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */
228 #ifdef AUTO_EOI_1
229 	outb(IO_ICU1+1, 2 | 1);		/* auto EOI, 8086 mode */
230 #else
231 	outb(IO_ICU1+1, 1);		/* 8086 mode */
232 #endif
233 	outb(IO_ICU1+1, 0xff);		/* leave interrupts masked */
234 	outb(IO_ICU1, 0x68);		/* special mask mode (if available) */
235 	outb(IO_ICU1, 0x0a);		/* Read IRR by default. */
236 #ifdef REORDER_IRQ
237 	outb(IO_ICU1, 0xc0 | (3 - 1));	/* pri order 3-7, 0-2 (com2 first) */
238 #endif
239 
240 	outb(IO_ICU2, 0x11);		/* reset; program device, four bytes */
241 	outb(IO_ICU2+1, ICU_OFFSET+8);	/* staring at this vector index */
242 	outb(IO_ICU2+1, IRQ_SLAVE);
243 #ifdef AUTO_EOI_2
244 	outb(IO_ICU2+1, 2 | 1);		/* auto EOI, 8086 mode */
245 #else
246 	outb(IO_ICU2+1, 1);		/* 8086 mode */
247 #endif
248 	outb(IO_ICU2+1, 0xff);		/* leave interrupts masked */
249 	outb(IO_ICU2, 0x68);		/* special mask mode (if available) */
250 	outb(IO_ICU2, 0x0a);		/* Read IRR by default. */
251 }
252 
253 /*
254  * Handle a NMI, possibly a machine check.
255  * return true to panic system, false to ignore.
256  */
257 int
isa_nmi()258 isa_nmi()
259 {
260 	/* This is historic garbage; these ports are not readable */
261 	log(LOG_CRIT, "No-maskable interrupt, may be parity error\n");
262 	return(0);
263 }
264 
265 u_long  intrstray[ICU_LEN];
266 
267 /*
268  * Caught a stray interrupt, notify
269  */
270 void
isa_strayintr(irq)271 isa_strayintr(irq)
272 	int irq;
273 {
274         /*
275          * Stray interrupts on irq 7 occur when an interrupt line is raised
276          * and then lowered before the CPU acknowledges it.  This generally
277          * means either the device is screwed or something is cli'ing too
278          * long and it's timing out.
279          */
280 	if (++intrstray[irq] <= 5)
281 		log(LOG_ERR, "stray interrupt %d%s\n", irq,
282 		    intrstray[irq] >= 5 ? "; stopped logging" : "");
283 }
284 
285 int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
286 int iminlevel[ICU_LEN], imaxlevel[ICU_LEN];
287 struct intrhand *intrhand[ICU_LEN];
288 
289 /*
290  * Recalculate the interrupt masks from scratch.
291  * We could code special registry and deregistry versions of this function that
292  * would be faster, but the code would be nastier, and we don't expect this to
293  * happen very much anyway.
294  */
295 void
intr_calculatemasks()296 intr_calculatemasks()
297 {
298 	int irq, level;
299 	struct intrhand *q;
300 
301 	/* First, figure out which levels each IRQ uses. */
302 	for (irq = 0; irq < ICU_LEN; irq++) {
303 		register int levels = 0;
304 		for (q = intrhand[irq]; q; q = q->ih_next)
305 			levels |= 1 << IPL(q->ih_level);
306 		intrlevel[irq] = levels;
307 	}
308 
309 	/* Then figure out which IRQs use each level. */
310 	for (level = 0; level < NIPL; level++) {
311 		register int irqs = 0;
312 		for (irq = 0; irq < ICU_LEN; irq++)
313 			if (intrlevel[irq] & (1 << level))
314 				irqs |= 1 << irq;
315 		imask[level] = irqs;
316 	}
317 
318 	/*
319 	 * Initialize soft interrupt masks to block themselves.
320 	 */
321 	IMASK(IPL_SOFTCLOCK) |= 1 << SIR_CLOCK;
322 	IMASK(IPL_SOFTNET) |= 1 << SIR_NET;
323 	IMASK(IPL_SOFTTTY) |= 1 << SIR_TTY;
324 
325 	/*
326 	 * Enforce a hierarchy that gives slow devices a better chance at not
327 	 * dropping data.
328 	 */
329 	for (level = 0; level < NIPL - 1; level++)
330 		imask[level + 1] |= imask[level];
331 
332 	/* And eventually calculate the complete masks. */
333 	for (irq = 0; irq < ICU_LEN; irq++) {
334 		register int irqs = 1 << irq;
335 		int minlevel = IPL_NONE;
336 		int maxlevel = IPL_NONE;
337 
338 		for (q = intrhand[irq]; q; q = q->ih_next) {
339 			irqs |= IMASK(q->ih_level);
340 			if (minlevel == IPL_NONE || q->ih_level < minlevel)
341 				minlevel = q->ih_level;
342 			if (q->ih_level > maxlevel)
343 				maxlevel = q->ih_level;
344 		}
345 		intrmask[irq] = irqs;
346 		iminlevel[irq] = minlevel;
347 		imaxlevel[irq] = maxlevel;
348 	}
349 
350 	/* Lastly, determine which IRQs are actually in use. */
351 	{
352 		register int irqs = 0;
353 		for (irq = 0; irq < ICU_LEN; irq++)
354 			if (intrhand[irq])
355 				irqs |= 1 << irq;
356 		if (irqs >= 0x100) /* any IRQs >= 8 in use */
357 			irqs |= 1 << IRQ_SLAVE;
358 		imen = ~irqs;
359 		SET_ICUS();
360 	}
361 
362 	/* For speed of splx, provide the inverse of the interrupt masks. */
363 	for (irq = 0; irq < ICU_LEN; irq++)
364 		iunmask[irq] = ~imask[irq];
365 }
366 
367 int
fakeintr(arg)368 fakeintr(arg)
369 	void *arg;
370 {
371 	return 0;
372 }
373 
374 #define	LEGAL_IRQ(x)	((x) >= 0 && (x) < ICU_LEN && (x) != 2)
375 
376 int
isa_intr_alloc(ic,mask,type,irq)377 isa_intr_alloc(ic, mask, type, irq)
378 	isa_chipset_tag_t ic;
379 	int mask;
380 	int type;
381 	int *irq;
382 {
383 	int i, bestirq, count;
384 	int tmp;
385 	struct intrhand **p, *q;
386 
387 	if (type == IST_NONE)
388 		panic("intr_alloc: bogus type");
389 
390 	bestirq = -1;
391 	count = -1;
392 
393 	/* some interrupts should never be dynamically allocated */
394 	mask &= 0xdef8;
395 
396 	/*
397 	 * XXX some interrupts will be used later (6 for fdc, 12 for pms).
398 	 * the right answer is to do "breadth-first" searching of devices.
399 	 */
400 	mask &= 0xefbf;
401 
402 	for (i = 0; i < ICU_LEN; i++) {
403 		if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0)
404 			continue;
405 
406 		switch(intrtype[i]) {
407 		case IST_NONE:
408 			/*
409 			 * if nothing's using the irq, just return it
410 			 */
411 			*irq = i;
412 			return (0);
413 
414 		case IST_EDGE:
415 		case IST_LEVEL:
416 			if (type != intrtype[i])
417 				continue;
418 			/*
419 			 * if the irq is shareable, count the number of other
420 			 * handlers, and if it's smaller than the last irq like
421 			 * this, remember it
422 			 *
423 			 * XXX We should probably also consider the
424 			 * interrupt level and stick IPL_TTY with other
425 			 * IPL_TTY, etc.
426 			 */
427 			for (p = &intrhand[i], tmp = 0; (q = *p) != NULL;
428 			     p = &q->ih_next, tmp++)
429 				;
430 			if ((bestirq == -1) || (count > tmp)) {
431 				bestirq = i;
432 				count = tmp;
433 			}
434 			break;
435 
436 		case IST_PULSE:
437 			/* this just isn't shareable */
438 			continue;
439 		}
440 	}
441 
442 	if (bestirq == -1)
443 		return (1);
444 
445 	*irq = bestirq;
446 
447 	return (0);
448 }
449 
450 /*
451  * Just check to see if an IRQ is available/can be shared.
452  * 0 = interrupt not available
453  * 1 = interrupt shareable
454  * 2 = interrupt all to ourself
455  */
456 int
isa_intr_check(ic,irq,type)457 isa_intr_check(ic, irq, type)
458 	isa_chipset_tag_t ic;	/* Not used. */
459 	int irq;
460 	int type;
461 {
462 	if (!LEGAL_IRQ(irq) || type == IST_NONE)
463 		return (0);
464 
465 	switch (intrtype[irq]) {
466 	case IST_NONE:
467 		return (2);
468 		break;
469 	case IST_LEVEL:
470 		if (type != intrtype[irq])
471 			return (0);
472 		return (1);
473 		break;
474 	case IST_EDGE:
475 	case IST_PULSE:
476 		if (type != IST_NONE)
477 			return (0);
478 	}
479 	return (1);
480 }
481 
482 /*
483  * Set up an interrupt handler to start being called.
484  * XXX PRONE TO RACE CONDITIONS, UGLY, 'INTERESTING' INSERTION ALGORITHM.
485  */
486 void *
isa_intr_establish(ic,irq,type,level,ih_fun,ih_arg,ih_what)487 isa_intr_establish(ic, irq, type, level, ih_fun, ih_arg, ih_what)
488 	isa_chipset_tag_t ic;
489 	int irq;
490 	int type;
491 	int level;
492 	int (*ih_fun)(void *);
493 	void *ih_arg;
494 	char *ih_what;
495 {
496 	struct intrhand **p, *q, *ih;
497 	static struct intrhand fakehand = {fakeintr};
498 
499 	/* no point in sleeping unless someone can free memory. */
500 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
501 	if (ih == NULL) {
502 		printf("%s: isa_intr_establish: can't malloc handler info\n",
503 		    ih_what);
504 		return NULL;
505 	}
506 
507 	if (!LEGAL_IRQ(irq) || type == IST_NONE) {
508 		printf("%s: intr_establish: bogus irq or type\n", ih_what);
509 		return NULL;
510 	}
511 	switch (intrtype[irq]) {
512 	case IST_NONE:
513 		intrtype[irq] = type;
514 		break;
515 	case IST_EDGE:
516 	case IST_LEVEL:
517 		if (type == intrtype[irq])
518 			break;
519 	case IST_PULSE:
520 		if (type != IST_NONE) {
521 			/*printf("%s: intr_establish: can't share %s with %s, irq %d\n",
522 			    ih_what, isa_intr_typename(intrtype[irq]),
523 			    isa_intr_typename(type), irq);*/
524 			return NULL;
525 		}
526 		break;
527 	}
528 
529 	/*
530 	 * Figure out where to put the handler.
531 	 * This is O(N^2), but we want to preserve the order, and N is
532 	 * generally small.
533 	 */
534 	for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
535 		;
536 
537 	/*
538 	 * Actually install a fake handler momentarily, since we might be doing
539 	 * this with interrupts enabled and don't want the real routine called
540 	 * until masking is set up.
541 	 */
542 	fakehand.ih_level = level;
543 	*p = &fakehand;
544 
545 	intr_calculatemasks();
546 
547 	/*
548 	 * Poke the real handler in now.
549 	 */
550 	ih->ih_fun = ih_fun;
551 	ih->ih_arg = ih_arg;
552 	ih->ih_count = 0;
553 	ih->ih_next = NULL;
554 	ih->ih_level = level;
555 	ih->ih_irq = irq;
556 	ih->ih_what = ih_what;
557 	*p = ih;
558 
559 	return (ih);
560 }
561 
562 /*
563  * Deregister an interrupt handler.
564  */
565 void
isa_intr_disestablish(ic,arg)566 isa_intr_disestablish(ic, arg)
567 	isa_chipset_tag_t ic;
568 	void *arg;
569 {
570 	struct intrhand *ih = arg;
571 	int irq = ih->ih_irq;
572 	struct intrhand **p, *q;
573 
574 	if (!LEGAL_IRQ(irq))
575 		panic("intr_disestablish: bogus irq");
576 
577 	/*
578 	 * Remove the handler from the chain.
579 	 * This is O(n^2), too.
580 	 */
581 	for (p = &intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next)
582 		;
583 	if (q)
584 		*p = q->ih_next;
585 	else
586 		panic("intr_disestablish: handler not registered");
587 	free(ih, M_DEVBUF);
588 
589 	intr_calculatemasks();
590 
591 	if (intrhand[irq] == NULL)
592 		intrtype[irq] = IST_NONE;
593 }
594 
595 void
isa_attach_hook(parent,self,iba)596 isa_attach_hook(parent, self, iba)
597 	struct device *parent, *self;
598 	struct isabus_attach_args *iba;
599 {
600 	extern int isa_has_been_seen;
601 
602 	/*
603 	 * Notify others that might need to know that the ISA bus
604 	 * has now been attached.
605 	 */
606 	if (isa_has_been_seen)
607 		panic("isaattach: ISA bus already seen!");
608 	isa_has_been_seen = 1;
609 }
610 
611 #if NISADMA > 0
612 /**********************************************************************
613  * bus.h dma interface entry points
614  **********************************************************************/
615 
616 #ifdef ISA_DMA_STATS
617 #define	STAT_INCR(v)	(v)++
618 #define	STAT_DECR(v)	do { \
619 		if ((v) == 0) \
620 			printf("%s:%d -- Already 0!\n", __FILE__, __LINE__); \
621 		else \
622 			(v)--; \
623 		} while (0)
624 u_long	isa_dma_stats_loads;
625 u_long	isa_dma_stats_bounces;
626 u_long	isa_dma_stats_nbouncebufs;
627 #else
628 #define	STAT_INCR(v)
629 #define	STAT_DECR(v)
630 #endif
631 
632 /*
633  * Create an ISA DMA map.
634  */
635 int
_isa_bus_dmamap_create(t,size,nsegments,maxsegsz,boundary,flags,dmamp)636 _isa_bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp)
637 	bus_dma_tag_t t;
638 	bus_size_t size;
639 	int nsegments;
640 	bus_size_t maxsegsz;
641 	bus_size_t boundary;
642 	int flags;
643 	bus_dmamap_t *dmamp;
644 {
645 	struct i386_isa_dma_cookie *cookie;
646 	bus_dmamap_t map;
647 	int error, cookieflags;
648 	void *cookiestore;
649 	size_t cookiesize;
650 
651 	/* Call common function to create the basic map. */
652 	error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary,
653 	    flags, dmamp);
654 	if (error)
655 		return (error);
656 
657 	map = *dmamp;
658 	map->_dm_cookie = NULL;
659 
660 	cookiesize = sizeof(struct i386_isa_dma_cookie);
661 
662 	/*
663 	 * ISA only has 24-bits of address space.  This means
664 	 * we can't DMA to pages over 16M.  In order to DMA to
665 	 * arbitrary buffers, we use "bounce buffers" - pages
666 	 * in memory below the 16M boundary.  On DMA reads,
667 	 * DMA happens to the bounce buffers, and is copied into
668 	 * the caller's buffer.  On writes, data is copied into
669 	 * but bounce buffer, and the DMA happens from those
670 	 * pages.  To software using the DMA mapping interface,
671 	 * this looks simply like a data cache.
672 	 *
673 	 * If we have more than 16M of RAM in the system, we may
674 	 * need bounce buffers.  We check and remember that here.
675 	 *
676 	 * There are exceptions, however.  VLB devices can do
677 	 * 32-bit DMA, and indicate that here.
678 	 *
679 	 * ...or, there is an opposite case.  The most segments
680 	 * a transfer will require is (maxxfer / NBPG) + 1.  If
681 	 * the caller can't handle that many segments (e.g. the
682 	 * ISA DMA controller), we may have to bounce it as well.
683 	 */
684 	cookieflags = 0;
685 	if ((avail_end > ISA_DMA_BOUNCE_THRESHOLD &&
686 	    (flags & ISABUS_DMA_32BIT) == 0) ||
687 	    ((map->_dm_size / NBPG) + 1) > map->_dm_segcnt) {
688 		cookieflags |= ID_MIGHT_NEED_BOUNCE;
689 		cookiesize += (sizeof(bus_dma_segment_t) * map->_dm_segcnt);
690 	}
691 
692 	/*
693 	 * Allocate our cookie.
694 	 */
695 	if ((cookiestore = malloc(cookiesize, M_DEVBUF,
696 	    (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) {
697 		error = ENOMEM;
698 		goto out;
699 	}
700 	bzero(cookiestore, cookiesize);
701 	cookie = (struct i386_isa_dma_cookie *)cookiestore;
702 	cookie->id_flags = cookieflags;
703 	map->_dm_cookie = cookie;
704 
705 	if (cookieflags & ID_MIGHT_NEED_BOUNCE) {
706 		/*
707 		 * Allocate the bounce pages now if the caller
708 		 * wishes us to do so.
709 		 */
710 		if ((flags & BUS_DMA_ALLOCNOW) == 0)
711 			goto out;
712 
713 		error = _isa_dma_alloc_bouncebuf(t, map, size, flags);
714 	}
715 
716  out:
717 	if (error) {
718 		if (map->_dm_cookie != NULL)
719 			free(map->_dm_cookie, M_DEVBUF);
720 		_bus_dmamap_destroy(t, map);
721 	}
722 	return (error);
723 }
724 
725 /*
726  * Destroy an ISA DMA map.
727  */
728 void
_isa_bus_dmamap_destroy(t,map)729 _isa_bus_dmamap_destroy(t, map)
730 	bus_dma_tag_t t;
731 	bus_dmamap_t map;
732 {
733 	struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
734 
735 	/*
736 	 * Free any bounce pages this map might hold.
737 	 */
738 	if (cookie->id_flags & ID_HAS_BOUNCE)
739 		_isa_dma_free_bouncebuf(t, map);
740 
741 	free(cookie, M_DEVBUF);
742 	_bus_dmamap_destroy(t, map);
743 }
744 
745 /*
746  * Load an ISA DMA map with a linear buffer.
747  */
748 int
_isa_bus_dmamap_load(t,map,buf,buflen,p,flags)749 _isa_bus_dmamap_load(t, map, buf, buflen, p, flags)
750 	bus_dma_tag_t t;
751 	bus_dmamap_t map;
752 	void *buf;
753 	bus_size_t buflen;
754 	struct proc *p;
755 	int flags;
756 {
757 	struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
758 	int error;
759 
760 	STAT_INCR(isa_dma_stats_loads);
761 
762 	/*
763 	 * Check to see if we might need to bounce the transfer.
764 	 */
765 	if (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) {
766 		/*
767 		 * Check if all pages are below the bounce
768 		 * threshold.  If they are, don't bother bouncing.
769 		 */
770 		if (_isa_dma_check_buffer(buf, buflen,
771 		    map->_dm_segcnt, map->_dm_boundary, p) == 0)
772 			return (_bus_dmamap_load(t, map, buf, buflen,
773 			    p, flags));
774 
775 		STAT_INCR(isa_dma_stats_bounces);
776 
777 		/*
778 		 * Allocate bounce pages, if necessary.
779 		 */
780 		if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) {
781 			error = _isa_dma_alloc_bouncebuf(t, map, buflen,
782 			    flags);
783 			if (error)
784 				return (error);
785 		}
786 
787 		/*
788 		 * Cache a pointer to the caller's buffer and
789 		 * load the DMA map with the bounce buffer.
790 		 */
791 		cookie->id_origbuf = buf;
792 		cookie->id_origbuflen = buflen;
793 		error = _bus_dmamap_load(t, map, cookie->id_bouncebuf,
794 		    buflen, p, flags);
795 
796 		if (error) {
797 			/*
798 			 * Free the bounce pages, unless our resources
799 			 * are reserved for our exclusive use.
800 			 */
801 			if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0)
802 				_isa_dma_free_bouncebuf(t, map);
803 		}
804 
805 		/* ...so _isa_bus_dmamap_sync() knows we're bouncing */
806 		cookie->id_flags |= ID_IS_BOUNCING;
807 	} else {
808 		/*
809 		 * Just use the generic load function.
810 		 */
811 		error = _bus_dmamap_load(t, map, buf, buflen, p, flags);
812 	}
813 
814 	return (error);
815 }
816 
817 /*
818  * Like _isa_bus_dmamap_load(), but for mbufs.
819  */
820 int
_isa_bus_dmamap_load_mbuf(t,map,m,flags)821 _isa_bus_dmamap_load_mbuf(t, map, m, flags)
822 	bus_dma_tag_t t;
823 	bus_dmamap_t map;
824 	struct mbuf *m;
825 	int flags;
826 {
827 
828 	panic("_isa_bus_dmamap_load_mbuf: not implemented");
829 }
830 
831 /*
832  * Like _isa_bus_dmamap_load(), but for uios.
833  */
834 int
_isa_bus_dmamap_load_uio(t,map,uio,flags)835 _isa_bus_dmamap_load_uio(t, map, uio, flags)
836 	bus_dma_tag_t t;
837 	bus_dmamap_t map;
838 	struct uio *uio;
839 	int flags;
840 {
841 
842 	panic("_isa_bus_dmamap_load_uio: not implemented");
843 }
844 
845 /*
846  * Like _isa_bus_dmamap_load(), but for raw memory allocated with
847  * bus_dmamem_alloc().
848  */
849 int
_isa_bus_dmamap_load_raw(t,map,segs,nsegs,size,flags)850 _isa_bus_dmamap_load_raw(t, map, segs, nsegs, size, flags)
851 	bus_dma_tag_t t;
852 	bus_dmamap_t map;
853 	bus_dma_segment_t *segs;
854 	int nsegs;
855 	bus_size_t size;
856 	int flags;
857 {
858 
859 	panic("_isa_bus_dmamap_load_raw: not implemented");
860 }
861 
862 /*
863  * Unload an ISA DMA map.
864  */
865 void
_isa_bus_dmamap_unload(t,map)866 _isa_bus_dmamap_unload(t, map)
867 	bus_dma_tag_t t;
868 	bus_dmamap_t map;
869 {
870 	struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
871 
872 	/*
873 	 * If we have bounce pages, free them, unless they're
874 	 * reserved for our exclusive use.
875 	 */
876 	if ((cookie->id_flags & ID_HAS_BOUNCE) &&
877 	    (map->_dm_flags & BUS_DMA_ALLOCNOW) == 0)
878 		_isa_dma_free_bouncebuf(t, map);
879 
880 	cookie->id_flags &= ~ID_IS_BOUNCING;
881 
882 	/*
883 	 * Do the generic bits of the unload.
884 	 */
885 	_bus_dmamap_unload(t, map);
886 }
887 
888 /*
889  * Synchronize an ISA DMA map.
890  */
891 void
_isa_bus_dmamap_sync(t,map,offset,len,op)892 _isa_bus_dmamap_sync(t, map, offset, len, op)
893 	bus_dma_tag_t t;
894 	bus_dmamap_t map;
895 	bus_addr_t offset;
896 	bus_size_t len;
897 	int op;
898 {
899 	struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
900 
901 #ifdef DEBUG
902 	if ((op & (BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD)) != 0) {
903 		if (offset >= map->dm_mapsize)
904 			panic("_isa_bus_dmamap_sync: bad offset");
905 		if (len == 0 || (offset + len) > map->dm_mapsize)
906 			panic("_isa_bus_dmamap_sync: bad length");
907 	}
908 #endif
909 
910 	switch (op) {
911 	case BUS_DMASYNC_PREREAD:
912 		/*
913 		 * Nothing to do for pre-read.
914 		 */
915 		break;
916 
917 	case BUS_DMASYNC_PREWRITE:
918 		/*
919 		 * If we're bouncing this transfer, copy the
920 		 * caller's buffer to the bounce buffer.
921 		 */
922 		if (cookie->id_flags & ID_IS_BOUNCING)
923 			bcopy(cookie->id_origbuf + offset,
924 			    cookie->id_bouncebuf + offset,
925 			    len);
926 		break;
927 
928 	case BUS_DMASYNC_POSTREAD:
929 		/*
930 		 * If we're bouncing this transfer, copy the
931 		 * bounce buffer to the caller's buffer.
932 		 */
933 		if (cookie->id_flags & ID_IS_BOUNCING)
934 			bcopy(cookie->id_bouncebuf + offset,
935 			    cookie->id_origbuf + offset,
936 			    len);
937 		break;
938 
939 	case BUS_DMASYNC_POSTWRITE:
940 		/*
941 		 * Nothing to do for post-write.
942 		 */
943 		break;
944 	}
945 
946 #if 0
947 	/* This is a noop anyhow, so why bother calling it? */
948 	_bus_dmamap_sync(t, map, op);
949 #endif
950 }
951 
952 /*
953  * Allocate memory safe for ISA DMA.
954  */
955 int
_isa_bus_dmamem_alloc(t,size,alignment,boundary,segs,nsegs,rsegs,flags)956 _isa_bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags)
957 	bus_dma_tag_t t;
958 	bus_size_t size, alignment, boundary;
959 	bus_dma_segment_t *segs;
960 	int nsegs;
961 	int *rsegs;
962 	int flags;
963 {
964 	paddr_t high;
965 
966 	if (avail_end > ISA_DMA_BOUNCE_THRESHOLD)
967 		high = trunc_page(ISA_DMA_BOUNCE_THRESHOLD);
968 	else
969 		high = trunc_page(avail_end);
970 
971 	return (_bus_dmamem_alloc_range(t, size, alignment, boundary,
972 	    segs, nsegs, rsegs, flags, 0, high));
973 }
974 
975 /*
976  * Free memory safe for ISA DMA.
977  */
978 void
_isa_bus_dmamem_free(t,segs,nsegs)979 _isa_bus_dmamem_free(t, segs, nsegs)
980 	bus_dma_tag_t t;
981 	bus_dma_segment_t *segs;
982 	int nsegs;
983 {
984 
985 	_bus_dmamem_free(t, segs, nsegs);
986 }
987 
988 /*
989  * Map ISA DMA-safe memory into kernel virtual address space.
990  */
991 int
_isa_bus_dmamem_map(t,segs,nsegs,size,kvap,flags)992 _isa_bus_dmamem_map(t, segs, nsegs, size, kvap, flags)
993 	bus_dma_tag_t t;
994 	bus_dma_segment_t *segs;
995 	int nsegs;
996 	size_t size;
997 	caddr_t *kvap;
998 	int flags;
999 {
1000 
1001 	return (_bus_dmamem_map(t, segs, nsegs, size, kvap, flags));
1002 }
1003 
1004 /*
1005  * Unmap ISA DMA-safe memory from kernel virtual address space.
1006  */
1007 void
_isa_bus_dmamem_unmap(t,kva,size)1008 _isa_bus_dmamem_unmap(t, kva, size)
1009 	bus_dma_tag_t t;
1010 	caddr_t kva;
1011 	size_t size;
1012 {
1013 
1014 	_bus_dmamem_unmap(t, kva, size);
1015 }
1016 
1017 /*
1018  * mmap(2) ISA DMA-safe memory.
1019  */
1020 paddr_t
_isa_bus_dmamem_mmap(t,segs,nsegs,off,prot,flags)1021 _isa_bus_dmamem_mmap(t, segs, nsegs, off, prot, flags)
1022 	bus_dma_tag_t t;
1023 	bus_dma_segment_t *segs;
1024 	int nsegs;
1025 	off_t off;
1026 	int prot, flags;
1027 {
1028 
1029 	return (_bus_dmamem_mmap(t, segs, nsegs, off, prot, flags));
1030 }
1031 
1032 /**********************************************************************
1033  * ISA DMA utility functions
1034  **********************************************************************/
1035 
1036 /*
1037  * Return 0 if all pages in the passed buffer lie within the DMA'able
1038  * range RAM.
1039  */
1040 int
_isa_dma_check_buffer(buf,buflen,segcnt,boundary,p)1041 _isa_dma_check_buffer(buf, buflen, segcnt, boundary, p)
1042 	void *buf;
1043 	bus_size_t buflen;
1044 	int segcnt;
1045 	bus_size_t boundary;
1046 	struct proc *p;
1047 {
1048 	vaddr_t vaddr = (vaddr_t)buf;
1049 	vaddr_t endva;
1050 	paddr_t pa, lastpa;
1051 	u_long pagemask = ~(boundary - 1);
1052 	pmap_t pmap;
1053 	int nsegs;
1054 
1055 	endva = round_page(vaddr + buflen);
1056 
1057 	nsegs = 1;
1058 	lastpa = 0;
1059 
1060 	if (p != NULL)
1061 		pmap = p->p_vmspace->vm_map.pmap;
1062 	else
1063 		pmap = pmap_kernel();
1064 
1065 	for (; vaddr < endva; vaddr += NBPG) {
1066 		/*
1067 		 * Get physical address for this segment.
1068 		 */
1069 		pmap_extract(pmap, (vaddr_t)vaddr, &pa);
1070 		pa = trunc_page(pa);
1071 
1072 		/*
1073 		 * Is it below the DMA'able threshold?
1074 		 */
1075 		if (pa > ISA_DMA_BOUNCE_THRESHOLD)
1076 			return (EINVAL);
1077 
1078 		if (lastpa) {
1079 			/*
1080 			 * Check excessive segment count.
1081 			 */
1082 			if (lastpa + NBPG != pa) {
1083 				if (++nsegs > segcnt)
1084 					return (EFBIG);
1085 			}
1086 
1087 			/*
1088 			 * Check boundary restriction.
1089 			 */
1090 			if (boundary) {
1091 				if ((lastpa ^ pa) & pagemask)
1092 					return (EINVAL);
1093 			}
1094 		}
1095 		lastpa = pa;
1096 	}
1097 
1098 	return (0);
1099 }
1100 
1101 int
_isa_dma_alloc_bouncebuf(t,map,size,flags)1102 _isa_dma_alloc_bouncebuf(t, map, size, flags)
1103 	bus_dma_tag_t t;
1104 	bus_dmamap_t map;
1105 	bus_size_t size;
1106 	int flags;
1107 {
1108 	struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
1109 	int error = 0;
1110 
1111 	cookie->id_bouncebuflen = round_page(size);
1112 	error = _isa_bus_dmamem_alloc(t, cookie->id_bouncebuflen,
1113 	    NBPG, map->_dm_boundary, cookie->id_bouncesegs,
1114 	    map->_dm_segcnt, &cookie->id_nbouncesegs, flags);
1115 	if (error)
1116 		goto out;
1117 	error = _isa_bus_dmamem_map(t, cookie->id_bouncesegs,
1118 	    cookie->id_nbouncesegs, cookie->id_bouncebuflen,
1119 	    (caddr_t *)&cookie->id_bouncebuf, flags);
1120 
1121  out:
1122 	if (error) {
1123 		_isa_bus_dmamem_free(t, cookie->id_bouncesegs,
1124 		    cookie->id_nbouncesegs);
1125 		cookie->id_bouncebuflen = 0;
1126 		cookie->id_nbouncesegs = 0;
1127 	} else {
1128 		cookie->id_flags |= ID_HAS_BOUNCE;
1129 		STAT_INCR(isa_dma_stats_nbouncebufs);
1130 	}
1131 
1132 	return (error);
1133 }
1134 
1135 void
_isa_dma_free_bouncebuf(t,map)1136 _isa_dma_free_bouncebuf(t, map)
1137 	bus_dma_tag_t t;
1138 	bus_dmamap_t map;
1139 {
1140 	struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
1141 
1142 	STAT_DECR(isa_dma_stats_nbouncebufs);
1143 
1144 	_isa_bus_dmamem_unmap(t, cookie->id_bouncebuf,
1145 	    cookie->id_bouncebuflen);
1146 	_isa_bus_dmamem_free(t, cookie->id_bouncesegs,
1147 	    cookie->id_nbouncesegs);
1148 	cookie->id_bouncebuflen = 0;
1149 	cookie->id_nbouncesegs = 0;
1150 	cookie->id_flags &= ~ID_HAS_BOUNCE;
1151 }
1152 #endif /* NISADMA > 0 */
1153