isabus.c revision 1.21 1 /* $NetBSD: isabus.c,v 1.21 2003/06/14 19:11:41 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_EDGE:
322 case IST_LEVEL:
323 if (type == intrtype[irq])
324 break;
325 case IST_PULSE:
326 if (type != IST_NONE)
327 panic("intr_establish: can't share %s with %s",
328 isa_intr_typename(intrtype[irq]),
329 isa_intr_typename(type));
330 break;
331 }
332
333 /*
334 * Figure out where to put the handler.
335 * This is O(N^2), but we want to preserve the order, and N is
336 * generally small.
337 */
338 for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
339 ;
340
341 /*
342 * Actually install a fake handler momentarily, since we might be doing
343 * this with interrupts enabled and don't want the real routine called
344 * until masking is set up.
345 */
346 fakehand.ih_level = level;
347 *p = &fakehand;
348
349 intr_calculatemasks();
350
351 /*
352 * Poke the real handler in now.
353 */
354 ih->ih_fun = ih_fun;
355 ih->ih_arg = ih_arg;
356 ih->ih_count = 0;
357 ih->ih_next = NULL;
358 ih->ih_level = level;
359 ih->ih_irq = irq;
360 ih->ih_what = ""; /* XXX - should be eliminated */
361 *p = ih;
362
363 return (ih);
364 }
365
366 void
367 isabr_intr_disestablish(ic, arg)
368 isa_chipset_tag_t ic;
369 void *arg;
370 {
371
372 }
373
374 /*
375 * Process an interrupt from the ISA bus.
376 */
377 int
378 isabr_iointr(mask, cf)
379 unsigned mask;
380 struct clockframe *cf;
381 {
382 struct intrhand *ih;
383 int isa_vector;
384 int o_imen;
385
386 isa_vector = (*isabr_conf->ic_intr_status)();
387 if (isa_vector < 0)
388 return (~0);
389
390 o_imen = imen;
391 imen |= 1 << (isa_vector & (ICU_LEN - 1));
392 if(isa_vector & 0x08) {
393 isa_inb(IO_ICU2 + 1);
394 isa_outb(IO_ICU2 + 1, imen >> 8);
395 isa_outb(IO_ICU2, 0x60 + (isa_vector & 7));
396 isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE);
397 }
398 else {
399 isa_inb(IO_ICU1 + 1);
400 isa_outb(IO_ICU1 + 1, imen);
401 isa_outb(IO_ICU1, 0x60 + isa_vector);
402 }
403 ih = intrhand[isa_vector];
404 if(isa_vector == 0) { /* Clock */ /*XXX*/
405 (*ih->ih_fun)(cf);
406 ih = ih->ih_next;
407 }
408 while(ih) {
409 (*ih->ih_fun)(ih->ih_arg);
410 ih = ih->ih_next;
411 }
412 imen = o_imen;
413 isa_inb(IO_ICU1 + 1);
414 isa_inb(IO_ICU2 + 1);
415 isa_outb(IO_ICU1 + 1, imen);
416 isa_outb(IO_ICU2 + 1, imen >> 8);
417
418 return(~0); /* Dont reenable */
419 }
420
421
422 /*
423 * Initialize the Interrupt controller logic.
424 */
425 void
426 isabr_initicu()
427 {
428
429 isa_outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
430 isa_outb(IO_ICU1+1, 0); /* starting at this vector index */
431 isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */
432 isa_outb(IO_ICU1+1, 1); /* 8086 mode */
433 isa_outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
434 isa_outb(IO_ICU1, 0x68); /* special mask mode (if available) */
435 isa_outb(IO_ICU1, 0x0a); /* Read IRR by default. */
436 #ifdef REORDER_IRQ
437 isa_outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
438 #endif
439
440 isa_outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
441 isa_outb(IO_ICU2+1, 8); /* staring at this vector index */
442 isa_outb(IO_ICU2+1, IRQ_SLAVE);
443 isa_outb(IO_ICU2+1, 1); /* 8086 mode */
444 isa_outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
445 isa_outb(IO_ICU2, 0x68); /* special mask mode (if available) */
446 isa_outb(IO_ICU2, 0x0a); /* Read IRR by default. */
447 }
448
449
450 /*
451 * SPEAKER BEEPER...
452 */
453 void
454 sysbeepstop(arg)
455 void *arg;
456 {
457 int s;
458
459 /* disable counter 2 */
460 s = splhigh();
461 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
462 splx(s);
463 beeping = 0;
464 }
465
466 void
467 sysbeep(pitch, period)
468 int pitch, period;
469 {
470 static int last_pitch, last_period;
471 int s;
472
473 if (cold)
474 return; /* Can't beep yet. */
475
476 if (beeping)
477 callout_stop(&sysbeep_ch);
478 if (!beeping || last_pitch != pitch) {
479 s = splhigh();
480 isa_outb(IO_TIMER1 + TIMER_MODE,
481 TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
482 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
483 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
484 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);
485 splx(s);
486 }
487 last_pitch = pitch;
488 beeping = last_period = period;
489 callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
490 }
491
492 int
493 isa_intr_alloc(isa_chipset_tag_t c, int mask, int type, int *irq_p)
494 {
495 int irq;
496 int maybe_irq = -1;
497 int shared_depth = 0;
498 mask &= 0x8b28; /* choose from 3, 5, 8, 9, 11, 15 XXX */
499 for (irq = 0; mask != 0; mask >>= 1, irq++) {
500 if ((mask & 1) == 0)
501 continue;
502 if (intrtype[irq] == IST_NONE) {
503 *irq_p = irq;
504 return 0;
505 }
506 /* Level interrupts can be shared */
507 if (type == IST_LEVEL && intrtype[irq] == IST_LEVEL) {
508 struct intrhand *ih = intrhand[irq];
509 int depth;
510 if (maybe_irq == -1) {
511 maybe_irq = irq;
512 continue;
513 }
514 for (depth = 0; ih != NULL; ih = ih->ih_next)
515 depth++;
516 if (depth < shared_depth) {
517 maybe_irq = irq;
518 shared_depth = depth;
519 }
520 }
521 }
522 if (maybe_irq != -1) {
523 *irq_p = maybe_irq;
524 return 0;
525 }
526 return 1;
527 }
528