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