1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright 2014 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> 27 * Copyright (c) 2014 by Delphix. All rights reserved. 28 * Copyright 2017 Joyent, Inc. 29 */ 30 31 #include <sys/cpuvar.h> 32 #include <sys/psm.h> 33 #include <sys/archsystm.h> 34 #include <sys/apic.h> 35 #include <sys/sunddi.h> 36 #include <sys/ddi_impldefs.h> 37 #include <sys/mach_intr.h> 38 #include <sys/sysmacros.h> 39 #include <sys/trap.h> 40 #include <sys/x86_archext.h> 41 #include <sys/privregs.h> 42 #include <sys/psm_common.h> 43 44 /* Function prototypes of local apic */ 45 static uint64_t local_apic_read(uint32_t reg); 46 static void local_apic_write(uint32_t reg, uint64_t value); 47 static int get_local_apic_pri(void); 48 static void local_apic_write_task_reg(uint64_t value); 49 static void local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1); 50 51 /* 52 * According to the X2APIC specification: 53 * 54 * xAPIC global enable X2APIC enable Description 55 * (IA32_APIC_BASE[11]) (IA32_APIC_BASE[10]) 56 * ----------------------------------------------------------- 57 * 0 0 APIC is disabled 58 * 0 1 Invalid 59 * 1 0 APIC is enabled in xAPIC mode 60 * 1 1 APIC is enabled in X2APIC mode 61 * ----------------------------------------------------------- 62 */ 63 apic_mode_t apic_mode = LOCAL_APIC; /* Default mode is Local APIC */ 64 65 /* See apic_directed_EOI_supported(). Currently 3-state variable. */ 66 volatile int apic_directed_eoi_state = 2; 67 68 /* Uses MMIO (Memory Mapped IO) */ 69 apic_reg_ops_t local_apic_regs_ops = { 70 local_apic_read, 71 local_apic_write, 72 get_local_apic_pri, 73 local_apic_write_task_reg, 74 local_apic_write_int_cmd, 75 apic_send_EOI, 76 }; 77 78 int apic_have_32bit_cr8 = 0; 79 80 /* The default ops is local APIC (Memory Mapped IO) */ 81 apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops; 82 83 /* 84 * APIC register ops related data sturctures and functions. 85 */ 86 void apic_send_EOI(); 87 void apic_send_directed_EOI(uint32_t irq); 88 89 /* 90 * Local APIC Implementation 91 */ 92 static uint64_t 93 local_apic_read(uint32_t reg) 94 { 95 return ((uint32_t)apicadr[reg]); 96 } 97 98 static void 99 local_apic_write(uint32_t reg, uint64_t value) 100 { 101 apicadr[reg] = (uint32_t)value; 102 } 103 104 static int 105 get_local_apic_pri(void) 106 { 107 #if defined(__amd64) 108 return ((int)getcr8()); 109 #else 110 if (apic_have_32bit_cr8) 111 return ((int)getcr8()); 112 return (apicadr[APIC_TASK_REG]); 113 #endif 114 } 115 116 static void 117 local_apic_write_task_reg(uint64_t value) 118 { 119 #if defined(__amd64) 120 setcr8((ulong_t)(value >> APIC_IPL_SHIFT)); 121 #else 122 if (apic_have_32bit_cr8) 123 setcr8((ulong_t)(value >> APIC_IPL_SHIFT)); 124 else 125 apicadr[APIC_TASK_REG] = (uint32_t)value; 126 #endif 127 } 128 129 static void 130 local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1) 131 { 132 apicadr[APIC_INT_CMD2] = cpu_id << APIC_ICR_ID_BIT_OFFSET; 133 apicadr[APIC_INT_CMD1] = cmd1; 134 } 135 136 137 /*ARGSUSED*/ 138 void 139 apic_send_EOI(uint32_t irq) 140 { 141 apic_reg_ops->apic_write(APIC_EOI_REG, 0); 142 } 143 144 /* 145 * Support for Directed EOI capability is available in both the xAPIC 146 * and x2APIC mode. 147 */ 148 void 149 apic_send_directed_EOI(uint32_t irq) 150 { 151 uchar_t ioapicindex; 152 uchar_t vector; 153 apic_irq_t *apic_irq; 154 short intr_index; 155 156 /* 157 * Following the EOI to the local APIC unit, perform a directed 158 * EOI to the IOxAPIC generating the interrupt by writing to its 159 * EOI register. 160 * 161 * A broadcast EOI is not generated. 162 */ 163 apic_reg_ops->apic_write(APIC_EOI_REG, 0); 164 165 apic_irq = apic_irq_table[irq]; 166 while (apic_irq) { 167 intr_index = apic_irq->airq_mps_intr_index; 168 if (intr_index == ACPI_INDEX || intr_index >= 0) { 169 ioapicindex = apic_irq->airq_ioapicindex; 170 vector = apic_irq->airq_vector; 171 ioapic_write_eoi(ioapicindex, vector); 172 } 173 apic_irq = apic_irq->airq_next; 174 } 175 } 176 177 /* 178 * Determine which mode the current CPU is in. See the table above. 179 * (IA32_APIC_BASE[11]) (IA32_APIC_BASE[10]) 180 */ 181 int 182 apic_local_mode(void) 183 { 184 uint64_t apic_base_msr; 185 int bit = ((0x1 << (X2APIC_ENABLE_BIT + 1)) | 186 (0x1 << X2APIC_ENABLE_BIT)); 187 188 apic_base_msr = rdmsr(REG_APIC_BASE_MSR); 189 190 if ((apic_base_msr & bit) == bit) 191 return (LOCAL_X2APIC); 192 else 193 return (LOCAL_APIC); 194 } 195 196 void 197 apic_set_directed_EOI_handler() 198 { 199 apic_reg_ops->apic_send_eoi = apic_send_directed_EOI; 200 } 201 202 int 203 apic_directed_EOI_supported() 204 { 205 uint32_t ver; 206 207 /* 208 * There are some known issues with some versions of Linux KVM and QEMU 209 * where by directed EOIs do not properly function and instead get 210 * coalesced at the hypervisor, causing the host not to see interrupts. 211 * Thus, when the platform is KVM, we would like to disable it by 212 * default, but keep it available otherwise. 213 * 214 * We use a three-state variable (apic_directed_eoi_state) to determine 215 * how we handle directed EOI. 216 * 217 * 0 --> Don't do directed EOI at all. 218 * 1 --> Do directed EOI if available, no matter the HW environment. 219 * 2 --> Don't do directed EOI on KVM, but do it otherwise if available. 220 * 221 * If some grinning weirdo put something else in there, treat it as '2' 222 * (i.e. the current default). 223 * 224 * Note, at this time illumos KVM does not identify as KVM. If it does, 225 * we'll need to do some work to determine if it should be caught by 226 * this or if it should show up as its own value of platform_type. 227 */ 228 switch (apic_directed_eoi_state) { 229 case 0: 230 /* Don't do it at all. */ 231 return (0); 232 case 1: 233 break; 234 case 2: 235 default: 236 /* Only do it if we aren't on KVM. */ 237 if (get_hwenv() == HW_KVM) 238 return (0); 239 /* FALLTHRU */ 240 } 241 242 ver = apic_reg_ops->apic_read(APIC_VERS_REG); 243 if (ver & APIC_DIRECTED_EOI_BIT) 244 return (1); 245 246 return (0); 247 } 248