f7467cf1ca04eaabf4affb24dfa8681e9767c1c4
[dragonfly.git] / sys / platform / pc32 / apic / mpapic.c
1 /*
2  * Copyright (c) 1996, by Steve Passe
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. The name of the developer may NOT be used to endorse or promote products
11  *    derived from this software without specific prior written permission.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD: src/sys/i386/i386/mpapic.c,v 1.37.2.7 2003/01/25 02:31:47 peter Exp $
26  */
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/bus.h>
32 #include <sys/machintr.h>
33 #include <machine/globaldata.h>
34 #include <machine/smp.h>
35 #include <machine/cputypes.h>
36 #include <machine/md_var.h>
37 #include <machine/pmap.h>
38 #include <machine_base/apic/mpapic.h>
39 #include <machine_base/apic/ioapic_abi.h>
40 #include <machine/segments.h>
41 #include <sys/thread2.h>
42
43 #include <machine/intr_machdep.h>
44
45 /* XXX */
46 extern pt_entry_t *SMPpt;
47
48 /* EISA Edge/Level trigger control registers */
49 #define ELCR0   0x4d0                   /* eisa irq 0-7 */
50 #define ELCR1   0x4d1                   /* eisa irq 8-15 */
51
52 struct ioapic_info {
53         int             io_idx;
54         int             io_apic_id;
55         void            *io_addr;
56         int             io_npin;
57         int             io_gsi_base;
58
59         TAILQ_ENTRY(ioapic_info) io_link;
60 };
61 TAILQ_HEAD(ioapic_info_list, ioapic_info);
62
63 struct ioapic_conf {
64         struct ioapic_info_list ioc_list;
65         int             ioc_intsrc[16]; /* XXX magic number */
66 };
67
68 static void     lapic_timer_calibrate(void);
69 static void     lapic_timer_set_divisor(int);
70 static void     lapic_timer_fixup_handler(void *);
71 static void     lapic_timer_restart_handler(void *);
72
73 void            lapic_timer_process(void);
74 void            lapic_timer_process_frame(struct intrframe *);
75
76 static int      lapic_timer_enable = 1;
77 TUNABLE_INT("hw.lapic_timer_enable", &lapic_timer_enable);
78
79 static void     lapic_timer_intr_reload(struct cputimer_intr *, sysclock_t);
80 static void     lapic_timer_intr_enable(struct cputimer_intr *);
81 static void     lapic_timer_intr_restart(struct cputimer_intr *);
82 static void     lapic_timer_intr_pmfixup(struct cputimer_intr *);
83
84 static void     ioapic_setup(const struct ioapic_info *);
85 static void     ioapic_set_apic_id(const struct ioapic_info *);
86 static void     ioapic_gsi_setup(int);
87 static const struct ioapic_info *
88                 ioapic_gsi_search(int);
89 static void     ioapic_pin_prog(void *, int, int,
90                     enum intr_trigger, enum intr_polarity, uint32_t);
91
92 static struct cputimer_intr lapic_cputimer_intr = {
93         .freq = 0,
94         .reload = lapic_timer_intr_reload,
95         .enable = lapic_timer_intr_enable,
96         .config = cputimer_intr_default_config,
97         .restart = lapic_timer_intr_restart,
98         .pmfixup = lapic_timer_intr_pmfixup,
99         .initclock = cputimer_intr_default_initclock,
100         .next = SLIST_ENTRY_INITIALIZER,
101         .name = "lapic",
102         .type = CPUTIMER_INTR_LAPIC,
103         .prio = CPUTIMER_INTR_PRIO_LAPIC,
104         .caps = CPUTIMER_INTR_CAP_NONE
105 };
106
107 /*
108  * pointers to pmapped apic hardware.
109  */
110
111 volatile ioapic_t       **ioapic;
112
113 static int              lapic_timer_divisor_idx = -1;
114 static const uint32_t   lapic_timer_divisors[] = {
115         APIC_TDCR_2,    APIC_TDCR_4,    APIC_TDCR_8,    APIC_TDCR_16,
116         APIC_TDCR_32,   APIC_TDCR_64,   APIC_TDCR_128,  APIC_TDCR_1
117 };
118 #define APIC_TIMER_NDIVISORS (int)(NELEM(lapic_timer_divisors))
119
120 int                     lapic_id_max;
121
122 static struct ioapic_conf       ioapic_conf;
123
124 /*
125  * Enable LAPIC, configure interrupts.
126  */
127 void
128 lapic_init(boolean_t bsp)
129 {
130         uint32_t timer;
131         u_int   temp;
132
133         /*
134          * Install vectors
135          *
136          * Since IDT is shared between BSP and APs, these vectors
137          * only need to be installed once; we do it on BSP.
138          */
139         if (bsp) {
140                 /* Install a 'Spurious INTerrupt' vector */
141                 setidt(XSPURIOUSINT_OFFSET, Xspuriousint,
142                     SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
143
144                 /* Install an inter-CPU IPI for TLB invalidation */
145                 setidt(XINVLTLB_OFFSET, Xinvltlb,
146                     SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
147
148                 /* Install an inter-CPU IPI for IPIQ messaging */
149                 setidt(XIPIQ_OFFSET, Xipiq,
150                     SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
151
152                 /* Install a timer vector */
153                 setidt(XTIMER_OFFSET, Xtimer,
154                     SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
155                 
156                 /* Install an inter-CPU IPI for CPU stop/restart */
157                 setidt(XCPUSTOP_OFFSET, Xcpustop,
158                     SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
159         }
160
161         /*
162          * Setup LINT0 as ExtINT on the BSP.  This is theoretically an
163          * aggregate interrupt input from the 8259.  The INTA cycle
164          * will be routed to the external controller (the 8259) which
165          * is expected to supply the vector.
166          *
167          * Must be setup edge triggered, active high.
168          *
169          * Disable LINT0 on BSP, if I/O APIC is enabled.
170          *
171          * Disable LINT0 on the APs.  It doesn't matter what delivery
172          * mode we use because we leave it masked.
173          */
174         temp = lapic.lvt_lint0;
175         temp &= ~(APIC_LVT_MASKED | APIC_LVT_TRIG_MASK | 
176                   APIC_LVT_POLARITY_MASK | APIC_LVT_DM_MASK);
177         if (bsp) {
178                 temp |= APIC_LVT_DM_EXTINT;
179                 if (apic_io_enable)
180                         temp |= APIC_LVT_MASKED;
181         } else {
182                 temp |= APIC_LVT_DM_FIXED | APIC_LVT_MASKED;
183         }
184         lapic.lvt_lint0 = temp;
185
186         /*
187          * Setup LINT1 as NMI.
188          *
189          * Must be setup edge trigger, active high.
190          *
191          * Enable LINT1 on BSP, if I/O APIC is enabled.
192          *
193          * Disable LINT1 on the APs.
194          */
195         temp = lapic.lvt_lint1;
196         temp &= ~(APIC_LVT_MASKED | APIC_LVT_TRIG_MASK | 
197                   APIC_LVT_POLARITY_MASK | APIC_LVT_DM_MASK);
198         temp |= APIC_LVT_MASKED | APIC_LVT_DM_NMI;
199         if (bsp && apic_io_enable)
200                 temp &= ~APIC_LVT_MASKED;
201         lapic.lvt_lint1 = temp;
202
203         /*
204          * Mask the LAPIC error interrupt, LAPIC performance counter
205          * interrupt.
206          */
207         lapic.lvt_error = lapic.lvt_error | APIC_LVT_MASKED;
208         lapic.lvt_pcint = lapic.lvt_pcint | APIC_LVT_MASKED;
209
210         /*
211          * Set LAPIC timer vector and mask the LAPIC timer interrupt.
212          */
213         timer = lapic.lvt_timer;
214         timer &= ~APIC_LVTT_VECTOR;
215         timer |= XTIMER_OFFSET;
216         timer |= APIC_LVTT_MASKED;
217         lapic.lvt_timer = timer;
218
219         /*
220          * Set the Task Priority Register as needed.   At the moment allow
221          * interrupts on all cpus (the APs will remain CLId until they are
222          * ready to deal).  We could disable all but IPIs by setting
223          * temp |= TPR_IPI for cpu != 0.
224          */
225         temp = lapic.tpr;
226         temp &= ~APIC_TPR_PRIO;         /* clear priority field */
227 #ifdef SMP /* APIC-IO */
228 if (!apic_io_enable) {
229 #endif
230         /*
231          * If we are NOT running the IO APICs, the LAPIC will only be used
232          * for IPIs.  Set the TPR to prevent any unintentional interrupts.
233          */
234         temp |= TPR_IPI;
235 #ifdef SMP /* APIC-IO */
236 }
237 #endif
238
239         lapic.tpr = temp;
240
241         /* 
242          * Enable the LAPIC 
243          */
244         temp = lapic.svr;
245         temp |= APIC_SVR_ENABLE;        /* enable the LAPIC */
246         temp &= ~APIC_SVR_FOCUS_DISABLE; /* enable lopri focus processor */
247
248         /*
249          * Set the spurious interrupt vector.  The low 4 bits of the vector
250          * must be 1111.
251          */
252         if ((XSPURIOUSINT_OFFSET & 0x0F) != 0x0F)
253                 panic("bad XSPURIOUSINT_OFFSET: 0x%08x", XSPURIOUSINT_OFFSET);
254         temp &= ~APIC_SVR_VECTOR;
255         temp |= XSPURIOUSINT_OFFSET;
256
257         lapic.svr = temp;
258
259         /*
260          * Pump out a few EOIs to clean out interrupts that got through
261          * before we were able to set the TPR.
262          */
263         lapic.eoi = 0;
264         lapic.eoi = 0;
265         lapic.eoi = 0;
266
267         if (bsp) {
268                 lapic_timer_calibrate();
269                 if (lapic_timer_enable) {
270                         cputimer_intr_register(&lapic_cputimer_intr);
271                         cputimer_intr_select(&lapic_cputimer_intr, 0);
272                 }
273         } else {
274                 lapic_timer_set_divisor(lapic_timer_divisor_idx);
275         }
276
277         if (bootverbose)
278                 apic_dump("apic_initialize()");
279 }
280
281 static void
282 lapic_timer_set_divisor(int divisor_idx)
283 {
284         KKASSERT(divisor_idx >= 0 && divisor_idx < APIC_TIMER_NDIVISORS);
285         lapic.dcr_timer = lapic_timer_divisors[divisor_idx];
286 }
287
288 static void
289 lapic_timer_oneshot(u_int count)
290 {
291         uint32_t value;
292
293         value = lapic.lvt_timer;
294         value &= ~APIC_LVTT_PERIODIC;
295         lapic.lvt_timer = value;
296         lapic.icr_timer = count;
297 }
298
299 static void
300 lapic_timer_oneshot_quick(u_int count)
301 {
302         lapic.icr_timer = count;
303 }
304
305 static void
306 lapic_timer_calibrate(void)
307 {
308         sysclock_t value;
309
310         /* Try to calibrate the local APIC timer. */
311         for (lapic_timer_divisor_idx = 0;
312              lapic_timer_divisor_idx < APIC_TIMER_NDIVISORS;
313              lapic_timer_divisor_idx++) {
314                 lapic_timer_set_divisor(lapic_timer_divisor_idx);
315                 lapic_timer_oneshot(APIC_TIMER_MAX_COUNT);
316                 DELAY(2000000);
317                 value = APIC_TIMER_MAX_COUNT - lapic.ccr_timer;
318                 if (value != APIC_TIMER_MAX_COUNT)
319                         break;
320         }
321         if (lapic_timer_divisor_idx >= APIC_TIMER_NDIVISORS)
322                 panic("lapic: no proper timer divisor?!\n");
323         lapic_cputimer_intr.freq = value / 2;
324
325         kprintf("lapic: divisor index %d, frequency %u Hz\n",
326                 lapic_timer_divisor_idx, lapic_cputimer_intr.freq);
327 }
328
329 static void
330 lapic_timer_process_oncpu(struct globaldata *gd, struct intrframe *frame)
331 {
332         sysclock_t count;
333
334         gd->gd_timer_running = 0;
335
336         count = sys_cputimer->count();
337         if (TAILQ_FIRST(&gd->gd_systimerq) != NULL)
338                 systimer_intr(&count, 0, frame);
339 }
340
341 void
342 lapic_timer_process(void)
343 {
344         lapic_timer_process_oncpu(mycpu, NULL);
345 }
346
347 void
348 lapic_timer_process_frame(struct intrframe *frame)
349 {
350         lapic_timer_process_oncpu(mycpu, frame);
351 }
352
353 static void
354 lapic_timer_intr_reload(struct cputimer_intr *cti, sysclock_t reload)
355 {
356         struct globaldata *gd = mycpu;
357
358         reload = (int64_t)reload * cti->freq / sys_cputimer->freq;
359         if (reload < 2)
360                 reload = 2;
361
362         if (gd->gd_timer_running) {
363                 if (reload < lapic.ccr_timer)
364                         lapic_timer_oneshot_quick(reload);
365         } else {
366                 gd->gd_timer_running = 1;
367                 lapic_timer_oneshot_quick(reload);
368         }
369 }
370
371 static void
372 lapic_timer_intr_enable(struct cputimer_intr *cti __unused)
373 {
374         uint32_t timer;
375
376         timer = lapic.lvt_timer;
377         timer &= ~(APIC_LVTT_MASKED | APIC_LVTT_PERIODIC);
378         lapic.lvt_timer = timer;
379
380         lapic_timer_fixup_handler(NULL);
381 }
382
383 static void
384 lapic_timer_fixup_handler(void *arg)
385 {
386         int *started = arg;
387
388         if (started != NULL)
389                 *started = 0;
390
391         if (cpu_vendor_id == CPU_VENDOR_AMD) {
392                 /*
393                  * Detect the presence of C1E capability mostly on latest
394                  * dual-cores (or future) k8 family.  This feature renders
395                  * the local APIC timer dead, so we disable it by reading
396                  * the Interrupt Pending Message register and clearing both
397                  * C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27).
398                  * 
399                  * Reference:
400                  *   "BIOS and Kernel Developer's Guide for AMD NPT
401                  *    Family 0Fh Processors"
402                  *   #32559 revision 3.00
403                  */
404                 if ((cpu_id & 0x00000f00) == 0x00000f00 &&
405                     (cpu_id & 0x0fff0000) >= 0x00040000) {
406                         uint64_t msr;
407
408                         msr = rdmsr(0xc0010055);
409                         if (msr & 0x18000000) {
410                                 struct globaldata *gd = mycpu;
411
412                                 kprintf("cpu%d: AMD C1E detected\n",
413                                         gd->gd_cpuid);
414                                 wrmsr(0xc0010055, msr & ~0x18000000ULL);
415
416                                 /*
417                                  * We are kinda stalled;
418                                  * kick start again.
419                                  */
420                                 gd->gd_timer_running = 1;
421                                 lapic_timer_oneshot_quick(2);
422
423                                 if (started != NULL)
424                                         *started = 1;
425                         }
426                 }
427         }
428 }
429
430 static void
431 lapic_timer_restart_handler(void *dummy __unused)
432 {
433         int started;
434
435         lapic_timer_fixup_handler(&started);
436         if (!started) {
437                 struct globaldata *gd = mycpu;
438
439                 gd->gd_timer_running = 1;
440                 lapic_timer_oneshot_quick(2);
441         }
442 }
443
444 /*
445  * This function is called only by ACPI-CA code currently:
446  * - AMD C1E fixup.  AMD C1E only seems to happen after ACPI
447  *   module controls PM.  So once ACPI-CA is attached, we try
448  *   to apply the fixup to prevent LAPIC timer from hanging.
449  */
450 static void
451 lapic_timer_intr_pmfixup(struct cputimer_intr *cti __unused)
452 {
453         lwkt_send_ipiq_mask(smp_active_mask,
454                             lapic_timer_fixup_handler, NULL);
455 }
456
457 static void
458 lapic_timer_intr_restart(struct cputimer_intr *cti __unused)
459 {
460         lwkt_send_ipiq_mask(smp_active_mask, lapic_timer_restart_handler, NULL);
461 }
462
463
464 /*
465  * dump contents of local APIC registers
466  */
467 void
468 apic_dump(char* str)
469 {
470         kprintf("SMP: CPU%d %s:\n", mycpu->gd_cpuid, str);
471         kprintf("     lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n",
472                 lapic.lvt_lint0, lapic.lvt_lint1, lapic.tpr, lapic.svr);
473 }
474
475
476 #ifdef SMP /* APIC-IO */
477
478 /*
479  * IO APIC code,
480  */
481
482 #define IOAPIC_ISA_INTS         16
483 #define REDIRCNT_IOAPIC(A) \
484             ((int)((io_apic_versions[(A)] & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1)
485
486 static int trigger (int apic, int pin, u_int32_t * flags);
487 static void polarity (int apic, int pin, u_int32_t * flags, int level);
488
489 #define DEFAULT_FLAGS           \
490         ((u_int32_t)            \
491          (IOART_INTMSET |       \
492           IOART_DESTPHY |       \
493           IOART_DELLOPRI))
494
495 #define DEFAULT_ISA_FLAGS       \
496         ((u_int32_t)            \
497          (IOART_INTMSET |       \
498           IOART_TRGREDG |       \
499           IOART_INTAHI |        \
500           IOART_DESTPHY |       \
501           IOART_DELLOPRI))
502
503 void
504 io_apic_set_id(int apic, int id)
505 {
506         u_int32_t ux;
507         
508         ux = ioapic_read(ioapic[apic], IOAPIC_ID);      /* get current contents */
509         if (((ux & APIC_ID_MASK) >> 24) != id) {
510                 kprintf("Changing APIC ID for IO APIC #%d"
511                        " from %d to %d on chip\n",
512                        apic, ((ux & APIC_ID_MASK) >> 24), id);
513                 ux &= ~APIC_ID_MASK;    /* clear the ID field */
514                 ux |= (id << 24);
515                 ioapic_write(ioapic[apic], IOAPIC_ID, ux);      /* write new value */
516                 ux = ioapic_read(ioapic[apic], IOAPIC_ID);      /* re-read && test */
517                 if (((ux & APIC_ID_MASK) >> 24) != id)
518                         panic("can't control IO APIC #%d ID, reg: 0x%08x",
519                               apic, ux);
520         }
521 }
522
523
524 int
525 io_apic_get_id(int apic)
526 {
527   return (ioapic_read(ioapic[apic], IOAPIC_ID) & APIC_ID_MASK) >> 24;
528 }
529   
530
531
532 /*
533  * Setup the IO APIC.
534  */
535 void
536 io_apic_setup_intpin(int apic, int pin)
537 {
538         int bus, bustype, irq;
539         u_char          select;         /* the select register is 8 bits */
540         u_int32_t       flags;          /* the window register is 32 bits */
541         u_int32_t       target;         /* the window register is 32 bits */
542         u_int32_t       vector;         /* the window register is 32 bits */
543         int             level;
544         int             cpuid;
545         char            envpath[32];
546
547         select = pin * 2 + IOAPIC_REDTBL0;      /* register */
548
549         /*
550          * Always clear an IO APIC pin before [re]programming it.  This is
551          * particularly important if the pin is set up for a level interrupt
552          * as the IOART_REM_IRR bit might be set.   When we reprogram the
553          * vector any EOI from pending ints on this pin could be lost and
554          * IRR might never get reset.
555          *
556          * To fix this problem, clear the vector and make sure it is 
557          * programmed as an edge interrupt.  This should theoretically
558          * clear IRR so we can later, safely program it as a level 
559          * interrupt.
560          */
561         imen_lock();
562
563         flags = ioapic_read(ioapic[apic], select) & IOART_RESV;
564         flags |= IOART_INTMSET | IOART_TRGREDG | IOART_INTAHI;
565         flags |= IOART_DESTPHY | IOART_DELFIXED;
566
567         target = ioapic_read(ioapic[apic], select + 1) & IOART_HI_DEST_RESV;
568         target |= 0;    /* fixed mode cpu mask of 0 - don't deliver anywhere */
569
570         vector = 0;
571
572         ioapic_write(ioapic[apic], select, flags | vector);
573         ioapic_write(ioapic[apic], select + 1, target);
574
575         imen_unlock();
576
577         /*
578          * We only deal with vectored interrupts here.  ? documentation is
579          * lacking, I'm guessing an interrupt type of 0 is the 'INT' type,
580          * vs ExTINT, etc.
581          *
582          * This test also catches unconfigured pins.
583          */
584         if (apic_int_type(apic, pin) != 0)
585                 return;
586
587         /*
588          * Leave the pin unprogrammed if it does not correspond to
589          * an IRQ.
590          */
591         irq = apic_irq(apic, pin);
592         if (irq < 0)
593                 return;
594         
595         /* determine the bus type for this pin */
596         bus = apic_src_bus_id(apic, pin);
597         if (bus < 0)
598                 return;
599         bustype = apic_bus_type(bus);
600         
601         if ((bustype == ISA) &&
602             (pin < IOAPIC_ISA_INTS) && 
603             (irq == pin) &&
604             (apic_polarity(apic, pin) == 0x1) &&
605             (apic_trigger(apic, pin) == 0x3)) {
606                 /* 
607                  * A broken BIOS might describe some ISA 
608                  * interrupts as active-high level-triggered.
609                  * Use default ISA flags for those interrupts.
610                  */
611                 flags = DEFAULT_ISA_FLAGS;
612         } else {
613                 /* 
614                  * Program polarity and trigger mode according to 
615                  * interrupt entry.
616                  */
617                 flags = DEFAULT_FLAGS;
618                 level = trigger(apic, pin, &flags);
619                 if (level == 1)
620                         int_to_apicintpin[irq].flags |= IOAPIC_IM_FLAG_LEVEL;
621                 polarity(apic, pin, &flags, level);
622         }
623
624         cpuid = 0;
625         ksnprintf(envpath, sizeof(envpath), "hw.irq.%d.dest", irq);
626         kgetenv_int(envpath, &cpuid);
627
628         /* ncpus may not be available yet */
629         if (cpuid > mp_naps)
630                 cpuid = 0;
631
632         if (bootverbose) {
633                 kprintf("IOAPIC #%d intpin %d -> irq %d (CPU%d)\n",
634                        apic, pin, irq, cpuid);
635         }
636
637         /*
638          * Program the appropriate registers.  This routing may be 
639          * overridden when an interrupt handler for a device is
640          * actually added (see register_int(), which calls through
641          * the MACHINTR ABI to set up an interrupt handler/vector).
642          *
643          * The order in which we must program the two registers for
644          * safety is unclear! XXX
645          */
646         imen_lock();
647
648         vector = IDT_OFFSET + irq;                      /* IDT vec */
649         target = ioapic_read(ioapic[apic], select + 1) & IOART_HI_DEST_RESV;
650         /* Deliver all interrupts to CPU0 (BSP) */
651         target |= (CPU_TO_ID(cpuid) << IOART_HI_DEST_SHIFT) &
652                   IOART_HI_DEST_MASK;
653         flags |= ioapic_read(ioapic[apic], select) & IOART_RESV;
654         ioapic_write(ioapic[apic], select, flags | vector);
655         ioapic_write(ioapic[apic], select + 1, target);
656
657         imen_unlock();
658 }
659
660 int
661 io_apic_setup(int apic)
662 {
663         int             maxpin;
664         int             pin;
665
666         maxpin = REDIRCNT_IOAPIC(apic);         /* pins in APIC */
667         kprintf("Programming %d pins in IOAPIC #%d\n", maxpin, apic);
668         
669         for (pin = 0; pin < maxpin; ++pin) {
670                 io_apic_setup_intpin(apic, pin);
671         }
672         while (pin < 32) {
673                 if (apic_int_type(apic, pin) >= 0) {
674                         kprintf("Warning: IOAPIC #%d pin %d does not exist,"
675                                 " cannot program!\n", apic, pin);
676                 }
677                 ++pin;
678         }
679
680         /* return GOOD status */
681         return 0;
682 }
683 #undef DEFAULT_ISA_FLAGS
684 #undef DEFAULT_FLAGS
685
686
687 #define DEFAULT_EXTINT_FLAGS    \
688         ((u_int32_t)            \
689          (IOART_INTMSET |       \
690           IOART_TRGREDG |       \
691           IOART_INTAHI |        \
692           IOART_DESTPHY |       \
693           IOART_DELLOPRI))
694
695 /*
696  * XXX this function is only used by 8254 setup
697  * Setup the source of External INTerrupts.
698  */
699 int
700 ext_int_setup(int apic, int intr)
701 {
702         u_char  select;         /* the select register is 8 bits */
703         u_int32_t flags;        /* the window register is 32 bits */
704         u_int32_t target;       /* the window register is 32 bits */
705         u_int32_t vector;       /* the window register is 32 bits */
706         int cpuid;
707         char envpath[32];
708
709         if (apic_int_type(apic, intr) != 3)
710                 return -1;
711
712         cpuid = 0;
713         ksnprintf(envpath, sizeof(envpath), "hw.irq.%d.dest", intr);
714         kgetenv_int(envpath, &cpuid);
715
716         /* ncpus may not be available yet */
717         if (cpuid > mp_naps)
718                 cpuid = 0;
719
720         /* Deliver interrupts to CPU0 (BSP) */
721         target = (CPU_TO_ID(cpuid) << IOART_HI_DEST_SHIFT) &
722                  IOART_HI_DEST_MASK;
723         select = IOAPIC_REDTBL0 + (2 * intr);
724         vector = IDT_OFFSET + intr;
725         flags = DEFAULT_EXTINT_FLAGS;
726
727         ioapic_write(ioapic[apic], select, flags | vector);
728         ioapic_write(ioapic[apic], select + 1, target);
729
730         return 0;
731 }
732 #undef DEFAULT_EXTINT_FLAGS
733
734
735 /*
736  * Set the trigger level for an IO APIC pin.
737  */
738 static int
739 trigger(int apic, int pin, u_int32_t * flags)
740 {
741         int     id;
742         int     eirq;
743         int     level;
744         static int intcontrol = -1;
745
746         switch (apic_trigger(apic, pin)) {
747
748         case 0x00:
749                 break;
750
751         case 0x01:
752                 *flags &= ~IOART_TRGRLVL;       /* *flags |= IOART_TRGREDG */
753                 return 0;
754
755         case 0x03:
756                 *flags |= IOART_TRGRLVL;
757                 return 1;
758
759         case -1:
760         default:
761                 goto bad;
762         }
763
764         if ((id = apic_src_bus_id(apic, pin)) == -1)
765                 goto bad;
766
767         switch (apic_bus_type(id)) {
768         case ISA:
769                 *flags &= ~IOART_TRGRLVL;       /* *flags |= IOART_TRGREDG; */
770                 return 0;
771
772         case EISA:
773                 eirq = apic_src_bus_irq(apic, pin);
774
775                 if (eirq < 0 || eirq > 15) {
776                         kprintf("EISA IRQ %d?!?!\n", eirq);
777                         goto bad;
778                 }
779
780                 if (intcontrol == -1) {
781                         intcontrol = inb(ELCR1) << 8;
782                         intcontrol |= inb(ELCR0);
783                         kprintf("EISA INTCONTROL = %08x\n", intcontrol);
784                 }
785
786                 /* Use ELCR settings to determine level or edge mode */
787                 level = (intcontrol >> eirq) & 1;
788
789                 /*
790                  * Note that on older Neptune chipset based systems, any
791                  * pci interrupts often show up here and in the ELCR as well
792                  * as level sensitive interrupts attributed to the EISA bus.
793                  */
794
795                 if (level)
796                         *flags |= IOART_TRGRLVL;
797                 else
798                         *flags &= ~IOART_TRGRLVL;
799
800                 return level;
801
802         case PCI:
803                 *flags |= IOART_TRGRLVL;
804                 return 1;
805
806         case -1:
807         default:
808                 goto bad;
809         }
810
811 bad:
812         panic("bad APIC IO INT flags");
813 }
814
815
816 /*
817  * Set the polarity value for an IO APIC pin.
818  */
819 static void
820 polarity(int apic, int pin, u_int32_t * flags, int level)
821 {
822         int     id;
823
824         switch (apic_polarity(apic, pin)) {
825
826         case 0x00:
827                 break;
828
829         case 0x01:
830                 *flags &= ~IOART_INTALO;        /* *flags |= IOART_INTAHI */
831                 return;
832
833         case 0x03:
834                 *flags |= IOART_INTALO;
835                 return;
836
837         case -1:
838         default:
839                 goto bad;
840         }
841
842         if ((id = apic_src_bus_id(apic, pin)) == -1)
843                 goto bad;
844
845         switch (apic_bus_type(id)) {
846         case ISA:
847                 *flags &= ~IOART_INTALO;        /* *flags |= IOART_INTAHI */
848                 return;
849
850         case EISA:
851                 /* polarity converter always gives active high */
852                 *flags &= ~IOART_INTALO;
853                 return;
854
855         case PCI:
856                 *flags |= IOART_INTALO;
857                 return;
858
859         case -1:
860         default:
861                 goto bad;
862         }
863
864 bad:
865         panic("bad APIC IO INT flags");
866 }
867
868
869 /*
870  * Print contents of unmasked IRQs.
871  */
872 void
873 imen_dump(void)
874 {
875         int x;
876
877         kprintf("SMP: enabled INTs: ");
878         for (x = 0; x < APIC_INTMAPSIZE; ++x) {
879                 if ((int_to_apicintpin[x].flags & IOAPIC_IM_FLAG_MASKED) == 0)
880                         kprintf("%d ", x);
881         }
882         kprintf("\n");
883 }
884
885
886 /*
887  * Inter Processor Interrupt functions.
888  */
889
890 #endif  /* SMP APIC-IO */
891
892 /*
893  * Send APIC IPI 'vector' to 'destType' via 'deliveryMode'.
894  *
895  *  destType is 1 of: APIC_DEST_SELF, APIC_DEST_ALLISELF, APIC_DEST_ALLESELF
896  *  vector is any valid SYSTEM INT vector
897  *  delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
898  *
899  * A backlog of requests can create a deadlock between cpus.  To avoid this
900  * we have to be able to accept IPIs at the same time we are trying to send
901  * them.  The critical section prevents us from attempting to send additional
902  * IPIs reentrantly, but also prevents IPIQ processing so we have to call
903  * lwkt_process_ipiq() manually.  It's rather messy and expensive for this
904  * to occur but fortunately it does not happen too often.
905  */
906 int
907 apic_ipi(int dest_type, int vector, int delivery_mode)
908 {
909         u_long  icr_lo;
910
911         crit_enter();
912         if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
913             unsigned int eflags = read_eflags();
914             cpu_enable_intr();
915             DEBUG_PUSH_INFO("apic_ipi");
916             while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
917                 lwkt_process_ipiq();
918             }
919             DEBUG_POP_INFO();
920             write_eflags(eflags);
921         }
922
923         icr_lo = (lapic.icr_lo & APIC_ICRLO_RESV_MASK) | dest_type | 
924                 delivery_mode | vector;
925         lapic.icr_lo = icr_lo;
926         crit_exit();
927         return 0;
928 }
929
930 void
931 single_apic_ipi(int cpu, int vector, int delivery_mode)
932 {
933         u_long  icr_lo;
934         u_long  icr_hi;
935
936         crit_enter();
937         if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
938             unsigned int eflags = read_eflags();
939             cpu_enable_intr();
940             DEBUG_PUSH_INFO("single_apic_ipi");
941             while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
942                 lwkt_process_ipiq();
943             }
944             DEBUG_POP_INFO();
945             write_eflags(eflags);
946         }
947         icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
948         icr_hi |= (CPU_TO_ID(cpu) << 24);
949         lapic.icr_hi = icr_hi;
950
951         /* build ICR_LOW */
952         icr_lo = (lapic.icr_lo & APIC_ICRLO_RESV_MASK)
953             | APIC_DEST_DESTFLD | delivery_mode | vector;
954
955         /* write APIC ICR */
956         lapic.icr_lo = icr_lo;
957         crit_exit();
958 }
959
960 #if 0   
961
962 /*
963  * Returns 0 if the apic is busy, 1 if we were able to queue the request.
964  *
965  * NOT WORKING YET!  The code as-is may end up not queueing an IPI at all
966  * to the target, and the scheduler does not 'poll' for IPI messages.
967  */
968 int
969 single_apic_ipi_passive(int cpu, int vector, int delivery_mode)
970 {
971         u_long  icr_lo;
972         u_long  icr_hi;
973
974         crit_enter();
975         if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
976             crit_exit();
977             return(0);
978         }
979         icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
980         icr_hi |= (CPU_TO_ID(cpu) << 24);
981         lapic.icr_hi = icr_hi;
982
983         /* build IRC_LOW */
984         icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
985             | APIC_DEST_DESTFLD | delivery_mode | vector;
986
987         /* write APIC ICR */
988         lapic.icr_lo = icr_lo;
989         crit_exit();
990         return(1);
991 }
992
993 #endif
994
995 /*
996  * Send APIC IPI 'vector' to 'target's via 'delivery_mode'.
997  *
998  * target is a bitmask of destination cpus.  Vector is any
999  * valid system INT vector.  Delivery mode may be either
1000  * APIC_DELMODE_FIXED or APIC_DELMODE_LOWPRIO.
1001  */
1002 void
1003 selected_apic_ipi(cpumask_t target, int vector, int delivery_mode)
1004 {
1005         crit_enter();
1006         while (target) {
1007                 int n = BSFCPUMASK(target);
1008                 target &= ~CPUMASK(n);
1009                 single_apic_ipi(n, vector, delivery_mode);
1010         }
1011         crit_exit();
1012 }
1013
1014 /*
1015  * Timer code, in development...
1016  *  - suggested by rgrimes@gndrsh.aac.dev.com
1017  */
1018 int
1019 get_apic_timer_frequency(void)
1020 {
1021         return(lapic_cputimer_intr.freq);
1022 }
1023
1024 /*
1025  * Load a 'downcount time' in uSeconds.
1026  */
1027 void
1028 set_apic_timer(int us)
1029 {
1030         u_int count;
1031
1032         /*
1033          * When we reach here, lapic timer's frequency
1034          * must have been calculated as well as the
1035          * divisor (lapic.dcr_timer is setup during the
1036          * divisor calculation).
1037          */
1038         KKASSERT(lapic_cputimer_intr.freq != 0 &&
1039                  lapic_timer_divisor_idx >= 0);
1040
1041         count = ((us * (int64_t)lapic_cputimer_intr.freq) + 999999) / 1000000;
1042         lapic_timer_oneshot(count);
1043 }
1044
1045
1046 /*
1047  * Read remaining time in timer.
1048  */
1049 int
1050 read_apic_timer(void)
1051 {
1052 #if 0
1053         /** XXX FIXME: we need to return the actual remaining time,
1054          *         for now we just return the remaining count.
1055          */
1056 #else
1057         return lapic.ccr_timer;
1058 #endif
1059 }
1060
1061
1062 /*
1063  * Spin-style delay, set delay time in uS, spin till it drains.
1064  */
1065 void
1066 u_sleep(int count)
1067 {
1068         set_apic_timer(count);
1069         while (read_apic_timer())
1070                  /* spin */ ;
1071 }
1072
1073 void
1074 lapic_map(vm_offset_t lapic_addr)
1075 {
1076         /* Local apic is mapped on last page */
1077         SMPpt[NPTEPG - 1] = (pt_entry_t)(PG_V | PG_RW | PG_N |
1078             pmap_get_pgeflag() | (lapic_addr & PG_FRAME));
1079
1080         kprintf("lapic: at %p\n", (void *)lapic_addr);
1081 }
1082
1083 static TAILQ_HEAD(, lapic_enumerator) lapic_enumerators =
1084         TAILQ_HEAD_INITIALIZER(lapic_enumerators);
1085
1086 void
1087 lapic_config(void)
1088 {
1089         struct lapic_enumerator *e;
1090         int error;
1091
1092         TAILQ_FOREACH(e, &lapic_enumerators, lapic_link) {
1093                 error = e->lapic_probe(e);
1094                 if (!error)
1095                         break;
1096         }
1097         if (e == NULL)
1098                 panic("can't config lapic\n");
1099
1100         e->lapic_enumerate(e);
1101 }
1102
1103 void
1104 lapic_enumerator_register(struct lapic_enumerator *ne)
1105 {
1106         struct lapic_enumerator *e;
1107
1108         TAILQ_FOREACH(e, &lapic_enumerators, lapic_link) {
1109                 if (e->lapic_prio < ne->lapic_prio) {
1110                         TAILQ_INSERT_BEFORE(e, ne, lapic_link);
1111                         return;
1112                 }
1113         }
1114         TAILQ_INSERT_TAIL(&lapic_enumerators, ne, lapic_link);
1115 }
1116
1117 static TAILQ_HEAD(, ioapic_enumerator) ioapic_enumerators =
1118         TAILQ_HEAD_INITIALIZER(ioapic_enumerators);
1119
1120 void
1121 ioapic_config(void)
1122 {
1123         struct ioapic_enumerator *e;
1124         int error, i;
1125         u_long ef = 0;
1126
1127         TAILQ_INIT(&ioapic_conf.ioc_list);
1128         /* XXX magic number */
1129         for (i = 0; i < 16; ++i)
1130                 ioapic_conf.ioc_intsrc[i] = -1;
1131
1132         TAILQ_FOREACH(e, &ioapic_enumerators, ioapic_link) {
1133                 error = e->ioapic_probe(e);
1134                 if (!error)
1135                         break;
1136         }
1137         if (e == NULL) {
1138 #ifdef notyet
1139                 panic("can't config I/O APIC\n");
1140 #else
1141                 kprintf("no I/O APIC\n");
1142                 return;
1143 #endif
1144         }
1145
1146         if (!ioapic_use_old) {
1147                 crit_enter();
1148
1149                 ef = read_eflags();
1150                 cpu_disable_intr();
1151
1152                 /*
1153                  * Switch to I/O APIC MachIntrABI and reconfigure
1154                  * the default IDT entries.
1155                  */
1156                 MachIntrABI = MachIntrABI_IOAPIC;
1157                 MachIntrABI.setdefault();
1158         }
1159
1160         e->ioapic_enumerate(e);
1161
1162         if (!ioapic_use_old) {
1163                 struct ioapic_info *info;
1164
1165                 /*
1166                  * Fixup the rest of the fields of ioapic_info
1167                  */
1168                 i = 0;
1169                 TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
1170                         const struct ioapic_info *prev_info;
1171
1172                         info->io_idx = i++;
1173                         info->io_apic_id = info->io_idx + lapic_id_max + 1;
1174
1175                         if (bootverbose) {
1176                                 kprintf("IOAPIC: idx %d, apic id %d, "
1177                                         "gsi base %d, npin %d\n",
1178                                         info->io_idx,
1179                                         info->io_apic_id,
1180                                         info->io_gsi_base,
1181                                         info->io_npin);
1182                         }
1183
1184                         /* Warning about possible GSI hole */
1185                         prev_info = TAILQ_PREV(info, ioapic_info_list, io_link);
1186                         if (prev_info != NULL) {
1187                                 if (info->io_gsi_base !=
1188                                 prev_info->io_gsi_base + prev_info->io_npin) {
1189                                         kprintf("IOAPIC: warning gsi hole "
1190                                                 "[%d, %d]\n",
1191                                                 prev_info->io_gsi_base +
1192                                                 prev_info->io_npin,
1193                                                 info->io_gsi_base - 1);
1194                                 }
1195                         }
1196                 }
1197
1198                 /*
1199                  * Setup all I/O APIC
1200                  */
1201                 TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link)
1202                         ioapic_setup(info);
1203                 ioapic_abi_fixup_irqmap();
1204
1205                 write_eflags(ef);
1206
1207                 MachIntrABI.cleanup();
1208
1209                 crit_exit();
1210         }
1211 }
1212
1213 void
1214 ioapic_enumerator_register(struct ioapic_enumerator *ne)
1215 {
1216         struct ioapic_enumerator *e;
1217
1218         TAILQ_FOREACH(e, &ioapic_enumerators, ioapic_link) {
1219                 if (e->ioapic_prio < ne->ioapic_prio) {
1220                         TAILQ_INSERT_BEFORE(e, ne, ioapic_link);
1221                         return;
1222                 }
1223         }
1224         TAILQ_INSERT_TAIL(&ioapic_enumerators, ne, ioapic_link);
1225 }
1226
1227 void
1228 ioapic_add(void *addr, int gsi_base, int npin)
1229 {
1230         struct ioapic_info *info, *ninfo;
1231         int gsi_end;
1232
1233         gsi_end = gsi_base + npin - 1;
1234         TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
1235                 if ((gsi_base >= info->io_gsi_base &&
1236                      gsi_base < info->io_gsi_base + info->io_npin) ||
1237                     (gsi_end >= info->io_gsi_base &&
1238                      gsi_end < info->io_gsi_base + info->io_npin)) {
1239                         panic("ioapic_add: overlapped gsi, base %d npin %d, "
1240                               "hit base %d, npin %d\n", gsi_base, npin,
1241                               info->io_gsi_base, info->io_npin);
1242                 }
1243                 if (info->io_addr == addr)
1244                         panic("ioapic_add: duplicated addr %p\n", addr);
1245         }
1246
1247         ninfo = kmalloc(sizeof(*ninfo), M_DEVBUF, M_WAITOK | M_ZERO);
1248         ninfo->io_addr = addr;
1249         ninfo->io_npin = npin;
1250         ninfo->io_gsi_base = gsi_base;
1251
1252         /*
1253          * Create IOAPIC list in ascending order of GSI base
1254          */
1255         TAILQ_FOREACH_REVERSE(info, &ioapic_conf.ioc_list,
1256             ioapic_info_list, io_link) {
1257                 if (ninfo->io_gsi_base > info->io_gsi_base) {
1258                         TAILQ_INSERT_AFTER(&ioapic_conf.ioc_list,
1259                             info, ninfo, io_link);
1260                         break;
1261                 }
1262         }
1263         if (info == NULL)
1264                 TAILQ_INSERT_HEAD(&ioapic_conf.ioc_list, ninfo, io_link);
1265 }
1266
1267 void
1268 ioapic_intsrc(int irq, int gsi)
1269 {
1270         KKASSERT(irq != gsi);
1271         KKASSERT(irq < 16);
1272
1273         if (gsi == 0) {
1274                 /* Don't allow mixed mode */
1275                 kprintf("IOAPIC: warning intsrc irq %d -> gsi 0\n", irq);
1276                 return;
1277         }
1278
1279         if (ioapic_conf.ioc_intsrc[irq] != -1 &&
1280             ioapic_conf.ioc_intsrc[irq] != gsi) {
1281                 kprintf("IOAPIC: warning intsrc irq %d, gsi %d -> gsi %d\n",
1282                         irq, ioapic_conf.ioc_intsrc[irq], gsi);
1283         }
1284         ioapic_conf.ioc_intsrc[irq] = gsi;
1285 }
1286
1287 static void
1288 ioapic_set_apic_id(const struct ioapic_info *info)
1289 {
1290         uint32_t id;
1291
1292         id = ioapic_read(info->io_addr, IOAPIC_ID);
1293
1294         id &= ~APIC_ID_MASK;
1295         id |= (info->io_apic_id << 24);
1296
1297         ioapic_write(info->io_addr, IOAPIC_ID, id);
1298
1299         /*
1300          * Re-read && test
1301          */
1302         id = ioapic_read(info->io_addr, IOAPIC_ID);
1303         if (((id & APIC_ID_MASK) >> 24) != info->io_apic_id) {
1304                 panic("ioapic_set_apic_id: can't set apic id to %d\n",
1305                       info->io_apic_id);
1306         }
1307 }
1308
1309 static void
1310 ioapic_gsi_setup(int gsi)
1311 {
1312         enum intr_trigger trig;
1313         enum intr_polarity pola;
1314         int irq;
1315
1316         if (gsi == 0) {
1317                 /* ExtINT */
1318                 imen_lock();
1319                 ioapic_extpin_setup(ioapic_gsi_ioaddr(gsi),
1320                     ioapic_gsi_pin(gsi), 0);
1321                 imen_unlock();
1322                 return;
1323         }
1324
1325         for (irq = 0; irq < 16; ++irq) {
1326                 if (gsi == ioapic_conf.ioc_intsrc[irq]) {
1327                         trig = INTR_TRIGGER_EDGE;
1328                         pola = INTR_POLARITY_HIGH;
1329                         break;
1330                 }
1331         }
1332
1333         if (irq == 16) {
1334                 if (gsi < 16) {
1335                         trig = INTR_TRIGGER_EDGE;
1336                         pola = INTR_POLARITY_HIGH;
1337                 } else {
1338                         trig = INTR_TRIGGER_LEVEL;
1339                         pola = INTR_POLARITY_LOW;
1340                 }
1341                 irq = gsi;
1342         }
1343
1344         ioapic_abi_set_irqmap(irq, gsi, trig, pola);
1345 }
1346
1347 void *
1348 ioapic_gsi_ioaddr(int gsi)
1349 {
1350         const struct ioapic_info *info;
1351
1352         info = ioapic_gsi_search(gsi);
1353         return info->io_addr;
1354 }
1355
1356 int
1357 ioapic_gsi_pin(int gsi)
1358 {
1359         const struct ioapic_info *info;
1360
1361         info = ioapic_gsi_search(gsi);
1362         return gsi - info->io_gsi_base;
1363 }
1364
1365 static const struct ioapic_info *
1366 ioapic_gsi_search(int gsi)
1367 {
1368         const struct ioapic_info *info;
1369
1370         TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
1371                 if (gsi >= info->io_gsi_base &&
1372                     gsi < info->io_gsi_base + info->io_npin)
1373                         return info;
1374         }
1375         panic("ioapic_gsi_search: no I/O APIC\n");
1376 }
1377
1378 int
1379 ioapic_gsi(int idx, int pin)
1380 {
1381         const struct ioapic_info *info;
1382
1383         TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
1384                 if (info->io_idx == idx)
1385                         break;
1386         }
1387         if (info == NULL)
1388                 return -1;
1389         if (pin >= info->io_npin)
1390                 return -1;
1391         return info->io_gsi_base + pin;
1392 }
1393
1394 void
1395 ioapic_extpin_setup(void *addr, int pin, int vec)
1396 {
1397         ioapic_pin_prog(addr, pin, vec,
1398             INTR_TRIGGER_CONFORM, INTR_POLARITY_CONFORM, IOART_DELEXINT);
1399 }
1400
1401 int
1402 ioapic_extpin_gsi(void)
1403 {
1404         return 0;
1405 }
1406
1407 void
1408 ioapic_pin_setup(void *addr, int pin, int vec,
1409     enum intr_trigger trig, enum intr_polarity pola)
1410 {
1411         /*
1412          * Always clear an I/O APIC pin before [re]programming it.  This is
1413          * particularly important if the pin is set up for a level interrupt
1414          * as the IOART_REM_IRR bit might be set.   When we reprogram the
1415          * vector any EOI from pending ints on this pin could be lost and
1416          * IRR might never get reset.
1417          *
1418          * To fix this problem, clear the vector and make sure it is 
1419          * programmed as an edge interrupt.  This should theoretically
1420          * clear IRR so we can later, safely program it as a level 
1421          * interrupt.
1422          */
1423         ioapic_pin_prog(addr, pin, vec, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH,
1424             IOART_DELFIXED);
1425         ioapic_pin_prog(addr, pin, vec, trig, pola, IOART_DELFIXED);
1426 }
1427
1428 static void
1429 ioapic_pin_prog(void *addr, int pin, int vec,
1430     enum intr_trigger trig, enum intr_polarity pola, uint32_t del_mode)
1431 {
1432         uint32_t flags, target;
1433         int select;
1434
1435         KKASSERT(del_mode == IOART_DELEXINT || del_mode == IOART_DELFIXED);
1436
1437         select = IOAPIC_REDTBL0 + (2 * pin);
1438
1439         flags = ioapic_read(addr, select) & IOART_RESV;
1440         flags |= IOART_INTMSET | IOART_DESTPHY;
1441 #ifdef foo
1442         flags |= del_mode;
1443 #else
1444         /*
1445          * We only support limited I/O APIC mixed mode,
1446          * so even for ExtINT, we still use "fixed"
1447          * delivery mode.
1448          */
1449         flags |= IOART_DELFIXED;
1450 #endif
1451
1452         if (del_mode == IOART_DELEXINT) {
1453                 KKASSERT(trig == INTR_TRIGGER_CONFORM &&
1454                          pola == INTR_POLARITY_CONFORM);
1455                 flags |= IOART_TRGREDG | IOART_INTAHI;
1456         } else {
1457                 switch (trig) {
1458                 case INTR_TRIGGER_EDGE:
1459                         flags |= IOART_TRGREDG;
1460                         break;
1461
1462                 case INTR_TRIGGER_LEVEL:
1463                         flags |= IOART_TRGRLVL;
1464                         break;
1465
1466                 case INTR_TRIGGER_CONFORM:
1467                         panic("ioapic_pin_prog: trig conform is not "
1468                               "supported\n");
1469                 }
1470                 switch (pola) {
1471                 case INTR_POLARITY_HIGH:
1472                         flags |= IOART_INTAHI;
1473                         break;
1474
1475                 case INTR_POLARITY_LOW:
1476                         flags |= IOART_INTALO;
1477                         break;
1478
1479                 case INTR_POLARITY_CONFORM:
1480                         panic("ioapic_pin_prog: pola conform is not "
1481                               "supported\n");
1482                 }
1483         }
1484
1485         target = ioapic_read(addr, select + 1) & IOART_HI_DEST_RESV;
1486         target |= (CPU_TO_ID(0) << IOART_HI_DEST_SHIFT) &
1487                   IOART_HI_DEST_MASK;
1488
1489         ioapic_write(addr, select, flags | vec);
1490         ioapic_write(addr, select + 1, target);
1491 }
1492
1493 static void
1494 ioapic_setup(const struct ioapic_info *info)
1495 {
1496         int i;
1497
1498         ioapic_set_apic_id(info);
1499
1500         for (i = 0; i < info->io_npin; ++i)
1501                 ioapic_gsi_setup(info->io_gsi_base + i);
1502 }