2 * APIC handling routines. APIC is a requirement for SMP
7 #include <minix/portio.h>
9 #include <minix/syslib.h>
10 #include <machine/cmos.h>
12 #include <minix/u64.h>
16 #include "kernel/clock.h"
23 #include "kernel/watchdog.h"
26 #define APIC_ENABLE 0x100
27 #define APIC_FOCUS_DISABLED (1 << 9)
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
96 #define LAPIC_VECTOR(irq) (IRQ0_VECTOR +(irq))
98 #define IOAPIC_IRQ_STATE_MASKED 0x1
100 /* currently only 2 interrupt priority levels are used */
105 struct io_apic io_apic
[MAX_NR_IOAPICS
];
109 typedef void (* eoi_method_t
)(struct irq
*);
112 struct io_apic
* ioa
;
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
127 #include "kernel/smp.h"
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
145 u32_t lapic_addr_vaddr
;
146 vir_bytes lapic_addr
;
147 vir_bytes lapic_eoi_addr
;
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;
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
);
206 static void ioapic_redirt_entry_read(void * ioapic_addr
,
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));
217 static void ioapic_redirt_entry_write(void * ioapic_addr
,
223 VERBOSE_APIC(printf("IO apic redir entry %3d "
224 "write 0x%08x 0x%08x\n", entry
, hi
, lo
));
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
)
245 tmr
= apic_read_tmr_vector(irq
->vector
);
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
)) {
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
;
275 lo
|= APIC_ICR_INT_MASK
;
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
)
288 void ioapic_eoi(int irq
)
290 if (ioapic_enabled
) {
291 io_apic_irq
[irq
].eoi(&io_apic_irq
[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)
307 /* Select IMCR and disconnect 8259s. */
312 return ioapic_enabled
= 1;
315 /* disables a single IO APIC */
316 static void ioapic_disable(struct io_apic
* ioapic
)
320 for (p
= 0; p
< io_apic
->pins
; p
++) {
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)
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. */
355 lapic_microsec_sleep(200); /* to enable APIC to switch to PIC */
357 apic_idt_init(TRUE
); /* reset */
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
);
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
);
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
)
390 ioapic_enable_irq(irq
);
393 irq_8259_unmask(irq
);
396 void ioapic_mask_irq(unsigned irq
)
399 ioapic_disable_irq(irq
);
405 unsigned int apicid(void)
407 return lapic_read(LAPIC_ID
) >> 24;
410 static int calib_clk_handler(irq_hook_t
* UNUSED(hook
))
417 tcrt
= lapic_read(LAPIC_TIMER_CCR
);
420 if (probe_ticks
== 1) {
424 else if (probe_ticks
== PROBE_TICKS
) {
434 static int spurious_irq_handler(irq_hook_t
* UNUSED(hook
))
437 * Do nothing, only unlock the kernel so we do not deadlock!
443 static void apic_calibrate_clocks(unsigned cpu
)
445 u32_t lvtt
, val
, lapic_delta
;
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
457 lapic_write (LAPIC_TIMER_ICR
, val
);
459 /* Set Current count register */
461 lapic_write (LAPIC_TIMER_CCR
, val
);
463 lvtt
= lapic_read(LAPIC_TIMER_DCR
) & ~0x0b;
464 /* Set Divide configuration register to 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
502 /* loop for some time to get a sample */
503 while(probe_ticks
< PROBE_TICKS
) {
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 */
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
);
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 */
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
;
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)
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
))
588 static u32_t
lapic_errstatus(void)
590 lapic_write(LAPIC_ESR
, 0);
591 return lapic_read(LAPIC_ESR
);
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
);
606 #endif /* CONFIG_SMP */
608 void lapic_disable(void)
610 /* Disable current APIC and close interrupts from PIC */
617 if (cpu_is_bsp(cpuid
) && !apic_imcrp
)
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
);
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;
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
);
653 /*FIXME this is a problem on AP */
655 * FIXME if the location is different (unlikely) then the one we expect,
658 addr
= (msr_lo
>> 12) | ((msr_hi
& 0xf) << 20);
659 if (addr
!= (lapic_addr
>> 12)) {
661 printf("ERROR : APIC address needs more then 32 bits\n");
664 lapic_addr
= msr_lo
& ~((1 << 12) - 1);
668 msr_lo
|= (1 << IA32_APIC_BASE_ENABLE_BIT
);
669 ia32_msr_write(IA32_APIC_BASE
, msr_hi
, msr_lo
);
674 int lapic_enable(unsigned cpu
)
681 cpu_has_tsc
= _cpufeature(_CPUF_I386_TSC
);
683 printf("CPU lacks timestamp counter, "
684 "cannot calibrate LAPIC timer\n");
688 if (!lapic_enable_in_msr())
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
);
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;
722 val
= lapic_read(LAPIC_LVTTMR
);
723 lapic_write(LAPIC_LVTTMR
, val
| APIC_ICR_INT_MASK
);
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
);
739 apic_calibrate_clocks(cpu
);
740 BOOT_VERBOSE(printf("APIC timer calibrated\n"));
745 void apic_spurios_intr_handler(void)
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)
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
},
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
},
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
},
851 static void lapic_set_dummy_handlers(void)
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
));
867 /* Build descriptors for interrupt gates in IDT. */
868 void apic_idt_init(const int reset
)
872 /* Set up idt tables for smp mode.
877 idt_copy_vectors_pic();
878 idt_copy_vectors(gate_table_common
);
882 is_bsp
= is_boot_apic(apicid());
886 printf("APIC debugging is enabled\n");
887 lapic_set_dummy_handlers();
890 /* Build descriptors for interrupt gates in IDT. */
892 idt_copy_vectors(gate_table_ioapic
);
894 idt_copy_vectors_pic();
896 idt_copy_vectors(gate_table_common
);
899 idt_copy_vectors(gate_table_smp
);
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 */
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
)
922 struct acpi_madt_ioapic
* acpi_ioa
;
925 acpi_ioa
= acpi_get_ioapic_next();
926 if (acpi_ioa
== NULL
)
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
,
947 int detect_ioapics(void)
951 if (machine
.acpi_rsdp
) {
952 status
= acpi_get_ioapics(io_apic
, &nioapics
, MAX_NR_IOAPICS
);
957 /* try something different like MPS */
965 void apic_send_ipi(unsigned vector
, unsigned cpu
, int type
)
970 /* no need of sending an IPI */
973 while (lapic_read_icr1() & APIC_ICR_DELIVERY_PENDING
)
976 icr1
= lapic_read_icr1() & 0xFFF0F800;
977 icr2
= lapic_read_icr2() & 0xFFFFFF;
981 if (!cpu_is_ready(cpu
))
983 lapic_write_icr2(icr2
| (cpuid2apicid
[cpu
] << 24));
984 lapic_write_icr1(icr1
| APIC_ICR_DEST_FIELD
| vector
);
987 lapic_write_icr2(icr2
);
988 lapic_write_icr1(icr1
| APIC_ICR_DEST_SELF
| vector
);
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
);
994 case APIC_IPI_TO_ALL
:
995 lapic_write_icr2(icr2
);
996 lapic_write_icr1(icr1
| APIC_ICR_DEST_ALL
| vector
);
999 printf("WARNING : unknown send ipi type request\n");
1004 int apic_send_startup_ipi(unsigned cpu
, phys_bytes trampoline
)
1007 u32_t errstatus
= 0;
1010 /* INIT-SIPI-SIPI sequence */
1012 for (i
= 0; i
< 2; i
++) {
1015 /* clear err status */
1019 val
= lapic_read(LAPIC_ICR2
) & 0xFFFFFF;
1020 val
|= cpuid2apicid
[cpu
] << 24;
1021 lapic_write(LAPIC_ICR2
, val
);
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
);
1031 /* wait for 200 micro-seconds*/
1032 lapic_microsec_sleep (200);
1035 while ((lapic_read(LAPIC_ICR1
) & APIC_ICR_DELIVERY_PENDING
) &&
1037 errstatus
= lapic_errstatus();
1039 if (!timeout
) break;
1042 /* skip this one and continue with another cpu */
1050 int apic_send_init_ipi(unsigned cpu
, phys_bytes trampoline
)
1052 u32_t ptr
, errstatus
= 0;
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);
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
);
1076 /* sleep for 200 micro-seconds */
1077 lapic_microsec_sleep(200);
1081 while ((lapic_read(LAPIC_ICR1
) & APIC_ICR_DELIVERY_PENDING
) && !errstatus
) {
1082 errstatus
= lapic_errstatus();
1084 if (!timeout
) break;
1088 return -1; /* to continue with a new processor */
1090 /* clear error state register. */
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
);
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();
1112 return -1; /* with the new processor */
1114 /* clear error state register. */
1115 (void) lapic_errstatus();
1118 lapic_microsec_sleep (10000);
1125 int apic_single_cpu_init(void)
1127 if (!cpu_feature_apic_on_chip())
1130 lapic_addr
= LOCAL_APIC_DEF_ADDR
;
1133 if (!lapic_enable(0)) {
1138 bsp_lapic_id
= apicid();
1139 printf("Boot cpu apic id %d\n", bsp_lapic_id
);
1143 if (!detect_ioapics()) {
1149 ioapic_enable_all();
1152 machine
.apic_enabled
= 1;
1154 apic_idt_init(0); /* Not a reset ! */
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
1168 return ioapic_eoi_edge
;
1170 return ioapic_eoi_level
;
1173 void set_irq_redir_low(unsigned irq
, u32_t
* low
)
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
);
1182 /* ISA active-high */
1183 val
&= ~APIC_ICR_INT_POLARITY
;
1184 /* ISA edge triggered */
1185 val
&= ~APIC_ICR_TRIGGER
;
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
;
1199 void ioapic_set_irq(unsigned irq
)
1203 assert(irq
< NR_IRQ_VECTORS
);
1205 /* shared irq, already set */
1206 if (io_apic_irq
[irq
].ioa
&& io_apic_irq
[irq
].eoi
)
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 */
1247 /* Enable 8259 - write 0x00 in OCW1
1248 * master and slave. */
1253 static void irq_lapic_status(int irq
)
1256 reg_t tmr
, irr
, isr
;
1260 intr
= &io_apic_irq
[irq
];
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",
1274 lapic_test_delivery_val(tmr
, vector
) ?
1276 lapic_test_delivery_val(irr
, vector
) ? 1 : 0,
1277 lapic_test_delivery_val(isr
, vector
) ? 1 : 0);
1279 printf("IRQ %d vec %d irr %d\n",
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",
1291 intr
->state
& IOAPIC_IRQ_STATE_MASKED
?
1292 "masked" : "unmasked");
1295 void dump_apic_irq_state(void)
1299 printf("--- IRQs state dump ---\n");
1300 for (irq
= 0; irq
< NR_IRQ_VECTORS
; irq
++) {
1301 irq_lapic_status(irq
);
1303 printf("--- all ---\n");