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