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