xref: /titanic_44/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c (revision 6eedf6a58bb97d935b764a55719f82a486168fbb)
1b6917abeSmishra /*
2b6917abeSmishra  * CDDL HEADER START
3b6917abeSmishra  *
4b6917abeSmishra  * The contents of this file are subject to the terms of the
5b6917abeSmishra  * Common Development and Distribution License (the "License").
6b6917abeSmishra  * You may not use this file except in compliance with the License.
7b6917abeSmishra  *
8b6917abeSmishra  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9b6917abeSmishra  * or http://www.opensolaris.org/os/licensing.
10b6917abeSmishra  * See the License for the specific language governing permissions
11b6917abeSmishra  * and limitations under the License.
12b6917abeSmishra  *
13b6917abeSmishra  * When distributing Covered Code, include this CDDL HEADER in each
14b6917abeSmishra  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15b6917abeSmishra  * If applicable, add the following below this CDDL HEADER, with the
16b6917abeSmishra  * fields enclosed by brackets "[]" replaced with your own identifying
17b6917abeSmishra  * information: Portions Copyright [yyyy] [name of copyright owner]
18b6917abeSmishra  *
19b6917abeSmishra  * CDDL HEADER END
20b6917abeSmishra  */
21b6917abeSmishra /*
22d23e508cSEdward Gillett  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23b6917abeSmishra  * Use is subject to license terms.
24b6917abeSmishra  */
25*6eedf6a5SJosef 'Jeff' Sipek /*
26*6eedf6a5SJosef 'Jeff' Sipek  * Copyright 2014 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
27*6eedf6a5SJosef 'Jeff' Sipek  */
28b6917abeSmishra 
29b6917abeSmishra #include <sys/cpuvar.h>
30b6917abeSmishra #include <sys/psm.h>
31b6917abeSmishra #include <sys/archsystm.h>
32b6917abeSmishra #include <sys/apic.h>
33b6917abeSmishra #include <sys/sunddi.h>
34b6917abeSmishra #include <sys/ddi_impldefs.h>
35b6917abeSmishra #include <sys/mach_intr.h>
36b6917abeSmishra #include <sys/sysmacros.h>
37b6917abeSmishra #include <sys/trap.h>
38b6917abeSmishra #include <sys/x86_archext.h>
39b6917abeSmishra #include <sys/privregs.h>
40b6917abeSmishra #include <sys/psm_common.h>
41b6917abeSmishra 
42325e77f4SSaurabh Misra /* Function prototypes of local apic and X2APIC */
43b6917abeSmishra static uint64_t local_apic_read(uint32_t reg);
44b6917abeSmishra static void local_apic_write(uint32_t reg, uint64_t value);
45b6917abeSmishra static int get_local_apic_pri(void);
46b6917abeSmishra static void local_apic_write_task_reg(uint64_t value);
47b6917abeSmishra static void local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
48b6917abeSmishra static uint64_t local_x2apic_read(uint32_t msr);
49b6917abeSmishra static void local_x2apic_write(uint32_t msr, uint64_t value);
50b6917abeSmishra static int get_local_x2apic_pri(void);
51b6917abeSmishra static void local_x2apic_write_task_reg(uint64_t value);
52b6917abeSmishra static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
53b6917abeSmishra 
54b6917abeSmishra /*
55325e77f4SSaurabh Misra  * According to the X2APIC specification:
56b6917abeSmishra  *
57325e77f4SSaurabh Misra  *   xAPIC global enable    X2APIC enable         Description
58b6917abeSmishra  *   (IA32_APIC_BASE[11])   (IA32_APIC_BASE[10])
59b6917abeSmishra  * -----------------------------------------------------------
60b6917abeSmishra  *      0 			0 	APIC is disabled
61b6917abeSmishra  * 	0			1	Invalid
62b6917abeSmishra  *	1			0	APIC is enabled in xAPIC mode
63325e77f4SSaurabh Misra  *	1			1	APIC is enabled in X2APIC mode
64b6917abeSmishra  * -----------------------------------------------------------
65b6917abeSmishra  */
66b6917abeSmishra int	x2apic_enable = 1;
679b1d70f8SJosef 'Jeff' Sipek apic_mode_t apic_mode = LOCAL_APIC;	/* Default mode is Local APIC */
68b6917abeSmishra 
69b6917abeSmishra /* Uses MMIO (Memory Mapped IO) */
70b6917abeSmishra static apic_reg_ops_t local_apic_regs_ops = {
71b6917abeSmishra 	local_apic_read,
72b6917abeSmishra 	local_apic_write,
73b6917abeSmishra 	get_local_apic_pri,
74b6917abeSmishra 	local_apic_write_task_reg,
75b6917abeSmishra 	local_apic_write_int_cmd,
76b6917abeSmishra 	apic_send_EOI,
77b6917abeSmishra };
78b6917abeSmishra 
79325e77f4SSaurabh Misra /* X2APIC : Uses RDMSR/WRMSR instructions to access APIC registers */
80b6917abeSmishra static apic_reg_ops_t x2apic_regs_ops = {
81b6917abeSmishra 	local_x2apic_read,
82b6917abeSmishra 	local_x2apic_write,
83b6917abeSmishra 	get_local_x2apic_pri,
84b6917abeSmishra 	local_x2apic_write_task_reg,
85b6917abeSmishra 	local_x2apic_write_int_cmd,
86b6917abeSmishra 	apic_send_EOI,
87b6917abeSmishra };
88b6917abeSmishra 
894c1c9391SJoe Bonasera int apic_have_32bit_cr8 = 0;
90b6917abeSmishra 
91b6917abeSmishra /* The default ops is local APIC (Memory Mapped IO) */
92b6917abeSmishra apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops;
93b6917abeSmishra 
94b6917abeSmishra /*
95b6917abeSmishra  * APIC register ops related data sturctures and functions.
96b6917abeSmishra  */
97b6917abeSmishra void apic_send_EOI();
98b6917abeSmishra void apic_send_directed_EOI(uint32_t irq);
99b6917abeSmishra 
100b6917abeSmishra #define	X2APIC_ENABLE_BIT	10
101b6917abeSmishra 
102b6917abeSmishra /*
103b6917abeSmishra  * Local APIC Implementation
104b6917abeSmishra  */
105b6917abeSmishra static uint64_t
local_apic_read(uint32_t reg)106b6917abeSmishra local_apic_read(uint32_t reg)
107b6917abeSmishra {
108b6917abeSmishra 	return ((uint32_t)apicadr[reg]);
109b6917abeSmishra }
110b6917abeSmishra 
111b6917abeSmishra static void
local_apic_write(uint32_t reg,uint64_t value)112b6917abeSmishra local_apic_write(uint32_t reg, uint64_t value)
113b6917abeSmishra {
114b6917abeSmishra 	apicadr[reg] = (uint32_t)value;
115b6917abeSmishra }
116b6917abeSmishra 
117b6917abeSmishra static int
get_local_apic_pri(void)118b6917abeSmishra get_local_apic_pri(void)
119b6917abeSmishra {
120b6917abeSmishra #if defined(__amd64)
121b6917abeSmishra 	return ((int)getcr8());
122b6917abeSmishra #else
1232ef50f01SJoe Bonasera 	if (apic_have_32bit_cr8)
1242ef50f01SJoe Bonasera 		return ((int)getcr8());
125b6917abeSmishra 	return (apicadr[APIC_TASK_REG]);
126b6917abeSmishra #endif
127b6917abeSmishra }
128b6917abeSmishra 
129b6917abeSmishra static void
local_apic_write_task_reg(uint64_t value)130b6917abeSmishra local_apic_write_task_reg(uint64_t value)
131b6917abeSmishra {
132b6917abeSmishra #if defined(__amd64)
133b6917abeSmishra 	setcr8((ulong_t)(value >> APIC_IPL_SHIFT));
134b6917abeSmishra #else
1352ef50f01SJoe Bonasera 	if (apic_have_32bit_cr8)
1362ef50f01SJoe Bonasera 		setcr8((ulong_t)(value >> APIC_IPL_SHIFT));
1372ef50f01SJoe Bonasera 	else
138b6917abeSmishra 		apicadr[APIC_TASK_REG] = (uint32_t)value;
139b6917abeSmishra #endif
140b6917abeSmishra }
141b6917abeSmishra 
142b6917abeSmishra static void
local_apic_write_int_cmd(uint32_t cpu_id,uint32_t cmd1)143b6917abeSmishra local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
144b6917abeSmishra {
145b6917abeSmishra 	apicadr[APIC_INT_CMD2] = cpu_id << APIC_ICR_ID_BIT_OFFSET;
146b6917abeSmishra 	apicadr[APIC_INT_CMD1] = cmd1;
147b6917abeSmishra }
148b6917abeSmishra 
149b6917abeSmishra /*
150325e77f4SSaurabh Misra  * X2APIC Implementation.
151b6917abeSmishra  */
152b6917abeSmishra static uint64_t
local_x2apic_read(uint32_t msr)153b6917abeSmishra local_x2apic_read(uint32_t msr)
154b6917abeSmishra {
155b6917abeSmishra 	uint64_t i;
156b6917abeSmishra 
157b6917abeSmishra 	i = (uint64_t)(rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2)) & 0xffffffff);
158b6917abeSmishra 	return (i);
159b6917abeSmishra }
160b6917abeSmishra 
161b6917abeSmishra static void
local_x2apic_write(uint32_t msr,uint64_t value)162b6917abeSmishra local_x2apic_write(uint32_t msr, uint64_t value)
163b6917abeSmishra {
164b6917abeSmishra 	uint64_t tmp;
165b6917abeSmishra 
166b6917abeSmishra 	if (msr != APIC_EOI_REG) {
167b6917abeSmishra 		tmp = rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2));
168b6917abeSmishra 		tmp = (tmp & 0xffffffff00000000) | value;
169f9c480cdSSaurabh Misra 	} else {
170f9c480cdSSaurabh Misra 		tmp = 0;
171b6917abeSmishra 	}
172b6917abeSmishra 
173b6917abeSmishra 	wrmsr((REG_X2APIC_BASE_MSR + (msr >> 2)), tmp);
174b6917abeSmishra }
175b6917abeSmishra 
176b6917abeSmishra static int
get_local_x2apic_pri(void)177b6917abeSmishra get_local_x2apic_pri(void)
178b6917abeSmishra {
1795d8efbbcSSaurabh Misra 	return (rdmsr(REG_X2APIC_BASE_MSR + (APIC_TASK_REG >> 2)));
180b6917abeSmishra }
181b6917abeSmishra 
182b6917abeSmishra static void
local_x2apic_write_task_reg(uint64_t value)183b6917abeSmishra local_x2apic_write_task_reg(uint64_t value)
184b6917abeSmishra {
185b6917abeSmishra 	X2APIC_WRITE(APIC_TASK_REG, value);
186b6917abeSmishra }
187b6917abeSmishra 
188b6917abeSmishra static void
local_x2apic_write_int_cmd(uint32_t cpu_id,uint32_t cmd1)189b6917abeSmishra local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
190b6917abeSmishra {
191b6917abeSmishra 	wrmsr((REG_X2APIC_BASE_MSR + (APIC_INT_CMD1 >> 2)),
192b6917abeSmishra 	    (((uint64_t)cpu_id << 32) | cmd1));
193b6917abeSmishra }
194b6917abeSmishra 
195b6917abeSmishra /*ARGSUSED*/
196b6917abeSmishra void
apic_send_EOI(uint32_t irq)197b6917abeSmishra apic_send_EOI(uint32_t irq)
198b6917abeSmishra {
199b6917abeSmishra 	apic_reg_ops->apic_write(APIC_EOI_REG, 0);
200b6917abeSmishra }
201b6917abeSmishra 
202d23e508cSEdward Gillett /*
203d23e508cSEdward Gillett  * Support for Directed EOI capability is available in both the xAPIC
204d23e508cSEdward Gillett  * and x2APIC mode.
205d23e508cSEdward Gillett  */
206b6917abeSmishra void
apic_send_directed_EOI(uint32_t irq)207b6917abeSmishra apic_send_directed_EOI(uint32_t irq)
208b6917abeSmishra {
209b6917abeSmishra 	uchar_t ioapicindex;
210b6917abeSmishra 	uchar_t vector;
211b6917abeSmishra 	apic_irq_t *apic_irq;
212b6917abeSmishra 	short intr_index;
213b6917abeSmishra 
214d23e508cSEdward Gillett 	/*
215d23e508cSEdward Gillett 	 * Following the EOI to the local APIC unit, perform a directed
216d23e508cSEdward Gillett 	 * EOI to the IOxAPIC generating the interrupt by writing to its
217d23e508cSEdward Gillett 	 * EOI register.
218d23e508cSEdward Gillett 	 *
219d23e508cSEdward Gillett 	 * A broadcast EOI is not generated.
220d23e508cSEdward Gillett 	 */
221d23e508cSEdward Gillett 	apic_reg_ops->apic_write(APIC_EOI_REG, 0);
222b6917abeSmishra 
223b6917abeSmishra 	apic_irq = apic_irq_table[irq];
224b6917abeSmishra 	while (apic_irq) {
225b6917abeSmishra 		intr_index = apic_irq->airq_mps_intr_index;
226b6917abeSmishra 		if (intr_index == ACPI_INDEX || intr_index >= 0) {
227b6917abeSmishra 			ioapicindex = apic_irq->airq_ioapicindex;
228b6917abeSmishra 			vector = apic_irq->airq_vector;
229b6917abeSmishra 			ioapic_write_eoi(ioapicindex, vector);
230b6917abeSmishra 		}
231b6917abeSmishra 		apic_irq = apic_irq->airq_next;
232b6917abeSmishra 	}
233b6917abeSmishra }
234b6917abeSmishra 
235b6917abeSmishra int
apic_detect_x2apic(void)236b6917abeSmishra apic_detect_x2apic(void)
237b6917abeSmishra {
238b6917abeSmishra 	if (x2apic_enable == 0)
239b6917abeSmishra 		return (0);
240b6917abeSmishra 
241*6eedf6a5SJosef 'Jeff' Sipek 	return (is_x86_feature(x86_featureset, X86FSET_X2APIC));
242b6917abeSmishra }
243b6917abeSmishra 
244b6917abeSmishra void
apic_enable_x2apic(void)245b6917abeSmishra apic_enable_x2apic(void)
246b6917abeSmishra {
247b6917abeSmishra 	uint64_t apic_base_msr;
248b6917abeSmishra 
249325e77f4SSaurabh Misra 	if (apic_local_mode() == LOCAL_X2APIC) {
250325e77f4SSaurabh Misra 		/* BIOS apparently has enabled X2APIC */
251325e77f4SSaurabh Misra 		if (apic_mode != LOCAL_X2APIC)
252b6917abeSmishra 			x2apic_update_psm();
253325e77f4SSaurabh Misra 		return;
254b6917abeSmishra 	}
255b6917abeSmishra 
256b6917abeSmishra 	/*
257325e77f4SSaurabh Misra 	 * This is the first time we are enabling X2APIC on this CPU
258325e77f4SSaurabh Misra 	 */
259325e77f4SSaurabh Misra 	apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
260325e77f4SSaurabh Misra 	apic_base_msr = apic_base_msr | (0x1 << X2APIC_ENABLE_BIT);
261325e77f4SSaurabh Misra 	wrmsr(REG_APIC_BASE_MSR, apic_base_msr);
262325e77f4SSaurabh Misra 
263325e77f4SSaurabh Misra 	if (apic_mode != LOCAL_X2APIC)
264325e77f4SSaurabh Misra 		x2apic_update_psm();
265325e77f4SSaurabh Misra }
266325e77f4SSaurabh Misra 
267325e77f4SSaurabh Misra /*
268325e77f4SSaurabh Misra  * Determine which mode the current CPU is in. See the table above.
269325e77f4SSaurabh Misra  * (IA32_APIC_BASE[11])   (IA32_APIC_BASE[10])
270325e77f4SSaurabh Misra  */
271325e77f4SSaurabh Misra int
apic_local_mode(void)272325e77f4SSaurabh Misra apic_local_mode(void)
273325e77f4SSaurabh Misra {
274325e77f4SSaurabh Misra 	uint64_t apic_base_msr;
275325e77f4SSaurabh Misra 	int bit = ((0x1 << (X2APIC_ENABLE_BIT + 1)) |
276325e77f4SSaurabh Misra 	    (0x1 << X2APIC_ENABLE_BIT));
277325e77f4SSaurabh Misra 
278325e77f4SSaurabh Misra 	apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
279325e77f4SSaurabh Misra 
280325e77f4SSaurabh Misra 	if ((apic_base_msr & bit) == bit)
281325e77f4SSaurabh Misra 		return (LOCAL_X2APIC);
282325e77f4SSaurabh Misra 	else
283325e77f4SSaurabh Misra 		return (LOCAL_APIC);
284325e77f4SSaurabh Misra }
285325e77f4SSaurabh Misra 
286325e77f4SSaurabh Misra void
apic_set_directed_EOI_handler()287e511d54dSSaurabh Misra apic_set_directed_EOI_handler()
288325e77f4SSaurabh Misra {
289325e77f4SSaurabh Misra 	apic_reg_ops->apic_send_eoi = apic_send_directed_EOI;
290325e77f4SSaurabh Misra }
291325e77f4SSaurabh Misra 
292e511d54dSSaurabh Misra int
apic_directed_EOI_supported()293e511d54dSSaurabh Misra apic_directed_EOI_supported()
294e511d54dSSaurabh Misra {
295e511d54dSSaurabh Misra 	uint32_t ver;
296e511d54dSSaurabh Misra 
297e511d54dSSaurabh Misra 	ver = apic_reg_ops->apic_read(APIC_VERS_REG);
298e511d54dSSaurabh Misra 	if (ver & APIC_DIRECTED_EOI_BIT)
299e511d54dSSaurabh Misra 		return (1);
300e511d54dSSaurabh Misra 
301e511d54dSSaurabh Misra 	return (0);
302e511d54dSSaurabh Misra }
303e511d54dSSaurabh Misra 
304325e77f4SSaurabh Misra /*
305325e77f4SSaurabh Misra  * Change apic_reg_ops depending upon the apic_mode.
306325e77f4SSaurabh Misra  */
307325e77f4SSaurabh Misra void
apic_change_ops()308325e77f4SSaurabh Misra apic_change_ops()
309325e77f4SSaurabh Misra {
310325e77f4SSaurabh Misra 	if (apic_mode == LOCAL_APIC)
311325e77f4SSaurabh Misra 		apic_reg_ops = &local_apic_regs_ops;
312325e77f4SSaurabh Misra 	else if (apic_mode == LOCAL_X2APIC)
313325e77f4SSaurabh Misra 		apic_reg_ops = &x2apic_regs_ops;
314325e77f4SSaurabh Misra }
315325e77f4SSaurabh Misra 
316325e77f4SSaurabh Misra /*
317325e77f4SSaurabh Misra  * Generates an interprocessor interrupt to another CPU when X2APIC mode is
318b6917abeSmishra  * enabled.
319b6917abeSmishra  */
320b6917abeSmishra void
x2apic_send_ipi(int cpun,int ipl)321b6917abeSmishra x2apic_send_ipi(int cpun, int ipl)
322b6917abeSmishra {
323b6917abeSmishra 	int vector;
324b6917abeSmishra 	ulong_t flag;
3255d8efbbcSSaurabh Misra 
32687cc6269SSaurabh Misra 	ASSERT(apic_mode == LOCAL_X2APIC);
32787cc6269SSaurabh Misra 
3285d8efbbcSSaurabh Misra 	/*
3295d8efbbcSSaurabh Misra 	 * With X2APIC, Intel relaxed the semantics of the
3305d8efbbcSSaurabh Misra 	 * WRMSR instruction such that references to the X2APIC
3315d8efbbcSSaurabh Misra 	 * MSR registers are no longer serializing instructions.
3325d8efbbcSSaurabh Misra 	 * The code that initiates IPIs assumes that some sort
3335d8efbbcSSaurabh Misra 	 * of memory serialization occurs. The old APIC code
3345d8efbbcSSaurabh Misra 	 * did a write to uncachable memory mapped registers.
3355d8efbbcSSaurabh Misra 	 * Any reference to uncached memory is a serializing
3365d8efbbcSSaurabh Misra 	 * operation. To mimic those semantics here, we do an
3375d8efbbcSSaurabh Misra 	 * atomic operation, which translates to a LOCK OR instruction,
3385d8efbbcSSaurabh Misra 	 * which is serializing.
3395d8efbbcSSaurabh Misra 	 */
3405d8efbbcSSaurabh Misra 	atomic_or_ulong(&flag, 1);
3415d8efbbcSSaurabh Misra 
342b6917abeSmishra 	vector = apic_resv_vector[ipl];
343b6917abeSmishra 
344b6917abeSmishra 	flag = intr_clear();
345b6917abeSmishra 
3465d8efbbcSSaurabh Misra 	/*
347325e77f4SSaurabh Misra 	 * According to X2APIC specification in section '2.3.5.1' of
3485d8efbbcSSaurabh Misra 	 * Interrupt Command Register Semantics, the semantics of
3495d8efbbcSSaurabh Misra 	 * programming Interrupt Command Register to dispatch an interrupt
3505d8efbbcSSaurabh Misra 	 * is simplified. A single MSR write to the 64-bit ICR is required
3515d8efbbcSSaurabh Misra 	 * for dispatching an interrupt. Specifically with the 64-bit MSR
3525d8efbbcSSaurabh Misra 	 * interface to ICR, system software is not required to check the
3535d8efbbcSSaurabh Misra 	 * status of the delivery status bit prior to writing to the ICR
3545d8efbbcSSaurabh Misra 	 * to send an IPI. With the removal of the Delivery Status bit,
3555d8efbbcSSaurabh Misra 	 * system software no longer has a reason to read the ICR. It remains
3565d8efbbcSSaurabh Misra 	 * readable only to aid in debugging.
3575d8efbbcSSaurabh Misra 	 */
3585d8efbbcSSaurabh Misra #ifdef	DEBUG
3595d8efbbcSSaurabh Misra 	APIC_AV_PENDING_SET();
3605d8efbbcSSaurabh Misra #endif	/* DEBUG */
361b6917abeSmishra 
36287cc6269SSaurabh Misra 	if ((cpun == psm_get_cpu_id())) {
36387cc6269SSaurabh Misra 		X2APIC_WRITE(X2APIC_SELF_IPI, vector);
36487cc6269SSaurabh Misra 	} else {
365b6917abeSmishra 		apic_reg_ops->apic_write_int_cmd(
366b6917abeSmishra 		    apic_cpus[cpun].aci_local_id, vector);
36787cc6269SSaurabh Misra 	}
368b6917abeSmishra 
369b6917abeSmishra 	intr_restore(flag);
370b6917abeSmishra }
371b6917abeSmishra 
372325e77f4SSaurabh Misra /*
373325e77f4SSaurabh Misra  * Generates IPI to another CPU depending on the local APIC mode.
374325e77f4SSaurabh Misra  * apic_send_ipi() and x2apic_send_ipi() depends on the configured
375325e77f4SSaurabh Misra  * mode of the local APIC, but that may not match the actual mode
376325e77f4SSaurabh Misra  * early in CPU startup.
377325e77f4SSaurabh Misra  *
378325e77f4SSaurabh Misra  * Any changes made to this routine must be accompanied by similar
379325e77f4SSaurabh Misra  * changes to apic_send_ipi().
380325e77f4SSaurabh Misra  */
381b6917abeSmishra void
apic_common_send_ipi(int cpun,int ipl)382325e77f4SSaurabh Misra apic_common_send_ipi(int cpun, int ipl)
383b6917abeSmishra {
384325e77f4SSaurabh Misra 	int vector;
385325e77f4SSaurabh Misra 	ulong_t flag;
386325e77f4SSaurabh Misra 	int mode = apic_local_mode();
387325e77f4SSaurabh Misra 
388325e77f4SSaurabh Misra 	if (mode == LOCAL_X2APIC) {
389325e77f4SSaurabh Misra 		x2apic_send_ipi(cpun, ipl);
390325e77f4SSaurabh Misra 		return;
391325e77f4SSaurabh Misra 	}
392325e77f4SSaurabh Misra 
393325e77f4SSaurabh Misra 	ASSERT(mode == LOCAL_APIC);
394325e77f4SSaurabh Misra 
395325e77f4SSaurabh Misra 	vector = apic_resv_vector[ipl];
396325e77f4SSaurabh Misra 	ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR));
397325e77f4SSaurabh Misra 	flag = intr_clear();
398325e77f4SSaurabh Misra 	while (local_apic_regs_ops.apic_read(APIC_INT_CMD1) & AV_PENDING)
399325e77f4SSaurabh Misra 		apic_ret();
400325e77f4SSaurabh Misra 	local_apic_regs_ops.apic_write_int_cmd(apic_cpus[cpun].aci_local_id,
401325e77f4SSaurabh Misra 	    vector);
402325e77f4SSaurabh Misra 	intr_restore(flag);
403b6917abeSmishra }
404