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