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