coverity appeasement
[minix.git] / kernel / arch / i386 / apic.c
blob597650020df509d1e614632173e505be97e3ad50
1 /*
2 * APIC handling routines. APIC is a requirement for SMP
3 */
4 #include "kernel/kernel.h"
5 #include <assert.h>
7 #include <unistd.h>
8 #include <minix/portio.h>
10 #include <minix/syslib.h>
11 #include <machine/cmos.h>
13 #include "arch_proto.h"
15 #include <minix/u64.h>
17 #include "apic.h"
18 #include "apic_asm.h"
19 #include "kernel/clock.h"
20 #include "glo.h"
21 #include "hw_intr.h"
23 #include "acpi.h"
25 #ifdef USE_WATCHDOG
26 #include "kernel/watchdog.h"
27 #endif
29 #define APIC_ENABLE 0x100
30 #define APIC_FOCUS_DISABLED (1 << 9)
31 #define APIC_SIV 0xFF
33 #define APIC_TDCR_2 0x00
34 #define APIC_TDCR_4 0x01
35 #define APIC_TDCR_8 0x02
36 #define APIC_TDCR_16 0x03
37 #define APIC_TDCR_32 0x08
38 #define APIC_TDCR_64 0x09
39 #define APIC_TDCR_128 0x0a
40 #define APIC_TDCR_1 0x0b
42 #define IS_SET(mask) (mask)
43 #define IS_CLEAR(mask) 0
45 #define APIC_LVTT_VECTOR_MASK 0x000000FF
46 #define APIC_LVTT_DS_PENDING (1 << 12)
47 #define APIC_LVTT_MASK (1 << 16)
48 #define APIC_LVTT_TM (1 << 17)
50 #define APIC_LVT_IIPP_MASK 0x00002000
51 #define APIC_LVT_IIPP_AH 0x00002000
52 #define APIC_LVT_IIPP_AL 0x00000000
54 #define APIC_LVT_TM_ONESHOT IS_CLEAR(APIC_LVTT_TM)
55 #define APIC_LVT_TM_PERIODIC IS_SET(APIC_LVTT_TM)
57 #define IOAPIC_REGSEL 0x0
58 #define IOAPIC_RW 0x10
60 #define APIC_ICR_DM_MASK 0x00000700
61 #define APIC_ICR_VECTOR APIC_LVTT_VECTOR_MASK
62 #define APIC_ICR_DM_FIXED (0 << 8)
63 #define APIC_ICR_DM_LOWEST_PRIORITY (1 << 8)
64 #define APIC_ICR_DM_SMI (2 << 8)
65 #define APIC_ICR_DM_RESERVED (3 << 8)
66 #define APIC_ICR_DM_NMI (4 << 8)
67 #define APIC_ICR_DM_INIT (5 << 8)
68 #define APIC_ICR_DM_STARTUP (6 << 8)
69 #define APIC_ICR_DM_EXTINT (7 << 8)
71 #define APIC_ICR_DM_PHYSICAL (0 << 11)
72 #define APIC_ICR_DM_LOGICAL (1 << 11)
74 #define APIC_ICR_DELIVERY_PENDING (1 << 12)
76 #define APIC_ICR_INT_POLARITY (1 << 13)
77 #define APIC_ICR_INTPOL_LOW IS_SET(APIC_ICR_INT_POLARITY)
78 #define APIC_ICR_INTPOL_HIGH IS_CLEAR(APIC_ICR_INT_POLARITY)
80 #define APIC_ICR_LEVEL_ASSERT (1 << 14)
81 #define APIC_ICR_LEVEL_DEASSERT (0 << 14)
83 #define APIC_ICR_TRIGGER (1 << 15)
84 #define APIC_ICR_TM_LEVEL IS_CLEAR(APIC_ICR_TRIGGER)
85 #define APIC_ICR_TM_EDGE IS_CLEAR(APIC_ICR_TRIGGER)
87 #define APIC_ICR_INT_MASK (1 << 16)
89 #define APIC_ICR_DEST_FIELD (0 << 18)
90 #define APIC_ICR_DEST_SELF (1 << 18)
91 #define APIC_ICR_DEST_ALL (2 << 18)
92 #define APIC_ICR_DEST_ALL_BUT_SELF (3 << 18)
94 #define IA32_APIC_BASE 0x1b
95 #define IA32_APIC_BASE_ENABLE_BIT 11
97 /* FIXME we should spread the irqs across as many priority levels as possible
98 * due to buggy hw */
99 #define LAPIC_VECTOR(irq) (IRQ0_VECTOR +(irq))
101 #define IOAPIC_IRQ_STATE_MASKED 0x1
103 /* currently only 2 interrupt priority levels are used */
104 #define SPL0 0x0
105 #define SPLHI 0xF
108 struct io_apic io_apic[MAX_NR_IOAPICS];
109 unsigned nioapics;
111 struct irq;
112 typedef void (* eoi_method_t)(struct irq *);
114 struct irq {
115 struct io_apic * ioa;
116 unsigned pin;
117 unsigned vector;
118 eoi_method_t eoi;
119 unsigned state;
122 static struct irq io_apic_irq[NR_IRQ_VECTORS];
125 * to make APIC work if SMP is not configured, we need to set the maximal number
126 * of CPUS to 1, cpuid to return 0 and the current cpu is always BSP
128 #ifdef CONFIG_SMP
130 #include "kernel/smp.h"
132 #endif
134 #include "kernel/spinlock.h"
137 #define lapic_write_icr1(val) lapic_write(LAPIC_ICR1, val)
138 #define lapic_write_icr2(val) lapic_write(LAPIC_ICR2, val)
140 #define lapic_read_icr1(x) lapic_read(LAPIC_ICR1)
141 #define lapic_read_icr2(x) lapic_read(LAPIC_ICR2)
143 #define is_boot_apic(apicid) ((apicid) == bsp_lapic_id)
145 #define VERBOSE_APIC(x) x
147 int ioapic_enabled;
148 u32_t lapic_addr_vaddr;
149 vir_bytes lapic_addr;
150 vir_bytes lapic_eoi_addr;
151 int bsp_lapic_id;
153 static volatile unsigned probe_ticks;
154 static u64_t tsc0, tsc1;
155 static u32_t lapic_tctr0, lapic_tctr1;
157 static unsigned apic_imcrp;
158 static const unsigned nlints = 0;
160 void arch_eoi(void)
162 apic_eoi();
166 * FIXME this should be a cpulocal variable but there are some problems with
167 * arch specific cpulocals. As this variable is write-once-read-only it is ok to
168 * have at as an array until we resolve the cpulocals properly
170 static u32_t lapic_bus_freq[CONFIG_MAX_CPUS];
171 /* the probe period will be roughly 100ms */
172 #define PROBE_TICKS (system_hz / 10)
174 #define IOAPIC_IOREGSEL 0x0
175 #define IOAPIC_IOWIN 0x10
177 static u32_t ioapic_read(u32_t ioa_base, u32_t reg)
179 *((volatile u32_t *)(ioa_base + IOAPIC_IOREGSEL)) = (reg & 0xff);
180 return *(volatile u32_t *)(ioa_base + IOAPIC_IOWIN);
183 static void ioapic_write(u32_t ioa_base, u8_t reg, u32_t val)
185 *((volatile u32_t *)(ioa_base + IOAPIC_IOREGSEL)) = reg;
186 *((volatile u32_t *)(ioa_base + IOAPIC_IOWIN)) = val;
189 void lapic_microsec_sleep(unsigned count);
190 void apic_idt_init(const int reset);
192 static void ioapic_enable_pin(vir_bytes ioapic_addr, int pin)
194 u32_t lo = ioapic_read(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2);
196 lo &= ~APIC_ICR_INT_MASK;
197 ioapic_write(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2, lo);
200 static void ioapic_disable_pin(vir_bytes ioapic_addr, int pin)
202 u32_t lo = ioapic_read(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2);
204 lo |= APIC_ICR_INT_MASK;
205 ioapic_write(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2, lo);
208 #if 0
209 static void ioapic_redirt_entry_read(void * ioapic_addr,
210 int entry,
211 u32_t *hi,
212 u32_t *lo)
214 *lo = ioapic_read((u32_t)ioapic_addr, (u8_t) (IOAPIC_REDIR_TABLE + entry * 2));
215 *hi = ioapic_read((u32_t)ioapic_addr, (u8_t) (IOAPIC_REDIR_TABLE + entry * 2 + 1));
218 #endif
220 static void ioapic_redirt_entry_write(void * ioapic_addr,
221 int entry,
222 u32_t hi,
223 u32_t lo)
225 #if 0
226 VERBOSE_APIC(printf("IO apic redir entry %3d "
227 "write 0x%08x 0x%08x\n", entry, hi, lo));
228 #endif
229 ioapic_write((u32_t)ioapic_addr, (u8_t) (IOAPIC_REDIR_TABLE + entry * 2 + 1), hi);
230 ioapic_write((u32_t)ioapic_addr, (u8_t) (IOAPIC_REDIR_TABLE + entry * 2), lo);
233 #define apic_read_tmr_vector(vec) \
234 lapic_read(LAPIC_TMR + 0x10 * ((vec) >> 5))
236 #define apic_read_irr_vector(vec) \
237 lapic_read(LAPIC_IRR + 0x10 * ((vec) >> 5))
239 #define apic_read_isr_vector(vec) \
240 lapic_read(LAPIC_ISR + 0x10 * ((vec) >> 5))
242 #define lapic_test_delivery_val(val, vector) ((val) & (1 << ((vector) & 0x1f)))
244 static void ioapic_eoi_level(struct irq * irq)
246 reg_t tmr;
248 tmr = apic_read_tmr_vector(irq->vector);
249 apic_eoi();
252 * test if it was a level or edge triggered interrupt. If delivered as
253 * edge exec the workaround for broken chipsets
255 if (!lapic_test_delivery_val(tmr, irq->vector)) {
256 int is_masked;
257 u32_t lo;
259 panic("EDGE instead of LEVEL!");
261 lo = ioapic_read(irq->ioa->addr,
262 IOAPIC_REDIR_TABLE + irq->pin * 2);
264 is_masked = lo & APIC_ICR_INT_MASK;
266 /* set mask and edge */
267 lo |= APIC_ICR_INT_MASK;
268 lo &= ~APIC_ICR_TRIGGER;
269 ioapic_write(irq->ioa->addr,
270 IOAPIC_REDIR_TABLE + irq->pin * 2, lo);
272 /* set back to level and restore the mask bit */
273 lo = ioapic_read(irq->ioa->addr,
274 IOAPIC_REDIR_TABLE + irq->pin * 2);
276 lo |= APIC_ICR_TRIGGER;
277 if (is_masked)
278 lo |= APIC_ICR_INT_MASK;
279 else
280 lo &= ~APIC_ICR_INT_MASK;
281 ioapic_write(irq->ioa->addr,
282 IOAPIC_REDIR_TABLE + irq->pin * 2, lo);
286 static void ioapic_eoi_edge(__unused struct irq * irq)
288 apic_eoi();
291 void ioapic_eoi(int irq)
293 if (ioapic_enabled) {
294 io_apic_irq[irq].eoi(&io_apic_irq[irq]);
296 else
297 irq_8259_eoi(irq);
300 void ioapic_set_id(u32_t addr, unsigned int id)
302 ioapic_write(addr, IOAPIC_ID, id << 24);
305 int ioapic_enable_all(void)
307 i8259_disable();
309 if (apic_imcrp) {
310 /* Select IMCR and disconnect 8259s. */
311 outb(0x22, 0x70);
312 outb(0x23, 0x01);
315 return ioapic_enabled = 1;
318 /* disables a single IO APIC */
319 static void ioapic_disable(struct io_apic * ioapic)
321 unsigned p;
323 for (p = 0; p < io_apic->pins; p++) {
324 u32_t low_32, hi_32;
325 low_32 = ioapic_read((u32_t)ioapic->addr,
326 (uint8_t) (IOAPIC_REDIR_TABLE + p * 2));
327 hi_32 = ioapic_read((u32_t)ioapic->addr,
328 (uint8_t) (IOAPIC_REDIR_TABLE + p * 2 + 1));
330 if (!(low_32 & APIC_ICR_INT_MASK)) {
331 low_32 |= APIC_ICR_INT_MASK;
332 ioapic_write((u32_t)ioapic->addr,
333 (uint8_t) (IOAPIC_REDIR_TABLE + p * 2 + 1), hi_32);
334 ioapic_write((u32_t)ioapic->addr,
335 (uint8_t) (IOAPIC_REDIR_TABLE + p * 2), low_32);
340 /* disables all IO APICs */
341 void ioapic_disable_all(void)
343 unsigned ioa;
344 if (!ioapic_enabled)
345 return;
347 for (ioa = 0 ; ioa < nioapics; ioa++)
348 ioapic_disable(&io_apic[ioa]);
350 ioapic_enabled = 0; /* io apic, disabled */
352 /* Enable 8259 - write 0x00 in OCW1 master and slave. */
353 if (apic_imcrp) {
354 outb(0x22, 0x70);
355 outb(0x23, 0x00);
358 lapic_microsec_sleep(200); /* to enable APIC to switch to PIC */
360 apic_idt_init(TRUE); /* reset */
361 idt_reload();
364 static void ioapic_disable_irq(unsigned irq)
366 if(!(io_apic_irq[irq].ioa)) {
367 printf("ioapic_disable_irq: no ioa set for irq %d!\n", irq);
368 return;
371 assert(io_apic_irq[irq].ioa);
373 ioapic_disable_pin(io_apic_irq[irq].ioa->addr, io_apic_irq[irq].pin);
374 io_apic_irq[irq].state |= IOAPIC_IRQ_STATE_MASKED;
377 static void ioapic_enable_irq(unsigned irq)
379 if(!(io_apic_irq[irq].ioa)) {
380 printf("ioapic_enable_irq: no ioa set for irq %d!\n", irq);
381 return;
384 assert(io_apic_irq[irq].ioa);
386 ioapic_enable_pin(io_apic_irq[irq].ioa->addr, io_apic_irq[irq].pin);
387 io_apic_irq[irq].state &= ~IOAPIC_IRQ_STATE_MASKED;
390 void ioapic_unmask_irq(unsigned irq)
392 if (ioapic_enabled)
393 ioapic_enable_irq(irq);
394 else
395 /* FIXME unlikely */
396 irq_8259_unmask(irq);
399 void ioapic_mask_irq(unsigned irq)
401 if (ioapic_enabled)
402 ioapic_disable_irq(irq);
403 else
404 /* FIXME unlikely */
405 irq_8259_mask(irq);
408 unsigned int apicid(void)
410 return lapic_read(LAPIC_ID) >> 24;
413 static int calib_clk_handler(irq_hook_t * UNUSED(hook))
415 u32_t tcrt;
416 u64_t tsc;
418 probe_ticks++;
419 read_tsc_64(&tsc);
420 tcrt = lapic_read(LAPIC_TIMER_CCR);
423 if (probe_ticks == 1) {
424 lapic_tctr0 = tcrt;
425 tsc0 = tsc;
427 else if (probe_ticks == PROBE_TICKS) {
428 lapic_tctr1 = tcrt;
429 tsc1 = tsc;
430 stop_8253A_timer();
433 BKL_UNLOCK();
434 return 1;
437 static int spurious_irq_handler(irq_hook_t * UNUSED(hook))
440 * Do nothing, only unlock the kernel so we do not deadlock!
442 BKL_UNLOCK();
443 return 1;
446 static void apic_calibrate_clocks(unsigned cpu)
448 u32_t lvtt, val, lapic_delta;
449 u64_t tsc_delta;
450 u64_t cpu_freq;
452 irq_hook_t calib_clk, spurious_irq;
454 BOOT_VERBOSE(printf("Calibrating clock\n"));
456 * Set Initial count register to the highest value so it does not
457 * underflow during the testing period
458 * */
459 val = 0xffffffff;
460 lapic_write (LAPIC_TIMER_ICR, val);
462 /* Set Current count register */
463 val = 0;
464 lapic_write (LAPIC_TIMER_CCR, val);
466 lvtt = lapic_read(LAPIC_TIMER_DCR) & ~0x0b;
467 /* Set Divide configuration register to 1 */
468 lvtt = APIC_TDCR_1;
469 lapic_write(LAPIC_TIMER_DCR, lvtt);
472 * mask the APIC timer interrupt in the LVT Timer Register so that we
473 * don't get an interrupt upon underflow which we don't know how to
474 * handle right know. If underflow happens, the system will not continue
475 * as something is wrong with the clock IRQ 0 and we cannot calibrate
476 * the clock which mean that we cannot run processes
478 lvtt = lapic_read (LAPIC_LVTTR);
479 lvtt |= APIC_LVTT_MASK;
480 lapic_write (LAPIC_LVTTR, lvtt);
482 /* set the probe, we use the legacy timer, IRQ 0 */
483 put_irq_handler(&calib_clk, CLOCK_IRQ, calib_clk_handler);
486 * A spurious interrupt may occur during the clock calibration. Since we
487 * do this calibration in kernel, we need a special handler which will
488 * leave the BKL unlocked like the clock handler. This is a corner case,
489 * boot time only situation
491 put_irq_handler(&spurious_irq, SPURIOUS_IRQ, spurious_irq_handler);
493 /* set the PIC timer to get some time */
494 init_8253A_timer(system_hz);
497 * We must unlock BKL here as the in-kernel interrupt will lock it
498 * again. The handler will unlock it after it is done. This is
499 * absolutely safe as only the BSP is running. It is just a workaround a
500 * corner case for APIC timer calibration
502 BKL_UNLOCK();
503 intr_enable();
505 /* loop for some time to get a sample */
506 while(probe_ticks < PROBE_TICKS) {
507 intr_enable();
510 intr_disable();
511 BKL_LOCK();
513 /* remove the probe */
514 rm_irq_handler(&calib_clk);
515 rm_irq_handler(&spurious_irq);
517 lapic_delta = lapic_tctr0 - lapic_tctr1;
518 tsc_delta = sub64(tsc1, tsc0);
520 lapic_bus_freq[cpuid] = system_hz * lapic_delta / (PROBE_TICKS - 1);
521 BOOT_VERBOSE(printf("APIC bus freq %u MHz\n",
522 lapic_bus_freq[cpuid] / 1000000));
523 cpu_freq = mul64(div64u64(tsc_delta, PROBE_TICKS - 1), make64(system_hz, 0));
524 cpu_set_freq(cpuid, cpu_freq);
525 cpu_info[cpuid].freq = div64u(cpu_freq, 1000000);
526 BOOT_VERBOSE(cpu_print_freq(cpuid));
529 void lapic_set_timer_one_shot(const u32_t usec)
531 /* sleep in micro seconds */
532 u32_t lvtt;
533 u32_t ticks_per_us;
534 const u8_t cpu = cpuid;
536 ticks_per_us = (lapic_bus_freq[cpu] / 1000000) * config_apic_timer_x;
538 lapic_write(LAPIC_TIMER_ICR, usec * ticks_per_us);
540 lvtt = APIC_TDCR_1;
541 lapic_write(LAPIC_TIMER_DCR, lvtt);
543 /* configure timer as one-shot */
544 lvtt = APIC_TIMER_INT_VECTOR;
545 lapic_write(LAPIC_LVTTR, lvtt);
548 void lapic_set_timer_periodic(const unsigned freq)
550 /* sleep in micro seconds */
551 u32_t lvtt;
552 u32_t lapic_ticks_per_clock_tick;
553 const u8_t cpu = cpuid;
555 lapic_ticks_per_clock_tick = (lapic_bus_freq[cpu] / freq) * config_apic_timer_x;
557 lvtt = APIC_TDCR_1;
558 lapic_write(LAPIC_TIMER_DCR, lvtt);
560 /* configure timer as periodic */
561 lvtt = APIC_LVTT_TM | APIC_TIMER_INT_VECTOR;
562 lapic_write(LAPIC_LVTTR, lvtt);
564 lapic_write(LAPIC_TIMER_ICR, lapic_ticks_per_clock_tick);
567 void lapic_stop_timer(void)
569 u32_t lvtt;
570 lvtt = lapic_read(LAPIC_LVTTR);
571 lapic_write(LAPIC_LVTTR, lvtt | APIC_LVTT_MASK);
572 /* zero the current counter so it can be restarted again */
573 lapic_write(LAPIC_TIMER_ICR, 0);
574 lapic_write(LAPIC_TIMER_CCR, 0);
577 void lapic_restart_timer(void)
579 /* restart the timer only if the counter reached zero, i.e. expired */
580 if (lapic_read(LAPIC_TIMER_CCR) == 0)
581 lapic_set_timer_one_shot(1000000/system_hz);
584 void lapic_microsec_sleep(unsigned count)
586 lapic_set_timer_one_shot(count);
587 while (lapic_read(LAPIC_TIMER_CCR))
588 arch_pause();
591 static u32_t lapic_errstatus(void)
593 lapic_write(LAPIC_ESR, 0);
594 return lapic_read(LAPIC_ESR);
597 #ifdef CONFIG_SMP
598 static int lapic_disable_in_msr(void)
600 u32_t msr_hi, msr_lo;
602 ia32_msr_read(IA32_APIC_BASE, &msr_hi, &msr_lo);
604 msr_lo &= ~(1 << IA32_APIC_BASE_ENABLE_BIT);
605 ia32_msr_write(IA32_APIC_BASE, msr_hi, msr_lo);
607 return 1;
609 #endif /* CONFIG_SMP */
611 void lapic_disable(void)
613 /* Disable current APIC and close interrupts from PIC */
614 u32_t val;
616 if (!lapic_addr)
617 return;
619 #ifdef CONFIG_SMP
620 if (cpu_is_bsp(cpuid) && !apic_imcrp)
621 #endif
623 /* leave it enabled if imcr is not set */
624 val = lapic_read(LAPIC_LINT0);
625 val &= ~(APIC_ICR_DM_MASK|APIC_ICR_INT_MASK);
626 val |= APIC_ICR_DM_EXTINT; /* ExtINT at LINT0 */
627 lapic_write (LAPIC_LINT0, val);
628 return;
631 #ifdef CONFIG_SMP
632 val = lapic_read(LAPIC_LINT0) & 0xFFFE58FF;
633 val |= APIC_ICR_INT_MASK;
634 lapic_write (LAPIC_LINT0, val);
636 val = lapic_read(LAPIC_LINT1) & 0xFFFE58FF;
637 val |= APIC_ICR_INT_MASK;
638 lapic_write (LAPIC_LINT1, val);
640 val = lapic_read(LAPIC_SIVR) & 0xFFFFFF00;
641 val &= ~APIC_ENABLE;
642 lapic_write(LAPIC_SIVR, val);
644 lapic_disable_in_msr();
645 #endif /* CONFIG_SMP */
648 static int lapic_enable_in_msr(void)
650 u32_t msr_hi, msr_lo;
652 ia32_msr_read(IA32_APIC_BASE, &msr_hi, &msr_lo);
654 #if 0
655 u32_t addr;
656 /*FIXME this is a problem on AP */
658 * FIXME if the location is different (unlikely) then the one we expect,
659 * update it
661 addr = (msr_lo >> 12) | ((msr_hi & 0xf) << 20);
662 if (addr != (lapic_addr >> 12)) {
663 if (msr_hi & 0xf) {
664 printf("ERROR : APIC address needs more then 32 bits\n");
665 return 0;
667 lapic_addr = msr_lo & ~((1 << 12) - 1);
669 #endif
671 msr_lo |= (1 << IA32_APIC_BASE_ENABLE_BIT);
672 ia32_msr_write(IA32_APIC_BASE, msr_hi, msr_lo);
674 return 1;
677 int lapic_enable(unsigned cpu)
679 u32_t val, nlvt;
681 if (!lapic_addr)
682 return 0;
684 cpu_has_tsc = _cpufeature(_CPUF_I386_TSC);
685 if (!cpu_has_tsc) {
686 printf("CPU lacks timestamp counter, "
687 "cannot calibrate LAPIC timer\n");
688 return 0;
691 if (!lapic_enable_in_msr())
692 return 0;
694 /* set the highest priority for ever */
695 lapic_write(LAPIC_TPR, 0x0);
697 lapic_eoi_addr = LAPIC_EOI;
698 /* clear error state register. */
699 val = lapic_errstatus ();
701 /* Enable Local APIC and set the spurious vector to 0xff. */
702 val = lapic_read(LAPIC_SIVR);
703 val |= APIC_ENABLE | APIC_SPURIOUS_INT_VECTOR;
704 val &= ~APIC_FOCUS_DISABLED;
705 lapic_write(LAPIC_SIVR, val);
706 (void) lapic_read(LAPIC_SIVR);
708 apic_eoi();
710 /* Program Logical Destination Register. */
711 val = lapic_read(LAPIC_LDR) & ~0xFF000000;
712 val |= (cpu & 0xFF) << 24;
713 lapic_write(LAPIC_LDR, val);
715 /* Program Destination Format Register for Flat mode. */
716 val = lapic_read(LAPIC_DFR) | 0xF0000000;
717 lapic_write (LAPIC_DFR, val);
719 val = lapic_read (LAPIC_LVTER) & 0xFFFFFF00;
720 lapic_write (LAPIC_LVTER, val);
722 nlvt = (lapic_read(LAPIC_VERSION)>>16) & 0xFF;
724 if(nlvt >= 4) {
725 val = lapic_read(LAPIC_LVTTMR);
726 lapic_write(LAPIC_LVTTMR, val | APIC_ICR_INT_MASK);
729 if(nlvt >= 5) {
730 val = lapic_read(LAPIC_LVTPCR);
731 lapic_write(LAPIC_LVTPCR, val | APIC_ICR_INT_MASK);
734 /* setup TPR to allow all interrupts. */
735 val = lapic_read (LAPIC_TPR);
736 /* accept all interrupts */
737 lapic_write (LAPIC_TPR, val & ~0xFF);
739 (void) lapic_read (LAPIC_SIVR);
740 apic_eoi();
742 apic_calibrate_clocks(cpu);
743 BOOT_VERBOSE(printf("APIC timer calibrated\n"));
745 return 1;
748 void apic_spurios_intr_handler(void)
750 static unsigned x;
752 x++;
753 if (x == 1 || (x % 100) == 0)
754 printf("WARNING spurious interrupt(s) %d on cpu %d\n", x, cpuid);
757 void apic_error_intr_handler(void)
759 static unsigned x;
761 x++;
762 if (x == 1 || (x % 100) == 0)
763 printf("WARNING apic error (0x%x) interrupt(s) %d on cpu %d\n",
764 lapic_errstatus(), x, cpuid);
767 static struct gate_table_s gate_table_ioapic[] = {
768 { apic_hwint0, LAPIC_VECTOR( 0), INTR_PRIVILEGE },
769 { apic_hwint1, LAPIC_VECTOR( 1), INTR_PRIVILEGE },
770 { apic_hwint2, LAPIC_VECTOR( 2), INTR_PRIVILEGE },
771 { apic_hwint3, LAPIC_VECTOR( 3), INTR_PRIVILEGE },
772 { apic_hwint4, LAPIC_VECTOR( 4), INTR_PRIVILEGE },
773 { apic_hwint5, LAPIC_VECTOR( 5), INTR_PRIVILEGE },
774 { apic_hwint6, LAPIC_VECTOR( 6), INTR_PRIVILEGE },
775 { apic_hwint7, LAPIC_VECTOR( 7), INTR_PRIVILEGE },
776 { apic_hwint8, LAPIC_VECTOR( 8), INTR_PRIVILEGE },
777 { apic_hwint9, LAPIC_VECTOR( 9), INTR_PRIVILEGE },
778 { apic_hwint10, LAPIC_VECTOR(10), INTR_PRIVILEGE },
779 { apic_hwint11, LAPIC_VECTOR(11), INTR_PRIVILEGE },
780 { apic_hwint12, LAPIC_VECTOR(12), INTR_PRIVILEGE },
781 { apic_hwint13, LAPIC_VECTOR(13), INTR_PRIVILEGE },
782 { apic_hwint14, LAPIC_VECTOR(14), INTR_PRIVILEGE },
783 { apic_hwint15, LAPIC_VECTOR(15), INTR_PRIVILEGE },
784 { apic_hwint16, LAPIC_VECTOR(16), INTR_PRIVILEGE },
785 { apic_hwint17, LAPIC_VECTOR(17), INTR_PRIVILEGE },
786 { apic_hwint18, LAPIC_VECTOR(18), INTR_PRIVILEGE },
787 { apic_hwint19, LAPIC_VECTOR(19), INTR_PRIVILEGE },
788 { apic_hwint20, LAPIC_VECTOR(20), INTR_PRIVILEGE },
789 { apic_hwint21, LAPIC_VECTOR(21), INTR_PRIVILEGE },
790 { apic_hwint22, LAPIC_VECTOR(22), INTR_PRIVILEGE },
791 { apic_hwint23, LAPIC_VECTOR(23), INTR_PRIVILEGE },
792 { apic_hwint24, LAPIC_VECTOR(24), INTR_PRIVILEGE },
793 { apic_hwint25, LAPIC_VECTOR(25), INTR_PRIVILEGE },
794 { apic_hwint26, LAPIC_VECTOR(26), INTR_PRIVILEGE },
795 { apic_hwint27, LAPIC_VECTOR(27), INTR_PRIVILEGE },
796 { apic_hwint28, LAPIC_VECTOR(28), INTR_PRIVILEGE },
797 { apic_hwint29, LAPIC_VECTOR(29), INTR_PRIVILEGE },
798 { apic_hwint30, LAPIC_VECTOR(30), INTR_PRIVILEGE },
799 { apic_hwint31, LAPIC_VECTOR(31), INTR_PRIVILEGE },
800 { apic_hwint32, LAPIC_VECTOR(32), INTR_PRIVILEGE },
801 { apic_hwint33, LAPIC_VECTOR(33), INTR_PRIVILEGE },
802 { apic_hwint34, LAPIC_VECTOR(34), INTR_PRIVILEGE },
803 { apic_hwint35, LAPIC_VECTOR(35), INTR_PRIVILEGE },
804 { apic_hwint36, LAPIC_VECTOR(36), INTR_PRIVILEGE },
805 { apic_hwint37, LAPIC_VECTOR(37), INTR_PRIVILEGE },
806 { apic_hwint38, LAPIC_VECTOR(38), INTR_PRIVILEGE },
807 { apic_hwint39, LAPIC_VECTOR(39), INTR_PRIVILEGE },
808 { apic_hwint40, LAPIC_VECTOR(40), INTR_PRIVILEGE },
809 { apic_hwint41, LAPIC_VECTOR(41), INTR_PRIVILEGE },
810 { apic_hwint42, LAPIC_VECTOR(42), INTR_PRIVILEGE },
811 { apic_hwint43, LAPIC_VECTOR(43), INTR_PRIVILEGE },
812 { apic_hwint44, LAPIC_VECTOR(44), INTR_PRIVILEGE },
813 { apic_hwint45, LAPIC_VECTOR(45), INTR_PRIVILEGE },
814 { apic_hwint46, LAPIC_VECTOR(46), INTR_PRIVILEGE },
815 { apic_hwint47, LAPIC_VECTOR(47), INTR_PRIVILEGE },
816 { apic_hwint48, LAPIC_VECTOR(48), INTR_PRIVILEGE },
817 { apic_hwint49, LAPIC_VECTOR(49), INTR_PRIVILEGE },
818 { apic_hwint50, LAPIC_VECTOR(50), INTR_PRIVILEGE },
819 { apic_hwint51, LAPIC_VECTOR(51), INTR_PRIVILEGE },
820 { apic_hwint52, LAPIC_VECTOR(52), INTR_PRIVILEGE },
821 { apic_hwint53, LAPIC_VECTOR(53), INTR_PRIVILEGE },
822 { apic_hwint54, LAPIC_VECTOR(54), INTR_PRIVILEGE },
823 { apic_hwint55, LAPIC_VECTOR(55), INTR_PRIVILEGE },
824 { apic_hwint56, LAPIC_VECTOR(56), INTR_PRIVILEGE },
825 { apic_hwint57, LAPIC_VECTOR(57), INTR_PRIVILEGE },
826 { apic_hwint58, LAPIC_VECTOR(58), INTR_PRIVILEGE },
827 { apic_hwint59, LAPIC_VECTOR(59), INTR_PRIVILEGE },
828 { apic_hwint60, LAPIC_VECTOR(60), INTR_PRIVILEGE },
829 { apic_hwint61, LAPIC_VECTOR(61), INTR_PRIVILEGE },
830 { apic_hwint62, LAPIC_VECTOR(62), INTR_PRIVILEGE },
831 { apic_hwint63, LAPIC_VECTOR(63), INTR_PRIVILEGE },
832 { apic_spurios_intr, APIC_SPURIOUS_INT_VECTOR, INTR_PRIVILEGE },
833 { apic_error_intr, APIC_ERROR_INT_VECTOR, INTR_PRIVILEGE },
834 { NULL, 0, 0}
837 static struct gate_table_s gate_table_common[] = {
838 { ipc_entry, IPC_VECTOR, USER_PRIVILEGE },
839 { kernel_call_entry, KERN_CALL_VECTOR, USER_PRIVILEGE },
840 { NULL, 0, 0}
843 #ifdef CONFIG_SMP
844 static struct gate_table_s gate_table_smp[] = {
845 { apic_ipi_sched_intr, APIC_SMP_SCHED_PROC_VECTOR, INTR_PRIVILEGE },
846 { apic_ipi_halt_intr, APIC_SMP_CPU_HALT_VECTOR, INTR_PRIVILEGE },
847 { NULL, 0, 0}
849 #endif
851 #ifdef APIC_DEBUG
852 static void lapic_set_dummy_handlers(void)
854 char * handler;
855 int vect = 32; /* skip the reserved vectors */
857 handler = &lapic_intr_dummy_handles_start;
858 handler += vect * LAPIC_INTR_DUMMY_HANDLER_SIZE;
859 for(; handler < &lapic_intr_dummy_handles_end;
860 handler += LAPIC_INTR_DUMMY_HANDLER_SIZE) {
861 int_gate_idt(vect++, (vir_bytes) handler,
862 PRESENT | INT_GATE_TYPE |
863 (INTR_PRIVILEGE << DPL_SHIFT));
866 #endif
868 /* Build descriptors for interrupt gates in IDT. */
869 void apic_idt_init(const int reset)
871 u32_t val;
873 /* Set up idt tables for smp mode.
875 int is_bsp;
877 if (reset) {
878 idt_copy_vectors_pic();
879 idt_copy_vectors(gate_table_common);
880 return;
883 is_bsp = is_boot_apic(apicid());
885 #ifdef APIC_DEBUG
886 if (is_bsp)
887 printf("APIC debugging is enabled\n");
888 lapic_set_dummy_handlers();
889 #endif
891 /* Build descriptors for interrupt gates in IDT. */
892 if (ioapic_enabled)
893 idt_copy_vectors(gate_table_ioapic);
894 else
895 idt_copy_vectors_pic();
897 idt_copy_vectors(gate_table_common);
899 #ifdef CONFIG_SMP
900 idt_copy_vectors(gate_table_smp);
901 #endif
903 /* Setup error interrupt vector */
904 val = lapic_read(LAPIC_LVTER);
905 val |= APIC_ERROR_INT_VECTOR;
906 val &= ~ APIC_ICR_INT_MASK;
907 lapic_write(LAPIC_LVTER, val);
908 (void) lapic_read(LAPIC_LVTER);
910 /* configure the timer interupt handler */
911 if (is_bsp) {
912 BOOT_VERBOSE(printf("Initiating APIC timer handler\n"));
913 /* register the timer interrupt handler for this CPU */
914 int_gate_idt(APIC_TIMER_INT_VECTOR, (vir_bytes) lapic_timer_int_handler,
915 PRESENT | INT_GATE_TYPE | (INTR_PRIVILEGE << DPL_SHIFT));
920 static int acpi_get_ioapics(struct io_apic * ioa, unsigned * nioa, unsigned max)
922 unsigned n = 0;
923 struct acpi_madt_ioapic * acpi_ioa;
925 while (n < max) {
926 acpi_ioa = acpi_get_ioapic_next();
927 if (acpi_ioa == NULL)
928 break;
930 assert(acpi_ioa->address);
932 ioa[n].id = acpi_ioa->id;
933 ioa[n].addr = acpi_ioa->address;
934 ioa[n].paddr = (phys_bytes) acpi_ioa->address;
935 ioa[n].gsi_base = acpi_ioa->global_int_base;
936 ioa[n].pins = ((ioapic_read(ioa[n].addr,
937 IOAPIC_VERSION) & 0xff0000) >> 16)+1;
938 printf("IO APIC idx %d id %d addr 0x%lx paddr 0x%lx pins %d\n",
939 n, acpi_ioa->id, ioa[n].addr, ioa[n].paddr,
940 ioa[n].pins);
941 n++;
944 *nioa = n;
945 return n;
948 int detect_ioapics(void)
950 int status;
952 if (machine.acpi_rsdp) {
953 status = acpi_get_ioapics(io_apic, &nioapics, MAX_NR_IOAPICS);
954 } else {
955 status = 0;
957 if (!status) {
958 /* try something different like MPS */
961 return status;
964 #ifdef CONFIG_SMP
966 void apic_send_ipi(unsigned vector, unsigned cpu, int type)
968 u32_t icr1, icr2;
970 if (ncpus == 1)
971 /* no need of sending an IPI */
972 return;
974 while (lapic_read_icr1() & APIC_ICR_DELIVERY_PENDING)
975 arch_pause();
977 icr1 = lapic_read_icr1() & 0xFFF0F800;
978 icr2 = lapic_read_icr2() & 0xFFFFFF;
980 switch (type) {
981 case APIC_IPI_DEST:
982 if (!cpu_is_ready(cpu))
983 return;
984 lapic_write_icr2(icr2 | (cpuid2apicid[cpu] << 24));
985 lapic_write_icr1(icr1 | APIC_ICR_DEST_FIELD | vector);
986 break;
987 case APIC_IPI_SELF:
988 lapic_write_icr2(icr2);
989 lapic_write_icr1(icr1 | APIC_ICR_DEST_SELF | vector);
990 break;
991 case APIC_IPI_TO_ALL_BUT_SELF:
992 lapic_write_icr2(icr2);
993 lapic_write_icr1(icr1 | APIC_ICR_DEST_ALL_BUT_SELF | vector);
994 break;
995 case APIC_IPI_TO_ALL:
996 lapic_write_icr2(icr2);
997 lapic_write_icr1(icr1 | APIC_ICR_DEST_ALL | vector);
998 break;
999 default:
1000 printf("WARNING : unknown send ipi type request\n");
1005 int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline)
1007 int timeout;
1008 u32_t errstatus = 0;
1009 int i;
1011 /* INIT-SIPI-SIPI sequence */
1013 for (i = 0; i < 2; i++) {
1014 u32_t val;
1016 /* clear err status */
1017 lapic_errstatus();
1019 /* set target pe */
1020 val = lapic_read(LAPIC_ICR2) & 0xFFFFFF;
1021 val |= cpuid2apicid[cpu] << 24;
1022 lapic_write(LAPIC_ICR2, val);
1024 /* send SIPI */
1025 val = lapic_read(LAPIC_ICR1) & 0xFFF32000;
1026 val |= APIC_ICR_LEVEL_ASSERT |APIC_ICR_DM_STARTUP;
1027 val |= (((u32_t)trampoline >> 12)&0xff);
1028 lapic_write(LAPIC_ICR1, val);
1030 timeout = 1000;
1032 /* wait for 200 micro-seconds*/
1033 lapic_microsec_sleep (200);
1034 errstatus = 0;
1036 while ((lapic_read(LAPIC_ICR1) & APIC_ICR_DELIVERY_PENDING) &&
1037 !errstatus) {
1038 errstatus = lapic_errstatus();
1039 timeout--;
1040 if (!timeout) break;
1043 /* skip this one and continue with another cpu */
1044 if (errstatus)
1045 return -1;
1048 return 0;
1051 int apic_send_init_ipi(unsigned cpu, phys_bytes trampoline)
1053 u32_t ptr, errstatus = 0;
1054 int timeout;
1056 /* set the warm reset vector */
1057 ptr = (u32_t)(trampoline & 0xF);
1058 phys_copy(0x467, vir2phys(&ptr), sizeof(u16_t ));
1059 ptr = (u32_t)(trampoline >> 4);
1060 phys_copy(0x469, vir2phys(&ptr), sizeof(u16_t ));
1062 /* set shutdown code */
1063 outb (RTC_INDEX, 0xF);
1064 outb (RTC_IO, 0xA);
1066 /* clear error state register. */
1067 (void) lapic_errstatus();
1069 /* assert INIT IPI , No Shorthand, destination mode : physical */
1070 lapic_write(LAPIC_ICR2, (lapic_read (LAPIC_ICR2) & 0xFFFFFF) |
1071 (cpuid2apicid[cpu] << 24));
1072 lapic_write(LAPIC_ICR1, (lapic_read (LAPIC_ICR1) & 0xFFF32000) |
1073 APIC_ICR_DM_INIT | APIC_ICR_TM_LEVEL | APIC_ICR_LEVEL_ASSERT);
1075 timeout = 1000;
1077 /* sleep for 200 micro-seconds */
1078 lapic_microsec_sleep(200);
1080 errstatus = 0;
1082 while ((lapic_read(LAPIC_ICR1) & APIC_ICR_DELIVERY_PENDING) && !errstatus) {
1083 errstatus = lapic_errstatus();
1084 timeout--;
1085 if (!timeout) break;
1088 if (errstatus)
1089 return -1; /* to continue with a new processor */
1091 /* clear error state register. */
1092 lapic_errstatus();
1094 /* deassert INIT IPI , No Shorthand, destination mode : physical */
1095 lapic_write(LAPIC_ICR2, (lapic_read (LAPIC_ICR2) & 0xFFFFFF) |
1096 (cpuid2apicid[cpu] << 24));
1097 lapic_write(LAPIC_ICR1, (lapic_read (LAPIC_ICR1) & 0xFFF32000) |
1098 APIC_ICR_DEST_ALL | APIC_ICR_TM_LEVEL);
1100 timeout = 1000;
1101 errstatus = 0;
1103 /* sleep for 200 micro-seconds */
1104 lapic_microsec_sleep(200);
1106 while ((lapic_read(LAPIC_ICR1)&APIC_ICR_DELIVERY_PENDING) && !errstatus) {
1107 errstatus = lapic_errstatus();
1108 timeout--;
1109 if(!timeout) break;
1112 if (errstatus)
1113 return -1; /* with the new processor */
1115 /* clear error state register. */
1116 (void) lapic_errstatus();
1118 /* wait 10ms */
1119 lapic_microsec_sleep (10000);
1121 return 0;
1123 #endif
1125 #ifndef CONFIG_SMP
1126 int apic_single_cpu_init(void)
1128 if (!cpu_feature_apic_on_chip())
1129 return 0;
1131 lapic_addr = LOCAL_APIC_DEF_ADDR;
1132 ioapic_enabled = 0;
1134 if (!lapic_enable(0)) {
1135 lapic_addr = 0x0;
1136 return 0;
1139 bsp_lapic_id = apicid();
1140 printf("Boot cpu apic id %d\n", bsp_lapic_id);
1142 acpi_init();
1144 if (!detect_ioapics()) {
1145 lapic_disable();
1146 lapic_addr = 0x0;
1147 return 0;
1150 ioapic_enable_all();
1152 if (ioapic_enabled)
1153 machine.apic_enabled = 1;
1155 apic_idt_init(0); /* Not a reset ! */
1156 idt_reload();
1157 return 1;
1159 #endif
1161 static eoi_method_t set_eoi_method(unsigned irq)
1164 * in APIC mode the lowest 16 IRQs are reserved for legacy (E)ISA edge
1165 * triggered interrupts. All the rest is for PCI level triggered
1166 * interrupts
1168 if (irq < 16)
1169 return ioapic_eoi_edge;
1170 else
1171 return ioapic_eoi_level;
1174 void set_irq_redir_low(unsigned irq, u32_t * low)
1176 u32_t val = 0;
1178 /* clear the polarity, trigger, mask and vector fields */
1179 val &= ~(APIC_ICR_VECTOR | APIC_ICR_INT_MASK |
1180 APIC_ICR_TRIGGER | APIC_ICR_INT_POLARITY);
1182 if (irq < 16) {
1183 /* ISA active-high */
1184 val &= ~APIC_ICR_INT_POLARITY;
1185 /* ISA edge triggered */
1186 val &= ~APIC_ICR_TRIGGER;
1188 else {
1189 /* PCI active-low */
1190 val |= APIC_ICR_INT_POLARITY;
1191 /* PCI level triggered */
1192 val |= APIC_ICR_TRIGGER;
1195 val |= io_apic_irq[irq].vector;
1197 *low = val;
1200 void ioapic_set_irq(unsigned irq)
1202 unsigned ioa;
1204 assert(irq < NR_IRQ_VECTORS);
1206 /* shared irq, already set */
1207 if (io_apic_irq[irq].ioa && io_apic_irq[irq].eoi)
1208 return;
1210 assert(!io_apic_irq[irq].ioa || !io_apic_irq[irq].eoi);
1212 for (ioa = 0; ioa < nioapics; ioa++) {
1213 if (io_apic[ioa].gsi_base <= irq &&
1214 io_apic[ioa].gsi_base +
1215 io_apic[ioa].pins > irq) {
1216 u32_t hi_32, low_32;
1218 io_apic_irq[irq].ioa = &io_apic[ioa];
1219 io_apic_irq[irq].pin = irq - io_apic[ioa].gsi_base;
1220 io_apic_irq[irq].eoi = set_eoi_method(irq);
1221 io_apic_irq[irq].vector = LAPIC_VECTOR(irq);
1223 set_irq_redir_low(irq, &low_32);
1225 * route the interrupts to the bsp by default
1227 hi_32 = bsp_lapic_id << 24;
1228 ioapic_redirt_entry_write((void *) io_apic[ioa].addr,
1229 io_apic_irq[irq].pin, hi_32, low_32);
1234 void ioapic_unset_irq(unsigned irq)
1236 assert(irq < NR_IRQ_VECTORS);
1238 ioapic_disable_irq(irq);
1239 io_apic_irq[irq].ioa = NULL;
1240 io_apic_irq[irq].eoi = NULL;
1243 void ioapic_reset_pic(void)
1245 apic_idt_init(TRUE); /* reset */
1246 idt_reload();
1248 /* Enable 8259 - write 0x00 in OCW1
1249 * master and slave. */
1250 outb(0x22, 0x70);
1251 outb(0x23, 0x00);
1254 static void irq_lapic_status(int irq)
1256 u32_t lo;
1257 reg_t tmr, irr, isr;
1258 int vector;
1259 struct irq * intr;
1261 intr = &io_apic_irq[irq];
1263 if (!intr->ioa)
1264 return;
1266 vector = LAPIC_VECTOR(irq);
1267 tmr = apic_read_tmr_vector(vector);
1268 irr = apic_read_irr_vector(vector);
1269 isr = apic_read_isr_vector(vector);
1272 if (lapic_test_delivery_val(isr, vector)) {
1273 printf("IRQ %d vec %d trigger %s irr %d isr %d\n",
1274 irq, vector,
1275 lapic_test_delivery_val(tmr, vector) ?
1276 "level" : "edge",
1277 lapic_test_delivery_val(irr, vector) ? 1 : 0,
1278 lapic_test_delivery_val(isr, vector) ? 1 : 0);
1279 } else {
1280 printf("IRQ %d vec %d irr %d\n",
1281 irq, vector,
1282 lapic_test_delivery_val(irr, vector) ? 1 : 0);
1285 lo = ioapic_read(intr->ioa->addr,
1286 IOAPIC_REDIR_TABLE + intr->pin * 2);
1287 printf("\tpin %2d vec 0x%02x ioa %d redir_lo 0x%08x %s\n",
1288 intr->pin,
1289 intr->vector,
1290 intr->ioa->id,
1292 intr->state & IOAPIC_IRQ_STATE_MASKED ?
1293 "masked" : "unmasked");
1296 void dump_apic_irq_state(void)
1298 int irq;
1300 printf("--- IRQs state dump ---\n");
1301 for (irq = 0; irq < NR_IRQ_VECTORS; irq++) {
1302 irq_lapic_status(irq);
1304 printf("--- all ---\n");