xref: /minix3/minix/kernel/arch/i386/apic.c (revision 2a4046681ace62ad0c38bcc11c47f796c74ca4c6)
1 /*
2  * APIC handling routines. APIC is a requirement for SMP
3  */
4 #include <assert.h>
5 
6 #include <unistd.h>
7 #include <minix/portio.h>
8 
9 #include <minix/syslib.h>
10 #include <machine/cmos.h>
11 
12 #include <minix/u64.h>
13 
14 #include "apic.h"
15 #include "apic_asm.h"
16 #include "kernel/clock.h"
17 #include "glo.h"
18 #include "hw_intr.h"
19 
20 #include "acpi.h"
21 
22 #ifdef USE_WATCHDOG
23 #include "kernel/watchdog.h"
24 #endif
25 
26 #define APIC_ENABLE		0x100
27 #define APIC_FOCUS_DISABLED	(1 << 9)
28 #define APIC_SIV		0xFF
29 
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
38 
39 #define IS_SET(mask)		(mask)
40 #define IS_CLEAR(mask)		0
41 
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)
46 
47 #define APIC_LVT_IIPP_MASK	0x00002000
48 #define APIC_LVT_IIPP_AH	0x00002000
49 #define APIC_LVT_IIPP_AL	0x00000000
50 
51 #define APIC_LVT_TM_ONESHOT	IS_CLEAR(APIC_LVTT_TM)
52 #define APIC_LVT_TM_PERIODIC	IS_SET(APIC_LVTT_TM)
53 
54 #define IOAPIC_REGSEL		0x0
55 #define IOAPIC_RW		0x10
56 
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)
67 
68 #define APIC_ICR_DM_PHYSICAL		(0 << 11)
69 #define APIC_ICR_DM_LOGICAL		(1 << 11)
70 
71 #define APIC_ICR_DELIVERY_PENDING	(1 << 12)
72 
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)
76 
77 #define APIC_ICR_LEVEL_ASSERT		(1 << 14)
78 #define APIC_ICR_LEVEL_DEASSERT		(0 << 14)
79 
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)
83 
84 #define APIC_ICR_INT_MASK		(1 << 16)
85 
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)
90 
91 #define IA32_APIC_BASE	0x1b
92 #define IA32_APIC_BASE_ENABLE_BIT	11
93 
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))
97 
98 #define IOAPIC_IRQ_STATE_MASKED 0x1
99 
100 /* currently only 2 interrupt priority levels are used */
101 #define SPL0				0x0
102 #define	SPLHI				0xF
103 
104 
105 struct io_apic io_apic[MAX_NR_IOAPICS];
106 unsigned nioapics;
107 
108 struct irq;
109 typedef void (* eoi_method_t)(struct irq *);
110 
111 struct irq {
112 	struct io_apic * 	ioa;
113 	unsigned		pin;
114 	unsigned		vector;
115 	eoi_method_t		eoi;
116 	unsigned		state;
117 };
118 
119 static struct irq io_apic_irq[NR_IRQ_VECTORS];
120 
121 /*
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
124  */
125 #ifdef CONFIG_SMP
126 
127 #include "kernel/smp.h"
128 
129 #endif
130 
131 #include "kernel/spinlock.h"
132 
133 
134 #define lapic_write_icr1(val)	lapic_write(LAPIC_ICR1, val)
135 #define lapic_write_icr2(val)	lapic_write(LAPIC_ICR2, val)
136 
137 #define lapic_read_icr1(x)	lapic_read(LAPIC_ICR1)
138 #define lapic_read_icr2(x)	lapic_read(LAPIC_ICR2)
139 
140 #define is_boot_apic(apicid)	((apicid) == bsp_lapic_id)
141 
142 #define VERBOSE_APIC(x) x
143 
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;
149 
150 static volatile unsigned probe_ticks;
151 static	u64_t tsc0, tsc1;
152 static	u32_t lapic_tctr0, lapic_tctr1;
153 
154 static unsigned apic_imcrp;
155 static const unsigned nlints = 0;
156 
157 void arch_eoi(void)
158 {
159 	apic_eoi();
160 }
161 
162 /*
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
166  */
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)
170 
171 #define IOAPIC_IOREGSEL	0x0
172 #define IOAPIC_IOWIN	0x10
173 
174 static u32_t ioapic_read(u32_t ioa_base, u32_t reg)
175 {
176 	*((volatile u32_t *)(ioa_base + IOAPIC_IOREGSEL)) = (reg & 0xff);
177 	return *(volatile u32_t *)(ioa_base + IOAPIC_IOWIN);
178 }
179 
180 static void ioapic_write(u32_t ioa_base, u8_t reg, u32_t val)
181 {
182 	*((volatile u32_t *)(ioa_base + IOAPIC_IOREGSEL)) = reg;
183 	*((volatile u32_t *)(ioa_base + IOAPIC_IOWIN)) = val;
184 }
185 
186 void lapic_microsec_sleep(unsigned count);
187 void apic_idt_init(const int reset);
188 
189 static void ioapic_enable_pin(vir_bytes ioapic_addr, int pin)
190 {
191 	u32_t lo = ioapic_read(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2);
192 
193 	lo &= ~APIC_ICR_INT_MASK;
194 	ioapic_write(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2, lo);
195 }
196 
197 static void ioapic_disable_pin(vir_bytes ioapic_addr, int pin)
198 {
199 	u32_t lo = ioapic_read(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2);
200 
201 	lo |= APIC_ICR_INT_MASK;
202 	ioapic_write(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2, lo);
203 }
204 
205 #if 0
206 static void ioapic_redirt_entry_read(void * ioapic_addr,
207 					int entry,
208 					u32_t *hi,
209 					u32_t *lo)
210 {
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));
213 
214 }
215 #endif
216 
217 static void ioapic_redirt_entry_write(void * ioapic_addr,
218 					int entry,
219 					u32_t hi,
220 					u32_t lo)
221 {
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);
228 }
229 
230 #define apic_read_tmr_vector(vec) \
231 		lapic_read(LAPIC_TMR + 0x10 * ((vec) >> 5))
232 
233 #define apic_read_irr_vector(vec) \
234 		lapic_read(LAPIC_IRR + 0x10 * ((vec) >> 5))
235 
236 #define apic_read_isr_vector(vec) \
237 		lapic_read(LAPIC_ISR + 0x10 * ((vec) >> 5))
238 
239 #define lapic_test_delivery_val(val, vector) ((val) & (1 << ((vector) & 0x1f)))
240 
241 static void ioapic_eoi_level(struct irq * irq)
242 {
243 	reg_t tmr;
244 
245 	tmr = apic_read_tmr_vector(irq->vector);
246 	apic_eoi();
247 
248 	/*
249 	 * test if it was a level or edge triggered interrupt. If delivered as
250 	 * edge exec the workaround for broken chipsets
251 	 */
252 	if (!lapic_test_delivery_val(tmr, irq->vector)) {
253 		int is_masked;
254 		u32_t lo;
255 
256 		panic("EDGE instead of LEVEL!");
257 
258 		lo = ioapic_read(irq->ioa->addr,
259 				IOAPIC_REDIR_TABLE + irq->pin * 2);
260 
261 		is_masked = lo & APIC_ICR_INT_MASK;
262 
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);
268 
269 		/* set back to level and restore the mask bit */
270 		lo = ioapic_read(irq->ioa->addr,
271 				IOAPIC_REDIR_TABLE + irq->pin * 2);
272 
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);
280 	}
281 }
282 
283 static void ioapic_eoi_edge(__unused struct irq * irq)
284 {
285 	apic_eoi();
286 }
287 
288 void ioapic_eoi(int irq)
289 {
290 	if (ioapic_enabled) {
291 		io_apic_irq[irq].eoi(&io_apic_irq[irq]);
292 	}
293 	else
294 		irq_8259_eoi(irq);
295 }
296 
297 void ioapic_set_id(u32_t addr, unsigned int id)
298 {
299 	ioapic_write(addr, IOAPIC_ID, id << 24);
300 }
301 
302 int ioapic_enable_all(void)
303 {
304 	i8259_disable();
305 
306 	if (apic_imcrp) {
307 		/* Select IMCR and disconnect 8259s. */
308 		outb(0x22, 0x70);
309 		outb(0x23, 0x01);
310 	}
311 
312 	return ioapic_enabled = 1;
313 }
314 
315 /* disables a single IO APIC */
316 static void ioapic_disable(struct io_apic * ioapic)
317 {
318 	unsigned p;
319 
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));
326 
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);
333 		}
334 	}
335 }
336 
337 /* disables all IO APICs */
338 void ioapic_disable_all(void)
339 {
340 	unsigned ioa;
341 	if (!ioapic_enabled)
342 		return;
343 
344 	for (ioa = 0 ; ioa < nioapics; ioa++)
345 		ioapic_disable(&io_apic[ioa]);
346 
347 	ioapic_enabled = 0; /* io apic, disabled */
348 
349 	/* Enable 8259 - write 0x00 in OCW1 master and slave.  */
350 	if (apic_imcrp) {
351 		outb(0x22, 0x70);
352 		outb(0x23, 0x00);
353 	}
354 
355 	lapic_microsec_sleep(200); /* to enable APIC to switch to PIC */
356 
357 	apic_idt_init(TRUE); /* reset */
358 	idt_reload();
359 }
360 
361 static void ioapic_disable_irq(unsigned irq)
362 {
363 	if(!(io_apic_irq[irq].ioa)) {
364 		printf("ioapic_disable_irq: no ioa set for irq %d!\n", irq);
365 		return;
366 	}
367 
368 	assert(io_apic_irq[irq].ioa);
369 
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;
372 }
373 
374 static void ioapic_enable_irq(unsigned irq)
375 {
376 	if(!(io_apic_irq[irq].ioa)) {
377 		printf("ioapic_enable_irq: no ioa set for irq %d!\n", irq);
378 		return;
379 	}
380 
381 	assert(io_apic_irq[irq].ioa);
382 
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;
385 }
386 
387 void ioapic_unmask_irq(unsigned irq)
388 {
389 	if (ioapic_enabled)
390 		ioapic_enable_irq(irq);
391 	else
392 		/* FIXME unlikely */
393 		irq_8259_unmask(irq);
394 }
395 
396 void ioapic_mask_irq(unsigned irq)
397 {
398 	if (ioapic_enabled)
399 		ioapic_disable_irq(irq);
400 	else
401 		/* FIXME unlikely */
402 		irq_8259_mask(irq);
403 }
404 
405 unsigned int apicid(void)
406 {
407 	return lapic_read(LAPIC_ID) >> 24;
408 }
409 
410 static int calib_clk_handler(irq_hook_t * UNUSED(hook))
411 {
412 	u32_t tcrt;
413 	u64_t tsc;
414 
415 	probe_ticks++;
416 	read_tsc_64(&tsc);
417 	tcrt = lapic_read(LAPIC_TIMER_CCR);
418 
419 
420 	if (probe_ticks == 1) {
421 		lapic_tctr0 = tcrt;
422 		tsc0 = tsc;
423 	}
424 	else if (probe_ticks == PROBE_TICKS) {
425 		lapic_tctr1 = tcrt;
426 		tsc1 = tsc;
427 		stop_8253A_timer();
428 	}
429 
430 	BKL_UNLOCK();
431 	return 1;
432 }
433 
434 static int spurious_irq_handler(irq_hook_t * UNUSED(hook))
435 {
436 	/*
437 	 * Do nothing, only unlock the kernel so we do not deadlock!
438 	 */
439 	BKL_UNLOCK();
440 	return 1;
441 }
442 
443 static void apic_calibrate_clocks(unsigned cpu)
444 {
445 	u32_t lvtt, val, lapic_delta;
446 	u64_t tsc_delta;
447 	u64_t cpu_freq;
448 
449 	irq_hook_t calib_clk, spurious_irq;
450 
451 	BOOT_VERBOSE(printf("Calibrating clock\n"));
452 	/*
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);
458 
459 	/* Set Current count register */
460 	val = 0;
461 	lapic_write (LAPIC_TIMER_CCR, val);
462 
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);
467 
468 	/*
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
474 	 */
475 	lvtt = lapic_read (LAPIC_LVTTR);
476 	lvtt |= APIC_LVTT_MASK;
477 	lapic_write (LAPIC_LVTTR, lvtt);
478 
479 	/* set the probe, we use the legacy timer, IRQ 0 */
480 	put_irq_handler(&calib_clk, CLOCK_IRQ, calib_clk_handler);
481 
482 	/*
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
487 	 */
488 	put_irq_handler(&spurious_irq, SPURIOUS_IRQ, spurious_irq_handler);
489 
490 	/* set the PIC timer to get some time */
491 	init_8253A_timer(system_hz);
492 
493 	/*
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
498 	 */
499 	BKL_UNLOCK();
500 	intr_enable();
501 
502 	/* loop for some time to get a sample */
503 	while(probe_ticks < PROBE_TICKS) {
504 		intr_enable();
505 	}
506 
507 	intr_disable();
508 	BKL_LOCK();
509 
510 	/* remove the probe */
511 	rm_irq_handler(&calib_clk);
512 	rm_irq_handler(&spurious_irq);
513 
514 	lapic_delta = lapic_tctr0 - lapic_tctr1;
515 	tsc_delta = tsc1 - tsc0;
516 
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));
524 }
525 
526 void lapic_set_timer_one_shot(const u32_t usec)
527 {
528 	/* sleep in micro seconds */
529 	u32_t lvtt;
530 	u32_t ticks_per_us;
531 	const u8_t cpu = cpuid;
532 
533 	ticks_per_us = (lapic_bus_freq[cpu] / 1000000) * config_apic_timer_x;
534 
535 	lapic_write(LAPIC_TIMER_ICR, usec * ticks_per_us);
536 
537 	lvtt = APIC_TDCR_1;
538 	lapic_write(LAPIC_TIMER_DCR, lvtt);
539 
540 	/* configure timer as one-shot */
541 	lvtt = APIC_TIMER_INT_VECTOR;
542 	lapic_write(LAPIC_LVTTR, lvtt);
543 }
544 
545 void lapic_set_timer_periodic(const unsigned freq)
546 {
547 	/* sleep in micro seconds */
548 	u32_t lvtt;
549 	u32_t lapic_ticks_per_clock_tick;
550 	const u8_t cpu = cpuid;
551 
552 	lapic_ticks_per_clock_tick = (lapic_bus_freq[cpu] / freq) * config_apic_timer_x;
553 
554 	lvtt = APIC_TDCR_1;
555 	lapic_write(LAPIC_TIMER_DCR, lvtt);
556 
557 	/* configure timer as periodic */
558 	lvtt = APIC_LVTT_TM | APIC_TIMER_INT_VECTOR;
559 	lapic_write(LAPIC_LVTTR, lvtt);
560 
561 	lapic_write(LAPIC_TIMER_ICR, lapic_ticks_per_clock_tick);
562 }
563 
564 void lapic_stop_timer(void)
565 {
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);
572 }
573 
574 void lapic_restart_timer(void)
575 {
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);
579 }
580 
581 void lapic_microsec_sleep(unsigned count)
582 {
583 	lapic_set_timer_one_shot(count);
584 	while (lapic_read(LAPIC_TIMER_CCR))
585 		arch_pause();
586 }
587 
588 static  u32_t lapic_errstatus(void)
589 {
590 	lapic_write(LAPIC_ESR, 0);
591 	return lapic_read(LAPIC_ESR);
592 }
593 
594 #ifdef CONFIG_SMP
595 static int lapic_disable_in_msr(void)
596 {
597 	u32_t msr_hi, msr_lo;
598 
599 	ia32_msr_read(IA32_APIC_BASE, &msr_hi, &msr_lo);
600 
601 	msr_lo &= ~(1 << IA32_APIC_BASE_ENABLE_BIT);
602 	ia32_msr_write(IA32_APIC_BASE, msr_hi, msr_lo);
603 
604 	return 1;
605 }
606 #endif /* CONFIG_SMP */
607 
608 void lapic_disable(void)
609 {
610 	/* Disable current APIC and close interrupts from PIC */
611 	u32_t val;
612 
613 	if (!lapic_addr)
614 		return;
615 
616 #ifdef CONFIG_SMP
617 	if (cpu_is_bsp(cpuid) && !apic_imcrp)
618 #endif
619 	{
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;
626 	}
627 
628 #ifdef CONFIG_SMP
629 	val = lapic_read(LAPIC_LINT0) & 0xFFFE58FF;
630 	val |= APIC_ICR_INT_MASK;
631 	lapic_write (LAPIC_LINT0, val);
632 
633 	val = lapic_read(LAPIC_LINT1) & 0xFFFE58FF;
634 	val |= APIC_ICR_INT_MASK;
635 	lapic_write (LAPIC_LINT1, val);
636 
637 	val = lapic_read(LAPIC_SIVR) & 0xFFFFFF00;
638 	val &= ~APIC_ENABLE;
639 	lapic_write(LAPIC_SIVR, val);
640 
641 	lapic_disable_in_msr();
642 #endif /* CONFIG_SMP */
643 }
644 
645 static int lapic_enable_in_msr(void)
646 {
647 	u32_t msr_hi, msr_lo;
648 
649 	ia32_msr_read(IA32_APIC_BASE, &msr_hi, &msr_lo);
650 
651 #if 0
652 	u32_t addr;
653 	/*FIXME this is a problem on AP */
654 	/*
655 	 * FIXME if the location is different (unlikely) then the one we expect,
656 	 * update it
657 	 */
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;
663 		}
664 		lapic_addr = msr_lo & ~((1 << 12) - 1);
665 	}
666 #endif
667 
668 	msr_lo |= (1 << IA32_APIC_BASE_ENABLE_BIT);
669 	ia32_msr_write(IA32_APIC_BASE, msr_hi, msr_lo);
670 
671 	return 1;
672 }
673 
674 int lapic_enable(unsigned cpu)
675 {
676 	u32_t val, nlvt;
677 
678 	if (!lapic_addr)
679 		return 0;
680 
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;
686 	}
687 
688 	if (!lapic_enable_in_msr())
689 		return 0;
690 
691 	/* set the highest priority for ever */
692 	lapic_write(LAPIC_TPR, 0x0);
693 
694 	lapic_eoi_addr = LAPIC_EOI;
695 	/* clear error state register. */
696 	val = lapic_errstatus ();
697 
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);
704 
705 	apic_eoi();
706 
707 	/* Program Logical Destination Register. */
708 	val = lapic_read(LAPIC_LDR) & ~0xFF000000;
709 	val |= (cpu & 0xFF) << 24;
710 	lapic_write(LAPIC_LDR, val);
711 
712 	/* Program Destination Format Register for Flat mode. */
713 	val = lapic_read(LAPIC_DFR) | 0xF0000000;
714 	lapic_write (LAPIC_DFR, val);
715 
716 	val = lapic_read (LAPIC_LVTER) & 0xFFFFFF00;
717 	lapic_write (LAPIC_LVTER, val);
718 
719 	nlvt = (lapic_read(LAPIC_VERSION)>>16) & 0xFF;
720 
721 	if(nlvt >= 4) {
722 		val = lapic_read(LAPIC_LVTTMR);
723 		lapic_write(LAPIC_LVTTMR, val | APIC_ICR_INT_MASK);
724 	}
725 
726 	if(nlvt >= 5) {
727 		val = lapic_read(LAPIC_LVTPCR);
728 		lapic_write(LAPIC_LVTPCR, val | APIC_ICR_INT_MASK);
729 	}
730 
731 	/* setup TPR to allow all interrupts. */
732 	val = lapic_read (LAPIC_TPR);
733 	/* accept all interrupts */
734 	lapic_write (LAPIC_TPR, val & ~0xFF);
735 
736 	(void) lapic_read (LAPIC_SIVR);
737 	apic_eoi();
738 
739 	apic_calibrate_clocks(cpu);
740 	BOOT_VERBOSE(printf("APIC timer calibrated\n"));
741 
742 	return 1;
743 }
744 
745 void apic_spurios_intr_handler(void)
746 {
747 	static unsigned x;
748 
749 	x++;
750 	if (x == 1 || (x % 100) == 0)
751 		printf("WARNING spurious interrupt(s) %d on cpu %d\n", x, cpuid);
752 }
753 
754 void apic_error_intr_handler(void)
755 {
756 	static unsigned x;
757 
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);
762 }
763 
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}
832 };
833 
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}
840 };
841 
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}
847 };
848 #endif
849 
850 #ifdef APIC_DEBUG
851 static void lapic_set_dummy_handlers(void)
852 {
853 	char * handler;
854 	int vect = 32; /* skip the reserved vectors */
855 
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));
863 	}
864 }
865 #endif
866 
867 /* Build descriptors for interrupt gates in IDT. */
868 void apic_idt_init(const int reset)
869 {
870 	u32_t val;
871 
872 	/* Set up idt tables for smp mode.
873 	 */
874 	int is_bsp;
875 
876 	if (reset) {
877 		idt_copy_vectors_pic();
878 		idt_copy_vectors(gate_table_common);
879 		return;
880 	}
881 
882 	is_bsp = is_boot_apic(apicid());
883 
884 #ifdef APIC_DEBUG
885 	if (is_bsp)
886 		printf("APIC debugging is enabled\n");
887 	lapic_set_dummy_handlers();
888 #endif
889 
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();
895 
896 	idt_copy_vectors(gate_table_common);
897 
898 #ifdef CONFIG_SMP
899 	idt_copy_vectors(gate_table_smp);
900 #endif
901 
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);
908 
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));
915 	}
916 
917 }
918 
919 static int acpi_get_ioapics(struct io_apic * ioa, unsigned * nioa, unsigned max)
920 {
921 	unsigned n = 0;
922 	struct acpi_madt_ioapic * acpi_ioa;
923 
924 	while (n < max) {
925 		acpi_ioa = acpi_get_ioapic_next();
926 		if (acpi_ioa == NULL)
927 			break;
928 
929 		assert(acpi_ioa->address);
930 
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++;
941 	}
942 
943 	*nioa = n;
944 	return n;
945 }
946 
947 int detect_ioapics(void)
948 {
949 	int status;
950 
951 	if (machine.acpi_rsdp) {
952 		status = acpi_get_ioapics(io_apic, &nioapics, MAX_NR_IOAPICS);
953 	} else {
954 		status = 0;
955 	}
956 	if (!status) {
957 		/* try something different like MPS */
958 	}
959 
960 	return status;
961 }
962 
963 #ifdef CONFIG_SMP
964 
965 void apic_send_ipi(unsigned vector, unsigned cpu, int type)
966 {
967 	u32_t icr1, icr2;
968 
969 	if (ncpus == 1)
970 		/* no need of sending an IPI */
971 		return;
972 
973 	while (lapic_read_icr1() & APIC_ICR_DELIVERY_PENDING)
974 		arch_pause();
975 
976 	icr1 = lapic_read_icr1() & 0xFFF0F800;
977 	icr2 = lapic_read_icr2() & 0xFFFFFF;
978 
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");
1000 	}
1001 
1002 }
1003 
1004 int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline)
1005 {
1006 	int timeout;
1007 	u32_t errstatus = 0;
1008 	int i;
1009 
1010 	/* INIT-SIPI-SIPI sequence */
1011 
1012 	for (i = 0; i < 2; i++) {
1013 		u32_t val;
1014 
1015 		/* clear err status */
1016 		lapic_errstatus();
1017 
1018 		/* set target pe */
1019 		val = lapic_read(LAPIC_ICR2) & 0xFFFFFF;
1020 		val |= cpuid2apicid[cpu] << 24;
1021 		lapic_write(LAPIC_ICR2, val);
1022 
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);
1028 
1029 		timeout = 1000;
1030 
1031 		/* wait for 200 micro-seconds*/
1032 		lapic_microsec_sleep (200);
1033 		errstatus = 0;
1034 
1035 		while ((lapic_read(LAPIC_ICR1) & APIC_ICR_DELIVERY_PENDING) &&
1036 				!errstatus) {
1037 			errstatus = lapic_errstatus();
1038 			timeout--;
1039 			if (!timeout) break;
1040 		}
1041 
1042 		/* skip this one and continue with another cpu */
1043 		if (errstatus)
1044 			return -1;
1045 	}
1046 
1047 	return 0;
1048 }
1049 
1050 int apic_send_init_ipi(unsigned cpu, phys_bytes trampoline)
1051 {
1052 	u32_t ptr, errstatus = 0;
1053 	int timeout;
1054 
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 ));
1060 
1061 	/* set shutdown code */
1062 	outb (RTC_INDEX, 0xF);
1063 	outb (RTC_IO, 0xA);
1064 
1065 	/* clear error state register. */
1066 	(void) lapic_errstatus();
1067 
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);
1073 
1074 	timeout = 1000;
1075 
1076 	/* sleep for 200 micro-seconds */
1077 	lapic_microsec_sleep(200);
1078 
1079 	errstatus = 0;
1080 
1081 	while ((lapic_read(LAPIC_ICR1) & APIC_ICR_DELIVERY_PENDING) && !errstatus) {
1082 		errstatus = lapic_errstatus();
1083 		timeout--;
1084 		if (!timeout) break;
1085 	}
1086 
1087 	if (errstatus)
1088 		return -1; /* to continue with a new processor */
1089 
1090 	/* clear error state register. */
1091 	lapic_errstatus();
1092 
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);
1098 
1099 	timeout = 1000;
1100 	errstatus = 0;
1101 
1102 	/* sleep for 200 micro-seconds */
1103 	lapic_microsec_sleep(200);
1104 
1105 	while ((lapic_read(LAPIC_ICR1)&APIC_ICR_DELIVERY_PENDING) && !errstatus) {
1106 		errstatus = lapic_errstatus();
1107 		timeout--;
1108 		if(!timeout) break;
1109 	}
1110 
1111 	if (errstatus)
1112 		return -1; /* with the new processor */
1113 
1114 	/* clear error state register.  */
1115 	(void) lapic_errstatus();
1116 
1117 	/* wait 10ms */
1118 	lapic_microsec_sleep (10000);
1119 
1120 	return 0;
1121 }
1122 #endif
1123 
1124 #ifndef CONFIG_SMP
1125 int apic_single_cpu_init(void)
1126 {
1127 	if (!cpu_feature_apic_on_chip())
1128 		return 0;
1129 
1130 	lapic_addr = LOCAL_APIC_DEF_ADDR;
1131 	ioapic_enabled = 0;
1132 
1133 	if (!lapic_enable(0)) {
1134 		lapic_addr = 0x0;
1135 		return 0;
1136 	}
1137 
1138 	bsp_lapic_id = apicid();
1139 	printf("Boot cpu apic id %d\n", bsp_lapic_id);
1140 
1141 	acpi_init();
1142 
1143 	if (!detect_ioapics()) {
1144 		lapic_disable();
1145 		lapic_addr = 0x0;
1146 		return 0;
1147 	}
1148 
1149 	ioapic_enable_all();
1150 
1151 	if (ioapic_enabled)
1152 		machine.apic_enabled = 1;
1153 
1154 	apic_idt_init(0); /* Not a reset ! */
1155 	idt_reload();
1156 	return 1;
1157 }
1158 #endif
1159 
1160 static eoi_method_t set_eoi_method(unsigned irq)
1161 {
1162 	/*
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
1166 	 */
1167 	if (irq < 16)
1168 		return ioapic_eoi_edge;
1169 	else
1170 		return ioapic_eoi_level;
1171 }
1172 
1173 void set_irq_redir_low(unsigned irq, u32_t * low)
1174 {
1175 	u32_t val = 0;
1176 
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);
1180 
1181 	if (irq < 16) {
1182 		/* ISA active-high */
1183 		val &= ~APIC_ICR_INT_POLARITY;
1184 		/* ISA edge triggered */
1185 		val &= ~APIC_ICR_TRIGGER;
1186 	}
1187 	else {
1188 		/* PCI active-low */
1189 		val |= APIC_ICR_INT_POLARITY;
1190 		/* PCI level triggered */
1191 		val |= APIC_ICR_TRIGGER;
1192 	}
1193 
1194 	val |= io_apic_irq[irq].vector;
1195 
1196 	*low = val;
1197 }
1198 
1199 void ioapic_set_irq(unsigned irq)
1200 {
1201 	unsigned ioa;
1202 
1203 	assert(irq < NR_IRQ_VECTORS);
1204 
1205 	/* shared irq, already set */
1206 	if (io_apic_irq[irq].ioa && io_apic_irq[irq].eoi)
1207 		return;
1208 
1209 	assert(!io_apic_irq[irq].ioa || !io_apic_irq[irq].eoi);
1210 
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;
1216 
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);
1221 
1222 			set_irq_redir_low(irq, &low_32);
1223 			/*
1224 			 * route the interrupts to the bsp by default
1225 			 */
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);
1229 		}
1230 	}
1231 }
1232 
1233 void ioapic_unset_irq(unsigned irq)
1234 {
1235 	assert(irq < NR_IRQ_VECTORS);
1236 
1237 	ioapic_disable_irq(irq);
1238 	io_apic_irq[irq].ioa = NULL;
1239 	io_apic_irq[irq].eoi = NULL;
1240 }
1241 
1242 void ioapic_reset_pic(void)
1243 {
1244 	apic_idt_init(TRUE); /* reset */
1245 	idt_reload();
1246 
1247 	/* Enable 8259 - write 0x00 in OCW1
1248 	 * master and slave.  */
1249 		outb(0x22, 0x70);
1250 		outb(0x23, 0x00);
1251 }
1252 
1253 static void irq_lapic_status(int irq)
1254 {
1255 	u32_t lo;
1256 	reg_t tmr, irr, isr;
1257 	int vector;
1258 	struct irq * intr;
1259 
1260 	intr = &io_apic_irq[irq];
1261 
1262 	if (!intr->ioa)
1263 		return;
1264 
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);
1269 
1270 
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);
1282 	}
1283 
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,
1290 			lo,
1291 			intr->state & IOAPIC_IRQ_STATE_MASKED ?
1292 			"masked" : "unmasked");
1293 }
1294 
1295 void dump_apic_irq_state(void)
1296 {
1297 	int irq;
1298 
1299 	printf("--- IRQs state dump ---\n");
1300 	for (irq = 0; irq < NR_IRQ_VECTORS; irq++) {
1301 		irq_lapic_status(irq);
1302 	}
1303 	printf("--- all ---\n");
1304 }
1305