]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/io_apic.c
Fix the format/display descriptor of vm.kmem_size and vm.kmem_free
[FreeBSD/FreeBSD.git] / sys / amd64 / amd64 / io_apic.c
1 /*-
2  * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of any co-contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include "opt_atpic.h"
34 #include "opt_isa.h"
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/lock.h>
42 #include <sys/mutex.h>
43 #include <sys/sysctl.h>
44
45 #include <vm/vm.h>
46 #include <vm/pmap.h>
47
48 #include <machine/apicreg.h>
49 #include <machine/frame.h>
50 #include <machine/intr_machdep.h>
51 #include <machine/apicvar.h>
52 #include <machine/segments.h>
53
54 #define IOAPIC_ISA_INTS         16
55 #define IOAPIC_MEM_REGION       32
56 #define IOAPIC_REDTBL_LO(i)     (IOAPIC_REDTBL + (i) * 2)
57 #define IOAPIC_REDTBL_HI(i)     (IOAPIC_REDTBL_LO(i) + 1)
58
59 #define IRQ_EXTINT              (NUM_IO_INTS + 1)
60 #define IRQ_NMI                 (NUM_IO_INTS + 2)
61 #define IRQ_SMI                 (NUM_IO_INTS + 3)
62 #define IRQ_DISABLED            (NUM_IO_INTS + 4)
63
64 #define TODO            printf("%s: not implemented!\n", __func__)
65
66 static MALLOC_DEFINE(M_IOAPIC, "io_apic", "I/O APIC structures");
67
68 /*
69  * I/O APIC interrupt source driver.  Each pin is assigned an IRQ cookie
70  * as laid out in the ACPI System Interrupt number model where each I/O
71  * APIC has a contiguous chunk of the System Interrupt address space.
72  * We assume that IRQs 1 - 15 behave like ISA IRQs and that all other
73  * IRQs behave as PCI IRQs by default.  We also assume that the pin for
74  * IRQ 0 is actually an ExtINT pin.  The apic enumerators override the
75  * configuration of individual pins as indicated by their tables.
76  */
77
78 struct ioapic_intsrc {
79         struct intsrc io_intsrc;
80         u_int io_irq;
81         u_int io_intpin:8;
82         u_int io_vector:8;
83         u_int io_cpu:8;
84         u_int io_activehi:1;
85         u_int io_edgetrigger:1;
86         u_int io_masked:1;
87         int io_bus:4;
88 };
89
90 struct ioapic {
91         struct pic io_pic;
92         u_int io_id:8;                  /* logical ID */
93         u_int io_apic_id:4;
94         u_int io_intbase:8;             /* System Interrupt base */
95         u_int io_numintr:8;
96         volatile ioapic_t *io_addr;     /* XXX: should use bus_space */
97         STAILQ_ENTRY(ioapic) io_next;
98         struct ioapic_intsrc io_pins[0];
99 };
100
101 static u_int    ioapic_read(volatile ioapic_t *apic, int reg);
102 static void     ioapic_write(volatile ioapic_t *apic, int reg, u_int val);
103 static const char *ioapic_bus_string(int bus_type);
104 static void     ioapic_print_irq(struct ioapic_intsrc *intpin);
105 static void     ioapic_enable_source(struct intsrc *isrc);
106 static void     ioapic_disable_source(struct intsrc *isrc, int eoi);
107 static void     ioapic_eoi_source(struct intsrc *isrc);
108 static void     ioapic_enable_intr(struct intsrc *isrc);
109 static int      ioapic_vector(struct intsrc *isrc);
110 static int      ioapic_source_pending(struct intsrc *isrc);
111 static int      ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
112                     enum intr_polarity pol);
113 static void     ioapic_suspend(struct intsrc *isrc);
114 static void     ioapic_resume(struct intsrc *isrc);
115 static void     ioapic_assign_cpu(struct intsrc *isrc, u_int apic_id);
116 static void     ioapic_program_intpin(struct ioapic_intsrc *intpin);
117
118 static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
119 struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source,
120                                ioapic_eoi_source, ioapic_enable_intr,
121                                ioapic_vector, ioapic_source_pending,
122                                ioapic_suspend, ioapic_resume,
123                                ioapic_config_intr, ioapic_assign_cpu };
124
125 static int next_ioapic_base;
126 static u_int next_id;
127
128 SYSCTL_NODE(_hw, OID_AUTO, apic, CTLFLAG_RD, 0, "APIC options");
129 static int enable_extint;
130 SYSCTL_INT(_hw_apic, OID_AUTO, enable_extint, CTLFLAG_RDTUN, &enable_extint, 0,
131     "Enable the ExtINT pin in the first I/O APIC");
132 TUNABLE_INT("hw.apic.enable_extint", &enable_extint);
133
134 static __inline void
135 _ioapic_eoi_source(struct intsrc *isrc)
136 {
137         lapic_eoi();
138 }
139
140 static u_int
141 ioapic_read(volatile ioapic_t *apic, int reg)
142 {
143
144         mtx_assert(&icu_lock, MA_OWNED);
145         apic->ioregsel = reg;
146         return (apic->iowin);
147 }
148
149 static void
150 ioapic_write(volatile ioapic_t *apic, int reg, u_int val)
151 {
152
153         mtx_assert(&icu_lock, MA_OWNED);
154         apic->ioregsel = reg;
155         apic->iowin = val;
156 }
157
158 static const char *
159 ioapic_bus_string(int bus_type)
160 {
161
162         switch (bus_type) {
163         case APIC_BUS_ISA:
164                 return ("ISA");
165         case APIC_BUS_EISA:
166                 return ("EISA");
167         case APIC_BUS_PCI:
168                 return ("PCI");
169         default:
170                 return ("unknown");
171         }
172 }
173
174 static void
175 ioapic_print_irq(struct ioapic_intsrc *intpin)
176 {
177
178         switch (intpin->io_irq) {
179         case IRQ_DISABLED:
180                 printf("disabled");
181                 break;
182         case IRQ_EXTINT:
183                 printf("ExtINT");
184                 break;
185         case IRQ_NMI:
186                 printf("NMI");
187                 break;
188         case IRQ_SMI:
189                 printf("SMI");
190                 break;
191         default:
192                 printf("%s IRQ %u", ioapic_bus_string(intpin->io_bus),
193                     intpin->io_irq);
194         }
195 }
196
197 static void
198 ioapic_enable_source(struct intsrc *isrc)
199 {
200         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
201         struct ioapic *io = (struct ioapic *)isrc->is_pic;
202         uint32_t flags;
203
204         mtx_lock_spin(&icu_lock);
205         if (intpin->io_masked) {
206                 flags = ioapic_read(io->io_addr,
207                     IOAPIC_REDTBL_LO(intpin->io_intpin));
208                 flags &= ~(IOART_INTMASK);
209                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
210                     flags);
211                 intpin->io_masked = 0;
212         }
213         mtx_unlock_spin(&icu_lock);
214 }
215
216 static void
217 ioapic_disable_source(struct intsrc *isrc, int eoi)
218 {
219         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
220         struct ioapic *io = (struct ioapic *)isrc->is_pic;
221         uint32_t flags;
222
223         mtx_lock_spin(&icu_lock);
224         if (!intpin->io_masked && !intpin->io_edgetrigger) {
225                 flags = ioapic_read(io->io_addr,
226                     IOAPIC_REDTBL_LO(intpin->io_intpin));
227                 flags |= IOART_INTMSET;
228                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
229                     flags);
230                 intpin->io_masked = 1;
231         }
232
233         if (eoi == PIC_EOI)
234                 _ioapic_eoi_source(isrc);
235
236         mtx_unlock_spin(&icu_lock);
237 }
238
239 static void
240 ioapic_eoi_source(struct intsrc *isrc)
241 {
242
243         _ioapic_eoi_source(isrc);
244 }
245
246 /*
247  * Completely program an intpin based on the data in its interrupt source
248  * structure.
249  */
250 static void
251 ioapic_program_intpin(struct ioapic_intsrc *intpin)
252 {
253         struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
254         uint32_t low, high, value;
255
256         /*
257          * If a pin is completely invalid or if it is valid but hasn't
258          * been enabled yet, just ensure that the pin is masked.
259          */
260         if (intpin->io_irq == IRQ_DISABLED || (intpin->io_irq < NUM_IO_INTS &&
261             intpin->io_vector == 0)) {
262                 mtx_lock_spin(&icu_lock);
263                 low = ioapic_read(io->io_addr,
264                     IOAPIC_REDTBL_LO(intpin->io_intpin));
265                 if ((low & IOART_INTMASK) == IOART_INTMCLR)
266                         ioapic_write(io->io_addr,
267                             IOAPIC_REDTBL_LO(intpin->io_intpin),
268                             low | IOART_INTMSET);
269                 mtx_unlock_spin(&icu_lock);
270                 return;
271         }
272
273         /* Set the destination. */
274         low = IOART_DESTPHY;
275         high = intpin->io_cpu << APIC_ID_SHIFT;
276
277         /* Program the rest of the low word. */
278         if (intpin->io_edgetrigger)
279                 low |= IOART_TRGREDG;
280         else
281                 low |= IOART_TRGRLVL;
282         if (intpin->io_activehi)
283                 low |= IOART_INTAHI;
284         else
285                 low |= IOART_INTALO;
286         if (intpin->io_masked)
287                 low |= IOART_INTMSET;
288         switch (intpin->io_irq) {
289         case IRQ_EXTINT:
290                 KASSERT(intpin->io_edgetrigger,
291                     ("ExtINT not edge triggered"));
292                 low |= IOART_DELEXINT;
293                 break;
294         case IRQ_NMI:
295                 KASSERT(intpin->io_edgetrigger,
296                     ("NMI not edge triggered"));
297                 low |= IOART_DELNMI;
298                 break;
299         case IRQ_SMI:
300                 KASSERT(intpin->io_edgetrigger,
301                     ("SMI not edge triggered"));
302                 low |= IOART_DELSMI;
303                 break;
304         default:
305                 KASSERT(intpin->io_vector != 0, ("No vector for IRQ %u",
306                     intpin->io_irq));
307                 low |= IOART_DELFIXED | intpin->io_vector;
308         }
309
310         /* Write the values to the APIC. */
311         mtx_lock_spin(&icu_lock);
312         ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), low);
313         value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin));
314         value &= ~IOART_DEST;
315         value |= high;
316         ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value);
317         mtx_unlock_spin(&icu_lock);
318 }
319
320 static void
321 ioapic_assign_cpu(struct intsrc *isrc, u_int apic_id)
322 {
323         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
324         struct ioapic *io = (struct ioapic *)isrc->is_pic;
325
326         intpin->io_cpu = apic_id;
327         if (bootverbose) {
328                 printf("ioapic%u: Assigning ", io->io_id);
329                 ioapic_print_irq(intpin);
330                 printf(" to local APIC %u\n", intpin->io_cpu);
331         }
332         ioapic_program_intpin(intpin);
333 }
334
335 static void
336 ioapic_enable_intr(struct intsrc *isrc)
337 {
338         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
339         struct ioapic *io = (struct ioapic *)isrc->is_pic;
340
341         if (intpin->io_vector == 0) {
342                 /*
343                  * Allocate an APIC vector for this interrupt pin.  Once
344                  * we have a vector we program the interrupt pin.
345                  */
346                 intpin->io_vector = apic_alloc_vector(intpin->io_irq);
347                 if (bootverbose) {
348                         printf("ioapic%u: routing intpin %u (", io->io_id,
349                             intpin->io_intpin);
350                         ioapic_print_irq(intpin);
351                         printf(") to vector %u\n", intpin->io_vector);
352                 }
353                 ioapic_program_intpin(intpin);
354                 apic_enable_vector(intpin->io_vector);
355         }
356 }
357
358 static int
359 ioapic_vector(struct intsrc *isrc)
360 {
361         struct ioapic_intsrc *pin;
362
363         pin = (struct ioapic_intsrc *)isrc;
364         return (pin->io_irq);
365 }
366
367 static int
368 ioapic_source_pending(struct intsrc *isrc)
369 {
370         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
371
372         if (intpin->io_vector == 0)
373                 return 0;
374         return (lapic_intr_pending(intpin->io_vector));
375 }
376
377 static int
378 ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
379     enum intr_polarity pol)
380 {
381         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
382         struct ioapic *io = (struct ioapic *)isrc->is_pic;
383         int changed;
384
385         KASSERT(!(trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM),
386             ("%s: Conforming trigger or polarity\n", __func__));
387
388         /*
389          * EISA interrupts always use active high polarity, so don't allow
390          * them to be set to active low.
391          *
392          * XXX: Should we write to the ELCR if the trigger mode changes for
393          * an EISA IRQ or an ISA IRQ with the ELCR present?
394          */
395         if (intpin->io_bus == APIC_BUS_EISA)
396                 pol = INTR_POLARITY_HIGH;
397         changed = 0;
398         if (intpin->io_edgetrigger != (trig == INTR_TRIGGER_EDGE)) {
399                 if (bootverbose)
400                         printf("ioapic%u: Changing trigger for pin %u to %s\n",
401                             io->io_id, intpin->io_intpin,
402                             trig == INTR_TRIGGER_EDGE ? "edge" : "level");
403                 intpin->io_edgetrigger = (trig == INTR_TRIGGER_EDGE);
404                 changed++;
405         }
406         if (intpin->io_activehi != (pol == INTR_POLARITY_HIGH)) {
407                 if (bootverbose)
408                         printf("ioapic%u: Changing polarity for pin %u to %s\n",
409                             io->io_id, intpin->io_intpin,
410                             pol == INTR_POLARITY_HIGH ? "high" : "low");
411                 intpin->io_activehi = (pol == INTR_POLARITY_HIGH);
412                 changed++;
413         }
414         if (changed)
415                 ioapic_program_intpin(intpin);
416         return (0);
417 }
418
419 static void
420 ioapic_suspend(struct intsrc *isrc)
421 {
422
423         TODO;
424 }
425
426 static void
427 ioapic_resume(struct intsrc *isrc)
428 {
429
430         ioapic_program_intpin((struct ioapic_intsrc *)isrc);
431 }
432
433 /*
434  * Create a plain I/O APIC object.
435  */
436 void *
437 ioapic_create(uintptr_t addr, int32_t apic_id, int intbase)
438 {
439         struct ioapic *io;
440         struct ioapic_intsrc *intpin;
441         volatile ioapic_t *apic;
442         u_int numintr, i;
443         uint32_t value;
444
445         /* Map the register window so we can access the device. */
446         apic = (ioapic_t *)pmap_mapdev(addr, IOAPIC_MEM_REGION);
447         mtx_lock_spin(&icu_lock);
448         value = ioapic_read(apic, IOAPIC_VER);
449         mtx_unlock_spin(&icu_lock);
450
451         /* If it's version register doesn't seem to work, punt. */
452         if (value == 0xffffffff) {
453                 pmap_unmapdev((vm_offset_t)apic, IOAPIC_MEM_REGION);
454                 return (NULL);
455         }
456
457         /* Determine the number of vectors and set the APIC ID. */
458         numintr = ((value & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1;
459         io = malloc(sizeof(struct ioapic) +
460             numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK);
461         io->io_pic = ioapic_template;
462         mtx_lock_spin(&icu_lock);
463         io->io_id = next_id++;
464         io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT; 
465         if (apic_id != -1 && io->io_apic_id != apic_id) {
466                 ioapic_write(apic, IOAPIC_ID, apic_id << APIC_ID_SHIFT);
467                 mtx_unlock_spin(&icu_lock);
468                 io->io_apic_id = apic_id;
469                 printf("ioapic%u: Changing APIC ID to %d\n", io->io_id,
470                     apic_id);
471         } else
472                 mtx_unlock_spin(&icu_lock);
473         if (intbase == -1) {
474                 intbase = next_ioapic_base;
475                 printf("ioapic%u: Assuming intbase of %d\n", io->io_id,
476                     intbase);
477         } else if (intbase != next_ioapic_base)
478                 printf("ioapic%u: WARNING: intbase %d != expected base %d\n",
479                     io->io_id, intbase, next_ioapic_base);
480         io->io_intbase = intbase;
481         next_ioapic_base = intbase + numintr;
482         io->io_numintr = numintr;
483         io->io_addr = apic;
484
485         /*
486          * Initialize pins.  Start off with interrupts disabled.  Default
487          * to active-hi and edge-triggered for ISA interrupts and active-lo
488          * and level-triggered for all others.
489          */
490         bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr);
491         mtx_lock_spin(&icu_lock);
492         for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) {
493                 intpin->io_intsrc.is_pic = (struct pic *)io;
494                 intpin->io_intpin = i;
495                 intpin->io_irq = intbase + i;
496
497                 /*
498                  * Assume that pin 0 on the first I/O APIC is an ExtINT pin.
499                  * Assume that pins 1-15 are ISA interrupts and that all
500                  * other pins are PCI interrupts.
501                  */
502                 if (intpin->io_irq == 0)
503                         ioapic_set_extint(io, i);
504                 else if (intpin->io_irq < IOAPIC_ISA_INTS) {
505                         intpin->io_bus = APIC_BUS_ISA;
506                         intpin->io_activehi = 1;
507                         intpin->io_edgetrigger = 1;
508                         intpin->io_masked = 1;
509                 } else {
510                         intpin->io_bus = APIC_BUS_PCI;
511                         intpin->io_activehi = 0;
512                         intpin->io_edgetrigger = 0;
513                         intpin->io_masked = 1;
514                 }
515
516                 /*
517                  * Route interrupts to the BSP by default.  Interrupts may
518                  * be routed to other CPUs later after they are enabled.
519                  */
520                 intpin->io_cpu = PCPU_GET(apic_id);
521                 if (bootverbose && intpin->io_irq != IRQ_DISABLED) {
522                         printf("ioapic%u: intpin %d -> ",  io->io_id, i);
523                         ioapic_print_irq(intpin);
524                         printf(" (%s, %s)\n", intpin->io_edgetrigger ?
525                             "edge" : "level", intpin->io_activehi ? "high" :
526                             "low");
527                 }
528                 value = ioapic_read(apic, IOAPIC_REDTBL_LO(i));
529                 ioapic_write(apic, IOAPIC_REDTBL_LO(i), value | IOART_INTMSET);
530         }
531         mtx_unlock_spin(&icu_lock);
532
533         return (io);
534 }
535
536 int
537 ioapic_get_vector(void *cookie, u_int pin)
538 {
539         struct ioapic *io;
540
541         io = (struct ioapic *)cookie;
542         if (pin >= io->io_numintr)
543                 return (-1);
544         return (io->io_pins[pin].io_irq);
545 }
546
547 int
548 ioapic_disable_pin(void *cookie, u_int pin)
549 {
550         struct ioapic *io;
551
552         io = (struct ioapic *)cookie;
553         if (pin >= io->io_numintr)
554                 return (EINVAL);
555         if (io->io_pins[pin].io_irq == IRQ_DISABLED)
556                 return (EINVAL);
557         io->io_pins[pin].io_irq = IRQ_DISABLED;
558         if (bootverbose)
559                 printf("ioapic%u: intpin %d disabled\n", io->io_id, pin);
560         return (0);
561 }
562
563 int
564 ioapic_remap_vector(void *cookie, u_int pin, int vector)
565 {
566         struct ioapic *io;
567
568         io = (struct ioapic *)cookie;
569         if (pin >= io->io_numintr || vector < 0)
570                 return (EINVAL);
571         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
572                 return (EINVAL);
573         io->io_pins[pin].io_irq = vector;
574         if (bootverbose)
575                 printf("ioapic%u: Routing IRQ %d -> intpin %d\n", io->io_id,
576                     vector, pin);
577         return (0);
578 }
579
580 int
581 ioapic_set_bus(void *cookie, u_int pin, int bus_type)
582 {
583         struct ioapic *io;
584
585         if (bus_type < 0 || bus_type > APIC_BUS_MAX)
586                 return (EINVAL);
587         io = (struct ioapic *)cookie;
588         if (pin >= io->io_numintr)
589                 return (EINVAL);
590         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
591                 return (EINVAL);
592         io->io_pins[pin].io_bus = bus_type;
593         if (bootverbose)
594                 printf("ioapic%u: intpin %d bus %s\n", io->io_id, pin,
595                     ioapic_bus_string(bus_type));
596         return (0);
597 }
598
599 int
600 ioapic_set_nmi(void *cookie, u_int pin)
601 {
602         struct ioapic *io;
603
604         io = (struct ioapic *)cookie;
605         if (pin >= io->io_numintr)
606                 return (EINVAL);
607         if (io->io_pins[pin].io_irq == IRQ_NMI)
608                 return (0);
609         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
610                 return (EINVAL);
611         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
612         io->io_pins[pin].io_irq = IRQ_NMI;
613         io->io_pins[pin].io_masked = 0;
614         io->io_pins[pin].io_edgetrigger = 1;
615         io->io_pins[pin].io_activehi = 1;
616         if (bootverbose)
617                 printf("ioapic%u: Routing NMI -> intpin %d\n",
618                     io->io_id, pin);
619         return (0);
620 }
621
622 int
623 ioapic_set_smi(void *cookie, u_int pin)
624 {
625         struct ioapic *io;
626
627         io = (struct ioapic *)cookie;
628         if (pin >= io->io_numintr)
629                 return (EINVAL);
630         if (io->io_pins[pin].io_irq == IRQ_SMI)
631                 return (0);
632         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
633                 return (EINVAL);
634         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
635         io->io_pins[pin].io_irq = IRQ_SMI;
636         io->io_pins[pin].io_masked = 0;
637         io->io_pins[pin].io_edgetrigger = 1;
638         io->io_pins[pin].io_activehi = 1;
639         if (bootverbose)
640                 printf("ioapic%u: Routing SMI -> intpin %d\n",
641                     io->io_id, pin);
642         return (0);
643 }
644
645 int
646 ioapic_set_extint(void *cookie, u_int pin)
647 {
648         struct ioapic *io;
649
650         io = (struct ioapic *)cookie;
651         if (pin >= io->io_numintr)
652                 return (EINVAL);
653         if (io->io_pins[pin].io_irq == IRQ_EXTINT)
654                 return (0);
655         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
656                 return (EINVAL);
657         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
658         io->io_pins[pin].io_irq = IRQ_EXTINT;
659         if (enable_extint)
660                 io->io_pins[pin].io_masked = 0;
661         else
662                 io->io_pins[pin].io_masked = 1;
663         io->io_pins[pin].io_edgetrigger = 1;
664         io->io_pins[pin].io_activehi = 1;
665         if (bootverbose)
666                 printf("ioapic%u: Routing external 8259A's -> intpin %d\n",
667                     io->io_id, pin);
668         return (0);
669 }
670
671 int
672 ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol)
673 {
674         struct ioapic *io;
675
676         io = (struct ioapic *)cookie;
677         if (pin >= io->io_numintr || pol == INTR_POLARITY_CONFORM)
678                 return (EINVAL);
679         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
680                 return (EINVAL);
681         io->io_pins[pin].io_activehi = (pol == INTR_POLARITY_HIGH);
682         if (bootverbose)
683                 printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin,
684                     pol == INTR_POLARITY_HIGH ? "high" : "low");
685         return (0);
686 }
687
688 int
689 ioapic_set_triggermode(void *cookie, u_int pin, enum intr_trigger trigger)
690 {
691         struct ioapic *io;
692
693         io = (struct ioapic *)cookie;
694         if (pin >= io->io_numintr || trigger == INTR_TRIGGER_CONFORM)
695                 return (EINVAL);
696         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
697                 return (EINVAL);
698         io->io_pins[pin].io_edgetrigger = (trigger == INTR_TRIGGER_EDGE);
699         if (bootverbose)
700                 printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin,
701                     trigger == INTR_TRIGGER_EDGE ? "edge" : "level");
702         return (0);
703 }
704
705 /*
706  * Register a complete I/O APIC object with the interrupt subsystem.
707  */
708 void
709 ioapic_register(void *cookie)
710 {
711         struct ioapic_intsrc *pin;
712         struct ioapic *io;
713         volatile ioapic_t *apic;
714         uint32_t flags;
715         int i;
716
717         io = (struct ioapic *)cookie;
718         apic = io->io_addr;
719         mtx_lock_spin(&icu_lock);
720         flags = ioapic_read(apic, IOAPIC_VER) & IOART_VER_VERSION;
721         STAILQ_INSERT_TAIL(&ioapic_list, io, io_next);
722         mtx_unlock_spin(&icu_lock);
723         printf("ioapic%u <Version %u.%u> irqs %u-%u on motherboard\n",
724             io->io_id, flags >> 4, flags & 0xf, io->io_intbase,
725             io->io_intbase + io->io_numintr - 1);
726
727         /* Register valid pins as interrupt sources. */
728         for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++)
729                 if (pin->io_irq < NUM_IO_INTS)
730                         intr_register_source(&pin->io_intsrc);
731 }