Remove building with NOCRYPTO option
[minix3.git] / minix / kernel / arch / i386 / apic.c
blob39346b679e02e86ce36ec6b9cb944368fa0c18f2
1 /*
2 * APIC handling routines. APIC is a requirement for SMP
3 */
4 #include <assert.h>
6 #include <unistd.h>
7 #include <minix/portio.h>
9 #include <minix/syslib.h>
10 #include <machine/cmos.h>
12 #include <minix/u64.h>
14 #include "apic.h"
15 #include "apic_asm.h"
16 #include "kernel/clock.h"
17 #include "glo.h"
18 #include "hw_intr.h"
20 #include "acpi.h"
22 #ifdef USE_WATCHDOG
23 #include "kernel/watchdog.h"
24 #endif
26 #define APIC_ENABLE 0x100
27 #define APIC_FOCUS_DISABLED (1 << 9)
28 #define APIC_SIV 0xFF
30 #define APIC_TDCR_2 0x00
31 #define APIC_TDCR_4 0x01
32 #define APIC_TDCR_8 0x02
33 #define APIC_TDCR_16 0x03
34 #define APIC_TDCR_32 0x08
35 #define APIC_TDCR_64 0x09
36 #define APIC_TDCR_128 0x0a
37 #define APIC_TDCR_1 0x0b
39 #define IS_SET(mask) (mask)
40 #define IS_CLEAR(mask) 0
42 #define APIC_LVTT_VECTOR_MASK 0x000000FF
43 #define APIC_LVTT_DS_PENDING (1 << 12)
44 #define APIC_LVTT_MASK (1 << 16)
45 #define APIC_LVTT_TM (1 << 17)
47 #define APIC_LVT_IIPP_MASK 0x00002000
48 #define APIC_LVT_IIPP_AH 0x00002000
49 #define APIC_LVT_IIPP_AL 0x00000000
51 #define APIC_LVT_TM_ONESHOT IS_CLEAR(APIC_LVTT_TM)
52 #define APIC_LVT_TM_PERIODIC IS_SET(APIC_LVTT_TM)
54 #define IOAPIC_REGSEL 0x0
55 #define IOAPIC_RW 0x10
57 #define APIC_ICR_DM_MASK 0x00000700
58 #define APIC_ICR_VECTOR APIC_LVTT_VECTOR_MASK
59 #define APIC_ICR_DM_FIXED (0 << 8)
60 #define APIC_ICR_DM_LOWEST_PRIORITY (1 << 8)
61 #define APIC_ICR_DM_SMI (2 << 8)
62 #define APIC_ICR_DM_RESERVED (3 << 8)
63 #define APIC_ICR_DM_NMI (4 << 8)
64 #define APIC_ICR_DM_INIT (5 << 8)
65 #define APIC_ICR_DM_STARTUP (6 << 8)
66 #define APIC_ICR_DM_EXTINT (7 << 8)
68 #define APIC_ICR_DM_PHYSICAL (0 << 11)
69 #define APIC_ICR_DM_LOGICAL (1 << 11)
71 #define APIC_ICR_DELIVERY_PENDING (1 << 12)
73 #define APIC_ICR_INT_POLARITY (1 << 13)
74 #define APIC_ICR_INTPOL_LOW IS_SET(APIC_ICR_INT_POLARITY)
75 #define APIC_ICR_INTPOL_HIGH IS_CLEAR(APIC_ICR_INT_POLARITY)
77 #define APIC_ICR_LEVEL_ASSERT (1 << 14)
78 #define APIC_ICR_LEVEL_DEASSERT (0 << 14)
80 #define APIC_ICR_TRIGGER (1 << 15)
81 #define APIC_ICR_TM_LEVEL IS_CLEAR(APIC_ICR_TRIGGER)
82 #define APIC_ICR_TM_EDGE IS_CLEAR(APIC_ICR_TRIGGER)
84 #define APIC_ICR_INT_MASK (1 << 16)
86 #define APIC_ICR_DEST_FIELD (0 << 18)
87 #define APIC_ICR_DEST_SELF (1 << 18)
88 #define APIC_ICR_DEST_ALL (2 << 18)
89 #define APIC_ICR_DEST_ALL_BUT_SELF (3 << 18)
91 #define IA32_APIC_BASE 0x1b
92 #define IA32_APIC_BASE_ENABLE_BIT 11
94 /* FIXME we should spread the irqs across as many priority levels as possible
95 * due to buggy hw */
96 #define LAPIC_VECTOR(irq) (IRQ0_VECTOR +(irq))
98 #define IOAPIC_IRQ_STATE_MASKED 0x1
100 /* currently only 2 interrupt priority levels are used */
101 #define SPL0 0x0
102 #define SPLHI 0xF
105 struct io_apic io_apic[MAX_NR_IOAPICS];
106 unsigned nioapics;
108 struct irq;
109 typedef void (* eoi_method_t)(struct irq *);
111 struct irq {
112 struct io_apic * ioa;
113 unsigned pin;
114 unsigned vector;
115 eoi_method_t eoi;
116 unsigned state;
119 static struct irq io_apic_irq[NR_IRQ_VECTORS];
122 * to make APIC work if SMP is not configured, we need to set the maximal number
123 * of CPUS to 1, cpuid to return 0 and the current cpu is always BSP
125 #ifdef CONFIG_SMP
127 #include "kernel/smp.h"
129 #endif
131 #include "kernel/spinlock.h"
134 #define lapic_write_icr1(val) lapic_write(LAPIC_ICR1, val)
135 #define lapic_write_icr2(val) lapic_write(LAPIC_ICR2, val)
137 #define lapic_read_icr1(x) lapic_read(LAPIC_ICR1)
138 #define lapic_read_icr2(x) lapic_read(LAPIC_ICR2)
140 #define is_boot_apic(apicid) ((apicid) == bsp_lapic_id)
142 #define VERBOSE_APIC(x) x
144 int ioapic_enabled;
145 u32_t lapic_addr_vaddr;
146 vir_bytes lapic_addr;
147 vir_bytes lapic_eoi_addr;
148 int bsp_lapic_id;
150 static volatile unsigned probe_ticks;
151 static u64_t tsc0, tsc1;
152 static u32_t lapic_tctr0, lapic_tctr1;
154 static unsigned apic_imcrp;
155 static const unsigned nlints = 0;
157 void arch_eoi(void)
159 apic_eoi();
163 * FIXME this should be a cpulocal variable but there are some problems with
164 * arch specific cpulocals. As this variable is write-once-read-only it is ok to
165 * have at as an array until we resolve the cpulocals properly
167 static u32_t lapic_bus_freq[CONFIG_MAX_CPUS];
168 /* the probe period will be roughly 100ms */
169 #define PROBE_TICKS (system_hz / 10)
171 #define IOAPIC_IOREGSEL 0x0
172 #define IOAPIC_IOWIN 0x10
174 static u32_t ioapic_read(u32_t ioa_base, u32_t reg)
176 *((volatile u32_t *)(ioa_base + IOAPIC_IOREGSEL)) = (reg & 0xff);
177 return *(volatile u32_t *)(ioa_base + IOAPIC_IOWIN);
180 static void ioapic_write(u32_t ioa_base, u8_t reg, u32_t val)
182 *((volatile u32_t *)(ioa_base + IOAPIC_IOREGSEL)) = reg;
183 *((volatile u32_t *)(ioa_base + IOAPIC_IOWIN)) = val;
186 void lapic_microsec_sleep(unsigned count);
187 void apic_idt_init(const int reset);
189 static void ioapic_enable_pin(vir_bytes ioapic_addr, int pin)
191 u32_t lo = ioapic_read(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2);
193 lo &= ~APIC_ICR_INT_MASK;
194 ioapic_write(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2, lo);
197 static void ioapic_disable_pin(vir_bytes ioapic_addr, int pin)
199 u32_t lo = ioapic_read(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2);
201 lo |= APIC_ICR_INT_MASK;
202 ioapic_write(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2, lo);
205 #if 0
206 static void ioapic_redirt_entry_read(void * ioapic_addr,
207 int entry,
208 u32_t *hi,
209 u32_t *lo)
211 *lo = ioapic_read((u32_t)ioapic_addr, (u8_t) (IOAPIC_REDIR_TABLE + entry * 2));
212 *hi = ioapic_read((u32_t)ioapic_addr, (u8_t) (IOAPIC_REDIR_TABLE + entry * 2 + 1));
215 #endif
217 static void ioapic_redirt_entry_write(void * ioapic_addr,
218 int entry,
219 u32_t hi,
220 u32_t lo)
222 #if 0
223 VERBOSE_APIC(printf("IO apic redir entry %3d "
224 "write 0x%08x 0x%08x\n", entry, hi, lo));
225 #endif
226 ioapic_write((u32_t)ioapic_addr, (u8_t) (IOAPIC_REDIR_TABLE + entry * 2 + 1), hi);
227 ioapic_write((u32_t)ioapic_addr, (u8_t) (IOAPIC_REDIR_TABLE + entry * 2), lo);
230 #define apic_read_tmr_vector(vec) \
231 lapic_read(LAPIC_TMR + 0x10 * ((vec) >> 5))
233 #define apic_read_irr_vector(vec) \
234 lapic_read(LAPIC_IRR + 0x10 * ((vec) >> 5))
236 #define apic_read_isr_vector(vec) \
237 lapic_read(LAPIC_ISR + 0x10 * ((vec) >> 5))
239 #define lapic_test_delivery_val(val, vector) ((val) & (1 << ((vector) & 0x1f)))
241 static void ioapic_eoi_level(struct irq * irq)
243 reg_t tmr;
245 tmr = apic_read_tmr_vector(irq->vector);
246 apic_eoi();
249 * test if it was a level or edge triggered interrupt. If delivered as
250 * edge exec the workaround for broken chipsets
252 if (!lapic_test_delivery_val(tmr, irq->vector)) {
253 int is_masked;
254 u32_t lo;
256 panic("EDGE instead of LEVEL!");
258 lo = ioapic_read(irq->ioa->addr,
259 IOAPIC_REDIR_TABLE + irq->pin * 2);
261 is_masked = lo & APIC_ICR_INT_MASK;
263 /* set mask and edge */
264 lo |= APIC_ICR_INT_MASK;
265 lo &= ~APIC_ICR_TRIGGER;
266 ioapic_write(irq->ioa->addr,
267 IOAPIC_REDIR_TABLE + irq->pin * 2, lo);
269 /* set back to level and restore the mask bit */
270 lo = ioapic_read(irq->ioa->addr,
271 IOAPIC_REDIR_TABLE + irq->pin * 2);
273 lo |= APIC_ICR_TRIGGER;
274 if (is_masked)
275 lo |= APIC_ICR_INT_MASK;
276 else
277 lo &= ~APIC_ICR_INT_MASK;
278 ioapic_write(irq->ioa->addr,
279 IOAPIC_REDIR_TABLE + irq->pin * 2, lo);
283 static void ioapic_eoi_edge(__unused struct irq * irq)
285 apic_eoi();
288 void ioapic_eoi(int irq)
290 if (ioapic_enabled) {
291 io_apic_irq[irq].eoi(&io_apic_irq[irq]);
293 else
294 irq_8259_eoi(irq);
297 void ioapic_set_id(u32_t addr, unsigned int id)
299 ioapic_write(addr, IOAPIC_ID, id << 24);
302 int ioapic_enable_all(void)
304 i8259_disable();
306 if (apic_imcrp) {
307 /* Select IMCR and disconnect 8259s. */
308 outb(0x22, 0x70);
309 outb(0x23, 0x01);
312 return ioapic_enabled = 1;
315 /* disables a single IO APIC */
316 static void ioapic_disable(struct io_apic * ioapic)
318 unsigned p;
320 for (p = 0; p < io_apic->pins; p++) {
321 u32_t low_32, hi_32;
322 low_32 = ioapic_read((u32_t)ioapic->addr,
323 (uint8_t) (IOAPIC_REDIR_TABLE + p * 2));
324 hi_32 = ioapic_read((u32_t)ioapic->addr,
325 (uint8_t) (IOAPIC_REDIR_TABLE + p * 2 + 1));
327 if (!(low_32 & APIC_ICR_INT_MASK)) {
328 low_32 |= APIC_ICR_INT_MASK;
329 ioapic_write((u32_t)ioapic->addr,
330 (uint8_t) (IOAPIC_REDIR_TABLE + p * 2 + 1), hi_32);
331 ioapic_write((u32_t)ioapic->addr,
332 (uint8_t) (IOAPIC_REDIR_TABLE + p * 2), low_32);
337 /* disables all IO APICs */
338 void ioapic_disable_all(void)
340 unsigned ioa;
341 if (!ioapic_enabled)
342 return;
344 for (ioa = 0 ; ioa < nioapics; ioa++)
345 ioapic_disable(&io_apic[ioa]);
347 ioapic_enabled = 0; /* io apic, disabled */
349 /* Enable 8259 - write 0x00 in OCW1 master and slave. */
350 if (apic_imcrp) {
351 outb(0x22, 0x70);
352 outb(0x23, 0x00);
355 lapic_microsec_sleep(200); /* to enable APIC to switch to PIC */
357 apic_idt_init(TRUE); /* reset */
358 idt_reload();
361 static void ioapic_disable_irq(unsigned irq)
363 if(!(io_apic_irq[irq].ioa)) {
364 printf("ioapic_disable_irq: no ioa set for irq %d!\n", irq);
365 return;
368 assert(io_apic_irq[irq].ioa);
370 ioapic_disable_pin(io_apic_irq[irq].ioa->addr, io_apic_irq[irq].pin);
371 io_apic_irq[irq].state |= IOAPIC_IRQ_STATE_MASKED;
374 static void ioapic_enable_irq(unsigned irq)
376 if(!(io_apic_irq[irq].ioa)) {
377 printf("ioapic_enable_irq: no ioa set for irq %d!\n", irq);
378 return;
381 assert(io_apic_irq[irq].ioa);
383 ioapic_enable_pin(io_apic_irq[irq].ioa->addr, io_apic_irq[irq].pin);
384 io_apic_irq[irq].state &= ~IOAPIC_IRQ_STATE_MASKED;
387 void ioapic_unmask_irq(unsigned irq)
389 if (ioapic_enabled)
390 ioapic_enable_irq(irq);
391 else
392 /* FIXME unlikely */
393 irq_8259_unmask(irq);
396 void ioapic_mask_irq(unsigned irq)
398 if (ioapic_enabled)
399 ioapic_disable_irq(irq);
400 else
401 /* FIXME unlikely */
402 irq_8259_mask(irq);
405 unsigned int apicid(void)
407 return lapic_read(LAPIC_ID) >> 24;
410 static int calib_clk_handler(irq_hook_t * UNUSED(hook))
412 u32_t tcrt;
413 u64_t tsc;
415 probe_ticks++;
416 read_tsc_64(&tsc);
417 tcrt = lapic_read(LAPIC_TIMER_CCR);
420 if (probe_ticks == 1) {
421 lapic_tctr0 = tcrt;
422 tsc0 = tsc;
424 else if (probe_ticks == PROBE_TICKS) {
425 lapic_tctr1 = tcrt;
426 tsc1 = tsc;
427 stop_8253A_timer();
430 BKL_UNLOCK();
431 return 1;
434 static int spurious_irq_handler(irq_hook_t * UNUSED(hook))
437 * Do nothing, only unlock the kernel so we do not deadlock!
439 BKL_UNLOCK();
440 return 1;
443 static void apic_calibrate_clocks(unsigned cpu)
445 u32_t lvtt, val, lapic_delta;
446 u64_t tsc_delta;
447 u64_t cpu_freq;
449 irq_hook_t calib_clk, spurious_irq;
451 BOOT_VERBOSE(printf("Calibrating clock\n"));
453 * Set Initial count register to the highest value so it does not
454 * underflow during the testing period
455 * */
456 val = 0xffffffff;
457 lapic_write (LAPIC_TIMER_ICR, val);
459 /* Set Current count register */
460 val = 0;
461 lapic_write (LAPIC_TIMER_CCR, val);
463 lvtt = lapic_read(LAPIC_TIMER_DCR) & ~0x0b;
464 /* Set Divide configuration register to 1 */
465 lvtt = APIC_TDCR_1;
466 lapic_write(LAPIC_TIMER_DCR, lvtt);
469 * mask the APIC timer interrupt in the LVT Timer Register so that we
470 * don't get an interrupt upon underflow which we don't know how to
471 * handle right know. If underflow happens, the system will not continue
472 * as something is wrong with the clock IRQ 0 and we cannot calibrate
473 * the clock which mean that we cannot run processes
475 lvtt = lapic_read (LAPIC_LVTTR);
476 lvtt |= APIC_LVTT_MASK;
477 lapic_write (LAPIC_LVTTR, lvtt);
479 /* set the probe, we use the legacy timer, IRQ 0 */
480 put_irq_handler(&calib_clk, CLOCK_IRQ, calib_clk_handler);
483 * A spurious interrupt may occur during the clock calibration. Since we
484 * do this calibration in kernel, we need a special handler which will
485 * leave the BKL unlocked like the clock handler. This is a corner case,
486 * boot time only situation
488 put_irq_handler(&spurious_irq, SPURIOUS_IRQ, spurious_irq_handler);
490 /* set the PIC timer to get some time */
491 init_8253A_timer(system_hz);
494 * We must unlock BKL here as the in-kernel interrupt will lock it
495 * again. The handler will unlock it after it is done. This is
496 * absolutely safe as only the BSP is running. It is just a workaround a
497 * corner case for APIC timer calibration
499 BKL_UNLOCK();
500 intr_enable();
502 /* loop for some time to get a sample */
503 while(probe_ticks < PROBE_TICKS) {
504 intr_enable();
507 intr_disable();
508 BKL_LOCK();
510 /* remove the probe */
511 rm_irq_handler(&calib_clk);
512 rm_irq_handler(&spurious_irq);
514 lapic_delta = lapic_tctr0 - lapic_tctr1;
515 tsc_delta = tsc1 - tsc0;
517 lapic_bus_freq[cpuid] = system_hz * lapic_delta / (PROBE_TICKS - 1);
518 BOOT_VERBOSE(printf("APIC bus freq %u MHz\n",
519 lapic_bus_freq[cpuid] / 1000000));
520 cpu_freq = (tsc_delta / (PROBE_TICKS - 1)) * make64(system_hz, 0);
521 cpu_set_freq(cpuid, cpu_freq);
522 cpu_info[cpuid].freq = (unsigned long)(cpu_freq / 1000000);
523 BOOT_VERBOSE(cpu_print_freq(cpuid));
526 void lapic_set_timer_one_shot(const u32_t usec)
528 /* sleep in micro seconds */
529 u32_t lvtt;
530 u32_t ticks_per_us;
531 const u8_t cpu = cpuid;
533 ticks_per_us = (lapic_bus_freq[cpu] / 1000000) * config_apic_timer_x;
535 lapic_write(LAPIC_TIMER_ICR, usec * ticks_per_us);
537 lvtt = APIC_TDCR_1;
538 lapic_write(LAPIC_TIMER_DCR, lvtt);
540 /* configure timer as one-shot */
541 lvtt = APIC_TIMER_INT_VECTOR;
542 lapic_write(LAPIC_LVTTR, lvtt);
545 void lapic_set_timer_periodic(const unsigned freq)
547 /* sleep in micro seconds */
548 u32_t lvtt;
549 u32_t lapic_ticks_per_clock_tick;
550 const u8_t cpu = cpuid;
552 lapic_ticks_per_clock_tick = (lapic_bus_freq[cpu] / freq) * config_apic_timer_x;
554 lvtt = APIC_TDCR_1;
555 lapic_write(LAPIC_TIMER_DCR, lvtt);
557 /* configure timer as periodic */
558 lvtt = APIC_LVTT_TM | APIC_TIMER_INT_VECTOR;
559 lapic_write(LAPIC_LVTTR, lvtt);
561 lapic_write(LAPIC_TIMER_ICR, lapic_ticks_per_clock_tick);
564 void lapic_stop_timer(void)
566 u32_t lvtt;
567 lvtt = lapic_read(LAPIC_LVTTR);
568 lapic_write(LAPIC_LVTTR, lvtt | APIC_LVTT_MASK);
569 /* zero the current counter so it can be restarted again */
570 lapic_write(LAPIC_TIMER_ICR, 0);
571 lapic_write(LAPIC_TIMER_CCR, 0);
574 void lapic_restart_timer(void)
576 /* restart the timer only if the counter reached zero, i.e. expired */
577 if (lapic_read(LAPIC_TIMER_CCR) == 0)
578 lapic_set_timer_one_shot(1000000/system_hz);
581 void lapic_microsec_sleep(unsigned count)
583 lapic_set_timer_one_shot(count);
584 while (lapic_read(LAPIC_TIMER_CCR))
585 arch_pause();
588 static u32_t lapic_errstatus(void)
590 lapic_write(LAPIC_ESR, 0);
591 return lapic_read(LAPIC_ESR);
594 #ifdef CONFIG_SMP
595 static int lapic_disable_in_msr(void)
597 u32_t msr_hi, msr_lo;
599 ia32_msr_read(IA32_APIC_BASE, &msr_hi, &msr_lo);
601 msr_lo &= ~(1 << IA32_APIC_BASE_ENABLE_BIT);
602 ia32_msr_write(IA32_APIC_BASE, msr_hi, msr_lo);
604 return 1;
606 #endif /* CONFIG_SMP */
608 void lapic_disable(void)
610 /* Disable current APIC and close interrupts from PIC */
611 u32_t val;
613 if (!lapic_addr)
614 return;
616 #ifdef CONFIG_SMP
617 if (cpu_is_bsp(cpuid) && !apic_imcrp)
618 #endif
620 /* leave it enabled if imcr is not set */
621 val = lapic_read(LAPIC_LINT0);
622 val &= ~(APIC_ICR_DM_MASK|APIC_ICR_INT_MASK);
623 val |= APIC_ICR_DM_EXTINT; /* ExtINT at LINT0 */
624 lapic_write (LAPIC_LINT0, val);
625 return;
628 #ifdef CONFIG_SMP
629 val = lapic_read(LAPIC_LINT0) & 0xFFFE58FF;
630 val |= APIC_ICR_INT_MASK;
631 lapic_write (LAPIC_LINT0, val);
633 val = lapic_read(LAPIC_LINT1) & 0xFFFE58FF;
634 val |= APIC_ICR_INT_MASK;
635 lapic_write (LAPIC_LINT1, val);
637 val = lapic_read(LAPIC_SIVR) & 0xFFFFFF00;
638 val &= ~APIC_ENABLE;
639 lapic_write(LAPIC_SIVR, val);
641 lapic_disable_in_msr();
642 #endif /* CONFIG_SMP */
645 static int lapic_enable_in_msr(void)
647 u32_t msr_hi, msr_lo;
649 ia32_msr_read(IA32_APIC_BASE, &msr_hi, &msr_lo);
651 #if 0
652 u32_t addr;
653 /*FIXME this is a problem on AP */
655 * FIXME if the location is different (unlikely) then the one we expect,
656 * update it
658 addr = (msr_lo >> 12) | ((msr_hi & 0xf) << 20);
659 if (addr != (lapic_addr >> 12)) {
660 if (msr_hi & 0xf) {
661 printf("ERROR : APIC address needs more then 32 bits\n");
662 return 0;
664 lapic_addr = msr_lo & ~((1 << 12) - 1);
666 #endif
668 msr_lo |= (1 << IA32_APIC_BASE_ENABLE_BIT);
669 ia32_msr_write(IA32_APIC_BASE, msr_hi, msr_lo);
671 return 1;
674 int lapic_enable(unsigned cpu)
676 u32_t val, nlvt;
678 if (!lapic_addr)
679 return 0;
681 cpu_has_tsc = _cpufeature(_CPUF_I386_TSC);
682 if (!cpu_has_tsc) {
683 printf("CPU lacks timestamp counter, "
684 "cannot calibrate LAPIC timer\n");
685 return 0;
688 if (!lapic_enable_in_msr())
689 return 0;
691 /* set the highest priority for ever */
692 lapic_write(LAPIC_TPR, 0x0);
694 lapic_eoi_addr = LAPIC_EOI;
695 /* clear error state register. */
696 val = lapic_errstatus ();
698 /* Enable Local APIC and set the spurious vector to 0xff. */
699 val = lapic_read(LAPIC_SIVR);
700 val |= APIC_ENABLE | APIC_SPURIOUS_INT_VECTOR;
701 val &= ~APIC_FOCUS_DISABLED;
702 lapic_write(LAPIC_SIVR, val);
703 (void) lapic_read(LAPIC_SIVR);
705 apic_eoi();
707 /* Program Logical Destination Register. */
708 val = lapic_read(LAPIC_LDR) & ~0xFF000000;
709 val |= (cpu & 0xFF) << 24;
710 lapic_write(LAPIC_LDR, val);
712 /* Program Destination Format Register for Flat mode. */
713 val = lapic_read(LAPIC_DFR) | 0xF0000000;
714 lapic_write (LAPIC_DFR, val);
716 val = lapic_read (LAPIC_LVTER) & 0xFFFFFF00;
717 lapic_write (LAPIC_LVTER, val);
719 nlvt = (lapic_read(LAPIC_VERSION)>>16) & 0xFF;
721 if(nlvt >= 4) {
722 val = lapic_read(LAPIC_LVTTMR);
723 lapic_write(LAPIC_LVTTMR, val | APIC_ICR_INT_MASK);
726 if(nlvt >= 5) {
727 val = lapic_read(LAPIC_LVTPCR);
728 lapic_write(LAPIC_LVTPCR, val | APIC_ICR_INT_MASK);
731 /* setup TPR to allow all interrupts. */
732 val = lapic_read (LAPIC_TPR);
733 /* accept all interrupts */
734 lapic_write (LAPIC_TPR, val & ~0xFF);
736 (void) lapic_read (LAPIC_SIVR);
737 apic_eoi();
739 apic_calibrate_clocks(cpu);
740 BOOT_VERBOSE(printf("APIC timer calibrated\n"));
742 return 1;
745 void apic_spurios_intr_handler(void)
747 static unsigned x;
749 x++;
750 if (x == 1 || (x % 100) == 0)
751 printf("WARNING spurious interrupt(s) %d on cpu %d\n", x, cpuid);
754 void apic_error_intr_handler(void)
756 static unsigned x;
758 x++;
759 if (x == 1 || (x % 100) == 0)
760 printf("WARNING apic error (0x%x) interrupt(s) %d on cpu %d\n",
761 lapic_errstatus(), x, cpuid);
764 static struct gate_table_s gate_table_ioapic[] = {
765 { apic_hwint0, LAPIC_VECTOR( 0), INTR_PRIVILEGE },
766 { apic_hwint1, LAPIC_VECTOR( 1), INTR_PRIVILEGE },
767 { apic_hwint2, LAPIC_VECTOR( 2), INTR_PRIVILEGE },
768 { apic_hwint3, LAPIC_VECTOR( 3), INTR_PRIVILEGE },
769 { apic_hwint4, LAPIC_VECTOR( 4), INTR_PRIVILEGE },
770 { apic_hwint5, LAPIC_VECTOR( 5), INTR_PRIVILEGE },
771 { apic_hwint6, LAPIC_VECTOR( 6), INTR_PRIVILEGE },
772 { apic_hwint7, LAPIC_VECTOR( 7), INTR_PRIVILEGE },
773 { apic_hwint8, LAPIC_VECTOR( 8), INTR_PRIVILEGE },
774 { apic_hwint9, LAPIC_VECTOR( 9), INTR_PRIVILEGE },
775 { apic_hwint10, LAPIC_VECTOR(10), INTR_PRIVILEGE },
776 { apic_hwint11, LAPIC_VECTOR(11), INTR_PRIVILEGE },
777 { apic_hwint12, LAPIC_VECTOR(12), INTR_PRIVILEGE },
778 { apic_hwint13, LAPIC_VECTOR(13), INTR_PRIVILEGE },
779 { apic_hwint14, LAPIC_VECTOR(14), INTR_PRIVILEGE },
780 { apic_hwint15, LAPIC_VECTOR(15), INTR_PRIVILEGE },
781 { apic_hwint16, LAPIC_VECTOR(16), INTR_PRIVILEGE },
782 { apic_hwint17, LAPIC_VECTOR(17), INTR_PRIVILEGE },
783 { apic_hwint18, LAPIC_VECTOR(18), INTR_PRIVILEGE },
784 { apic_hwint19, LAPIC_VECTOR(19), INTR_PRIVILEGE },
785 { apic_hwint20, LAPIC_VECTOR(20), INTR_PRIVILEGE },
786 { apic_hwint21, LAPIC_VECTOR(21), INTR_PRIVILEGE },
787 { apic_hwint22, LAPIC_VECTOR(22), INTR_PRIVILEGE },
788 { apic_hwint23, LAPIC_VECTOR(23), INTR_PRIVILEGE },
789 { apic_hwint24, LAPIC_VECTOR(24), INTR_PRIVILEGE },
790 { apic_hwint25, LAPIC_VECTOR(25), INTR_PRIVILEGE },
791 { apic_hwint26, LAPIC_VECTOR(26), INTR_PRIVILEGE },
792 { apic_hwint27, LAPIC_VECTOR(27), INTR_PRIVILEGE },
793 { apic_hwint28, LAPIC_VECTOR(28), INTR_PRIVILEGE },
794 { apic_hwint29, LAPIC_VECTOR(29), INTR_PRIVILEGE },
795 { apic_hwint30, LAPIC_VECTOR(30), INTR_PRIVILEGE },
796 { apic_hwint31, LAPIC_VECTOR(31), INTR_PRIVILEGE },
797 { apic_hwint32, LAPIC_VECTOR(32), INTR_PRIVILEGE },
798 { apic_hwint33, LAPIC_VECTOR(33), INTR_PRIVILEGE },
799 { apic_hwint34, LAPIC_VECTOR(34), INTR_PRIVILEGE },
800 { apic_hwint35, LAPIC_VECTOR(35), INTR_PRIVILEGE },
801 { apic_hwint36, LAPIC_VECTOR(36), INTR_PRIVILEGE },
802 { apic_hwint37, LAPIC_VECTOR(37), INTR_PRIVILEGE },
803 { apic_hwint38, LAPIC_VECTOR(38), INTR_PRIVILEGE },
804 { apic_hwint39, LAPIC_VECTOR(39), INTR_PRIVILEGE },
805 { apic_hwint40, LAPIC_VECTOR(40), INTR_PRIVILEGE },
806 { apic_hwint41, LAPIC_VECTOR(41), INTR_PRIVILEGE },
807 { apic_hwint42, LAPIC_VECTOR(42), INTR_PRIVILEGE },
808 { apic_hwint43, LAPIC_VECTOR(43), INTR_PRIVILEGE },
809 { apic_hwint44, LAPIC_VECTOR(44), INTR_PRIVILEGE },
810 { apic_hwint45, LAPIC_VECTOR(45), INTR_PRIVILEGE },
811 { apic_hwint46, LAPIC_VECTOR(46), INTR_PRIVILEGE },
812 { apic_hwint47, LAPIC_VECTOR(47), INTR_PRIVILEGE },
813 { apic_hwint48, LAPIC_VECTOR(48), INTR_PRIVILEGE },
814 { apic_hwint49, LAPIC_VECTOR(49), INTR_PRIVILEGE },
815 { apic_hwint50, LAPIC_VECTOR(50), INTR_PRIVILEGE },
816 { apic_hwint51, LAPIC_VECTOR(51), INTR_PRIVILEGE },
817 { apic_hwint52, LAPIC_VECTOR(52), INTR_PRIVILEGE },
818 { apic_hwint53, LAPIC_VECTOR(53), INTR_PRIVILEGE },
819 { apic_hwint54, LAPIC_VECTOR(54), INTR_PRIVILEGE },
820 { apic_hwint55, LAPIC_VECTOR(55), INTR_PRIVILEGE },
821 { apic_hwint56, LAPIC_VECTOR(56), INTR_PRIVILEGE },
822 { apic_hwint57, LAPIC_VECTOR(57), INTR_PRIVILEGE },
823 { apic_hwint58, LAPIC_VECTOR(58), INTR_PRIVILEGE },
824 { apic_hwint59, LAPIC_VECTOR(59), INTR_PRIVILEGE },
825 { apic_hwint60, LAPIC_VECTOR(60), INTR_PRIVILEGE },
826 { apic_hwint61, LAPIC_VECTOR(61), INTR_PRIVILEGE },
827 { apic_hwint62, LAPIC_VECTOR(62), INTR_PRIVILEGE },
828 { apic_hwint63, LAPIC_VECTOR(63), INTR_PRIVILEGE },
829 { apic_spurios_intr, APIC_SPURIOUS_INT_VECTOR, INTR_PRIVILEGE },
830 { apic_error_intr, APIC_ERROR_INT_VECTOR, INTR_PRIVILEGE },
831 { NULL, 0, 0}
834 static struct gate_table_s gate_table_common[] = {
835 { ipc_entry_softint_orig, IPC_VECTOR_ORIG, USER_PRIVILEGE },
836 { kernel_call_entry_orig, KERN_CALL_VECTOR_ORIG, USER_PRIVILEGE },
837 { ipc_entry_softint_um, IPC_VECTOR_UM, USER_PRIVILEGE },
838 { kernel_call_entry_um, KERN_CALL_VECTOR_UM, USER_PRIVILEGE },
839 { NULL, 0, 0}
842 #ifdef CONFIG_SMP
843 static struct gate_table_s gate_table_smp[] = {
844 { apic_ipi_sched_intr, APIC_SMP_SCHED_PROC_VECTOR, INTR_PRIVILEGE },
845 { apic_ipi_halt_intr, APIC_SMP_CPU_HALT_VECTOR, INTR_PRIVILEGE },
846 { NULL, 0, 0}
848 #endif
850 #ifdef APIC_DEBUG
851 static void lapic_set_dummy_handlers(void)
853 char * handler;
854 int vect = 32; /* skip the reserved vectors */
856 handler = &lapic_intr_dummy_handles_start;
857 handler += vect * LAPIC_INTR_DUMMY_HANDLER_SIZE;
858 for(; handler < &lapic_intr_dummy_handles_end;
859 handler += LAPIC_INTR_DUMMY_HANDLER_SIZE) {
860 int_gate_idt(vect++, (vir_bytes) handler,
861 PRESENT | INT_GATE_TYPE |
862 (INTR_PRIVILEGE << DPL_SHIFT));
865 #endif
867 /* Build descriptors for interrupt gates in IDT. */
868 void apic_idt_init(const int reset)
870 u32_t val;
872 /* Set up idt tables for smp mode.
874 int is_bsp;
876 if (reset) {
877 idt_copy_vectors_pic();
878 idt_copy_vectors(gate_table_common);
879 return;
882 is_bsp = is_boot_apic(apicid());
884 #ifdef APIC_DEBUG
885 if (is_bsp)
886 printf("APIC debugging is enabled\n");
887 lapic_set_dummy_handlers();
888 #endif
890 /* Build descriptors for interrupt gates in IDT. */
891 if (ioapic_enabled)
892 idt_copy_vectors(gate_table_ioapic);
893 else
894 idt_copy_vectors_pic();
896 idt_copy_vectors(gate_table_common);
898 #ifdef CONFIG_SMP
899 idt_copy_vectors(gate_table_smp);
900 #endif
902 /* Setup error interrupt vector */
903 val = lapic_read(LAPIC_LVTER);
904 val |= APIC_ERROR_INT_VECTOR;
905 val &= ~ APIC_ICR_INT_MASK;
906 lapic_write(LAPIC_LVTER, val);
907 (void) lapic_read(LAPIC_LVTER);
909 /* configure the timer interupt handler */
910 if (is_bsp) {
911 BOOT_VERBOSE(printf("Initiating APIC timer handler\n"));
912 /* register the timer interrupt handler for this CPU */
913 int_gate_idt(APIC_TIMER_INT_VECTOR, (vir_bytes) lapic_timer_int_handler,
914 PRESENT | INT_GATE_TYPE | (INTR_PRIVILEGE << DPL_SHIFT));
919 static int acpi_get_ioapics(struct io_apic * ioa, unsigned * nioa, unsigned max)
921 unsigned n = 0;
922 struct acpi_madt_ioapic * acpi_ioa;
924 while (n < max) {
925 acpi_ioa = acpi_get_ioapic_next();
926 if (acpi_ioa == NULL)
927 break;
929 assert(acpi_ioa->address);
931 ioa[n].id = acpi_ioa->id;
932 ioa[n].addr = acpi_ioa->address;
933 ioa[n].paddr = (phys_bytes) acpi_ioa->address;
934 ioa[n].gsi_base = acpi_ioa->global_int_base;
935 ioa[n].pins = ((ioapic_read(ioa[n].addr,
936 IOAPIC_VERSION) & 0xff0000) >> 16)+1;
937 printf("IO APIC idx %d id %d addr 0x%lx paddr 0x%lx pins %d\n",
938 n, acpi_ioa->id, ioa[n].addr, ioa[n].paddr,
939 ioa[n].pins);
940 n++;
943 *nioa = n;
944 return n;
947 int detect_ioapics(void)
949 int status;
951 if (machine.acpi_rsdp) {
952 status = acpi_get_ioapics(io_apic, &nioapics, MAX_NR_IOAPICS);
953 } else {
954 status = 0;
956 if (!status) {
957 /* try something different like MPS */
960 return status;
963 #ifdef CONFIG_SMP
965 void apic_send_ipi(unsigned vector, unsigned cpu, int type)
967 u32_t icr1, icr2;
969 if (ncpus == 1)
970 /* no need of sending an IPI */
971 return;
973 while (lapic_read_icr1() & APIC_ICR_DELIVERY_PENDING)
974 arch_pause();
976 icr1 = lapic_read_icr1() & 0xFFF0F800;
977 icr2 = lapic_read_icr2() & 0xFFFFFF;
979 switch (type) {
980 case APIC_IPI_DEST:
981 if (!cpu_is_ready(cpu))
982 return;
983 lapic_write_icr2(icr2 | (cpuid2apicid[cpu] << 24));
984 lapic_write_icr1(icr1 | APIC_ICR_DEST_FIELD | vector);
985 break;
986 case APIC_IPI_SELF:
987 lapic_write_icr2(icr2);
988 lapic_write_icr1(icr1 | APIC_ICR_DEST_SELF | vector);
989 break;
990 case APIC_IPI_TO_ALL_BUT_SELF:
991 lapic_write_icr2(icr2);
992 lapic_write_icr1(icr1 | APIC_ICR_DEST_ALL_BUT_SELF | vector);
993 break;
994 case APIC_IPI_TO_ALL:
995 lapic_write_icr2(icr2);
996 lapic_write_icr1(icr1 | APIC_ICR_DEST_ALL | vector);
997 break;
998 default:
999 printf("WARNING : unknown send ipi type request\n");
1004 int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline)
1006 int timeout;
1007 u32_t errstatus = 0;
1008 int i;
1010 /* INIT-SIPI-SIPI sequence */
1012 for (i = 0; i < 2; i++) {
1013 u32_t val;
1015 /* clear err status */
1016 lapic_errstatus();
1018 /* set target pe */
1019 val = lapic_read(LAPIC_ICR2) & 0xFFFFFF;
1020 val |= cpuid2apicid[cpu] << 24;
1021 lapic_write(LAPIC_ICR2, val);
1023 /* send SIPI */
1024 val = lapic_read(LAPIC_ICR1) & 0xFFF32000;
1025 val |= APIC_ICR_LEVEL_ASSERT |APIC_ICR_DM_STARTUP;
1026 val |= (((u32_t)trampoline >> 12)&0xff);
1027 lapic_write(LAPIC_ICR1, val);
1029 timeout = 1000;
1031 /* wait for 200 micro-seconds*/
1032 lapic_microsec_sleep (200);
1033 errstatus = 0;
1035 while ((lapic_read(LAPIC_ICR1) & APIC_ICR_DELIVERY_PENDING) &&
1036 !errstatus) {
1037 errstatus = lapic_errstatus();
1038 timeout--;
1039 if (!timeout) break;
1042 /* skip this one and continue with another cpu */
1043 if (errstatus)
1044 return -1;
1047 return 0;
1050 int apic_send_init_ipi(unsigned cpu, phys_bytes trampoline)
1052 u32_t ptr, errstatus = 0;
1053 int timeout;
1055 /* set the warm reset vector */
1056 ptr = (u32_t)(trampoline & 0xF);
1057 phys_copy(0x467, vir2phys(&ptr), sizeof(u16_t ));
1058 ptr = (u32_t)(trampoline >> 4);
1059 phys_copy(0x469, vir2phys(&ptr), sizeof(u16_t ));
1061 /* set shutdown code */
1062 outb (RTC_INDEX, 0xF);
1063 outb (RTC_IO, 0xA);
1065 /* clear error state register. */
1066 (void) lapic_errstatus();
1068 /* assert INIT IPI , No Shorthand, destination mode : physical */
1069 lapic_write(LAPIC_ICR2, (lapic_read (LAPIC_ICR2) & 0xFFFFFF) |
1070 (cpuid2apicid[cpu] << 24));
1071 lapic_write(LAPIC_ICR1, (lapic_read (LAPIC_ICR1) & 0xFFF32000) |
1072 APIC_ICR_DM_INIT | APIC_ICR_TM_LEVEL | APIC_ICR_LEVEL_ASSERT);
1074 timeout = 1000;
1076 /* sleep for 200 micro-seconds */
1077 lapic_microsec_sleep(200);
1079 errstatus = 0;
1081 while ((lapic_read(LAPIC_ICR1) & APIC_ICR_DELIVERY_PENDING) && !errstatus) {
1082 errstatus = lapic_errstatus();
1083 timeout--;
1084 if (!timeout) break;
1087 if (errstatus)
1088 return -1; /* to continue with a new processor */
1090 /* clear error state register. */
1091 lapic_errstatus();
1093 /* deassert INIT IPI , No Shorthand, destination mode : physical */
1094 lapic_write(LAPIC_ICR2, (lapic_read (LAPIC_ICR2) & 0xFFFFFF) |
1095 (cpuid2apicid[cpu] << 24));
1096 lapic_write(LAPIC_ICR1, (lapic_read (LAPIC_ICR1) & 0xFFF32000) |
1097 APIC_ICR_DEST_ALL | APIC_ICR_TM_LEVEL);
1099 timeout = 1000;
1100 errstatus = 0;
1102 /* sleep for 200 micro-seconds */
1103 lapic_microsec_sleep(200);
1105 while ((lapic_read(LAPIC_ICR1)&APIC_ICR_DELIVERY_PENDING) && !errstatus) {
1106 errstatus = lapic_errstatus();
1107 timeout--;
1108 if(!timeout) break;
1111 if (errstatus)
1112 return -1; /* with the new processor */
1114 /* clear error state register. */
1115 (void) lapic_errstatus();
1117 /* wait 10ms */
1118 lapic_microsec_sleep (10000);
1120 return 0;
1122 #endif
1124 #ifndef CONFIG_SMP
1125 int apic_single_cpu_init(void)
1127 if (!cpu_feature_apic_on_chip())
1128 return 0;
1130 lapic_addr = LOCAL_APIC_DEF_ADDR;
1131 ioapic_enabled = 0;
1133 if (!lapic_enable(0)) {
1134 lapic_addr = 0x0;
1135 return 0;
1138 bsp_lapic_id = apicid();
1139 printf("Boot cpu apic id %d\n", bsp_lapic_id);
1141 acpi_init();
1143 if (!detect_ioapics()) {
1144 lapic_disable();
1145 lapic_addr = 0x0;
1146 return 0;
1149 ioapic_enable_all();
1151 if (ioapic_enabled)
1152 machine.apic_enabled = 1;
1154 apic_idt_init(0); /* Not a reset ! */
1155 idt_reload();
1156 return 1;
1158 #endif
1160 static eoi_method_t set_eoi_method(unsigned irq)
1163 * in APIC mode the lowest 16 IRQs are reserved for legacy (E)ISA edge
1164 * triggered interrupts. All the rest is for PCI level triggered
1165 * interrupts
1167 if (irq < 16)
1168 return ioapic_eoi_edge;
1169 else
1170 return ioapic_eoi_level;
1173 void set_irq_redir_low(unsigned irq, u32_t * low)
1175 u32_t val = 0;
1177 /* clear the polarity, trigger, mask and vector fields */
1178 val &= ~(APIC_ICR_VECTOR | APIC_ICR_INT_MASK |
1179 APIC_ICR_TRIGGER | APIC_ICR_INT_POLARITY);
1181 if (irq < 16) {
1182 /* ISA active-high */
1183 val &= ~APIC_ICR_INT_POLARITY;
1184 /* ISA edge triggered */
1185 val &= ~APIC_ICR_TRIGGER;
1187 else {
1188 /* PCI active-low */
1189 val |= APIC_ICR_INT_POLARITY;
1190 /* PCI level triggered */
1191 val |= APIC_ICR_TRIGGER;
1194 val |= io_apic_irq[irq].vector;
1196 *low = val;
1199 void ioapic_set_irq(unsigned irq)
1201 unsigned ioa;
1203 assert(irq < NR_IRQ_VECTORS);
1205 /* shared irq, already set */
1206 if (io_apic_irq[irq].ioa && io_apic_irq[irq].eoi)
1207 return;
1209 assert(!io_apic_irq[irq].ioa || !io_apic_irq[irq].eoi);
1211 for (ioa = 0; ioa < nioapics; ioa++) {
1212 if (io_apic[ioa].gsi_base <= irq &&
1213 io_apic[ioa].gsi_base +
1214 io_apic[ioa].pins > irq) {
1215 u32_t hi_32, low_32;
1217 io_apic_irq[irq].ioa = &io_apic[ioa];
1218 io_apic_irq[irq].pin = irq - io_apic[ioa].gsi_base;
1219 io_apic_irq[irq].eoi = set_eoi_method(irq);
1220 io_apic_irq[irq].vector = LAPIC_VECTOR(irq);
1222 set_irq_redir_low(irq, &low_32);
1224 * route the interrupts to the bsp by default
1226 hi_32 = bsp_lapic_id << 24;
1227 ioapic_redirt_entry_write((void *) io_apic[ioa].addr,
1228 io_apic_irq[irq].pin, hi_32, low_32);
1233 void ioapic_unset_irq(unsigned irq)
1235 assert(irq < NR_IRQ_VECTORS);
1237 ioapic_disable_irq(irq);
1238 io_apic_irq[irq].ioa = NULL;
1239 io_apic_irq[irq].eoi = NULL;
1242 void ioapic_reset_pic(void)
1244 apic_idt_init(TRUE); /* reset */
1245 idt_reload();
1247 /* Enable 8259 - write 0x00 in OCW1
1248 * master and slave. */
1249 outb(0x22, 0x70);
1250 outb(0x23, 0x00);
1253 static void irq_lapic_status(int irq)
1255 u32_t lo;
1256 reg_t tmr, irr, isr;
1257 int vector;
1258 struct irq * intr;
1260 intr = &io_apic_irq[irq];
1262 if (!intr->ioa)
1263 return;
1265 vector = LAPIC_VECTOR(irq);
1266 tmr = apic_read_tmr_vector(vector);
1267 irr = apic_read_irr_vector(vector);
1268 isr = apic_read_isr_vector(vector);
1271 if (lapic_test_delivery_val(isr, vector)) {
1272 printf("IRQ %d vec %d trigger %s irr %d isr %d\n",
1273 irq, vector,
1274 lapic_test_delivery_val(tmr, vector) ?
1275 "level" : "edge",
1276 lapic_test_delivery_val(irr, vector) ? 1 : 0,
1277 lapic_test_delivery_val(isr, vector) ? 1 : 0);
1278 } else {
1279 printf("IRQ %d vec %d irr %d\n",
1280 irq, vector,
1281 lapic_test_delivery_val(irr, vector) ? 1 : 0);
1284 lo = ioapic_read(intr->ioa->addr,
1285 IOAPIC_REDIR_TABLE + intr->pin * 2);
1286 printf("\tpin %2d vec 0x%02x ioa %d redir_lo 0x%08x %s\n",
1287 intr->pin,
1288 intr->vector,
1289 intr->ioa->id,
1291 intr->state & IOAPIC_IRQ_STATE_MASKED ?
1292 "masked" : "unmasked");
1295 void dump_apic_irq_state(void)
1297 int irq;
1299 printf("--- IRQs state dump ---\n");
1300 for (irq = 0; irq < NR_IRQ_VECTORS; irq++) {
1301 irq_lapic_status(irq);
1303 printf("--- all ---\n");