Annotation of sys/arch/i386/i386/ioapic.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ioapic.c,v 1.14 2007/02/22 19:46:16 marco Exp $ */
2: /* $NetBSD: ioapic.c,v 1.7 2003/07/14 22:32:40 lukem Exp $ */
3:
4: /*-
5: * Copyright (c) 2000 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by RedBack Networks Inc.
10: *
11: * Author: Bill Sommerfeld
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
21: * 3. All advertising materials mentioning features or use of this software
22: * must display the following acknowledgement:
23: * This product includes software developed by the NetBSD
24: * Foundation, Inc. and its contributors.
25: * 4. Neither the name of The NetBSD Foundation nor the names of its
26: * contributors may be used to endorse or promote products derived
27: * from this software without specific prior written permission.
28: *
29: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39: * POSSIBILITY OF SUCH DAMAGE.
40: */
41:
42:
43: /*
44: * Copyright (c) 1999 Stefan Grefen
45: *
46: * Redistribution and use in source and binary forms, with or without
47: * modification, are permitted provided that the following conditions
48: * are met:
49: * 1. Redistributions of source code must retain the above copyright
50: * notice, this list of conditions and the following disclaimer.
51: * 2. Redistributions in binary form must reproduce the above copyright
52: * notice, this list of conditions and the following disclaimer in the
53: * documentation and/or other materials provided with the distribution.
54: * 3. All advertising materials mentioning features or use of this software
55: * must display the following acknowledgement:
56: * This product includes software developed by the NetBSD
57: * Foundation, Inc. and its contributors.
58: * 4. Neither the name of The NetBSD Foundation nor the names of its
59: * contributors may be used to endorse or promote products derived
60: * from this software without specific prior written permission.
61: *
62: * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
63: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE
66: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72: * SUCH DAMAGE.
73: */
74: #include <sys/param.h>
75: #include <sys/systm.h>
76: #include <sys/device.h>
77: #include <sys/malloc.h>
78:
79: #include <machine/bus.h>
80: #include <machine/psl.h>
81:
82: #include <uvm/uvm_extern.h>
83:
84: #include <machine/i82093reg.h>
85: #include <machine/i82093var.h>
86:
87: #include <machine/i82489reg.h>
88: #include <machine/i82489var.h>
89:
90: #include <machine/pmap.h>
91:
92: #include <machine/mpbiosvar.h>
93:
94: #include "isa.h"
95:
96: /*
97: * XXX locking
98: */
99:
100: int ioapic_match(struct device *, void *, void *);
101: void ioapic_attach(struct device *, struct device *, void *);
102:
103: /* XXX */
104: extern int bus_mem_add_mapping(bus_addr_t, bus_size_t, int,
105: bus_space_handle_t *);
106:
107: void apic_set_redir(struct ioapic_softc *, int);
108: void apic_vectorset(struct ioapic_softc *, int, int, int);
109:
110: void apic_stray(int);
111:
112: int apic_verbose = 0;
113:
114: int ioapic_bsp_id = 0;
115: int ioapic_cold = 1;
116:
117: struct ioapic_softc *ioapics; /* head of linked list */
118: int nioapics = 0; /* number attached */
119: static int ioapic_vecbase;
120:
121: void ioapic_set_id(struct ioapic_softc *);
122:
123: /*
124: * A bitmap telling what APIC IDs usable for I/O APICs are free.
125: * The size must be at least IOAPIC_ID_MAX bits (16).
126: */
127: u_int16_t ioapic_id_map = (1 << IOAPIC_ID_MAX) - 1;
128:
129: /*
130: * When we renumber I/O APICs we provide a mapping vector giving us the new
131: * ID out of the old BIOS supplied one. Each item must be able to hold IDs
132: * in [0, IOAPIC_ID_MAX << 1), since we use an extra bit to tell if the ID
133: * has actually been remapped.
134: */
135: u_int8_t ioapic_id_remap[IOAPIC_ID_MAX];
136:
137: /*
138: * Register read/write routines.
139: */
140: static __inline u_int32_t
141: ioapic_read(struct ioapic_softc *sc, int regid)
142: {
143: u_int32_t val;
144:
145: /*
146: * XXX lock apic
147: */
148: *(sc->sc_reg) = regid;
149: val = *sc->sc_data;
150:
151: return (val);
152:
153: }
154:
155: static __inline void
156: ioapic_write(struct ioapic_softc *sc, int regid, int val)
157: {
158: /*
159: * XXX lock apic
160: */
161: *(sc->sc_reg) = regid;
162: *(sc->sc_data) = val;
163: }
164:
165: struct ioapic_softc *
166: ioapic_find(int apicid)
167: {
168: struct ioapic_softc *sc;
169:
170: if (apicid == MPS_ALL_APICS) { /* XXX mpbios-specific */
171: /*
172: * XXX kludge for all-ioapics interrupt support
173: * on single ioapic systems
174: */
175: if (nioapics <= 1)
176: return (ioapics);
177: panic("unsupported: all-ioapics interrupt with >1 ioapic");
178: }
179:
180: for (sc = ioapics; sc != NULL; sc = sc->sc_next)
181: if (sc->sc_apicid == apicid)
182: return (sc);
183:
184: return (NULL);
185: }
186:
187: /*
188: * For the case the I/O APICs were configured using ACPI, there must
189: * be an option to match global ACPI interrupts with APICs.
190: */
191: struct ioapic_softc *
192: ioapic_find_bybase(int vec)
193: {
194: struct ioapic_softc *sc;
195:
196: for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
197: if (vec >= sc->sc_apic_vecbase &&
198: vec < (sc->sc_apic_vecbase + sc->sc_apic_sz))
199: return sc;
200: }
201:
202: return NULL;
203: }
204:
205: static __inline void
206: ioapic_add(struct ioapic_softc *sc)
207: {
208: sc->sc_next = ioapics;
209: ioapics = sc;
210: nioapics++;
211: }
212:
213: void
214: ioapic_print_redir(struct ioapic_softc *sc, char *why, int pin)
215: {
216: u_int32_t redirlo = ioapic_read(sc, IOAPIC_REDLO(pin));
217: u_int32_t redirhi = ioapic_read(sc, IOAPIC_REDHI(pin));
218:
219: apic_format_redir(sc->sc_dev.dv_xname, why, pin, redirhi, redirlo);
220: }
221:
222: struct cfattach ioapic_ca = {
223: sizeof(struct ioapic_softc), ioapic_match, ioapic_attach
224: };
225:
226: struct cfdriver ioapic_cd = {
227: NULL, "ioapic", DV_DULL /* XXX DV_CPU ? */
228: };
229:
230: int
231: ioapic_match(struct device *parent, void *matchv, void *aux)
232: {
233: struct cfdata *match = (struct cfdata *)matchv;
234: struct apic_attach_args * aaa = (struct apic_attach_args *)aux;
235:
236: if (strcmp(aaa->aaa_name, match->cf_driver->cd_name) == 0)
237: return (1);
238: return (0);
239: }
240:
241: /* Reprogram the APIC ID, and check that it actually got set. */
242: void
243: ioapic_set_id(struct ioapic_softc *sc) {
244: u_int8_t apic_id;
245:
246: ioapic_write(sc, IOAPIC_ID,
247: (ioapic_read(sc, IOAPIC_ID) & ~IOAPIC_ID_MASK) |
248: (sc->sc_apicid << IOAPIC_ID_SHIFT));
249:
250: apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK) >>
251: IOAPIC_ID_SHIFT;
252:
253: if (apic_id != sc->sc_apicid)
254: printf(", can't remap to apid %d\n", sc->sc_apicid);
255: else
256: printf(", remapped to apid %d\n", sc->sc_apicid);
257: }
258:
259: /*
260: * can't use bus_space_xxx as we don't have a bus handle ...
261: */
262: void
263: ioapic_attach(struct device *parent, struct device *self, void *aux)
264: {
265: struct ioapic_softc *sc = (struct ioapic_softc *)self;
266: struct apic_attach_args *aaa = (struct apic_attach_args *)aux;
267: int apic_id;
268: int8_t new_id;
269: bus_space_handle_t bh;
270: u_int32_t ver_sz;
271: int i, ioapic_found;
272:
273: sc->sc_flags = aaa->flags;
274: sc->sc_apicid = aaa->apic_id;
275:
276: printf(": apid %d pa 0x%lx", aaa->apic_id, aaa->apic_address);
277:
278: if (bus_mem_add_mapping(aaa->apic_address, PAGE_SIZE, 0, &bh) != 0) {
279: printf(", map failed\n");
280: return;
281: }
282: sc->sc_reg = (volatile u_int32_t *)(bh + IOAPIC_REG);
283: sc->sc_data = (volatile u_int32_t *)(bh + IOAPIC_DATA);
284:
285: ver_sz = ioapic_read(sc, IOAPIC_VER);
286: sc->sc_apic_vers = (ver_sz & IOAPIC_VER_MASK) >> IOAPIC_VER_SHIFT;
287: sc->sc_apic_sz = (ver_sz & IOAPIC_MAX_MASK) >> IOAPIC_MAX_SHIFT;
288: sc->sc_apic_sz++;
289:
290: if (aaa->apic_vecbase != -1)
291: sc->sc_apic_vecbase = aaa->apic_vecbase;
292: else {
293: /*
294: * XXX this assumes ordering of ioapics in the table.
295: * Only needed for broken BIOS workaround (see mpbios.c)
296: */
297: sc->sc_apic_vecbase = ioapic_vecbase;
298: ioapic_vecbase += sc->sc_apic_sz;
299: }
300:
301: if (mp_verbose) {
302: printf(", %s mode",
303: aaa->flags & IOAPIC_PICMODE ? "PIC" : "virtual wire");
304: }
305:
306: printf(", version %x, %d pins\n", sc->sc_apic_vers, sc->sc_apic_sz);
307:
308: /*
309: * If either a LAPIC or an I/O APIC is already at the ID the BIOS
310: * setup for this I/O APIC, try to find a free ID to use and reprogram
311: * the chip. Record this remapping since all references done by the
312: * MP BIOS will be through the old ID.
313: */
314: ioapic_found = ioapic_find(sc->sc_apicid) != NULL;
315: if (cpu_info[sc->sc_apicid] != NULL || ioapic_found) {
316: printf("%s: duplicate apic id", sc->sc_dev.dv_xname);
317: new_id = ffs(ioapic_id_map) - 1;
318: if (new_id == -1) {
319: printf(" (and none free, ignoring)\n");
320: return;
321: }
322:
323: /*
324: * If there were many I/O APICs at the same ID, we choose
325: * to let later references to that ID (in the MP BIOS) refer
326: * to the first found.
327: */
328: if (!ioapic_found && !IOAPIC_REMAPPED(sc->sc_apicid))
329: IOAPIC_REMAP(sc->sc_apicid, new_id);
330: sc->sc_apicid = new_id;
331: ioapic_set_id(sc);
332: }
333: ioapic_id_map &= ~(1 << sc->sc_apicid);
334:
335: ioapic_add(sc);
336:
337: apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK) >>
338: IOAPIC_ID_SHIFT;
339:
340: sc->sc_pins = malloc(sizeof(struct ioapic_pin) * sc->sc_apic_sz,
341: M_DEVBUF, M_WAITOK);
342:
343: for (i=0; i<sc->sc_apic_sz; i++) {
344: sc->sc_pins[i].ip_handler = NULL;
345: sc->sc_pins[i].ip_next = NULL;
346: sc->sc_pins[i].ip_map = NULL;
347: sc->sc_pins[i].ip_vector = 0;
348: sc->sc_pins[i].ip_type = 0;
349: sc->sc_pins[i].ip_minlevel = 0xff; /* XXX magic*/
350: sc->sc_pins[i].ip_maxlevel = 0; /* XXX magic */
351: }
352:
353: /*
354: * In case the APIC is not initialized to the correct ID
355: * do it now.
356: */
357: if (apic_id != sc->sc_apicid) {
358: printf("%s: misconfigured as apic %d", sc->sc_dev.dv_xname,
359: apic_id);
360: ioapic_set_id(sc);
361: }
362: #if 0
363: /* output of this was boring. */
364: if (mp_verbose)
365: for (i=0; i<sc->sc_apic_sz; i++)
366: ioapic_print_redir(sc, "boot", i);
367: #endif
368: }
369:
370: /*
371: * Interrupt mapping.
372: *
373: * Multiple handlers may exist for each pin, so there's an
374: * intrhand chain for each pin.
375: *
376: * Ideally, each pin maps to a single vector at the priority of the
377: * highest level interrupt for that pin.
378: *
379: * XXX in the event that there are more than 16 interrupt sources at a
380: * single level, some doubling-up may be needed. This is not yet
381: * implemented.
382: *
383: * XXX we are wasting some space here because we only use a limited
384: * range of the vectors here. (0x30..0xef)
385: */
386:
387: struct intrhand *apic_intrhand[256];
388: int apic_intrcount[256];
389: int apic_maxlevel[256];
390:
391:
392: /* XXX should check vs. softc max int number */
393: #define LEGAL_IRQ(x) ((x) >= 0 && (x) < APIC_ICU_LEN && (x) != 2)
394:
395: void
396: apic_set_redir(struct ioapic_softc *sc, int pin)
397: {
398: u_int32_t redlo;
399: u_int32_t redhi = 0;
400: int delmode;
401:
402: struct ioapic_pin *pp;
403: struct mp_intr_map *map;
404:
405: pp = &sc->sc_pins[pin];
406: map = pp->ip_map;
407: redlo = (map == NULL) ? IOAPIC_REDLO_MASK : map->redir;
408: delmode = (redlo & IOAPIC_REDLO_DEL_MASK) >> IOAPIC_REDLO_DEL_SHIFT;
409:
410: /* XXX magic numbers */
411: if ((delmode != 0) && (delmode != 1))
412: ;
413: else if (pp->ip_handler == NULL) {
414: redlo |= IOAPIC_REDLO_MASK;
415: } else {
416: redlo |= (pp->ip_vector & 0xff);
417: redlo &= ~IOAPIC_REDLO_DEL_MASK;
418: redlo |= (IOAPIC_REDLO_DEL_FIXED << IOAPIC_REDLO_DEL_SHIFT);
419: redlo &= ~IOAPIC_REDLO_DSTMOD;
420:
421: /*
422: * Destination: BSP CPU
423: *
424: * XXX will want to distribute interrupts across cpu's
425: * eventually. most likely, we'll want to vector each
426: * interrupt to a specific CPU and load-balance across
427: * cpu's. but there's no point in doing that until after
428: * most interrupts run without the kernel lock.
429: */
430: redhi |= (ioapic_bsp_id << IOAPIC_REDHI_DEST_SHIFT);
431:
432: /* XXX derive this bit from BIOS info */
433: if (pp->ip_type == IST_LEVEL)
434: redlo |= IOAPIC_REDLO_LEVEL;
435: else
436: redlo &= ~IOAPIC_REDLO_LEVEL;
437: if (map != NULL && ((map->flags & 3) == MPS_INTPO_DEF)) {
438: if (pp->ip_type == IST_LEVEL)
439: redlo |= IOAPIC_REDLO_ACTLO;
440: else
441: redlo &= ~IOAPIC_REDLO_ACTLO;
442: }
443: }
444: /* Do atomic write */
445: ioapic_write(sc, IOAPIC_REDLO(pin), IOAPIC_REDLO_MASK);
446: ioapic_write(sc, IOAPIC_REDHI(pin), redhi);
447: ioapic_write(sc, IOAPIC_REDLO(pin), redlo);
448: if (mp_verbose)
449: ioapic_print_redir(sc, "int", pin);
450: }
451:
452: /*
453: * XXX To be really correct an NISA > 0 condition should check for these.
454: * However, the i386 port pretty much assumes isa is there anyway.
455: * For example, pci_intr_establish calls isa_intr_establish unconditionally.
456: */
457: extern int fakeintr(void *); /* XXX headerify */
458: extern char *isa_intr_typename(int); /* XXX headerify */
459:
460: /*
461: * apic_vectorset: allocate a vector for the given pin, based on
462: * the levels of the interrupts on that pin.
463: *
464: * XXX if the level of the pin changes while the pin is
465: * masked, need to do something special to prevent pending
466: * interrupts from being lost.
467: * (the answer may be to hang the interrupt chain off of both vectors
468: * until any interrupts from the old source have been handled. the trouble
469: * is that we don't have a global view of what interrupts are pending.
470: *
471: * Deferring for now since MP systems are more likely servers rather
472: * than laptops or desktops, and thus will have relatively static
473: * interrupt configuration.
474: */
475:
476: void
477: apic_vectorset(struct ioapic_softc *sc, int pin, int minlevel, int maxlevel)
478: {
479: struct ioapic_pin *pp = &sc->sc_pins[pin];
480: int ovector = 0;
481: int nvector = 0;
482:
483: ovector = pp->ip_vector;
484:
485: if (maxlevel == 0) {
486: /* no vector needed. */
487: pp->ip_minlevel = 0xff; /* XXX magic */
488: pp->ip_maxlevel = 0; /* XXX magic */
489: pp->ip_vector = 0;
490: } else if (maxlevel != pp->ip_maxlevel) {
491: #ifdef MPVERBOSE
492: if (minlevel != maxlevel)
493: printf("%s: pin %d shares different IPL interrupts "
494: "(%x..%x)\n", sc->sc_dev.dv_xname, pin,
495: minlevel, maxlevel);
496: #endif
497:
498: /*
499: * Allocate interrupt vector at the *lowest* priority level
500: * of any of the handlers invoked by this pin.
501: *
502: * The interrupt handler will raise ipl higher than this
503: * as appropriate.
504: */
505: nvector = idt_vec_alloc(minlevel, minlevel+15);
506:
507: if (nvector == 0) {
508: /*
509: * XXX XXX we should be able to deal here..
510: * need to double-up an existing vector
511: * and install a slightly different handler.
512: */
513: panic("%s: can't alloc vector for pin %d at level %x",
514: sc->sc_dev.dv_xname, pin, maxlevel);
515: }
516: apic_maxlevel[nvector] = maxlevel;
517: /*
518: * XXX want special handler for the maxlevel != minlevel
519: * case here!
520: */
521: idt_vec_set(nvector, apichandler[nvector & 0xf]);
522: pp->ip_vector = nvector;
523: pp->ip_minlevel = minlevel;
524: pp->ip_maxlevel = maxlevel;
525: }
526: apic_intrhand[pp->ip_vector] = pp->ip_handler;
527:
528: if (ovector) {
529: /*
530: * XXX should defer this until we're sure the old vector
531: * doesn't have a pending interrupt on any processor.
532: * do this by setting a counter equal to the number of CPU's,
533: * and firing off a low-priority broadcast IPI to all cpu's.
534: * each cpu then decrements the counter; when it
535: * goes to zero, free the vector..
536: * i.e., defer until all processors have run with a CPL
537: * less than the level of the interrupt..
538: *
539: * this is only an issue for dynamic interrupt configuration
540: * (e.g., cardbus or pcmcia).
541: */
542: apic_intrhand[ovector] = NULL;
543: idt_vec_free(ovector);
544: printf("freed vector %x\n", ovector);
545: }
546:
547: apic_set_redir(sc, pin);
548: }
549:
550: /*
551: * Throw the switch and enable interrupts..
552: */
553:
554: void
555: ioapic_enable(void)
556: {
557: int p, maxlevel, minlevel;
558: struct ioapic_softc *sc;
559: struct intrhand *q;
560: extern void intr_calculatemasks(void); /* XXX */
561:
562: intr_calculatemasks(); /* for softints, AST's */
563:
564: ioapic_cold = 0;
565:
566: if (ioapics == NULL)
567: return;
568:
569: #if 1 /* XXX Will probably get removed */
570: lapic_set_softvectors();
571: lapic_set_lvt();
572: #endif
573:
574: if (ioapics->sc_flags & IOAPIC_PICMODE) {
575: printf("%s: writing to IMCR to disable pics\n",
576: ioapics->sc_dev.dv_xname);
577: outb(IMCR_ADDR, IMCR_REGISTER);
578: outb(IMCR_DATA, IMCR_APIC);
579: }
580:
581: #if 0 /* XXX Will be removed when we have intrsource. */
582: isa_nodefaultirq();
583: #endif
584:
585: for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
586: if (mp_verbose)
587: printf("%s: enabling\n", sc->sc_dev.dv_xname);
588:
589: for (p=0; p<sc->sc_apic_sz; p++) {
590: maxlevel = 0; /* magic */
591: minlevel = 0xff; /* magic */
592:
593: for (q = sc->sc_pins[p].ip_handler; q != NULL;
594: q = q->ih_next) {
595: if (q->ih_level > maxlevel)
596: maxlevel = q->ih_level;
597: if (q->ih_level < minlevel)
598: minlevel = q->ih_level;
599: }
600: apic_vectorset(sc, p, minlevel, maxlevel);
601: }
602: }
603: }
604:
605: /*
606: * Interrupt handler management with the apic is radically different from the
607: * good old 8259.
608: *
609: * The APIC adds an additional level of indirection between interrupt
610: * signals and interrupt vectors in the IDT.
611: * It also encodes a priority into the high-order 4 bits of the IDT vector
612: * number.
613: *
614: *
615: * interrupt establishment:
616: * -> locate interrupt pin.
617: * -> locate or allocate vector for pin.
618: * -> locate or allocate handler chain for vector.
619: * -> chain interrupt into handler chain.
620: * #ifdef notyet
621: * -> if level of handler chain increases, reallocate vector, move chain.
622: * #endif
623: */
624:
625: void *
626: apic_intr_establish(int irq, int type, int level, int (*ih_fun)(void *),
627: void *ih_arg, char *ih_what)
628: {
629: unsigned int ioapic = APIC_IRQ_APIC(irq);
630: unsigned int intr = APIC_IRQ_PIN(irq);
631: struct ioapic_softc *sc = ioapic_find(ioapic);
632: struct ioapic_pin *pin;
633: struct intrhand **p, *q, *ih;
634: static struct intrhand fakehand = {fakeintr};
635: extern int cold;
636: int minlevel, maxlevel;
637:
638: if (sc == NULL)
639: panic("apic_intr_establish: unknown ioapic %d", ioapic);
640:
641: if ((irq & APIC_INT_VIA_APIC) == 0)
642: panic("apic_intr_establish of non-apic interrupt 0x%x", irq);
643:
644: if (intr >= sc->sc_apic_sz || type == IST_NONE)
645: panic("apic_intr_establish: bogus intr or type");
646:
647: /* no point in sleeping unless someone can free memory. */
648: ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
649: if (ih == NULL)
650: panic("apic_intr_establish: can't malloc handler info");
651:
652: pin = &sc->sc_pins[intr];
653: switch (pin->ip_type) {
654: case IST_NONE:
655: pin->ip_type = type;
656: break;
657: case IST_EDGE:
658: case IST_LEVEL:
659: if (type == pin->ip_type)
660: break;
661: case IST_PULSE:
662: if (type != IST_NONE) {
663: /*printf("%s: intr_establish: can't share %s with %s, irq %d\n",
664: ih_what, isa_intr_typename(pin->ip_type),
665: isa_intr_typename(type), intr);*/
666: free(ih, M_DEVBUF);
667: return (NULL);
668: }
669: break;
670: }
671:
672: /*
673: * Figure out where to put the handler.
674: * This is O(N^2) to establish N interrupts, but we want to
675: * preserve the order, and N is generally small.
676: */
677: maxlevel = level;
678: minlevel = level;
679: for (p = &pin->ip_handler; (q = *p) != NULL; p = &q->ih_next) {
680: if (q->ih_level > maxlevel)
681: maxlevel = q->ih_level;
682: if (q->ih_level < minlevel)
683: minlevel = q->ih_level;
684: }
685:
686: /*
687: * Actually install a fake handler momentarily, since we might be doing
688: * this with interrupts enabled and don't want the real routine called
689: * until masking is set up.
690: */
691: fakehand.ih_level = level;
692: *p = &fakehand;
693:
694: /*
695: * Fix up the vector for this pin.
696: * (if cold, defer this until most interrupts have been established,
697: * to avoid too much thrashing of the idt..)
698: */
699:
700: if (!ioapic_cold)
701: apic_vectorset(sc, intr, minlevel, maxlevel);
702:
703: #if 0
704: apic_calculatemasks();
705: #endif
706:
707: /*
708: * Poke the real handler in now.
709: */
710: ih->ih_fun = ih_fun;
711: ih->ih_arg = ih_arg;
712: ih->ih_next = NULL;
713: ih->ih_level = level;
714: ih->ih_irq = irq;
715: evcount_attach(&ih->ih_count, ih_what, (void *)&pin->ip_vector,
716: &evcount_intr);
717: *p = ih;
718:
719: return (ih);
720: }
721:
722: /*
723: * apic disestablish:
724: * locate handler chain.
725: * dechain intrhand from handler chain
726: * if chain empty {
727: * reprogram apic for "safe" vector.
728: * free vector (point at stray handler).
729: * }
730: * #ifdef notyet
731: * else {
732: * recompute level for current chain.
733: * if changed, reallocate vector, move chain.
734: * }
735: * #endif
736: */
737:
738: void
739: apic_intr_disestablish(void *arg)
740: {
741: struct intrhand *ih = arg;
742: int irq = ih->ih_irq;
743: unsigned int ioapic = APIC_IRQ_APIC(irq);
744: unsigned int intr = APIC_IRQ_PIN(irq);
745: struct ioapic_softc *sc = ioapic_find(ioapic);
746: struct ioapic_pin *pin = &sc->sc_pins[intr];
747: struct intrhand **p, *q;
748: int minlevel, maxlevel;
749:
750: if (sc == NULL)
751: panic("apic_intr_disestablish: unknown ioapic %d", ioapic);
752:
753: if (intr >= sc->sc_apic_sz)
754: panic("apic_intr_disestablish: bogus irq");
755:
756: /*
757: * Remove the handler from the chain.
758: * This is O(n^2), too.
759: */
760: maxlevel = 0;
761: minlevel = 0xff;
762: for (p = &pin->ip_handler; (q = *p) != NULL && q != ih;
763: p = &q->ih_next) {
764: if (q->ih_level > maxlevel)
765: maxlevel = q->ih_level;
766: if (q->ih_level < minlevel)
767: minlevel = q->ih_level;
768: }
769:
770: if (q)
771: *p = q->ih_next;
772: else
773: panic("intr_disestablish: handler not registered");
774: for (; q != NULL; q = q->ih_next) {
775: if (q->ih_level > maxlevel)
776: maxlevel = q->ih_level;
777: if (q->ih_level < minlevel)
778: minlevel = q->ih_level;
779: }
780:
781: if (!ioapic_cold)
782: apic_vectorset(sc, intr, minlevel, maxlevel);
783:
784: evcount_detach(&ih->ih_count);
785: free(ih, M_DEVBUF);
786: }
787:
788: void
789: apic_stray(int irqnum) {
790: unsigned int apicid;
791: struct ioapic_softc *sc;
792:
793: apicid = APIC_IRQ_APIC(irqnum);
794: sc = ioapic_find(apicid);
795: if (sc == NULL)
796: return;
797: printf("%s: stray interrupt %d\n", sc->sc_dev.dv_xname, irqnum);
798: }
799:
800: #ifdef DDB
801: void ioapic_dump(void);
802:
803: void
804: ioapic_dump(void)
805: {
806: struct ioapic_softc *sc;
807: struct ioapic_pin *ip;
808: int p;
809:
810: for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
811: for (p = 0; p < sc->sc_apic_sz; p++) {
812: ip = &sc->sc_pins[p];
813: if (ip->ip_type != IST_NONE)
814: ioapic_print_redir(sc, "dump", p);
815: }
816: }
817: }
818: #endif
CVSweb