xref: /minix3/minix/kernel/arch/i386/apic.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1 /*
2  * APIC handling routines. APIC is a requirement for SMP
3  */
4 #include "kernel/kernel.h"
5 #include <assert.h>
6 
7 #include <unistd.h>
8 #include <minix/portio.h>
9 
10 #include <minix/syslib.h>
11 #include <machine/cmos.h>
12 
13 #include "arch_proto.h"
14 
15 #include <minix/u64.h>
16 
17 #include "apic.h"
18 #include "apic_asm.h"
19 #include "kernel/clock.h"
20 #include "glo.h"
21 #include "hw_intr.h"
22 
23 #include "acpi.h"
24 
25 #ifdef USE_WATCHDOG
26 #include "kernel/watchdog.h"
27 #endif
28 
29 #define APIC_ENABLE		0x100
30 #define APIC_FOCUS_DISABLED	(1 << 9)
31 #define APIC_SIV		0xFF
32 
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
41 
42 #define IS_SET(mask)		(mask)
43 #define IS_CLEAR(mask)		0
44 
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)
49 
50 #define APIC_LVT_IIPP_MASK	0x00002000
51 #define APIC_LVT_IIPP_AH	0x00002000
52 #define APIC_LVT_IIPP_AL	0x00000000
53 
54 #define APIC_LVT_TM_ONESHOT	IS_CLEAR(APIC_LVTT_TM)
55 #define APIC_LVT_TM_PERIODIC	IS_SET(APIC_LVTT_TM)
56 
57 #define IOAPIC_REGSEL		0x0
58 #define IOAPIC_RW		0x10
59 
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)
70 
71 #define APIC_ICR_DM_PHYSICAL		(0 << 11)
72 #define APIC_ICR_DM_LOGICAL		(1 << 11)
73 
74 #define APIC_ICR_DELIVERY_PENDING	(1 << 12)
75 
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)
79 
80 #define APIC_ICR_LEVEL_ASSERT		(1 << 14)
81 #define APIC_ICR_LEVEL_DEASSERT		(0 << 14)
82 
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)
86 
87 #define APIC_ICR_INT_MASK		(1 << 16)
88 
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)
93 
94 #define IA32_APIC_BASE	0x1b
95 #define IA32_APIC_BASE_ENABLE_BIT	11
96 
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))
100 
101 #define IOAPIC_IRQ_STATE_MASKED 0x1
102 
103 /* currently only 2 interrupt priority levels are used */
104 #define SPL0				0x0
105 #define	SPLHI				0xF
106 
107 
108 struct io_apic io_apic[MAX_NR_IOAPICS];
109 unsigned nioapics;
110 
111 struct irq;
112 typedef void (* eoi_method_t)(struct irq *);
113 
114 struct irq {
115 	struct io_apic * 	ioa;
116 	unsigned		pin;
117 	unsigned		vector;
118 	eoi_method_t		eoi;
119 	unsigned		state;
120 };
121 
122 static struct irq io_apic_irq[NR_IRQ_VECTORS];
123 
124 /*
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
127  */
128 #ifdef CONFIG_SMP
129 
130 #include "kernel/smp.h"
131 
132 #endif
133 
134 #include "kernel/spinlock.h"
135 
136 
137 #define lapic_write_icr1(val)	lapic_write(LAPIC_ICR1, val)
138 #define lapic_write_icr2(val)	lapic_write(LAPIC_ICR2, val)
139 
140 #define lapic_read_icr1(x)	lapic_read(LAPIC_ICR1)
141 #define lapic_read_icr2(x)	lapic_read(LAPIC_ICR2)
142 
143 #define is_boot_apic(apicid)	((apicid) == bsp_lapic_id)
144 
145 #define VERBOSE_APIC(x) x
146 
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;
152 
153 static volatile unsigned probe_ticks;
154 static	u64_t tsc0, tsc1;
155 static	u32_t lapic_tctr0, lapic_tctr1;
156 
157 static unsigned apic_imcrp;
158 static const unsigned nlints = 0;
159 
160 void arch_eoi(void)
161 {
162 	apic_eoi();
163 }
164 
165 /*
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
169  */
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)
173 
174 #define IOAPIC_IOREGSEL	0x0
175 #define IOAPIC_IOWIN	0x10
176 
177 static u32_t ioapic_read(u32_t ioa_base, u32_t reg)
178 {
179 	*((volatile u32_t *)(ioa_base + IOAPIC_IOREGSEL)) = (reg & 0xff);
180 	return *(volatile u32_t *)(ioa_base + IOAPIC_IOWIN);
181 }
182 
183 static void ioapic_write(u32_t ioa_base, u8_t reg, u32_t val)
184 {
185 	*((volatile u32_t *)(ioa_base + IOAPIC_IOREGSEL)) = reg;
186 	*((volatile u32_t *)(ioa_base + IOAPIC_IOWIN)) = val;
187 }
188 
189 void lapic_microsec_sleep(unsigned count);
190 void apic_idt_init(const int reset);
191 
192 static void ioapic_enable_pin(vir_bytes ioapic_addr, int pin)
193 {
194 	u32_t lo = ioapic_read(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2);
195 
196 	lo &= ~APIC_ICR_INT_MASK;
197 	ioapic_write(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2, lo);
198 }
199 
200 static void ioapic_disable_pin(vir_bytes ioapic_addr, int pin)
201 {
202 	u32_t lo = ioapic_read(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2);
203 
204 	lo |= APIC_ICR_INT_MASK;
205 	ioapic_write(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2, lo);
206 }
207 
208 #if 0
209 static void ioapic_redirt_entry_read(void * ioapic_addr,
210 					int entry,
211 					u32_t *hi,
212 					u32_t *lo)
213 {
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));
216 
217 }
218 #endif
219 
220 static void ioapic_redirt_entry_write(void * ioapic_addr,
221 					int entry,
222 					u32_t hi,
223 					u32_t lo)
224 {
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);
231 }
232 
233 #define apic_read_tmr_vector(vec) \
234 		lapic_read(LAPIC_TMR + 0x10 * ((vec) >> 5))
235 
236 #define apic_read_irr_vector(vec) \
237 		lapic_read(LAPIC_IRR + 0x10 * ((vec) >> 5))
238 
239 #define apic_read_isr_vector(vec) \
240 		lapic_read(LAPIC_ISR + 0x10 * ((vec) >> 5))
241 
242 #define lapic_test_delivery_val(val, vector) ((val) & (1 << ((vector) & 0x1f)))
243 
244 static void ioapic_eoi_level(struct irq * irq)
245 {
246 	reg_t tmr;
247 
248 	tmr = apic_read_tmr_vector(irq->vector);
249 	apic_eoi();
250 
251 	/*
252 	 * test if it was a level or edge triggered interrupt. If delivered as
253 	 * edge exec the workaround for broken chipsets
254 	 */
255 	if (!lapic_test_delivery_val(tmr, irq->vector)) {
256 		int is_masked;
257 		u32_t lo;
258 
259 		panic("EDGE instead of LEVEL!");
260 
261 		lo = ioapic_read(irq->ioa->addr,
262 				IOAPIC_REDIR_TABLE + irq->pin * 2);
263 
264 		is_masked = lo & APIC_ICR_INT_MASK;
265 
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);
271 
272 		/* set back to level and restore the mask bit */
273 		lo = ioapic_read(irq->ioa->addr,
274 				IOAPIC_REDIR_TABLE + irq->pin * 2);
275 
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);
283 	}
284 }
285 
286 static void ioapic_eoi_edge(__unused struct irq * irq)
287 {
288 	apic_eoi();
289 }
290 
291 void ioapic_eoi(int irq)
292 {
293 	if (ioapic_enabled) {
294 		io_apic_irq[irq].eoi(&io_apic_irq[irq]);
295 	}
296 	else
297 		irq_8259_eoi(irq);
298 }
299 
300 void ioapic_set_id(u32_t addr, unsigned int id)
301 {
302 	ioapic_write(addr, IOAPIC_ID, id << 24);
303 }
304 
305 int ioapic_enable_all(void)
306 {
307 	i8259_disable();
308 
309 	if (apic_imcrp) {
310 		/* Select IMCR and disconnect 8259s. */
311 		outb(0x22, 0x70);
312 		outb(0x23, 0x01);
313 	}
314 
315 	return ioapic_enabled = 1;
316 }
317 
318 /* disables a single IO APIC */
319 static void ioapic_disable(struct io_apic * ioapic)
320 {
321 	unsigned p;
322 
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));
329 
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);
336 		}
337 	}
338 }
339 
340 /* disables all IO APICs */
341 void ioapic_disable_all(void)
342 {
343 	unsigned ioa;
344 	if (!ioapic_enabled)
345 		return;
346 
347 	for (ioa = 0 ; ioa < nioapics; ioa++)
348 		ioapic_disable(&io_apic[ioa]);
349 
350 	ioapic_enabled = 0; /* io apic, disabled */
351 
352 	/* Enable 8259 - write 0x00 in OCW1 master and slave.  */
353 	if (apic_imcrp) {
354 		outb(0x22, 0x70);
355 		outb(0x23, 0x00);
356 	}
357 
358 	lapic_microsec_sleep(200); /* to enable APIC to switch to PIC */
359 
360 	apic_idt_init(TRUE); /* reset */
361 	idt_reload();
362 }
363 
364 static void ioapic_disable_irq(unsigned irq)
365 {
366 	if(!(io_apic_irq[irq].ioa)) {
367 		printf("ioapic_disable_irq: no ioa set for irq %d!\n", irq);
368 		return;
369 	}
370 
371 	assert(io_apic_irq[irq].ioa);
372 
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;
375 }
376 
377 static void ioapic_enable_irq(unsigned irq)
378 {
379 	if(!(io_apic_irq[irq].ioa)) {
380 		printf("ioapic_enable_irq: no ioa set for irq %d!\n", irq);
381 		return;
382 	}
383 
384 	assert(io_apic_irq[irq].ioa);
385 
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;
388 }
389 
390 void ioapic_unmask_irq(unsigned irq)
391 {
392 	if (ioapic_enabled)
393 		ioapic_enable_irq(irq);
394 	else
395 		/* FIXME unlikely */
396 		irq_8259_unmask(irq);
397 }
398 
399 void ioapic_mask_irq(unsigned irq)
400 {
401 	if (ioapic_enabled)
402 		ioapic_disable_irq(irq);
403 	else
404 		/* FIXME unlikely */
405 		irq_8259_mask(irq);
406 }
407 
408 unsigned int apicid(void)
409 {
410 	return lapic_read(LAPIC_ID) >> 24;
411 }
412 
413 static int calib_clk_handler(irq_hook_t * UNUSED(hook))
414 {
415 	u32_t tcrt;
416 	u64_t tsc;
417 
418 	probe_ticks++;
419 	read_tsc_64(&tsc);
420 	tcrt = lapic_read(LAPIC_TIMER_CCR);
421 
422 
423 	if (probe_ticks == 1) {
424 		lapic_tctr0 = tcrt;
425 		tsc0 = tsc;
426 	}
427 	else if (probe_ticks == PROBE_TICKS) {
428 		lapic_tctr1 = tcrt;
429 		tsc1 = tsc;
430 		stop_8253A_timer();
431 	}
432 
433 	BKL_UNLOCK();
434 	return 1;
435 }
436 
437 static int spurious_irq_handler(irq_hook_t * UNUSED(hook))
438 {
439 	/*
440 	 * Do nothing, only unlock the kernel so we do not deadlock!
441 	 */
442 	BKL_UNLOCK();
443 	return 1;
444 }
445 
446 static void apic_calibrate_clocks(unsigned cpu)
447 {
448 	u32_t lvtt, val, lapic_delta;
449 	u64_t tsc_delta;
450 	u64_t cpu_freq;
451 
452 	irq_hook_t calib_clk, spurious_irq;
453 
454 	BOOT_VERBOSE(printf("Calibrating clock\n"));
455 	/*
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);
461 
462 	/* Set Current count register */
463 	val = 0;
464 	lapic_write (LAPIC_TIMER_CCR, val);
465 
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);
470 
471 	/*
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
477 	 */
478 	lvtt = lapic_read (LAPIC_LVTTR);
479 	lvtt |= APIC_LVTT_MASK;
480 	lapic_write (LAPIC_LVTTR, lvtt);
481 
482 	/* set the probe, we use the legacy timer, IRQ 0 */
483 	put_irq_handler(&calib_clk, CLOCK_IRQ, calib_clk_handler);
484 
485 	/*
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
490 	 */
491 	put_irq_handler(&spurious_irq, SPURIOUS_IRQ, spurious_irq_handler);
492 
493 	/* set the PIC timer to get some time */
494 	init_8253A_timer(system_hz);
495 
496 	/*
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
501 	 */
502 	BKL_UNLOCK();
503 	intr_enable();
504 
505 	/* loop for some time to get a sample */
506 	while(probe_ticks < PROBE_TICKS) {
507 		intr_enable();
508 	}
509 
510 	intr_disable();
511 	BKL_LOCK();
512 
513 	/* remove the probe */
514 	rm_irq_handler(&calib_clk);
515 	rm_irq_handler(&spurious_irq);
516 
517 	lapic_delta = lapic_tctr0 - lapic_tctr1;
518 	tsc_delta = tsc1 - tsc0;
519 
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 = (tsc_delta / (PROBE_TICKS - 1)) * make64(system_hz, 0);
524 	cpu_set_freq(cpuid, cpu_freq);
525 	cpu_info[cpuid].freq = (unsigned long)(cpu_freq / 1000000);
526 	BOOT_VERBOSE(cpu_print_freq(cpuid));
527 }
528 
529 void lapic_set_timer_one_shot(const u32_t usec)
530 {
531 	/* sleep in micro seconds */
532 	u32_t lvtt;
533 	u32_t ticks_per_us;
534 	const u8_t cpu = cpuid;
535 
536 	ticks_per_us = (lapic_bus_freq[cpu] / 1000000) * config_apic_timer_x;
537 
538 	lapic_write(LAPIC_TIMER_ICR, usec * ticks_per_us);
539 
540 	lvtt = APIC_TDCR_1;
541 	lapic_write(LAPIC_TIMER_DCR, lvtt);
542 
543 	/* configure timer as one-shot */
544 	lvtt = APIC_TIMER_INT_VECTOR;
545 	lapic_write(LAPIC_LVTTR, lvtt);
546 }
547 
548 void lapic_set_timer_periodic(const unsigned freq)
549 {
550 	/* sleep in micro seconds */
551 	u32_t lvtt;
552 	u32_t lapic_ticks_per_clock_tick;
553 	const u8_t cpu = cpuid;
554 
555 	lapic_ticks_per_clock_tick = (lapic_bus_freq[cpu] / freq) * config_apic_timer_x;
556 
557 	lvtt = APIC_TDCR_1;
558 	lapic_write(LAPIC_TIMER_DCR, lvtt);
559 
560 	/* configure timer as periodic */
561 	lvtt = APIC_LVTT_TM | APIC_TIMER_INT_VECTOR;
562 	lapic_write(LAPIC_LVTTR, lvtt);
563 
564 	lapic_write(LAPIC_TIMER_ICR, lapic_ticks_per_clock_tick);
565 }
566 
567 void lapic_stop_timer(void)
568 {
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);
575 }
576 
577 void lapic_restart_timer(void)
578 {
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);
582 }
583 
584 void lapic_microsec_sleep(unsigned count)
585 {
586 	lapic_set_timer_one_shot(count);
587 	while (lapic_read(LAPIC_TIMER_CCR))
588 		arch_pause();
589 }
590 
591 static  u32_t lapic_errstatus(void)
592 {
593 	lapic_write(LAPIC_ESR, 0);
594 	return lapic_read(LAPIC_ESR);
595 }
596 
597 #ifdef CONFIG_SMP
598 static int lapic_disable_in_msr(void)
599 {
600 	u32_t msr_hi, msr_lo;
601 
602 	ia32_msr_read(IA32_APIC_BASE, &msr_hi, &msr_lo);
603 
604 	msr_lo &= ~(1 << IA32_APIC_BASE_ENABLE_BIT);
605 	ia32_msr_write(IA32_APIC_BASE, msr_hi, msr_lo);
606 
607 	return 1;
608 }
609 #endif /* CONFIG_SMP */
610 
611 void lapic_disable(void)
612 {
613 	/* Disable current APIC and close interrupts from PIC */
614 	u32_t val;
615 
616 	if (!lapic_addr)
617 		return;
618 
619 #ifdef CONFIG_SMP
620 	if (cpu_is_bsp(cpuid) && !apic_imcrp)
621 #endif
622 	{
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;
629 	}
630 
631 #ifdef CONFIG_SMP
632 	val = lapic_read(LAPIC_LINT0) & 0xFFFE58FF;
633 	val |= APIC_ICR_INT_MASK;
634 	lapic_write (LAPIC_LINT0, val);
635 
636 	val = lapic_read(LAPIC_LINT1) & 0xFFFE58FF;
637 	val |= APIC_ICR_INT_MASK;
638 	lapic_write (LAPIC_LINT1, val);
639 
640 	val = lapic_read(LAPIC_SIVR) & 0xFFFFFF00;
641 	val &= ~APIC_ENABLE;
642 	lapic_write(LAPIC_SIVR, val);
643 
644 	lapic_disable_in_msr();
645 #endif /* CONFIG_SMP */
646 }
647 
648 static int lapic_enable_in_msr(void)
649 {
650 	u32_t msr_hi, msr_lo;
651 
652 	ia32_msr_read(IA32_APIC_BASE, &msr_hi, &msr_lo);
653 
654 #if 0
655 	u32_t addr;
656 	/*FIXME this is a problem on AP */
657 	/*
658 	 * FIXME if the location is different (unlikely) then the one we expect,
659 	 * update it
660 	 */
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;
666 		}
667 		lapic_addr = msr_lo & ~((1 << 12) - 1);
668 	}
669 #endif
670 
671 	msr_lo |= (1 << IA32_APIC_BASE_ENABLE_BIT);
672 	ia32_msr_write(IA32_APIC_BASE, msr_hi, msr_lo);
673 
674 	return 1;
675 }
676 
677 int lapic_enable(unsigned cpu)
678 {
679 	u32_t val, nlvt;
680 
681 	if (!lapic_addr)
682 		return 0;
683 
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;
689 	}
690 
691 	if (!lapic_enable_in_msr())
692 		return 0;
693 
694 	/* set the highest priority for ever */
695 	lapic_write(LAPIC_TPR, 0x0);
696 
697 	lapic_eoi_addr = LAPIC_EOI;
698 	/* clear error state register. */
699 	val = lapic_errstatus ();
700 
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);
707 
708 	apic_eoi();
709 
710 	/* Program Logical Destination Register. */
711 	val = lapic_read(LAPIC_LDR) & ~0xFF000000;
712 	val |= (cpu & 0xFF) << 24;
713 	lapic_write(LAPIC_LDR, val);
714 
715 	/* Program Destination Format Register for Flat mode. */
716 	val = lapic_read(LAPIC_DFR) | 0xF0000000;
717 	lapic_write (LAPIC_DFR, val);
718 
719 	val = lapic_read (LAPIC_LVTER) & 0xFFFFFF00;
720 	lapic_write (LAPIC_LVTER, val);
721 
722 	nlvt = (lapic_read(LAPIC_VERSION)>>16) & 0xFF;
723 
724 	if(nlvt >= 4) {
725 		val = lapic_read(LAPIC_LVTTMR);
726 		lapic_write(LAPIC_LVTTMR, val | APIC_ICR_INT_MASK);
727 	}
728 
729 	if(nlvt >= 5) {
730 		val = lapic_read(LAPIC_LVTPCR);
731 		lapic_write(LAPIC_LVTPCR, val | APIC_ICR_INT_MASK);
732 	}
733 
734 	/* setup TPR to allow all interrupts. */
735 	val = lapic_read (LAPIC_TPR);
736 	/* accept all interrupts */
737 	lapic_write (LAPIC_TPR, val & ~0xFF);
738 
739 	(void) lapic_read (LAPIC_SIVR);
740 	apic_eoi();
741 
742 	apic_calibrate_clocks(cpu);
743 	BOOT_VERBOSE(printf("APIC timer calibrated\n"));
744 
745 	return 1;
746 }
747 
748 void apic_spurios_intr_handler(void)
749 {
750 	static unsigned x;
751 
752 	x++;
753 	if (x == 1 || (x % 100) == 0)
754 		printf("WARNING spurious interrupt(s) %d on cpu %d\n", x, cpuid);
755 }
756 
757 void apic_error_intr_handler(void)
758 {
759 	static unsigned x;
760 
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);
765 }
766 
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}
835 };
836 
837 static struct gate_table_s gate_table_common[] = {
838 	{ ipc_entry_softint_orig, IPC_VECTOR_ORIG, USER_PRIVILEGE },
839 	{ kernel_call_entry_orig, KERN_CALL_VECTOR_ORIG, USER_PRIVILEGE },
840 	{ ipc_entry_softint_um, IPC_VECTOR_UM, USER_PRIVILEGE },
841 	{ kernel_call_entry_um, KERN_CALL_VECTOR_UM, USER_PRIVILEGE },
842 	{ NULL, 0, 0}
843 };
844 
845 #ifdef CONFIG_SMP
846 static struct gate_table_s gate_table_smp[] = {
847 	{ apic_ipi_sched_intr, APIC_SMP_SCHED_PROC_VECTOR, INTR_PRIVILEGE },
848 	{ apic_ipi_halt_intr,  APIC_SMP_CPU_HALT_VECTOR, INTR_PRIVILEGE },
849 	{ NULL, 0, 0}
850 };
851 #endif
852 
853 #ifdef APIC_DEBUG
854 static void lapic_set_dummy_handlers(void)
855 {
856 	char * handler;
857 	int vect = 32; /* skip the reserved vectors */
858 
859 	handler = &lapic_intr_dummy_handles_start;
860 	handler += vect * LAPIC_INTR_DUMMY_HANDLER_SIZE;
861 	for(; handler < &lapic_intr_dummy_handles_end;
862 			handler += LAPIC_INTR_DUMMY_HANDLER_SIZE) {
863 		int_gate_idt(vect++, (vir_bytes) handler,
864 				PRESENT | INT_GATE_TYPE |
865 				(INTR_PRIVILEGE << DPL_SHIFT));
866 	}
867 }
868 #endif
869 
870 /* Build descriptors for interrupt gates in IDT. */
871 void apic_idt_init(const int reset)
872 {
873 	u32_t val;
874 
875 	/* Set up idt tables for smp mode.
876 	 */
877 	int is_bsp;
878 
879 	if (reset) {
880 		idt_copy_vectors_pic();
881 		idt_copy_vectors(gate_table_common);
882 		return;
883 	}
884 
885 	is_bsp = is_boot_apic(apicid());
886 
887 #ifdef APIC_DEBUG
888 	if (is_bsp)
889 		printf("APIC debugging is enabled\n");
890 	lapic_set_dummy_handlers();
891 #endif
892 
893 	/* Build descriptors for interrupt gates in IDT. */
894 	if (ioapic_enabled)
895 		idt_copy_vectors(gate_table_ioapic);
896 	else
897 		idt_copy_vectors_pic();
898 
899 	idt_copy_vectors(gate_table_common);
900 
901 #ifdef CONFIG_SMP
902 	idt_copy_vectors(gate_table_smp);
903 #endif
904 
905 	/* Setup error interrupt vector */
906 	val = lapic_read(LAPIC_LVTER);
907 	val |= APIC_ERROR_INT_VECTOR;
908 	val &= ~ APIC_ICR_INT_MASK;
909 	lapic_write(LAPIC_LVTER, val);
910 	(void) lapic_read(LAPIC_LVTER);
911 
912 	/* configure the timer interupt handler */
913 	if (is_bsp) {
914 		BOOT_VERBOSE(printf("Initiating APIC timer handler\n"));
915 		/* register the timer interrupt handler for this CPU */
916 		int_gate_idt(APIC_TIMER_INT_VECTOR, (vir_bytes) lapic_timer_int_handler,
917 				PRESENT | INT_GATE_TYPE | (INTR_PRIVILEGE << DPL_SHIFT));
918 	}
919 
920 }
921 
922 static int acpi_get_ioapics(struct io_apic * ioa, unsigned * nioa, unsigned max)
923 {
924 	unsigned n = 0;
925 	struct acpi_madt_ioapic * acpi_ioa;
926 
927 	while (n < max) {
928 		acpi_ioa = acpi_get_ioapic_next();
929 		if (acpi_ioa == NULL)
930 			break;
931 
932 		assert(acpi_ioa->address);
933 
934 		ioa[n].id = acpi_ioa->id;
935 		ioa[n].addr = acpi_ioa->address;
936 		ioa[n].paddr = (phys_bytes) acpi_ioa->address;
937 		ioa[n].gsi_base = acpi_ioa->global_int_base;
938 		ioa[n].pins = ((ioapic_read(ioa[n].addr,
939 				IOAPIC_VERSION) & 0xff0000) >> 16)+1;
940 		printf("IO APIC idx %d id %d addr 0x%lx paddr 0x%lx pins %d\n",
941 				n, acpi_ioa->id, ioa[n].addr, ioa[n].paddr,
942 				ioa[n].pins);
943 		n++;
944 	}
945 
946 	*nioa = n;
947 	return n;
948 }
949 
950 int detect_ioapics(void)
951 {
952 	int status;
953 
954 	if (machine.acpi_rsdp) {
955 		status = acpi_get_ioapics(io_apic, &nioapics, MAX_NR_IOAPICS);
956 	} else {
957 		status = 0;
958 	}
959 	if (!status) {
960 		/* try something different like MPS */
961 	}
962 
963 	return status;
964 }
965 
966 #ifdef CONFIG_SMP
967 
968 void apic_send_ipi(unsigned vector, unsigned cpu, int type)
969 {
970 	u32_t icr1, icr2;
971 
972 	if (ncpus == 1)
973 		/* no need of sending an IPI */
974 		return;
975 
976 	while (lapic_read_icr1() & APIC_ICR_DELIVERY_PENDING)
977 		arch_pause();
978 
979 	icr1 = lapic_read_icr1() & 0xFFF0F800;
980 	icr2 = lapic_read_icr2() & 0xFFFFFF;
981 
982 	switch (type) {
983 		case APIC_IPI_DEST:
984 			if (!cpu_is_ready(cpu))
985 				return;
986 			lapic_write_icr2(icr2 |	(cpuid2apicid[cpu] << 24));
987 			lapic_write_icr1(icr1 |	APIC_ICR_DEST_FIELD | vector);
988 			break;
989 		case APIC_IPI_SELF:
990 			lapic_write_icr2(icr2);
991 			lapic_write_icr1(icr1 |	APIC_ICR_DEST_SELF | vector);
992 			break;
993 		case APIC_IPI_TO_ALL_BUT_SELF:
994 			lapic_write_icr2(icr2);
995 			lapic_write_icr1(icr1 |	APIC_ICR_DEST_ALL_BUT_SELF | vector);
996 			break;
997 		case APIC_IPI_TO_ALL:
998 			lapic_write_icr2(icr2);
999 			lapic_write_icr1(icr1 |	APIC_ICR_DEST_ALL | vector);
1000 			break;
1001 		default:
1002 			printf("WARNING : unknown send ipi type request\n");
1003 	}
1004 
1005 }
1006 
1007 int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline)
1008 {
1009 	int timeout;
1010 	u32_t errstatus = 0;
1011 	int i;
1012 
1013 	/* INIT-SIPI-SIPI sequence */
1014 
1015 	for (i = 0; i < 2; i++) {
1016 		u32_t val;
1017 
1018 		/* clear err status */
1019 		lapic_errstatus();
1020 
1021 		/* set target pe */
1022 		val = lapic_read(LAPIC_ICR2) & 0xFFFFFF;
1023 		val |= cpuid2apicid[cpu] << 24;
1024 		lapic_write(LAPIC_ICR2, val);
1025 
1026 		/* send SIPI */
1027 		val = lapic_read(LAPIC_ICR1) & 0xFFF32000;
1028 		val |= APIC_ICR_LEVEL_ASSERT |APIC_ICR_DM_STARTUP;
1029 		val |= (((u32_t)trampoline >> 12)&0xff);
1030 		lapic_write(LAPIC_ICR1, val);
1031 
1032 		timeout = 1000;
1033 
1034 		/* wait for 200 micro-seconds*/
1035 		lapic_microsec_sleep (200);
1036 		errstatus = 0;
1037 
1038 		while ((lapic_read(LAPIC_ICR1) & APIC_ICR_DELIVERY_PENDING) &&
1039 				!errstatus) {
1040 			errstatus = lapic_errstatus();
1041 			timeout--;
1042 			if (!timeout) break;
1043 		}
1044 
1045 		/* skip this one and continue with another cpu */
1046 		if (errstatus)
1047 			return -1;
1048 	}
1049 
1050 	return 0;
1051 }
1052 
1053 int apic_send_init_ipi(unsigned cpu, phys_bytes trampoline)
1054 {
1055 	u32_t ptr, errstatus = 0;
1056 	int timeout;
1057 
1058 	/* set the warm reset vector */
1059 	ptr = (u32_t)(trampoline & 0xF);
1060 	phys_copy(0x467, vir2phys(&ptr), sizeof(u16_t ));
1061 	ptr = (u32_t)(trampoline >> 4);
1062 	phys_copy(0x469, vir2phys(&ptr), sizeof(u16_t ));
1063 
1064 	/* set shutdown code */
1065 	outb (RTC_INDEX, 0xF);
1066 	outb (RTC_IO, 0xA);
1067 
1068 	/* clear error state register. */
1069 	(void) lapic_errstatus();
1070 
1071 	/* assert INIT IPI , No Shorthand, destination mode : physical */
1072 	lapic_write(LAPIC_ICR2, (lapic_read (LAPIC_ICR2) & 0xFFFFFF) |
1073 					(cpuid2apicid[cpu] << 24));
1074 	lapic_write(LAPIC_ICR1, (lapic_read (LAPIC_ICR1) & 0xFFF32000) |
1075 		APIC_ICR_DM_INIT | APIC_ICR_TM_LEVEL | APIC_ICR_LEVEL_ASSERT);
1076 
1077 	timeout = 1000;
1078 
1079 	/* sleep for 200 micro-seconds */
1080 	lapic_microsec_sleep(200);
1081 
1082 	errstatus = 0;
1083 
1084 	while ((lapic_read(LAPIC_ICR1) & APIC_ICR_DELIVERY_PENDING) && !errstatus) {
1085 		errstatus = lapic_errstatus();
1086 		timeout--;
1087 		if (!timeout) break;
1088 	}
1089 
1090 	if (errstatus)
1091 		return -1; /* to continue with a new processor */
1092 
1093 	/* clear error state register. */
1094 	lapic_errstatus();
1095 
1096 	/* deassert INIT IPI , No Shorthand, destination mode : physical */
1097 	lapic_write(LAPIC_ICR2, (lapic_read (LAPIC_ICR2) & 0xFFFFFF) |
1098 					(cpuid2apicid[cpu] << 24));
1099 	lapic_write(LAPIC_ICR1, (lapic_read (LAPIC_ICR1) & 0xFFF32000) |
1100 		APIC_ICR_DEST_ALL | APIC_ICR_TM_LEVEL);
1101 
1102 	timeout = 1000;
1103 	errstatus = 0;
1104 
1105 	/* sleep for 200 micro-seconds */
1106 	lapic_microsec_sleep(200);
1107 
1108 	while ((lapic_read(LAPIC_ICR1)&APIC_ICR_DELIVERY_PENDING) && !errstatus) {
1109 		errstatus = lapic_errstatus();
1110 		timeout--;
1111 		if(!timeout) break;
1112 	}
1113 
1114 	if (errstatus)
1115 		return -1; /* with the new processor */
1116 
1117 	/* clear error state register.  */
1118 	(void) lapic_errstatus();
1119 
1120 	/* wait 10ms */
1121 	lapic_microsec_sleep (10000);
1122 
1123 	return 0;
1124 }
1125 #endif
1126 
1127 #ifndef CONFIG_SMP
1128 int apic_single_cpu_init(void)
1129 {
1130 	if (!cpu_feature_apic_on_chip())
1131 		return 0;
1132 
1133 	lapic_addr = LOCAL_APIC_DEF_ADDR;
1134 	ioapic_enabled = 0;
1135 
1136 	if (!lapic_enable(0)) {
1137 		lapic_addr = 0x0;
1138 		return 0;
1139 	}
1140 
1141 	bsp_lapic_id = apicid();
1142 	printf("Boot cpu apic id %d\n", bsp_lapic_id);
1143 
1144 	acpi_init();
1145 
1146 	if (!detect_ioapics()) {
1147 		lapic_disable();
1148 		lapic_addr = 0x0;
1149 		return 0;
1150 	}
1151 
1152 	ioapic_enable_all();
1153 
1154 	if (ioapic_enabled)
1155 		machine.apic_enabled = 1;
1156 
1157 	apic_idt_init(0); /* Not a reset ! */
1158 	idt_reload();
1159 	return 1;
1160 }
1161 #endif
1162 
1163 static eoi_method_t set_eoi_method(unsigned irq)
1164 {
1165 	/*
1166 	 * in APIC mode the lowest 16 IRQs are reserved for legacy (E)ISA edge
1167 	 * triggered interrupts. All the rest is for PCI level triggered
1168 	 * interrupts
1169 	 */
1170 	if (irq < 16)
1171 		return ioapic_eoi_edge;
1172 	else
1173 		return ioapic_eoi_level;
1174 }
1175 
1176 void set_irq_redir_low(unsigned irq, u32_t * low)
1177 {
1178 	u32_t val = 0;
1179 
1180 	/* clear the polarity, trigger, mask and vector fields */
1181 	val &= ~(APIC_ICR_VECTOR | APIC_ICR_INT_MASK |
1182 			APIC_ICR_TRIGGER | APIC_ICR_INT_POLARITY);
1183 
1184 	if (irq < 16) {
1185 		/* ISA active-high */
1186 		val &= ~APIC_ICR_INT_POLARITY;
1187 		/* ISA edge triggered */
1188 		val &= ~APIC_ICR_TRIGGER;
1189 	}
1190 	else {
1191 		/* PCI active-low */
1192 		val |= APIC_ICR_INT_POLARITY;
1193 		/* PCI level triggered */
1194 		val |= APIC_ICR_TRIGGER;
1195 	}
1196 
1197 	val |= io_apic_irq[irq].vector;
1198 
1199 	*low = val;
1200 }
1201 
1202 void ioapic_set_irq(unsigned irq)
1203 {
1204 	unsigned ioa;
1205 
1206 	assert(irq < NR_IRQ_VECTORS);
1207 
1208 	/* shared irq, already set */
1209 	if (io_apic_irq[irq].ioa && io_apic_irq[irq].eoi)
1210 		return;
1211 
1212 	assert(!io_apic_irq[irq].ioa || !io_apic_irq[irq].eoi);
1213 
1214 	for (ioa = 0; ioa < nioapics; ioa++) {
1215 		if (io_apic[ioa].gsi_base <= irq &&
1216 				io_apic[ioa].gsi_base +
1217 				io_apic[ioa].pins > irq) {
1218 			u32_t hi_32, low_32;
1219 
1220 			io_apic_irq[irq].ioa = &io_apic[ioa];
1221 			io_apic_irq[irq].pin = irq - io_apic[ioa].gsi_base;
1222 			io_apic_irq[irq].eoi = set_eoi_method(irq);
1223 			io_apic_irq[irq].vector = LAPIC_VECTOR(irq);
1224 
1225 			set_irq_redir_low(irq, &low_32);
1226 			/*
1227 			 * route the interrupts to the bsp by default
1228 			 */
1229 			hi_32 = bsp_lapic_id << 24;
1230 			ioapic_redirt_entry_write((void *) io_apic[ioa].addr,
1231 					io_apic_irq[irq].pin, hi_32, low_32);
1232 		}
1233 	}
1234 }
1235 
1236 void ioapic_unset_irq(unsigned irq)
1237 {
1238 	assert(irq < NR_IRQ_VECTORS);
1239 
1240 	ioapic_disable_irq(irq);
1241 	io_apic_irq[irq].ioa = NULL;
1242 	io_apic_irq[irq].eoi = NULL;
1243 }
1244 
1245 void ioapic_reset_pic(void)
1246 {
1247 	apic_idt_init(TRUE); /* reset */
1248 	idt_reload();
1249 
1250 	/* Enable 8259 - write 0x00 in OCW1
1251 	 * master and slave.  */
1252 		outb(0x22, 0x70);
1253 		outb(0x23, 0x00);
1254 }
1255 
1256 static void irq_lapic_status(int irq)
1257 {
1258 	u32_t lo;
1259 	reg_t tmr, irr, isr;
1260 	int vector;
1261 	struct irq * intr;
1262 
1263 	intr = &io_apic_irq[irq];
1264 
1265 	if (!intr->ioa)
1266 		return;
1267 
1268 	vector = LAPIC_VECTOR(irq);
1269 	tmr =  apic_read_tmr_vector(vector);
1270 	irr =  apic_read_irr_vector(vector);
1271 	isr =  apic_read_isr_vector(vector);
1272 
1273 
1274 	if (lapic_test_delivery_val(isr, vector)) {
1275 		printf("IRQ %d vec %d trigger %s irr %d isr %d\n",
1276 				irq, vector,
1277 				lapic_test_delivery_val(tmr, vector) ?
1278 				"level" : "edge",
1279 				lapic_test_delivery_val(irr, vector) ? 1 : 0,
1280 				lapic_test_delivery_val(isr, vector) ? 1 : 0);
1281 	} else {
1282 		printf("IRQ %d vec %d irr %d\n",
1283 				irq, vector,
1284 				lapic_test_delivery_val(irr, vector) ? 1 : 0);
1285 	}
1286 
1287 	lo = ioapic_read(intr->ioa->addr,
1288 			IOAPIC_REDIR_TABLE + intr->pin * 2);
1289 	printf("\tpin %2d vec 0x%02x ioa %d redir_lo 0x%08x %s\n",
1290 			intr->pin,
1291 			intr->vector,
1292 			intr->ioa->id,
1293 			lo,
1294 			intr->state & IOAPIC_IRQ_STATE_MASKED ?
1295 			"masked" : "unmasked");
1296 }
1297 
1298 void dump_apic_irq_state(void)
1299 {
1300 	int irq;
1301 
1302 	printf("--- IRQs state dump ---\n");
1303 	for (irq = 0; irq < NR_IRQ_VECTORS; irq++) {
1304 		irq_lapic_status(irq);
1305 	}
1306 	printf("--- all ---\n");
1307 }
1308