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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/cpuvar.h> 29 #include <sys/psm.h> 30 #include <sys/archsystm.h> 31 #include <sys/apic.h> 32 #include <sys/sunddi.h> 33 #include <sys/ddi_impldefs.h> 34 #include <sys/mach_intr.h> 35 #include <sys/sysmacros.h> 36 #include <sys/trap.h> 37 #include <sys/x86_archext.h> 38 #include <sys/privregs.h> 39 #include <sys/psm_common.h> 40 41 /* Function prototypes of local apic and x2apic */ 42 static uint64_t local_apic_read(uint32_t reg); 43 static void local_apic_write(uint32_t reg, uint64_t value); 44 static int get_local_apic_pri(void); 45 static void local_apic_write_task_reg(uint64_t value); 46 static void local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1); 47 static uint64_t local_x2apic_read(uint32_t msr); 48 static void local_x2apic_write(uint32_t msr, uint64_t value); 49 static int get_local_x2apic_pri(void); 50 static void local_x2apic_write_task_reg(uint64_t value); 51 static void local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1); 52 53 /* 54 * According to the x2APIC specification: 55 * 56 * xAPIC global enable x2APIC enable Description 57 * (IA32_APIC_BASE[11]) (IA32_APIC_BASE[10]) 58 * ----------------------------------------------------------- 59 * 0 0 APIC is disabled 60 * 0 1 Invalid 61 * 1 0 APIC is enabled in xAPIC mode 62 * 1 1 APIC is enabled in x2APIC mode 63 * ----------------------------------------------------------- 64 */ 65 int x2apic_enable = 1; 66 int apic_mode = LOCAL_APIC; /* Default mode is Local APIC */ 67 68 /* Uses MMIO (Memory Mapped IO) */ 69 static 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 /* x2APIC : Uses RDMSR/WRMSR instructions to access APIC registers */ 79 static apic_reg_ops_t x2apic_regs_ops = { 80 local_x2apic_read, 81 local_x2apic_write, 82 get_local_x2apic_pri, 83 local_x2apic_write_task_reg, 84 local_x2apic_write_int_cmd, 85 apic_send_EOI, 86 }; 87 88 89 /* The default ops is local APIC (Memory Mapped IO) */ 90 apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops; 91 92 /* 93 * APIC register ops related data sturctures and functions. 94 */ 95 int apic_direct_EOI = 0; /* Directed EOI Support */ 96 97 void apic_send_EOI(); 98 void apic_send_directed_EOI(uint32_t irq); 99 100 #define X2APIC_CPUID_BIT 21 101 #define X2APIC_ENABLE_BIT 10 102 103 /* 104 * Local APIC Implementation 105 */ 106 static uint64_t 107 local_apic_read(uint32_t reg) 108 { 109 return ((uint32_t)apicadr[reg]); 110 } 111 112 static void 113 local_apic_write(uint32_t reg, uint64_t value) 114 { 115 apicadr[reg] = (uint32_t)value; 116 } 117 118 static int 119 get_local_apic_pri(void) 120 { 121 #if defined(__amd64) 122 return ((int)getcr8()); 123 #else 124 return (apicadr[APIC_TASK_REG]); 125 #endif 126 } 127 128 static void 129 local_apic_write_task_reg(uint64_t value) 130 { 131 #if defined(__amd64) 132 setcr8((ulong_t)(value >> APIC_IPL_SHIFT)); 133 #else 134 apicadr[APIC_TASK_REG] = (uint32_t)value; 135 #endif 136 } 137 138 static void 139 local_apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1) 140 { 141 apicadr[APIC_INT_CMD2] = cpu_id << APIC_ICR_ID_BIT_OFFSET; 142 apicadr[APIC_INT_CMD1] = cmd1; 143 } 144 145 /* 146 * x2APIC Implementation. 147 */ 148 static uint64_t 149 local_x2apic_read(uint32_t msr) 150 { 151 uint64_t i; 152 153 i = (uint64_t)(rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2)) & 0xffffffff); 154 return (i); 155 } 156 157 static void 158 local_x2apic_write(uint32_t msr, uint64_t value) 159 { 160 uint64_t tmp; 161 162 if (msr != APIC_EOI_REG) { 163 tmp = rdmsr(REG_X2APIC_BASE_MSR + (msr >> 2)); 164 tmp = (tmp & 0xffffffff00000000) | value; 165 } 166 167 wrmsr((REG_X2APIC_BASE_MSR + (msr >> 2)), tmp); 168 } 169 170 static int 171 get_local_x2apic_pri(void) 172 { 173 return (rdmsr(REG_X2APIC_BASE_MSR + (APIC_TASK_REG) >> 2)); 174 } 175 176 static void 177 local_x2apic_write_task_reg(uint64_t value) 178 { 179 X2APIC_WRITE(APIC_TASK_REG, value); 180 } 181 182 static void 183 local_x2apic_write_int_cmd(uint32_t cpu_id, uint32_t cmd1) 184 { 185 wrmsr((REG_X2APIC_BASE_MSR + (APIC_INT_CMD1 >> 2)), 186 (((uint64_t)cpu_id << 32) | cmd1)); 187 } 188 189 /*ARGSUSED*/ 190 void 191 apic_send_EOI(uint32_t irq) 192 { 193 apic_reg_ops->apic_write(APIC_EOI_REG, 0); 194 } 195 196 void 197 apic_send_directed_EOI(uint32_t irq) 198 { 199 uchar_t ioapicindex; 200 uchar_t vector; 201 apic_irq_t *apic_irq; 202 short intr_index; 203 204 ASSERT(apic_mode == LOCAL_X2APIC); 205 206 apic_irq = apic_irq_table[irq]; 207 208 while (apic_irq) { 209 intr_index = apic_irq->airq_mps_intr_index; 210 if (intr_index == ACPI_INDEX || intr_index >= 0) { 211 ioapicindex = apic_irq->airq_ioapicindex; 212 vector = apic_irq->airq_vector; 213 ioapic_write_eoi(ioapicindex, vector); 214 } 215 apic_irq = apic_irq->airq_next; 216 } 217 } 218 219 int 220 apic_detect_x2apic(void) 221 { 222 struct cpuid_regs cp; 223 224 if (x2apic_enable == 0) 225 return (0); 226 227 cp.cp_eax = 1; 228 (void) __cpuid_insn(&cp); 229 230 return ((cp.cp_ecx & (0x1 << X2APIC_CPUID_BIT)) ? 1 : 0); 231 } 232 233 void 234 apic_enable_x2apic(void) 235 { 236 uint64_t apic_base_msr; 237 238 apic_base_msr = rdmsr(REG_APIC_BASE_MSR); 239 apic_base_msr = apic_base_msr | (0x1 << X2APIC_ENABLE_BIT); 240 241 wrmsr(REG_APIC_BASE_MSR, apic_base_msr); 242 243 /* change the mode and ops */ 244 if (apic_mode != LOCAL_X2APIC) { 245 apic_mode = LOCAL_X2APIC; 246 apic_reg_ops = &x2apic_regs_ops; 247 x2apic_update_psm(); 248 } 249 } 250 251 /* 252 * Generates an interprocessor interrupt to another CPU when x2APIC mode is 253 * enabled. 254 */ 255 void 256 x2apic_send_ipi(int cpun, int ipl) 257 { 258 int vector; 259 ulong_t flag; 260 ASSERT(apic_mode == LOCAL_X2APIC); 261 262 vector = apic_resv_vector[ipl]; 263 264 flag = intr_clear(); 265 266 while (apic_reg_ops->apic_read(APIC_INT_CMD1) & AV_PENDING) 267 apic_ret(); 268 269 if ((cpun == psm_get_cpu_id())) 270 apic_reg_ops->apic_write(X2APIC_SELF_IPI, vector); 271 else 272 apic_reg_ops->apic_write_int_cmd( 273 apic_cpus[cpun].aci_local_id, vector); 274 275 intr_restore(flag); 276 } 277 278 279 void 280 apic_change_eoi() 281 { 282 apic_reg_ops->apic_send_eoi = apic_send_directed_EOI; 283 } 284