xref: /titanic_51/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c (revision 3f745f41d6d087602fbb2f748e1baabc3768f5fb)
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  */
256eedf6a5SJosef 'Jeff' Sipek /*
266eedf6a5SJosef 'Jeff' Sipek  * Copyright 2014 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
27*3f745f41SDan McDonald  * Copyright (c) 2014 by Delphix. All rights reserved.
286eedf6a5SJosef 'Jeff' Sipek  */
29b6917abeSmishra 
30b6917abeSmishra #include <sys/cpuvar.h>
31b6917abeSmishra #include <sys/psm.h>
32b6917abeSmishra #include <sys/archsystm.h>
33b6917abeSmishra #include <sys/apic.h>
34b6917abeSmishra #include <sys/sunddi.h>
35b6917abeSmishra #include <sys/ddi_impldefs.h>
36b6917abeSmishra #include <sys/mach_intr.h>
37b6917abeSmishra #include <sys/sysmacros.h>
38b6917abeSmishra #include <sys/trap.h>
39b6917abeSmishra #include <sys/x86_archext.h>
40b6917abeSmishra #include <sys/privregs.h>
41b6917abeSmishra #include <sys/psm_common.h>
42b6917abeSmishra 
43325e77f4SSaurabh Misra /* Function prototypes of local apic and X2APIC */
44b6917abeSmishra static uint64_t local_apic_read(uint32_t reg);
45b6917abeSmishra static void local_apic_write(uint32_t reg, uint64_t value);
46b6917abeSmishra static int get_local_apic_pri(void);
47b6917abeSmishra static void local_apic_write_task_reg(uint64_t value);
48b6917abeSmishra static void local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
49b6917abeSmishra static uint64_t local_x2apic_read(uint32_t msr);
50b6917abeSmishra static void local_x2apic_write(uint32_t msr, uint64_t value);
51b6917abeSmishra static int get_local_x2apic_pri(void);
52b6917abeSmishra static void local_x2apic_write_task_reg(uint64_t value);
53b6917abeSmishra static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1);
54b6917abeSmishra 
55b6917abeSmishra /*
56325e77f4SSaurabh Misra  * According to the X2APIC specification:
57b6917abeSmishra  *
58325e77f4SSaurabh Misra  *   xAPIC global enable    X2APIC enable         Description
59b6917abeSmishra  *   (IA32_APIC_BASE[11])   (IA32_APIC_BASE[10])
60b6917abeSmishra  * -----------------------------------------------------------
61b6917abeSmishra  *      0 			0 	APIC is disabled
62b6917abeSmishra  * 	0			1	Invalid
63b6917abeSmishra  *	1			0	APIC is enabled in xAPIC mode
64325e77f4SSaurabh Misra  *	1			1	APIC is enabled in X2APIC mode
65b6917abeSmishra  * -----------------------------------------------------------
66b6917abeSmishra  */
67b6917abeSmishra int	x2apic_enable = 1;
689b1d70f8SJosef 'Jeff' Sipek apic_mode_t apic_mode = LOCAL_APIC;	/* Default mode is Local APIC */
69b6917abeSmishra 
70*3f745f41SDan McDonald /* See apic_directed_EOI_supported().  Currently 3-state variable. */
71*3f745f41SDan McDonald volatile int apic_directed_eoi_state = 2;
72*3f745f41SDan McDonald 
73b6917abeSmishra /* Uses MMIO (Memory Mapped IO) */
74b6917abeSmishra static apic_reg_ops_t local_apic_regs_ops = {
75b6917abeSmishra 	local_apic_read,
76b6917abeSmishra 	local_apic_write,
77b6917abeSmishra 	get_local_apic_pri,
78b6917abeSmishra 	local_apic_write_task_reg,
79b6917abeSmishra 	local_apic_write_int_cmd,
80b6917abeSmishra 	apic_send_EOI,
81b6917abeSmishra };
82b6917abeSmishra 
83325e77f4SSaurabh Misra /* X2APIC : Uses RDMSR/WRMSR instructions to access APIC registers */
84b6917abeSmishra static apic_reg_ops_t x2apic_regs_ops = {
85b6917abeSmishra 	local_x2apic_read,
86b6917abeSmishra 	local_x2apic_write,
87b6917abeSmishra 	get_local_x2apic_pri,
88b6917abeSmishra 	local_x2apic_write_task_reg,
89b6917abeSmishra 	local_x2apic_write_int_cmd,
90b6917abeSmishra 	apic_send_EOI,
91b6917abeSmishra };
92b6917abeSmishra 
934c1c9391SJoe Bonasera int apic_have_32bit_cr8 = 0;
94b6917abeSmishra 
95b6917abeSmishra /* The default ops is local APIC (Memory Mapped IO) */
96b6917abeSmishra apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops;
97b6917abeSmishra 
98b6917abeSmishra /*
99b6917abeSmishra  * APIC register ops related data sturctures and functions.
100b6917abeSmishra  */
101b6917abeSmishra void apic_send_EOI();
102b6917abeSmishra void apic_send_directed_EOI(uint32_t irq);
103b6917abeSmishra 
104b6917abeSmishra #define	X2APIC_ENABLE_BIT	10
105b6917abeSmishra 
106b6917abeSmishra /*
107b6917abeSmishra  * Local APIC Implementation
108b6917abeSmishra  */
109b6917abeSmishra static uint64_t
110b6917abeSmishra local_apic_read(uint32_t reg)
111b6917abeSmishra {
112b6917abeSmishra 	return ((uint32_t)apicadr[reg]);
113b6917abeSmishra }
114b6917abeSmishra 
115b6917abeSmishra static void
116b6917abeSmishra local_apic_write(uint32_t reg, uint64_t value)
117b6917abeSmishra {
118b6917abeSmishra 	apicadr[reg] = (uint32_t)value;
119b6917abeSmishra }
120b6917abeSmishra 
121b6917abeSmishra static int
122b6917abeSmishra get_local_apic_pri(void)
123b6917abeSmishra {
124b6917abeSmishra #if defined(__amd64)
125b6917abeSmishra 	return ((int)getcr8());
126b6917abeSmishra #else
1272ef50f01SJoe Bonasera 	if (apic_have_32bit_cr8)
1282ef50f01SJoe Bonasera 		return ((int)getcr8());
129b6917abeSmishra 	return (apicadr[APIC_TASK_REG]);
130b6917abeSmishra #endif
131b6917abeSmishra }
132b6917abeSmishra 
133b6917abeSmishra static void
134b6917abeSmishra local_apic_write_task_reg(uint64_t value)
135b6917abeSmishra {
136b6917abeSmishra #if defined(__amd64)
137b6917abeSmishra 	setcr8((ulong_t)(value >> APIC_IPL_SHIFT));
138b6917abeSmishra #else
1392ef50f01SJoe Bonasera 	if (apic_have_32bit_cr8)
1402ef50f01SJoe Bonasera 		setcr8((ulong_t)(value >> APIC_IPL_SHIFT));
1412ef50f01SJoe Bonasera 	else
142b6917abeSmishra 		apicadr[APIC_TASK_REG] = (uint32_t)value;
143b6917abeSmishra #endif
144b6917abeSmishra }
145b6917abeSmishra 
146b6917abeSmishra static void
147b6917abeSmishra local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
148b6917abeSmishra {
149b6917abeSmishra 	apicadr[APIC_INT_CMD2] = cpu_id << APIC_ICR_ID_BIT_OFFSET;
150b6917abeSmishra 	apicadr[APIC_INT_CMD1] = cmd1;
151b6917abeSmishra }
152b6917abeSmishra 
153b6917abeSmishra /*
154325e77f4SSaurabh Misra  * X2APIC Implementation.
155b6917abeSmishra  */
156b6917abeSmishra static uint64_t
157b6917abeSmishra local_x2apic_read(uint32_t msr)
158b6917abeSmishra {
159b6917abeSmishra 	uint64_t i;
160b6917abeSmishra 
161b6917abeSmishra 	i = (uint64_t)(rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2)) & 0xffffffff);
162b6917abeSmishra 	return (i);
163b6917abeSmishra }
164b6917abeSmishra 
165b6917abeSmishra static void
166b6917abeSmishra local_x2apic_write(uint32_t msr, uint64_t value)
167b6917abeSmishra {
168b6917abeSmishra 	uint64_t tmp;
169b6917abeSmishra 
170b6917abeSmishra 	if (msr != APIC_EOI_REG) {
171b6917abeSmishra 		tmp = rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2));
172b6917abeSmishra 		tmp = (tmp & 0xffffffff00000000) | value;
173f9c480cdSSaurabh Misra 	} else {
174f9c480cdSSaurabh Misra 		tmp = 0;
175b6917abeSmishra 	}
176b6917abeSmishra 
177b6917abeSmishra 	wrmsr((REG_X2APIC_BASE_MSR + (msr >> 2)), tmp);
178b6917abeSmishra }
179b6917abeSmishra 
180b6917abeSmishra static int
181b6917abeSmishra get_local_x2apic_pri(void)
182b6917abeSmishra {
1835d8efbbcSSaurabh Misra 	return (rdmsr(REG_X2APIC_BASE_MSR + (APIC_TASK_REG >> 2)));
184b6917abeSmishra }
185b6917abeSmishra 
186b6917abeSmishra static void
187b6917abeSmishra local_x2apic_write_task_reg(uint64_t value)
188b6917abeSmishra {
189b6917abeSmishra 	X2APIC_WRITE(APIC_TASK_REG, value);
190b6917abeSmishra }
191b6917abeSmishra 
192b6917abeSmishra static void
193b6917abeSmishra local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1)
194b6917abeSmishra {
195b6917abeSmishra 	wrmsr((REG_X2APIC_BASE_MSR + (APIC_INT_CMD1 >> 2)),
196b6917abeSmishra 	    (((uint64_t)cpu_id << 32) | cmd1));
197b6917abeSmishra }
198b6917abeSmishra 
199b6917abeSmishra /*ARGSUSED*/
200b6917abeSmishra void
201b6917abeSmishra apic_send_EOI(uint32_t irq)
202b6917abeSmishra {
203b6917abeSmishra 	apic_reg_ops->apic_write(APIC_EOI_REG, 0);
204b6917abeSmishra }
205b6917abeSmishra 
206d23e508cSEdward Gillett /*
207d23e508cSEdward Gillett  * Support for Directed EOI capability is available in both the xAPIC
208d23e508cSEdward Gillett  * and x2APIC mode.
209d23e508cSEdward Gillett  */
210b6917abeSmishra void
211b6917abeSmishra apic_send_directed_EOI(uint32_t irq)
212b6917abeSmishra {
213b6917abeSmishra 	uchar_t ioapicindex;
214b6917abeSmishra 	uchar_t vector;
215b6917abeSmishra 	apic_irq_t *apic_irq;
216b6917abeSmishra 	short intr_index;
217b6917abeSmishra 
218d23e508cSEdward Gillett 	/*
219d23e508cSEdward Gillett 	 * Following the EOI to the local APIC unit, perform a directed
220d23e508cSEdward Gillett 	 * EOI to the IOxAPIC generating the interrupt by writing to its
221d23e508cSEdward Gillett 	 * EOI register.
222d23e508cSEdward Gillett 	 *
223d23e508cSEdward Gillett 	 * A broadcast EOI is not generated.
224d23e508cSEdward Gillett 	 */
225d23e508cSEdward Gillett 	apic_reg_ops->apic_write(APIC_EOI_REG, 0);
226b6917abeSmishra 
227b6917abeSmishra 	apic_irq = apic_irq_table[irq];
228b6917abeSmishra 	while (apic_irq) {
229b6917abeSmishra 		intr_index = apic_irq->airq_mps_intr_index;
230b6917abeSmishra 		if (intr_index == ACPI_INDEX || intr_index >= 0) {
231b6917abeSmishra 			ioapicindex = apic_irq->airq_ioapicindex;
232b6917abeSmishra 			vector = apic_irq->airq_vector;
233b6917abeSmishra 			ioapic_write_eoi(ioapicindex, vector);
234b6917abeSmishra 		}
235b6917abeSmishra 		apic_irq = apic_irq->airq_next;
236b6917abeSmishra 	}
237b6917abeSmishra }
238b6917abeSmishra 
239b6917abeSmishra int
240b6917abeSmishra apic_detect_x2apic(void)
241b6917abeSmishra {
242b6917abeSmishra 	if (x2apic_enable == 0)
243b6917abeSmishra 		return (0);
244b6917abeSmishra 
2456eedf6a5SJosef 'Jeff' Sipek 	return (is_x86_feature(x86_featureset, X86FSET_X2APIC));
246b6917abeSmishra }
247b6917abeSmishra 
248b6917abeSmishra void
249b6917abeSmishra apic_enable_x2apic(void)
250b6917abeSmishra {
251b6917abeSmishra 	uint64_t apic_base_msr;
252b6917abeSmishra 
253325e77f4SSaurabh Misra 	if (apic_local_mode() == LOCAL_X2APIC) {
254325e77f4SSaurabh Misra 		/* BIOS apparently has enabled X2APIC */
255325e77f4SSaurabh Misra 		if (apic_mode != LOCAL_X2APIC)
256b6917abeSmishra 			x2apic_update_psm();
257325e77f4SSaurabh Misra 		return;
258b6917abeSmishra 	}
259b6917abeSmishra 
260b6917abeSmishra 	/*
261325e77f4SSaurabh Misra 	 * This is the first time we are enabling X2APIC on this CPU
262325e77f4SSaurabh Misra 	 */
263325e77f4SSaurabh Misra 	apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
264325e77f4SSaurabh Misra 	apic_base_msr = apic_base_msr | (0x1 << X2APIC_ENABLE_BIT);
265325e77f4SSaurabh Misra 	wrmsr(REG_APIC_BASE_MSR, apic_base_msr);
266325e77f4SSaurabh Misra 
267325e77f4SSaurabh Misra 	if (apic_mode != LOCAL_X2APIC)
268325e77f4SSaurabh Misra 		x2apic_update_psm();
269325e77f4SSaurabh Misra }
270325e77f4SSaurabh Misra 
271325e77f4SSaurabh Misra /*
272325e77f4SSaurabh Misra  * Determine which mode the current CPU is in. See the table above.
273325e77f4SSaurabh Misra  * (IA32_APIC_BASE[11])   (IA32_APIC_BASE[10])
274325e77f4SSaurabh Misra  */
275325e77f4SSaurabh Misra int
276325e77f4SSaurabh Misra apic_local_mode(void)
277325e77f4SSaurabh Misra {
278325e77f4SSaurabh Misra 	uint64_t apic_base_msr;
279325e77f4SSaurabh Misra 	int bit = ((0x1 << (X2APIC_ENABLE_BIT + 1)) |
280325e77f4SSaurabh Misra 	    (0x1 << X2APIC_ENABLE_BIT));
281325e77f4SSaurabh Misra 
282325e77f4SSaurabh Misra 	apic_base_msr = rdmsr(REG_APIC_BASE_MSR);
283325e77f4SSaurabh Misra 
284325e77f4SSaurabh Misra 	if ((apic_base_msr & bit) == bit)
285325e77f4SSaurabh Misra 		return (LOCAL_X2APIC);
286325e77f4SSaurabh Misra 	else
287325e77f4SSaurabh Misra 		return (LOCAL_APIC);
288325e77f4SSaurabh Misra }
289325e77f4SSaurabh Misra 
290325e77f4SSaurabh Misra void
291e511d54dSSaurabh Misra apic_set_directed_EOI_handler()
292325e77f4SSaurabh Misra {
293325e77f4SSaurabh Misra 	apic_reg_ops->apic_send_eoi = apic_send_directed_EOI;
294325e77f4SSaurabh Misra }
295325e77f4SSaurabh Misra 
296e511d54dSSaurabh Misra int
297e511d54dSSaurabh Misra apic_directed_EOI_supported()
298e511d54dSSaurabh Misra {
299e511d54dSSaurabh Misra 	uint32_t ver;
300e511d54dSSaurabh Misra 
301*3f745f41SDan McDonald 	/*
302*3f745f41SDan McDonald 	 * There are some known issues with some versions of Linux KVM and QEMU
303*3f745f41SDan McDonald 	 * where by directed EOIs do not properly function and instead get
304*3f745f41SDan McDonald 	 * coalesced at the hypervisor, causing the host not to see interrupts.
305*3f745f41SDan McDonald 	 * Thus, when the platform is KVM, we would like to disable it by
306*3f745f41SDan McDonald 	 * default, but keep it available otherwise.
307*3f745f41SDan McDonald 	 *
308*3f745f41SDan McDonald 	 * We use a three-state variable (apic_directed_eoi_state) to determine
309*3f745f41SDan McDonald 	 * how we handle directed EOI.
310*3f745f41SDan McDonald 	 *
311*3f745f41SDan McDonald 	 * 0 --> Don't do directed EOI at all.
312*3f745f41SDan McDonald 	 * 1 --> Do directed EOI if available, no matter the HW environment.
313*3f745f41SDan McDonald 	 * 2 --> Don't do directed EOI on KVM, but do it otherwise if available.
314*3f745f41SDan McDonald 	 *
315*3f745f41SDan McDonald 	 * If some grinning weirdo put something else in there, treat it as '2'
316*3f745f41SDan McDonald 	 * (i.e. the current default).
317*3f745f41SDan McDonald 	 *
318*3f745f41SDan McDonald 	 * Note, at this time illumos KVM does not identify as KVM. If it does,
319*3f745f41SDan McDonald 	 * we'll need to do some work to determine if it should be caught by
320*3f745f41SDan McDonald 	 * this or if it should show up as its own value of platform_type.
321*3f745f41SDan McDonald 	 */
322*3f745f41SDan McDonald 	switch (apic_directed_eoi_state) {
323*3f745f41SDan McDonald 	case 0:
324*3f745f41SDan McDonald 		/* Don't do it at all. */
325*3f745f41SDan McDonald 		return (0);
326*3f745f41SDan McDonald 	case 1:
327*3f745f41SDan McDonald 		break;
328*3f745f41SDan McDonald 	case 2:
329*3f745f41SDan McDonald 	default:
330*3f745f41SDan McDonald 		/* Only do it if we aren't on KVM. */
331*3f745f41SDan McDonald 		if (get_hwenv() == HW_KVM)
332*3f745f41SDan McDonald 			return (0);
333*3f745f41SDan McDonald 		/* FALLTHRU */
334*3f745f41SDan McDonald 	}
335*3f745f41SDan McDonald 
336e511d54dSSaurabh Misra 	ver = apic_reg_ops->apic_read(APIC_VERS_REG);
337e511d54dSSaurabh Misra 	if (ver & APIC_DIRECTED_EOI_BIT)
338e511d54dSSaurabh Misra 		return (1);
339e511d54dSSaurabh Misra 
340e511d54dSSaurabh Misra 	return (0);
341e511d54dSSaurabh Misra }
342e511d54dSSaurabh Misra 
343325e77f4SSaurabh Misra /*
344325e77f4SSaurabh Misra  * Change apic_reg_ops depending upon the apic_mode.
345325e77f4SSaurabh Misra  */
346325e77f4SSaurabh Misra void
347325e77f4SSaurabh Misra apic_change_ops()
348325e77f4SSaurabh Misra {
349325e77f4SSaurabh Misra 	if (apic_mode == LOCAL_APIC)
350325e77f4SSaurabh Misra 		apic_reg_ops = &local_apic_regs_ops;
351325e77f4SSaurabh Misra 	else if (apic_mode == LOCAL_X2APIC)
352325e77f4SSaurabh Misra 		apic_reg_ops = &x2apic_regs_ops;
353325e77f4SSaurabh Misra }
354325e77f4SSaurabh Misra 
355325e77f4SSaurabh Misra /*
356325e77f4SSaurabh Misra  * Generates an interprocessor interrupt to another CPU when X2APIC mode is
357b6917abeSmishra  * enabled.
358b6917abeSmishra  */
359b6917abeSmishra void
360b6917abeSmishra x2apic_send_ipi(int cpun, int ipl)
361b6917abeSmishra {
362b6917abeSmishra 	int vector;
363b6917abeSmishra 	ulong_t flag;
3645d8efbbcSSaurabh Misra 
36587cc6269SSaurabh Misra 	ASSERT(apic_mode == LOCAL_X2APIC);
36687cc6269SSaurabh Misra 
3675d8efbbcSSaurabh Misra 	/*
3685d8efbbcSSaurabh Misra 	 * With X2APIC, Intel relaxed the semantics of the
3695d8efbbcSSaurabh Misra 	 * WRMSR instruction such that references to the X2APIC
3705d8efbbcSSaurabh Misra 	 * MSR registers are no longer serializing instructions.
3715d8efbbcSSaurabh Misra 	 * The code that initiates IPIs assumes that some sort
3725d8efbbcSSaurabh Misra 	 * of memory serialization occurs. The old APIC code
3735d8efbbcSSaurabh Misra 	 * did a write to uncachable memory mapped registers.
3745d8efbbcSSaurabh Misra 	 * Any reference to uncached memory is a serializing
3755d8efbbcSSaurabh Misra 	 * operation. To mimic those semantics here, we do an
3765d8efbbcSSaurabh Misra 	 * atomic operation, which translates to a LOCK OR instruction,
3775d8efbbcSSaurabh Misra 	 * which is serializing.
3785d8efbbcSSaurabh Misra 	 */
3795d8efbbcSSaurabh Misra 	atomic_or_ulong(&flag, 1);
3805d8efbbcSSaurabh Misra 
381b6917abeSmishra 	vector = apic_resv_vector[ipl];
382b6917abeSmishra 
383b6917abeSmishra 	flag = intr_clear();
384b6917abeSmishra 
3855d8efbbcSSaurabh Misra 	/*
386325e77f4SSaurabh Misra 	 * According to X2APIC specification in section '2.3.5.1' of
3875d8efbbcSSaurabh Misra 	 * Interrupt Command Register Semantics, the semantics of
3885d8efbbcSSaurabh Misra 	 * programming Interrupt Command Register to dispatch an interrupt
3895d8efbbcSSaurabh Misra 	 * is simplified. A single MSR write to the 64-bit ICR is required
3905d8efbbcSSaurabh Misra 	 * for dispatching an interrupt. Specifically with the 64-bit MSR
3915d8efbbcSSaurabh Misra 	 * interface to ICR, system software is not required to check the
3925d8efbbcSSaurabh Misra 	 * status of the delivery status bit prior to writing to the ICR
3935d8efbbcSSaurabh Misra 	 * to send an IPI. With the removal of the Delivery Status bit,
3945d8efbbcSSaurabh Misra 	 * system software no longer has a reason to read the ICR. It remains
3955d8efbbcSSaurabh Misra 	 * readable only to aid in debugging.
3965d8efbbcSSaurabh Misra 	 */
3975d8efbbcSSaurabh Misra #ifdef	DEBUG
3985d8efbbcSSaurabh Misra 	APIC_AV_PENDING_SET();
3995d8efbbcSSaurabh Misra #endif	/* DEBUG */
400b6917abeSmishra 
40187cc6269SSaurabh Misra 	if ((cpun == psm_get_cpu_id())) {
40287cc6269SSaurabh Misra 		X2APIC_WRITE(X2APIC_SELF_IPI, vector);
40387cc6269SSaurabh Misra 	} else {
404b6917abeSmishra 		apic_reg_ops->apic_write_int_cmd(
405b6917abeSmishra 		    apic_cpus[cpun].aci_local_id, vector);
40687cc6269SSaurabh Misra 	}
407b6917abeSmishra 
408b6917abeSmishra 	intr_restore(flag);
409b6917abeSmishra }
410b6917abeSmishra 
411325e77f4SSaurabh Misra /*
412325e77f4SSaurabh Misra  * Generates IPI to another CPU depending on the local APIC mode.
413325e77f4SSaurabh Misra  * apic_send_ipi() and x2apic_send_ipi() depends on the configured
414325e77f4SSaurabh Misra  * mode of the local APIC, but that may not match the actual mode
415325e77f4SSaurabh Misra  * early in CPU startup.
416325e77f4SSaurabh Misra  *
417325e77f4SSaurabh Misra  * Any changes made to this routine must be accompanied by similar
418325e77f4SSaurabh Misra  * changes to apic_send_ipi().
419325e77f4SSaurabh Misra  */
420b6917abeSmishra void
421325e77f4SSaurabh Misra apic_common_send_ipi(int cpun, int ipl)
422b6917abeSmishra {
423325e77f4SSaurabh Misra 	int vector;
424325e77f4SSaurabh Misra 	ulong_t flag;
425325e77f4SSaurabh Misra 	int mode = apic_local_mode();
426325e77f4SSaurabh Misra 
427325e77f4SSaurabh Misra 	if (mode == LOCAL_X2APIC) {
428325e77f4SSaurabh Misra 		x2apic_send_ipi(cpun, ipl);
429325e77f4SSaurabh Misra 		return;
430325e77f4SSaurabh Misra 	}
431325e77f4SSaurabh Misra 
432325e77f4SSaurabh Misra 	ASSERT(mode == LOCAL_APIC);
433325e77f4SSaurabh Misra 
434325e77f4SSaurabh Misra 	vector = apic_resv_vector[ipl];
435325e77f4SSaurabh Misra 	ASSERT((vector >= APIC_BASE_VECT) && (vector <= APIC_SPUR_INTR));
436325e77f4SSaurabh Misra 	flag = intr_clear();
437325e77f4SSaurabh Misra 	while (local_apic_regs_ops.apic_read(APIC_INT_CMD1) & AV_PENDING)
438325e77f4SSaurabh Misra 		apic_ret();
439325e77f4SSaurabh Misra 	local_apic_regs_ops.apic_write_int_cmd(apic_cpus[cpun].aci_local_id,
440325e77f4SSaurabh Misra 	    vector);
441325e77f4SSaurabh Misra 	intr_restore(flag);
442b6917abeSmishra }
443