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