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.0/sys/i386/i386/io_apic.c 148747 2005-08-05 19:08:25Z jhb $");
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 VECTOR_EXTINT 252
59 #define VECTOR_NMI 253
60 #define VECTOR_SMI 254
61 #define VECTOR_DISABLED 255
62
63 #define DEST_NONE -1
64
65 #define TODO printf("%s: not implemented!\n", __func__)
66
67 static MALLOC_DEFINE(M_IOAPIC, "I/O APIC", "I/O APIC structures");
68
69 /*
70 * New interrupt support code..
71 *
72 * XXX: we really should have the interrupt cookie passed up from new-bus
73 * just be a int pin, and not map 1:1 to interrupt vector number but should
74 * use INTR_TYPE_FOO to set priority bands for device classes and do all the
75 * magic remapping of intpin to vector in here. For now we just cheat as on
76 * ia64 and map intpin X to vector NRSVIDT + X. Note that we assume that the
77 * first IO APIC has ISA interrupts on pins 1-15. Not sure how you are
78 * really supposed to figure out which IO APIC in a system with multiple IO
79 * APIC's actually has the ISA interrupts routed to it. As far as interrupt
80 * pin numbers, we use the ACPI System Interrupt number model where each
81 * IO APIC has a contiguous chunk of the System Interrupt address space.
82 */
83
84 struct ioapic_intsrc {
85 struct intsrc io_intsrc;
86 u_int io_intpin:8;
87 u_int io_vector:8;
88 u_int io_activehi:1;
89 u_int io_edgetrigger:1;
90 u_int io_masked:1;
91 int io_dest:5;
92 int io_bus:4;
93 };
94
95 struct ioapic {
96 struct pic io_pic;
97 u_int io_id:8; /* logical ID */
98 u_int io_apic_id:4;
99 u_int io_intbase:8; /* System Interrupt base */
100 u_int io_numintr:8;
101 volatile ioapic_t *io_addr; /* XXX: should use bus_space */
102 STAILQ_ENTRY(ioapic) io_next;
103 struct ioapic_intsrc io_pins[0];
104 };
105
106 static u_int ioapic_read(volatile ioapic_t *apic, int reg);
107 static void ioapic_write(volatile ioapic_t *apic, int reg, u_int val);
108 static const char *ioapic_bus_string(int bus_type);
109 static void ioapic_print_vector(struct ioapic_intsrc *intpin);
110 static void ioapic_enable_source(struct intsrc *isrc);
111 static void ioapic_disable_source(struct intsrc *isrc, int eoi);
112 static void ioapic_eoi_source(struct intsrc *isrc);
113 static void ioapic_enable_intr(struct intsrc *isrc);
114 static int ioapic_vector(struct intsrc *isrc);
115 static int ioapic_source_pending(struct intsrc *isrc);
116 static int ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
117 enum intr_polarity pol);
118 static void ioapic_suspend(struct intsrc *isrc);
119 static void ioapic_resume(struct intsrc *isrc);
120 static void ioapic_program_destination(struct ioapic_intsrc *intpin);
121 static void ioapic_program_intpin(struct ioapic_intsrc *intpin);
122
123 static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
124 struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source,
125 ioapic_eoi_source, ioapic_enable_intr,
126 ioapic_vector, ioapic_source_pending,
127 ioapic_suspend, ioapic_resume,
128 ioapic_config_intr };
129
130 static int bsp_id, current_cluster, logical_clusters, next_ioapic_base;
131 static u_int next_id, program_logical_dest;
132
133 SYSCTL_NODE(_hw, OID_AUTO, apic, CTLFLAG_RD, 0, "APIC options");
134 static int enable_extint;
135 SYSCTL_INT(_hw_apic, OID_AUTO, enable_extint, CTLFLAG_RDTUN, &enable_extint, 0,
136 "Enable the ExtINT pin in the first I/O APIC");
137 TUNABLE_INT("hw.apic.enable_extint", &enable_extint);
138
139 static __inline void
140 _ioapic_eoi_source(struct intsrc *isrc)
141 {
142 lapic_eoi();
143 }
144
145 static u_int
146 ioapic_read(volatile ioapic_t *apic, int reg)
147 {
148
149 mtx_assert(&icu_lock, MA_OWNED);
150 apic->ioregsel = reg;
151 return (apic->iowin);
152 }
153
154 static void
155 ioapic_write(volatile ioapic_t *apic, int reg, u_int val)
156 {
157
158 mtx_assert(&icu_lock, MA_OWNED);
159 apic->ioregsel = reg;
160 apic->iowin = val;
161 }
162
163 static const char *
164 ioapic_bus_string(int bus_type)
165 {
166
167 switch (bus_type) {
168 case APIC_BUS_ISA:
169 return ("ISA");
170 case APIC_BUS_EISA:
171 return ("EISA");
172 case APIC_BUS_PCI:
173 return ("PCI");
174 default:
175 return ("unknown");
176 }
177 }
178
179 static void
180 ioapic_print_vector(struct ioapic_intsrc *intpin)
181 {
182
183 switch (intpin->io_vector) {
184 case VECTOR_DISABLED:
185 printf("disabled");
186 break;
187 case VECTOR_EXTINT:
188 printf("ExtINT");
189 break;
190 case VECTOR_NMI:
191 printf("NMI");
192 break;
193 case VECTOR_SMI:
194 printf("SMI");
195 break;
196 default:
197 printf("%s IRQ %u", ioapic_bus_string(intpin->io_bus),
198 intpin->io_vector);
199 }
200 }
201
202 static void
203 ioapic_enable_source(struct intsrc *isrc)
204 {
205 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
206 struct ioapic *io = (struct ioapic *)isrc->is_pic;
207 uint32_t flags;
208
209 mtx_lock_spin(&icu_lock);
210 if (intpin->io_masked) {
211 flags = ioapic_read(io->io_addr,
212 IOAPIC_REDTBL_LO(intpin->io_intpin));
213 flags &= ~(IOART_INTMASK);
214 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
215 flags);
216 intpin->io_masked = 0;
217 }
218 mtx_unlock_spin(&icu_lock);
219 }
220
221 static void
222 ioapic_disable_source(struct intsrc *isrc, int eoi)
223 {
224 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
225 struct ioapic *io = (struct ioapic *)isrc->is_pic;
226 uint32_t flags;
227
228 mtx_lock_spin(&icu_lock);
229 if (!intpin->io_masked && !intpin->io_edgetrigger) {
230 flags = ioapic_read(io->io_addr,
231 IOAPIC_REDTBL_LO(intpin->io_intpin));
232 flags |= IOART_INTMSET;
233 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
234 flags);
235 intpin->io_masked = 1;
236 }
237
238 if (eoi == PIC_EOI)
239 _ioapic_eoi_source(isrc);
240
241 mtx_unlock_spin(&icu_lock);
242 }
243
244 static void
245 ioapic_eoi_source(struct intsrc *isrc)
246 {
247
248 _ioapic_eoi_source(isrc);
249 }
250
251 /*
252 * Completely program an intpin based on the data in its interrupt source
253 * structure.
254 */
255 static void
256 ioapic_program_intpin(struct ioapic_intsrc *intpin)
257 {
258 struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
259 uint32_t low, high, value;
260
261 /* For disabled pins, just ensure that they are masked. */
262 if (intpin->io_vector == VECTOR_DISABLED) {
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 return;
270 }
271
272 /* Set the destination. */
273 if (intpin->io_dest == DEST_NONE) {
274 low = IOART_DESTPHY;
275 high = bsp_id << APIC_ID_SHIFT;
276 } else {
277 low = IOART_DESTLOG;
278 high = (intpin->io_dest << APIC_ID_CLUSTER_SHIFT |
279 APIC_ID_CLUSTER_ID) << APIC_ID_SHIFT;
280 }
281
282 /* Program the rest of the low word. */
283 if (intpin->io_edgetrigger)
284 low |= IOART_TRGREDG;
285 else
286 low |= IOART_TRGRLVL;
287 if (intpin->io_activehi)
288 low |= IOART_INTAHI;
289 else
290 low |= IOART_INTALO;
291 if (intpin->io_masked)
292 low |= IOART_INTMSET;
293 switch (intpin->io_vector) {
294 case VECTOR_EXTINT:
295 KASSERT(intpin->io_edgetrigger,
296 ("ExtINT not edge triggered"));
297 low |= IOART_DELEXINT;
298 break;
299 case VECTOR_NMI:
300 KASSERT(intpin->io_edgetrigger,
301 ("NMI not edge triggered"));
302 low |= IOART_DELNMI;
303 break;
304 case VECTOR_SMI:
305 KASSERT(intpin->io_edgetrigger,
306 ("SMI not edge triggered"));
307 low |= IOART_DELSMI;
308 break;
309 default:
310 low |= IOART_DELLOPRI | apic_irq_to_idt(intpin->io_vector);
311 }
312
313 /* Write the values to the APIC. */
314 mtx_lock_spin(&icu_lock);
315 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), low);
316 value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin));
317 value &= ~IOART_DEST;
318 value |= high;
319 ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value);
320 mtx_unlock_spin(&icu_lock);
321 }
322
323 /*
324 * Program an individual intpin's logical destination.
325 */
326 static void
327 ioapic_program_destination(struct ioapic_intsrc *intpin)
328 {
329 struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
330
331 KASSERT(intpin->io_dest != DEST_NONE,
332 ("intpin not assigned to a cluster"));
333 if (bootverbose) {
334 printf("ioapic%u: routing intpin %u (", io->io_id,
335 intpin->io_intpin);
336 ioapic_print_vector(intpin);
337 printf(") to cluster %u\n", intpin->io_dest);
338 }
339 ioapic_program_intpin(intpin);
340 }
341
342 static void
343 ioapic_assign_cluster(struct ioapic_intsrc *intpin)
344 {
345
346 /*
347 * Assign this intpin to a logical APIC cluster in a
348 * round-robin fashion. We don't actually use the logical
349 * destination for this intpin until after all the CPU's
350 * have been started so that we don't end up with interrupts
351 * that don't go anywhere. Another alternative might be to
352 * start up the CPU's earlier so that they can handle interrupts
353 * sooner.
354 */
355 intpin->io_dest = current_cluster;
356 current_cluster++;
357 if (current_cluster >= logical_clusters)
358 current_cluster = 0;
359 if (program_logical_dest)
360 ioapic_program_destination(intpin);
361 }
362
363 static void
364 ioapic_enable_intr(struct intsrc *isrc)
365 {
366 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
367
368 if (intpin->io_dest == DEST_NONE) {
369 ioapic_assign_cluster(intpin);
370 lapic_enable_intr(intpin->io_vector);
371 }
372 }
373
374 static int
375 ioapic_vector(struct intsrc *isrc)
376 {
377 struct ioapic_intsrc *pin;
378
379 pin = (struct ioapic_intsrc *)isrc;
380 return (pin->io_vector);
381 }
382
383 static int
384 ioapic_source_pending(struct intsrc *isrc)
385 {
386 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
387
388 return (lapic_intr_pending(intpin->io_vector));
389 }
390
391 static int
392 ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
393 enum intr_polarity pol)
394 {
395 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
396 struct ioapic *io = (struct ioapic *)isrc->is_pic;
397 int changed;
398
399 KASSERT(!(trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM),
400 ("%s: Conforming trigger or polarity\n", __func__));
401
402 /*
403 * EISA interrupts always use active high polarity, so don't allow
404 * them to be set to active low.
405 *
406 * XXX: Should we write to the ELCR if the trigger mode changes for
407 * an EISA IRQ or an ISA IRQ with the ELCR present?
408 */
409 if (intpin->io_bus == APIC_BUS_EISA)
410 pol = INTR_POLARITY_HIGH;
411 changed = 0;
412 if (intpin->io_edgetrigger != (trig == INTR_TRIGGER_EDGE)) {
413 if (bootverbose)
414 printf("ioapic%u: Changing trigger for pin %u to %s\n",
415 io->io_id, intpin->io_intpin,
416 trig == INTR_TRIGGER_EDGE ? "edge" : "level");
417 intpin->io_edgetrigger = (trig == INTR_TRIGGER_EDGE);
418 changed++;
419 }
420 if (intpin->io_activehi != (pol == INTR_POLARITY_HIGH)) {
421 if (bootverbose)
422 printf("ioapic%u: Changing polarity for pin %u to %s\n",
423 io->io_id, intpin->io_intpin,
424 pol == INTR_POLARITY_HIGH ? "high" : "low");
425 intpin->io_activehi = (pol == INTR_POLARITY_HIGH);
426 changed++;
427 }
428 if (changed)
429 ioapic_program_intpin(intpin);
430 return (0);
431 }
432
433 static void
434 ioapic_suspend(struct intsrc *isrc)
435 {
436
437 TODO;
438 }
439
440 static void
441 ioapic_resume(struct intsrc *isrc)
442 {
443
444 ioapic_program_intpin((struct ioapic_intsrc *)isrc);
445 }
446
447 /*
448 * Allocate and return a logical cluster ID. Note that the first time
449 * this is called, it returns cluster 0. ioapic_enable_intr() treats
450 * the two cases of logical_clusters == 0 and logical_clusters == 1 the
451 * same: one cluster of ID 0 exists. The logical_clusters == 0 case is
452 * for UP kernels, which should never call this function.
453 */
454 int
455 ioapic_next_logical_cluster(void)
456 {
457
458 if (logical_clusters >= APIC_MAX_CLUSTER)
459 panic("WARNING: Local APIC cluster IDs exhausted!");
460 return (logical_clusters++);
461 }
462
463 /*
464 * Create a plain I/O APIC object.
465 */
466 void *
467 ioapic_create(uintptr_t addr, int32_t apic_id, int intbase)
468 {
469 struct ioapic *io;
470 struct ioapic_intsrc *intpin;
471 volatile ioapic_t *apic;
472 u_int numintr, i;
473 uint32_t value;
474
475 /* Map the register window so we can access the device. */
476 apic = (ioapic_t *)pmap_mapdev(addr, IOAPIC_MEM_REGION);
477 mtx_lock_spin(&icu_lock);
478 value = ioapic_read(apic, IOAPIC_VER);
479 mtx_unlock_spin(&icu_lock);
480
481 /* If it's version register doesn't seem to work, punt. */
482 if (value == 0xffffff) {
483 pmap_unmapdev((vm_offset_t)apic, IOAPIC_MEM_REGION);
484 return (NULL);
485 }
486
487 /* Determine the number of vectors and set the APIC ID. */
488 numintr = ((value & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1;
489 io = malloc(sizeof(struct ioapic) +
490 numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK);
491 io->io_pic = ioapic_template;
492 mtx_lock_spin(&icu_lock);
493 io->io_id = next_id++;
494 io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT;
495 if (apic_id != -1 && io->io_apic_id != apic_id) {
496 ioapic_write(apic, IOAPIC_ID, apic_id << APIC_ID_SHIFT);
497 mtx_unlock_spin(&icu_lock);
498 io->io_apic_id = apic_id;
499 printf("ioapic%u: Changing APIC ID to %d\n", io->io_id,
500 apic_id);
501 } else
502 mtx_unlock_spin(&icu_lock);
503 if (intbase == -1) {
504 intbase = next_ioapic_base;
505 printf("ioapic%u: Assuming intbase of %d\n", io->io_id,
506 intbase);
507 } else if (intbase != next_ioapic_base)
508 printf("ioapic%u: WARNING: intbase %d != expected base %d\n",
509 io->io_id, intbase, next_ioapic_base);
510 io->io_intbase = intbase;
511 next_ioapic_base = intbase + numintr;
512 io->io_numintr = numintr;
513 io->io_addr = apic;
514
515 /*
516 * Initialize pins. Start off with interrupts disabled. Default
517 * to active-hi and edge-triggered for ISA interrupts and active-lo
518 * and level-triggered for all others.
519 */
520 bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr);
521 mtx_lock_spin(&icu_lock);
522 for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) {
523 intpin->io_intsrc.is_pic = (struct pic *)io;
524 intpin->io_intpin = i;
525 intpin->io_vector = intbase + i;
526
527 /*
528 * Assume that pin 0 on the first I/O APIC is an ExtINT pin.
529 * Assume that pins 1-15 are ISA interrupts and that all
530 * other pins are PCI interrupts.
531 */
532 if (intpin->io_vector == 0)
533 ioapic_set_extint(io, i);
534 else if (intpin->io_vector < IOAPIC_ISA_INTS) {
535 intpin->io_bus = APIC_BUS_ISA;
536 intpin->io_activehi = 1;
537 intpin->io_edgetrigger = 1;
538 intpin->io_masked = 1;
539 } else {
540 intpin->io_bus = APIC_BUS_PCI;
541 intpin->io_activehi = 0;
542 intpin->io_edgetrigger = 0;
543 intpin->io_masked = 1;
544 }
545
546 /*
547 * Route interrupts to the BSP by default using physical
548 * addressing. Vectored interrupts get readdressed using
549 * logical IDs to CPU clusters when they are enabled.
550 */
551 intpin->io_dest = DEST_NONE;
552 if (bootverbose && intpin->io_vector != VECTOR_DISABLED) {
553 printf("ioapic%u: intpin %d -> ", io->io_id, i);
554 ioapic_print_vector(intpin);
555 printf(" (%s, %s)\n", intpin->io_edgetrigger ?
556 "edge" : "level", intpin->io_activehi ? "high" :
557 "low");
558 }
559 value = ioapic_read(apic, IOAPIC_REDTBL_LO(i));
560 ioapic_write(apic, IOAPIC_REDTBL_LO(i), value | IOART_INTMSET);
561 }
562 mtx_unlock_spin(&icu_lock);
563
564 return (io);
565 }
566
567 int
568 ioapic_get_vector(void *cookie, u_int pin)
569 {
570 struct ioapic *io;
571
572 io = (struct ioapic *)cookie;
573 if (pin >= io->io_numintr)
574 return (-1);
575 return (io->io_pins[pin].io_vector);
576 }
577
578 int
579 ioapic_disable_pin(void *cookie, u_int pin)
580 {
581 struct ioapic *io;
582
583 io = (struct ioapic *)cookie;
584 if (pin >= io->io_numintr)
585 return (EINVAL);
586 if (io->io_pins[pin].io_vector == VECTOR_DISABLED)
587 return (EINVAL);
588 io->io_pins[pin].io_vector = VECTOR_DISABLED;
589 if (bootverbose)
590 printf("ioapic%u: intpin %d disabled\n", io->io_id, pin);
591 return (0);
592 }
593
594 int
595 ioapic_remap_vector(void *cookie, u_int pin, int vector)
596 {
597 struct ioapic *io;
598
599 io = (struct ioapic *)cookie;
600 if (pin >= io->io_numintr || vector < 0)
601 return (EINVAL);
602 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
603 return (EINVAL);
604 io->io_pins[pin].io_vector = vector;
605 if (bootverbose)
606 printf("ioapic%u: Routing IRQ %d -> intpin %d\n", io->io_id,
607 vector, pin);
608 return (0);
609 }
610
611 int
612 ioapic_set_bus(void *cookie, u_int pin, int bus_type)
613 {
614 struct ioapic *io;
615
616 if (bus_type < 0 || bus_type > APIC_BUS_MAX)
617 return (EINVAL);
618 io = (struct ioapic *)cookie;
619 if (pin >= io->io_numintr)
620 return (EINVAL);
621 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
622 return (EINVAL);
623 io->io_pins[pin].io_bus = bus_type;
624 if (bootverbose)
625 printf("ioapic%u: intpin %d bus %s\n", io->io_id, pin,
626 ioapic_bus_string(bus_type));
627 return (0);
628 }
629
630 int
631 ioapic_set_nmi(void *cookie, u_int pin)
632 {
633 struct ioapic *io;
634
635 io = (struct ioapic *)cookie;
636 if (pin >= io->io_numintr)
637 return (EINVAL);
638 if (io->io_pins[pin].io_vector == VECTOR_NMI)
639 return (0);
640 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
641 return (EINVAL);
642 io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
643 io->io_pins[pin].io_vector = VECTOR_NMI;
644 io->io_pins[pin].io_masked = 0;
645 io->io_pins[pin].io_edgetrigger = 1;
646 io->io_pins[pin].io_activehi = 1;
647 if (bootverbose)
648 printf("ioapic%u: Routing NMI -> intpin %d\n",
649 io->io_id, pin);
650 return (0);
651 }
652
653 int
654 ioapic_set_smi(void *cookie, u_int pin)
655 {
656 struct ioapic *io;
657
658 io = (struct ioapic *)cookie;
659 if (pin >= io->io_numintr)
660 return (EINVAL);
661 if (io->io_pins[pin].io_vector == VECTOR_SMI)
662 return (0);
663 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
664 return (EINVAL);
665 io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
666 io->io_pins[pin].io_vector = VECTOR_SMI;
667 io->io_pins[pin].io_masked = 0;
668 io->io_pins[pin].io_edgetrigger = 1;
669 io->io_pins[pin].io_activehi = 1;
670 if (bootverbose)
671 printf("ioapic%u: Routing SMI -> intpin %d\n",
672 io->io_id, pin);
673 return (0);
674 }
675
676 int
677 ioapic_set_extint(void *cookie, u_int pin)
678 {
679 struct ioapic *io;
680
681 io = (struct ioapic *)cookie;
682 if (pin >= io->io_numintr)
683 return (EINVAL);
684 if (io->io_pins[pin].io_vector == VECTOR_EXTINT)
685 return (0);
686 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
687 return (EINVAL);
688 io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
689 io->io_pins[pin].io_vector = VECTOR_EXTINT;
690 if (enable_extint)
691 io->io_pins[pin].io_masked = 0;
692 else
693 io->io_pins[pin].io_masked = 1;
694 io->io_pins[pin].io_edgetrigger = 1;
695 io->io_pins[pin].io_activehi = 1;
696 if (bootverbose)
697 printf("ioapic%u: Routing external 8259A's -> intpin %d\n",
698 io->io_id, pin);
699 return (0);
700 }
701
702 int
703 ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol)
704 {
705 struct ioapic *io;
706
707 io = (struct ioapic *)cookie;
708 if (pin >= io->io_numintr || pol == INTR_POLARITY_CONFORM)
709 return (EINVAL);
710 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
711 return (EINVAL);
712 io->io_pins[pin].io_activehi = (pol == INTR_POLARITY_HIGH);
713 if (bootverbose)
714 printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin,
715 pol == INTR_POLARITY_HIGH ? "high" : "low");
716 return (0);
717 }
718
719 int
720 ioapic_set_triggermode(void *cookie, u_int pin, enum intr_trigger trigger)
721 {
722 struct ioapic *io;
723
724 io = (struct ioapic *)cookie;
725 if (pin >= io->io_numintr || trigger == INTR_TRIGGER_CONFORM)
726 return (EINVAL);
727 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
728 return (EINVAL);
729 io->io_pins[pin].io_edgetrigger = (trigger == INTR_TRIGGER_EDGE);
730 if (bootverbose)
731 printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin,
732 trigger == INTR_TRIGGER_EDGE ? "edge" : "level");
733 return (0);
734 }
735
736 /*
737 * Register a complete I/O APIC object with the interrupt subsystem.
738 */
739 void
740 ioapic_register(void *cookie)
741 {
742 struct ioapic_intsrc *pin;
743 struct ioapic *io;
744 volatile ioapic_t *apic;
745 uint32_t flags;
746 int i;
747
748 io = (struct ioapic *)cookie;
749 apic = io->io_addr;
750 mtx_lock_spin(&icu_lock);
751 flags = ioapic_read(apic, IOAPIC_VER) & IOART_VER_VERSION;
752 STAILQ_INSERT_TAIL(&ioapic_list, io, io_next);
753 mtx_unlock_spin(&icu_lock);
754 printf("ioapic%u <Version %u.%u> irqs %u-%u on motherboard\n",
755 io->io_id, flags >> 4, flags & 0xf, io->io_intbase,
756 io->io_intbase + io->io_numintr - 1);
757 bsp_id = PCPU_GET(apic_id);
758 for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++) {
759 /*
760 * Finish initializing the pins by programming the vectors
761 * and delivery mode.
762 */
763 if (pin->io_vector == VECTOR_DISABLED)
764 continue;
765 ioapic_program_intpin(pin);
766 if (pin->io_vector >= NUM_IO_INTS)
767 continue;
768 intr_register_source(&pin->io_intsrc);
769 }
770 }
771
772 /*
773 * Program all the intpins to use logical destinations once the AP's
774 * have been launched.
775 */
776 static void
777 ioapic_set_logical_destinations(void *arg __unused)
778 {
779 struct ioapic *io;
780 int i;
781
782 program_logical_dest = 1;
783 STAILQ_FOREACH(io, &ioapic_list, io_next)
784 for (i = 0; i < io->io_numintr; i++)
785 if (io->io_pins[i].io_dest != DEST_NONE)
786 ioapic_program_destination(&io->io_pins[i]);
787 }
788 SYSINIT(ioapic_destinations, SI_SUB_SMP, SI_ORDER_SECOND,
789 ioapic_set_logical_destinations, NULL)
Cache object: 711cb75b2375ec12264d9c2fc4719b10
|