isabus.c revision 1.23 1 /* $NetBSD: isabus.c,v 1.23 2003/06/15 05:58:45 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 #include <sys/extent.h>
101
102 #include <uvm/uvm_extern.h>
103
104 #include <machine/cpu.h>
105 #include <machine/pio.h>
106 #include <machine/autoconf.h>
107 #include <machine/intr.h>
108
109 #include <dev/ic/i8253reg.h>
110 #include <dev/isa/isareg.h>
111 #include <dev/isa/isavar.h>
112 #include <arc/isa/isabrvar.h>
113 #include <arc/isa/spkrreg.h>
114
115 static int beeping;
116 static struct callout sysbeep_ch = CALLOUT_INITIALIZER;
117
118 static long isa_mem_ex_storage[EXTENT_FIXED_STORAGE_SIZE(16) / sizeof(long)];
119 static long isa_io_ex_storage[EXTENT_FIXED_STORAGE_SIZE(16) / sizeof(long)];
120
121 #define IRQ_SLAVE 2
122
123 /* Definition of the driver for autoconfig. */
124 int isabrprint(void *, const char *);
125
126 extern struct arc_bus_space arc_bus_io, arc_bus_mem;
127
128 void isabr_attach_hook __P((struct device *, struct device *,
129 struct isabus_attach_args *));
130 const struct evcnt *isabr_intr_evcnt __P((isa_chipset_tag_t, int));
131 void *isabr_intr_establish __P((isa_chipset_tag_t, int, int, int,
132 int (*)(void *), void *));
133 void isabr_intr_disestablish __P((isa_chipset_tag_t, void*));
134 int isabr_iointr __P((unsigned int, struct clockframe *));
135 void isabr_initicu __P((void));
136 void intr_calculatemasks __P((void));
137 int fakeintr __P((void *a));
138
139 struct isabr_config *isabr_conf = NULL;
140 u_int32_t imask[_IPL_N]; /* XXX */
141
142 void
143 isabrattach(sc)
144 struct isabr_softc *sc;
145 {
146 struct isabus_attach_args iba;
147
148 if (isabr_conf == NULL)
149 panic("isabr_conf isn't initialized");
150
151 printf("\n");
152
153 /* Initialize interrupt controller */
154 isabr_initicu();
155
156 /*XXX we may remove the abus part of the softc struct... */
157 sc->sc_bus.ab_dv = (struct device *)sc;
158 sc->sc_bus.ab_type = BUS_ISABR;
159
160 sc->arc_isa_cs.ic_attach_hook = isabr_attach_hook;
161 sc->arc_isa_cs.ic_intr_evcnt = isabr_intr_evcnt;
162 sc->arc_isa_cs.ic_intr_establish = isabr_intr_establish;
163 sc->arc_isa_cs.ic_intr_disestablish = isabr_intr_disestablish;
164
165 arc_bus_space_init_extent(&arc_bus_mem, (caddr_t)isa_mem_ex_storage,
166 sizeof(isa_mem_ex_storage));
167 arc_bus_space_init_extent(&arc_bus_io, (caddr_t)isa_io_ex_storage,
168 sizeof(isa_io_ex_storage));
169
170 iba.iba_busname = "isa";
171 iba.iba_iot = &arc_bus_io;
172 iba.iba_memt = &arc_bus_mem;
173 iba.iba_dmat = &sc->sc_dmat;
174 iba.iba_ic = &sc->arc_isa_cs;
175 config_found(&sc->sc_dev, &iba, isabrprint);
176 }
177
178 int
179 isabrprint(aux, pnp)
180 void *aux;
181 const char *pnp;
182 {
183 struct confargs *ca = aux;
184
185 if (pnp)
186 aprint_normal("%s at %s", ca->ca_name, pnp);
187 aprint_verbose(" isa_io_base 0x%lx isa_mem_base 0x%lx",
188 arc_bus_io.bs_vbase, arc_bus_mem.bs_vbase);
189 return (UNCONF);
190 }
191
192
193 /*
194 * Interrupt system driver code
195 * ============================
196 */
197 #define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
198
199 int imen;
200 int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
201 struct intrhand *intrhand[ICU_LEN];
202
203 int fakeintr(a)
204 void *a;
205 {
206 return 0;
207 }
208
209 /*
210 * Recalculate the interrupt masks from scratch.
211 * We could code special registry and deregistry versions of this function that
212 * would be faster, but the code would be nastier, and we don't expect this to
213 * happen very much anyway.
214 */
215 void
216 intr_calculatemasks()
217 {
218 int irq, level;
219 struct intrhand *q;
220
221 /* First, figure out which levels each IRQ uses. */
222 for (irq = 0; irq < ICU_LEN; irq++) {
223 int levels = 0;
224 for (q = intrhand[irq]; q; q = q->ih_next)
225 levels |= 1 << q->ih_level;
226 intrlevel[irq] = levels;
227 }
228
229 /* Then figure out which IRQs use each level. */
230 for (level = 0; level < _IPL_N; level++) {
231 int irqs = 0;
232 for (irq = 0; irq < ICU_LEN; irq++)
233 if (intrlevel[irq] & (1 << level))
234 irqs |= 1 << irq;
235 imask[level] = irqs;
236 }
237
238 imask[IPL_NONE] = 0;
239
240 imask[IPL_SOFT] |= imask[IPL_NONE];
241 imask[IPL_SOFTCLOCK] |= imask[IPL_SOFT];
242 imask[IPL_SOFTNET] |= imask[IPL_SOFTCLOCK];
243 imask[IPL_SOFTSERIAL] |= imask[IPL_SOFTNET];
244
245 /*
246 * Enforce a hierarchy that gives slow devices a better chance at not
247 * dropping data.
248 */
249 imask[IPL_BIO] |= imask[IPL_SOFTSERIAL];
250 imask[IPL_NET] |= imask[IPL_BIO];
251 imask[IPL_TTY] |= imask[IPL_NET];
252
253 /*
254 * Since run queues may be manipulated by both the statclock and tty,
255 * network, and diskdrivers, clock > tty.
256 */
257 imask[IPL_CLOCK] |= imask[IPL_TTY];
258 imask[IPL_STATCLOCK] |= imask[IPL_CLOCK];
259
260 /*
261 * IPL_HIGH must block everything that can manipulate a run queue.
262 */
263 imask[IPL_HIGH] |= imask[IPL_STATCLOCK];
264
265 /* And eventually calculate the complete masks. */
266 for (irq = 0; irq < ICU_LEN; irq++) {
267 int irqs = 1 << irq;
268 for (q = intrhand[irq]; q; q = q->ih_next)
269 irqs |= imask[q->ih_level];
270 intrmask[irq] = irqs;
271 }
272
273 /* Lastly, determine which IRQs are actually in use. */
274 {
275 int irqs = 0;
276 for (irq = 0; irq < ICU_LEN; irq++)
277 if (intrhand[irq])
278 irqs |= 1 << irq;
279 if (irqs >= 0x100) /* any IRQs >= 8 in use */
280 irqs |= 1 << IRQ_SLAVE;
281 imen = ~irqs;
282 isa_outb(IO_ICU1 + 1, imen);
283 isa_outb(IO_ICU2 + 1, imen >> 8);
284 }
285 }
286
287 void
288 isabr_attach_hook(parent, self, iba)
289 struct device *parent, *self;
290 struct isabus_attach_args *iba;
291 {
292
293 /* Nothing to do. */
294 }
295
296 const struct evcnt *
297 isabr_intr_evcnt(ic, irq)
298 isa_chipset_tag_t ic;
299 int irq;
300 {
301
302 /* XXX for now, no evcnt parent reported */
303 return NULL;
304 }
305
306 /*
307 * Establish a ISA bus interrupt.
308 */
309 void *
310 isabr_intr_establish(ic, irq, type, level, ih_fun, ih_arg)
311 isa_chipset_tag_t ic;
312 int irq;
313 int type;
314 int level;
315 int (*ih_fun) __P((void *));
316 void *ih_arg;
317 {
318 struct intrhand **p, *q, *ih;
319 static struct intrhand fakehand = {NULL, fakeintr};
320
321 /* no point in sleeping unless someone can free memory. */
322 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
323 if (ih == NULL)
324 panic("isa_intr_establish: can't malloc handler info");
325
326 if (!LEGAL_IRQ(irq) || type == IST_NONE)
327 panic("intr_establish: bogus irq or type");
328
329 switch (intrtype[irq]) {
330 case IST_NONE:
331 intrtype[irq] = type;
332 break;
333 case IST_EDGE:
334 case IST_LEVEL:
335 if (type == intrtype[irq])
336 break;
337 case IST_PULSE:
338 if (type != IST_NONE)
339 panic("intr_establish: can't share %s with %s",
340 isa_intr_typename(intrtype[irq]),
341 isa_intr_typename(type));
342 break;
343 }
344
345 /*
346 * Figure out where to put the handler.
347 * This is O(N^2), but we want to preserve the order, and N is
348 * generally small.
349 */
350 for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
351 ;
352
353 /*
354 * Actually install a fake handler momentarily, since we might be doing
355 * this with interrupts enabled and don't want the real routine called
356 * until masking is set up.
357 */
358 fakehand.ih_level = level;
359 *p = &fakehand;
360
361 intr_calculatemasks();
362
363 /*
364 * Poke the real handler in now.
365 */
366 ih->ih_fun = ih_fun;
367 ih->ih_arg = ih_arg;
368 ih->ih_count = 0;
369 ih->ih_next = NULL;
370 ih->ih_level = level;
371 ih->ih_irq = irq;
372 ih->ih_what = ""; /* XXX - should be eliminated */
373 *p = ih;
374
375 return (ih);
376 }
377
378 void
379 isabr_intr_disestablish(ic, arg)
380 isa_chipset_tag_t ic;
381 void *arg;
382 {
383
384 }
385
386 /*
387 * Process an interrupt from the ISA bus.
388 */
389 int
390 isabr_iointr(mask, cf)
391 unsigned mask;
392 struct clockframe *cf;
393 {
394 struct intrhand *ih;
395 int isa_vector;
396 int o_imen;
397
398 isa_vector = (*isabr_conf->ic_intr_status)();
399 if (isa_vector < 0)
400 return (~0);
401
402 o_imen = imen;
403 imen |= 1 << (isa_vector & (ICU_LEN - 1));
404 if(isa_vector & 0x08) {
405 isa_inb(IO_ICU2 + 1);
406 isa_outb(IO_ICU2 + 1, imen >> 8);
407 isa_outb(IO_ICU2, 0x60 + (isa_vector & 7));
408 isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE);
409 }
410 else {
411 isa_inb(IO_ICU1 + 1);
412 isa_outb(IO_ICU1 + 1, imen);
413 isa_outb(IO_ICU1, 0x60 + isa_vector);
414 }
415 ih = intrhand[isa_vector];
416 if(isa_vector == 0) { /* Clock */ /*XXX*/
417 (*ih->ih_fun)(cf);
418 ih = ih->ih_next;
419 }
420 while(ih) {
421 (*ih->ih_fun)(ih->ih_arg);
422 ih = ih->ih_next;
423 }
424 imen = o_imen;
425 isa_inb(IO_ICU1 + 1);
426 isa_inb(IO_ICU2 + 1);
427 isa_outb(IO_ICU1 + 1, imen);
428 isa_outb(IO_ICU2 + 1, imen >> 8);
429
430 return(~0); /* Dont reenable */
431 }
432
433
434 /*
435 * Initialize the Interrupt controller logic.
436 */
437 void
438 isabr_initicu()
439 {
440
441 int i;
442
443 for (i = 0; i < ICU_LEN; i++) {
444 switch (i) {
445 case 2:
446 case 8:
447 intrtype[i] = IST_EDGE;
448 break;
449 default:
450 intrtype[i] = IST_NONE;
451 break;
452 }
453 }
454
455 isa_outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
456 isa_outb(IO_ICU1+1, 0); /* starting at this vector index */
457 isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */
458 isa_outb(IO_ICU1+1, 1); /* 8086 mode */
459 isa_outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
460 isa_outb(IO_ICU1, 0x68); /* special mask mode (if available) */
461 isa_outb(IO_ICU1, 0x0a); /* Read IRR by default. */
462 #ifdef REORDER_IRQ
463 isa_outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
464 #endif
465
466 isa_outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
467 isa_outb(IO_ICU2+1, 8); /* staring at this vector index */
468 isa_outb(IO_ICU2+1, IRQ_SLAVE);
469 isa_outb(IO_ICU2+1, 1); /* 8086 mode */
470 isa_outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
471 isa_outb(IO_ICU2, 0x68); /* special mask mode (if available) */
472 isa_outb(IO_ICU2, 0x0a); /* Read IRR by default. */
473 }
474
475
476 /*
477 * SPEAKER BEEPER...
478 */
479 void
480 sysbeepstop(arg)
481 void *arg;
482 {
483 int s;
484
485 /* disable counter 2 */
486 s = splhigh();
487 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
488 splx(s);
489 beeping = 0;
490 }
491
492 void
493 sysbeep(pitch, period)
494 int pitch, period;
495 {
496 static int last_pitch, last_period;
497 int s;
498
499 if (cold)
500 return; /* Can't beep yet. */
501
502 if (beeping)
503 callout_stop(&sysbeep_ch);
504 if (!beeping || last_pitch != pitch) {
505 s = splhigh();
506 isa_outb(IO_TIMER1 + TIMER_MODE,
507 TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
508 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
509 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
510 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);
511 splx(s);
512 }
513 last_pitch = pitch;
514 beeping = last_period = period;
515 callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
516 }
517
518 int
519 isa_intr_alloc(isa_chipset_tag_t c, int mask, int type, int *irq_p)
520 {
521 int irq;
522 int maybe_irq = -1;
523 int shared_depth = 0;
524 mask &= 0x8b28; /* choose from 3, 5, 8, 9, 11, 15 XXX */
525 for (irq = 0; mask != 0; mask >>= 1, irq++) {
526 if ((mask & 1) == 0)
527 continue;
528 if (intrtype[irq] == IST_NONE) {
529 *irq_p = irq;
530 return 0;
531 }
532 /* Level interrupts can be shared */
533 if (type == IST_LEVEL && intrtype[irq] == IST_LEVEL) {
534 struct intrhand *ih = intrhand[irq];
535 int depth;
536 if (maybe_irq == -1) {
537 maybe_irq = irq;
538 continue;
539 }
540 for (depth = 0; ih != NULL; ih = ih->ih_next)
541 depth++;
542 if (depth < shared_depth) {
543 maybe_irq = irq;
544 shared_depth = depth;
545 }
546 }
547 }
548 if (maybe_irq != -1) {
549 *irq_p = maybe_irq;
550 return 0;
551 }
552 return 1;
553 }
554