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
local_apic_read(uint32_t reg)110b6917abeSmishra local_apic_read(uint32_t reg)
111b6917abeSmishra {
112b6917abeSmishra return ((uint32_t)apicadr[reg]);
113b6917abeSmishra }
114b6917abeSmishra
115b6917abeSmishra static void
local_apic_write(uint32_t reg,uint64_t value)116b6917abeSmishra local_apic_write(uint32_t reg, uint64_t value)
117b6917abeSmishra {
118b6917abeSmishra apicadr[reg] = (uint32_t)value;
119b6917abeSmishra }
120b6917abeSmishra
121b6917abeSmishra static int
get_local_apic_pri(void)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
local_apic_write_task_reg(uint64_t value)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
local_apic_write_int_cmd(uint32_t cpu_id,uint32_t cmd1)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
local_x2apic_read(uint32_t msr)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
local_x2apic_write(uint32_t msr,uint64_t value)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
get_local_x2apic_pri(void)181b6917abeSmishra get_local_x2apic_pri(void)
182b6917abeSmishra {
1835d8efbbcSSaurabh Misra return (rdmsr(REG_X2APIC_BASE_MSR + (APIC_TASK_REG >> 2)));
184b6917abeSmishra }
185b6917abeSmishra
186b6917abeSmishra static void
local_x2apic_write_task_reg(uint64_t value)187b6917abeSmishra local_x2apic_write_task_reg(uint64_t value)
188b6917abeSmishra {
189b6917abeSmishra X2APIC_WRITE(APIC_TASK_REG, value);
190b6917abeSmishra }
191b6917abeSmishra
192b6917abeSmishra static void
local_x2apic_write_int_cmd(uint32_t cpu_id,uint32_t cmd1)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
apic_send_EOI(uint32_t irq)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
apic_send_directed_EOI(uint32_t irq)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
apic_detect_x2apic(void)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
apic_enable_x2apic(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
apic_local_mode(void)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
apic_set_directed_EOI_handler()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
apic_directed_EOI_supported()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
apic_change_ops()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
x2apic_send_ipi(int cpun,int ipl)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
apic_common_send_ipi(int cpun,int ipl)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