isabus.c revision 1.25 1 /* $NetBSD: isabus.c,v 1.25 2003/08/07 16:26:50 agc Exp $ */
2 /* $OpenBSD: isabus.c,v 1.15 1998/03/16 09:38:46 pefo Exp $ */
3 /* NetBSD: isa.c,v 1.33 1995/06/28 04:30:51 cgd Exp */
4
5 /*-
6 * Copyright (c) 1990 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * William Jolitz and Don Ahn.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)isa.c 7.2 (Berkeley) 5/12/91
37 */
38 /*-
39 * Copyright (c) 1995 Per Fogelstrom
40 * Copyright (c) 1993, 1994 Charles M. Hannum.
41 *
42 * This code is derived from software contributed to Berkeley by
43 * William Jolitz and Don Ahn.
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. All advertising materials mentioning features or use of this software
54 * must display the following acknowledgement:
55 * This product includes software developed by the University of
56 * California, Berkeley and its contributors.
57 * 4. Neither the name of the University nor the names of its contributors
58 * may be used to endorse or promote products derived from this software
59 * without specific prior written permission.
60 *
61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71 * SUCH DAMAGE.
72 *
73 * @(#)isa.c 7.2 (Berkeley) 5/12/91
74 */
75 /*
76 * Mach Operating System
77 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
78 * All Rights Reserved.
79 *
80 * Permission to use, copy, modify and distribute this software and its
81 * documentation is hereby granted, provided that both the copyright
82 * notice and this permission notice appear in all copies of the
83 * software, derivative works or modified versions, and any portions
84 * thereof, and that both notices appear in supporting documentation.
85 *
86 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
87 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
88 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
89 *
90 * Carnegie Mellon requests users of this software to return to
91 *
92 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
93 * School of Computer Science
94 * Carnegie Mellon University
95 * Pittsburgh PA 15213-3890
96 *
97 * any improvements or extensions that they make and grant Carnegie Mellon
98 * the rights to redistribute these changes.
99 */
100 /*
101 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
102
103 All Rights Reserved
104
105 Permission to use, copy, modify, and distribute this software and
106 its documentation for any purpose and without fee is hereby
107 granted, provided that the above copyright notice appears in all
108 copies and that both the copyright notice and this permission notice
109 appear in supporting documentation, and that the name of Intel
110 not be used in advertising or publicity pertaining to distribution
111 of the software without specific, written prior permission.
112
113 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
114 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
115 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
116 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
117 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
118 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
119 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
120 */
121
122 #include <sys/cdefs.h>
123 __KERNEL_RCSID(0, "$NetBSD: isabus.c,v 1.25 2003/08/07 16:26:50 agc Exp $");
124
125 #include <sys/param.h>
126 #include <sys/proc.h>
127 #include <sys/user.h>
128 #include <sys/systm.h>
129 #include <sys/callout.h>
130 #include <sys/time.h>
131 #include <sys/kernel.h>
132 #include <sys/device.h>
133 #include <sys/malloc.h>
134 #include <sys/extent.h>
135
136 #include <uvm/uvm_extern.h>
137
138 #include <machine/cpu.h>
139 #include <machine/pio.h>
140 #include <machine/autoconf.h>
141 #include <machine/intr.h>
142
143 #include <dev/ic/i8253reg.h>
144 #include <dev/isa/isareg.h>
145 #include <dev/isa/isavar.h>
146 #include <arc/isa/isabrvar.h>
147 #include <arc/isa/spkrreg.h>
148
149 static int beeping;
150 static struct callout sysbeep_ch = CALLOUT_INITIALIZER;
151
152 static long isa_mem_ex_storage[EXTENT_FIXED_STORAGE_SIZE(16) / sizeof(long)];
153 static long isa_io_ex_storage[EXTENT_FIXED_STORAGE_SIZE(16) / sizeof(long)];
154
155 #define IRQ_SLAVE 2
156
157 /* Definition of the driver for autoconfig. */
158 int isabrprint(void *, const char *);
159
160 extern struct arc_bus_space arc_bus_io, arc_bus_mem;
161
162 void isabr_attach_hook __P((struct device *, struct device *,
163 struct isabus_attach_args *));
164 const struct evcnt *isabr_intr_evcnt __P((isa_chipset_tag_t, int));
165 void *isabr_intr_establish __P((isa_chipset_tag_t, int, int, int,
166 int (*)(void *), void *));
167 void isabr_intr_disestablish __P((isa_chipset_tag_t, void*));
168 int isabr_iointr __P((unsigned int, struct clockframe *));
169 void isabr_initicu __P((void));
170 void intr_calculatemasks __P((void));
171 int fakeintr __P((void *a));
172
173 struct isabr_config *isabr_conf = NULL;
174 u_int32_t imask[_IPL_N]; /* XXX */
175
176 void
177 isabrattach(sc)
178 struct isabr_softc *sc;
179 {
180 struct isabus_attach_args iba;
181
182 if (isabr_conf == NULL)
183 panic("isabr_conf isn't initialized");
184
185 printf("\n");
186
187 /* Initialize interrupt controller */
188 isabr_initicu();
189
190 /*XXX we may remove the abus part of the softc struct... */
191 sc->sc_bus.ab_dv = (struct device *)sc;
192 sc->sc_bus.ab_type = BUS_ISABR;
193
194 sc->arc_isa_cs.ic_attach_hook = isabr_attach_hook;
195 sc->arc_isa_cs.ic_intr_evcnt = isabr_intr_evcnt;
196 sc->arc_isa_cs.ic_intr_establish = isabr_intr_establish;
197 sc->arc_isa_cs.ic_intr_disestablish = isabr_intr_disestablish;
198
199 arc_bus_space_init_extent(&arc_bus_mem, (caddr_t)isa_mem_ex_storage,
200 sizeof(isa_mem_ex_storage));
201 arc_bus_space_init_extent(&arc_bus_io, (caddr_t)isa_io_ex_storage,
202 sizeof(isa_io_ex_storage));
203
204 iba.iba_busname = "isa";
205 iba.iba_iot = &arc_bus_io;
206 iba.iba_memt = &arc_bus_mem;
207 iba.iba_dmat = &sc->sc_dmat;
208 iba.iba_ic = &sc->arc_isa_cs;
209 config_found(&sc->sc_dev, &iba, isabrprint);
210 }
211
212 int
213 isabrprint(aux, pnp)
214 void *aux;
215 const char *pnp;
216 {
217 struct confargs *ca = aux;
218
219 if (pnp)
220 aprint_normal("%s at %s", ca->ca_name, pnp);
221 aprint_verbose(" isa_io_base 0x%lx isa_mem_base 0x%lx",
222 arc_bus_io.bs_vbase, arc_bus_mem.bs_vbase);
223 return (UNCONF);
224 }
225
226
227 /*
228 * Interrupt system driver code
229 * ============================
230 */
231 #define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
232
233 int imen;
234 int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
235 struct intrhand *intrhand[ICU_LEN];
236
237 int fakeintr(a)
238 void *a;
239 {
240 return 0;
241 }
242
243 /*
244 * Recalculate the interrupt masks from scratch.
245 * We could code special registry and deregistry versions of this function that
246 * would be faster, but the code would be nastier, and we don't expect this to
247 * happen very much anyway.
248 */
249 void
250 intr_calculatemasks()
251 {
252 int irq, level;
253 struct intrhand *q;
254
255 /* First, figure out which levels each IRQ uses. */
256 for (irq = 0; irq < ICU_LEN; irq++) {
257 int levels = 0;
258 for (q = intrhand[irq]; q; q = q->ih_next)
259 levels |= 1 << q->ih_level;
260 intrlevel[irq] = levels;
261 }
262
263 /* Then figure out which IRQs use each level. */
264 for (level = 0; level < _IPL_N; level++) {
265 int irqs = 0;
266 for (irq = 0; irq < ICU_LEN; irq++)
267 if (intrlevel[irq] & (1 << level))
268 irqs |= 1 << irq;
269 imask[level] = irqs;
270 }
271
272 imask[IPL_NONE] = 0;
273
274 imask[IPL_SOFT] |= imask[IPL_NONE];
275 imask[IPL_SOFTCLOCK] |= imask[IPL_SOFT];
276 imask[IPL_SOFTNET] |= imask[IPL_SOFTCLOCK];
277 imask[IPL_SOFTSERIAL] |= imask[IPL_SOFTNET];
278
279 /*
280 * Enforce a hierarchy that gives slow devices a better chance at not
281 * dropping data.
282 */
283 imask[IPL_BIO] |= imask[IPL_SOFTSERIAL];
284 imask[IPL_NET] |= imask[IPL_BIO];
285 imask[IPL_TTY] |= imask[IPL_NET];
286
287 /*
288 * Since run queues may be manipulated by both the statclock and tty,
289 * network, and diskdrivers, clock > tty.
290 */
291 imask[IPL_CLOCK] |= imask[IPL_TTY];
292 imask[IPL_STATCLOCK] |= imask[IPL_CLOCK];
293
294 /*
295 * IPL_HIGH must block everything that can manipulate a run queue.
296 */
297 imask[IPL_HIGH] |= imask[IPL_STATCLOCK];
298
299 /* And eventually calculate the complete masks. */
300 for (irq = 0; irq < ICU_LEN; irq++) {
301 int irqs = 1 << irq;
302 for (q = intrhand[irq]; q; q = q->ih_next)
303 irqs |= imask[q->ih_level];
304 intrmask[irq] = irqs;
305 }
306
307 /* Lastly, determine which IRQs are actually in use. */
308 {
309 int irqs = 0;
310 for (irq = 0; irq < ICU_LEN; irq++)
311 if (intrhand[irq])
312 irqs |= 1 << irq;
313 if (irqs >= 0x100) /* any IRQs >= 8 in use */
314 irqs |= 1 << IRQ_SLAVE;
315 imen = ~irqs;
316 isa_outb(IO_ICU1 + 1, imen);
317 isa_outb(IO_ICU2 + 1, imen >> 8);
318 }
319 }
320
321 void
322 isabr_attach_hook(parent, self, iba)
323 struct device *parent, *self;
324 struct isabus_attach_args *iba;
325 {
326
327 /* Nothing to do. */
328 }
329
330 const struct evcnt *
331 isabr_intr_evcnt(ic, irq)
332 isa_chipset_tag_t ic;
333 int irq;
334 {
335
336 /* XXX for now, no evcnt parent reported */
337 return NULL;
338 }
339
340 /*
341 * Establish a ISA bus interrupt.
342 */
343 void *
344 isabr_intr_establish(ic, irq, type, level, ih_fun, ih_arg)
345 isa_chipset_tag_t ic;
346 int irq;
347 int type;
348 int level;
349 int (*ih_fun) __P((void *));
350 void *ih_arg;
351 {
352 struct intrhand **p, *q, *ih;
353 static struct intrhand fakehand = {NULL, fakeintr};
354
355 /* no point in sleeping unless someone can free memory. */
356 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
357 if (ih == NULL)
358 panic("isa_intr_establish: can't malloc handler info");
359
360 if (!LEGAL_IRQ(irq) || type == IST_NONE)
361 panic("intr_establish: bogus irq or type");
362
363 switch (intrtype[irq]) {
364 case IST_NONE:
365 intrtype[irq] = type;
366 break;
367 case IST_EDGE:
368 case IST_LEVEL:
369 if (type == intrtype[irq])
370 break;
371 case IST_PULSE:
372 if (type != IST_NONE)
373 panic("intr_establish: can't share %s with %s",
374 isa_intr_typename(intrtype[irq]),
375 isa_intr_typename(type));
376 break;
377 }
378
379 /*
380 * Figure out where to put the handler.
381 * This is O(N^2), but we want to preserve the order, and N is
382 * generally small.
383 */
384 for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
385 ;
386
387 /*
388 * Actually install a fake handler momentarily, since we might be doing
389 * this with interrupts enabled and don't want the real routine called
390 * until masking is set up.
391 */
392 fakehand.ih_level = level;
393 *p = &fakehand;
394
395 intr_calculatemasks();
396
397 /*
398 * Poke the real handler in now.
399 */
400 ih->ih_fun = ih_fun;
401 ih->ih_arg = ih_arg;
402 ih->ih_count = 0;
403 ih->ih_next = NULL;
404 ih->ih_level = level;
405 ih->ih_irq = irq;
406 ih->ih_what = ""; /* XXX - should be eliminated */
407 *p = ih;
408
409 return (ih);
410 }
411
412 void
413 isabr_intr_disestablish(ic, arg)
414 isa_chipset_tag_t ic;
415 void *arg;
416 {
417
418 }
419
420 /*
421 * Process an interrupt from the ISA bus.
422 */
423 int
424 isabr_iointr(mask, cf)
425 unsigned mask;
426 struct clockframe *cf;
427 {
428 struct intrhand *ih;
429 int isa_vector;
430 int o_imen;
431
432 isa_vector = (*isabr_conf->ic_intr_status)();
433 if (isa_vector < 0)
434 return (~0);
435
436 o_imen = imen;
437 imen |= 1 << (isa_vector & (ICU_LEN - 1));
438 if(isa_vector & 0x08) {
439 isa_inb(IO_ICU2 + 1);
440 isa_outb(IO_ICU2 + 1, imen >> 8);
441 isa_outb(IO_ICU2, 0x60 + (isa_vector & 7));
442 isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE);
443 }
444 else {
445 isa_inb(IO_ICU1 + 1);
446 isa_outb(IO_ICU1 + 1, imen);
447 isa_outb(IO_ICU1, 0x60 + isa_vector);
448 }
449 ih = intrhand[isa_vector];
450 if(isa_vector == 0) { /* Clock */ /*XXX*/
451 (*ih->ih_fun)(cf);
452 ih = ih->ih_next;
453 }
454 while(ih) {
455 (*ih->ih_fun)(ih->ih_arg);
456 ih = ih->ih_next;
457 }
458 imen = o_imen;
459 isa_inb(IO_ICU1 + 1);
460 isa_inb(IO_ICU2 + 1);
461 isa_outb(IO_ICU1 + 1, imen);
462 isa_outb(IO_ICU2 + 1, imen >> 8);
463
464 return(~0); /* Dont reenable */
465 }
466
467
468 /*
469 * Initialize the Interrupt controller logic.
470 */
471 void
472 isabr_initicu()
473 {
474
475 int i;
476
477 for (i = 0; i < ICU_LEN; i++) {
478 switch (i) {
479 case 2:
480 case 8:
481 intrtype[i] = IST_EDGE;
482 break;
483 default:
484 intrtype[i] = IST_NONE;
485 break;
486 }
487 }
488
489 isa_outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
490 isa_outb(IO_ICU1+1, 0); /* starting at this vector index */
491 isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */
492 isa_outb(IO_ICU1+1, 1); /* 8086 mode */
493 isa_outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
494 isa_outb(IO_ICU1, 0x68); /* special mask mode (if available) */
495 isa_outb(IO_ICU1, 0x0a); /* Read IRR by default. */
496 #ifdef REORDER_IRQ
497 isa_outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
498 #endif
499
500 isa_outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
501 isa_outb(IO_ICU2+1, 8); /* staring at this vector index */
502 isa_outb(IO_ICU2+1, IRQ_SLAVE);
503 isa_outb(IO_ICU2+1, 1); /* 8086 mode */
504 isa_outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
505 isa_outb(IO_ICU2, 0x68); /* special mask mode (if available) */
506 isa_outb(IO_ICU2, 0x0a); /* Read IRR by default. */
507 }
508
509
510 /*
511 * SPEAKER BEEPER...
512 */
513 void
514 sysbeepstop(arg)
515 void *arg;
516 {
517 int s;
518
519 /* disable counter 2 */
520 s = splhigh();
521 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
522 splx(s);
523 beeping = 0;
524 }
525
526 void
527 sysbeep(pitch, period)
528 int pitch, period;
529 {
530 static int last_pitch, last_period;
531 int s;
532
533 if (cold)
534 return; /* Can't beep yet. */
535
536 if (beeping)
537 callout_stop(&sysbeep_ch);
538 if (!beeping || last_pitch != pitch) {
539 s = splhigh();
540 isa_outb(IO_TIMER1 + TIMER_MODE,
541 TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
542 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
543 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
544 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);
545 splx(s);
546 }
547 last_pitch = pitch;
548 beeping = last_period = period;
549 callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
550 }
551
552 int
553 isa_intr_alloc(isa_chipset_tag_t c, int mask, int type, int *irq_p)
554 {
555 int irq;
556 int maybe_irq = -1;
557 int shared_depth = 0;
558 mask &= 0x8b28; /* choose from 3, 5, 8, 9, 11, 15 XXX */
559 for (irq = 0; mask != 0; mask >>= 1, irq++) {
560 if ((mask & 1) == 0)
561 continue;
562 if (intrtype[irq] == IST_NONE) {
563 *irq_p = irq;
564 return 0;
565 }
566 /* Level interrupts can be shared */
567 if (type == IST_LEVEL && intrtype[irq] == IST_LEVEL) {
568 struct intrhand *ih = intrhand[irq];
569 int depth;
570 if (maybe_irq == -1) {
571 maybe_irq = irq;
572 continue;
573 }
574 for (depth = 0; ih != NULL; ih = ih->ih_next)
575 depth++;
576 if (depth < shared_depth) {
577 maybe_irq = irq;
578 shared_depth = depth;
579 }
580 }
581 }
582 if (maybe_irq != -1) {
583 *irq_p = maybe_irq;
584 return 0;
585 }
586 return 1;
587 }
588