i386 - Get completely rid of APIC_IO
[dragonfly.git] / sys / platform / pc32 / apic / mpapic.c
CommitLineData
984263bc
MD
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 $
0ca0cd25 26 * $DragonFly: src/sys/platform/pc32/apic/mpapic.c,v 1.22 2008/04/20 13:44:26 swildner Exp $
984263bc
MD
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
b12a1521 31#include <sys/kernel.h>
72740893 32#include <machine/globaldata.h>
984263bc 33#include <machine/smp.h>
90e8a35b 34#include <machine/cputypes.h>
d595a6c0 35#include <machine/md_var.h>
ad52b37b 36#include <machine/pmap.h>
a9295349 37#include <machine_base/apic/mpapic.h>
984263bc 38#include <machine/segments.h>
96728c05 39#include <sys/thread2.h>
984263bc 40
a9295349 41#include <machine_base/isa/intr_machdep.h> /* Xspuriousint() */
984263bc 42
ad52b37b
SZ
43/* XXX */
44extern pt_entry_t *SMPpt;
45
984263bc
MD
46/* EISA Edge/Level trigger control registers */
47#define ELCR0 0x4d0 /* eisa irq 0-7 */
48#define ELCR1 0x4d1 /* eisa irq 8-15 */
49
b52c8db0 50static void lapic_timer_calibrate(void);
086575e9 51static void lapic_timer_set_divisor(int);
a9e511df 52static void lapic_timer_fixup_handler(void *);
76c58571 53static void lapic_timer_restart_handler(void *);
c5b8324c 54
78ea5a2a
SZ
55void lapic_timer_process(void);
56void lapic_timer_process_frame(struct intrframe *);
c5b8324c 57
ef612539 58static int lapic_timer_enable = 1;
c5b8324c 59TUNABLE_INT("hw.lapic_timer_enable", &lapic_timer_enable);
b52c8db0 60
ef612539
SZ
61static void lapic_timer_intr_reload(struct cputimer_intr *, sysclock_t);
62static void lapic_timer_intr_enable(struct cputimer_intr *);
63static void lapic_timer_intr_restart(struct cputimer_intr *);
64static void lapic_timer_intr_pmfixup(struct cputimer_intr *);
65
66static struct cputimer_intr lapic_cputimer_intr = {
67 .freq = 0,
68 .reload = lapic_timer_intr_reload,
69 .enable = lapic_timer_intr_enable,
70 .config = cputimer_intr_default_config,
71 .restart = lapic_timer_intr_restart,
72 .pmfixup = lapic_timer_intr_pmfixup,
73 .initclock = cputimer_intr_default_initclock,
74 .next = SLIST_ENTRY_INITIALIZER,
75 .name = "lapic",
76 .type = CPUTIMER_INTR_LAPIC,
77 .prio = CPUTIMER_INTR_PRIO_LAPIC,
78 .caps = CPUTIMER_INTR_CAP_NONE
79};
80
984263bc
MD
81/*
82 * pointers to pmapped apic hardware.
83 */
84
984263bc 85volatile ioapic_t **ioapic;
984263bc 86
086575e9
SZ
87static int lapic_timer_divisor_idx = -1;
88static const uint32_t lapic_timer_divisors[] = {
89 APIC_TDCR_2, APIC_TDCR_4, APIC_TDCR_8, APIC_TDCR_16,
90 APIC_TDCR_32, APIC_TDCR_64, APIC_TDCR_128, APIC_TDCR_1
91};
92#define APIC_TIMER_NDIVISORS \
93 (int)(sizeof(lapic_timer_divisors) / sizeof(lapic_timer_divisors[0]))
94
95
984263bc
MD
96/*
97 * Enable APIC, configure interrupts.
98 */
99void
b52c8db0 100apic_initialize(boolean_t bsp)
984263bc 101{
78ea5a2a 102 uint32_t timer;
984263bc
MD
103 u_int temp;
104
9d6bf2df 105 /*
97359a5b
MD
106 * setup LVT1 as ExtINT on the BSP. This is theoretically an
107 * aggregate interrupt input from the 8259. The INTA cycle
108 * will be routed to the external controller (the 8259) which
109 * is expected to supply the vector.
110 *
111 * Must be setup edge triggered, active high.
112 *
113 * Disable LVT1 on the APs. It doesn't matter what delivery
114 * mode we use because we leave it masked.
9d6bf2df 115 */
984263bc 116 temp = lapic.lvt_lint0;
9d6bf2df
MD
117 temp &= ~(APIC_LVT_MASKED | APIC_LVT_TRIG_MASK |
118 APIC_LVT_POLARITY_MASK | APIC_LVT_DM_MASK);
72740893 119 if (mycpu->gd_cpuid == 0)
9d6bf2df 120 temp |= APIC_LVT_DM_EXTINT;
984263bc 121 else
97359a5b 122 temp |= APIC_LVT_DM_FIXED | APIC_LVT_MASKED;
984263bc
MD
123 lapic.lvt_lint0 = temp;
124
9d6bf2df
MD
125 /*
126 * setup LVT2 as NMI, masked till later. Edge trigger, active high.
127 */
984263bc 128 temp = lapic.lvt_lint1;
9d6bf2df
MD
129 temp &= ~(APIC_LVT_MASKED | APIC_LVT_TRIG_MASK |
130 APIC_LVT_POLARITY_MASK | APIC_LVT_DM_MASK);
131 temp |= APIC_LVT_MASKED | APIC_LVT_DM_NMI;
984263bc
MD
132 lapic.lvt_lint1 = temp;
133
d9eea1a5 134 /*
c6a1aabe 135 * Mask the apic error interrupt, apic performance counter
78ea5a2a 136 * interrupt.
c6a1aabe
MD
137 */
138 lapic.lvt_error = lapic.lvt_error | APIC_LVT_MASKED;
139 lapic.lvt_pcint = lapic.lvt_pcint | APIC_LVT_MASKED;
78ea5a2a
SZ
140
141 /* Set apic timer vector and mask the apic timer interrupt. */
142 timer = lapic.lvt_timer;
143 timer &= ~APIC_LVTT_VECTOR;
144 timer |= XTIMER_OFFSET;
145 timer |= APIC_LVTT_MASKED;
146 lapic.lvt_timer = timer;
c6a1aabe
MD
147
148 /*
d9eea1a5
MD
149 * Set the Task Priority Register as needed. At the moment allow
150 * interrupts on all cpus (the APs will remain CLId until they are
151 * ready to deal). We could disable all but IPIs by setting
152 * temp |= TPR_IPI_ONLY for cpu != 0.
153 */
984263bc
MD
154 temp = lapic.tpr;
155 temp &= ~APIC_TPR_PRIO; /* clear priority field */
79b62055
MN
156#ifdef SMP /* APIC-IO */
157if (!apic_io_enable) {
158#endif
97359a5b
MD
159 /*
160 * If we are NOT running the IO APICs, the LAPIC will only be used
161 * for IPIs. Set the TPR to prevent any unintentional interrupts.
162 */
163 temp |= TPR_IPI_ONLY;
79b62055
MN
164#ifdef SMP /* APIC-IO */
165}
97359a5b 166#endif
8a8d5d85 167
984263bc
MD
168 lapic.tpr = temp;
169
97359a5b
MD
170 /*
171 * enable the local APIC
172 */
984263bc 173 temp = lapic.svr;
9d6bf2df 174 temp |= APIC_SVR_ENABLE; /* enable the APIC */
97359a5b 175 temp &= ~APIC_SVR_FOCUS_DISABLE; /* enable lopri focus processor */
984263bc 176
9d6bf2df
MD
177 /*
178 * Set the spurious interrupt vector. The low 4 bits of the vector
179 * must be 1111.
180 */
181 if ((XSPURIOUSINT_OFFSET & 0x0F) != 0x0F)
984263bc 182 panic("bad XSPURIOUSINT_OFFSET: 0x%08x", XSPURIOUSINT_OFFSET);
9d6bf2df
MD
183 temp &= ~APIC_SVR_VECTOR;
184 temp |= XSPURIOUSINT_OFFSET;
984263bc 185
984263bc
MD
186 lapic.svr = temp;
187
0b692e79
MD
188 /*
189 * Pump out a few EOIs to clean out interrupts that got through
190 * before we were able to set the TPR.
191 */
192 lapic.eoi = 0;
193 lapic.eoi = 0;
194 lapic.eoi = 0;
195
c5b8324c 196 if (bsp) {
b52c8db0 197 lapic_timer_calibrate();
ef612539
SZ
198 if (lapic_timer_enable) {
199 cputimer_intr_register(&lapic_cputimer_intr);
200 cputimer_intr_select(&lapic_cputimer_intr, 0);
201 }
c5b8324c 202 } else {
086575e9 203 lapic_timer_set_divisor(lapic_timer_divisor_idx);
c5b8324c 204 }
b52c8db0 205
984263bc
MD
206 if (bootverbose)
207 apic_dump("apic_initialize()");
208}
209
210
b52c8db0
SZ
211static void
212lapic_timer_set_divisor(int divisor_idx)
213{
214 KKASSERT(divisor_idx >= 0 && divisor_idx < APIC_TIMER_NDIVISORS);
215 lapic.dcr_timer = lapic_timer_divisors[divisor_idx];
216}
217
218static void
219lapic_timer_oneshot(u_int count)
220{
221 uint32_t value;
222
223 value = lapic.lvt_timer;
224 value &= ~APIC_LVTT_PERIODIC;
225 lapic.lvt_timer = value;
226 lapic.icr_timer = count;
227}
228
229static void
6198c499
SZ
230lapic_timer_oneshot_quick(u_int count)
231{
232 lapic.icr_timer = count;
233}
234
235static void
b52c8db0
SZ
236lapic_timer_calibrate(void)
237{
47bdf646 238 sysclock_t value;
b52c8db0
SZ
239
240 /* Try to calibrate the local APIC timer. */
241 for (lapic_timer_divisor_idx = 0;
242 lapic_timer_divisor_idx < APIC_TIMER_NDIVISORS;
243 lapic_timer_divisor_idx++) {
244 lapic_timer_set_divisor(lapic_timer_divisor_idx);
245 lapic_timer_oneshot(APIC_TIMER_MAX_COUNT);
246 DELAY(2000000);
247 value = APIC_TIMER_MAX_COUNT - lapic.ccr_timer;
248 if (value != APIC_TIMER_MAX_COUNT)
249 break;
250 }
251 if (lapic_timer_divisor_idx >= APIC_TIMER_NDIVISORS)
252 panic("lapic: no proper timer divisor?!\n");
ef612539 253 lapic_cputimer_intr.freq = value / 2;
b52c8db0 254
47bdf646 255 kprintf("lapic: divisor index %d, frequency %u Hz\n",
ef612539 256 lapic_timer_divisor_idx, lapic_cputimer_intr.freq);
b52c8db0
SZ
257}
258
c5b8324c
SZ
259static void
260lapic_timer_process_oncpu(struct globaldata *gd, struct intrframe *frame)
261{
262 sysclock_t count;
263
264 gd->gd_timer_running = 0;
265
266 count = sys_cputimer->count();
267 if (TAILQ_FIRST(&gd->gd_systimerq) != NULL)
268 systimer_intr(&count, 0, frame);
269}
270
78ea5a2a
SZ
271void
272lapic_timer_process(void)
273{
ae48d6cd 274 lapic_timer_process_oncpu(mycpu, NULL);
78ea5a2a
SZ
275}
276
277void
278lapic_timer_process_frame(struct intrframe *frame)
279{
ae48d6cd 280 lapic_timer_process_oncpu(mycpu, frame);
b12a1521
SZ
281}
282
c5b8324c 283static void
ef612539 284lapic_timer_intr_reload(struct cputimer_intr *cti, sysclock_t reload)
c5b8324c
SZ
285{
286 struct globaldata *gd = mycpu;
287
ef612539 288 reload = (int64_t)reload * cti->freq / sys_cputimer->freq;
c5b8324c
SZ
289 if (reload < 2)
290 reload = 2;
291
292 if (gd->gd_timer_running) {
293 if (reload < lapic.ccr_timer)
294 lapic_timer_oneshot_quick(reload);
295 } else {
296 gd->gd_timer_running = 1;
297 lapic_timer_oneshot_quick(reload);
298 }
299}
300
ef612539
SZ
301static void
302lapic_timer_intr_enable(struct cputimer_intr *cti __unused)
6198c499
SZ
303{
304 uint32_t timer;
305
306 timer = lapic.lvt_timer;
307 timer &= ~(APIC_LVTT_MASKED | APIC_LVTT_PERIODIC);
308 lapic.lvt_timer = timer;
a9e511df
SZ
309
310 lapic_timer_fixup_handler(NULL);
311}
312
313static void
76c58571 314lapic_timer_fixup_handler(void *arg)
a9e511df 315{
76c58571
SZ
316 int *started = arg;
317
318 if (started != NULL)
319 *started = 0;
320
90e8a35b 321 if (cpu_vendor_id == CPU_VENDOR_AMD) {
a9e511df
SZ
322 /*
323 * Detect the presence of C1E capability mostly on latest
324 * dual-cores (or future) k8 family. This feature renders
325 * the local APIC timer dead, so we disable it by reading
326 * the Interrupt Pending Message register and clearing both
327 * C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27).
328 *
329 * Reference:
330 * "BIOS and Kernel Developer's Guide for AMD NPT
331 * Family 0Fh Processors"
332 * #32559 revision 3.00
333 */
334 if ((cpu_id & 0x00000f00) == 0x00000f00 &&
335 (cpu_id & 0x0fff0000) >= 0x00040000) {
336 uint64_t msr;
337
338 msr = rdmsr(0xc0010055);
339 if (msr & 0x18000000) {
340 struct globaldata *gd = mycpu;
341
342 kprintf("cpu%d: AMD C1E detected\n",
343 gd->gd_cpuid);
344 wrmsr(0xc0010055, msr & ~0x18000000ULL);
345
346 /*
347 * We are kinda stalled;
348 * kick start again.
349 */
350 gd->gd_timer_running = 1;
351 lapic_timer_oneshot_quick(2);
76c58571
SZ
352
353 if (started != NULL)
354 *started = 1;
a9e511df
SZ
355 }
356 }
357 }
358}
359
76c58571
SZ
360static void
361lapic_timer_restart_handler(void *dummy __unused)
362{
363 int started;
364
365 lapic_timer_fixup_handler(&started);
366 if (!started) {
367 struct globaldata *gd = mycpu;
368
369 gd->gd_timer_running = 1;
370 lapic_timer_oneshot_quick(2);
371 }
372}
373
a9e511df
SZ
374/*
375 * This function is called only by ACPI-CA code currently:
376 * - AMD C1E fixup. AMD C1E only seems to happen after ACPI
377 * module controls PM. So once ACPI-CA is attached, we try
378 * to apply the fixup to prevent LAPIC timer from hanging.
379 */
ef612539
SZ
380static void
381lapic_timer_intr_pmfixup(struct cputimer_intr *cti __unused)
a9e511df 382{
ef612539
SZ
383 lwkt_send_ipiq_mask(smp_active_mask,
384 lapic_timer_fixup_handler, NULL);
6198c499
SZ
385}
386
ef612539
SZ
387static void
388lapic_timer_intr_restart(struct cputimer_intr *cti __unused)
76c58571 389{
76c58571
SZ
390 lwkt_send_ipiq_mask(smp_active_mask, lapic_timer_restart_handler, NULL);
391}
392
b52c8db0 393
984263bc
MD
394/*
395 * dump contents of local APIC registers
396 */
397void
398apic_dump(char* str)
399{
26be20a0
SW
400 kprintf("SMP: CPU%d %s:\n", mycpu->gd_cpuid, str);
401 kprintf(" lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n",
984263bc
MD
402 lapic.lvt_lint0, lapic.lvt_lint1, lapic.tpr, lapic.svr);
403}
404
405
79b62055 406#ifdef SMP /* APIC-IO */
984263bc
MD
407
408/*
409 * IO APIC code,
410 */
411
412#define IOAPIC_ISA_INTS 16
413#define REDIRCNT_IOAPIC(A) \
414 ((int)((io_apic_versions[(A)] & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1)
415
3ae0cd58
RG
416static int trigger (int apic, int pin, u_int32_t * flags);
417static void polarity (int apic, int pin, u_int32_t * flags, int level);
984263bc
MD
418
419#define DEFAULT_FLAGS \
420 ((u_int32_t) \
421 (IOART_INTMSET | \
422 IOART_DESTPHY | \
423 IOART_DELLOPRI))
424
425#define DEFAULT_ISA_FLAGS \
426 ((u_int32_t) \
427 (IOART_INTMSET | \
428 IOART_TRGREDG | \
429 IOART_INTAHI | \
430 IOART_DESTPHY | \
431 IOART_DELLOPRI))
432
433void
434io_apic_set_id(int apic, int id)
435{
436 u_int32_t ux;
437
438 ux = io_apic_read(apic, IOAPIC_ID); /* get current contents */
439 if (((ux & APIC_ID_MASK) >> 24) != id) {
26be20a0 440 kprintf("Changing APIC ID for IO APIC #%d"
984263bc
MD
441 " from %d to %d on chip\n",
442 apic, ((ux & APIC_ID_MASK) >> 24), id);
443 ux &= ~APIC_ID_MASK; /* clear the ID field */
444 ux |= (id << 24);
445 io_apic_write(apic, IOAPIC_ID, ux); /* write new value */
446 ux = io_apic_read(apic, IOAPIC_ID); /* re-read && test */
447 if (((ux & APIC_ID_MASK) >> 24) != id)
448 panic("can't control IO APIC #%d ID, reg: 0x%08x",
449 apic, ux);
450 }
451}
452
453
454int
455io_apic_get_id(int apic)
456{
457 return (io_apic_read(apic, IOAPIC_ID) & APIC_ID_MASK) >> 24;
458}
459
460
461
462/*
463 * Setup the IO APIC.
464 */
984263bc
MD
465void
466io_apic_setup_intpin(int apic, int pin)
467{
468 int bus, bustype, irq;
469 u_char select; /* the select register is 8 bits */
470 u_int32_t flags; /* the window register is 32 bits */
471 u_int32_t target; /* the window register is 32 bits */
472 u_int32_t vector; /* the window register is 32 bits */
473 int level;
db958607
SZ
474 int cpuid;
475 char envpath[32];
984263bc 476
984263bc 477 select = pin * 2 + IOAPIC_REDTBL0; /* register */
65de6d19
MD
478
479 /*
480 * Always clear an IO APIC pin before [re]programming it. This is
481 * particularly important if the pin is set up for a level interrupt
482 * as the IOART_REM_IRR bit might be set. When we reprogram the
483 * vector any EOI from pending ints on this pin could be lost and
484 * IRR might never get reset.
984263bc 485 *
65de6d19
MD
486 * To fix this problem, clear the vector and make sure it is
487 * programmed as an edge interrupt. This should theoretically
488 * clear IRR so we can later, safely program it as a level
489 * interrupt.
984263bc 490 */
8a8d5d85 491 imen_lock();
65de6d19
MD
492
493 flags = io_apic_read(apic, select) & IOART_RESV;
494 flags |= IOART_INTMSET | IOART_TRGREDG | IOART_INTAHI;
495 flags |= IOART_DESTPHY | IOART_DELFIXED;
496
497 target = io_apic_read(apic, select + 1) & IOART_HI_DEST_RESV;
498 target |= 0; /* fixed mode cpu mask of 0 - don't deliver anywhere */
499
500 vector = 0;
501
502 io_apic_write(apic, select, flags | vector);
503 io_apic_write(apic, select + 1, target);
504
8a8d5d85 505 imen_unlock();
65de6d19
MD
506
507 /*
508 * We only deal with vectored interrupts here. ? documentation is
509 * lacking, I'm guessing an interrupt type of 0 is the 'INT' type,
510 * vs ExTINT, etc.
511 *
512 * This test also catches unconfigured pins.
513 */
984263bc
MD
514 if (apic_int_type(apic, pin) != 0)
515 return;
65de6d19
MD
516
517 /*
518 * Leave the pin unprogrammed if it does not correspond to
519 * an IRQ.
520 */
984263bc
MD
521 irq = apic_irq(apic, pin);
522 if (irq < 0)
523 return;
524
525 /* determine the bus type for this pin */
526 bus = apic_src_bus_id(apic, pin);
65de6d19 527 if (bus < 0)
984263bc
MD
528 return;
529 bustype = apic_bus_type(bus);
530
531 if ((bustype == ISA) &&
532 (pin < IOAPIC_ISA_INTS) &&
533 (irq == pin) &&
534 (apic_polarity(apic, pin) == 0x1) &&
535 (apic_trigger(apic, pin) == 0x3)) {
536 /*
537 * A broken BIOS might describe some ISA
538 * interrupts as active-high level-triggered.
539 * Use default ISA flags for those interrupts.
540 */
541 flags = DEFAULT_ISA_FLAGS;
542 } else {
543 /*
544 * Program polarity and trigger mode according to
545 * interrupt entry.
546 */
547 flags = DEFAULT_FLAGS;
548 level = trigger(apic, pin, &flags);
549 if (level == 1)
0f546930 550 int_to_apicintpin[irq].flags |= IOAPIC_IM_FLAG_LEVEL;
984263bc
MD
551 polarity(apic, pin, &flags, level);
552 }
db958607
SZ
553
554 cpuid = 0;
555 ksnprintf(envpath, sizeof(envpath), "hw.irq.%d.dest", irq);
556 kgetenv_int(envpath, &cpuid);
557
558 /* ncpus may not be available yet */
559 if (cpuid > mp_naps)
560 cpuid = 0;
561
5737d650 562 if (bootverbose) {
db958607
SZ
563 kprintf("IOAPIC #%d intpin %d -> irq %d (CPU%d)\n",
564 apic, pin, irq, cpuid);
5737d650 565 }
65de6d19
MD
566
567 /*
568 * Program the appropriate registers. This routing may be
569 * overridden when an interrupt handler for a device is
9d522d14 570 * actually added (see register_int(), which calls through
65de6d19
MD
571 * the MACHINTR ABI to set up an interrupt handler/vector).
572 *
573 * The order in which we must program the two registers for
574 * safety is unclear! XXX
575 */
8a8d5d85 576 imen_lock();
65de6d19
MD
577
578 vector = IDT_OFFSET + irq; /* IDT vec */
579 target = io_apic_read(apic, select + 1) & IOART_HI_DEST_RESV;
0c8fbc51 580 /* Deliver all interrupts to CPU0 (BSP) */
db958607
SZ
581 target |= (CPU_TO_ID(cpuid) << IOART_HI_DEST_SHIFT) &
582 IOART_HI_DEST_MASK;
65de6d19 583 flags |= io_apic_read(apic, select) & IOART_RESV;
984263bc
MD
584 io_apic_write(apic, select, flags | vector);
585 io_apic_write(apic, select + 1, target);
65de6d19 586
8a8d5d85 587 imen_unlock();
984263bc
MD
588}
589
590int
591io_apic_setup(int apic)
592{
593 int maxpin;
594 int pin;
595
984263bc 596 maxpin = REDIRCNT_IOAPIC(apic); /* pins in APIC */
26be20a0 597 kprintf("Programming %d pins in IOAPIC #%d\n", maxpin, apic);
984263bc
MD
598
599 for (pin = 0; pin < maxpin; ++pin) {
600 io_apic_setup_intpin(apic, pin);
601 }
1f1464ad
MD
602 while (pin < 32) {
603 if (apic_int_type(apic, pin) >= 0) {
26be20a0 604 kprintf("Warning: IOAPIC #%d pin %d does not exist,"
1f1464ad
MD
605 " cannot program!\n", apic, pin);
606 }
607 ++pin;
608 }
984263bc
MD
609
610 /* return GOOD status */
611 return 0;
612}
613#undef DEFAULT_ISA_FLAGS
614#undef DEFAULT_FLAGS
615
616
617#define DEFAULT_EXTINT_FLAGS \
618 ((u_int32_t) \
619 (IOART_INTMSET | \
620 IOART_TRGREDG | \
621 IOART_INTAHI | \
622 IOART_DESTPHY | \
623 IOART_DELLOPRI))
624
625/*
db958607 626 * XXX this function is only used by 8254 setup
984263bc
MD
627 * Setup the source of External INTerrupts.
628 */
629int
630ext_int_setup(int apic, int intr)
631{
632 u_char select; /* the select register is 8 bits */
633 u_int32_t flags; /* the window register is 32 bits */
634 u_int32_t target; /* the window register is 32 bits */
635 u_int32_t vector; /* the window register is 32 bits */
db958607
SZ
636 int cpuid;
637 char envpath[32];
984263bc
MD
638
639 if (apic_int_type(apic, intr) != 3)
640 return -1;
641
db958607
SZ
642 cpuid = 0;
643 ksnprintf(envpath, sizeof(envpath), "hw.irq.%d.dest", intr);
644 kgetenv_int(envpath, &cpuid);
645
646 /* ncpus may not be available yet */
647 if (cpuid > mp_naps)
648 cpuid = 0;
649
0c8fbc51 650 /* Deliver interrupts to CPU0 (BSP) */
db958607
SZ
651 target = (CPU_TO_ID(cpuid) << IOART_HI_DEST_SHIFT) &
652 IOART_HI_DEST_MASK;
984263bc 653 select = IOAPIC_REDTBL0 + (2 * intr);
97359a5b 654 vector = IDT_OFFSET + intr;
984263bc
MD
655 flags = DEFAULT_EXTINT_FLAGS;
656
657 io_apic_write(apic, select, flags | vector);
658 io_apic_write(apic, select + 1, target);
659
660 return 0;
661}
662#undef DEFAULT_EXTINT_FLAGS
663
664
665/*
666 * Set the trigger level for an IO APIC pin.
667 */
668static int
669trigger(int apic, int pin, u_int32_t * flags)
670{
671 int id;
672 int eirq;
673 int level;
674 static int intcontrol = -1;
675
676 switch (apic_trigger(apic, pin)) {
677
678 case 0x00:
679 break;
680
681 case 0x01:
682 *flags &= ~IOART_TRGRLVL; /* *flags |= IOART_TRGREDG */
683 return 0;
684
685 case 0x03:
686 *flags |= IOART_TRGRLVL;
687 return 1;
688
689 case -1:
690 default:
691 goto bad;
692 }
693
694 if ((id = apic_src_bus_id(apic, pin)) == -1)
695 goto bad;
696
697 switch (apic_bus_type(id)) {
698 case ISA:
699 *flags &= ~IOART_TRGRLVL; /* *flags |= IOART_TRGREDG; */
700 return 0;
701
702 case EISA:
703 eirq = apic_src_bus_irq(apic, pin);
704
705 if (eirq < 0 || eirq > 15) {
26be20a0 706 kprintf("EISA IRQ %d?!?!\n", eirq);
984263bc
MD
707 goto bad;
708 }
709
710 if (intcontrol == -1) {
711 intcontrol = inb(ELCR1) << 8;
712 intcontrol |= inb(ELCR0);
26be20a0 713 kprintf("EISA INTCONTROL = %08x\n", intcontrol);
984263bc
MD
714 }
715
716 /* Use ELCR settings to determine level or edge mode */
717 level = (intcontrol >> eirq) & 1;
718
719 /*
720 * Note that on older Neptune chipset based systems, any
721 * pci interrupts often show up here and in the ELCR as well
722 * as level sensitive interrupts attributed to the EISA bus.
723 */
724
725 if (level)
726 *flags |= IOART_TRGRLVL;
727 else
728 *flags &= ~IOART_TRGRLVL;
729
730 return level;
731
732 case PCI:
733 *flags |= IOART_TRGRLVL;
734 return 1;
735
736 case -1:
737 default:
738 goto bad;
739 }
740
741bad:
742 panic("bad APIC IO INT flags");
743}
744
745
746/*
747 * Set the polarity value for an IO APIC pin.
748 */
749static void
750polarity(int apic, int pin, u_int32_t * flags, int level)
751{
752 int id;
753
754 switch (apic_polarity(apic, pin)) {
755
756 case 0x00:
757 break;
758
759 case 0x01:
760 *flags &= ~IOART_INTALO; /* *flags |= IOART_INTAHI */
761 return;
762
763 case 0x03:
764 *flags |= IOART_INTALO;
765 return;
766
767 case -1:
768 default:
769 goto bad;
770 }
771
772 if ((id = apic_src_bus_id(apic, pin)) == -1)
773 goto bad;
774
775 switch (apic_bus_type(id)) {
776 case ISA:
777 *flags &= ~IOART_INTALO; /* *flags |= IOART_INTAHI */
778 return;
779
780 case EISA:
781 /* polarity converter always gives active high */
782 *flags &= ~IOART_INTALO;
783 return;
784
785 case PCI:
786 *flags |= IOART_INTALO;
787 return;
788
789 case -1:
790 default:
791 goto bad;
792 }
793
794bad:
795 panic("bad APIC IO INT flags");
796}
797
798
799/*
ea689d1c 800 * Print contents of unmasked IRQs.
984263bc 801 */
984263bc
MD
802void
803imen_dump(void)
804{
805 int x;
806
26be20a0 807 kprintf("SMP: enabled INTs: ");
ea689d1c
SZ
808 for (x = 0; x < APIC_INTMAPSIZE; ++x) {
809 if ((int_to_apicintpin[x].flags & IOAPIC_IM_FLAG_MASKED) == 0)
810 kprintf("%d ", x);
811 }
812 kprintf("\n");
984263bc
MD
813}
814
815
816/*
817 * Inter Processor Interrupt functions.
818 */
819
79b62055 820#endif /* SMP APIC-IO */
984263bc
MD
821
822/*
823 * Send APIC IPI 'vector' to 'destType' via 'deliveryMode'.
824 *
825 * destType is 1 of: APIC_DEST_SELF, APIC_DEST_ALLISELF, APIC_DEST_ALLESELF
826 * vector is any valid SYSTEM INT vector
827 * delivery_mode is 1 of: APIC_DELMODE_FIXED, APIC_DELMODE_LOWPRIO
96728c05
MD
828 *
829 * A backlog of requests can create a deadlock between cpus. To avoid this
830 * we have to be able to accept IPIs at the same time we are trying to send
831 * them. The critical section prevents us from attempting to send additional
832 * IPIs reentrantly, but also prevents IPIQ processing so we have to call
833 * lwkt_process_ipiq() manually. It's rather messy and expensive for this
834 * to occur but fortunately it does not happen too often.
984263bc 835 */
984263bc
MD
836int
837apic_ipi(int dest_type, int vector, int delivery_mode)
838{
839 u_long icr_lo;
840
96728c05
MD
841 crit_enter();
842 if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
843 unsigned int eflags = read_eflags();
844 cpu_enable_intr();
845 while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
846 lwkt_process_ipiq();
847 }
848 write_eflags(eflags);
984263bc 849 }
984263bc 850
9d6bf2df 851 icr_lo = (lapic.icr_lo & APIC_ICRLO_RESV_MASK) | dest_type |
96728c05 852 delivery_mode | vector;
984263bc 853 lapic.icr_lo = icr_lo;
96728c05 854 crit_exit();
984263bc
MD
855 return 0;
856}
857
41a01a4d
MD
858void
859single_apic_ipi(int cpu, int vector, int delivery_mode)
984263bc
MD
860{
861 u_long icr_lo;
862 u_long icr_hi;
984263bc 863
41a01a4d 864 crit_enter();
96728c05
MD
865 if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
866 unsigned int eflags = read_eflags();
867 cpu_enable_intr();
868 while ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
869 lwkt_process_ipiq();
870 }
871 write_eflags(eflags);
984263bc 872 }
984263bc
MD
873 icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
874 icr_hi |= (CPU_TO_ID(cpu) << 24);
875 lapic.icr_hi = icr_hi;
876
b2f93ae9 877 /* build ICR_LOW */
9d6bf2df 878 icr_lo = (lapic.icr_lo & APIC_ICRLO_RESV_MASK)
984263bc
MD
879 | APIC_DEST_DESTFLD | delivery_mode | vector;
880
881 /* write APIC ICR */
882 lapic.icr_lo = icr_lo;
41a01a4d 883 crit_exit();
984263bc
MD
884}
885
41a01a4d
MD
886#if 0
887
888/*
889 * Returns 0 if the apic is busy, 1 if we were able to queue the request.
890 *
891 * NOT WORKING YET! The code as-is may end up not queueing an IPI at all
892 * to the target, and the scheduler does not 'poll' for IPI messages.
893 */
894int
895single_apic_ipi_passive(int cpu, int vector, int delivery_mode)
896{
897 u_long icr_lo;
898 u_long icr_hi;
899
900 crit_enter();
901 if ((lapic.icr_lo & APIC_DELSTAT_MASK) != 0) {
902 crit_exit();
903 return(0);
904 }
905 icr_hi = lapic.icr_hi & ~APIC_ID_MASK;
906 icr_hi |= (CPU_TO_ID(cpu) << 24);
907 lapic.icr_hi = icr_hi;
908
909 /* build IRC_LOW */
910 icr_lo = (lapic.icr_lo & APIC_RESV2_MASK)
911 | APIC_DEST_DESTFLD | delivery_mode | vector;
912
913 /* write APIC ICR */
914 lapic.icr_lo = icr_lo;
915 crit_exit();
916 return(1);
917}
918
919#endif
920
984263bc
MD
921/*
922 * Send APIC IPI 'vector' to 'target's via 'delivery_mode'.
923 *
96728c05
MD
924 * target is a bitmask of destination cpus. Vector is any
925 * valid system INT vector. Delivery mode may be either
926 * APIC_DELMODE_FIXED or APIC_DELMODE_LOWPRIO.
984263bc 927 */
41a01a4d 928void
984263bc
MD
929selected_apic_ipi(u_int target, int vector, int delivery_mode)
930{
96728c05
MD
931 crit_enter();
932 while (target) {
933 int n = bsfl(target);
934 target &= ~(1 << n);
41a01a4d 935 single_apic_ipi(n, vector, delivery_mode);
96728c05
MD
936 }
937 crit_exit();
984263bc 938}
984263bc 939
984263bc
MD
940/*
941 * Timer code, in development...
942 * - suggested by rgrimes@gndrsh.aac.dev.com
943 */
bb467734
MD
944int
945get_apic_timer_frequency(void)
946{
947 return(lapic_cputimer_intr.freq);
948}
984263bc 949
984263bc
MD
950/*
951 * Load a 'downcount time' in uSeconds.
952 */
953void
2942ed63 954set_apic_timer(int us)
984263bc 955{
2942ed63 956 u_int count;
984263bc
MD
957
958 /*
2942ed63
SZ
959 * When we reach here, lapic timer's frequency
960 * must have been calculated as well as the
961 * divisor (lapic.dcr_timer is setup during the
962 * divisor calculation).
984263bc 963 */
ef612539 964 KKASSERT(lapic_cputimer_intr.freq != 0 &&
2942ed63
SZ
965 lapic_timer_divisor_idx >= 0);
966
ef612539 967 count = ((us * (int64_t)lapic_cputimer_intr.freq) + 999999) / 1000000;
2942ed63 968 lapic_timer_oneshot(count);
984263bc
MD
969}
970
971
972/*
973 * Read remaining time in timer.
974 */
975int
976read_apic_timer(void)
977{
978#if 0
979 /** XXX FIXME: we need to return the actual remaining time,
980 * for now we just return the remaining count.
981 */
982#else
983 return lapic.ccr_timer;
984#endif
985}
986
987
988/*
989 * Spin-style delay, set delay time in uS, spin till it drains.
990 */
991void
992u_sleep(int count)
993{
994 set_apic_timer(count);
995 while (read_apic_timer())
996 /* spin */ ;
997}
ad52b37b
SZ
998
999void
84cc808b 1000lapic_map(vm_offset_t lapic_addr)
ad52b37b
SZ
1001{
1002 /* Local apic is mapped on last page */
1003 SMPpt[NPTEPG - 1] = (pt_entry_t)(PG_V | PG_RW | PG_N |
1004 pmap_get_pgeflag() | (lapic_addr & PG_FRAME));
1005
d557216f 1006 kprintf("lapic: at %p\n", (void *)lapic_addr);
ad52b37b 1007}
281d9482
SZ
1008
1009static TAILQ_HEAD(, lapic_enumerator) lapic_enumerators =
1010 TAILQ_HEAD_INITIALIZER(lapic_enumerators);
1011
1012void
1013lapic_config(void)
1014{
1015 struct lapic_enumerator *e;
1016 int error;
1017
1018 TAILQ_FOREACH(e, &lapic_enumerators, lapic_link) {
1019 error = e->lapic_probe(e);
1020 if (!error)
1021 break;
1022 }
1023 if (e == NULL)
1024 panic("can't config lapic\n");
1025
1026 e->lapic_enumerate(e);
1027}
1028
1029void
1030lapic_enumerator_register(struct lapic_enumerator *ne)
1031{
1032 struct lapic_enumerator *e;
1033
1034 TAILQ_FOREACH(e, &lapic_enumerators, lapic_link) {
1035 if (e->lapic_prio < ne->lapic_prio) {
1036 TAILQ_INSERT_BEFORE(e, ne, lapic_link);
1037 return;
1038 }
1039 }
1040 TAILQ_INSERT_TAIL(&lapic_enumerators, ne, lapic_link);
1041}