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/5.2/sys/amd64/amd64/io_apic.c 122849 2003-11-17 08:58:16Z peter $");
32
33 #include "opt_atpic.h"
34 #include "opt_isa.h"
35 #include "opt_no_mixed_mode.h"
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/bus.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/lock.h>
43 #include <sys/mutex.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 #if defined(DEV_ISA) && defined(DEV_ATPIC) && !defined(NO_MIXED_MODE)
55 #define MIXED_MODE
56 #endif
57
58 #define IOAPIC_ISA_INTS 16
59 #define IOAPIC_MEM_REGION 32
60 #define IOAPIC_REDTBL_LO(i) (IOAPIC_REDTBL + (i) * 2)
61 #define IOAPIC_REDTBL_HI(i) (IOAPIC_REDTBL_LO(i) + 1)
62
63 #define VECTOR_EXTINT 252
64 #define VECTOR_NMI 253
65 #define VECTOR_SMI 254
66 #define VECTOR_DISABLED 255
67
68 #define DEST_NONE -1
69 #define DEST_EXTINT -2
70
71 #define TODO printf("%s: not implemented!\n", __func__)
72
73 MALLOC_DEFINE(M_IOAPIC, "I/O APIC", "I/O APIC structures");
74
75 /*
76 * New interrupt support code..
77 *
78 * XXX: we really should have the interrupt cookie passed up from new-bus
79 * just be a int pin, and not map 1:1 to interrupt vector number but should
80 * use INTR_TYPE_FOO to set priority bands for device classes and do all the
81 * magic remapping of intpin to vector in here. For now we just cheat as on
82 * ia64 and map intpin X to vector NRSVIDT + X. Note that we assume that the
83 * first IO APIC has ISA interrupts on pins 1-15. Not sure how you are
84 * really supposed to figure out which IO APIC in a system with multiple IO
85 * APIC's actually has the ISA interrupts routed to it. As far as interrupt
86 * pin numbers, we use the ACPI System Interrupt number model where each
87 * IO APIC has a contiguous chunk of the System Interrupt address space.
88 */
89
90 /*
91 * Direct the ExtINT pin on the first I/O APIC to a logical cluster of
92 * CPUs rather than a physical destination of just the BSP.
93 *
94 * Note: This is disabled by default as test systems seem to croak with it
95 * enabled.
96 #define ENABLE_EXTINT_LOGICAL_DESTINATION
97 */
98
99 struct ioapic_intsrc {
100 struct intsrc io_intsrc;
101 u_int io_intpin:8;
102 u_int io_vector:8;
103 u_int io_activehi:1;
104 u_int io_edgetrigger:1;
105 u_int io_masked:1;
106 int io_dest:5;
107 };
108
109 struct ioapic {
110 struct pic io_pic;
111 u_int io_id:8; /* logical ID */
112 u_int io_apic_id:4;
113 u_int io_intbase:8; /* System Interrupt base */
114 u_int io_numintr:8;
115 volatile ioapic_t *io_addr; /* XXX: should use bus_space */
116 STAILQ_ENTRY(ioapic) io_next;
117 struct ioapic_intsrc io_pins[0];
118 };
119
120 static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
121 static u_int next_id, program_logical_dest;
122
123 static u_int ioapic_read(volatile ioapic_t *apic, int reg);
124 static void ioapic_write(volatile ioapic_t *apic, int reg, u_int val);
125 static void ioapic_enable_source(struct intsrc *isrc);
126 static void ioapic_disable_source(struct intsrc *isrc);
127 static void ioapic_eoi_source(struct intsrc *isrc);
128 static void ioapic_enable_intr(struct intsrc *isrc);
129 static int ioapic_vector(struct intsrc *isrc);
130 static int ioapic_source_pending(struct intsrc *isrc);
131 static void ioapic_suspend(struct intsrc *isrc);
132 static void ioapic_resume(struct intsrc *isrc);
133 static void ioapic_program_destination(struct ioapic_intsrc *intpin);
134 #ifdef MIXED_MODE
135 static void ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin);
136 #endif
137
138 struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source,
139 ioapic_eoi_source, ioapic_enable_intr,
140 ioapic_vector, ioapic_source_pending,
141 ioapic_suspend, ioapic_resume };
142
143 static int next_ioapic_base, logical_clusters, current_cluster;
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 void
164 ioapic_enable_source(struct intsrc *isrc)
165 {
166 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
167 struct ioapic *io = (struct ioapic *)isrc->is_pic;
168 uint32_t flags;
169
170 mtx_lock_spin(&icu_lock);
171 if (intpin->io_masked) {
172 flags = ioapic_read(io->io_addr,
173 IOAPIC_REDTBL_LO(intpin->io_intpin));
174 flags &= ~(IOART_INTMASK);
175 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
176 flags);
177 intpin->io_masked = 0;
178 }
179 mtx_unlock_spin(&icu_lock);
180 }
181
182 static void
183 ioapic_disable_source(struct intsrc *isrc)
184 {
185 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
186 struct ioapic *io = (struct ioapic *)isrc->is_pic;
187 uint32_t flags;
188
189 mtx_lock_spin(&icu_lock);
190 if (!intpin->io_masked && !intpin->io_edgetrigger) {
191 flags = ioapic_read(io->io_addr,
192 IOAPIC_REDTBL_LO(intpin->io_intpin));
193 flags |= IOART_INTMSET;
194 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
195 flags);
196 intpin->io_masked = 1;
197 }
198 mtx_unlock_spin(&icu_lock);
199 }
200
201 static void
202 ioapic_eoi_source(struct intsrc *isrc)
203 {
204
205 lapic_eoi();
206 }
207
208 /*
209 * Program an individual intpin's logical destination.
210 */
211 static void
212 ioapic_program_destination(struct ioapic_intsrc *intpin)
213 {
214 struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
215 uint32_t value;
216
217 KASSERT(intpin->io_dest != DEST_NONE,
218 ("intpin not assigned to a cluster"));
219 KASSERT(intpin->io_dest != DEST_EXTINT,
220 ("intpin routed via ExtINT"));
221 if (bootverbose) {
222 printf("ioapic%u: routing intpin %u (", io->io_id,
223 intpin->io_intpin);
224 if (intpin->io_vector == VECTOR_EXTINT)
225 printf("ExtINT");
226 else
227 printf("IRQ %u", intpin->io_vector);
228 printf(") to cluster %u\n", intpin->io_dest);
229 }
230 mtx_lock_spin(&icu_lock);
231 value = ioapic_read(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin));
232 value &= ~IOART_DESTMOD;
233 value |= IOART_DESTLOG;
234 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), value);
235 value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin));
236 value &= ~IOART_DEST;
237 value |= (intpin->io_dest << APIC_ID_CLUSTER_SHIFT |
238 APIC_ID_CLUSTER_ID) << APIC_ID_SHIFT;
239 ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value);
240 mtx_unlock_spin(&icu_lock);
241 }
242
243 static void
244 ioapic_assign_cluster(struct ioapic_intsrc *intpin)
245 {
246
247 /*
248 * Assign this intpin to a logical APIC cluster in a
249 * round-robin fashion. We don't actually use the logical
250 * destination for this intpin until after all the CPU's
251 * have been started so that we don't end up with interrupts
252 * that don't go anywhere. Another alternative might be to
253 * start up the CPU's earlier so that they can handle interrupts
254 * sooner.
255 */
256 intpin->io_dest = current_cluster;
257 current_cluster++;
258 if (current_cluster >= logical_clusters)
259 current_cluster = 0;
260 if (program_logical_dest)
261 ioapic_program_destination(intpin);
262 }
263
264 static void
265 ioapic_enable_intr(struct intsrc *isrc)
266 {
267 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
268
269 KASSERT(intpin->io_dest != DEST_EXTINT,
270 ("ExtINT pin trying to use ioapic enable_intr method"));
271 if (intpin->io_dest == DEST_NONE) {
272 ioapic_assign_cluster(intpin);
273 lapic_enable_intr(intpin->io_vector);
274 }
275 }
276
277 static int
278 ioapic_vector(struct intsrc *isrc)
279 {
280 struct ioapic_intsrc *pin;
281
282 pin = (struct ioapic_intsrc *)isrc;
283 return (pin->io_vector);
284 }
285
286 static int
287 ioapic_source_pending(struct intsrc *isrc)
288 {
289 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
290
291 return (lapic_intr_pending(intpin->io_vector));
292 }
293
294 static void
295 ioapic_suspend(struct intsrc *isrc)
296 {
297
298 TODO;
299 }
300
301 static void
302 ioapic_resume(struct intsrc *isrc)
303 {
304
305 TODO;
306 }
307
308 /*
309 * Allocate and return a logical cluster ID. Note that the first time
310 * this is called, it returns cluster 0. ioapic_enable_intr() treats
311 * the two cases of logical_clusters == 0 and logical_clusters == 1 the
312 * same: one cluster of ID 0 exists. The logical_clusters == 0 case is
313 * for UP kernels, which should never call this function.
314 */
315 int
316 ioapic_next_logical_cluster(void)
317 {
318
319 if (logical_clusters >= APIC_MAX_CLUSTER)
320 panic("WARNING: Local APIC cluster IDs exhausted!");
321 return (logical_clusters++);
322 }
323
324 /*
325 * Create a plain I/O APIC object.
326 */
327 void *
328 ioapic_create(uintptr_t addr, int32_t apic_id, int intbase)
329 {
330 struct ioapic *io;
331 struct ioapic_intsrc *intpin;
332 volatile ioapic_t *apic;
333 u_int numintr, i;
334 uint32_t value;
335
336 apic = (ioapic_t *)pmap_mapdev(addr, IOAPIC_MEM_REGION);
337 mtx_lock_spin(&icu_lock);
338 numintr = ((ioapic_read(apic, IOAPIC_VER) & IOART_VER_MAXREDIR) >>
339 MAXREDIRSHIFT) + 1;
340 mtx_unlock_spin(&icu_lock);
341 io = malloc(sizeof(struct ioapic) +
342 numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK);
343 io->io_pic = ioapic_template;
344 mtx_lock_spin(&icu_lock);
345 io->io_id = next_id++;
346 io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT;
347 if (apic_id != -1 && io->io_apic_id != apic_id) {
348 ioapic_write(apic, IOAPIC_ID, apic_id << APIC_ID_SHIFT);
349 mtx_unlock_spin(&icu_lock);
350 io->io_apic_id = apic_id;
351 printf("ioapic%u: Changing APIC ID to %d\n", io->io_id,
352 apic_id);
353 } else
354 mtx_unlock_spin(&icu_lock);
355 if (intbase == -1) {
356 intbase = next_ioapic_base;
357 printf("ioapic%u: Assuming intbase of %d\n", io->io_id,
358 intbase);
359 } else if (intbase != next_ioapic_base)
360 printf("ioapic%u: WARNING: intbase %d != expected base %d\n",
361 io->io_id, intbase, next_ioapic_base);
362 io->io_intbase = intbase;
363 next_ioapic_base = intbase + numintr;
364 io->io_numintr = numintr;
365 io->io_addr = apic;
366
367 /*
368 * Initialize pins. Start off with interrupts disabled. Default
369 * to active-hi and edge-triggered for ISA interrupts and active-lo
370 * and level-triggered for all others.
371 */
372 bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr);
373 mtx_lock_spin(&icu_lock);
374 for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) {
375 intpin->io_intsrc.is_pic = (struct pic *)io;
376 intpin->io_intpin = i;
377 intpin->io_vector = intbase + i;
378
379 /*
380 * Assume that pin 0 on the first IO APIC is an ExtINT pin by
381 * default. Assume that intpins 1-15 are ISA interrupts and
382 * use suitable defaults for those. Assume that all other
383 * intpins are PCI interrupts. Enable the ExtINT pin by
384 * default but mask all other pins.
385 */
386 if (intpin->io_vector == 0) {
387 intpin->io_activehi = 1;
388 intpin->io_edgetrigger = 1;
389 intpin->io_vector = VECTOR_EXTINT;
390 intpin->io_masked = 0;
391 } else if (intpin->io_vector < IOAPIC_ISA_INTS) {
392 intpin->io_activehi = 1;
393 intpin->io_edgetrigger = 1;
394 intpin->io_masked = 1;
395 } else {
396 intpin->io_activehi = 0;
397 intpin->io_edgetrigger = 0;
398 intpin->io_masked = 1;
399 }
400
401 /*
402 * Start off without a logical cluster destination until
403 * the pin is enabled.
404 */
405 intpin->io_dest = DEST_NONE;
406 if (bootverbose) {
407 printf("ioapic%u: intpin %d -> ", io->io_id, i);
408 if (intpin->io_vector == VECTOR_EXTINT)
409 printf("ExtINT");
410 else
411 printf("irq %u", intpin->io_vector);
412 printf(" (%s, active%s)\n", intpin->io_edgetrigger ?
413 "edge" : "level", intpin->io_activehi ? "hi" :
414 "lo");
415 }
416 value = ioapic_read(apic, IOAPIC_REDTBL_LO(i));
417 ioapic_write(apic, IOAPIC_REDTBL_LO(i), value | IOART_INTMSET);
418 }
419 mtx_unlock_spin(&icu_lock);
420
421 return (io);
422 }
423
424 int
425 ioapic_get_vector(void *cookie, u_int pin)
426 {
427 struct ioapic *io;
428
429 io = (struct ioapic *)cookie;
430 if (pin >= io->io_numintr)
431 return (-1);
432 return (io->io_pins[pin].io_vector);
433 }
434
435 int
436 ioapic_disable_pin(void *cookie, u_int pin)
437 {
438 struct ioapic *io;
439
440 io = (struct ioapic *)cookie;
441 if (pin >= io->io_numintr)
442 return (EINVAL);
443 if (io->io_pins[pin].io_vector == VECTOR_DISABLED)
444 return (EINVAL);
445 io->io_pins[pin].io_vector = VECTOR_DISABLED;
446 if (bootverbose)
447 printf("ioapic%u: intpin %d disabled\n", io->io_id, pin);
448 return (0);
449 }
450
451 int
452 ioapic_remap_vector(void *cookie, u_int pin, int vector)
453 {
454 struct ioapic *io;
455
456 io = (struct ioapic *)cookie;
457 if (pin >= io->io_numintr || vector < 0)
458 return (EINVAL);
459 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
460 return (EINVAL);
461 io->io_pins[pin].io_vector = vector;
462 if (bootverbose)
463 printf("ioapic%u: Routing IRQ %d -> intpin %d\n", io->io_id,
464 vector, pin);
465 return (0);
466 }
467
468 int
469 ioapic_set_nmi(void *cookie, u_int pin)
470 {
471 struct ioapic *io;
472
473 io = (struct ioapic *)cookie;
474 if (pin >= io->io_numintr)
475 return (EINVAL);
476 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
477 return (EINVAL);
478 io->io_pins[pin].io_vector = VECTOR_NMI;
479 io->io_pins[pin].io_masked = 0;
480 io->io_pins[pin].io_edgetrigger = 1;
481 io->io_pins[pin].io_activehi = 1;
482 if (bootverbose)
483 printf("ioapic%u: Routing NMI -> intpin %d\n",
484 io->io_id, pin);
485 return (0);
486 }
487
488 int
489 ioapic_set_smi(void *cookie, u_int pin)
490 {
491 struct ioapic *io;
492
493 io = (struct ioapic *)cookie;
494 if (pin >= io->io_numintr)
495 return (EINVAL);
496 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
497 return (EINVAL);
498 io->io_pins[pin].io_vector = VECTOR_SMI;
499 io->io_pins[pin].io_masked = 0;
500 io->io_pins[pin].io_edgetrigger = 1;
501 io->io_pins[pin].io_activehi = 1;
502 if (bootverbose)
503 printf("ioapic%u: Routing SMI -> intpin %d\n",
504 io->io_id, pin);
505 return (0);
506 }
507
508 int
509 ioapic_set_extint(void *cookie, u_int pin)
510 {
511 struct ioapic *io;
512
513 io = (struct ioapic *)cookie;
514 if (pin >= io->io_numintr)
515 return (EINVAL);
516 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
517 return (EINVAL);
518 io->io_pins[pin].io_vector = VECTOR_EXTINT;
519 io->io_pins[pin].io_masked = 0;
520 io->io_pins[pin].io_edgetrigger = 1;
521 io->io_pins[pin].io_activehi = 1;
522 if (bootverbose)
523 printf("ioapic%u: Routing external 8259A's -> intpin %d\n",
524 io->io_id, pin);
525 return (0);
526 }
527
528 int
529 ioapic_set_polarity(void *cookie, u_int pin, char activehi)
530 {
531 struct ioapic *io;
532
533 io = (struct ioapic *)cookie;
534 if (pin >= io->io_numintr)
535 return (EINVAL);
536 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
537 return (EINVAL);
538 io->io_pins[pin].io_activehi = activehi;
539 if (bootverbose)
540 printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin,
541 activehi ? "active-hi" : "active-lo");
542 return (0);
543 }
544
545 int
546 ioapic_set_triggermode(void *cookie, u_int pin, char edgetrigger)
547 {
548 struct ioapic *io;
549
550 io = (struct ioapic *)cookie;
551 if (pin >= io->io_numintr)
552 return (EINVAL);
553 if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
554 return (EINVAL);
555 io->io_pins[pin].io_edgetrigger = edgetrigger;
556 if (bootverbose)
557 printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin,
558 edgetrigger ? "edge" : "level");
559 return (0);
560 }
561
562 /*
563 * Register a complete I/O APIC object with the interrupt subsystem.
564 */
565 void
566 ioapic_register(void *cookie)
567 {
568 struct ioapic_intsrc *pin;
569 struct ioapic *io;
570 volatile ioapic_t *apic;
571 uint32_t flags;
572 int i;
573
574 io = (struct ioapic *)cookie;
575 apic = io->io_addr;
576 mtx_lock_spin(&icu_lock);
577 flags = ioapic_read(apic, IOAPIC_VER) & IOART_VER_VERSION;
578 STAILQ_INSERT_TAIL(&ioapic_list, io, io_next);
579 mtx_unlock_spin(&icu_lock);
580 printf("ioapic%u <Version %u.%u> irqs %u-%u on motherboard\n",
581 io->io_id, flags >> 4, flags & 0xf, io->io_intbase,
582 io->io_intbase + io->io_numintr - 1);
583 for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++) {
584 /*
585 * Finish initializing the pins by programming the vectors
586 * and delivery mode.
587 */
588 if (pin->io_vector == VECTOR_DISABLED)
589 continue;
590 flags = IOART_DESTPHY;
591 if (pin->io_edgetrigger)
592 flags |= IOART_TRGREDG;
593 else
594 flags |= IOART_TRGRLVL;
595 if (pin->io_activehi)
596 flags |= IOART_INTAHI;
597 else
598 flags |= IOART_INTALO;
599 if (pin->io_masked)
600 flags |= IOART_INTMSET;
601 switch (pin->io_vector) {
602 case VECTOR_EXTINT:
603 KASSERT(pin->io_edgetrigger,
604 ("EXTINT not edge triggered"));
605 flags |= IOART_DELEXINT;
606 break;
607 case VECTOR_NMI:
608 KASSERT(pin->io_edgetrigger,
609 ("NMI not edge triggered"));
610 flags |= IOART_DELNMI;
611 break;
612 case VECTOR_SMI:
613 KASSERT(pin->io_edgetrigger,
614 ("SMI not edge triggered"));
615 flags |= IOART_DELSMI;
616 break;
617 default:
618 flags |= IOART_DELLOPRI |
619 apic_irq_to_idt(pin->io_vector);
620 }
621 mtx_lock_spin(&icu_lock);
622 ioapic_write(apic, IOAPIC_REDTBL_LO(i), flags);
623
624 /*
625 * Route interrupts to the BSP by default using physical
626 * addressing. Vectored interrupts get readdressed using
627 * logical IDs to CPU clusters when they are enabled.
628 */
629 flags = ioapic_read(apic, IOAPIC_REDTBL_HI(i));
630 flags &= ~IOART_DEST;
631 flags |= PCPU_GET(apic_id) << APIC_ID_SHIFT;
632 ioapic_write(apic, IOAPIC_REDTBL_HI(i), flags);
633 mtx_unlock_spin(&icu_lock);
634 if (pin->io_vector < NUM_IO_INTS) {
635 #ifdef MIXED_MODE
636 /* Route IRQ0 via the 8259A using mixed mode. */
637 if (pin->io_vector == 0)
638 ioapic_setup_mixed_mode(pin);
639 else
640 #endif
641 intr_register_source(&pin->io_intsrc);
642 }
643
644 }
645 }
646
647 /*
648 * Program all the intpins to use logical destinations once the AP's
649 * have been launched.
650 */
651 static void
652 ioapic_set_logical_destinations(void *arg __unused)
653 {
654 struct ioapic *io;
655 int i;
656
657 program_logical_dest = 1;
658 STAILQ_FOREACH(io, &ioapic_list, io_next)
659 for (i = 0; i < io->io_numintr; i++)
660 if (io->io_pins[i].io_dest != DEST_NONE &&
661 io->io_pins[i].io_dest != DEST_EXTINT)
662 ioapic_program_destination(&io->io_pins[i]);
663 }
664 SYSINIT(ioapic_destinations, SI_SUB_SMP, SI_ORDER_SECOND,
665 ioapic_set_logical_destinations, NULL)
666
667 #ifdef MIXED_MODE
668 /*
669 * Support for mixed-mode interrupt sources. These sources route an ISA
670 * IRQ through the 8259A's via the ExtINT on pin 0 of the I/O APIC that
671 * routes the ISA interrupts. We just ignore the intpins that use this
672 * mode and allow the atpic driver to register its interrupt source for
673 * that IRQ instead.
674 */
675
676 void
677 ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin)
678 {
679 struct ioapic_intsrc *extint;
680 struct ioapic *io;
681
682 /*
683 * Mark the associated I/O APIC intpin as being delivered via
684 * ExtINT and enable the ExtINT pin on the I/O APIC if needed.
685 */
686 intpin->io_dest = DEST_EXTINT;
687 io = (struct ioapic *)intpin->io_intsrc.is_pic;
688 extint = &io->io_pins[0];
689 if (extint->io_vector != VECTOR_EXTINT)
690 panic("Can't find ExtINT pin to route through!");
691 #ifdef ENABLE_EXTINT_LOGICAL_DESTINATION
692 if (extint->io_dest == DEST_NONE)
693 ioapic_assign_cluster(extint);
694 #endif
695 }
696
697 #endif /* MIXED_MODE */
Cache object: 6284d91fbca790a068fedb016667fed7
|